From d5b34e8c038f140627b807a40552e76d5d17d9a1 Mon Sep 17 00:00:00 2001 From: johnpyp Date: Mon, 9 Aug 2021 20:39:21 -0400 Subject: [PATCH 0001/2320] Fixed: (Indexer) BroadcastheNet - Report TvdbId and RId --- .../Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs b/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs index 7adfeec02..7664792af 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs @@ -55,7 +55,7 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet LimitsMax = 1000, TvSearchParams = new List { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.TvdbId, TvSearchParam.RId } }; From fe324dcc0c95691f4202e452eea7615ddfbbaffa Mon Sep 17 00:00:00 2001 From: chryzsh Date: Fri, 13 Aug 2021 09:54:41 +0200 Subject: [PATCH 0002/2320] Fixed: (Indexer) PTP IMDB search --- .../PassThePopcorn/PassThePopcornRequestGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornRequestGenerator.cs index 77fb4c6ee..0bc70fd41 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornRequestGenerator.cs @@ -22,7 +22,7 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace()) { - pageableRequests.Add(GetRequest(searchCriteria.ImdbId)); + pageableRequests.Add(GetRequest(searchCriteria.FullImdbId)); } else { From 4bd23a60bdebfe72de469b85de9e5de98402faf5 Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 13 Aug 2021 15:37:25 -0400 Subject: [PATCH 0003/2320] Fixed: Pad seasons parameter for newznab tvsearch --- .../NewznabRequestGeneratorFixture.cs | 21 +++++++++++++++++++ .../Newznab/NewznabRequestGenerator.cs | 3 ++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabRequestGeneratorFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabRequestGeneratorFixture.cs index 63be78c4c..1f097a7ed 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabRequestGeneratorFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabRequestGeneratorFixture.cs @@ -13,6 +13,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests public class NewznabRequestGeneratorFixture : CoreTest { private MovieSearchCriteria _movieSearchCriteria; + private TvSearchCriteria _tvSearchCriteria; private IndexerCapabilities _capabilities; [SetUp] @@ -30,6 +31,13 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests Categories = new int[] { 2000 } }; + _tvSearchCriteria = new TvSearchCriteria + { + SearchTerm = "Star Wars", + Categories = new int[] { 5000 }, + Season = 0 + }; + _capabilities = new IndexerCapabilities(); Mocker.GetMock() @@ -178,5 +186,18 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests pageTier2.Url.Query.Should().NotContain("imdbid=0076759"); pageTier2.Url.Query.Should().Contain("q="); } + + [Test] + public void should_pad_seasons_for_tv_search() + { + _capabilities.TvSearchParams = new List { TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep }; + + var results = Subject.GetSearchRequests(_tvSearchCriteria); + results.Tiers.Should().Be(1); + + var pageTier = results.GetTier(0).First().First(); + + pageTier.Url.Query.Should().Contain("season=00"); + } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs index b446deb8d..4b106137f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs @@ -140,7 +140,8 @@ namespace NzbDrone.Core.Indexers.Newznab if (searchCriteria.Season.HasValue && capabilities.TvSearchSeasonAvailable) { - parameters.Add("season", searchCriteria.Season.ToString()); + // Pad seasons to two decimals due to issues with NNTmux handling season = 0 + parameters.Add("season", searchCriteria.Season.Value.ToString("00")); } if (searchCriteria.Episode.IsNotNullOrWhiteSpace() && capabilities.TvSearchEpAvailable) From 2114db02d8bf6a45716ebfdbd50134906a99a8ee Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 13 Aug 2021 16:00:09 -0400 Subject: [PATCH 0004/2320] Fixed: (Rarbg) Advertise IMDB, TMDB, TVDB Search Fixes #392 --- src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs | 4 ++-- .../Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs index d80f0c8f3..6d17559fb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs @@ -49,11 +49,11 @@ namespace NzbDrone.Core.Indexers.Rarbg { TvSearchParams = new List { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId }, MovieSearchParams = new List { - MovieSearchParam.Q, MovieSearchParam.ImdbId + MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId }, MusicSearchParams = new List { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs index 12035ac4a..29093f389 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs @@ -46,7 +46,8 @@ namespace NzbDrone.Core.Indexers.Rarbg { requestBuilder.AddQueryParam("search_tvdb", tvdbId); } - else if (term.IsNotNullOrWhiteSpace()) + + if (term.IsNotNullOrWhiteSpace()) { requestBuilder.AddQueryParam("search_string", $"{term}"); } From 5d980a175cda9d53c84aab3f74f15f794491d50b Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 13 Aug 2021 16:42:49 -0400 Subject: [PATCH 0005/2320] Fixed: (DanishBytes) Handle response with null bumped_at Fixes #384 --- src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs index a0955fe7c..50ba133a8 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs @@ -49,7 +49,7 @@ namespace NzbDrone.Core.Indexers.Definitions { TvSearchParams = new List { - TvSearchParam.Q, TvSearchParam.ImdbId, TvSearchParam.TvdbId + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId }, MovieSearchParams = new List { @@ -70,7 +70,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping("3", NewznabStandardCategory.Audio, "Music"); caps.Categories.AddCategoryMapping("4", NewznabStandardCategory.PCGames, "Games"); caps.Categories.AddCategoryMapping("5", NewznabStandardCategory.PC0day, "Appz"); - caps.Categories.AddCategoryMapping("6", NewznabStandardCategory.Books, "Bookz"); + caps.Categories.AddCategoryMapping("8", NewznabStandardCategory.Books, "Bookz"); return caps; } @@ -294,12 +294,6 @@ namespace NzbDrone.Core.Indexers.Definitions [JsonProperty(PropertyName = "created_at")] public DateTime CreatedAt { get; set; } - [JsonProperty(PropertyName = "bumped_at")] - public DateTime BumpedAt { get; set; } - - [JsonProperty(PropertyName = "type_id")] - public int TypeId { get; set; } - [JsonProperty(PropertyName = "resolution_id")] public int ResolutionId { get; set; } From 5d5e2042d0aa0b611bf764a1f79c50ccf1fef99f Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 13 Aug 2021 16:46:48 -0400 Subject: [PATCH 0006/2320] Fixed: Handle response when magnet is empty Fixes #404 --- src/Prowlarr.Api.V1/Indexers/NewznabController.cs | 4 ++-- src/Prowlarr.Api.V1/Search/SearchController.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Prowlarr.Api.V1/Indexers/NewznabController.cs b/src/Prowlarr.Api.V1/Indexers/NewznabController.cs index 9b3b20ebb..b7851da2d 100644 --- a/src/Prowlarr.Api.V1/Indexers/NewznabController.cs +++ b/src/Prowlarr.Api.V1/Indexers/NewznabController.cs @@ -129,11 +129,11 @@ namespace NzbDrone.Api.V1.Indexers foreach (var result in results.Releases) { - result.DownloadUrl = result.DownloadUrl != null ? _downloadMappingService.ConvertToProxyLink(new Uri(result.DownloadUrl), request.server, indexerDef.Id, result.Title).ToString() : null; + result.DownloadUrl = result.DownloadUrl.IsNotNullOrWhiteSpace() ? _downloadMappingService.ConvertToProxyLink(new Uri(result.DownloadUrl), request.server, indexerDef.Id, result.Title).ToString() : null; if (result.DownloadProtocol == DownloadProtocol.Torrent) { - ((TorrentInfo)result).MagnetUrl = ((TorrentInfo)result).MagnetUrl != null ? _downloadMappingService.ConvertToProxyLink(new Uri(((TorrentInfo)result).MagnetUrl), request.server, indexerDef.Id, result.Title).ToString() : null; + ((TorrentInfo)result).MagnetUrl = ((TorrentInfo)result).MagnetUrl.IsNotNullOrWhiteSpace() ? _downloadMappingService.ConvertToProxyLink(new Uri(((TorrentInfo)result).MagnetUrl), request.server, indexerDef.Id, result.Title).ToString() : null; } } diff --git a/src/Prowlarr.Api.V1/Search/SearchController.cs b/src/Prowlarr.Api.V1/Search/SearchController.cs index 651d28e87..3990026f4 100644 --- a/src/Prowlarr.Api.V1/Search/SearchController.cs +++ b/src/Prowlarr.Api.V1/Search/SearchController.cs @@ -127,8 +127,8 @@ namespace Prowlarr.Api.V1.Search var release = downloadDecision.ToResource(); _remoteReleaseCache.Set(GetCacheKey(release), downloadDecision, TimeSpan.FromMinutes(30)); - release.DownloadUrl = release.DownloadUrl != null ? _downloadMappingService.ConvertToProxyLink(new Uri(release.DownloadUrl), serverUrl, release.IndexerId, release.Title).ToString() : null; - release.MagnetUrl = release.MagnetUrl != null ? _downloadMappingService.ConvertToProxyLink(new Uri(release.MagnetUrl), serverUrl, release.IndexerId, release.Title).ToString() : null; + release.DownloadUrl = release.DownloadUrl.IsNotNullOrWhiteSpace() ? _downloadMappingService.ConvertToProxyLink(new Uri(release.DownloadUrl), serverUrl, release.IndexerId, release.Title).ToString() : null; + release.MagnetUrl = release.MagnetUrl.IsNotNullOrWhiteSpace() ? _downloadMappingService.ConvertToProxyLink(new Uri(release.MagnetUrl), serverUrl, release.IndexerId, release.Title).ToString() : null; result.Add(release); } From a95465195dcd28ecef7ba4f51219f8475e72b384 Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 13 Aug 2021 18:20:40 -0400 Subject: [PATCH 0007/2320] New: (Indexer) BB --- src/NzbDrone.Core/Indexers/Definitions/BB.cs | 364 +++++++++++++++++++ 1 file changed, 364 insertions(+) create mode 100644 src/NzbDrone.Core/Indexers/Definitions/BB.cs diff --git a/src/NzbDrone.Core/Indexers/Definitions/BB.cs b/src/NzbDrone.Core/Indexers/Definitions/BB.cs new file mode 100644 index 000000000..cb8114d93 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/BB.cs @@ -0,0 +1,364 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using AngleSharp.Dom; +using AngleSharp.Html.Parser; +using FluentValidation; +using NLog; +using NzbDrone.Common.Http; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Indexers.Definitions +{ + public class BB : TorrentIndexerBase + { + public override string Name => "BB"; + public override string[] IndexerUrls => new string[] { StringUtil.FromBase64("aHR0cHM6Ly9iYWNvbmJpdHMub3JnLw==") }; + private string LoginUrl => Settings.BaseUrl + "login.php"; + public override string Description => "bB is a Private Torrent Tracker for 0DAY / GENERAL"; + public override string Language => "en-us"; + public override Encoding Encoding => Encoding.UTF8; + public override DownloadProtocol Protocol => DownloadProtocol.Torrent; + public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + public override IndexerCapabilities Capabilities => SetCapabilities(); + + public BB(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) + { + } + + public override IIndexerRequestGenerator GetRequestGenerator() + { + return new BBRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; + } + + public override IParseIndexerResponse GetParser() + { + return new BBParser(Settings, Capabilities.Categories); + } + + protected override async Task DoLogin() + { + var requestBuilder = new HttpRequestBuilder(LoginUrl) + { + LogResponseContent = true, + AllowAutoRedirect = true + }; + + requestBuilder.Method = HttpMethod.POST; + requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); + + var cookies = Cookies; + + Cookies = null; + var authLoginRequest = requestBuilder + .AddFormParameter("username", Settings.Username) + .AddFormParameter("password", Settings.Password) + .AddFormParameter("keeplogged", "1") + .AddFormParameter("login", "Log+In!") + .SetHeader("Content-Type", "multipart/form-data") + .Build(); + + var headers = new NameValueCollection + { + { "Referer", LoginUrl } + }; + + authLoginRequest.Headers.Add(headers); + + var response = await ExecuteAuth(authLoginRequest); + + if (CheckIfLoginNeeded(response)) + { + var parser = new HtmlParser(); + var dom = parser.ParseDocument(response.Content); + var messageEl = dom.QuerySelectorAll("#loginform"); + var messages = new List(); + for (var i = 0; i < 13; i++) + { + var child = messageEl[0].ChildNodes[i]; + messages.Add(child.Text().Trim()); + } + + var message = string.Join(" ", messages); + + throw new IndexerAuthException(message); + } + + cookies = response.GetCookies(); + UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); + + _logger.Debug("BB authentication succeeded."); + } + + protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) + { + return false; + } + + private IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities + { + TvSearchParams = new List + { + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep + }, + MovieSearchParams = new List + { + MovieSearchParam.Q + }, + MusicSearchParams = new List + { + MusicSearchParam.Q + }, + BookSearchParams = new List + { + BookSearchParam.Q + } + }; + + caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Audio); + caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.AudioMP3); + caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.AudioLossless); + caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.PC); + caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.BooksEBook); + caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.AudioAudiobook); + caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Other); + caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.BooksMags); + caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.BooksComics); + caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.TVAnime); + caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.Movies); + caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.TVHD); + caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.TVSD); + caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.TV); + caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.PCGames); + caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.Console); + caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.Other); + caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.Other); + + return caps; + } + } + + public class BBRequestGenerator : IIndexerRequestGenerator + { + public BBSettings Settings { get; set; } + public IndexerCapabilities Capabilities { get; set; } + + public BBRequestGenerator() + { + } + + private IEnumerable GetPagedRequests(string term, int[] categories) + { + var searchUrl = string.Format("{0}/torrents.php", Settings.BaseUrl.TrimEnd('/')); + + // TODO: IMDB search is available but it requires to parse the details page + var qc = new NameValueCollection + { + { "order_by", "s3" }, + { "order_way", "desc" }, + { "disablegrouping", "1" }, + { "searchtags", "" }, + { "tags_type", "0" }, + { "action", "basic" }, + { "searchstr", term } + }; + + var catList = Capabilities.Categories.MapTorznabCapsToTrackers(categories); + + foreach (var cat in catList) + { + qc.Add($"filter_cat[{cat}]", "1"); + } + + searchUrl = searchUrl + "?" + qc.GetQueryString(); + + var request = new IndexerRequest(searchUrl, HttpAccept.Html); + + yield return request; + } + + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public Func> GetCookies { get; set; } + public Action, DateTime?> CookiesUpdater { get; set; } + } + + public class BBParser : IParseIndexerResponse + { + private readonly BBSettings _settings; + private readonly IndexerCapabilitiesCategories _categories; + + public BBParser(BBSettings settings, IndexerCapabilitiesCategories categories) + { + _settings = settings; + _categories = categories; + } + + public IList ParseResponse(IndexerResponse indexerResponse) + { + var torrentInfos = new List(); + + var parser = new HtmlParser(); + var dom = parser.ParseDocument(indexerResponse.Content); + var rows = dom.QuerySelectorAll("#torrent_table > tbody > tr.torrent"); + + foreach (var row in rows) + { + var release = new TorrentInfo(); + + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; // 48 hours + + var catStr = row.Children[0].FirstElementChild.GetAttribute("href").Split(new[] { '[', ']' })[1]; + release.Categories = _categories.MapTrackerCatToNewznab(catStr); + + var qDetails = row.Children[1].QuerySelector("a[title='View Torrent']"); + release.InfoUrl = _settings.BaseUrl + qDetails.GetAttribute("href"); + release.Guid = release.InfoUrl; + + var qDownload = row.Children[1].QuerySelector("a[title='Download']"); + release.DownloadUrl = _settings.BaseUrl + qDownload.GetAttribute("href"); + + var dateStr = row.Children[3].TextContent.Trim().Replace(" and", ""); + release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); + + var sizeStr = row.Children[4].TextContent; + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Files = ParseUtil.CoerceInt(row.Children[2].TextContent.Trim()); + release.Seeders = ParseUtil.CoerceInt(row.Children[7].TextContent.Trim()); + release.Peers = ParseUtil.CoerceInt(row.Children[8].TextContent.Trim()) + release.Seeders; + + var grabs = row.QuerySelector("td:nth-child(6)").TextContent; + release.Grabs = ParseUtil.CoerceInt(grabs); + + if (row.QuerySelector("strong:contains(\"Freeleech!\")") != null) + { + release.DownloadVolumeFactor = 0; + } + else + { + release.DownloadVolumeFactor = 1; + } + + release.UploadVolumeFactor = 1; + + var title = row.QuerySelector("td:nth-child(2)"); + foreach (var element in title.QuerySelectorAll("span, strong, div, br")) + { + element.Remove(); + } + + release.Title = ParseUtil.NormalizeMultiSpaces(title.TextContent.Replace(" - ]", "]")); + + //change "Season #" to "S##" for TV shows + if (catStr == "10") + { + release.Title = Regex.Replace(release.Title, + @"Season (\d+)", + m => string.Format("S{0:00}", + int.Parse(m.Groups[1].Value))); + } + + torrentInfos.Add(release); + } + + return torrentInfos.ToArray(); + } + + public Action, DateTime?> CookiesUpdater { get; set; } + } + + public class BBSettingsValidator : AbstractValidator + { + public BBSettingsValidator() + { + RuleFor(c => c.Username).NotEmpty(); + RuleFor(c => c.Password).NotEmpty(); + } + } + + public class BBSettings : IIndexerSettings + { + private static readonly BBSettingsValidator Validator = new BBSettingsValidator(); + + public BBSettings() + { + Username = ""; + Password = ""; + } + + [FieldDefinition(1, Label = "Base Url", HelpText = "Select which baseurl Prowlarr will use for requests to the site", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls")] + public string BaseUrl { get; set; } + + [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] + public string Username { get; set; } + + [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] + public string Password { get; set; } + + [FieldDefinition(4)] + public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} From 6c5d48621f22aea0e4d590f56954c7446e6efc86 Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 13 Aug 2021 21:25:52 -0400 Subject: [PATCH 0008/2320] Fixed: (Indexer) Use Indexer Encoding for Query and Auth Fixes #370 --- src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs | 2 -- src/NzbDrone.Core/Indexers/HttpIndexerBase.cs | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs index fd9a2f94e..9ec0ff36f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs @@ -74,8 +74,6 @@ namespace NzbDrone.Core.Indexers.Definitions var authLoginRequest = requestBuilder.Build(); - authLoginRequest.Encoding = Encoding; - var response = await ExecuteAuth(authLoginRequest); if (!response.Content.Contains("id=\"logged-in-username\"")) diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index 6bc5f4b8f..ef1e4f51d 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -377,6 +377,8 @@ namespace NzbDrone.Core.Indexers } request.HttpRequest.SuppressHttpError = true; + request.HttpRequest.Encoding = Encoding; + var response = await _httpClient.ExecuteAsync(request.HttpRequest); // Check reponse to see if auth is needed, if needed try again @@ -410,6 +412,8 @@ namespace NzbDrone.Core.Indexers protected async Task ExecuteAuth(HttpRequest request) { + request.Encoding = Encoding; + var response = await _httpClient.ExecuteAsync(request); _eventAggregator.PublishEvent(new IndexerAuthEvent(Definition.Id, !response.HasHttpError, response.ElapsedTime)); From bdcead007cce4d6dbb160a15959c66c5d92f9ed0 Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 13 Aug 2021 21:28:01 -0400 Subject: [PATCH 0009/2320] Cleanup: (Rutracker) Purge unused using statements --- src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs index 9ec0ff36f..4a48547fc 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs @@ -9,18 +9,14 @@ using AngleSharp.Dom; using AngleSharp.Html.Parser; using FluentValidation; using NLog; -using NzbDrone.Common.Cache; -using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; -using NzbDrone.Core.Indexers.Definitions.Cardigann; using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions From 3e2d3c510a68ee934bf674d7b8c503a723d080cf Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 13 Aug 2021 21:31:13 -0400 Subject: [PATCH 0010/2320] Bump AngleSharp to 0.16.0 --- src/NzbDrone.Core/Prowlarr.Core.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index ad8c88fe8..560e659b3 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -19,7 +19,7 @@ - + From 3e07a9397c8ebcc839e82598def100ad2d973785 Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 13 Aug 2021 21:34:39 -0400 Subject: [PATCH 0011/2320] Bump DryIOC to 4.8.1 --- src/NzbDrone.Common/Prowlarr.Common.csproj | 2 +- src/NzbDrone.Host/Prowlarr.Host.csproj | 2 +- src/NzbDrone.Update/Prowlarr.Update.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index 19f1beef0..6156b1fd9 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -5,7 +5,7 @@ - + diff --git a/src/NzbDrone.Host/Prowlarr.Host.csproj b/src/NzbDrone.Host/Prowlarr.Host.csproj index 2a14658f1..edddca01b 100644 --- a/src/NzbDrone.Host/Prowlarr.Host.csproj +++ b/src/NzbDrone.Host/Prowlarr.Host.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/NzbDrone.Update/Prowlarr.Update.csproj b/src/NzbDrone.Update/Prowlarr.Update.csproj index 09a125af6..a103670ce 100644 --- a/src/NzbDrone.Update/Prowlarr.Update.csproj +++ b/src/NzbDrone.Update/Prowlarr.Update.csproj @@ -4,7 +4,7 @@ net5.0 - + From 305df2fb7b3d7ba39a0b658a0e4819dcd5e107ac Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 13 Aug 2021 21:38:31 -0400 Subject: [PATCH 0012/2320] Bump Microsoft.NET.Test.Sdk to 16.11.0 --- src/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 6910ac01b..78a356827 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -94,7 +94,7 @@ - + From 1e317dac6b737213cd8a321df490aa044c2f5415 Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 13 Aug 2021 21:40:34 -0400 Subject: [PATCH 0013/2320] Bump Net5 to 5.0.9 --- azure-pipelines.yml | 2 +- package.json | 2 +- .../Prowlarr.Integration.Test.csproj | 2 +- yarn.lock | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 84d62b940..cb4070b42 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -13,7 +13,7 @@ variables: buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' sentryOrg: 'servarr' sentryUrl: 'https://sentry.servarr.com' - dotnetVersion: '5.0.302' + dotnetVersion: '5.0.400' yarnCacheFolder: $(Pipeline.Workspace)/.yarn trigger: diff --git a/package.json b/package.json index ca4b0fe1c..cbfa48c71 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "@fortawesome/free-regular-svg-icons": "5.15.3", "@fortawesome/free-solid-svg-icons": "5.15.3", "@fortawesome/react-fontawesome": "0.1.14", - "@microsoft/signalr": "5.0.8", + "@microsoft/signalr": "5.0.9", "@sentry/browser": "6.10.0", "@sentry/integrations": "6.10.0", "chart.js": "3.2.0", diff --git a/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj b/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj index df1043e88..02846b5c8 100644 --- a/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj +++ b/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj @@ -4,7 +4,7 @@ Library - + diff --git a/yarn.lock b/yarn.lock index 770dc75b6..e416d2c54 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1095,10 +1095,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== -"@microsoft/signalr@5.0.8": - version "5.0.8" - resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-5.0.8.tgz#0504884a4675956f8a09bbf025b54712171639d6" - integrity sha512-g5U7zGa1CeoPztA1VGLiB418sZ6gt8ZEOsX8krpegyMquzH2Qinny1zQjNsg3mgjGlJI+FXD5bO4gVsHGUp2hA== +"@microsoft/signalr@5.0.9": + version "5.0.9" + resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-5.0.9.tgz#cff2b0a091298049fd012e7b6cd015a814f8698d" + integrity sha512-pQufk3+mChfystnmYpglyRYQFp+036QmOxbZUFr2cFf2iiS8ekBX5uVBOG8OexKcsG4TcJNAU/ref90Y9+3ZiA== dependencies: abort-controller "^3.0.0" eventsource "^1.0.7" From 878e269e7065cf70c9e9ffed7ace70576540d175 Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 13 Aug 2021 21:42:26 -0400 Subject: [PATCH 0014/2320] Bump MailKit to 2.14.0 --- src/NzbDrone.Core/Prowlarr.Core.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index 560e659b3..9963f4169 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -4,7 +4,7 @@ - + From 204052de9c81643f50fb0de2e3903cde43b3b1e8 Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 13 Aug 2021 21:46:57 -0400 Subject: [PATCH 0015/2320] Bump Dapper to 2.0.90 --- src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj | 2 +- src/NzbDrone.Core/Prowlarr.Core.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj index cb8efbd43..49557c26d 100644 --- a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj @@ -3,7 +3,7 @@ net5.0 - + diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index 9963f4169..27565c348 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -3,7 +3,7 @@ net5.0 - + From 868f779c5d749b780d66c6d5520b0c3b4dae0715 Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 13 Aug 2021 22:16:19 -0400 Subject: [PATCH 0016/2320] Fixed: (Newznab) Don't die if TV or Music only Fixes #283 --- .../Indexers/Definitions/Newznab/Newznab.cs | 24 ++++++++++++++++--- .../Newznab/NewznabRequestGenerator.cs | 9 +++++-- .../Indexers/Definitions/Torznab/Torznab.cs | 24 ++++++++++++++++--- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs index faceed2f3..37ba5f4df 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs @@ -177,13 +177,31 @@ namespace NzbDrone.Core.Indexers.Newznab } if (capabilities.MovieSearchParams != null && - new[] { MovieSearchParam.Q, MovieSearchParam.ImdbId }.Any(v => capabilities.MovieSearchParams.Contains(v)) && - new[] { MovieSearchParam.ImdbTitle, MovieSearchParam.ImdbYear }.All(v => capabilities.MovieSearchParams.Contains(v))) + new[] { MovieSearchParam.Q, MovieSearchParam.ImdbId }.Any(v => capabilities.MovieSearchParams.Contains(v))) { return null; } - return new ValidationFailure(string.Empty, "This indexer does not support searching for movies :(. Tell your indexer staff to enable this or force add the indexer by disabling search, adding the indexer and then enabling it again."); + if (capabilities.TvSearchParams != null && + new[] { TvSearchParam.Q, TvSearchParam.TvdbId, TvSearchParam.RId }.Any(v => capabilities.TvSearchParams.Contains(v)) && + new[] { TvSearchParam.Season, TvSearchParam.Ep }.All(v => capabilities.TvSearchParams.Contains(v))) + { + return null; + } + + if (capabilities.MusicSearchParams != null && + new[] { MusicSearchParam.Q, MusicSearchParam.Artist, MusicSearchParam.Album }.Any(v => capabilities.MusicSearchParams.Contains(v))) + { + return null; + } + + if (capabilities.BookSearchParams != null && + new[] { BookSearchParam.Q, BookSearchParam.Author, BookSearchParam.Title }.Any(v => capabilities.BookSearchParams.Contains(v))) + { + return null; + } + + return new ValidationFailure(string.Empty, "This indexer does not support searching for tv, music, or movies :(. Tell your indexer staff to enable this or force add the indexer by disabling search, adding the indexer and then enabling it again."); } catch (Exception ex) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs index 4b106137f..45a8b8729 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs @@ -140,8 +140,7 @@ namespace NzbDrone.Core.Indexers.Newznab if (searchCriteria.Season.HasValue && capabilities.TvSearchSeasonAvailable) { - // Pad seasons to two decimals due to issues with NNTmux handling season = 0 - parameters.Add("season", searchCriteria.Season.Value.ToString("00")); + parameters.Add("season", NewznabifySeasonNumber(searchCriteria.Season.Value)); } if (searchCriteria.Episode.IsNotNullOrWhiteSpace() && capabilities.TvSearchEpAvailable) @@ -270,6 +269,12 @@ namespace NzbDrone.Core.Indexers.Newznab return title.Replace("+", "%20"); } + // Temporary workaround for NNTMux considering season=0 -> null. '00' should work on existing newznab indexers. + private static string NewznabifySeasonNumber(int seasonNumber) + { + return seasonNumber == 0 ? "00" : seasonNumber.ToString(); + } + public Func> GetCookies { get; set; } public Action, DateTime?> CookiesUpdater { get; set; } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs index ae6bb7886..8bf5c06ff 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs @@ -153,13 +153,31 @@ namespace NzbDrone.Core.Indexers.Torznab } if (capabilities.MovieSearchParams != null && - new[] { MovieSearchParam.Q, MovieSearchParam.ImdbId }.Any(v => capabilities.MovieSearchParams.Contains(v)) && - new[] { MovieSearchParam.ImdbTitle, MovieSearchParam.ImdbYear }.All(v => capabilities.MovieSearchParams.Contains(v))) + new[] { MovieSearchParam.Q, MovieSearchParam.ImdbId }.Any(v => capabilities.MovieSearchParams.Contains(v))) { return null; } - return new ValidationFailure(string.Empty, "This indexer does not support searching for movies :(. Tell your indexer staff to enable this or force add the indexer by disabling search, adding the indexer and then enabling it again."); + if (capabilities.TvSearchParams != null && + new[] { TvSearchParam.Q, TvSearchParam.TvdbId, TvSearchParam.RId }.Any(v => capabilities.TvSearchParams.Contains(v)) && + new[] { TvSearchParam.Season, TvSearchParam.Ep }.All(v => capabilities.TvSearchParams.Contains(v))) + { + return null; + } + + if (capabilities.MusicSearchParams != null && + new[] { MusicSearchParam.Q, MusicSearchParam.Artist, MusicSearchParam.Album }.Any(v => capabilities.MusicSearchParams.Contains(v))) + { + return null; + } + + if (capabilities.BookSearchParams != null && + new[] { BookSearchParam.Q, BookSearchParam.Author, BookSearchParam.Title }.Any(v => capabilities.BookSearchParams.Contains(v))) + { + return null; + } + + return new ValidationFailure(string.Empty, "This indexer does not support searching for tv, music, or movies :(. Tell your indexer staff to enable this or force add the indexer by disabling search, adding the indexer and then enabling it again."); } catch (Exception ex) { From 12ae8edc50ff039d0871b275ed67490055e1a039 Mon Sep 17 00:00:00 2001 From: Qstick Date: Mon, 21 Jun 2021 19:49:24 -0400 Subject: [PATCH 0017/2320] New: (Indexer) Binsearch --- .../Indexer/Edit/EditIndexerModalContent.js | 1 - .../Indexers/Definitions/BinSearch.cs | 229 ++++++++++++++++++ 2 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs diff --git a/frontend/src/Indexer/Edit/EditIndexerModalContent.js b/frontend/src/Indexer/Edit/EditIndexerModalContent.js index 98934e71c..2a7c7a6ee 100644 --- a/frontend/src/Indexer/Edit/EditIndexerModalContent.js +++ b/frontend/src/Indexer/Edit/EditIndexerModalContent.js @@ -89,7 +89,6 @@ function EditIndexerModalContent(props) { type={inputTypes.CHECK} name="enable" helpTextWarning={supportsRss.value ? undefined : translate('RSSIsNotSupportedWithThisIndexer')} - isDisabled={!supportsRss.value} {...enable} onChange={onInputChange} /> diff --git a/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs b/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs new file mode 100644 index 000000000..dd1ed9d45 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs @@ -0,0 +1,229 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using AngleSharp.Html.Parser; +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Download; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Indexers.Definitions +{ + public class BinSearch : UsenetIndexerBase + { + public override string Name => "BinSearch"; + public override string[] IndexerUrls => new string[] { "https://binsearch.info/" }; + public override string Description => "The binary Usenet search engine"; + public override string Language => "en-us"; + public override Encoding Encoding => Encoding.UTF8; + public override DownloadProtocol Protocol => DownloadProtocol.Usenet; + public override IndexerPrivacy Privacy => IndexerPrivacy.Public; + public override bool SupportsRss => false; + public override IndexerCapabilities Capabilities => SetCapabilities(); + + public BinSearch(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, nzbValidationService, logger) + { + } + + public override IIndexerRequestGenerator GetRequestGenerator() + { + return new BinSearchRequestGenerator() { Capabilities = Capabilities, Settings = Settings }; + } + + public override IParseIndexerResponse GetParser() + { + return new BinSearchParser(Capabilities.Categories, Settings); + } + + private IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities + { + TvSearchParams = new List + { + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep + }, + MovieSearchParams = new List + { + MovieSearchParam.Q + }, + MusicSearchParams = new List + { + MusicSearchParam.Q + }, + BookSearchParams = new List + { + BookSearchParam.Q + } + }; + + return caps; + } + } + + public class BinSearchRequestGenerator : IIndexerRequestGenerator + { + public IndexerCapabilities Capabilities { get; set; } + public BinSearchSettings Settings { get; set; } + + public BinSearchRequestGenerator() + { + } + + private IEnumerable GetPagedRequests(string term, SearchCriteriaBase searchCriteria) + { + var qc = new NameValueCollection + { + { "adv_col", "on" }, + { "postdate", "date" }, + { "adv_sort", "date" }, + { "q", term }, + { "m", searchCriteria.Offset.ToString() }, + { "max", searchCriteria.Limit?.ToString() ?? "100" } + }; + + var searchUrl = string.Format("{0}/?{1}", Settings.BaseUrl.TrimEnd('/'), qc.GetQueryString()); + + var request = new IndexerRequest(searchUrl, HttpAccept.Json); + + yield return request; + } + + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria)); + + return pageableRequests; + } + + public Func> GetCookies { get; set; } + public Action, DateTime?> CookiesUpdater { get; set; } + } + + public class BinSearchParser : IParseIndexerResponse + { + private readonly IndexerCapabilitiesCategories _categories; + private readonly BinSearchSettings _settings; + + public BinSearchParser(IndexerCapabilitiesCategories categories, BinSearchSettings settings) + { + _categories = categories; + _settings = settings; + } + + public IList ParseResponse(IndexerResponse indexerResponse) + { + var releaseInfos = new List(); + + var parser = new HtmlParser(); + var doc = parser.ParseDocument(indexerResponse.Content); + var rows = doc.QuerySelectorAll("table.xMenuT > tbody > tr").Skip(1); + foreach (var row in rows) + { + var titleElement = row.QuerySelector("td > span.s"); + + if (titleElement == null) + { + continue; + } + + var parsedTitle = ParseTitleRegex.Match(titleElement.TextContent); + + if (!parsedTitle.Success || parsedTitle.Groups["title"].Value.IsNullOrWhiteSpace()) + { + continue; + } + + var guid = row.QuerySelector("input[type=checkbox]").GetAttribute("name"); + var publishDate = DateTimeUtil.FromUnknown(row.QuerySelector("td:nth-child(6)").TextContent); + var sizeElement = row.QuerySelector("td > span.d"); + var size = ParseSizeRegex.Match(sizeElement.TextContent); + var infoUrl = string.Format("{0}{1}", _settings.BaseUrl.TrimEnd('/'), row.QuerySelector("a").GetAttribute("href")); + var downloadUrl = string.Format("{0}/?action=nzb&{1}=1", _settings.BaseUrl.TrimEnd('/'), guid); + + var release = new ReleaseInfo + { + Guid = guid, + Title = parsedTitle.Groups["title"].Value, + Size = ReleaseInfo.GetBytes(string.Format("{0} {1}", size.Groups["size"].Value, size.Groups["unit"].Value)), + PublishDate = publishDate, + Categories = new List { NewznabStandardCategory.Other }, + InfoUrl = infoUrl, + DownloadUrl = downloadUrl + }; + + releaseInfos.Add(release); + } + + return releaseInfos.ToArray(); + } + + private static readonly Regex ParseTitleRegex = new Regex(@"\""(?.*)(?:\.(rar|nfo|mkv|par2|001|nzb|url|zip|r[0-9]{2}))\"""); + private static readonly Regex ParseSizeRegex = new Regex(@"size: (?<size>[0-9]+(\.[0-9]+)?).(?<unit>(GB|MB|KB|B))"); + + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + } + + public class BinSearchSettings : IIndexerSettings + { + [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] + public string BaseUrl { get; set; } + + [FieldDefinition(2)] + public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(); + } + } +} From 9a6391873fd26e91d0a3ba322e6d26f158f89a18 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 14 Aug 2021 17:15:54 -0400 Subject: [PATCH 0018/2320] Fixed: (HDBits) Unknown Categories on every release Fixes #365 --- src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBits.cs | 2 +- .../Indexers/Definitions/HDBits/HDBitsParser.cs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBits.cs b/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBits.cs index 569465925..43425cb96 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBits.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBits.cs @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Indexers.HDBits public override IParseIndexerResponse GetParser() { - return new HDBitsParser(Settings); + return new HDBitsParser(Settings, Capabilities.Categories); } private IndexerCapabilities SetCapabilities() diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsParser.cs b/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsParser.cs index 3c1d43371..ad76e0970 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsParser.cs @@ -12,10 +12,12 @@ namespace NzbDrone.Core.Indexers.HDBits public class HDBitsParser : IParseIndexerResponse { private readonly HDBitsSettings _settings; + private readonly IndexerCapabilitiesCategories _categories; - public HDBitsParser(HDBitsSettings settings) + public HDBitsParser(HDBitsSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; + _categories = categories; } public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) @@ -65,6 +67,7 @@ namespace NzbDrone.Core.Indexers.HDBits Guid = string.Format("HDBits-{0}", id), Title = result.Name, Size = result.Size, + Categories = _categories.MapTrackerCatToNewznab(result.TypeCategory.ToString()), InfoHash = result.Hash, DownloadUrl = GetDownloadUrl(id), InfoUrl = GetInfoUrl(id), From 27c643d2f54f069c278e852d8fe91e3f570d341a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 14 Aug 2021 20:07:54 -0400 Subject: [PATCH 0019/2320] New: (DownloadClient) Aria2 --- .../Download/Clients/Aria2/Aria2.cs | 140 +++++++++++++++++ .../Download/Clients/Aria2/Aria2Containers.cs | 111 ++++++++++++++ .../Download/Clients/Aria2/Aria2Proxy.cs | 144 ++++++++++++++++++ .../Download/Clients/Aria2/Aria2Settings.cs | 49 ++++++ 4 files changed, 444 insertions(+) create mode 100644 src/NzbDrone.Core/Download/Clients/Aria2/Aria2.cs create mode 100644 src/NzbDrone.Core/Download/Clients/Aria2/Aria2Containers.cs create mode 100644 src/NzbDrone.Core/Download/Clients/Aria2/Aria2Proxy.cs create mode 100644 src/NzbDrone.Core/Download/Clients/Aria2/Aria2Settings.cs diff --git a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2.cs b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2.cs new file mode 100644 index 000000000..7eac71b7f --- /dev/null +++ b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using FluentValidation.Results; +using NLog; +using NzbDrone.Common.Disk; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Download.Clients.Aria2 +{ + public class Aria2 : TorrentClientBase<Aria2Settings> + { + private readonly IAria2Proxy _proxy; + + public override string Name => "Aria2"; + + public Aria2(IAria2Proxy proxy, + ITorrentFileInfoReader torrentFileInfoReader, + IHttpClient httpClient, + IConfigService configService, + IDiskProvider diskProvider, + Logger logger) + : base(torrentFileInfoReader, httpClient, configService, diskProvider, logger) + { + _proxy = proxy; + } + + protected override string AddFromMagnetLink(ReleaseInfo release, string hash, string magnetLink) + { + var gid = _proxy.AddUri(Settings, magnetLink); + + var tries = 10; + var retryDelay = 500; + + // Wait a bit for the magnet to be resolved. + if (!WaitForTorrent(gid, hash, tries, retryDelay)) + { + _logger.Warn($"Aria2 could not add magnent within {tries * retryDelay / 1000} seconds, download may remain stuck: {magnetLink}."); + return hash; + } + + _logger.Debug($"Äria2 AddFromMagnetLink '{hash}' -> '{gid}'"); + + return hash; + } + + protected override string AddFromTorrentFile(ReleaseInfo release, string hash, string filename, byte[] fileContent) + { + var gid = _proxy.AddTorrent(Settings, fileContent); + + var tries = 10; + var retryDelay = 500; + + // Wait a bit for the magnet to be resolved. + if (!WaitForTorrent(gid, hash, tries, retryDelay)) + { + _logger.Warn($"Aria2 could not add torrent within {tries * retryDelay / 1000} seconds, download may remain stuck: {filename}."); + return hash; + } + + return hash; + } + + private bool WaitForTorrent(string gid, string hash, int tries, int retryDelay) + { + for (var i = 0; i < tries; i++) + { + var found = _proxy.GetFromGID(Settings, gid); + + if (found?.InfoHash?.ToLower() == hash?.ToLower()) + { + return true; + } + + Thread.Sleep(retryDelay); + } + + _logger.Debug("Could not find hash {0} in {1} tries at {2} ms intervals.", hash, tries, retryDelay); + + return false; + } + + protected override void Test(List<ValidationFailure> failures) + { + failures.AddIfNotNull(TestConnection()); + + if (failures.HasErrors()) + { + return; + } + } + + private ValidationFailure TestConnection() + { + try + { + var version = _proxy.GetVersion(Settings); + + if (new Version(version) < new Version("1.34.0")) + { + return new ValidationFailure(string.Empty, "Aria2 version should be at least 1.34.0. Version reported is {0}", version); + } + } + catch (Exception ex) + { + _logger.Error(ex, "Failed to test Aria2"); + + return new NzbDroneValidationFailure("Host", "Unable to connect to Aria2") + { + DetailedDescription = ex.Message + }; + } + + return null; + } + + protected override string AddFromTorrentLink(ReleaseInfo release, string hash, string torrentLink) + { + var gid = _proxy.AddUri(Settings, torrentLink); + + var tries = 10; + var retryDelay = 500; + + // Wait a bit for the magnet to be resolved. + if (!WaitForTorrent(gid, hash, tries, retryDelay)) + { + _logger.Warn($"Aria2 could not add torrent within {tries * retryDelay / 1000} seconds, download may remain stuck: {torrentLink}."); + return hash; + } + + _logger.Debug($"Aria2 AddFromTorrentLink '{hash}' -> '{gid}'"); + + return hash; + } + } +} diff --git a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Containers.cs b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Containers.cs new file mode 100644 index 000000000..d4ab5a49c --- /dev/null +++ b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Containers.cs @@ -0,0 +1,111 @@ +using CookComputing.XmlRpc; + +namespace NzbDrone.Core.Download.Clients.Aria2 +{ + public class Aria2Version + { + [XmlRpcMember("version")] + public string Version; + + [XmlRpcMember("enabledFeatures")] + public string[] EnabledFeatures; + } + + public class Aria2Uri + { + [XmlRpcMember("status")] + public string Status; + + [XmlRpcMember("uri")] + public string Uri; + } + + public class Aria2File + { + [XmlRpcMember("index")] + public string Index; + + [XmlRpcMember("length")] + public string Length; + + [XmlRpcMember("completedLength")] + public string CompletedLength; + + [XmlRpcMember("path")] + public string Path; + + [XmlRpcMember("selected")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public string Selected; + + [XmlRpcMember("uris")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public Aria2Uri[] Uris; + } + + public class Aria2Status + { + [XmlRpcMember("bittorrent")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public XmlRpcStruct Bittorrent; + + [XmlRpcMember("bitfield")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public string Bitfield; + + [XmlRpcMember("infoHash")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public string InfoHash; + + [XmlRpcMember("completedLength")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public string CompletedLength; + + [XmlRpcMember("connections")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public string Connections; + + [XmlRpcMember("dir")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public string Dir; + + [XmlRpcMember("downloadSpeed")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public string DownloadSpeed; + + [XmlRpcMember("files")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public Aria2File[] Files; + + [XmlRpcMember("gid")] + public string Gid; + + [XmlRpcMember("numPieces")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public string NumPieces; + + [XmlRpcMember("pieceLength")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public string PieceLength; + + [XmlRpcMember("status")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public string Status; + + [XmlRpcMember("totalLength")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public string TotalLength; + + [XmlRpcMember("uploadLength")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public string UploadLength; + + [XmlRpcMember("uploadSpeed")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public string UploadSpeed; + + [XmlRpcMember("errorMessage")] + [XmlRpcMissingMapping(MappingAction.Ignore)] + public string ErrorMessage; + } +} diff --git a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Proxy.cs b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Proxy.cs new file mode 100644 index 000000000..855d300ba --- /dev/null +++ b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Proxy.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using CookComputing.XmlRpc; +using NLog; + +namespace NzbDrone.Core.Download.Clients.Aria2 +{ + public interface IAria2Proxy + { + string GetVersion(Aria2Settings settings); + string AddUri(Aria2Settings settings, string magnet); + string AddTorrent(Aria2Settings settings, byte[] torrent); + Aria2Status GetFromGID(Aria2Settings settings, string gid); + } + + public interface IAria2 : IXmlRpcProxy + { + [XmlRpcMethod("aria2.getVersion")] + Aria2Version GetVersion(string token); + + [XmlRpcMethod("aria2.addUri")] + string AddUri(string token, string[] uri); + + [XmlRpcMethod("aria2.addTorrent")] + string AddTorrent(string token, byte[] torrent); + + [XmlRpcMethod("aria2.forceRemove")] + string Remove(string token, string gid); + + [XmlRpcMethod("aria2.tellStatus")] + Aria2Status GetFromGid(string token, string gid); + + [XmlRpcMethod("aria2.getGlobalOption")] + XmlRpcStruct GetGlobalOption(string token); + + [XmlRpcMethod("aria2.tellActive")] + Aria2Status[] GetActives(string token); + + [XmlRpcMethod("aria2.tellWaiting")] + Aria2Status[] GetWaitings(string token, int offset, int num); + + [XmlRpcMethod("aria2.tellStopped")] + Aria2Status[] GetStoppeds(string token, int offset, int num); + } + + public class Aria2Proxy : IAria2Proxy + { + private readonly Logger _logger; + + public Aria2Proxy(Logger logger) + { + _logger = logger; + } + + private string GetToken(Aria2Settings settings) + { + return $"token:{settings?.SecretToken}"; + } + + private string GetURL(Aria2Settings settings) + { + return $"http{(settings.UseSsl ? "s" : "")}://{settings.Host}:{settings.Port}{settings.RpcPath}"; + } + + public string GetVersion(Aria2Settings settings) + { + _logger.Debug("> aria2.getVersion"); + + var client = BuildClient(settings); + var version = ExecuteRequest(() => client.GetVersion(GetToken(settings))); + + _logger.Debug("< aria2.getVersion"); + + return version.Version; + } + + public Aria2Status GetFromGID(Aria2Settings settings, string gid) + { + _logger.Debug("> aria2.tellStatus"); + + var client = BuildClient(settings); + var found = ExecuteRequest(() => client.GetFromGid(GetToken(settings), gid)); + + _logger.Debug("< aria2.tellStatus"); + + return found; + } + + public string AddUri(Aria2Settings settings, string magnet) + { + _logger.Debug("> aria2.addUri"); + + var client = BuildClient(settings); + var gid = ExecuteRequest(() => client.AddUri(GetToken(settings), new[] { magnet })); + + _logger.Debug("< aria2.addUri"); + + return gid; + } + + public string AddTorrent(Aria2Settings settings, byte[] torrent) + { + _logger.Debug("> aria2.addTorrent"); + + var client = BuildClient(settings); + var gid = ExecuteRequest(() => client.AddTorrent(GetToken(settings), torrent)); + + _logger.Debug("< aria2.addTorrent"); + + return gid; + } + + private IAria2 BuildClient(Aria2Settings settings) + { + var client = XmlRpcProxyGen.Create<IAria2>(); + client.Url = GetURL(settings); + + return client; + } + + private T ExecuteRequest<T>(Func<T> task) + { + try + { + return task(); + } + catch (XmlRpcServerException ex) + { + throw new DownloadClientException("Unable to connect to aria2, please check your settings", ex); + } + catch (WebException ex) + { + if (ex.Status == WebExceptionStatus.TrustFailure) + { + throw new DownloadClientUnavailableException("Unable to connect to aria2, certificate validation failed.", ex); + } + + throw new DownloadClientUnavailableException("Unable to connect to aria2, please check your settings", ex); + } + } + } +} diff --git a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Settings.cs b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Settings.cs new file mode 100644 index 000000000..a78732c52 --- /dev/null +++ b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Settings.cs @@ -0,0 +1,49 @@ +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Download.Clients.Aria2 +{ + public class Aria2SettingsValidator : AbstractValidator<Aria2Settings> + { + public Aria2SettingsValidator() + { + RuleFor(c => c.Host).ValidHost(); + } + } + + public class Aria2Settings : IProviderConfig + { + private static readonly Aria2SettingsValidator Validator = new Aria2SettingsValidator(); + + public Aria2Settings() + { + Host = "localhost"; + Port = 6800; + RpcPath = "/rpc"; + UseSsl = false; + SecretToken = "MySecretToken"; + } + + [FieldDefinition(0, Label = "Host", Type = FieldType.Textbox)] + public string Host { get; set; } + + [FieldDefinition(1, Label = "Port", Type = FieldType.Number)] + public int Port { get; set; } + + [FieldDefinition(2, Label = "RPC Path", Type = FieldType.Textbox)] + public string RpcPath { get; set; } + + [FieldDefinition(3, Label = "Use SSL", Type = FieldType.Checkbox)] + public bool UseSsl { get; set; } + + [FieldDefinition(4, Label = "Secret token", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] + public string SecretToken { get; set; } + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} From 1c15932b900ffd7ae3350cb11f3b5074abf30180 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sat, 14 Aug 2021 19:39:50 +0000 Subject: [PATCH 0020/2320] Translated using Weblate (German) Currently translated at 98.8% (421 of 426 strings) Translated using Weblate (German) Currently translated at 98.3% (419 of 426 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (426 of 426 strings) Translated using Weblate (Portuguese) Currently translated at 85.4% (364 of 426 strings) Co-authored-by: Nyuels <nils.faerber@rwth-aachen.de> Co-authored-by: Nyuels <nyuels@nyuels.de> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Will Segatto <segatto.w@gmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/de.json | 12 ++++++++---- src/NzbDrone.Core/Localization/Core/pt.json | 2 +- src/NzbDrone.Core/Localization/Core/pt_BR.json | 8 ++++---- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/de.json b/src/NzbDrone.Core/Localization/Core/de.json index c91a8a767..ccddbf041 100644 --- a/src/NzbDrone.Core/Localization/Core/de.json +++ b/src/NzbDrone.Core/Localization/Core/de.json @@ -718,7 +718,7 @@ "CheckDownloadClientForDetails": "prüfe den Downloader für mehr Details", "CancelPendingTask": "Diese laufende Aufgabe wirklich abbrechen?", "BranchUpdateMechanism": "Branch für den externen Updateablauf", - "BranchUpdate": "Branch zum updaten von Prowlarr", + "BranchUpdate": "Verwendeter Branch zur Aktualisierung von Prowlarr", "BeforeUpdate": "Vor dem Update", "AllowMovieChangeClickToChangeMovie": "Klicken um den Film zu bearbeiten", "AddingTag": "Tag hinzufügen", @@ -757,7 +757,7 @@ "RegularExpressionsCanBeTested": "Reguläre Ausdrücke können getestet werden ", "ProwlarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "Benutzerdefinierte Bedingungen gegen die unten aufgeführten Release-Eigenschaften werden unterstützt.", "ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "RSS Film Listen sowie unten aufgelistete werden untertützt.", - "ProwlarrSupportsAnyIndexer": "Jeder Indexer der den Newznab-Standard verwendet oder unten aufgelistet ist wird untertützt.", + "ProwlarrSupportsAnyIndexer": "Prowlarr unterstützt alle Indexer, welcher den Newznab/Torznab Standard implementiert (verwende 'Generic Newznab' (für Usenet) oder 'Generic Torznab' (für Torrents)) und darüber hinaus viele weitere Indexer. Wählen Sie im Folgenden Ihren Indexer aus der Liste.", "ProwlarrSupportsAnyDownloadClient": "Jeder Downloader der den Newznab-Standard verwendet oder unten aufgelistet ist wird untertützt.", "OnDeleteHelpText": "Löschen", "NoUpdatesAreAvailable": "Es sind keine Updates verfügbar", @@ -926,10 +926,14 @@ "Custom": "Benutzerdefiniert", "CouldNotConnectSignalR": "Es konnte keine Verbindung zu SignalR hergestellt werden, die Benutzeroberfläche wird nicht aktualisiert", "Category": "Kategorie", - "Apps": "Apps", + "Apps": "Anwendungen", "AppProfileInUse": "App-Profil im Einsatz", "AppProfileDeleteConfirm": "Möchten Sie {0} wirklich löschen?", "Applications": "Anwendungen", "AddRemoveOnly": "Nur hinzufügen und entfernen", - "AddDownloadClientToProwlarr": "Durch das Hinzufügen eines Download-Clients kann Prowlarr während einer manuellen Suche Releases direkt über die Benutzeroberfläche senden." + "AddDownloadClientToProwlarr": "Durch das Hinzufügen eines Download-Clients kann Prowlarr während einer manuellen Suche Releases direkt über die Benutzeroberfläche senden.", + "Stats": "Statistiken", + "NoSearchResultsFound": "Keine Suchergebnisse gefunden. Versuchen Sie unten eine erneute Suche durchzuführen.", + "Query": "Abfrage", + "Torrent": "Torrent" } diff --git a/src/NzbDrone.Core/Localization/Core/pt.json b/src/NzbDrone.Core/Localization/Core/pt.json index dc232666e..f472a3e9b 100644 --- a/src/NzbDrone.Core/Localization/Core/pt.json +++ b/src/NzbDrone.Core/Localization/Core/pt.json @@ -286,7 +286,7 @@ "ConnectionLostMessage": "O Prowlarr perdeu a ligação com o back-end e precisará recarregar para restaurar a funcionalidade.", "ConnectionLostAutomaticMessage": "O Prowlarr tentará ligar automaticamente, ou você pode clicar em Recarregar abaixo.", "ConnectionLost": "Ligação perdida", - "Connect": "Ligar", + "Connect": "Conexões", "Component": "Componente", "CompletedDownloadHandling": "Manuseio de Download Completado", "Columns": "Colunas", diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index fe332bdc2..0def3004f 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -84,7 +84,7 @@ "Backup": "Backup", "BackupFolderHelpText": "Os caminhos relativos estarão no diretório AppData do Prowlarr", "BackupIntervalHelpText": "Intervalo entre backups automáticos", - "BackupNow": "Fazer backup agora", + "BackupNow": "Disparar Backup", "Backups": "Backups", "BeforeUpdate": "Antes da atualização", "BindAddress": "Endereço de vínculo", @@ -104,7 +104,7 @@ "CloseCurrentModal": "Fechar modal atual", "Columns": "Colunas", "Component": "Componente", - "Connect": "Conectar", + "Connect": "Conexões", "ConnectionLost": "Conexão perdida", "ConnectionLostMessage": "O Prowlarr perdeu a conexão com o backend e precisará ser recarregado para restaurar a funcionalidade.", "Connections": "Conexões", @@ -265,7 +265,7 @@ "Refresh": "Atualizar", "RefreshMovie": "Atualizar filme", "ReleaseBranchCheckPreviousVersionMessage": "A ramificação {0} é para uma versão anterior do Prowlarr, defina a ramificação como \"Nightly\" para obter mais atualizações", - "ReleaseStatus": "Status do lançamento", + "ReleaseStatus": "Status da versão", "Reload": "Recarregar", "RemovedFromTaskQueue": "Removido da fila de tarefas", "RemoveFilter": "Remover filtro", @@ -337,7 +337,7 @@ "Today": "Hoje", "Tomorrow": "Amanhã", "Type": "Tipo", - "UI": "interface", + "UI": "Interface", "UILanguage": "Idioma da interface", "UILanguageHelpTextWarning": "É necessário recarregar o navegador", "UISettings": "Configurações da interface", From 09d839ffb124c2aadf020c0d955f338abfeade2b Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 14 Aug 2021 17:42:14 -0500 Subject: [PATCH 0021/2320] Fixed: Incorrectly Cleansing TorrentLeech Search URL --- .../InstrumentationTests/CleanseLogMessageFixture.cs | 8 ++++++++ src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs index f6a84b1c9..04daad591 100644 --- a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs +++ b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs @@ -102,5 +102,13 @@ namespace NzbDrone.Common.Test.InstrumentationTests cleansedMessage.Should().Be(message); } + + [TestCase(@"https://www.torrentleech.org/torrents/browse/list/imdbID/tt8005374/categories/29,2,26,27,32,44,7,34,35")] + public void should_not_clean_url(string message) + { + var cleansedMessage = CleanseLogMessage.Cleanse(message); + + cleansedMessage.Should().Be(message); + } } } diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index 47c6fd93f..d64cc7ad5 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -13,8 +13,8 @@ namespace NzbDrone.Common.Instrumentation // Url new Regex(@"(?<=\?|&|: |;)(apikey|token|passkey|auth|authkey|user|uid|api|[a-z_]*apikey|account|passwd|pwd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"(?<=\?|&| )[^=]*?(_?(?<!use)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), - new Regex(@"torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), - new Regex(@"torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"rss\.torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"rss\.torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"/fetch/[a-z0-9]{32}/(?<secret>[a-z0-9]{32})", RegexOptions.Compiled), new Regex(@"getnzb.*?(?<=\?|&)(r)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), From 77892a3885a0675e9cc53a48a6fe9b28011cb7a6 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 13 Aug 2021 17:25:20 -0400 Subject: [PATCH 0022/2320] New: Sync Indexers with Mylar3 --- .../Applications/AppIndexerMap.cs | 1 + .../Applications/AppIndexerMapService.cs | 6 + .../Applications/ApplicationBase.cs | 4 +- .../Applications/ApplicationService.cs | 15 +- .../Applications/IApplication.cs | 2 +- .../Applications/Lidarr/Lidarr.cs | 6 +- src/NzbDrone.Core/Applications/Mylar/Mylar.cs | 154 ++++++++++++++ .../Applications/Mylar/MylarError.cs | 14 ++ .../Applications/Mylar/MylarException.cs | 23 +++ .../Applications/Mylar/MylarField.cs | 22 ++ .../Applications/Mylar/MylarIndexer.cs | 49 +++++ .../Applications/Mylar/MylarSettings.cs | 46 +++++ .../Applications/Mylar/MylarStatus.cs | 8 + .../Applications/Mylar/MylarV3Proxy.cs | 190 ++++++++++++++++++ .../Applications/Radarr/Radarr.cs | 6 +- .../Applications/Readarr/Readarr.cs | 8 +- .../Applications/Sonarr/Sonarr.cs | 6 +- .../Migration/011_app_indexer_remote_name.cs | 14 ++ 18 files changed, 553 insertions(+), 21 deletions(-) create mode 100644 src/NzbDrone.Core/Applications/Mylar/Mylar.cs create mode 100644 src/NzbDrone.Core/Applications/Mylar/MylarError.cs create mode 100644 src/NzbDrone.Core/Applications/Mylar/MylarException.cs create mode 100644 src/NzbDrone.Core/Applications/Mylar/MylarField.cs create mode 100644 src/NzbDrone.Core/Applications/Mylar/MylarIndexer.cs create mode 100644 src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs create mode 100644 src/NzbDrone.Core/Applications/Mylar/MylarStatus.cs create mode 100644 src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs create mode 100644 src/NzbDrone.Core/Datastore/Migration/011_app_indexer_remote_name.cs diff --git a/src/NzbDrone.Core/Applications/AppIndexerMap.cs b/src/NzbDrone.Core/Applications/AppIndexerMap.cs index bd91cb315..d1b36d3fb 100644 --- a/src/NzbDrone.Core/Applications/AppIndexerMap.cs +++ b/src/NzbDrone.Core/Applications/AppIndexerMap.cs @@ -7,5 +7,6 @@ namespace NzbDrone.Core.Applications public int IndexerId { get; set; } public int AppId { get; set; } public int RemoteIndexerId { get; set; } + public string RemoteIndexerName { get; set; } } } diff --git a/src/NzbDrone.Core/Applications/AppIndexerMapService.cs b/src/NzbDrone.Core/Applications/AppIndexerMapService.cs index cdfd59bd2..ed1733757 100644 --- a/src/NzbDrone.Core/Applications/AppIndexerMapService.cs +++ b/src/NzbDrone.Core/Applications/AppIndexerMapService.cs @@ -8,6 +8,7 @@ namespace NzbDrone.Core.Applications { List<AppIndexerMap> GetMappingsForApp(int appId); AppIndexerMap Insert(AppIndexerMap appIndexerMap); + AppIndexerMap Update(AppIndexerMap appIndexerMap); void Delete(int mappingId); void DeleteAllForApp(int appId); } @@ -41,6 +42,11 @@ namespace NzbDrone.Core.Applications return _appIndexerMapRepository.Insert(appIndexerMap); } + public AppIndexerMap Update(AppIndexerMap appIndexerMap) + { + return _appIndexerMapRepository.Update(appIndexerMap); + } + public void Handle(ProviderDeletedEvent<IApplication> message) { _appIndexerMapRepository.DeleteAllForApp(message.ProviderId); diff --git a/src/NzbDrone.Core/Applications/ApplicationBase.cs b/src/NzbDrone.Core/Applications/ApplicationBase.cs index 0317ad799..6989ad579 100644 --- a/src/NzbDrone.Core/Applications/ApplicationBase.cs +++ b/src/NzbDrone.Core/Applications/ApplicationBase.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Core.Applications protected readonly IAppIndexerMapService _appIndexerMapService; protected readonly Logger _logger; - protected static readonly Regex AppIndexerRegex = new Regex(@"\/(?<indexer>\d.)\/", + protected static readonly Regex AppIndexerRegex = new Regex(@"\/(?<indexer>\d.)\/?$", RegexOptions.IgnoreCase | RegexOptions.Compiled); public abstract string Name { get; } @@ -58,7 +58,7 @@ namespace NzbDrone.Core.Applications public abstract void AddIndexer(IndexerDefinition indexer); public abstract void UpdateIndexer(IndexerDefinition indexer); public abstract void RemoveIndexer(int indexerId); - public abstract Dictionary<int, int> GetIndexerMappings(); + public abstract List<AppIndexerMap> GetIndexerMappings(); public virtual object RequestAction(string action, IDictionary<string, string> query) { diff --git a/src/NzbDrone.Core/Applications/ApplicationService.cs b/src/NzbDrone.Core/Applications/ApplicationService.cs index 16344f70a..554fc1daa 100644 --- a/src/NzbDrone.Core/Applications/ApplicationService.cs +++ b/src/NzbDrone.Core/Applications/ApplicationService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using NLog; +using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Configuration.Events; using NzbDrone.Core.Indexers; @@ -110,9 +111,6 @@ namespace NzbDrone.Core.Applications { var indexerMappings = _appIndexerMapService.GetMappingsForApp(app.Definition.Id); - //Remote-Local mappings currently stored by Prowlarr - var prowlarrMappings = indexerMappings.ToDictionary(i => i.RemoteIndexerId, i => i.IndexerId); - //Get Dictionary of Remote Indexers point to Prowlarr and what they are mapped to var remoteMappings = ExecuteAction(a => a.GetIndexerMappings(), app); @@ -124,9 +122,16 @@ namespace NzbDrone.Core.Applications //Add mappings if not already in db, these were setup manually in the app or orphaned by a table wipe foreach (var mapping in remoteMappings) { - if (!prowlarrMappings.ContainsKey(mapping.Key)) + if (!indexerMappings.Any(m => (m.RemoteIndexerId > 0 && m.RemoteIndexerId == mapping.RemoteIndexerId) || (m.RemoteIndexerName.IsNotNullOrWhiteSpace() && m.RemoteIndexerName == mapping.RemoteIndexerName))) { - var addMapping = new AppIndexerMap { AppId = app.Definition.Id, RemoteIndexerId = mapping.Key, IndexerId = mapping.Value }; + var addMapping = new AppIndexerMap + { + AppId = app.Definition.Id, + RemoteIndexerId = mapping.RemoteIndexerId, + RemoteIndexerName = mapping.RemoteIndexerName, + IndexerId = mapping.IndexerId + }; + _appIndexerMapService.Insert(addMapping); indexerMappings.Add(addMapping); } diff --git a/src/NzbDrone.Core/Applications/IApplication.cs b/src/NzbDrone.Core/Applications/IApplication.cs index f947b59d8..5dd4572f5 100644 --- a/src/NzbDrone.Core/Applications/IApplication.cs +++ b/src/NzbDrone.Core/Applications/IApplication.cs @@ -9,6 +9,6 @@ namespace NzbDrone.Core.Applications void AddIndexer(IndexerDefinition indexer); void UpdateIndexer(IndexerDefinition indexer); void RemoveIndexer(int indexerId); - Dictionary<int, int> GetIndexerMappings(); + List<AppIndexerMap> GetIndexerMappings(); } } diff --git a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs index f8343eb92..f241fd850 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs @@ -55,12 +55,12 @@ namespace NzbDrone.Core.Applications.Lidarr return new ValidationResult(failures); } - public override Dictionary<int, int> GetIndexerMappings() + public override List<AppIndexerMap> GetIndexerMappings() { var indexers = _lidarrV1Proxy.GetIndexers(Settings) .Where(i => i.Implementation == "Newznab" || i.Implementation == "Torznab"); - var mappings = new Dictionary<int, int>(); + var mappings = new List<AppIndexerMap>(); foreach (var indexer in indexers) { @@ -71,7 +71,7 @@ namespace NzbDrone.Core.Applications.Lidarr if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId)) { //Add parsed mapping if it's mapped to a Indexer in this Prowlarr instance - mappings.Add(indexer.Id, indexerId); + mappings.Add(new AppIndexerMap { RemoteIndexerId = indexer.Id, IndexerId = indexerId }); } } } diff --git a/src/NzbDrone.Core/Applications/Mylar/Mylar.cs b/src/NzbDrone.Core/Applications/Mylar/Mylar.cs new file mode 100644 index 000000000..24590176d --- /dev/null +++ b/src/NzbDrone.Core/Applications/Mylar/Mylar.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using FluentValidation.Results; +using Newtonsoft.Json.Linq; +using NLog; +using NzbDrone.Common.Cache; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers; + +namespace NzbDrone.Core.Applications.Mylar +{ + public class Mylar : ApplicationBase<MylarSettings> + { + public override string Name => "Mylar"; + + private readonly IMylarV3Proxy _mylarV3Proxy; + private readonly IConfigFileProvider _configFileProvider; + + public Mylar(IMylarV3Proxy lidarrV1Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, Logger logger) + : base(appIndexerMapService, logger) + { + _mylarV3Proxy = lidarrV1Proxy; + _configFileProvider = configFileProvider; + } + + public override ValidationResult Test() + { + var failures = new List<ValidationFailure>(); + + try + { + failures.AddIfNotNull(_mylarV3Proxy.TestConnection(Settings)); + } + catch (WebException ex) + { + _logger.Error(ex, "Unable to send test message"); + failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Unable to complete application test, cannot connect to Mylar")); + } + + return new ValidationResult(failures); + } + + public override List<AppIndexerMap> GetIndexerMappings() + { + var indexers = _mylarV3Proxy.GetIndexers(Settings); + + var mappings = new List<AppIndexerMap>(); + + foreach (var indexer in indexers) + { + if (indexer.Apikey == _configFileProvider.ApiKey) + { + var match = AppIndexerRegex.Match(indexer.Host); + + if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId)) + { + //Add parsed mapping if it's mapped to a Indexer in this Prowlarr instance + mappings.Add(new AppIndexerMap { RemoteIndexerName = $"{indexer.Type},{indexer.Name}", IndexerId = indexerId }); + } + } + } + + return mappings; + } + + public override void AddIndexer(IndexerDefinition indexer) + { + if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) + { + var lidarrIndexer = BuildMylarIndexer(indexer, indexer.Protocol); + + var remoteIndexer = _mylarV3Proxy.AddIndexer(lidarrIndexer, Settings); + _appIndexerMapService.Insert(new AppIndexerMap { AppId = Definition.Id, IndexerId = indexer.Id, RemoteIndexerName = $"{remoteIndexer.Type},{remoteIndexer.Name}" }); + } + } + + public override void RemoveIndexer(int indexerId) + { + var appMappings = _appIndexerMapService.GetMappingsForApp(Definition.Id); + + var indexerMapping = appMappings.FirstOrDefault(m => m.IndexerId == indexerId); + + if (indexerMapping != null) + { + //Remove Indexer remotely and then remove the mapping + var indexerProps = indexerMapping.RemoteIndexerName.Split(","); + _mylarV3Proxy.RemoveIndexer(indexerProps[1], (MylarProviderType)Enum.Parse(typeof(MylarProviderType), indexerProps[0]), Settings); + _appIndexerMapService.Delete(indexerMapping.Id); + } + } + + public override void UpdateIndexer(IndexerDefinition indexer) + { + _logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id); + + var appMappings = _appIndexerMapService.GetMappingsForApp(Definition.Id); + var indexerMapping = appMappings.FirstOrDefault(m => m.IndexerId == indexer.Id); + var indexerProps = indexerMapping.RemoteIndexerName.Split(","); + + var mylarIndexer = BuildMylarIndexer(indexer, indexer.Protocol, indexerProps[1]); + + //Use the old remote id to find the indexer on Mylar incase the update was from a name change in Prowlarr + var remoteIndexer = _mylarV3Proxy.GetIndexer(indexerProps[1], mylarIndexer.Type, Settings); + + if (remoteIndexer != null) + { + _logger.Debug("Remote indexer found, syncing with current settings"); + + if (!mylarIndexer.Equals(remoteIndexer)) + { + _mylarV3Proxy.UpdateIndexer(mylarIndexer, Settings); + indexerMapping.RemoteIndexerName = $"{mylarIndexer.Type},{mylarIndexer.Altername}"; + _appIndexerMapService.Update(indexerMapping); + } + } + else + { + _appIndexerMapService.Delete(indexerMapping.Id); + + if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) + { + _logger.Debug("Remote indexer not found, re-adding {0} to Mylar", indexer.Name); + var newRemoteIndexer = _mylarV3Proxy.AddIndexer(mylarIndexer, Settings); + _appIndexerMapService.Insert(new AppIndexerMap { AppId = Definition.Id, IndexerId = indexer.Id, RemoteIndexerName = $"{newRemoteIndexer.Type},{newRemoteIndexer.Name}" }); + } + else + { + _logger.Debug("Remote indexer not found for {0}, skipping re-add to Mylar due to indexer capabilities", indexer.Name); + } + } + } + + private MylarIndexer BuildMylarIndexer(IndexerDefinition indexer, DownloadProtocol protocol, string originalName = null) + { + var schema = protocol == DownloadProtocol.Usenet ? MylarProviderType.Newznab : MylarProviderType.Torznab; + + var lidarrIndexer = new MylarIndexer + { + Name = originalName ?? $"{indexer.Name} (Prowlarr)", + Altername = $"{indexer.Name} (Prowlarr)", + Host = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}", + Apikey = _configFileProvider.ApiKey, + Categories = string.Join(",", indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray())), + Enabled = indexer.Enable, + Type = schema, + }; + + return lidarrIndexer; + } + } +} diff --git a/src/NzbDrone.Core/Applications/Mylar/MylarError.cs b/src/NzbDrone.Core/Applications/Mylar/MylarError.cs new file mode 100644 index 000000000..d7d18a2dd --- /dev/null +++ b/src/NzbDrone.Core/Applications/Mylar/MylarError.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NzbDrone.Core.Applications.Mylar +{ + public class MylarError + { + public int Code { get; set; } + public string Message { get; set; } + } +} diff --git a/src/NzbDrone.Core/Applications/Mylar/MylarException.cs b/src/NzbDrone.Core/Applications/Mylar/MylarException.cs new file mode 100644 index 000000000..af217c41d --- /dev/null +++ b/src/NzbDrone.Core/Applications/Mylar/MylarException.cs @@ -0,0 +1,23 @@ +using System; +using NzbDrone.Common.Exceptions; + +namespace NzbDrone.Core.Applications.Mylar +{ + public class MylarException : NzbDroneException + { + public MylarException(string message) + : base(message) + { + } + + public MylarException(string message, params object[] args) + : base(message, args) + { + } + + public MylarException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} diff --git a/src/NzbDrone.Core/Applications/Mylar/MylarField.cs b/src/NzbDrone.Core/Applications/Mylar/MylarField.cs new file mode 100644 index 000000000..909aec6f1 --- /dev/null +++ b/src/NzbDrone.Core/Applications/Mylar/MylarField.cs @@ -0,0 +1,22 @@ +namespace NzbDrone.Core.Applications.Mylar +{ + public class MylarField + { + public int Order { get; set; } + public string Name { get; set; } + public string Label { get; set; } + public string Unit { get; set; } + public string HelpText { get; set; } + public string HelpLink { get; set; } + public object Value { get; set; } + public string Type { get; set; } + public bool Advanced { get; set; } + public string Section { get; set; } + public string Hidden { get; set; } + + public MylarField Clone() + { + return (MylarField)MemberwiseClone(); + } + } +} diff --git a/src/NzbDrone.Core/Applications/Mylar/MylarIndexer.cs b/src/NzbDrone.Core/Applications/Mylar/MylarIndexer.cs new file mode 100644 index 000000000..da537f3b7 --- /dev/null +++ b/src/NzbDrone.Core/Applications/Mylar/MylarIndexer.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; + +namespace NzbDrone.Core.Applications.Mylar +{ + public class MylarIndexerResponse + { + public bool Success { get; set; } + public MylarIndexerData Data { get; set; } + public MylarError Error { get; set; } + } + + public class MylarIndexerData + { + public List<MylarIndexer> Torznabs { get; set; } + public List<MylarIndexer> Newznabs { get; set; } + } + + public enum MylarProviderType + { + Newznab, + Torznab + } + + public class MylarIndexer + { + public string Name { get; set; } + public string Host { get; set; } + public string Apikey { get; set; } + public string Categories { get; set; } + public bool Enabled { get; set; } + public string Altername { get; set; } + public MylarProviderType Type { get; set; } + + public bool Equals(MylarIndexer other) + { + if (ReferenceEquals(null, other)) + { + return false; + } + + return other.Host == Host && + other.Apikey == Apikey && + other.Name == Name && + other.Categories == Categories && + other.Enabled == Enabled && + other.Altername == Altername; + } + } +} diff --git a/src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs b/src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs new file mode 100644 index 000000000..250316528 --- /dev/null +++ b/src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Applications.Mylar +{ + public class MylarSettingsValidator : AbstractValidator<MylarSettings> + { + public MylarSettingsValidator() + { + RuleFor(c => c.BaseUrl).IsValidUrl(); + RuleFor(c => c.ProwlarrUrl).IsValidUrl(); + RuleFor(c => c.ApiKey).NotEmpty(); + } + } + + public class MylarSettings : IApplicationSettings + { + private static readonly MylarSettingsValidator Validator = new MylarSettingsValidator(); + + public MylarSettings() + { + ProwlarrUrl = "http://localhost:9696"; + BaseUrl = "http://localhost:8090"; + SyncCategories = new[] { NewznabStandardCategory.BooksComics.Id }; + } + + public IEnumerable<int> SyncCategories { get; set; } + + [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Mylar sees it, including http(s)://, port, and urlbase if needed")] + public string ProwlarrUrl { get; set; } + + [FieldDefinition(1, Label = "Mylar Server", HelpText = "Mylar server URL, including http(s):// and port if needed")] + public string BaseUrl { get; set; } + + [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Mylar in Settings/Web Interface")] + public string ApiKey { get; set; } + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} diff --git a/src/NzbDrone.Core/Applications/Mylar/MylarStatus.cs b/src/NzbDrone.Core/Applications/Mylar/MylarStatus.cs new file mode 100644 index 000000000..5cf431b57 --- /dev/null +++ b/src/NzbDrone.Core/Applications/Mylar/MylarStatus.cs @@ -0,0 +1,8 @@ +namespace NzbDrone.Core.Applications.Mylar +{ + public class MylarStatus + { + public bool Success { get; set; } + public MylarError Error { get; set; } + } +} diff --git a/src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs b/src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs new file mode 100644 index 000000000..bdd0654d8 --- /dev/null +++ b/src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using FluentValidation.Results; +using Newtonsoft.Json; +using NLog; +using NzbDrone.Common.Http; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Indexers; + +namespace NzbDrone.Core.Applications.Mylar +{ + public interface IMylarV3Proxy + { + MylarIndexer AddIndexer(MylarIndexer indexer, MylarSettings settings); + List<MylarIndexer> GetIndexers(MylarSettings settings); + MylarIndexer GetIndexer(string indexerName, MylarProviderType indexerType, MylarSettings settings); + void RemoveIndexer(string indexerName, MylarProviderType indexerType, MylarSettings settings); + MylarIndexer UpdateIndexer(MylarIndexer indexer, MylarSettings settings); + ValidationFailure TestConnection(MylarSettings settings); + } + + public class MylarV1Proxy : IMylarV3Proxy + { + private readonly IHttpClient _httpClient; + private readonly Logger _logger; + + public MylarV1Proxy(IHttpClient httpClient, Logger logger) + { + _httpClient = httpClient; + _logger = logger; + } + + public MylarStatus GetStatus(MylarSettings settings) + { + var request = BuildRequest(settings, "/api", "getVersion", HttpMethod.GET); + return Execute<MylarStatus>(request); + } + + public List<MylarIndexer> GetIndexers(MylarSettings settings) + { + var request = BuildRequest(settings, "/api", "listProviders", HttpMethod.GET); + + var response = Execute<MylarIndexerResponse>(request); + + if (!response.Success) + { + throw new MylarException(string.Format("Mylar Error - Code {0}: {1}", response.Error.Code, response.Error.Message)); + } + + var indexers = new List<MylarIndexer>(); + + var torIndexers = response.Data.Torznabs; + torIndexers.ForEach(i => i.Type = MylarProviderType.Torznab); + + var nzbIndexers = response.Data.Newznabs; + nzbIndexers.ForEach(i => i.Type = MylarProviderType.Newznab); + + indexers.AddRange(torIndexers); + indexers.AddRange(nzbIndexers); + indexers.ForEach(i => i.Altername = i.Name); + + return indexers; + } + + public MylarIndexer GetIndexer(string indexerName, MylarProviderType indexerType, MylarSettings settings) + { + var indexers = GetIndexers(settings); + + return indexers.SingleOrDefault(i => i.Name == indexerName && i.Type == indexerType); + } + + public void RemoveIndexer(string indexerName, MylarProviderType indexerType, MylarSettings settings) + { + var parameters = new Dictionary<string, string> + { + { "name", indexerName }, + { "providertype", indexerType.ToString().ToLower() } + }; + + var request = BuildRequest(settings, "/api", "delProvider", HttpMethod.GET, parameters); + CheckForError(Execute<MylarStatus>(request)); + } + + public MylarIndexer AddIndexer(MylarIndexer indexer, MylarSettings settings) + { + var parameters = new Dictionary<string, string> + { + { "name", indexer.Name }, + { "providertype", indexer.Type.ToString().ToLower() }, + { "host", indexer.Host }, + { "prov_apikey", indexer.Apikey }, + { "enabled", indexer.Enabled.ToString().ToLower() }, + { "categories", indexer.Categories } + }; + + var request = BuildRequest(settings, "/api", "addProvider", HttpMethod.GET, parameters); + CheckForError(Execute<MylarStatus>(request)); + return indexer; + } + + public MylarIndexer UpdateIndexer(MylarIndexer indexer, MylarSettings settings) + { + var parameters = new Dictionary<string, string> + { + { "name", indexer.Name }, + { "providertype", indexer.Type.ToString().ToLower() }, + { "host", indexer.Host }, + { "prov_apikey", indexer.Apikey }, + { "enabled", indexer.Enabled.ToString().ToLower() }, + { "categories", indexer.Categories }, + { "altername", indexer.Altername } + }; + + var request = BuildRequest(settings, "/api", "changeProvider", HttpMethod.GET, parameters); + CheckForError(Execute<MylarStatus>(request)); + return indexer; + } + + private void CheckForError(MylarStatus response) + { + if (!response.Success) + { + throw new MylarException(string.Format("Mylar Error - Code {0}: {1}", response.Error.Code, response.Error.Message)); + } + } + + public ValidationFailure TestConnection(MylarSettings settings) + { + try + { + var status = GetStatus(settings); + + if (!status.Success) + { + return new ValidationFailure("ApiKey", status.Error.Message); + } + } + catch (HttpException ex) + { + _logger.Error(ex, "Unable to send test message"); + return new ValidationFailure("BaseUrl", "Unable to complete application test"); + } + catch (Exception ex) + { + _logger.Error(ex, "Unable to send test message"); + return new ValidationFailure("", "Unable to send test message"); + } + + return null; + } + + private HttpRequest BuildRequest(MylarSettings settings, string resource, string command, HttpMethod method, Dictionary<string, string> parameters = null) + { + var baseUrl = settings.BaseUrl.TrimEnd('/'); + + var requestBuilder = new HttpRequestBuilder(baseUrl).Resource(resource) + .AddQueryParam("cmd", command) + .AddQueryParam("apikey", settings.ApiKey); + + if (parameters != null) + { + foreach (var param in parameters) + { + requestBuilder.AddQueryParam(param.Key, param.Value); + } + } + + var request = requestBuilder.Build(); + + request.Headers.ContentType = "application/json"; + + request.Method = method; + request.AllowAutoRedirect = true; + + return request; + } + + private TResource Execute<TResource>(HttpRequest request) + where TResource : new() + { + var response = _httpClient.Execute(request); + + var results = JsonConvert.DeserializeObject<TResource>(response.Content); + + return results; + } + } +} diff --git a/src/NzbDrone.Core/Applications/Radarr/Radarr.cs b/src/NzbDrone.Core/Applications/Radarr/Radarr.cs index 94f293125..0c5bcdfaa 100644 --- a/src/NzbDrone.Core/Applications/Radarr/Radarr.cs +++ b/src/NzbDrone.Core/Applications/Radarr/Radarr.cs @@ -55,12 +55,12 @@ namespace NzbDrone.Core.Applications.Radarr return new ValidationResult(failures); } - public override Dictionary<int, int> GetIndexerMappings() + public override List<AppIndexerMap> GetIndexerMappings() { var indexers = _radarrV3Proxy.GetIndexers(Settings) .Where(i => i.Implementation == "Newznab" || i.Implementation == "Torznab"); - var mappings = new Dictionary<int, int>(); + var mappings = new List<AppIndexerMap>(); foreach (var indexer in indexers) { @@ -71,7 +71,7 @@ namespace NzbDrone.Core.Applications.Radarr if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId)) { //Add parsed mapping if it's mapped to a Indexer in this Prowlarr instance - mappings.Add(indexer.Id, indexerId); + mappings.Add(new AppIndexerMap { RemoteIndexerId = indexer.Id, IndexerId = indexerId }); } } } diff --git a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs index 405bcadbb..b1205c5d1 100644 --- a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs +++ b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs @@ -55,12 +55,12 @@ namespace NzbDrone.Core.Applications.Readarr return new ValidationResult(failures); } - public override Dictionary<int, int> GetIndexerMappings() + public override List<AppIndexerMap> GetIndexerMappings() { var indexers = _readarrV1Proxy.GetIndexers(Settings) - .Where(i => i.Implementation == "Newznab" || i.Implementation == "Torznab"); + .Where(i => i.Implementation == "Newznab" || i.Implementation == "Torznab"); - var mappings = new Dictionary<int, int>(); + var mappings = new List<AppIndexerMap>(); foreach (var indexer in indexers) { @@ -71,7 +71,7 @@ namespace NzbDrone.Core.Applications.Readarr if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId)) { //Add parsed mapping if it's mapped to a Indexer in this Prowlarr instance - mappings.Add(indexer.Id, indexerId); + mappings.Add(new AppIndexerMap { RemoteIndexerId = indexer.Id, IndexerId = indexerId }); } } } diff --git a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs index 16fe2c641..9285d7498 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs @@ -55,12 +55,12 @@ namespace NzbDrone.Core.Applications.Sonarr return new ValidationResult(failures); } - public override Dictionary<int, int> GetIndexerMappings() + public override List<AppIndexerMap> GetIndexerMappings() { var indexers = _sonarrV3Proxy.GetIndexers(Settings) .Where(i => i.Implementation == "Newznab" || i.Implementation == "Torznab"); - var mappings = new Dictionary<int, int>(); + var mappings = new List<AppIndexerMap>(); foreach (var indexer in indexers) { @@ -71,7 +71,7 @@ namespace NzbDrone.Core.Applications.Sonarr if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId)) { //Add parsed mapping if it's mapped to a Indexer in this Prowlarr instance - mappings.Add(indexer.Id, indexerId); + mappings.Add(new AppIndexerMap { RemoteIndexerId = indexer.Id, IndexerId = indexerId }); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/011_app_indexer_remote_name.cs b/src/NzbDrone.Core/Datastore/Migration/011_app_indexer_remote_name.cs new file mode 100644 index 000000000..688124030 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/011_app_indexer_remote_name.cs @@ -0,0 +1,14 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(11)] + public class app_indexer_remote_name : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Alter.Table("ApplicationIndexerMapping").AddColumn("RemoteIndexerName").AsString().Nullable(); + } + } +} From 252b9a1b6b59b3949a000345c917e27aca52fc0b Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 14 Aug 2021 23:56:37 -0400 Subject: [PATCH 0023/2320] Fixed: (Sonarr) Correctly set anime categories --- src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs | 6 +++--- src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs index 9285d7498..589e8eb72 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs @@ -81,7 +81,7 @@ namespace NzbDrone.Core.Applications.Sonarr public override void AddIndexer(IndexerDefinition indexer) { - if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) + if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexer.Capabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any()) { var sonarrIndexer = BuildSonarrIndexer(indexer, indexer.Protocol); @@ -128,7 +128,7 @@ namespace NzbDrone.Core.Applications.Sonarr { _appIndexerMapService.Delete(indexerMapping.Id); - if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) + if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexer.Capabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any()) { _logger.Debug("Remote indexer not found, re-adding {0} to Sonarr", indexer.Name); sonarrIndexer.Id = 0; @@ -169,7 +169,7 @@ namespace NzbDrone.Core.Applications.Sonarr sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/api"; sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey; sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray())); - sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "animeCategories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray())); + sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "animeCategories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray())); return sonarrIndexer; } diff --git a/src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs b/src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs index eb12b7c6f..0ab030ca4 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs @@ -23,10 +23,12 @@ namespace NzbDrone.Core.Applications.Sonarr { ProwlarrUrl = "http://localhost:9696"; BaseUrl = "http://localhost:8989"; - SyncCategories = new[] { 5000, 5010, 5020, 5030, 5040, 5045, 5050, 5070 }; + SyncCategories = new[] { 5000, 5010, 5020, 5030, 5040, 5045, 5050 }; + AnimeSyncCategories = new[] { 5070 }; } public IEnumerable<int> SyncCategories { get; set; } + public IEnumerable<int> AnimeSyncCategories { get; set; } [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Sonarr sees it, including http(s)://, port, and urlbase if needed")] public string ProwlarrUrl { get; set; } From 31886e8d3524830a86ca3ab6234fc608ada8a817 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 15 Aug 2021 00:42:51 -0400 Subject: [PATCH 0024/2320] New: (Newznab) Parse PosterUrl when available --- .../Indexers/Definitions/Newznab/NewznabRssParser.cs | 6 ++++++ .../Indexers/Definitions/Torznab/TorznabRssParser.cs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs index 5fe15d65c..54c192eb4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs @@ -99,6 +99,7 @@ namespace NzbDrone.Core.Indexers.Newznab releaseInfo.ImdbId = GetImdbId(item); releaseInfo.Grabs = GetGrabs(item); releaseInfo.Files = GetFiles(item); + releaseInfo.PosterUrl = GetPosterUrl(item); return releaseInfo; } @@ -220,6 +221,11 @@ namespace NzbDrone.Core.Indexers.Newznab return 0; } + protected virtual string GetPosterUrl(XElement item) + { + return ParseUrl(TryGetNewznabAttribute(item, "coverurl")); + } + protected virtual int GetFiles(XElement item) { var filesString = TryGetNewznabAttribute(item, "files"); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs index 24e44fe56..58f493bbb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs @@ -62,6 +62,7 @@ namespace NzbDrone.Core.Indexers.Torznab } torrentInfo.IndexerFlags = GetFlags(item); + torrentInfo.PosterUrl = GetPosterUrl(item); } return torrentInfo; @@ -133,6 +134,11 @@ namespace NzbDrone.Core.Indexers.Torznab return !imdbIdString.IsNullOrWhiteSpace() ? imdbIdString.Substring(2) : null; } + protected virtual string GetPosterUrl(XElement item) + { + return ParseUrl(TryGetTorznabAttribute(item, "coverurl")); + } + protected override string GetInfoHash(XElement item) { return TryGetTorznabAttribute(item, "infohash"); From 7480ebea85843c361052c2e649c336ff553b1e9d Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 31 Jul 2021 16:30:41 -0400 Subject: [PATCH 0025/2320] New: Per Indexer Proxies Fixes #281 --- frontend/src/App/AppRoutes.js | 6 + frontend/src/Components/Form/InfoInput.js | 2 - .../Components/Page/Sidebar/PageSidebar.js | 4 + .../Indexer/Edit/EditIndexerModalContent.js | 13 ++ .../Edit/EditIndexerModalContentConnector.js | 1 - .../IndexerProxies/AddIndexerProxyItem.css | 44 +++++ .../IndexerProxies/AddIndexerProxyItem.js | 111 +++++++++++ .../IndexerProxies/AddIndexerProxyModal.js | 25 +++ .../AddIndexerProxyModalContent.css | 5 + .../AddIndexerProxyModalContent.js | 88 +++++++++ .../AddIndexerProxyModalContentConnector.js | 70 +++++++ .../AddIndexerProxyPresetMenuItem.js | 49 +++++ .../IndexerProxies/EditIndexerProxyModal.js | 27 +++ .../EditIndexerProxyModalConnector.js | 65 +++++++ .../EditIndexerProxyModalContent.css | 11 ++ .../EditIndexerProxyModalContent.js | 175 ++++++++++++++++++ .../EditIndexerProxyModalContentConnector.js | 88 +++++++++ .../IndexerProxies/IndexerProxies.css | 20 ++ .../Indexers/IndexerProxies/IndexerProxies.js | 121 ++++++++++++ .../IndexerProxies/IndexerProxiesConnector.js | 65 +++++++ .../Indexers/IndexerProxies/IndexerProxy.css | 23 +++ .../Indexers/IndexerProxies/IndexerProxy.js | 144 ++++++++++++++ .../src/Settings/Indexers/IndexerSettings.js | 22 +++ .../Tags/Details/TagDetailsDelayProfile.js | 47 ----- .../Tags/Details/TagDetailsModalContent.js | 91 ++------- .../TagDetailsModalContentConnector.js | 43 ++--- frontend/src/Settings/Tags/Tag.js | 52 ++---- frontend/src/Settings/Tags/TagsConnector.js | 12 +- .../Store/Actions/Settings/indexerProxies.js | 110 +++++++++++ frontend/src/Store/Actions/settingsActions.js | 5 + .../Http/Dispatchers/ManagedHttpDispatcher.cs | 2 +- src/NzbDrone.Common/Http/HttpClient.cs | 2 +- src/NzbDrone.Common/Http/HttpRequest.cs | 15 ++ .../AvistazTests/PrivateHDFixture.cs | 6 +- .../FileListTests/FileListFixture.cs | 6 +- .../IndexerTests/HDBitsTests/HDBitsFixture.cs | 12 +- .../NewznabCapabilitiesProviderFixture.cs | 41 ++-- .../NewznabTests/NewznabFixture.cs | 8 +- .../NewznabRequestGeneratorFixture.cs | 2 +- .../IndexerTests/PTPTests/PTPFixture.cs | 12 +- .../IndexerTests/RarbgTests/RarbgFixture.cs | 18 +- .../IndexerTests/TestIndexer.cs | 2 +- .../TorznabTests/TorznabFixture.cs | 20 +- .../Migration/010_indexer_proxies.cs | 21 +++ src/NzbDrone.Core/Datastore/TableMapping.cs | 5 +- .../HealthCheck/Checks/IndexerProxyCheck.cs | 92 +++++++++ src/NzbDrone.Core/IndexerProxies/Http/Http.cs | 34 ++++ .../IndexerProxies/Http/HttpSettings.cs | 43 +++++ .../IndexerProxies/HttpIndexerProxyBase.cs | 61 ++++++ .../IndexerProxies/IIndexerProxy.cs | 11 ++ .../IndexerProxies/IIndexerProxySettings.cs | 9 + .../IndexerProxies/IndexerProxyBase.cs | 52 ++++++ .../IndexerProxies/IndexerProxyDefinition.cs | 10 + .../IndexerProxies/IndexerProxyFactory.cs | 21 +++ .../IndexerProxies/IndexerProxyRepository.cs | 24 +++ .../IndexerProxies/IndexerProxyService.cs | 19 ++ .../IndexerProxies/Socks4/Socks4.cs | 66 +++++++ .../IndexerProxies/Socks4/Socks4Settings.cs | 43 +++++ .../IndexerProxies/Socks5/Socks5.cs | 67 +++++++ .../IndexerProxies/Socks5/Socks5Settings.cs | 43 +++++ .../Indexers/Definitions/Aither.cs | 2 +- .../Indexers/Definitions/AlphaRatio.cs | 2 +- .../Indexers/Definitions/Anidub.cs | 6 +- .../Indexers/Definitions/Anilibria.cs | 2 +- .../Indexers/Definitions/AnimeBytes.cs | 2 +- .../Indexers/Definitions/AnimeTorrents.cs | 4 +- .../Indexers/Definitions/AnimeWorld.cs | 2 +- .../Indexers/Definitions/Animedia.cs | 4 +- .../Indexers/Definitions/Anthelion.cs | 2 +- .../Indexers/Definitions/AvistaZ.cs | 2 +- .../Definitions/Avistaz/AvistazBase.cs | 2 +- .../Avistaz/AvistazRequestGenerator.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/BB.cs | 2 +- .../Indexers/Definitions/BakaBT.cs | 6 +- .../Indexers/Definitions/BeyondHD.cs | 2 +- .../Indexers/Definitions/BinSearch.cs | 2 +- .../Indexers/Definitions/Blutopia.cs | 2 +- .../BroadcastheNet/BroadcastheNet.cs | 2 +- .../Indexers/Definitions/BrokenStones.cs | 2 +- .../Indexers/Definitions/CGPeers.cs | 2 +- .../Definitions/Cardigann/Cardigann.cs | 5 +- .../Cardigann/CardigannRequestGenerator.cs | 24 +-- .../Indexers/Definitions/CinemaZ.cs | 2 +- .../Indexers/Definitions/DanishBytes.cs | 2 +- .../Indexers/Definitions/DigitalCore.cs | 2 +- .../Indexers/Definitions/ExoticaZ.cs | 2 +- .../Indexers/Definitions/FileList/FileList.cs | 2 +- .../Indexers/Definitions/Gazelle/Gazelle.cs | 2 +- .../Gazelle/GazelleRequestGenerator.cs | 2 +- .../Indexers/Definitions/GazelleGames.cs | 2 +- .../Indexers/Definitions/HDBits/HDBits.cs | 2 +- .../Indexers/Definitions/HDSpace.cs | 4 +- .../Indexers/Definitions/HDTorrents.cs | 2 +- .../Definitions/Headphones/Headphones.cs | 4 +- .../Indexers/Definitions/IPTorrents.cs | 2 +- .../Indexers/Definitions/ImmortalSeed.cs | 2 +- .../Indexers/Definitions/InternetArchive.cs | 2 +- .../Indexers/Definitions/Milkie.cs | 2 +- .../Indexers/Definitions/MyAnonamouse.cs | 2 +- .../Indexers/Definitions/Nebulance.cs | 2 +- .../Indexers/Definitions/Newznab/Newznab.cs | 8 +- .../Newznab/NewznabCapabilitiesProvider.cs | 16 +- .../Newznab/NewznabRequestGenerator.cs | 12 +- .../Indexers/Definitions/NotWhatCD.cs | 2 +- .../Indexers/Definitions/Orpheus.cs | 2 +- .../PassThePopcorn/PassThePopcorn.cs | 2 +- .../PassThePopcornRequestGenerator.cs | 2 +- .../Indexers/Definitions/PreToMe.cs | 4 +- .../Indexers/Definitions/PrivateHD.cs | 2 +- .../Indexers/Definitions/Rarbg/Rarbg.cs | 2 +- .../Definitions/Rarbg/RarbgTokenProvider.cs | 4 +- .../Indexers/Definitions/Redacted.cs | 4 +- .../Indexers/Definitions/RevolutionTT.cs | 4 +- .../Indexers/Definitions/RuTracker.cs | 2 +- .../Indexers/Definitions/SceneTime.cs | 2 +- .../Indexers/Definitions/SecretCinema.cs | 2 +- .../Indexers/Definitions/ShareIsland.cs | 2 +- .../Indexers/Definitions/Shizaproject.cs | 2 +- .../Indexers/Definitions/ShowRSS.cs | 2 +- .../Indexers/Definitions/SpeedApp.cs | 4 +- .../Indexers/Definitions/SubsPlease.cs | 2 +- .../Indexers/Definitions/SuperBits.cs | 2 +- .../Indexers/Definitions/TVVault.cs | 2 +- .../Indexers/Definitions/ThePirateBay.cs | 2 +- .../Indexers/Definitions/TorrentDay.cs | 2 +- .../Indexers/Definitions/TorrentLeech.cs | 2 +- .../Indexers/Definitions/TorrentParadiseMl.cs | 2 +- .../TorrentPotato/TorrentPotato.cs | 2 +- .../Indexers/Definitions/TorrentSeeds.cs | 6 +- .../Indexers/Definitions/TorrentSyndikat.cs | 2 +- .../Indexers/Definitions/TorrentsCSV.cs | 2 +- .../Indexers/Definitions/Torznab/Torznab.cs | 8 +- .../Indexers/Definitions/UNIT3D/Unit3dBase.cs | 2 +- .../UNIT3D/Unit3dRequestGenerator.cs | 2 +- .../Indexers/Definitions/Xthor/Xthor.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/YTS.cs | 2 +- .../Indexers/Definitions/ZonaQ.cs | 6 +- src/NzbDrone.Core/Indexers/HttpIndexerBase.cs | 10 +- src/NzbDrone.Core/Indexers/IndexerFactory.cs | 4 +- .../Indexers/IndexerHttpClient.cs | 96 ++++++++++ src/NzbDrone.Core/Indexers/IndexerRequest.cs | 2 +- .../Indexers/TorrentIndexerBase.cs | 2 +- .../Indexers/UsenetIndexerBase.cs | 2 +- src/NzbDrone.Core/Localization/Core/en.json | 8 + src/NzbDrone.Core/Tags/TagDetails.cs | 4 +- src/NzbDrone.Core/Tags/TagService.cs | 22 ++- .../IndexerProxies/IndexerProxyController.cs | 16 ++ .../IndexerProxies/IndexerProxyResource.cs | 40 ++++ .../Tags/TagDetailsResource.cs | 6 +- 149 files changed, 2374 insertions(+), 393 deletions(-) create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyItem.css create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyItem.js create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModal.js create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContent.css create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContent.js create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContentConnector.js create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyPresetMenuItem.js create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModal.js create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalConnector.js create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalContent.css create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalContent.js create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalContentConnector.js create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.css create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.js create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/IndexerProxiesConnector.js create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/IndexerProxy.css create mode 100644 frontend/src/Settings/Indexers/IndexerProxies/IndexerProxy.js create mode 100644 frontend/src/Settings/Indexers/IndexerSettings.js delete mode 100644 frontend/src/Settings/Tags/Details/TagDetailsDelayProfile.js create mode 100644 frontend/src/Store/Actions/Settings/indexerProxies.js create mode 100644 src/NzbDrone.Core/Datastore/Migration/010_indexer_proxies.cs create mode 100644 src/NzbDrone.Core/HealthCheck/Checks/IndexerProxyCheck.cs create mode 100644 src/NzbDrone.Core/IndexerProxies/Http/Http.cs create mode 100644 src/NzbDrone.Core/IndexerProxies/Http/HttpSettings.cs create mode 100644 src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs create mode 100644 src/NzbDrone.Core/IndexerProxies/IIndexerProxy.cs create mode 100644 src/NzbDrone.Core/IndexerProxies/IIndexerProxySettings.cs create mode 100644 src/NzbDrone.Core/IndexerProxies/IndexerProxyBase.cs create mode 100644 src/NzbDrone.Core/IndexerProxies/IndexerProxyDefinition.cs create mode 100644 src/NzbDrone.Core/IndexerProxies/IndexerProxyFactory.cs create mode 100644 src/NzbDrone.Core/IndexerProxies/IndexerProxyRepository.cs create mode 100644 src/NzbDrone.Core/IndexerProxies/IndexerProxyService.cs create mode 100644 src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs create mode 100644 src/NzbDrone.Core/IndexerProxies/Socks4/Socks4Settings.cs create mode 100644 src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs create mode 100644 src/NzbDrone.Core/IndexerProxies/Socks5/Socks5Settings.cs create mode 100644 src/NzbDrone.Core/Indexers/IndexerHttpClient.cs create mode 100644 src/Prowlarr.Api.V1/IndexerProxies/IndexerProxyController.cs create mode 100644 src/Prowlarr.Api.V1/IndexerProxies/IndexerProxyResource.cs diff --git a/frontend/src/App/AppRoutes.js b/frontend/src/App/AppRoutes.js index d9ff7b470..bf08d82b1 100644 --- a/frontend/src/App/AppRoutes.js +++ b/frontend/src/App/AppRoutes.js @@ -11,6 +11,7 @@ import ApplicationSettingsConnector from 'Settings/Applications/ApplicationSetti import DevelopmentSettingsConnector from 'Settings/Development/DevelopmentSettingsConnector'; import DownloadClientSettingsConnector from 'Settings/DownloadClients/DownloadClientSettingsConnector'; import GeneralSettingsConnector from 'Settings/General/GeneralSettingsConnector'; +import IndexerSettings from 'Settings/Indexers/IndexerSettings'; import NotificationSettings from 'Settings/Notifications/NotificationSettings'; import Settings from 'Settings/Settings'; import TagSettings from 'Settings/Tags/TagSettings'; @@ -90,6 +91,11 @@ function AppRoutes(props) { component={Settings} /> + <Route + path="/settings/indexers" + component={IndexerSettings} + /> + <Route path="/settings/applications" component={ApplicationSettingsConnector} diff --git a/frontend/src/Components/Form/InfoInput.js b/frontend/src/Components/Form/InfoInput.js index f5fb9b15c..eb3e9dee3 100644 --- a/frontend/src/Components/Form/InfoInput.js +++ b/frontend/src/Components/Form/InfoInput.js @@ -11,8 +11,6 @@ class InfoInput extends Component { value } = this.props; - console.log(this.props); - return ( <span dangerouslySetInnerHTML={{ __html: value }} /> ); diff --git a/frontend/src/Components/Page/Sidebar/PageSidebar.js b/frontend/src/Components/Page/Sidebar/PageSidebar.js index 42db980a9..9de449f95 100644 --- a/frontend/src/Components/Page/Sidebar/PageSidebar.js +++ b/frontend/src/Components/Page/Sidebar/PageSidebar.js @@ -48,6 +48,10 @@ const links = [ title: translate('Settings'), to: '/settings', children: [ + { + title: translate('Indexers'), + to: '/settings/indexers' + }, { title: translate('Apps'), to: '/settings/applications' diff --git a/frontend/src/Indexer/Edit/EditIndexerModalContent.js b/frontend/src/Indexer/Edit/EditIndexerModalContent.js index 2a7c7a6ee..2cc55b8a2 100644 --- a/frontend/src/Indexer/Edit/EditIndexerModalContent.js +++ b/frontend/src/Indexer/Edit/EditIndexerModalContent.js @@ -45,6 +45,7 @@ function EditIndexerModalContent(props) { supportsRss, supportsRedirect, appProfileId, + tags, fields, priority } = item; @@ -151,6 +152,18 @@ function EditIndexerModalContent(props) { onChange={onInputChange} /> </FormGroup> + + <FormGroup> + <FormLabel>{translate('Tags')}</FormLabel> + + <FormInputGroup + type={inputTypes.TAG} + name="tags" + helpText="Use tags to specify default clients, specify Indexer Proxies, or just to organize your indexers." + {...tags} + onChange={onInputChange} + /> + </FormGroup> </Form> } </ModalBody> diff --git a/frontend/src/Indexer/Edit/EditIndexerModalContentConnector.js b/frontend/src/Indexer/Edit/EditIndexerModalContentConnector.js index de0120f90..676457a12 100644 --- a/frontend/src/Indexer/Edit/EditIndexerModalContentConnector.js +++ b/frontend/src/Indexer/Edit/EditIndexerModalContentConnector.js @@ -59,7 +59,6 @@ class EditIndexerModalContentConnector extends Component { } onAdvancedSettingsPress = () => { - console.log('settings'); this.props.toggleAdvancedSettings(); } diff --git a/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyItem.css b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyItem.css new file mode 100644 index 000000000..81e135559 --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyItem.css @@ -0,0 +1,44 @@ +.indexerProxy { + composes: card from '~Components/Card.css'; + + position: relative; + width: 300px; + height: 100px; +} + +.underlay { + @add-mixin cover; +} + +.overlay { + @add-mixin linkOverlay; + + padding: 10px; +} + +.name { + text-align: center; + font-weight: lighter; + font-size: 24px; +} + +.actions { + margin-top: 20px; + text-align: right; +} + +.presetsMenu { + composes: menu from '~Components/Menu/Menu.css'; + + display: inline-block; + margin: 0 5px; +} + +.presetsMenuButton { + composes: button from '~Components/Link/Button.css'; + + &::after { + margin-left: 5px; + content: '\25BE'; + } +} diff --git a/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyItem.js b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyItem.js new file mode 100644 index 000000000..73e6454a9 --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyItem.js @@ -0,0 +1,111 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +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 { sizes } from 'Helpers/Props'; +import translate from 'Utilities/String/translate'; +import AddIndexerProxyPresetMenuItem from './AddIndexerProxyPresetMenuItem'; +import styles from './AddIndexerProxyItem.css'; + +class AddIndexerProxyItem extends Component { + + // + // Listeners + + onIndexerProxySelect = () => { + const { + implementation + } = this.props; + + this.props.onIndexerProxySelect({ implementation }); + } + + // + // Render + + render() { + const { + implementation, + implementationName, + infoLink, + presets, + onIndexerProxySelect + } = this.props; + + const hasPresets = !!presets && !!presets.length; + + return ( + <div + className={styles.indexerProxy} + > + <Link + className={styles.underlay} + onPress={this.onIndexerProxySelect} + /> + + <div className={styles.overlay}> + <div className={styles.name}> + {implementationName} + </div> + + <div className={styles.actions}> + { + hasPresets && + <span> + <Button + size={sizes.SMALL} + onPress={this.onIndexerProxySelect} + > + Custom + </Button> + + <Menu className={styles.presetsMenu}> + <Button + className={styles.presetsMenuButton} + size={sizes.SMALL} + > + Presets + </Button> + + <MenuContent> + { + presets.map((preset) => { + return ( + <AddIndexerProxyPresetMenuItem + key={preset.name} + name={preset.name} + implementation={implementation} + onPress={onIndexerProxySelect} + /> + ); + }) + } + </MenuContent> + </Menu> + </span> + } + + <Button + to={infoLink} + size={sizes.SMALL} + > + {translate('MoreInfo')} + </Button> + </div> + </div> + </div> + ); + } +} + +AddIndexerProxyItem.propTypes = { + implementation: PropTypes.string.isRequired, + implementationName: PropTypes.string.isRequired, + infoLink: PropTypes.string.isRequired, + presets: PropTypes.arrayOf(PropTypes.object), + onIndexerProxySelect: PropTypes.func.isRequired +}; + +export default AddIndexerProxyItem; diff --git a/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModal.js b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModal.js new file mode 100644 index 000000000..55550d3c5 --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModal.js @@ -0,0 +1,25 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import Modal from 'Components/Modal/Modal'; +import AddIndexerProxyModalContentConnector from './AddIndexerProxyModalContentConnector'; + +function AddIndexerProxyModal({ isOpen, onModalClose, ...otherProps }) { + return ( + <Modal + isOpen={isOpen} + onModalClose={onModalClose} + > + <AddIndexerProxyModalContentConnector + {...otherProps} + onModalClose={onModalClose} + /> + </Modal> + ); +} + +AddIndexerProxyModal.propTypes = { + isOpen: PropTypes.bool.isRequired, + onModalClose: PropTypes.func.isRequired +}; + +export default AddIndexerProxyModal; diff --git a/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContent.css b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContent.css new file mode 100644 index 000000000..89168dc33 --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContent.css @@ -0,0 +1,5 @@ +.indexerProxies { + display: flex; + justify-content: center; + flex-wrap: wrap; +} diff --git a/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContent.js b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContent.js new file mode 100644 index 000000000..f00a05bd5 --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContent.js @@ -0,0 +1,88 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import Button from 'Components/Link/Button'; +import LoadingIndicator from 'Components/Loading/LoadingIndicator'; +import ModalBody from 'Components/Modal/ModalBody'; +import ModalContent from 'Components/Modal/ModalContent'; +import ModalFooter from 'Components/Modal/ModalFooter'; +import ModalHeader from 'Components/Modal/ModalHeader'; +import translate from 'Utilities/String/translate'; +import AddIndexerProxyItem from './AddIndexerProxyItem'; +import styles from './AddIndexerProxyModalContent.css'; + +class AddIndexerProxyModalContent extends Component { + + // + // Render + + render() { + const { + isSchemaFetching, + isSchemaPopulated, + schemaError, + schema, + onIndexerProxySelect, + onModalClose + } = this.props; + + return ( + <ModalContent onModalClose={onModalClose}> + <ModalHeader> + Add IndexerProxy + </ModalHeader> + + <ModalBody> + { + isSchemaFetching && + <LoadingIndicator /> + } + + { + !isSchemaFetching && !!schemaError && + <div> + {translate('UnableToAddANewIndexerProxyPleaseTryAgain')} + </div> + } + + { + isSchemaPopulated && !schemaError && + <div> + <div className={styles.indexerProxies}> + { + schema.map((indexerProxy) => { + return ( + <AddIndexerProxyItem + key={indexerProxy.implementation} + implementation={indexerProxy.implementation} + {...indexerProxy} + onIndexerProxySelect={onIndexerProxySelect} + /> + ); + }) + } + </div> + </div> + } + </ModalBody> + <ModalFooter> + <Button + onPress={onModalClose} + > + {translate('Close')} + </Button> + </ModalFooter> + </ModalContent> + ); + } +} + +AddIndexerProxyModalContent.propTypes = { + isSchemaFetching: PropTypes.bool.isRequired, + isSchemaPopulated: PropTypes.bool.isRequired, + schemaError: PropTypes.object, + schema: PropTypes.arrayOf(PropTypes.object).isRequired, + onIndexerProxySelect: PropTypes.func.isRequired, + onModalClose: PropTypes.func.isRequired +}; + +export default AddIndexerProxyModalContent; diff --git a/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContentConnector.js b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContentConnector.js new file mode 100644 index 000000000..cccafe922 --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContentConnector.js @@ -0,0 +1,70 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import { fetchIndexerProxySchema, selectIndexerProxySchema } from 'Store/Actions/settingsActions'; +import AddIndexerProxyModalContent from './AddIndexerProxyModalContent'; + +function createMapStateToProps() { + return createSelector( + (state) => state.settings.indexerProxies, + (indexerProxies) => { + const { + isSchemaFetching, + isSchemaPopulated, + schemaError, + schema + } = indexerProxies; + + return { + isSchemaFetching, + isSchemaPopulated, + schemaError, + schema + }; + } + ); +} + +const mapDispatchToProps = { + fetchIndexerProxySchema, + selectIndexerProxySchema +}; + +class AddIndexerProxyModalContentConnector extends Component { + + // + // Lifecycle + + componentDidMount() { + this.props.fetchIndexerProxySchema(); + } + + // + // Listeners + + onIndexerProxySelect = ({ implementation, name }) => { + this.props.selectIndexerProxySchema({ implementation, presetName: name }); + this.props.onModalClose({ indexerProxySelected: true }); + } + + // + // Render + + render() { + return ( + <AddIndexerProxyModalContent + {...this.props} + onIndexerProxySelect={this.onIndexerProxySelect} + /> + ); + } +} + +AddIndexerProxyModalContentConnector.propTypes = { + fetchIndexerProxySchema: PropTypes.func.isRequired, + selectIndexerProxySchema: PropTypes.func.isRequired, + onModalClose: PropTypes.func.isRequired +}; + +export default connect(createMapStateToProps, mapDispatchToProps)(AddIndexerProxyModalContentConnector); diff --git a/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyPresetMenuItem.js b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyPresetMenuItem.js new file mode 100644 index 000000000..52ee40c10 --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyPresetMenuItem.js @@ -0,0 +1,49 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import MenuItem from 'Components/Menu/MenuItem'; + +class AddIndexerProxyPresetMenuItem extends Component { + + // + // Listeners + + onPress = () => { + const { + name, + implementation + } = this.props; + + this.props.onPress({ + name, + implementation + }); + } + + // + // Render + + render() { + const { + name, + implementation, + ...otherProps + } = this.props; + + return ( + <MenuItem + {...otherProps} + onPress={this.onPress} + > + {name} + </MenuItem> + ); + } +} + +AddIndexerProxyPresetMenuItem.propTypes = { + name: PropTypes.string.isRequired, + implementation: PropTypes.string.isRequired, + onPress: PropTypes.func.isRequired +}; + +export default AddIndexerProxyPresetMenuItem; diff --git a/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModal.js b/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModal.js new file mode 100644 index 000000000..adacde9c3 --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModal.js @@ -0,0 +1,27 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import Modal from 'Components/Modal/Modal'; +import { sizes } from 'Helpers/Props'; +import EditIndexerProxyModalContentConnector from './EditIndexerProxyModalContentConnector'; + +function EditIndexerProxyModal({ isOpen, onModalClose, ...otherProps }) { + return ( + <Modal + size={sizes.MEDIUM} + isOpen={isOpen} + onModalClose={onModalClose} + > + <EditIndexerProxyModalContentConnector + {...otherProps} + onModalClose={onModalClose} + /> + </Modal> + ); +} + +EditIndexerProxyModal.propTypes = { + isOpen: PropTypes.bool.isRequired, + onModalClose: PropTypes.func.isRequired +}; + +export default EditIndexerProxyModal; diff --git a/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalConnector.js b/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalConnector.js new file mode 100644 index 000000000..a1a6563e7 --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalConnector.js @@ -0,0 +1,65 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { clearPendingChanges } from 'Store/Actions/baseActions'; +import { cancelSaveIndexerProxy, cancelTestIndexerProxy } from 'Store/Actions/settingsActions'; +import EditIndexerProxyModal from './EditIndexerProxyModal'; + +function createMapDispatchToProps(dispatch, props) { + const section = 'settings.indexerProxies'; + + return { + dispatchClearPendingChanges() { + dispatch(clearPendingChanges({ section })); + }, + + dispatchCancelTestIndexerProxy() { + dispatch(cancelTestIndexerProxy({ section })); + }, + + dispatchCancelSaveIndexerProxy() { + dispatch(cancelSaveIndexerProxy({ section })); + } + }; +} + +class EditIndexerProxyModalConnector extends Component { + + // + // Listeners + + onModalClose = () => { + this.props.dispatchClearPendingChanges(); + this.props.dispatchCancelTestIndexerProxy(); + this.props.dispatchCancelSaveIndexerProxy(); + this.props.onModalClose(); + } + + // + // Render + + render() { + const { + dispatchClearPendingChanges, + dispatchCancelTestIndexerProxy, + dispatchCancelSaveIndexerProxy, + ...otherProps + } = this.props; + + return ( + <EditIndexerProxyModal + {...otherProps} + onModalClose={this.onModalClose} + /> + ); + } +} + +EditIndexerProxyModalConnector.propTypes = { + onModalClose: PropTypes.func.isRequired, + dispatchClearPendingChanges: PropTypes.func.isRequired, + dispatchCancelTestIndexerProxy: PropTypes.func.isRequired, + dispatchCancelSaveIndexerProxy: PropTypes.func.isRequired +}; + +export default connect(null, createMapDispatchToProps)(EditIndexerProxyModalConnector); diff --git a/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalContent.css b/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalContent.css new file mode 100644 index 000000000..8e1c16507 --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalContent.css @@ -0,0 +1,11 @@ +.deleteButton { + composes: button from '~Components/Link/Button.css'; + + margin-right: auto; +} + +.message { + composes: alert from '~Components/Alert.css'; + + margin-bottom: 30px; +} diff --git a/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalContent.js b/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalContent.js new file mode 100644 index 000000000..59ce4e820 --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalContent.js @@ -0,0 +1,175 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import Alert from 'Components/Alert'; +import Form from 'Components/Form/Form'; +import FormGroup from 'Components/Form/FormGroup'; +import FormInputGroup from 'Components/Form/FormInputGroup'; +import FormLabel from 'Components/Form/FormLabel'; +import ProviderFieldFormGroup from 'Components/Form/ProviderFieldFormGroup'; +import Button from 'Components/Link/Button'; +import SpinnerErrorButton from 'Components/Link/SpinnerErrorButton'; +import LoadingIndicator from 'Components/Loading/LoadingIndicator'; +import ModalBody from 'Components/Modal/ModalBody'; +import ModalContent from 'Components/Modal/ModalContent'; +import ModalFooter from 'Components/Modal/ModalFooter'; +import ModalHeader from 'Components/Modal/ModalHeader'; +import { inputTypes, kinds } from 'Helpers/Props'; +import translate from 'Utilities/String/translate'; +import styles from './EditIndexerProxyModalContent.css'; + +function EditIndexerProxyModalContent(props) { + const { + advancedSettings, + isFetching, + error, + isSaving, + isTesting, + saveError, + item, + onInputChange, + onFieldChange, + onModalClose, + onSavePress, + onTestPress, + onDeleteIndexerProxyPress, + ...otherProps + } = props; + + const { + id, + implementationName, + name, + tags, + fields, + message + } = item; + + return ( + <ModalContent onModalClose={onModalClose}> + <ModalHeader> + {`${id ? 'Edit' : 'Add'} Proxy - ${implementationName}`} + </ModalHeader> + + <ModalBody> + { + isFetching && + <LoadingIndicator /> + } + + { + !isFetching && !!error && + <div> + {translate('UnableToAddANewIndexerProxyPleaseTryAgain')} + </div> + } + + { + !isFetching && !error && + <Form {...otherProps}> + { + !!message && + <Alert + className={styles.message} + kind={message.value.type} + > + {message.value.message} + </Alert> + } + + <FormGroup> + <FormLabel>{translate('Name')}</FormLabel> + + <FormInputGroup + type={inputTypes.TEXT} + name="name" + {...name} + onChange={onInputChange} + /> + </FormGroup> + + <FormGroup> + <FormLabel>{translate('Tags')}</FormLabel> + + <FormInputGroup + type={inputTypes.TAG} + name="tags" + helpText={translate('TagsHelpText')} + {...tags} + onChange={onInputChange} + /> + </FormGroup> + + { + fields.map((field) => { + return ( + <ProviderFieldFormGroup + key={field.name} + advancedSettings={advancedSettings} + provider="indexerProxy" + providerData={item} + section="settings.indexerProxies" + {...field} + onChange={onFieldChange} + /> + ); + }) + } + + </Form> + } + </ModalBody> + <ModalFooter> + { + id && + <Button + className={styles.deleteButton} + kind={kinds.DANGER} + onPress={onDeleteIndexerProxyPress} + > + {translate('Delete')} + </Button> + } + + <SpinnerErrorButton + isSpinning={isTesting} + error={saveError} + onPress={onTestPress} + > + {translate('Test')} + </SpinnerErrorButton> + + <Button + onPress={onModalClose} + > + {translate('Cancel')} + </Button> + + <SpinnerErrorButton + isSpinning={isSaving} + error={saveError} + onPress={onSavePress} + > + {translate('Save')} + </SpinnerErrorButton> + </ModalFooter> + </ModalContent> + ); +} + +EditIndexerProxyModalContent.propTypes = { + advancedSettings: PropTypes.bool.isRequired, + isFetching: PropTypes.bool.isRequired, + error: PropTypes.object, + isSaving: PropTypes.bool.isRequired, + isTesting: PropTypes.bool.isRequired, + saveError: PropTypes.object, + item: PropTypes.object.isRequired, + onInputChange: PropTypes.func.isRequired, + onFieldChange: PropTypes.func.isRequired, + onModalClose: PropTypes.func.isRequired, + onSavePress: PropTypes.func.isRequired, + onTestPress: PropTypes.func.isRequired, + onDeleteIndexerProxyPress: PropTypes.func +}; + +export default EditIndexerProxyModalContent; diff --git a/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalContentConnector.js b/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalContentConnector.js new file mode 100644 index 000000000..01db7709b --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalContentConnector.js @@ -0,0 +1,88 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import { saveIndexerProxy, setIndexerProxyFieldValue, setIndexerProxyValue, testIndexerProxy } from 'Store/Actions/settingsActions'; +import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector'; +import EditIndexerProxyModalContent from './EditIndexerProxyModalContent'; + +function createMapStateToProps() { + return createSelector( + (state) => state.settings.advancedSettings, + createProviderSettingsSelector('indexerProxies'), + (advancedSettings, indexerProxy) => { + return { + advancedSettings, + ...indexerProxy + }; + } + ); +} + +const mapDispatchToProps = { + setIndexerProxyValue, + setIndexerProxyFieldValue, + saveIndexerProxy, + testIndexerProxy +}; + +class EditIndexerProxyModalContentConnector extends Component { + + // + // Lifecycle + + componentDidUpdate(prevProps, prevState) { + if (prevProps.isSaving && !this.props.isSaving && !this.props.saveError) { + this.props.onModalClose(); + } + } + + // + // Listeners + + onInputChange = ({ name, value }) => { + this.props.setIndexerProxyValue({ name, value }); + } + + onFieldChange = ({ name, value }) => { + this.props.setIndexerProxyFieldValue({ name, value }); + } + + onSavePress = () => { + this.props.saveIndexerProxy({ id: this.props.id }); + } + + onTestPress = () => { + this.props.testIndexerProxy({ id: this.props.id }); + } + + // + // Render + + render() { + return ( + <EditIndexerProxyModalContent + {...this.props} + onSavePress={this.onSavePress} + onTestPress={this.onTestPress} + onInputChange={this.onInputChange} + onFieldChange={this.onFieldChange} + /> + ); + } +} + +EditIndexerProxyModalContentConnector.propTypes = { + id: PropTypes.number, + isFetching: PropTypes.bool.isRequired, + isSaving: PropTypes.bool.isRequired, + saveError: PropTypes.object, + item: PropTypes.object.isRequired, + setIndexerProxyValue: PropTypes.func.isRequired, + setIndexerProxyFieldValue: PropTypes.func.isRequired, + saveIndexerProxy: PropTypes.func.isRequired, + testIndexerProxy: PropTypes.func.isRequired, + onModalClose: PropTypes.func.isRequired +}; + +export default connect(createMapStateToProps, mapDispatchToProps)(EditIndexerProxyModalContentConnector); diff --git a/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.css b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.css new file mode 100644 index 000000000..4a80c6128 --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.css @@ -0,0 +1,20 @@ +.indexerProxies { + display: flex; + flex-wrap: wrap; +} + +.addIndexerProxy { + composes: indexerProxy from '~./IndexerProxy.css'; + + background-color: $cardAlternateBackgroundColor; + color: $gray; + text-align: center; +} + +.center { + display: inline-block; + padding: 5px 20px 0; + border: 1px solid $borderColor; + border-radius: 4px; + background-color: $white; +} diff --git a/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.js b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.js new file mode 100644 index 000000000..b51b8116f --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.js @@ -0,0 +1,121 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import Card from 'Components/Card'; +import FieldSet from 'Components/FieldSet'; +import Icon from 'Components/Icon'; +import PageSectionContent from 'Components/Page/PageSectionContent'; +import { icons } from 'Helpers/Props'; +import translate from 'Utilities/String/translate'; +import AddIndexerProxyModal from './AddIndexerProxyModal'; +import EditIndexerProxyModalConnector from './EditIndexerProxyModalConnector'; +import IndexerProxy from './IndexerProxy'; +import styles from './IndexerProxies.css'; + +class IndexerProxies extends Component { + + // + // Lifecycle + + constructor(props, context) { + super(props, context); + + this.state = { + isAddIndexerProxyModalOpen: false, + isEditIndexerProxyModalOpen: false + }; + } + + // + // Listeners + + onAddIndexerProxyPress = () => { + this.setState({ isAddIndexerProxyModalOpen: true }); + } + + onAddIndexerProxyModalClose = ({ indexerProxySelected = false } = {}) => { + this.setState({ + isAddIndexerProxyModalOpen: false, + isEditIndexerProxyModalOpen: indexerProxySelected + }); + } + + onEditIndexerProxyModalClose = () => { + this.setState({ isEditIndexerProxyModalOpen: false }); + } + + // + // Render + + render() { + const { + items, + tagList, + indexerList, + onConfirmDeleteIndexerProxy, + ...otherProps + } = this.props; + + const { + isAddIndexerProxyModalOpen, + isEditIndexerProxyModalOpen + } = this.state; + + return ( + <FieldSet legend={translate('Indexer Proxies')}> + <PageSectionContent + errorMessage={translate('UnableToLoadIndexerProxies')} + {...otherProps} + > + <div className={styles.indexerProxies}> + { + items.map((item) => { + return ( + <IndexerProxy + key={item.id} + {...item} + tagList={tagList} + indexerList={indexerList} + onConfirmDeleteIndexerProxy={onConfirmDeleteIndexerProxy} + /> + ); + }) + } + + <Card + className={styles.addIndexerProxy} + onPress={this.onAddIndexerProxyPress} + > + <div className={styles.center}> + <Icon + name={icons.ADD} + size={45} + /> + </div> + </Card> + </div> + + <AddIndexerProxyModal + isOpen={isAddIndexerProxyModalOpen} + onModalClose={this.onAddIndexerProxyModalClose} + /> + + <EditIndexerProxyModalConnector + isOpen={isEditIndexerProxyModalOpen} + onModalClose={this.onEditIndexerProxyModalClose} + /> + </PageSectionContent> + </FieldSet> + ); + } +} + +IndexerProxies.propTypes = { + isFetching: PropTypes.bool.isRequired, + error: PropTypes.object, + items: PropTypes.arrayOf(PropTypes.object).isRequired, + tagList: PropTypes.arrayOf(PropTypes.object).isRequired, + indexerList: PropTypes.arrayOf(PropTypes.object).isRequired, + onConfirmDeleteIndexerProxy: PropTypes.func.isRequired +}; + +export default IndexerProxies; diff --git a/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxiesConnector.js b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxiesConnector.js new file mode 100644 index 000000000..94258079a --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxiesConnector.js @@ -0,0 +1,65 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import { deleteIndexerProxy, fetchIndexerProxies } from 'Store/Actions/settingsActions'; +import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector'; +import createTagsSelector from 'Store/Selectors/createTagsSelector'; +import sortByName from 'Utilities/Array/sortByName'; +import IndexerProxies from './IndexerProxies'; + +function createMapStateToProps() { + return createSelector( + createSortedSectionSelector('settings.indexerProxies', sortByName), + createSortedSectionSelector('indexers', sortByName), + createTagsSelector(), + (indexerProxies, indexers, tagList) => { + return { + ...indexerProxies, + indexerList: indexers.items, + tagList + }; + } + ); +} + +const mapDispatchToProps = { + fetchIndexerProxies, + deleteIndexerProxy +}; + +class IndexerProxiesConnector extends Component { + + // + // Lifecycle + + componentDidMount() { + this.props.fetchIndexerProxies(); + } + + // + // Listeners + + onConfirmDeleteIndexerProxy = (id) => { + this.props.deleteIndexerProxy({ id }); + } + + // + // Render + + render() { + return ( + <IndexerProxies + {...this.props} + onConfirmDeleteIndexerProxy={this.onConfirmDeleteIndexerProxy} + /> + ); + } +} + +IndexerProxiesConnector.propTypes = { + fetchIndexerProxies: PropTypes.func.isRequired, + deleteIndexerProxy: PropTypes.func.isRequired +}; + +export default connect(createMapStateToProps, mapDispatchToProps)(IndexerProxiesConnector); diff --git a/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxy.css b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxy.css new file mode 100644 index 000000000..061e6d4bd --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxy.css @@ -0,0 +1,23 @@ +.indexerProxy { + composes: card from '~Components/Card.css'; + + width: 290px; +} + +.name { + @add-mixin truncate; + + margin-bottom: 20px; + font-weight: 300; + font-size: 24px; +} + +.indexers { + flex: 1 0 auto; +} + +.enabled { + display: flex; + flex-wrap: wrap; + margin-top: 5px; +} diff --git a/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxy.js b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxy.js new file mode 100644 index 000000000..18c96144a --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxy.js @@ -0,0 +1,144 @@ +import _ from 'lodash'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import Card from 'Components/Card'; +import Label from 'Components/Label'; +import ConfirmModal from 'Components/Modal/ConfirmModal'; +import TagList from 'Components/TagList'; +import { kinds } from 'Helpers/Props'; +import translate from 'Utilities/String/translate'; +import EditIndexerProxyModalConnector from './EditIndexerProxyModalConnector'; +import styles from './IndexerProxy.css'; + +class IndexerProxy extends Component { + + // + // Lifecycle + + constructor(props, context) { + super(props, context); + + this.state = { + isEditIndexerProxyModalOpen: false, + isDeleteIndexerProxyModalOpen: false + }; + } + + // + // Listeners + + onEditIndexerProxyPress = () => { + this.setState({ isEditIndexerProxyModalOpen: true }); + } + + onEditIndexerProxyModalClose = () => { + this.setState({ isEditIndexerProxyModalOpen: false }); + } + + onDeleteIndexerProxyPress = () => { + this.setState({ + isEditIndexerProxyModalOpen: false, + isDeleteIndexerProxyModalOpen: true + }); + } + + onDeleteIndexerProxyModalClose= () => { + this.setState({ isDeleteIndexerProxyModalOpen: false }); + } + + onConfirmDeleteIndexerProxy = () => { + this.props.onConfirmDeleteIndexerProxy(this.props.id); + } + + // + // Render + + render() { + const { + id, + name, + tags, + tagList, + indexerList + } = this.props; + + return ( + <Card + className={styles.indexerProxy} + overlayContent={true} + onPress={this.onEditIndexerProxyPress} + > + <div className={styles.name}> + {name} + </div> + + <TagList + tags={tags} + tagList={tagList} + /> + + <div className={styles.indexers}> + { + tags.map((t) => { + const indexers = _.filter(indexerList, { tags: [t] }); + + if (!indexers || indexers.length === 0) { + return null; + } + + return indexers.map((i) => { + return ( + <Label + key={i.name} + kind={kinds.SUCCESS} + > + {i.name} + </Label> + ); + }); + }) + } + </div> + + { + !tags || tags.length === 0 ? + <Label + kind={kinds.DISABLED} + outline={true} + > + Disabled + </Label> : + null + } + + <EditIndexerProxyModalConnector + id={id} + isOpen={this.state.isEditIndexerProxyModalOpen} + onModalClose={this.onEditIndexerProxyModalClose} + onDeleteIndexerProxyPress={this.onDeleteIndexerProxyPress} + /> + + <ConfirmModal + isOpen={this.state.isDeleteIndexerProxyModalOpen} + kind={kinds.DANGER} + title={translate('DeleteIndexerProxy')} + message={translate('DeleteIndexerProxyMessageText', [name])} + confirmLabel={translate('Delete')} + onConfirm={this.onConfirmDeleteIndexerProxy} + onCancel={this.onDeleteIndexerProxyModalClose} + /> + </Card> + ); + } +} + +IndexerProxy.propTypes = { + id: PropTypes.number.isRequired, + name: PropTypes.string.isRequired, + tags: PropTypes.arrayOf(PropTypes.number).isRequired, + tagList: PropTypes.arrayOf(PropTypes.object).isRequired, + indexerList: PropTypes.arrayOf(PropTypes.object).isRequired, + onConfirmDeleteIndexerProxy: PropTypes.func.isRequired +}; + +export default IndexerProxy; diff --git a/frontend/src/Settings/Indexers/IndexerSettings.js b/frontend/src/Settings/Indexers/IndexerSettings.js new file mode 100644 index 000000000..ec73bc0aa --- /dev/null +++ b/frontend/src/Settings/Indexers/IndexerSettings.js @@ -0,0 +1,22 @@ +import React from 'react'; +import PageContent from 'Components/Page/PageContent'; +import PageContentBody from 'Components/Page/PageContentBody'; +import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector'; +import translate from 'Utilities/String/translate'; +import IndexerProxiesConnector from './IndexerProxies/IndexerProxiesConnector'; + +function IndexerSettings() { + return ( + <PageContent title={translate('Proxies')}> + <SettingsToolbarConnector + showSave={false} + /> + + <PageContentBody> + <IndexerProxiesConnector /> + </PageContentBody> + </PageContent> + ); +} + +export default IndexerSettings; diff --git a/frontend/src/Settings/Tags/Details/TagDetailsDelayProfile.js b/frontend/src/Settings/Tags/Details/TagDetailsDelayProfile.js deleted file mode 100644 index ab670359b..000000000 --- a/frontend/src/Settings/Tags/Details/TagDetailsDelayProfile.js +++ /dev/null @@ -1,47 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import titleCase from 'Utilities/String/titleCase'; - -function TagDetailsDelayProfile(props) { - const { - preferredProtocol, - enableUsenet, - enableTorrent, - usenetDelay, - torrentDelay - } = props; - - return ( - <div> - <div> - Protocol: {titleCase(preferredProtocol)} - </div> - - <div> - { - enableUsenet ? - `Usenet Delay: ${usenetDelay}` : - 'Usenet disabled' - } - </div> - - <div> - { - enableTorrent ? - `Torrent Delay: ${torrentDelay}` : - 'Torrents disabled' - } - </div> - </div> - ); -} - -TagDetailsDelayProfile.propTypes = { - preferredProtocol: PropTypes.string.isRequired, - enableUsenet: PropTypes.bool.isRequired, - enableTorrent: PropTypes.bool.isRequired, - usenetDelay: PropTypes.number.isRequired, - torrentDelay: PropTypes.number.isRequired -}; - -export default TagDetailsDelayProfile; diff --git a/frontend/src/Settings/Tags/Details/TagDetailsModalContent.js b/frontend/src/Settings/Tags/Details/TagDetailsModalContent.js index aa248f158..c65f46974 100644 --- a/frontend/src/Settings/Tags/Details/TagDetailsModalContent.js +++ b/frontend/src/Settings/Tags/Details/TagDetailsModalContent.js @@ -1,26 +1,22 @@ import PropTypes from 'prop-types'; import React from 'react'; import FieldSet from 'Components/FieldSet'; -import Label from 'Components/Label'; import Button from 'Components/Link/Button'; import ModalBody from 'Components/Modal/ModalBody'; import ModalContent from 'Components/Modal/ModalContent'; import ModalFooter from 'Components/Modal/ModalFooter'; import ModalHeader from 'Components/Modal/ModalHeader'; import { kinds } from 'Helpers/Props'; -import split from 'Utilities/String/split'; import translate from 'Utilities/String/translate'; -import TagDetailsDelayProfile from './TagDetailsDelayProfile'; import styles from './TagDetailsModalContent.css'; function TagDetailsModalContent(props) { const { label, isTagUsed, - movies, - delayProfiles, + indexers, notifications, - restrictions, + indexerProxies, onModalClose, onDeleteTagPress } = props; @@ -40,13 +36,13 @@ function TagDetailsModalContent(props) { } { - !!movies.length && - <FieldSet legend={translate('Movies')}> + !!indexers.length && + <FieldSet legend={translate('Indexers')}> { - movies.map((item) => { + indexers.map((item) => { return ( <div key={item.id}> - {item.title} + {item.name} </div> ); }) @@ -54,35 +50,6 @@ function TagDetailsModalContent(props) { </FieldSet> } - { - !!delayProfiles.length && - <FieldSet legend={translate('DelayProfile')}> - { - delayProfiles.map((item) => { - const { - id, - preferredProtocol, - enableUsenet, - enableTorrent, - usenetDelay, - torrentDelay - } = item; - - return ( - <TagDetailsDelayProfile - key={id} - preferredProtocol={preferredProtocol} - enableUsenet={enableUsenet} - enableTorrent={enableTorrent} - usenetDelay={usenetDelay} - torrentDelay={torrentDelay} - /> - ); - }) - } - </FieldSet> - } - { !!notifications.length && <FieldSet legend={translate('Connections')}> @@ -99,44 +66,13 @@ function TagDetailsModalContent(props) { } { - !!restrictions.length && - <FieldSet legend={translate('Restrictions')}> + !!indexerProxies.length && + <FieldSet legend={translate('Indexer Proxies')}> { - restrictions.map((item) => { + indexerProxies.map((item) => { return ( - <div - key={item.id} - className={styles.restriction} - > - <div> - { - split(item.required).map((r) => { - return ( - <Label - key={r} - kind={kinds.SUCCESS} - > - {r} - </Label> - ); - }) - } - </div> - - <div> - { - split(item.ignored).map((i) => { - return ( - <Label - key={i} - kind={kinds.DANGER} - > - {i} - </Label> - ); - }) - } - </div> + <div key={item.id}> + {item.name} </div> ); }) @@ -171,10 +107,9 @@ function TagDetailsModalContent(props) { TagDetailsModalContent.propTypes = { label: PropTypes.string.isRequired, isTagUsed: PropTypes.bool.isRequired, - movies: PropTypes.arrayOf(PropTypes.object).isRequired, - delayProfiles: PropTypes.arrayOf(PropTypes.object).isRequired, + indexers: PropTypes.arrayOf(PropTypes.object).isRequired, notifications: PropTypes.arrayOf(PropTypes.object).isRequired, - restrictions: PropTypes.arrayOf(PropTypes.object).isRequired, + indexerProxies: PropTypes.arrayOf(PropTypes.object).isRequired, onModalClose: PropTypes.func.isRequired, onDeleteTagPress: PropTypes.func.isRequired }; diff --git a/frontend/src/Settings/Tags/Details/TagDetailsModalContentConnector.js b/frontend/src/Settings/Tags/Details/TagDetailsModalContentConnector.js index 43a1f9b3c..4c67407ba 100644 --- a/frontend/src/Settings/Tags/Details/TagDetailsModalContentConnector.js +++ b/frontend/src/Settings/Tags/Details/TagDetailsModalContentConnector.js @@ -1,6 +1,5 @@ import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import createAllIndexersSelector from 'Store/Selectors/createAllIndexersSelector'; import TagDetailsModalContent from './TagDetailsModalContent'; function findMatchingItems(ids, items) { @@ -9,35 +8,15 @@ function findMatchingItems(ids, items) { }); } -function createUnorderedMatchingMoviesSelector() { +function createMatchingIndexersSelector() { return createSelector( (state, { indexerIds }) => indexerIds, - createAllIndexersSelector(), + (state) => state.indexers.items, findMatchingItems ); } -function createMatchingMoviesSelector() { - return createSelector( - createUnorderedMatchingMoviesSelector(), - (movies) => { - return movies.sort((movieA, movieB) => { - const sortTitleA = movieA.sortTitle; - const sortTitleB = movieB.sortTitle; - - if (sortTitleA > sortTitleB) { - return 1; - } else if (sortTitleA < sortTitleB) { - return -1; - } - - return 0; - }); - } - ); -} - -function createMatchingNotificationsSelector() { +function createMatchingIndexerProxiesSelector() { return createSelector( (state, { notificationIds }) => notificationIds, (state) => state.settings.notifications.items, @@ -45,13 +24,23 @@ function createMatchingNotificationsSelector() { ); } +function createMatchingNotificationsSelector() { + return createSelector( + (state, { indexerProxyIds }) => indexerProxyIds, + (state) => state.settings.indexerProxies.items, + findMatchingItems + ); +} + function createMapStateToProps() { return createSelector( - createMatchingMoviesSelector(), + createMatchingIndexersSelector(), + createMatchingIndexerProxiesSelector(), createMatchingNotificationsSelector(), - (movies, notifications) => { + (indexers, indexerProxies, notifications) => { return { - movies, + indexers, + indexerProxies, notifications }; } diff --git a/frontend/src/Settings/Tags/Tag.js b/frontend/src/Settings/Tags/Tag.js index 86219ccf6..eed93bd4e 100644 --- a/frontend/src/Settings/Tags/Tag.js +++ b/frontend/src/Settings/Tags/Tag.js @@ -53,11 +53,9 @@ class Tag extends Component { render() { const { label, - delayProfileIds, notificationIds, - restrictionIds, - importListIds, - movieIds + indexerIds, + indexerProxyIds } = this.props; const { @@ -66,11 +64,9 @@ class Tag extends Component { } = this.state; const isTagUsed = !!( - delayProfileIds.length || + indexerIds.length || notificationIds.length || - restrictionIds.length || - importListIds.length || - movieIds.length + indexerProxyIds.length ); return ( @@ -87,16 +83,9 @@ class Tag extends Component { isTagUsed && <div> { - !!movieIds.length && + !!indexerIds.length && <div> - {movieIds.length} movies - </div> - } - - { - !!delayProfileIds.length && - <div> - {delayProfileIds.length} delay profile{delayProfileIds.length > 1 && 's'} + {indexerIds.length} indexer{indexerIds.length > 1 && 's'} </div> } @@ -108,16 +97,9 @@ class Tag extends Component { } { - !!restrictionIds.length && + !!indexerProxyIds.length && <div> - {restrictionIds.length} restriction{restrictionIds.length > 1 && 's'} - </div> - } - - { - !!importListIds.length && - <div> - {importListIds.length} list{importListIds.length > 1 && 's'} + {indexerProxyIds.length} indexerProxy{indexerProxyIds.length > 1 && 's'} </div> } </div> @@ -133,11 +115,9 @@ class Tag extends Component { <TagDetailsModal label={label} isTagUsed={isTagUsed} - movieIds={movieIds} - delayProfileIds={delayProfileIds} + indexerIds={indexerIds} notificationIds={notificationIds} - restrictionIds={restrictionIds} - importListIds={importListIds} + indexerProxyIds={indexerProxyIds} isOpen={isDetailsModalOpen} onModalClose={this.onDetailsModalClose} onDeleteTagPress={this.onDeleteTagPress} @@ -160,20 +140,16 @@ class Tag extends Component { Tag.propTypes = { id: PropTypes.number.isRequired, label: PropTypes.string.isRequired, - delayProfileIds: PropTypes.arrayOf(PropTypes.number).isRequired, notificationIds: PropTypes.arrayOf(PropTypes.number).isRequired, - restrictionIds: PropTypes.arrayOf(PropTypes.number).isRequired, - importListIds: PropTypes.arrayOf(PropTypes.number).isRequired, - movieIds: PropTypes.arrayOf(PropTypes.number).isRequired, + indexerIds: PropTypes.arrayOf(PropTypes.number).isRequired, + indexerProxyIds: PropTypes.arrayOf(PropTypes.number).isRequired, onConfirmDeleteTag: PropTypes.func.isRequired }; Tag.defaultProps = { - delayProfileIds: [], + indexerIds: [], notificationIds: [], - restrictionIds: [], - importListIds: [], - movieIds: [] + indexerProxyIds: [] }; export default Tag; diff --git a/frontend/src/Settings/Tags/TagsConnector.js b/frontend/src/Settings/Tags/TagsConnector.js index edcfa4918..374d3caa7 100644 --- a/frontend/src/Settings/Tags/TagsConnector.js +++ b/frontend/src/Settings/Tags/TagsConnector.js @@ -2,7 +2,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { fetchNotifications } from 'Store/Actions/settingsActions'; +import { fetchIndexerProxies, fetchNotifications } from 'Store/Actions/settingsActions'; import { fetchTagDetails } from 'Store/Actions/tagActions'; import Tags from './Tags'; @@ -26,7 +26,8 @@ function createMapStateToProps() { const mapDispatchToProps = { dispatchFetchTagDetails: fetchTagDetails, - dispatchFetchNotifications: fetchNotifications + dispatchFetchNotifications: fetchNotifications, + dispatchFetchIndexerProxies: fetchIndexerProxies }; class MetadatasConnector extends Component { @@ -37,11 +38,13 @@ class MetadatasConnector extends Component { componentDidMount() { const { dispatchFetchTagDetails, - dispatchFetchNotifications + dispatchFetchNotifications, + dispatchFetchIndexerProxies } = this.props; dispatchFetchTagDetails(); dispatchFetchNotifications(); + dispatchFetchIndexerProxies(); } // @@ -58,7 +61,8 @@ class MetadatasConnector extends Component { MetadatasConnector.propTypes = { dispatchFetchTagDetails: PropTypes.func.isRequired, - dispatchFetchNotifications: PropTypes.func.isRequired + dispatchFetchNotifications: PropTypes.func.isRequired, + dispatchFetchIndexerProxies: PropTypes.func.isRequired }; export default connect(createMapStateToProps, mapDispatchToProps)(MetadatasConnector); diff --git a/frontend/src/Store/Actions/Settings/indexerProxies.js b/frontend/src/Store/Actions/Settings/indexerProxies.js new file mode 100644 index 000000000..6ba5c731b --- /dev/null +++ b/frontend/src/Store/Actions/Settings/indexerProxies.js @@ -0,0 +1,110 @@ +import { createAction } from 'redux-actions'; +import createFetchHandler from 'Store/Actions/Creators/createFetchHandler'; +import createFetchSchemaHandler from 'Store/Actions/Creators/createFetchSchemaHandler'; +import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler'; +import createSaveProviderHandler, { createCancelSaveProviderHandler } from 'Store/Actions/Creators/createSaveProviderHandler'; +import createTestProviderHandler, { createCancelTestProviderHandler } from 'Store/Actions/Creators/createTestProviderHandler'; +import createSetProviderFieldValueReducer from 'Store/Actions/Creators/Reducers/createSetProviderFieldValueReducer'; +import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer'; +import { createThunk } from 'Store/thunks'; +import selectProviderSchema from 'Utilities/State/selectProviderSchema'; + +// +// Variables + +const section = 'settings.indexerProxies'; + +// +// Actions Types + +export const FETCH_INDEXER_PROXYS = 'settings/indexerProxies/fetchIndexerProxies'; +export const FETCH_INDEXER_PROXY_SCHEMA = 'settings/indexerProxies/fetchIndexerProxySchema'; +export const SELECT_INDEXER_PROXY_SCHEMA = 'settings/indexerProxies/selectIndexerProxySchema'; +export const SET_INDEXER_PROXY_VALUE = 'settings/indexerProxies/setIndexerProxyValue'; +export const SET_INDEXER_PROXY_FIELD_VALUE = 'settings/indexerProxies/setIndexerProxyFieldValue'; +export const SAVE_INDEXER_PROXY = 'settings/indexerProxies/saveIndexerProxy'; +export const CANCEL_SAVE_INDEXER_PROXY = 'settings/indexerProxies/cancelSaveIndexerProxy'; +export const DELETE_INDEXER_PROXY = 'settings/indexerProxies/deleteIndexerProxy'; +export const TEST_INDEXER_PROXY = 'settings/indexerProxies/testIndexerProxy'; +export const CANCEL_TEST_INDEXER_PROXY = 'settings/indexerProxies/cancelTestIndexerProxy'; + +// +// Action Creators + +export const fetchIndexerProxies = createThunk(FETCH_INDEXER_PROXYS); +export const fetchIndexerProxySchema = createThunk(FETCH_INDEXER_PROXY_SCHEMA); +export const selectIndexerProxySchema = createAction(SELECT_INDEXER_PROXY_SCHEMA); + +export const saveIndexerProxy = createThunk(SAVE_INDEXER_PROXY); +export const cancelSaveIndexerProxy = createThunk(CANCEL_SAVE_INDEXER_PROXY); +export const deleteIndexerProxy = createThunk(DELETE_INDEXER_PROXY); +export const testIndexerProxy = createThunk(TEST_INDEXER_PROXY); +export const cancelTestIndexerProxy = createThunk(CANCEL_TEST_INDEXER_PROXY); + +export const setIndexerProxyValue = createAction(SET_INDEXER_PROXY_VALUE, (payload) => { + return { + section, + ...payload + }; +}); + +export const setIndexerProxyFieldValue = createAction(SET_INDEXER_PROXY_FIELD_VALUE, (payload) => { + return { + section, + ...payload + }; +}); + +// +// Details + +export default { + + // + // State + + defaultState: { + isFetching: false, + isPopulated: false, + error: null, + isSchemaFetching: false, + isSchemaPopulated: false, + schemaError: null, + schema: [], + selectedSchema: {}, + isSaving: false, + saveError: null, + isTesting: false, + items: [], + pendingChanges: {} + }, + + // + // Action Handlers + + actionHandlers: { + [FETCH_INDEXER_PROXYS]: createFetchHandler(section, '/indexerProxy'), + [FETCH_INDEXER_PROXY_SCHEMA]: createFetchSchemaHandler(section, '/indexerProxy/schema'), + + [SAVE_INDEXER_PROXY]: createSaveProviderHandler(section, '/indexerProxy'), + [CANCEL_SAVE_INDEXER_PROXY]: createCancelSaveProviderHandler(section), + [DELETE_INDEXER_PROXY]: createRemoveItemHandler(section, '/indexerProxy'), + [TEST_INDEXER_PROXY]: createTestProviderHandler(section, '/indexerProxy'), + [CANCEL_TEST_INDEXER_PROXY]: createCancelTestProviderHandler(section) + }, + + // + // Reducers + + reducers: { + [SET_INDEXER_PROXY_VALUE]: createSetSettingValueReducer(section), + [SET_INDEXER_PROXY_FIELD_VALUE]: createSetProviderFieldValueReducer(section), + + [SELECT_INDEXER_PROXY_SCHEMA]: (state, { payload }) => { + return selectProviderSchema(state, section, payload, (selectedSchema) => { + return selectedSchema; + }); + } + } + +}; diff --git a/frontend/src/Store/Actions/settingsActions.js b/frontend/src/Store/Actions/settingsActions.js index 09540a2b6..e7fe7247a 100644 --- a/frontend/src/Store/Actions/settingsActions.js +++ b/frontend/src/Store/Actions/settingsActions.js @@ -7,6 +7,7 @@ import development from './Settings/development'; import downloadClients from './Settings/downloadClients'; import general from './Settings/general'; import indexerCategories from './Settings/indexerCategories'; +import indexerProxies from './Settings/indexerProxies'; import languages from './Settings/languages'; import notifications from './Settings/notifications'; import ui from './Settings/ui'; @@ -14,6 +15,7 @@ import ui from './Settings/ui'; export * from './Settings/downloadClients'; export * from './Settings/general'; export * from './Settings/indexerCategories'; +export * from './Settings/indexerProxies'; export * from './Settings/languages'; export * from './Settings/notifications'; export * from './Settings/applications'; @@ -35,6 +37,7 @@ export const defaultState = { downloadClients: downloadClients.defaultState, general: general.defaultState, indexerCategories: indexerCategories.defaultState, + indexerProxies: indexerProxies.defaultState, languages: languages.defaultState, notifications: notifications.defaultState, applications: applications.defaultState, @@ -64,6 +67,7 @@ export const actionHandlers = handleThunks({ ...downloadClients.actionHandlers, ...general.actionHandlers, ...indexerCategories.actionHandlers, + ...indexerProxies.actionHandlers, ...languages.actionHandlers, ...notifications.actionHandlers, ...applications.actionHandlers, @@ -84,6 +88,7 @@ export const reducers = createHandleActions({ ...downloadClients.reducers, ...general.reducers, ...indexerCategories.reducers, + ...indexerProxies.reducers, ...languages.reducers, ...notifications.reducers, ...applications.reducers, diff --git a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs index d51a14929..e20341305 100644 --- a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs +++ b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs @@ -59,7 +59,7 @@ namespace NzbDrone.Common.Http.Dispatchers webRequest.Timeout = (int)Math.Ceiling(request.RequestTimeout.TotalMilliseconds); } - webRequest.Proxy = GetProxy(request.Url); + webRequest.Proxy = request.Proxy ?? GetProxy(request.Url); if (request.Headers != null) { diff --git a/src/NzbDrone.Common/Http/HttpClient.cs b/src/NzbDrone.Common/Http/HttpClient.cs index 2e8f7530f..47286b3b0 100644 --- a/src/NzbDrone.Common/Http/HttpClient.cs +++ b/src/NzbDrone.Common/Http/HttpClient.cs @@ -61,7 +61,7 @@ namespace NzbDrone.Common.Http _cookieContainerCache = cacheManager.GetCache<CookieContainer>(typeof(HttpClient)); } - public async Task<HttpResponse> ExecuteAsync(HttpRequest request) + public virtual async Task<HttpResponse> ExecuteAsync(HttpRequest request) { var cookieContainer = InitializeRequestCookies(request); diff --git a/src/NzbDrone.Common/Http/HttpRequest.cs b/src/NzbDrone.Common/Http/HttpRequest.cs index ed09dff85..9f2aab320 100644 --- a/src/NzbDrone.Common/Http/HttpRequest.cs +++ b/src/NzbDrone.Common/Http/HttpRequest.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Net; using System.Text; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; @@ -31,6 +32,7 @@ namespace NzbDrone.Common.Http public HttpMethod Method { get; set; } public HttpHeader Headers { get; set; } public Encoding Encoding { get; set; } + public IWebProxy Proxy { get; set; } public byte[] ContentData { get; set; } public string ContentSummary { get; set; } public bool SuppressHttpError { get; set; } @@ -87,6 +89,19 @@ namespace NzbDrone.Common.Http } } + public string GetContent() + { + if (Encoding != null) + { + return Encoding.GetString(ContentData); + } + else + { + var encoding = HttpHeader.GetEncodingFromContentType(Headers.ContentType); + return encoding.GetString(ContentData); + } + } + public void AddBasicAuthentication(string username, string password) { var authInfo = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes($"{username}:{password}")); diff --git a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/PrivateHDFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/PrivateHDFixture.cs index c5143bb00..86469cdc8 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/PrivateHDFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/PrivateHDFixture.cs @@ -33,9 +33,9 @@ namespace NzbDrone.Core.Test.IndexerTests.AvistazTests { var recentFeed = ReadAllText(@"Files/Indexers/PrivateHD/recentfeed.json"); - Mocker.GetMock<IHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) - .Returns<HttpRequest>(r => Task.FromResult(new HttpResponse(r, new HttpHeader { { "Content-Type", "application/json" } }, new CookieCollection(), recentFeed))); + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader { { "Content-Type", "application/json" } }, new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/FileListTests/FileListFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/FileListTests/FileListFixture.cs index ce24c5a7b..63570a01e 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/FileListTests/FileListFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/FileListTests/FileListFixture.cs @@ -32,9 +32,9 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests { var recentFeed = ReadAllText(@"Files/Indexers/FileList/recentfeed.json"); - Mocker.GetMock<IHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) - .Returns<HttpRequest>(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/HDBitsTests/HDBitsFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/HDBitsTests/HDBitsFixture.cs index dcb82d705..49feabe43 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/HDBitsTests/HDBitsFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/HDBitsTests/HDBitsFixture.cs @@ -44,9 +44,9 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests { var responseJson = ReadAllText(fileName); - Mocker.GetMock<IHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST))) - .Returns<HttpRequest>(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), responseJson))); + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), responseJson))); var torrents = (await Subject.Fetch(_movieSearchCriteria)).Releases; @@ -73,9 +73,9 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests { var responseJson = new { status = 5, message = "Invalid authentication credentials" }.ToJson(); - Mocker.GetMock<IHttpClient>() - .Setup(v => v.ExecuteAsync(It.IsAny<HttpRequest>())) - .Returns<HttpRequest>(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), Encoding.UTF8.GetBytes(responseJson)))); + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteAsync(It.IsAny<HttpRequest>(), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), Encoding.UTF8.GetBytes(responseJson)))); var torrents = (await Subject.Fetch(_movieSearchCriteria)).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs index fce49a5a4..03aa7da01 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs @@ -1,10 +1,12 @@ using System; using System.Net; +using System.Threading.Tasks; using System.Xml; using FluentAssertions; using Moq; using NUnit.Framework; using NzbDrone.Common.Http; +using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers.Newznab; using NzbDrone.Core.Test.Framework; @@ -14,6 +16,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests public class NewznabCapabilitiesProviderFixture : CoreTest<NewznabCapabilitiesProvider> { private NewznabSettings _settings; + private IndexerDefinition _definition; private string _caps; [SetUp] @@ -24,14 +27,24 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests BaseUrl = "http://indxer.local" }; + _definition = new IndexerDefinition() + { + Id = 5, + Name = "Newznab", + Settings = new NewznabSettings() + { + BaseUrl = "http://indexer.local/" + } + }; + _caps = ReadAllText("Files/Indexers/Newznab/newznab_caps.xml"); } private void GivenCapsResponse(string caps) { - Mocker.GetMock<IHttpClient>() - .Setup(o => o.Get(It.IsAny<HttpRequest>())) - .Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new CookieCollection(), caps)); + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.Execute(It.IsAny<HttpRequest>(), It.IsAny<IndexerDefinition>())) + .Returns<HttpRequest, IndexerDefinition>((r, d) => new HttpResponse(r, new HttpHeader(), new CookieCollection(), caps)); } [Test] @@ -39,11 +52,11 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests { GivenCapsResponse(_caps); - Subject.GetCapabilities(_settings); - Subject.GetCapabilities(_settings); + Subject.GetCapabilities(_settings, _definition); + Subject.GetCapabilities(_settings, _definition); - Mocker.GetMock<IHttpClient>() - .Verify(o => o.Get(It.IsAny<HttpRequest>()), Times.Once()); + Mocker.GetMock<IIndexerHttpClient>() + .Verify(o => o.Execute(It.IsAny<HttpRequest>(), It.IsAny<IndexerDefinition>()), Times.Once()); } [Test] @@ -51,7 +64,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests { GivenCapsResponse(_caps); - var caps = Subject.GetCapabilities(_settings); + var caps = Subject.GetCapabilities(_settings, _definition); caps.LimitsDefault.Value.Should().Be(25); caps.LimitsMax.Value.Should().Be(60); @@ -62,7 +75,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests { GivenCapsResponse(_caps.Replace("<limits", "<abclimits")); - var caps = Subject.GetCapabilities(_settings); + var caps = Subject.GetCapabilities(_settings, _definition); caps.LimitsDefault.Value.Should().Be(100); caps.LimitsMax.Value.Should().Be(100); @@ -71,11 +84,11 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests [Test] public void should_throw_if_failed_to_get() { - Mocker.GetMock<IHttpClient>() - .Setup(o => o.Get(It.IsAny<HttpRequest>())) + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.Execute(It.IsAny<HttpRequest>(), It.IsAny<IndexerDefinition>())) .Throws<Exception>(); - Assert.Throws<Exception>(() => Subject.GetCapabilities(_settings)); + Assert.Throws<Exception>(() => Subject.GetCapabilities(_settings, _definition)); } [Test] @@ -83,7 +96,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests { GivenCapsResponse(_caps.Replace("<limits", "<>")); - Assert.Throws<XmlException>(() => Subject.GetCapabilities(_settings)); + Assert.Throws<XmlException>(() => Subject.GetCapabilities(_settings, _definition)); } [Test] @@ -91,7 +104,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests { GivenCapsResponse(_caps.Replace("5030", "asdf")); - var result = Subject.GetCapabilities(_settings); + var result = Subject.GetCapabilities(_settings, _definition); result.Should().NotBeNull(); } diff --git a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabFixture.cs index a3d5a8d14..77120b8d4 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabFixture.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests _caps = new IndexerCapabilities(); Mocker.GetMock<INewznabCapabilitiesProvider>() - .Setup(v => v.GetCapabilities(It.IsAny<NewznabSettings>())) + .Setup(v => v.GetCapabilities(It.IsAny<NewznabSettings>(), It.IsAny<IndexerDefinition>())) .Returns(_caps); } @@ -42,9 +42,9 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests { var recentFeed = ReadAllText(@"Files/Indexers/Newznab/newznab_nzb_su.xml"); - Mocker.GetMock<IHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) - .Returns<HttpRequest>(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 }, Limit = 100, Offset = 0 })).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabRequestGeneratorFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabRequestGeneratorFixture.cs index 1f097a7ed..ead7db168 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabRequestGeneratorFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabRequestGeneratorFixture.cs @@ -41,7 +41,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests _capabilities = new IndexerCapabilities(); Mocker.GetMock<INewznabCapabilitiesProvider>() - .Setup(v => v.GetCapabilities(It.IsAny<NewznabSettings>())) + .Setup(v => v.GetCapabilities(It.IsAny<NewznabSettings>(), It.IsAny<IndexerDefinition>())) .Returns(_capabilities); } diff --git a/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs index 3a04ebee6..736386139 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs @@ -36,13 +36,13 @@ namespace NzbDrone.Core.Test.IndexerTests.PTPTests Json.Serialize(authResponse, authStream); var responseJson = ReadAllText(fileName); - Mocker.GetMock<IHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST))) - .Returns<HttpRequest>(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), authStream.ToString()))); + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), authStream.ToString()))); - Mocker.GetMock<IHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) - .Returns<HttpRequest>(r => Task.FromResult(new HttpResponse(r, new HttpHeader { ContentType = HttpAccept.Json.Value }, new CookieCollection(), responseJson))); + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader { ContentType = HttpAccept.Json.Value }, new CookieCollection(), responseJson))); var torrents = (await Subject.Fetch(new MovieSearchCriteria())).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs index 7fcfe1cdf..7d6fd31d5 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs @@ -37,9 +37,9 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests { var recentFeed = ReadAllText(@"Files/Indexers/Rarbg/RecentFeed_v2.json"); - Mocker.GetMock<IHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) - .Returns<HttpRequest>(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; @@ -64,9 +64,9 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests [Test] public async Task should_parse_error_20_as_empty_results() { - Mocker.GetMock<IHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) - .Returns<HttpRequest>(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), "{ error_code: 20, error: \"some message\" }"))); + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), "{ error_code: 20, error: \"some message\" }"))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; @@ -76,9 +76,9 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests [Test] public async Task should_warn_on_unknown_error() { - Mocker.GetMock<IHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) - .Returns<HttpRequest>(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), "{ error_code: 25, error: \"some message\" }"))); + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), "{ error_code: 25, error: \"some message\" }"))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/TestIndexer.cs b/src/NzbDrone.Core.Test/IndexerTests/TestIndexer.cs index c88fa7f22..969f0c014 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/TestIndexer.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/TestIndexer.cs @@ -20,7 +20,7 @@ namespace NzbDrone.Core.Test.IndexerTests public int _supportedPageSize; public override int PageSize => _supportedPageSize; - public TestIndexer(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger) + public TestIndexer(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, nzbValidationService, logger) { } diff --git a/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs index 8922e36be..444ad4433 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs @@ -34,7 +34,7 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests _caps = new IndexerCapabilities(); Mocker.GetMock<INewznabCapabilitiesProvider>() - .Setup(v => v.GetCapabilities(It.IsAny<NewznabSettings>())) + .Setup(v => v.GetCapabilities(It.IsAny<NewznabSettings>(), It.IsAny<IndexerDefinition>())) .Returns(_caps); } @@ -43,9 +43,9 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests { var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_hdaccess_net.xml"); - Mocker.GetMock<IHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) - .Returns<HttpRequest>(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria())).Releases; @@ -72,9 +72,9 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests { var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_tpb.xml"); - Mocker.GetMock<IHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) - .Returns<HttpRequest>(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria())).Releases; @@ -102,9 +102,9 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests { var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_animetosho.xml"); - Mocker.GetMock<IHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET))) - .Returns<HttpRequest>(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria())).Releases; diff --git a/src/NzbDrone.Core/Datastore/Migration/010_indexer_proxies.cs b/src/NzbDrone.Core/Datastore/Migration/010_indexer_proxies.cs new file mode 100644 index 000000000..e6fb9a703 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/010_indexer_proxies.cs @@ -0,0 +1,21 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(10)] + public class IndexerProxies : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Create.TableForModel("IndexerProxies") + .WithColumn("Name").AsString() + .WithColumn("Settings").AsString() + .WithColumn("Implementation").AsString() + .WithColumn("ConfigContract").AsString().Nullable() + .WithColumn("Tags").AsString().Nullable(); + + Alter.Table("Indexers").AddColumn("Tags").AsString().Nullable(); + } + } +} diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index 1ab5e9994..74e6c6b28 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -9,6 +9,7 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.CustomFilters; using NzbDrone.Core.Datastore.Converters; using NzbDrone.Core.Download; +using NzbDrone.Core.IndexerProxies; using NzbDrone.Core.Indexers; using NzbDrone.Core.Instrumentation; using NzbDrone.Core.Jobs; @@ -53,7 +54,6 @@ namespace NzbDrone.Core.Datastore .Ignore(i => i.SupportsSearch) .Ignore(i => i.SupportsRedirect) .Ignore(i => i.Capabilities) - .Ignore(d => d.Tags) .HasOne(a => a.AppProfile, a => a.AppProfileId); Mapper.Entity<DownloadClientDefinition>("DownloadClients").RegisterModel() @@ -65,6 +65,9 @@ namespace NzbDrone.Core.Datastore .Ignore(x => x.ImplementationName) .Ignore(i => i.SupportsOnHealthIssue); + Mapper.Entity<IndexerProxyDefinition>("IndexerProxies").RegisterModel() + .Ignore(x => x.ImplementationName); + Mapper.Entity<ApplicationDefinition>("Applications").RegisterModel() .Ignore(x => x.ImplementationName); diff --git a/src/NzbDrone.Core/HealthCheck/Checks/IndexerProxyCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/IndexerProxyCheck.cs new file mode 100644 index 000000000..1a48fc6ca --- /dev/null +++ b/src/NzbDrone.Core/HealthCheck/Checks/IndexerProxyCheck.cs @@ -0,0 +1,92 @@ +using System; +using System.Linq; +using System.Net; +using NLog; +using NzbDrone.Common.Cloud; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Core.IndexerProxies; +using NzbDrone.Core.Localization; + +namespace NzbDrone.Core.HealthCheck.Checks +{ + public class IndexerProxyCheck : HealthCheckBase + { + private readonly Logger _logger; + private readonly IIndexerProxyFactory _proxyFactory; + private readonly IHttpClient _client; + + private readonly IHttpRequestBuilderFactory _cloudRequestBuilder; + + public IndexerProxyCheck(IProwlarrCloudRequestBuilder cloudRequestBuilder, + IHttpClient client, + IIndexerProxyFactory proxyFactory, + ILocalizationService localizationService, + Logger logger) + : base(localizationService) + { + _proxyFactory = proxyFactory; + _cloudRequestBuilder = cloudRequestBuilder.Services; + _logger = logger; + _client = client; + } + + public override HealthCheck Check() + { + var enabledProviders = _proxyFactory.GetAvailableProviders(); + + var badProxies = enabledProviders.Where(p => !IsProxyWorking(p)).ToList(); + + if (enabledProviders.Empty()) + { + return new HealthCheck(GetType()); + } + + if (badProxies.Count == enabledProviders.Count) + { + return new HealthCheck(GetType(), + HealthCheckResult.Error, + _localizationService.GetLocalizedString("IndexerProxyStatusCheckAllClientMessage"), + "#proxies-are-unavailable-due-to-failures"); + } + + return new HealthCheck(GetType(), + HealthCheckResult.Warning, + string.Format(_localizationService.GetLocalizedString("IndexerProxyStatusCheckSingleClientMessage"), + string.Join(", ", badProxies.Select(v => v.Definition.Name))), + "#proxies-are-unavailable-due-to-failures"); + } + + private bool IsProxyWorking(IIndexerProxy indexerProxy) + { + var request = _cloudRequestBuilder.Create() + .Resource("/ping") + .Build(); + + try + { + var addresses = Dns.GetHostAddresses(((IIndexerProxySettings)indexerProxy.Definition.Settings).Host); + if (!addresses.Any()) + { + return false; + } + + var response = _client.Execute(request); + + // We only care about 400 responses, other error codes can be ignored + if (response.StatusCode == HttpStatusCode.BadRequest) + { + _logger.Error("Proxy Health Check failed: {0}", response.StatusCode); + return false; + } + } + catch (Exception ex) + { + _logger.Error(ex, "Proxy Health Check failed"); + return false; + } + + return true; + } + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/Http/Http.cs b/src/NzbDrone.Core/IndexerProxies/Http/Http.cs new file mode 100644 index 000000000..03ab6a802 --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/Http/Http.cs @@ -0,0 +1,34 @@ +using System.Net; +using NLog; +using NzbDrone.Common.Cloud; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; + +namespace NzbDrone.Core.IndexerProxies.Http +{ + public class Http : HttpIndexerProxyBase<HttpSettings> + { + public Http(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger) + : base(cloudRequestBuilder, httpClient, logger) + { + } + + public override string Name => "Http"; + + public override HttpRequest PreRequest(HttpRequest request) + { + if (Settings.Username.IsNotNullOrWhiteSpace() && Settings.Password.IsNotNullOrWhiteSpace()) + { + request.Proxy = new WebProxy(Settings.Host + ":" + Settings.Port, false, null, new NetworkCredential(Settings.Username, Settings.Password)); + } + else + { + request.Proxy = new WebProxy(Settings.Host + ":" + Settings.Port, false, null); + } + + _logger.Debug("Applying HTTP(S) Proxy {0} to request {1}", Name, request.Url); + + return request; + } + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/Http/HttpSettings.cs b/src/NzbDrone.Core/IndexerProxies/Http/HttpSettings.cs new file mode 100644 index 000000000..4ba1d65bb --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/Http/HttpSettings.cs @@ -0,0 +1,43 @@ +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.IndexerProxies.Http +{ + public class HttpSettingsValidator : AbstractValidator<HttpSettings> + { + public HttpSettingsValidator() + { + RuleFor(c => c.Host).NotEmpty(); + RuleFor(c => c.Port).NotEmpty(); + } + } + + public class HttpSettings : IIndexerProxySettings + { + private static readonly HttpSettingsValidator Validator = new HttpSettingsValidator(); + + public HttpSettings() + { + Username = ""; + Password = ""; + } + + [FieldDefinition(0, Label = "Host")] + public string Host { get; set; } + + [FieldDefinition(1, Label = "Port")] + public int Port { get; set; } + + [FieldDefinition(2, Label = "Username", Privacy = PrivacyLevel.UserName)] + public string Username { get; set; } + + [FieldDefinition(3, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] + public string Password { get; set; } + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs b/src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs new file mode 100644 index 000000000..5868ef412 --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using FluentValidation.Results; +using NLog; +using NzbDrone.Common.Cloud; +using NzbDrone.Common.Http; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.IndexerProxies +{ + public abstract class HttpIndexerProxyBase<TSettings> : IndexerProxyBase<TSettings> + where TSettings : IIndexerProxySettings, new() + { + protected readonly IHttpClient _httpClient; + protected readonly IHttpRequestBuilderFactory _cloudRequestBuilder; + protected readonly Logger _logger; + + public HttpIndexerProxyBase(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger) + { + _httpClient = httpClient; + _logger = logger; + _cloudRequestBuilder = cloudRequestBuilder.Services; + } + + public override ValidationResult Test() + { + var failures = new List<ValidationFailure>(); + + var addresses = Dns.GetHostAddresses(Settings.Host); + if (!addresses.Any()) + { + failures.Add(new NzbDroneValidationFailure("Host", "ProxyCheckResolveIpMessage")); + } + + var request = PreRequest(_cloudRequestBuilder.Create() + .Resource("/ping") + .Build()); + + try + { + var response = _httpClient.Execute(request); + + // We only care about 400 responses, other error codes can be ignored + if (response.StatusCode == HttpStatusCode.BadRequest) + { + _logger.Error("Proxy Health Check failed: {0}", response.StatusCode); + failures.Add(new NzbDroneValidationFailure("Host", "ProxyCheckBadRequestMessage")); + } + } + catch (Exception ex) + { + _logger.Error(ex, "Proxy Health Check failed"); + failures.Add(new NzbDroneValidationFailure("Host", "ProxyCheckFailedToTestMessage")); + } + + return new ValidationResult(failures); + } + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/IIndexerProxy.cs b/src/NzbDrone.Core/IndexerProxies/IIndexerProxy.cs new file mode 100644 index 000000000..a814d564f --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/IIndexerProxy.cs @@ -0,0 +1,11 @@ +using NzbDrone.Common.Http; +using NzbDrone.Core.ThingiProvider; + +namespace NzbDrone.Core.IndexerProxies +{ + public interface IIndexerProxy : IProvider + { + HttpRequest PreRequest(HttpRequest request); + HttpResponse PostResponse(HttpResponse response); + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/IIndexerProxySettings.cs b/src/NzbDrone.Core/IndexerProxies/IIndexerProxySettings.cs new file mode 100644 index 000000000..932e42f89 --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/IIndexerProxySettings.cs @@ -0,0 +1,9 @@ +using NzbDrone.Core.ThingiProvider; + +namespace NzbDrone.Core.IndexerProxies +{ + public interface IIndexerProxySettings : IProviderConfig + { + string Host { get; set; } + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/IndexerProxyBase.cs b/src/NzbDrone.Core/IndexerProxies/IndexerProxyBase.cs new file mode 100644 index 000000000..b4c82808d --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/IndexerProxyBase.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using FluentValidation.Results; +using NzbDrone.Common.Http; +using NzbDrone.Core.ThingiProvider; + +namespace NzbDrone.Core.IndexerProxies +{ + public abstract class IndexerProxyBase<TSettings> : IIndexerProxy + where TSettings : IIndexerProxySettings, new() + { + public abstract string Name { get; } + public virtual ProviderMessage Message => null; + + public Type ConfigContract => typeof(TSettings); + + public IEnumerable<ProviderDefinition> DefaultDefinitions => new List<ProviderDefinition>(); + + public ProviderDefinition Definition { get; set; } + public abstract ValidationResult Test(); + + public abstract HttpRequest PreRequest(HttpRequest request); + public virtual HttpResponse PostResponse(HttpResponse response) + { + return response; + } + + protected TSettings Settings => (TSettings)Definition.Settings; + + public override string ToString() + { + return GetType().Name; + } + + public virtual object RequestAction(string action, IDictionary<string, string> query) + { + return null; + } + + private bool HasConcreteImplementation(string methodName) + { + var method = GetType().GetMethod(methodName); + + if (method == null) + { + throw new MissingMethodException(GetType().Name, Name); + } + + return !method.DeclaringType.IsAbstract; + } + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/IndexerProxyDefinition.cs b/src/NzbDrone.Core/IndexerProxies/IndexerProxyDefinition.cs new file mode 100644 index 000000000..6fb2c7ff2 --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/IndexerProxyDefinition.cs @@ -0,0 +1,10 @@ +using System.Linq; +using NzbDrone.Core.ThingiProvider; + +namespace NzbDrone.Core.IndexerProxies +{ + public class IndexerProxyDefinition : ProviderDefinition + { + public override bool Enable => Tags.Any(); + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/IndexerProxyFactory.cs b/src/NzbDrone.Core/IndexerProxies/IndexerProxyFactory.cs new file mode 100644 index 000000000..c21d9e2f4 --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/IndexerProxyFactory.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NLog; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.ThingiProvider; + +namespace NzbDrone.Core.IndexerProxies +{ + public interface IIndexerProxyFactory : IProviderFactory<IIndexerProxy, IndexerProxyDefinition> + { + } + + public class IndexerProxyFactory : ProviderFactory<IIndexerProxy, IndexerProxyDefinition>, IIndexerProxyFactory + { + public IndexerProxyFactory(IIndexerProxyRepository providerRepository, IEnumerable<IIndexerProxy> providers, IServiceProvider container, IEventAggregator eventAggregator, Logger logger) + : base(providerRepository, providers, container, eventAggregator, logger) + { + } + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/IndexerProxyRepository.cs b/src/NzbDrone.Core/IndexerProxies/IndexerProxyRepository.cs new file mode 100644 index 000000000..7b471a031 --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/IndexerProxyRepository.cs @@ -0,0 +1,24 @@ +using NzbDrone.Core.Datastore; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.ThingiProvider; + +namespace NzbDrone.Core.IndexerProxies +{ + public interface IIndexerProxyRepository : IProviderRepository<IndexerProxyDefinition> + { + void UpdateSettings(IndexerProxyDefinition model); + } + + public class IndexerProxyRepository : ProviderRepository<IndexerProxyDefinition>, IIndexerProxyRepository + { + public IndexerProxyRepository(IMainDatabase database, IEventAggregator eventAggregator) + : base(database, eventAggregator) + { + } + + public void UpdateSettings(IndexerProxyDefinition model) + { + SetFields(model, m => m.Settings); + } + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/IndexerProxyService.cs b/src/NzbDrone.Core/IndexerProxies/IndexerProxyService.cs new file mode 100644 index 000000000..5a86d1fb8 --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/IndexerProxyService.cs @@ -0,0 +1,19 @@ +using System; +using NLog; +using NzbDrone.Core.HealthCheck; +using NzbDrone.Core.Messaging.Events; + +namespace NzbDrone.Core.IndexerProxies +{ + public class IndexerProxyService + { + private readonly IIndexerProxyFactory _indexerProxyFactory; + private readonly Logger _logger; + + public IndexerProxyService(IIndexerProxyFactory indexerProxyFactory, Logger logger) + { + _indexerProxyFactory = indexerProxyFactory; + _logger = logger; + } + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs b/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs new file mode 100644 index 000000000..fa32e1673 --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs @@ -0,0 +1,66 @@ +using System; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using com.LandonKey.SocksWebProxy; +using com.LandonKey.SocksWebProxy.Proxy; +using NLog; +using NzbDrone.Common.Cloud; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; + +namespace NzbDrone.Core.IndexerProxies.Socks4 +{ + public class Socks4 : HttpIndexerProxyBase<Socks4Settings> + { + public Socks4(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger) + : base(cloudRequestBuilder, httpClient, logger) + { + } + + public override string Name => "Socks4"; + public override HttpRequest PreRequest(HttpRequest request) + { + if (Settings.Username.IsNotNullOrWhiteSpace() && Settings.Password.IsNotNullOrWhiteSpace()) + { + request.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(Settings.Host), Settings.Port, ProxyConfig.SocksVersion.Four), false); + } + else + { + request.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(Settings.Host), Settings.Port, ProxyConfig.SocksVersion.Four, Settings.Username, Settings.Password), false); + } + + _logger.Debug("Applying Socks4 Proxy {0} to request {1}", Name, request.Url); + + return request; + } + + private static int GetNextFreePort() + { + var listener = new TcpListener(IPAddress.Loopback, 0); + listener.Start(); + var port = ((IPEndPoint)listener.LocalEndpoint).Port; + listener.Stop(); + + return port; + } + + private static IPAddress GetProxyIpAddress(string host) + { + IPAddress ipAddress; + if (!IPAddress.TryParse(host, out ipAddress)) + { + try + { + ipAddress = Dns.GetHostEntry(host).AddressList.OrderByDescending(a => a.AddressFamily == AddressFamily.InterNetwork).First(); + } + catch (Exception e) + { + throw new InvalidOperationException(string.Format("Unable to resolve proxy hostname '{0}' to a valid IP address.", host), e); + } + } + + return ipAddress; + } + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4Settings.cs b/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4Settings.cs new file mode 100644 index 000000000..694b8fdea --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4Settings.cs @@ -0,0 +1,43 @@ +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.IndexerProxies.Socks4 +{ + public class Socks4SettingsValidator : AbstractValidator<Socks4Settings> + { + public Socks4SettingsValidator() + { + RuleFor(c => c.Host).NotEmpty(); + RuleFor(c => c.Port).NotEmpty(); + } + } + + public class Socks4Settings : IIndexerProxySettings + { + private static readonly Socks4SettingsValidator Validator = new Socks4SettingsValidator(); + + public Socks4Settings() + { + Username = ""; + Password = ""; + } + + [FieldDefinition(0, Label = "Host")] + public string Host { get; set; } + + [FieldDefinition(1, Label = "Port")] + public int Port { get; set; } + + [FieldDefinition(2, Label = "Username", Privacy = PrivacyLevel.UserName)] + public string Username { get; set; } + + [FieldDefinition(3, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] + public string Password { get; set; } + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs b/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs new file mode 100644 index 000000000..5c3727972 --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs @@ -0,0 +1,67 @@ +using System; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using com.LandonKey.SocksWebProxy; +using com.LandonKey.SocksWebProxy.Proxy; +using NLog; +using NzbDrone.Common.Cloud; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; + +namespace NzbDrone.Core.IndexerProxies.Socks5 +{ + public class Socks5 : HttpIndexerProxyBase<Socks5Settings> + { + public Socks5(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger) + : base(cloudRequestBuilder, httpClient, logger) + { + } + + public override string Name => "Socks5"; + + public override HttpRequest PreRequest(HttpRequest request) + { + if (Settings.Username.IsNotNullOrWhiteSpace() && Settings.Password.IsNotNullOrWhiteSpace()) + { + request.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(Settings.Host), Settings.Port, ProxyConfig.SocksVersion.Five), false); + } + else + { + request.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(Settings.Host), Settings.Port, ProxyConfig.SocksVersion.Five, Settings.Username, Settings.Password), false); + } + + _logger.Debug("Applying Socks5 Proxy {0} to request {1}", Name, request.Url); + + return request; + } + + private static int GetNextFreePort() + { + var listener = new TcpListener(IPAddress.Loopback, 0); + listener.Start(); + var port = ((IPEndPoint)listener.LocalEndpoint).Port; + listener.Stop(); + + return port; + } + + private static IPAddress GetProxyIpAddress(string host) + { + IPAddress ipAddress; + if (!IPAddress.TryParse(host, out ipAddress)) + { + try + { + ipAddress = Dns.GetHostEntry(host).AddressList.OrderByDescending(a => a.AddressFamily == AddressFamily.InterNetwork).First(); + } + catch (Exception e) + { + throw new InvalidOperationException(string.Format("Unable to resolve proxy hostname '{0}' to a valid IP address.", host), e); + } + } + + return ipAddress; + } + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5Settings.cs b/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5Settings.cs new file mode 100644 index 000000000..071881441 --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5Settings.cs @@ -0,0 +1,43 @@ +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.IndexerProxies.Socks5 +{ + public class Socks5SettingsValidator : AbstractValidator<Socks5Settings> + { + public Socks5SettingsValidator() + { + RuleFor(c => c.Host).NotEmpty(); + RuleFor(c => c.Port).NotEmpty(); + } + } + + public class Socks5Settings : IIndexerProxySettings + { + private static readonly Socks5SettingsValidator Validator = new Socks5SettingsValidator(); + + public Socks5Settings() + { + Username = ""; + Password = ""; + } + + [FieldDefinition(0, Label = "Host")] + public string Host { get; set; } + + [FieldDefinition(1, Label = "Port")] + public int Port { get; set; } + + [FieldDefinition(2, Label = "Username", Privacy = PrivacyLevel.UserName)] + public string Username { get; set; } + + [FieldDefinition(3, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] + public string Password { get; set; } + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Aither.cs b/src/NzbDrone.Core/Indexers/Definitions/Aither.cs index ea6d3a5b8..1aff169c4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Aither.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Aither.cs @@ -15,7 +15,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Language => "en-us"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public Aither(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public Aither(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/AlphaRatio.cs b/src/NzbDrone.Core/Indexers/Definitions/AlphaRatio.cs index 90390fbdf..1b1329374 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AlphaRatio.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AlphaRatio.cs @@ -13,7 +13,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Description => "AlphaRatio(AR) is a Private Torrent Tracker for 0DAY / GENERAL"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public AlphaRatio(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public AlphaRatio(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs b/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs index 278e2040f..c31bae08e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPublic; public override IndexerCapabilities Capabilities => SetCapabilities(); - public Anidub(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public Anidub(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } @@ -58,7 +58,7 @@ namespace NzbDrone.Core.Indexers.Definitions AllowAutoRedirect = true }; - var mainPage = await _httpClient.ExecuteAsync(new HttpRequest(Settings.BaseUrl)); + var mainPage = await ExecuteAuth(new HttpRequest(Settings.BaseUrl)); requestBuilder.Method = Common.Http.HttpMethod.POST; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); @@ -254,7 +254,7 @@ namespace NzbDrone.Core.Indexers.Definitions { private readonly AnidubSettings _settings; private readonly IndexerCapabilitiesCategories _categories; - public IHttpClient HttpClient { get; set; } + public IIndexerHttpClient HttpClient { get; set; } public Logger Logger { get; set; } private static Dictionary<string, string> CategoriesMap => new Dictionary<string, string> diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs b/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs index 464e392a8..fd8469149 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Public; public override IndexerCapabilities Capabilities => SetCapabilities(); - public Anilibria(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public Anilibria(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs index 54318e20f..d0f9135b6 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs @@ -34,7 +34,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public AnimeBytes(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public AnimeBytes(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs index e68495616..600205049 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public AnimeTorrents(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public AnimeTorrents(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } @@ -56,7 +56,7 @@ namespace NzbDrone.Core.Indexers.Definitions AllowAutoRedirect = true }; - var loginPage = await _httpClient.ExecuteAsync(new HttpRequest(LoginUrl)); + var loginPage = await ExecuteAuth(new HttpRequest(LoginUrl)); requestBuilder.Method = HttpMethod.POST; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); requestBuilder.SetCookies(loginPage.GetCookies()); diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs index c6eb1a217..55f871a0e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs @@ -15,7 +15,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Language => "de-de"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public AnimeWorld(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public AnimeWorld(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs b/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs index 1a6275347..7d8297d69 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Public; public override IndexerCapabilities Capabilities => SetCapabilities(); - public Animedia(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public Animedia(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } @@ -153,7 +153,7 @@ namespace NzbDrone.Core.Indexers.Definitions private static readonly Regex CategorieMovieRegex = new Regex(@"Фильм", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex CategorieOVARegex = new Regex(@"ОВА|OVA|ОНА|ONA|Special", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex CategorieDoramaRegex = new Regex(@"Дорама", RegexOptions.Compiled | RegexOptions.IgnoreCase); - public IHttpClient HttpClient { get; set; } + public IIndexerHttpClient HttpClient { get; set; } public Logger Logger { get; set; } public AnimediaParser(AnimediaSettings settings, IndexerCapabilitiesCategories categories) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs b/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs index 6b4178183..b99807cdc 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public Anthelion(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public Anthelion(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/AvistaZ.cs b/src/NzbDrone.Core/Indexers/Definitions/AvistaZ.cs index ec55fd785..97dda7e42 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AvistaZ.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AvistaZ.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Description => "Aka AsiaTorrents"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public AvistaZ(IIndexerRepository indexerRepository, IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public AvistaZ(IIndexerRepository indexerRepository, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(indexerRepository, httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazBase.cs index 3e39259c8..f231fae7c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazBase.cs @@ -21,7 +21,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz private IIndexerRepository _indexerRepository; public AvistazBase(IIndexerRepository indexerRepository, - IHttpClient httpClient, + IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs index 81f9b3c42..ab8d086b7 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz public AvistazSettings Settings { get; set; } public IDictionary<string, string> AuthCookieCache { get; set; } - public IHttpClient HttpClient { get; set; } + public IIndexerHttpClient HttpClient { get; set; } public IndexerCapabilities Capabilities { get; set; } public Logger Logger { get; set; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/BB.cs b/src/NzbDrone.Core/Indexers/Definitions/BB.cs index cb8114d93..b6ecf0c38 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BB.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BB.cs @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public BB(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public BB(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs index bc8e123c4..4266f7889 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public BakaBT(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public BakaBT(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } @@ -56,7 +56,7 @@ namespace NzbDrone.Core.Indexers.Definitions AllowAutoRedirect = true }; - var loginPage = await _httpClient.ExecuteAsync(new HttpRequest(LoginUrl)); + var loginPage = await ExecuteAuth(new HttpRequest(LoginUrl)); requestBuilder.Method = HttpMethod.POST; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); @@ -78,7 +78,7 @@ namespace NzbDrone.Core.Indexers.Definitions .SetHeader("Content-Type", "multipart/form-data") .Build(); - var response = await _httpClient.ExecuteAsync(authLoginRequest); + var response = await ExecuteAuth(authLoginRequest); if (response.Content != null && response.Content.Contains("<a href=\"logout.php\">Logout</a>")) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs b/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs index 3337c89b6..acda788be 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public BeyondHD(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public BeyondHD(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs b/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs index dd1ed9d45..a2cfdc38f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override bool SupportsRss => false; public override IndexerCapabilities Capabilities => SetCapabilities(); - public BinSearch(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger) + public BinSearch(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, nzbValidationService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs b/src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs index 72152ed02..45302f0d9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Description => "Blutopia (BLU) is a Private Torrent Tracker for HD MOVIES / TV"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public Blutopia(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public Blutopia(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs b/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs index 7664792af..bf5762aaa 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs @@ -20,7 +20,7 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet public override string[] IndexerUrls => new string[] { "http://api.broadcasthe.net/" }; public override string Description => "BroadcasTheNet (BTN) is an invite-only torrent tracker focused on TV shows"; - public BroadcastheNet(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public BroadcastheNet(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/BrokenStones.cs b/src/NzbDrone.Core/Indexers/Definitions/BrokenStones.cs index 1be45bf2c..1ab58c181 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BrokenStones.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BrokenStones.cs @@ -12,7 +12,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Description => "Broken Stones is a Private site for MacOS and iOS APPS / GAMES"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public BrokenStones(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public BrokenStones(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/CGPeers.cs b/src/NzbDrone.Core/Indexers/Definitions/CGPeers.cs index 61f7baaed..c82b62fa2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/CGPeers.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/CGPeers.cs @@ -12,7 +12,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Description => "CGPeers is a Private Torrent Tracker for GRAPHICS SOFTWARE / TUTORIALS / ETC"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public CGPeers(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public CGPeers(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs index 07d2e5b0d..3ba142241 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs @@ -41,6 +41,7 @@ namespace NzbDrone.Core.Indexers.Cardigann _logger) { HttpClient = _httpClient, + Definition = Definition, Settings = Settings }); @@ -85,7 +86,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } public Cardigann(IIndexerDefinitionUpdateService definitionService, - IHttpClient httpClient, + IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, @@ -176,7 +177,7 @@ namespace NzbDrone.Core.Indexers.Cardigann try { - var response = await _httpClient.ExecuteAsync(request); + var response = await _httpClient.ExecuteAsync(request, Definition); downloadBytes = response.ResponseData; } catch (HttpException ex) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 52aa156bd..644229ad2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -13,12 +13,14 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Definitions.Cardigann; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Parser; +using NzbDrone.Core.ThingiProvider; namespace NzbDrone.Core.Indexers.Cardigann { public class CardigannRequestGenerator : CardigannBase, IIndexerRequestGenerator { - public IHttpClient HttpClient { get; set; } + public IIndexerHttpClient HttpClient { get; set; } + public ProviderDefinition Definition { get; set; } public IDictionary<string, string> Cookies { get; set; } protected HttpResponse landingResult; protected IHtmlDocument landingResultDocument; @@ -192,7 +194,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.Headers.Add("Referer", SiteLink); - var response = await HttpClient.ExecuteAsync(requestBuilder.Build()); + var response = await HttpClient.ExecuteAsync(requestBuilder.Build(), Definition); Cookies = response.GetCookies(); @@ -329,7 +331,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.Headers.Add("Referer", loginUrl); - var simpleCaptchaResult = await HttpClient.ExecuteAsync(requestBuilder.Build()); + var simpleCaptchaResult = await HttpClient.ExecuteAsync(requestBuilder.Build(), Definition); var simpleCaptchaJSON = JObject.Parse(simpleCaptchaResult.Content); var captchaSelection = simpleCaptchaJSON["images"][0]["hash"].ToString(); @@ -409,7 +411,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var request = requestBuilder.Build(); request.SetContent(body); - loginResult = await HttpClient.ExecuteAsync(request); + loginResult = await HttpClient.ExecuteAsync(request, Definition); } else { @@ -429,7 +431,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.AddFormParameter(pair.Key, pair.Value); } - loginResult = await HttpClient.ExecuteAsync(requestBuilder.Build()); + loginResult = await HttpClient.ExecuteAsync(requestBuilder.Build(), Definition); } Cookies = loginResult.GetCookies(); @@ -464,7 +466,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.Headers.Add("Referer", SiteLink); - var response = await HttpClient.ExecuteAsync(requestBuilder.Build()); + var response = await HttpClient.ExecuteAsync(requestBuilder.Build(), Definition); Cookies = response.GetCookies(); @@ -488,7 +490,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.Headers.Add("Referer", SiteLink); - var response = await HttpClient.ExecuteAsync(requestBuilder.Build()); + var response = await HttpClient.ExecuteAsync(requestBuilder.Build(), Definition); Cookies = response.GetCookies(); @@ -567,7 +569,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var request = requestBuilder.Build(); - landingResult = await HttpClient.ExecuteAsync(request); + landingResult = await HttpClient.ExecuteAsync(request, Definition); Cookies = landingResult.GetCookies(); @@ -611,7 +613,7 @@ namespace NzbDrone.Core.Indexers.Cardigann .SetHeader("Referer", loginUrl.AbsoluteUri) .Build(); - var response = await HttpClient.ExecuteAsync(request); + var response = await HttpClient.ExecuteAsync(request, Definition); return new Captcha { @@ -701,7 +703,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } } - var response = await HttpClient.ExecuteAsync(httpRequest.Build()); + var response = await HttpClient.ExecuteAsync(httpRequest.Build(), Definition); _logger.Debug($"CardigannIndexer ({_definition.Id}): handleRequest() remote server returned {response.StatusCode.ToString()}"); return response; @@ -741,7 +743,7 @@ namespace NzbDrone.Core.Indexers.Cardigann request.AllowAutoRedirect = true; - var response = await HttpClient.ExecuteAsync(request); + var response = await HttpClient.ExecuteAsync(request, Definition); var results = response.Content; var searchResultParser = new HtmlParser(); diff --git a/src/NzbDrone.Core/Indexers/Definitions/CinemaZ.cs b/src/NzbDrone.Core/Indexers/Definitions/CinemaZ.cs index c1e39a218..0f872ee08 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/CinemaZ.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/CinemaZ.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Description => "CinemaZ (EuTorrents) is a Private Torrent Tracker for FOREIGN NON-ASIAN MOVIES."; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public CinemaZ(IIndexerRepository indexerRepository, IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public CinemaZ(IIndexerRepository indexerRepository, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(indexerRepository, httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs index 50ba133a8..b4a66c93e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public DanishBytes(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public DanishBytes(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs b/src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs index 7631cc6db..432946efb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public DigitalCore(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public DigitalCore(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/ExoticaZ.cs b/src/NzbDrone.Core/Indexers/Definitions/ExoticaZ.cs index 91618971a..61fc89751 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ExoticaZ.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ExoticaZ.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Description => "ExoticaZ (YourExotic) is a Private Torrent Tracker for 3X"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public ExoticaZ(IIndexerRepository indexerRepository, IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public ExoticaZ(IIndexerRepository indexerRepository, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(indexerRepository, httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileList.cs b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileList.cs index 3be337450..d07ac31c2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileList.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileList.cs @@ -18,7 +18,7 @@ namespace NzbDrone.Core.Indexers.FileList public override bool SupportsRedirect => true; public override IndexerCapabilities Capabilities => SetCapabilities(); - public FileList(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public FileList(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs index 03e7281af..bf316f438 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs @@ -17,7 +17,7 @@ namespace NzbDrone.Core.Indexers.Gazelle public override int PageSize => 50; public override IndexerCapabilities Capabilities => SetCapabilities(); - public Gazelle(IHttpClient httpClient, + public Gazelle(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs index c2646c441..3a1e5361d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs @@ -11,7 +11,7 @@ namespace NzbDrone.Core.Indexers.Gazelle public GazelleSettings Settings { get; set; } public IDictionary<string, string> AuthCookieCache { get; set; } - public IHttpClient HttpClient { get; set; } + public IIndexerHttpClient HttpClient { get; set; } public IndexerCapabilities Capabilities { get; set; } public Logger Logger { get; set; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs b/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs index 30ffb5da0..01eb277e9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public GazelleGames(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public GazelleGames(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBits.cs b/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBits.cs index 43425cb96..b5426b8ac 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBits.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBits.cs @@ -18,7 +18,7 @@ namespace NzbDrone.Core.Indexers.HDBits public override int PageSize => 30; - public HDBits(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public HDBits(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs b/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs index 8c1832067..b3a953b0b 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public HDSpace(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public HDSpace(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } @@ -49,7 +49,7 @@ namespace NzbDrone.Core.Indexers.Definitions protected override async Task DoLogin() { - var loginPage = await _httpClient.ExecuteAsync(new HttpRequest(LoginUrl)); + var loginPage = await ExecuteAuth(new HttpRequest(LoginUrl)); var requestBuilder = new HttpRequestBuilder(LoginUrl) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs index c15401f91..4c860d812 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public HDTorrents(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public HDTorrents(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs b/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs index d19ddabeb..c6afa18f1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Core.Indexers.Headphones return new HeadphonesRssParser(Capabilities.Categories); } - public Headphones(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger) + public Headphones(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, nzbValidationService, logger) { } @@ -63,7 +63,7 @@ namespace NzbDrone.Core.Indexers.Headphones try { - var response = await _httpClient.ExecuteAsync(request); + var response = await _httpClient.ExecuteAsync(request, Definition); downloadBytes = response.ResponseData; } catch (Exception) diff --git a/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs index 6a29006ac..e42c20979 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs @@ -40,7 +40,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public IPTorrents(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public IPTorrents(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs b/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs index 28fa0aac8..77b81d1fc 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public ImmortalSeed(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public ImmortalSeed(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs b/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs index 1f3474262..91e01dded 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override bool FollowRedirect => true; - public InternetArchive(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public InternetArchive(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Milkie.cs b/src/NzbDrone.Core/Indexers/Definitions/Milkie.cs index 5e681adad..6b465ca5a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Milkie.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Milkie.cs @@ -25,7 +25,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public Milkie(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public Milkie(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs b/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs index 8da08bd97..0e2db997e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public MyAnonamouse(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public MyAnonamouse(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs index 901175f5d..a73234f40 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public Nebulance(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public Nebulance(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs index 37ba5f4df..d6e73e22e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Indexers.Newznab public override IndexerCapabilities Capabilities { get => GetCapabilitiesFromSettings(); protected set => base.Capabilities = value; } - public override int PageSize => _capabilitiesProvider.GetCapabilities(Settings).LimitsDefault.Value; + public override int PageSize => _capabilitiesProvider.GetCapabilities(Settings, Definition).LimitsDefault.Value; public override IIndexerRequestGenerator GetRequestGenerator() { @@ -77,7 +77,7 @@ namespace NzbDrone.Core.Indexers.Newznab public override IndexerCapabilities GetCapabilities() { // Newznab uses different Caps per site, so we need to cache them to db on first indexer add to prevent issues with loading UI and pulling caps every time. - return _capabilitiesProvider.GetCapabilities(Settings); + return _capabilitiesProvider.GetCapabilities(Settings, Definition); } public override IEnumerable<ProviderDefinition> DefaultDefinitions @@ -112,7 +112,7 @@ namespace NzbDrone.Core.Indexers.Newznab } } - public Newznab(INewznabCapabilitiesProvider capabilitiesProvider, IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger) + public Newznab(INewznabCapabilitiesProvider capabilitiesProvider, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, nzbValidationService, logger) { _capabilitiesProvider = capabilitiesProvider; @@ -169,7 +169,7 @@ namespace NzbDrone.Core.Indexers.Newznab { try { - var capabilities = _capabilitiesProvider.GetCapabilities(Settings); + var capabilities = _capabilitiesProvider.GetCapabilities(Settings, Definition); if (capabilities.SearchParams != null && capabilities.SearchParams.Contains(SearchParam.Q)) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs index 9b9a4fe2a..fe069c0bc 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs @@ -7,36 +7,37 @@ using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Common.Serializer; +using NzbDrone.Core.ThingiProvider; namespace NzbDrone.Core.Indexers.Newznab { public interface INewznabCapabilitiesProvider { - IndexerCapabilities GetCapabilities(NewznabSettings settings); + IndexerCapabilities GetCapabilities(NewznabSettings settings, ProviderDefinition definition); } public class NewznabCapabilitiesProvider : INewznabCapabilitiesProvider { private readonly ICached<IndexerCapabilities> _capabilitiesCache; - private readonly IHttpClient _httpClient; + private readonly IIndexerHttpClient _httpClient; private readonly Logger _logger; - public NewznabCapabilitiesProvider(ICacheManager cacheManager, IHttpClient httpClient, Logger logger) + public NewznabCapabilitiesProvider(ICacheManager cacheManager, IIndexerHttpClient httpClient, Logger logger) { _capabilitiesCache = cacheManager.GetCache<IndexerCapabilities>(GetType()); _httpClient = httpClient; _logger = logger; } - public IndexerCapabilities GetCapabilities(NewznabSettings indexerSettings) + public IndexerCapabilities GetCapabilities(NewznabSettings indexerSettings, ProviderDefinition definition) { var key = indexerSettings.ToJson(); - var capabilities = _capabilitiesCache.Get(key, () => FetchCapabilities(indexerSettings), TimeSpan.FromDays(7)); + var capabilities = _capabilitiesCache.Get(key, () => FetchCapabilities(indexerSettings, definition), TimeSpan.FromDays(7)); return capabilities; } - private IndexerCapabilities FetchCapabilities(NewznabSettings indexerSettings) + private IndexerCapabilities FetchCapabilities(NewznabSettings indexerSettings, ProviderDefinition definition) { var capabilities = new IndexerCapabilities(); @@ -49,12 +50,13 @@ namespace NzbDrone.Core.Indexers.Newznab var request = new HttpRequest(url, HttpAccept.Rss); request.AllowAutoRedirect = true; + request.Method = HttpMethod.GET; HttpResponse response; try { - response = _httpClient.Get(request); + response = _httpClient.Execute(request, definition); } catch (Exception ex) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs index 45a8b8729..f8835e82a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs @@ -6,6 +6,7 @@ using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Parser; +using NzbDrone.Core.ThingiProvider; namespace NzbDrone.Core.Indexers.Newznab { @@ -15,6 +16,7 @@ namespace NzbDrone.Core.Indexers.Newznab public int MaxPages { get; set; } public int PageSize { get; set; } public NewznabSettings Settings { get; set; } + public ProviderDefinition Definition { get; set; } public NewznabRequestGenerator(INewznabCapabilitiesProvider capabilitiesProvider) { @@ -26,7 +28,7 @@ namespace NzbDrone.Core.Indexers.Newznab public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) { - var capabilities = _capabilitiesProvider.GetCapabilities(Settings); + var capabilities = _capabilitiesProvider.GetCapabilities(Settings, Definition); var pageableRequests = new IndexerPageableRequestChain(); var parameters = new NameValueCollection(); @@ -72,7 +74,7 @@ namespace NzbDrone.Core.Indexers.Newznab public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) { - var capabilities = _capabilitiesProvider.GetCapabilities(Settings); + var capabilities = _capabilitiesProvider.GetCapabilities(Settings, Definition); var pageableRequests = new IndexerPageableRequestChain(); var parameters = new NameValueCollection(); @@ -113,7 +115,7 @@ namespace NzbDrone.Core.Indexers.Newznab public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) { - var capabilities = _capabilitiesProvider.GetCapabilities(Settings); + var capabilities = _capabilitiesProvider.GetCapabilities(Settings, Definition); var pageableRequests = new IndexerPageableRequestChain(); var parameters = new NameValueCollection(); @@ -174,7 +176,7 @@ namespace NzbDrone.Core.Indexers.Newznab public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) { - var capabilities = _capabilitiesProvider.GetCapabilities(Settings); + var capabilities = _capabilitiesProvider.GetCapabilities(Settings, Definition); var pageableRequests = new IndexerPageableRequestChain(); var parameters = new NameValueCollection(); @@ -215,7 +217,7 @@ namespace NzbDrone.Core.Indexers.Newznab public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) { - var capabilities = _capabilitiesProvider.GetCapabilities(Settings); + var capabilities = _capabilitiesProvider.GetCapabilities(Settings, Definition); var pageableRequests = new IndexerPageableRequestChain(); var parameters = new NameValueCollection(); diff --git a/src/NzbDrone.Core/Indexers/Definitions/NotWhatCD.cs b/src/NzbDrone.Core/Indexers/Definitions/NotWhatCD.cs index b305358f8..36b0ff1f0 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/NotWhatCD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/NotWhatCD.cs @@ -13,7 +13,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Description => "NotWhat.CD (NWCD) is a private Music tracker that arised after the former (WCD) shut down."; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public NotWhatCD(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public NotWhatCD(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs index 1cf42b846..a0316a18b 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs @@ -13,7 +13,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Description => "Orpheus (APOLLO) is a Private Torrent Tracker for MUSIC"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public Orpheus(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public Orpheus(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcorn.cs b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcorn.cs index a7dc63a15..9f76e5109 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcorn.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcorn.cs @@ -21,7 +21,7 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn public override int PageSize => 50; - public PassThePopcorn(IHttpClient httpClient, + public PassThePopcorn(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, ICacheManager cacheManager, IIndexerStatusService indexerStatusService, diff --git a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornRequestGenerator.cs index 0bc70fd41..40c1fd867 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornRequestGenerator.cs @@ -13,7 +13,7 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn public IDictionary<string, string> Cookies { get; set; } - public IHttpClient HttpClient { get; set; } + public IIndexerHttpClient HttpClient { get; set; } public Logger Logger { get; set; } public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) diff --git a/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs b/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs index 69ab1cfea..c7e3e7390 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public PreToMe(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public PreToMe(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } @@ -57,7 +57,7 @@ namespace NzbDrone.Core.Indexers.Definitions AllowAutoRedirect = true }; - var loginPage = await _httpClient.ExecuteAsync(new HttpRequest(Settings.BaseUrl + "login.php")); + var loginPage = await ExecuteAuth(new HttpRequest(Settings.BaseUrl + "login.php")); requestBuilder.Method = HttpMethod.POST; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); diff --git a/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs b/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs index ee4d6595b..bb1fac39e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Description => "PrivateHD is a Private Torrent Tracker for HD MOVIES / TV and the sister-site of AvistaZ, CinemaZ, ExoticaZ, and AnimeTorrents"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public PrivateHD(IIndexerRepository indexerRepository, IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public PrivateHD(IIndexerRepository indexerRepository, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(indexerRepository, httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs index 6d17559fb..5ba132468 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Indexers.Rarbg public override TimeSpan RateLimit => TimeSpan.FromSeconds(2); - public Rarbg(IRarbgTokenProvider tokenProvider, IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public Rarbg(IRarbgTokenProvider tokenProvider, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { _tokenProvider = tokenProvider; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs index a4686ee82..2319105a4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs @@ -14,11 +14,11 @@ namespace NzbDrone.Core.Indexers.Rarbg public class RarbgTokenProvider : IRarbgTokenProvider { - private readonly IHttpClient _httpClient; + private readonly IIndexerHttpClient _httpClient; private readonly ICached<string> _tokenCache; private readonly Logger _logger; - public RarbgTokenProvider(IHttpClient httpClient, ICacheManager cacheManager, Logger logger) + public RarbgTokenProvider(IIndexerHttpClient httpClient, ICacheManager cacheManager, Logger logger) { _httpClient = httpClient; _tokenCache = cacheManager.GetCache<string>(GetType()); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs b/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs index 0a13f6000..5f664cd05 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerCapabilities Capabilities => SetCapabilities(); public override bool SupportsRedirect => true; - public Redacted(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public Redacted(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } @@ -93,7 +93,7 @@ namespace NzbDrone.Core.Indexers.Definitions public IndexerCapabilities Capabilities { get; set; } public Func<IDictionary<string, string>> GetCookies { get; set; } public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - public IHttpClient HttpClient { get; set; } + public IIndexerHttpClient HttpClient { get; set; } public RedactedRequestGenerator() { diff --git a/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs b/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs index 31f4e0c2a..41e66ba09 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public RevolutionTT(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public RevolutionTT(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } @@ -56,7 +56,7 @@ namespace NzbDrone.Core.Indexers.Definitions AllowAutoRedirect = true }; - var loginPage = await _httpClient.ExecuteAsync(new HttpRequest(Settings.BaseUrl + "login.php")); + var loginPage = await ExecuteAuth(new HttpRequest(Settings.BaseUrl + "login.php")); requestBuilder.Method = HttpMethod.POST; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); diff --git a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs index 4a48547fc..408c7ad83 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs @@ -34,7 +34,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public RuTracker(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public RuTracker(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs b/src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs index fc0ae8fa3..f982bcdc3 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public SceneTime(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public SceneTime(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs b/src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs index b9f5c3996..31553311e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public SecretCinema(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public SecretCinema(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs b/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs index 6b497eee2..0698e0859 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs @@ -15,7 +15,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Language => "it-it"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public ShareIsland(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public ShareIsland(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Shizaproject.cs b/src/NzbDrone.Core/Indexers/Definitions/Shizaproject.cs index 3c329afbf..5ad5cbf9f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Shizaproject.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Shizaproject.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Public; public override IndexerCapabilities Capabilities => SetCapabilities(); - public Shizaproject(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public Shizaproject(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs b/src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs index ad7d0992b..11ec011d1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Public; public override IndexerCapabilities Capabilities => SetCapabilities(); - public ShowRSS(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public ShowRSS(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs index 5ef0518ca..316b3f7ba 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs @@ -48,7 +48,7 @@ namespace NzbDrone.Core.Indexers.Definitions private IIndexerRepository _indexerRepository; - public SpeedApp(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger, IIndexerRepository indexerRepository) + public SpeedApp(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger, IIndexerRepository indexerRepository) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { _indexerRepository = indexerRepository; @@ -141,7 +141,7 @@ namespace NzbDrone.Core.Indexers.Definitions try { - var response = await _httpClient.ExecuteAsync(request); + var response = await _httpClient.ExecuteAsync(request, Definition); torrentData = response.ResponseData; } catch (HttpException ex) diff --git a/src/NzbDrone.Core/Indexers/Definitions/SubsPlease.cs b/src/NzbDrone.Core/Indexers/Definitions/SubsPlease.cs index 9085a1afd..69e47b9d5 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SubsPlease.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SubsPlease.cs @@ -34,7 +34,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Public; public override IndexerCapabilities Capabilities => SetCapabilities(); - public SubsPlease(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public SubsPlease(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs b/src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs index dc92cf62a..4b433eea3 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public SuperBits(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public SuperBits(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs b/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs index ed822a85d..6f2891cb1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public TVVault(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public TVVault(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs b/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs index 17a2ced98..047cb5ece 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Public; public override IndexerCapabilities Capabilities => SetCapabilities(); - public ThePirateBay(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public ThePirateBay(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs index b2c9c8bc2..af9c444d0 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs @@ -38,7 +38,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public TorrentDay(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public TorrentDay(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs index 1783ebe8c..6b21342ee 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public TorrentLeech(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public TorrentLeech(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs index 0e95632df..cf8973080 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Public; public override IndexerCapabilities Capabilities => SetCapabilities(); - public TorrentParadiseMl(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public TorrentParadiseMl(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentPotato/TorrentPotato.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentPotato/TorrentPotato.cs index e9638c821..a75e3e67b 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentPotato/TorrentPotato.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentPotato/TorrentPotato.cs @@ -16,7 +16,7 @@ namespace NzbDrone.Core.Indexers.TorrentPotato public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override TimeSpan RateLimit => TimeSpan.FromSeconds(2); - public TorrentPotato(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public TorrentPotato(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs index 6557a917b..f6e400e0e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public TorrentSeeds(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public TorrentSeeds(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } @@ -53,7 +53,7 @@ namespace NzbDrone.Core.Indexers.Definitions LogResponseContent = true }; - var loginPage = await _httpClient.ExecuteAsync(new HttpRequest(TokenUrl)); + var loginPage = await ExecuteAuth(new HttpRequest(TokenUrl)); var parser = new HtmlParser(); var dom = parser.ParseDocument(loginPage.Content); var token = dom.QuerySelector("form.form-horizontal > span"); @@ -74,7 +74,7 @@ namespace NzbDrone.Core.Indexers.Definitions .SetHeader("Content-Type", "multipart/form-data") .Build(); - var response = await _httpClient.ExecuteAsync(authLoginRequest); + var response = await ExecuteAuth(authLoginRequest); cookies = response.GetCookies(); UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs index 97cd08897..ce819f2eb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public TorrentSyndikat(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public TorrentSyndikat(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentsCSV.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentsCSV.cs index b68da5b9f..027febd03 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentsCSV.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentsCSV.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerCapabilities Capabilities => SetCapabilities(); public override bool SupportsRss => false; - public TorrentsCSV(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public TorrentsCSV(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs index 8bf5c06ff..997a9477f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Indexers.Torznab public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public override int PageSize => _capabilitiesProvider.GetCapabilities(Settings).LimitsDefault.Value; + public override int PageSize => _capabilitiesProvider.GetCapabilities(Settings, Definition).LimitsDefault.Value; public override IndexerCapabilities Capabilities { get => GetCapabilitiesFromSettings(); protected set => base.Capabilities = value; } public override IIndexerRequestGenerator GetRequestGenerator() @@ -76,7 +76,7 @@ namespace NzbDrone.Core.Indexers.Torznab public override IndexerCapabilities GetCapabilities() { // Newznab uses different Caps per site, so we need to cache them to db on first indexer add to prevent issues with loading UI and pulling caps every time. - return _capabilitiesProvider.GetCapabilities(Settings); + return _capabilitiesProvider.GetCapabilities(Settings, Definition); } public override IEnumerable<ProviderDefinition> DefaultDefinitions @@ -89,7 +89,7 @@ namespace NzbDrone.Core.Indexers.Torznab } } - public Torznab(INewznabCapabilitiesProvider capabilitiesProvider, IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public Torznab(INewznabCapabilitiesProvider capabilitiesProvider, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { _capabilitiesProvider = capabilitiesProvider; @@ -145,7 +145,7 @@ namespace NzbDrone.Core.Indexers.Torznab { try { - var capabilities = _capabilitiesProvider.GetCapabilities(Settings); + var capabilities = _capabilitiesProvider.GetCapabilities(Settings, Definition); if (capabilities.SearchParams != null && capabilities.SearchParams.Contains(SearchParam.Q)) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/UNIT3D/Unit3dBase.cs b/src/NzbDrone.Core/Indexers/Definitions/UNIT3D/Unit3dBase.cs index a96a6da84..c5e17194c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/UNIT3D/Unit3dBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/UNIT3D/Unit3dBase.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Core.Indexers.Definitions.UNIT3D public override int PageSize => 50; public override IndexerCapabilities Capabilities => SetCapabilities(); - public Unit3dBase(IHttpClient httpClient, + public Unit3dBase(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, diff --git a/src/NzbDrone.Core/Indexers/Definitions/UNIT3D/Unit3dRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/UNIT3D/Unit3dRequestGenerator.cs index 4797a26f5..5957534f2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/UNIT3D/Unit3dRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/UNIT3D/Unit3dRequestGenerator.cs @@ -12,7 +12,7 @@ namespace NzbDrone.Core.Indexers.Definitions.UNIT3D { public Unit3dSettings Settings { get; set; } - public IHttpClient HttpClient { get; set; } + public IIndexerHttpClient HttpClient { get; set; } public IndexerCapabilities Capabilities { get; set; } public Logger Logger { get; set; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs b/src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs index c5f1419ea..108df2755 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs @@ -21,7 +21,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Xthor public override TimeSpan RateLimit => TimeSpan.FromSeconds(2.1); public override IndexerCapabilities Capabilities => SetCapabilities(); - public Xthor(IHttpClient httpClient, + public Xthor(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, diff --git a/src/NzbDrone.Core/Indexers/Definitions/YTS.cs b/src/NzbDrone.Core/Indexers/Definitions/YTS.cs index d98ee986e..169835c23 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/YTS.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/YTS.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override TimeSpan RateLimit => TimeSpan.FromSeconds(2.5); public override IndexerCapabilities Capabilities => SetCapabilities(); - public YTS(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public YTS(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs b/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs index 1b07f4a4b..80bb816c2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs @@ -39,7 +39,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); - public ZonaQ(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public ZonaQ(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } @@ -59,7 +59,7 @@ namespace NzbDrone.Core.Indexers.Definitions _logger.Debug("ZonaQ authentication succeeded."); // The first page set the cookies and the session_id - var loginPage = await _httpClient.ExecuteAsync(new HttpRequest(Login1Url)); + var loginPage = await ExecuteAuth(new HttpRequest(Login1Url)); var parser = new HtmlParser(); var dom = parser.ParseDocument(loginPage.Content); var sessionId = dom.QuerySelector("input#session_id")?.GetAttribute("value"); @@ -132,7 +132,7 @@ namespace NzbDrone.Core.Indexers.Definitions requestBuilder4.SetCookies(response.GetCookies()); var authLoginRequest3 = requestBuilder4.Build(); - response = await _httpClient.ExecuteAsync(authLoginRequest3); + response = await ExecuteAuth(authLoginRequest3); UpdateCookies(response.GetCookies(), DateTime.Now + TimeSpan.FromDays(30)); } diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index ef1e4f51d..5a7c87bad 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -23,7 +23,7 @@ namespace NzbDrone.Core.Indexers { protected const int MaxNumResultsPerQuery = 1000; - protected readonly IHttpClient _httpClient; + protected readonly IIndexerHttpClient _httpClient; protected readonly IEventAggregator _eventAggregator; public IDictionary<string, string> Cookies { get; set; } @@ -42,7 +42,7 @@ namespace NzbDrone.Core.Indexers public abstract IIndexerRequestGenerator GetRequestGenerator(); public abstract IParseIndexerResponse GetParser(); - public HttpIndexerBase(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + public HttpIndexerBase(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(indexerStatusService, configService, logger) { _httpClient = httpClient; @@ -379,7 +379,7 @@ namespace NzbDrone.Core.Indexers request.HttpRequest.SuppressHttpError = true; request.HttpRequest.Encoding = Encoding; - var response = await _httpClient.ExecuteAsync(request.HttpRequest); + var response = await _httpClient.ExecuteAsync(request.HttpRequest, Definition); // Check reponse to see if auth is needed, if needed try again if (CheckIfLoginNeeded(response)) @@ -391,7 +391,7 @@ namespace NzbDrone.Core.Indexers request.HttpRequest.Url = originalUrl; ModifyRequest(request); - response = await _httpClient.ExecuteAsync(request.HttpRequest); + response = await _httpClient.ExecuteAsync(request.HttpRequest, Definition); } // Throw common http errors here before we try to parse @@ -414,7 +414,7 @@ namespace NzbDrone.Core.Indexers { request.Encoding = Encoding; - var response = await _httpClient.ExecuteAsync(request); + var response = await _httpClient.ExecuteAsync(request, Definition); _eventAggregator.PublishEvent(new IndexerAuthEvent(Definition.Id, !response.HasHttpError, response.ElapsedTime)); diff --git a/src/NzbDrone.Core/Indexers/IndexerFactory.cs b/src/NzbDrone.Core/Indexers/IndexerFactory.cs index b93d79147..9096d22b9 100644 --- a/src/NzbDrone.Core/Indexers/IndexerFactory.cs +++ b/src/NzbDrone.Core/Indexers/IndexerFactory.cs @@ -259,7 +259,7 @@ namespace NzbDrone.Core.Indexers if (definition.Implementation == typeof(Newznab.Newznab).Name || definition.Implementation == typeof(Torznab.Torznab).Name) { var settings = (NewznabSettings)definition.Settings; - settings.Categories = _newznabCapabilitiesProvider.GetCapabilities(settings)?.Categories.GetTorznabCategoryList() ?? null; + settings.Categories = _newznabCapabilitiesProvider.GetCapabilities(settings, definition)?.Categories.GetTorznabCategoryList() ?? null; } if (definition.Implementation == typeof(Cardigann.Cardigann).Name) @@ -279,7 +279,7 @@ namespace NzbDrone.Core.Indexers if (definition.Enable && (definition.Implementation == typeof(Newznab.Newznab).Name || definition.Implementation == typeof(Torznab.Torznab).Name)) { var settings = (NewznabSettings)definition.Settings; - settings.Categories = _newznabCapabilitiesProvider.GetCapabilities(settings)?.Categories.GetTorznabCategoryList() ?? null; + settings.Categories = _newznabCapabilitiesProvider.GetCapabilities(settings, definition)?.Categories.GetTorznabCategoryList() ?? null; } if (definition.Implementation == typeof(Cardigann.Cardigann).Name) diff --git a/src/NzbDrone.Core/Indexers/IndexerHttpClient.cs b/src/NzbDrone.Core/Indexers/IndexerHttpClient.cs new file mode 100644 index 000000000..1558b139c --- /dev/null +++ b/src/NzbDrone.Core/Indexers/IndexerHttpClient.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using NLog; +using NzbDrone.Common.Cache; +using NzbDrone.Common.Http; +using NzbDrone.Common.Http.Dispatchers; +using NzbDrone.Common.TPL; +using NzbDrone.Core.IndexerProxies; +using NzbDrone.Core.ThingiProvider; + +namespace NzbDrone.Core.Indexers +{ + public interface IIndexerHttpClient : IHttpClient + { + Task<HttpResponse> ExecuteAsync(HttpRequest request, ProviderDefinition definition); + HttpResponse Execute(HttpRequest request, ProviderDefinition definition); + } + + public class IndexerHttpClient : HttpClient, IIndexerHttpClient + { + private readonly IIndexerProxyFactory _indexerProxyFactory; + public IndexerHttpClient(IIndexerProxyFactory indexerProxyFactory, + IEnumerable<IHttpRequestInterceptor> requestInterceptors, + ICacheManager cacheManager, + IRateLimitService rateLimitService, + IHttpDispatcher httpDispatcher, + Logger logger) + : base(requestInterceptors, cacheManager, rateLimitService, httpDispatcher, logger) + { + _indexerProxyFactory = indexerProxyFactory; + } + + public async Task<HttpResponse> ExecuteAsync(HttpRequest request, ProviderDefinition definition) + { + var selectedProxy = GetProxy(definition); + + request = PreRequest(request, selectedProxy); + + return PostResponse(await ExecuteAsync(request), selectedProxy); + } + + public HttpResponse Execute(HttpRequest request, ProviderDefinition definition) + { + var selectedProxy = GetProxy(definition); + + request = PreRequest(request, selectedProxy); + + return PostResponse(Execute(request), selectedProxy); + } + + private IIndexerProxy GetProxy(ProviderDefinition definition) + { + //Skip DB call if no tags on the indexers + if (definition.Tags.Count == 0) + { + return null; + } + + var proxies = _indexerProxyFactory.GetAvailableProviders(); + IIndexerProxy selectedProxy = null; + + foreach (var proxy in proxies) + { + if (definition.Tags.Intersect(proxy.Definition.Tags).Any()) + { + selectedProxy = proxy; + break; + } + } + + return selectedProxy; + } + + private HttpRequest PreRequest(HttpRequest request, IIndexerProxy selectedProxy) + { + if (selectedProxy != null) + { + request = selectedProxy.PreRequest(request); + } + + return request; + } + + private HttpResponse PostResponse(HttpResponse response, IIndexerProxy selectedProxy) + { + if (selectedProxy != null) + { + response = selectedProxy.PostResponse(response); + } + + return response; + } + } +} diff --git a/src/NzbDrone.Core/Indexers/IndexerRequest.cs b/src/NzbDrone.Core/Indexers/IndexerRequest.cs index 572273d9f..6a1b9c167 100644 --- a/src/NzbDrone.Core/Indexers/IndexerRequest.cs +++ b/src/NzbDrone.Core/Indexers/IndexerRequest.cs @@ -1,4 +1,4 @@ -using NzbDrone.Common.Http; +using NzbDrone.Common.Http; namespace NzbDrone.Core.Indexers { diff --git a/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs b/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs index 510eab655..226be41b1 100644 --- a/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Core.Indexers public abstract class TorrentIndexerBase<TSettings> : HttpIndexerBase<TSettings> where TSettings : IIndexerSettings, new() { - protected TorrentIndexerBase(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + protected TorrentIndexerBase(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } diff --git a/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs b/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs index 42d8e20b4..d1ab70ddc 100644 --- a/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs @@ -15,7 +15,7 @@ namespace NzbDrone.Core.Indexers { private readonly IValidateNzbs _nzbValidationService; - protected UsenetIndexerBase(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger) + protected UsenetIndexerBase(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { _nzbValidationService = nzbValidationService; diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index f0a9a911c..24a8b5ed4 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -95,6 +95,8 @@ "DeleteDownloadClientMessageText": "Are you sure you want to delete the download client '{0}'?", "DeleteIndexer": "Delete Indexer", "DeleteIndexerMessageText": "Are you sure you want to delete the indexer '{0}'?", + "DeleteIndexerProxy": "Delete Indexer Proxy", + "DeleteIndexerProxyMessageText": "Are you sure you want to delete the proxy '{0}'?", "DeleteNotification": "Delete Notification", "DeleteNotificationMessageText": "Are you sure you want to delete the notification '{0}'?", "DeleteTag": "Delete Tag", @@ -186,12 +188,16 @@ "IndexerObsoleteCheckMessage": "Indexers are obsolete or have been updated: {0}. Please remove and (or) re-add to Prowlarr", "IndexerPriority": "Indexer Priority", "IndexerPriorityHelpText": "Indexer Priority from 1 (Highest) to 50 (Lowest). Default: 25.", + "IndexerProxies": "Indexer Proxies", + "IndexerProxyStatusCheckAllClientMessage": "All proxies are unavailable due to failures", + "IndexerProxyStatusCheckSingleClientMessage": "Proxies unavailable due to failures: {0}", "IndexerQuery": "Indexer Query", "IndexerRss": "Indexer Rss", "Indexers": "Indexers", "IndexersSelectedInterp": "{0} Indexer(s) Selected", "IndexerStatusCheckAllClientMessage": "All indexers are unavailable due to failures", "IndexerStatusCheckSingleClientMessage": "Indexers unavailable due to failures: {0}", + "IndexerTagsHelpText": "Use tags to specify default clients, specify Indexer Proxies, or just to organize your indexers.", "Info": "Info", "InteractiveSearch": "Interactive Search", "Interval": "Interval", @@ -392,6 +398,7 @@ "UnableToAddANewAppProfilePleaseTryAgain": "Unable to add a new application profile, please try again.", "UnableToAddANewDownloadClientPleaseTryAgain": "Unable to add a new download client, please try again.", "UnableToAddANewIndexerPleaseTryAgain": "Unable to add a new indexer, please try again.", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Unable to add a new indexer proxy, please try again.", "UnableToAddANewNotificationPleaseTryAgain": "Unable to add a new notification, please try again.", "UnableToLoadAppProfiles": "Unable to load app profiles", "UnableToLoadBackups": "Unable to load backups", @@ -399,6 +406,7 @@ "UnableToLoadDownloadClients": "Unable to load download clients", "UnableToLoadGeneralSettings": "Unable to load General settings", "UnableToLoadHistory": "Unable to load history", + "UnableToLoadIndexerProxies": "Unable To Load Indexer Proxies", "UnableToLoadIndexers": "Unable to load Indexers", "UnableToLoadNotifications": "Unable to load Notifications", "UnableToLoadQualityDefinitions": "Unable to load Quality Definitions", diff --git a/src/NzbDrone.Core/Tags/TagDetails.cs b/src/NzbDrone.Core/Tags/TagDetails.cs index d538b7771..e0b2c018a 100644 --- a/src/NzbDrone.Core/Tags/TagDetails.cs +++ b/src/NzbDrone.Core/Tags/TagDetails.cs @@ -8,12 +8,14 @@ namespace NzbDrone.Core.Tags { public string Label { get; set; } public List<int> NotificationIds { get; set; } + public List<int> IndexerIds { get; set; } + public List<int> IndexerProxyIds { get; set; } public bool InUse { get { - return NotificationIds.Any(); + return NotificationIds.Any() || IndexerIds.Any() || IndexerProxyIds.Any(); } } } diff --git a/src/NzbDrone.Core/Tags/TagService.cs b/src/NzbDrone.Core/Tags/TagService.cs index b8994d127..727ad88ca 100644 --- a/src/NzbDrone.Core/Tags/TagService.cs +++ b/src/NzbDrone.Core/Tags/TagService.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using System.Linq; using NzbDrone.Core.Datastore; +using NzbDrone.Core.IndexerProxies; +using NzbDrone.Core.Indexers; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Notifications; @@ -24,14 +26,20 @@ namespace NzbDrone.Core.Tags private readonly ITagRepository _repo; private readonly IEventAggregator _eventAggregator; private readonly INotificationFactory _notificationFactory; + private readonly IIndexerFactory _indexerFactory; + private readonly IIndexerProxyFactory _indexerProxyFactory; public TagService(ITagRepository repo, IEventAggregator eventAggregator, - INotificationFactory notificationFactory) + INotificationFactory notificationFactory, + IIndexerFactory indexerFactory, + IIndexerProxyFactory indexerProxyFactory) { _repo = repo; _eventAggregator = eventAggregator; _notificationFactory = notificationFactory; + _indexerFactory = indexerFactory; + _indexerProxyFactory = indexerProxyFactory; } public Tag GetTag(int tagId) @@ -60,12 +68,16 @@ namespace NzbDrone.Core.Tags { var tag = GetTag(tagId); var notifications = _notificationFactory.AllForTag(tagId); + var indexers = _indexerFactory.AllForTag(tagId); + var indexerProxies = _indexerProxyFactory.AllForTag(tagId); return new TagDetails { Id = tagId, Label = tag.Label, - NotificationIds = notifications.Select(c => c.Id).ToList() + NotificationIds = notifications.Select(c => c.Id).ToList(), + IndexerIds = indexers.Select(c => c.Id).ToList(), + IndexerProxyIds = indexerProxies.Select(c => c.Id).ToList() }; } @@ -73,6 +85,8 @@ namespace NzbDrone.Core.Tags { var tags = All(); var notifications = _notificationFactory.All(); + var indexers = _indexerFactory.All(); + var indexerProxies = _indexerProxyFactory.All(); var details = new List<TagDetails>(); @@ -82,7 +96,9 @@ namespace NzbDrone.Core.Tags { Id = tag.Id, Label = tag.Label, - NotificationIds = notifications.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList() + NotificationIds = notifications.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList(), + IndexerIds = indexers.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList(), + IndexerProxyIds = indexerProxies.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList() }); } diff --git a/src/Prowlarr.Api.V1/IndexerProxies/IndexerProxyController.cs b/src/Prowlarr.Api.V1/IndexerProxies/IndexerProxyController.cs new file mode 100644 index 000000000..f63ee4a3e --- /dev/null +++ b/src/Prowlarr.Api.V1/IndexerProxies/IndexerProxyController.cs @@ -0,0 +1,16 @@ +using NzbDrone.Core.IndexerProxies; +using Prowlarr.Http; + +namespace Prowlarr.Api.V1.IndexerProxies +{ + [V1ApiController] + public class IndexerProxyController : ProviderControllerBase<IndexerProxyResource, IIndexerProxy, IndexerProxyDefinition> + { + public static readonly IndexerProxyResourceMapper ResourceMapper = new IndexerProxyResourceMapper(); + + public IndexerProxyController(IndexerProxyFactory notificationFactory) + : base(notificationFactory, "indexerProxy", ResourceMapper) + { + } + } +} diff --git a/src/Prowlarr.Api.V1/IndexerProxies/IndexerProxyResource.cs b/src/Prowlarr.Api.V1/IndexerProxies/IndexerProxyResource.cs new file mode 100644 index 000000000..6b8719289 --- /dev/null +++ b/src/Prowlarr.Api.V1/IndexerProxies/IndexerProxyResource.cs @@ -0,0 +1,40 @@ +using NzbDrone.Core.IndexerProxies; + +namespace Prowlarr.Api.V1.IndexerProxies +{ + public class IndexerProxyResource : ProviderResource<IndexerProxyResource> + { + public string Link { get; set; } + public bool OnHealthIssue { get; set; } + public bool SupportsOnHealthIssue { get; set; } + public bool IncludeHealthWarnings { get; set; } + public string TestCommand { get; set; } + } + + public class IndexerProxyResourceMapper : ProviderResourceMapper<IndexerProxyResource, IndexerProxyDefinition> + { + public override IndexerProxyResource ToResource(IndexerProxyDefinition definition) + { + if (definition == null) + { + return default(IndexerProxyResource); + } + + var resource = base.ToResource(definition); + + return resource; + } + + public override IndexerProxyDefinition ToModel(IndexerProxyResource resource) + { + if (resource == null) + { + return default(IndexerProxyDefinition); + } + + var definition = base.ToModel(resource); + + return definition; + } + } +} diff --git a/src/Prowlarr.Api.V1/Tags/TagDetailsResource.cs b/src/Prowlarr.Api.V1/Tags/TagDetailsResource.cs index 41ef94c94..2404e6857 100644 --- a/src/Prowlarr.Api.V1/Tags/TagDetailsResource.cs +++ b/src/Prowlarr.Api.V1/Tags/TagDetailsResource.cs @@ -9,6 +9,8 @@ namespace Prowlarr.Api.V1.Tags { public string Label { get; set; } public List<int> NotificationIds { get; set; } + public List<int> IndexerIds { get; set; } + public List<int> IndexerProxyIds { get; set; } } public static class TagDetailsResourceMapper @@ -24,7 +26,9 @@ namespace Prowlarr.Api.V1.Tags { Id = model.Id, Label = model.Label, - NotificationIds = model.NotificationIds + NotificationIds = model.NotificationIds, + IndexerIds = model.IndexerIds, + IndexerProxyIds = model.IndexerProxyIds }; } From 742c0d02bc7e71e6ed5dded33ae0d011506de1e5 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 1 Aug 2021 00:16:37 -0400 Subject: [PATCH 0026/2320] New: FlareSolverr Proxy Option --- .../FlareSolverr/FlareSolverr.cs | 224 ++++++++++++++++++ .../FlareSolverr/FlareSolverrException.cs | 23 ++ .../FlareSolverr/FlareSolverrSettings.cs | 32 +++ 3 files changed, 279 insertions(+) create mode 100644 src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs create mode 100644 src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverrException.cs create mode 100644 src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverrSettings.cs diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs new file mode 100644 index 000000000..f58f9ccaf --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -0,0 +1,224 @@ +using System; +using System.Collections.Generic; +using System.Net; +using FluentValidation.Results; +using Newtonsoft.Json; +using NLog; +using NzbDrone.Common.Cloud; +using NzbDrone.Common.Http; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.IndexerProxies.FlareSolverr +{ + public class FlareSolverr : HttpIndexerProxyBase<FlareSolverrSettings> + { + public FlareSolverr(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger) + : base(cloudRequestBuilder, httpClient, logger) + { + } + + public override string Name => "FlareSolverr"; + + public override HttpRequest PreRequest(HttpRequest request) + { + return GenerateFlareSolverrRequest(request); + } + + public override HttpResponse PostResponse(HttpResponse response) + { + FlareSolverrResponse result = null; + + if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.InternalServerError) + { + throw new FlareSolverrException("HTTP StatusCode not 200 or 500. Status is :" + response.StatusCode); + } + + result = JsonConvert.DeserializeObject<FlareSolverrResponse>(response.Content); + + var cookieCollection = new CookieCollection(); + var responseHeader = new HttpHeader(); + + foreach (var cookie in result.Solution.Cookies) + { + cookieCollection.Add(cookie.ToCookieObj()); + } + + //Build new response with FS Cookie and Site Response + var newResponse = new HttpResponse(response.Request, responseHeader, cookieCollection, result.Solution.Response); + + return newResponse; + } + + private HttpRequest GenerateFlareSolverrRequest(HttpRequest request) + { + FlareSolverrRequest req; + + var url = request.Url.ToString(); + var userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"; + var maxTimeout = 60000; + + if (request.Method == HttpMethod.GET) + { + req = new FlareSolverrRequestGet + { + Cmd = "request.get", + Url = url, + MaxTimeout = maxTimeout, + UserAgent = userAgent + }; + } + else if (request.Method == HttpMethod.POST) + { + var contentTypeType = request.Headers.ContentType; + + if (contentTypeType == "application/x-www-form-urlencoded") + { + var contentTypeValue = request.Headers.ContentType.ToString(); + var postData = request.GetContent(); + + req = new FlareSolverrRequestPostUrlEncoded + { + Cmd = "request.post", + Url = url, + PostData = postData, + Headers = new HeadersPost + { + ContentType = contentTypeValue, + ContentLength = null + }, + MaxTimeout = maxTimeout, + UserAgent = userAgent + }; + } + else if (contentTypeType.Contains("multipart/form-data")) + { + //TODO Implement - check if we just need to pass the content-type with the relevant headers + throw new FlareSolverrException("Unimplemented POST Content-Type: " + request.Headers.ContentType); + } + else + { + throw new FlareSolverrException("Unsupported POST Content-Type: " + request.Headers.ContentType); + } + } + else + { + throw new FlareSolverrException("Unsupported HttpMethod: " + request.Method); + } + + var apiUrl = string.Format("{0}/v1", Settings.Host.TrimEnd('/')); + var newRequest = new HttpRequest(apiUrl, HttpAccept.Json); + + newRequest.SetContent(req.ToJson()); + newRequest.Method = HttpMethod.POST; + + _logger.Debug("Applying FlareSolverr Proxy {0} to request {1}", Name, request.Url); + + return newRequest; + } + + public override ValidationResult Test() + { + var failures = new List<ValidationFailure>(); + + var request = PreRequest(_cloudRequestBuilder.Create() + .Resource("/ping") + .Build()); + + try + { + var response = _httpClient.Execute(request); + + // We only care about 400 responses, other error codes can be ignored + if (response.StatusCode == HttpStatusCode.BadRequest) + { + _logger.Error("Proxy Health Check failed: {0}", response.StatusCode); + failures.Add(new NzbDroneValidationFailure("Host", "ProxyCheckBadRequestMessage")); + } + } + catch (Exception ex) + { + _logger.Error(ex, "Proxy Health Check failed"); + failures.Add(new NzbDroneValidationFailure("Host", "ProxyCheckFailedToTestMessage")); + } + + return new ValidationResult(failures); + } + + public class FlareSolverrRequest + { + public string Cmd { get; set; } + public string Url { get; set; } + public string UserAgent { get; set; } + } + + public class FlareSolverrRequestGet : FlareSolverrRequest + { + public string Headers { get; set; } + public int MaxTimeout { get; set; } + } + + public class FlareSolverrRequestPost : FlareSolverrRequest + { + public string PostData { get; set; } + public int MaxTimeout { get; set; } + } + + public class FlareSolverrRequestPostUrlEncoded : FlareSolverrRequestPost + { + public HeadersPost Headers { get; set; } + } + + public class HeadersPost + { + public string ContentType { get; set; } + public string ContentLength { get; set; } + } + + public class FlareSolverrResponse + { + public string Status { get; set; } + public string Message { get; set; } + public long StartTimestamp { get; set; } + public long EndTimestamp { get; set; } + public string Version { get; set; } + public Solution Solution { get; set; } + } + + public class Solution + { + public string Url { get; set; } + public string Status { get; set; } + public Headers Headers { get; set; } + public string Response { get; set; } + public Cookie[] Cookies { get; set; } + public string UserAgent { get; set; } + } + + public class Cookie + { + public string Name { get; set; } + public string Value { get; set; } + public string Domain { get; set; } + public string Path { get; set; } + public double Expires { get; set; } + public int Size { get; set; } + public bool HttpOnly { get; set; } + public bool Secure { get; set; } + public bool Session { get; set; } + public string SameSite { get; set; } + + public string ToHeaderValue() => $"{Name}={Value}"; + public System.Net.Cookie ToCookieObj() => new System.Net.Cookie(Name, Value); + } + + public class Headers + { + public string Status { get; set; } + public string Date { get; set; } + + [JsonProperty(PropertyName = "content-type")] + public string ContentType { get; set; } + } + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverrException.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverrException.cs new file mode 100644 index 000000000..e571de8ab --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverrException.cs @@ -0,0 +1,23 @@ +using System; +using NzbDrone.Common.Exceptions; + +namespace NzbDrone.Core.IndexerProxies.FlareSolverr +{ + public class FlareSolverrException : NzbDroneException + { + public FlareSolverrException(string message) + : base(message) + { + } + + public FlareSolverrException(string message, params object[] args) + : base(message, args) + { + } + + public FlareSolverrException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverrSettings.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverrSettings.cs new file mode 100644 index 000000000..0af09fc82 --- /dev/null +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverrSettings.cs @@ -0,0 +1,32 @@ +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.IndexerProxies.FlareSolverr +{ + public class FlareSolverrSettingsValidator : AbstractValidator<FlareSolverrSettings> + { + public FlareSolverrSettingsValidator() + { + RuleFor(c => c.Host).NotEmpty(); + } + } + + public class FlareSolverrSettings : IIndexerProxySettings + { + private static readonly FlareSolverrSettingsValidator Validator = new FlareSolverrSettingsValidator(); + + public FlareSolverrSettings() + { + Host = "http://localhost:8191/"; + } + + [FieldDefinition(0, Label = "Host")] + public string Host { get; set; } + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} From e8c6103cc7a53ea0addd21df4405d24cdc3cfb7e Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 15 Aug 2021 08:21:25 -0500 Subject: [PATCH 0027/2320] Fixed: Missing Indexer Proxy Modal translate --- .../Indexers/IndexerProxies/AddIndexerProxyModalContent.js | 2 +- src/NzbDrone.Core/Localization/Core/en.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContent.js b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContent.js index f00a05bd5..4e8caffaa 100644 --- a/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContent.js +++ b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContent.js @@ -28,7 +28,7 @@ class AddIndexerProxyModalContent extends Component { return ( <ModalContent onModalClose={onModalClose}> <ModalHeader> - Add IndexerProxy + {translate('AddIndexerProxy')} </ModalHeader> <ModalBody> diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 24a8b5ed4..ac461ff7f 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -9,6 +9,7 @@ "Added": "Added", "AddedToDownloadClient": "Release added to client", "AddIndexer": "Add Indexer", + "AddIndexerProxy": "Add Indexer Proxy", "AddingTag": "Adding tag", "AddNewIndexer": "Add New Indexer", "AddRemoveOnly": "Add and Remove Only", From 7c1f5f769d168b3f03de5bc40113ffd001144b7e Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 15 Aug 2021 08:36:28 -0500 Subject: [PATCH 0028/2320] Fixed: Settings Page Translates New: Indexer Proxies Settings Page Links - renamed Connect to Notifications --- frontend/src/Settings/Settings.js | 19 +++++++++++++++---- src/NzbDrone.Core/Localization/Core/en.json | 11 +++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/frontend/src/Settings/Settings.js b/frontend/src/Settings/Settings.js index c29cb7cef..dadb3188d 100644 --- a/frontend/src/Settings/Settings.js +++ b/frontend/src/Settings/Settings.js @@ -16,13 +16,24 @@ function Settings() { <PageContentBody> <Link className={styles.link} - to="/settings/applications" + to="/settings/indexers" > - Applications + {translate('Indexers')} </Link> <div className={styles.summary}> - Applications and settings to configure how prowlarr interacts with your PVR programs + {translate('IndexerSettingsSummary')} + </div> + + <Link + className={styles.link} + to="/settings/applications" + > + {translate('Apps')} + </Link> + + <div className={styles.summary}> + {translate('AppSettingsSummary')} </div> <Link @@ -40,7 +51,7 @@ function Settings() { className={styles.link} to="/settings/connect" > - Notifications + {translate('Notifications')} </Link> <div className={styles.summary}> diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index ac461ff7f..e5aee90c8 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -37,6 +37,7 @@ "AppProfiles": "App Profiles", "AppProfileSelectHelpText": "App profiles are used to control RSS, Automatic Search and Interactive Search settings on application sync", "Apps": "Apps", + "AppSettingsSummary": "Applications and settings to configure how Prowlarr interacts with your PVR programs", "AreYouSureYouWantToResetYourAPIKey": "Are you sure you want to reset your API Key?", "Auth": "Auth", "Authentication": "Authentication", @@ -72,13 +73,13 @@ "CloseCurrentModal": "Close Current Modal", "Columns": "Columns", "Component": "Component", - "Connect": "Connect", + "Connect": "Notifications", "ConnectionLost": "Connection Lost", "ConnectionLostAutomaticMessage": "Prowlarr will try to connect automatically, or you can click reload below.", "ConnectionLostMessage": "Prowlarr has lost it's connection to the backend and will need to be reloaded to restore functionality.", "Connections": "Connections", "ConnectSettings": "Connect Settings", - "ConnectSettingsSummary": "Notifications, connections to media servers/players and custom scripts", + "ConnectSettingsSummary": "Notifications and custom scripts", "CouldNotConnectSignalR": "Could not connect to SignalR, UI won't update", "Custom": "Custom", "CustomFilters": "Custom Filters", @@ -164,7 +165,7 @@ "FullSync": "Full Sync", "General": "General", "GeneralSettings": "General Settings", - "GeneralSettingsSummary": "Port, SSL, username/password, proxy, analytics and updates", + "GeneralSettingsSummary": "Port, SSL, username/password, proxy, analytics, and updates", "Grabbed": "Grabbed", "Grabs": "Grabs", "Health": "Health", @@ -190,6 +191,7 @@ "IndexerPriority": "Indexer Priority", "IndexerPriorityHelpText": "Indexer Priority from 1 (Highest) to 50 (Lowest). Default: 25.", "IndexerProxies": "Indexer Proxies", + "IndexerSettingsSummary": "Configure various global Indexer settings including Proxies.", "IndexerProxyStatusCheckAllClientMessage": "All proxies are unavailable due to failures", "IndexerProxyStatusCheckSingleClientMessage": "Proxies unavailable due to failures: {0}", "IndexerQuery": "Indexer Query", @@ -248,6 +250,7 @@ "NoMinimumForAnyRuntime": "No minimum for any runtime", "NoSearchResultsFound": "No search results found, try performing a new search below.", "NoTagsHaveBeenAddedYet": "No tags have been added yet", + "Notifications": "Notifications", "NotificationTriggers": "Notification Triggers", "NotificationTriggersHelpText": "Select which events should trigger this notification", "NoUpdatesAreAvailable": "No updates are available", @@ -394,7 +397,7 @@ "UILanguageHelpText": "Language that Prowlarr will use for UI", "UILanguageHelpTextWarning": "Browser Reload Required", "UISettings": "UI Settings", - "UISettingsSummary": "Calendar, date and color impaired options", + "UISettingsSummary": "Date, language, and color impaired options", "UnableToAddANewApplicationPleaseTryAgain": "Unable to add a new application, please try again.", "UnableToAddANewAppProfilePleaseTryAgain": "Unable to add a new application profile, please try again.", "UnableToAddANewDownloadClientPleaseTryAgain": "Unable to add a new download client, please try again.", From b7731faedc5eb16de6cda9176779abde216766c9 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 15 Aug 2021 19:48:14 -0400 Subject: [PATCH 0029/2320] Fixed: (Indexer Proxy) Socks4 and Socks5 not using Credentials --- .../HealthCheck/Checks/IndexerProxyCheck.cs | 6 +++++- .../IndexerProxies/HttpIndexerProxyBase.cs | 6 +++--- src/NzbDrone.Core/IndexerProxies/IndexerProxyBase.cs | 12 ------------ src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs | 4 ++-- src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs | 4 ++-- 5 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/NzbDrone.Core/HealthCheck/Checks/IndexerProxyCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/IndexerProxyCheck.cs index 1a48fc6ca..3e4a8d7c7 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/IndexerProxyCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/IndexerProxyCheck.cs @@ -7,9 +7,13 @@ using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.IndexerProxies; using NzbDrone.Core.Localization; +using NzbDrone.Core.ThingiProvider.Events; namespace NzbDrone.Core.HealthCheck.Checks { + [CheckOn(typeof(ProviderDeletedEvent<IIndexerProxy>))] + [CheckOn(typeof(ProviderAddedEvent<IIndexerProxy>))] + [CheckOn(typeof(ProviderUpdatedEvent<IIndexerProxy>))] public class IndexerProxyCheck : HealthCheckBase { private readonly Logger _logger; @@ -37,7 +41,7 @@ namespace NzbDrone.Core.HealthCheck.Checks var badProxies = enabledProviders.Where(p => !IsProxyWorking(p)).ToList(); - if (enabledProviders.Empty()) + if (enabledProviders.Empty() || badProxies.Count == 0) { return new HealthCheck(GetType()); } diff --git a/src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs b/src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs index 5868ef412..f37389b4d 100644 --- a/src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs +++ b/src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs @@ -40,19 +40,19 @@ namespace NzbDrone.Core.IndexerProxies try { - var response = _httpClient.Execute(request); + var response = PostResponse(_httpClient.Execute(request)); // We only care about 400 responses, other error codes can be ignored if (response.StatusCode == HttpStatusCode.BadRequest) { _logger.Error("Proxy Health Check failed: {0}", response.StatusCode); - failures.Add(new NzbDroneValidationFailure("Host", "ProxyCheckBadRequestMessage")); + failures.Add(new NzbDroneValidationFailure("Host", string.Format("Failed to test proxy. StatusCode: {0}", response.StatusCode))); } } catch (Exception ex) { _logger.Error(ex, "Proxy Health Check failed"); - failures.Add(new NzbDroneValidationFailure("Host", "ProxyCheckFailedToTestMessage")); + failures.Add(new NzbDroneValidationFailure("Host", string.Format("Failed to test proxy: {0}", request.Url))); } return new ValidationResult(failures); diff --git a/src/NzbDrone.Core/IndexerProxies/IndexerProxyBase.cs b/src/NzbDrone.Core/IndexerProxies/IndexerProxyBase.cs index b4c82808d..1efe8437c 100644 --- a/src/NzbDrone.Core/IndexerProxies/IndexerProxyBase.cs +++ b/src/NzbDrone.Core/IndexerProxies/IndexerProxyBase.cs @@ -36,17 +36,5 @@ namespace NzbDrone.Core.IndexerProxies { return null; } - - private bool HasConcreteImplementation(string methodName) - { - var method = GetType().GetMethod(methodName); - - if (method == null) - { - throw new MissingMethodException(GetType().Name, Name); - } - - return !method.DeclaringType.IsAbstract; - } } } diff --git a/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs b/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs index fa32e1673..22ca0ce2c 100644 --- a/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs +++ b/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs @@ -23,11 +23,11 @@ namespace NzbDrone.Core.IndexerProxies.Socks4 { if (Settings.Username.IsNotNullOrWhiteSpace() && Settings.Password.IsNotNullOrWhiteSpace()) { - request.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(Settings.Host), Settings.Port, ProxyConfig.SocksVersion.Four), false); + request.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(Settings.Host), Settings.Port, ProxyConfig.SocksVersion.Four, Settings.Username, Settings.Password), false); } else { - request.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(Settings.Host), Settings.Port, ProxyConfig.SocksVersion.Four, Settings.Username, Settings.Password), false); + request.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(Settings.Host), Settings.Port, ProxyConfig.SocksVersion.Four), false); } _logger.Debug("Applying Socks4 Proxy {0} to request {1}", Name, request.Url); diff --git a/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs b/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs index 5c3727972..3ad62e24a 100644 --- a/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs +++ b/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs @@ -24,11 +24,11 @@ namespace NzbDrone.Core.IndexerProxies.Socks5 { if (Settings.Username.IsNotNullOrWhiteSpace() && Settings.Password.IsNotNullOrWhiteSpace()) { - request.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(Settings.Host), Settings.Port, ProxyConfig.SocksVersion.Five), false); + request.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(Settings.Host), Settings.Port, ProxyConfig.SocksVersion.Five, Settings.Username, Settings.Password), false); } else { - request.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(Settings.Host), Settings.Port, ProxyConfig.SocksVersion.Five, Settings.Username, Settings.Password), false); + request.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(Settings.Host), Settings.Port, ProxyConfig.SocksVersion.Five), false); } _logger.Debug("Applying Socks5 Proxy {0} to request {1}", Name, request.Url); From 635fa78da90c514452a0c0a80c6d4fc1d88a1754 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 15 Aug 2021 22:41:33 -0400 Subject: [PATCH 0030/2320] Fixed: Cursor Jumps to end in when editing search term Fixes #290 --- frontend/src/Search/SearchFooter.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/frontend/src/Search/SearchFooter.js b/frontend/src/Search/SearchFooter.js index 3288109b2..a69ff04c6 100644 --- a/frontend/src/Search/SearchFooter.js +++ b/frontend/src/Search/SearchFooter.js @@ -27,7 +27,7 @@ class SearchFooter extends Component { this.state = { searchingReleases: false, - searchQuery: defaultSearchQuery, + searchQuery: defaultSearchQuery || '', searchIndexerIds: defaultIndexerIds, searchCategories: defaultCategories }; @@ -52,14 +52,12 @@ class SearchFooter extends Component { isFetching, defaultIndexerIds, defaultCategories, - defaultSearchQuery, searchError } = this.props; const { searchIndexerIds, - searchCategories, - searchQuery + searchCategories } = this.state; const newState = {}; @@ -72,10 +70,6 @@ class SearchFooter extends Component { newState.searchCategories = defaultCategories; } - if (searchQuery !== defaultSearchQuery) { - newState.searchQuery = defaultSearchQuery; - } - if (prevProps.isFetching && !isFetching && !searchError) { newState.searchingReleases = false; } @@ -92,6 +86,10 @@ class SearchFooter extends Component { this.props.onSearchPress(this.state.searchQuery, this.state.searchIndexerIds, this.state.searchCategories); } + onSearchInputChange = ({ value }) => { + this.setState({ searchQuery: value }); + } + // // Render @@ -121,7 +119,7 @@ class SearchFooter extends Component { autoFocus={true} value={searchQuery} isDisabled={isFetching} - onChange={onInputChange} + onChange={this.onSearchInputChange} /> </div> From 891ca0f56bb02a34a3a23e559fcb1806b73d81f1 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 16 Aug 2021 21:09:55 -0400 Subject: [PATCH 0031/2320] Fixed: (Sonarr) Workaround Sonarr issue with caps and basic search Fixes #430 --- .../Indexers/NewznabController.cs | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Prowlarr.Api.V1/Indexers/NewznabController.cs b/src/Prowlarr.Api.V1/Indexers/NewznabController.cs index b7851da2d..6acaf9fd8 100644 --- a/src/Prowlarr.Api.V1/Indexers/NewznabController.cs +++ b/src/Prowlarr.Api.V1/Indexers/NewznabController.cs @@ -72,7 +72,26 @@ namespace NzbDrone.Api.V1.Indexers switch (requestType) { case "caps": - var caps = new IndexerCapabilities(); + var caps = new IndexerCapabilities + { + TvSearchParams = new List<TvSearchParam> + { + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep + }, + MovieSearchParams = new List<MovieSearchParam> + { + MovieSearchParam.Q + }, + MusicSearchParams = new List<MusicSearchParam> + { + MusicSearchParam.Q + }, + BookSearchParams = new List<BookSearchParam> + { + BookSearchParam.Q + } + }; + foreach (var cat in NewznabStandardCategory.AllCats) { caps.Categories.AddCategoryMapping(1, cat); From 4a957b618e99ccf183e9bd0a611bd383409637d3 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 17 Aug 2021 07:45:20 -0400 Subject: [PATCH 0032/2320] Fixed: Proxy HealthCheck should use Proxy.Test method Fixes #431 --- .../HealthCheck/Checks/IndexerProxyCheck.cs | 53 ++----------------- 1 file changed, 3 insertions(+), 50 deletions(-) diff --git a/src/NzbDrone.Core/HealthCheck/Checks/IndexerProxyCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/IndexerProxyCheck.cs index 3e4a8d7c7..a78061561 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/IndexerProxyCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/IndexerProxyCheck.cs @@ -1,10 +1,5 @@ -using System; using System.Linq; -using System.Net; -using NLog; -using NzbDrone.Common.Cloud; using NzbDrone.Common.Extensions; -using NzbDrone.Common.Http; using NzbDrone.Core.IndexerProxies; using NzbDrone.Core.Localization; using NzbDrone.Core.ThingiProvider.Events; @@ -16,30 +11,20 @@ namespace NzbDrone.Core.HealthCheck.Checks [CheckOn(typeof(ProviderUpdatedEvent<IIndexerProxy>))] public class IndexerProxyCheck : HealthCheckBase { - private readonly Logger _logger; private readonly IIndexerProxyFactory _proxyFactory; - private readonly IHttpClient _client; - private readonly IHttpRequestBuilderFactory _cloudRequestBuilder; - - public IndexerProxyCheck(IProwlarrCloudRequestBuilder cloudRequestBuilder, - IHttpClient client, - IIndexerProxyFactory proxyFactory, - ILocalizationService localizationService, - Logger logger) + public IndexerProxyCheck(IIndexerProxyFactory proxyFactory, + ILocalizationService localizationService) : base(localizationService) { _proxyFactory = proxyFactory; - _cloudRequestBuilder = cloudRequestBuilder.Services; - _logger = logger; - _client = client; } public override HealthCheck Check() { var enabledProviders = _proxyFactory.GetAvailableProviders(); - var badProxies = enabledProviders.Where(p => !IsProxyWorking(p)).ToList(); + var badProxies = enabledProviders.Where(p => p.Test().IsValid == false).ToList(); if (enabledProviders.Empty() || badProxies.Count == 0) { @@ -60,37 +45,5 @@ namespace NzbDrone.Core.HealthCheck.Checks string.Join(", ", badProxies.Select(v => v.Definition.Name))), "#proxies-are-unavailable-due-to-failures"); } - - private bool IsProxyWorking(IIndexerProxy indexerProxy) - { - var request = _cloudRequestBuilder.Create() - .Resource("/ping") - .Build(); - - try - { - var addresses = Dns.GetHostAddresses(((IIndexerProxySettings)indexerProxy.Definition.Settings).Host); - if (!addresses.Any()) - { - return false; - } - - var response = _client.Execute(request); - - // We only care about 400 responses, other error codes can be ignored - if (response.StatusCode == HttpStatusCode.BadRequest) - { - _logger.Error("Proxy Health Check failed: {0}", response.StatusCode); - return false; - } - } - catch (Exception ex) - { - _logger.Error(ex, "Proxy Health Check failed"); - return false; - } - - return true; - } } } From de86274b080eeb126fd0cf322b8f90a51aa85a91 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Tue, 17 Aug 2021 17:37:39 +0000 Subject: [PATCH 0033/2320] Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.0% (434 of 438 strings) Co-authored-by: Havok Dan <havokdan@yahoo.com.br> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/pt_BR.json | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index 0def3004f..0a904b31c 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -425,5 +425,17 @@ "AddRemoveOnly": "Adicionar e remover apenas", "AddDownloadClientToProwlarr": "Adicionar um cliente de download possibilita que o Prowlarr envie lançamentos diretamente da interface ao executar uma pesquisa manual.", "Add": "Adicionar", - "NoSearchResultsFound": "Nenhum resultado encontrado, tente fazer uma nova busca abaixo." + "NoSearchResultsFound": "Nenhum resultado encontrado, tente fazer uma nova busca abaixo.", + "AppSettingsSummary": "Aplicativos e configurações para configurar como Prowlarr interage com seus programas PVR", + "DeleteIndexerProxy": "Apagar Proxy do Indexador", + "DeleteIndexerProxyMessageText": "Tem certeza que deseja apagar o proxy '{0}'?", + "AddIndexerProxy": "Adicionar Proxy ao Indexador", + "IndexerProxies": "Proxies do Indexador", + "IndexerSettingsSummary": "Defina várias configurações globais do Indexador, incluindo Proxies.", + "IndexerProxyStatusCheckAllClientMessage": "Todos os proxies estão indisponíveis devido a falhas", + "IndexerProxyStatusCheckSingleClientMessage": "Proxies indisponíveis devido a falhas: {0}", + "IndexerTagsHelpText": "Use etiquetas para especificar clientes padrão, especificar proxies indexadores ou apenas para organizar seus indexadores.", + "Notifications": "Notificações", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Não foi possível adicionar um novo proxy indexador, tente novamente.", + "UnableToLoadIndexerProxies": "Incapaz de carregar proxies indexadores" } From 2cd0dde4e20d56f1f906cb3d01a400ed7fe0f566 Mon Sep 17 00:00:00 2001 From: Yukine <devyukine@gmx.de> Date: Mon, 16 Aug 2021 11:38:27 +0200 Subject: [PATCH 0034/2320] Fixed: (Indexer) AnimeBytes Synonymns & Links are optional --- .../Indexers/Definitions/AnimeBytes.cs | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs index d0f9135b6..ec7c4adaf 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs @@ -236,13 +236,18 @@ namespace NzbDrone.Core.Indexers.Definitions synonyms.Add(mainTitle); - if (group.Synonymns.StringArray != null) + if (group.Synonymns != null) { - synonyms.AddRange(group.Synonymns.StringArray); - } - else - { - synonyms.AddRange(group.Synonymns.StringMap.Values); + var syn = (Synonymns)group.Synonymns; + + if (syn.StringArray != null) + { + synonyms.AddRange(syn.StringArray); + } + else + { + synonyms.AddRange(syn.StringMap.Values); + } } List<IndexerCategory> category = null; @@ -565,7 +570,7 @@ namespace NzbDrone.Core.Indexers.Definitions [JsonProperty("Synonymns")] [JsonConverter(typeof(SynonymnsConverter))] - public Synonymns Synonymns { get; set; } + public Synonymns? Synonymns { get; set; } [JsonProperty("Snatched")] public long Snatched { get; set; } @@ -575,7 +580,7 @@ namespace NzbDrone.Core.Indexers.Definitions [JsonProperty("Links")] [JsonConverter(typeof(LinksUnionConverter))] - public LinksUnion Links { get; set; } + public LinksUnion? Links { get; set; } [JsonProperty("Votes")] public long Votes { get; set; } @@ -711,6 +716,8 @@ namespace NzbDrone.Core.Indexers.Definitions case JsonToken.StartArray: var arrayValue = serializer.Deserialize<List<object>>(reader); return new LinksUnion { AnythingArray = arrayValue }; + case JsonToken.Null: + return null; } throw new Exception("Cannot unmarshal type LinksUnion"); @@ -725,12 +732,12 @@ namespace NzbDrone.Core.Indexers.Definitions return; } - if (value.LinksClass == null) + if (value.LinksClass != null) { - throw new Exception("Cannot marshal type LinksUnion"); + serializer.Serialize(writer, value.LinksClass); } - serializer.Serialize(writer, value.LinksClass); + serializer.Serialize(writer, null); } public static readonly LinksUnionConverter Singleton = new LinksUnionConverter(); @@ -785,6 +792,8 @@ namespace NzbDrone.Core.Indexers.Definitions case JsonToken.StartArray: var arrayValue = serializer.Deserialize<List<string>>(reader); return new Synonymns { StringArray = arrayValue }; + case JsonToken.Null: + return null; } throw new Exception("Cannot unmarshal type Synonymns"); @@ -799,12 +808,12 @@ namespace NzbDrone.Core.Indexers.Definitions return; } - if (value.StringMap == null) + if (value.StringMap != null) { - throw new Exception("Cannot marshal type Synonymns"); + serializer.Serialize(writer, value.StringMap); } - serializer.Serialize(writer, value.StringMap); + serializer.Serialize(writer, null); } public static readonly SynonymnsConverter Singleton = new SynonymnsConverter(); From efb2a5751c127a737b885540be4ee596028f6422 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 17 Aug 2021 10:22:01 -0500 Subject: [PATCH 0035/2320] Fixed: (Mylar3) Indexer Host needs to include trailing /api --- src/NzbDrone.Core/Applications/Mylar/Mylar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Applications/Mylar/Mylar.cs b/src/NzbDrone.Core/Applications/Mylar/Mylar.cs index 24590176d..bddf9baa0 100644 --- a/src/NzbDrone.Core/Applications/Mylar/Mylar.cs +++ b/src/NzbDrone.Core/Applications/Mylar/Mylar.cs @@ -141,7 +141,7 @@ namespace NzbDrone.Core.Applications.Mylar { Name = originalName ?? $"{indexer.Name} (Prowlarr)", Altername = $"{indexer.Name} (Prowlarr)", - Host = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}", + Host = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/api", Apikey = _configFileProvider.ApiKey, Categories = string.Join(",", indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray())), Enabled = indexer.Enable, From b54c7e220e6bf3e22008d1e2b289239cdfcaabd5 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 17 Aug 2021 10:36:08 -0500 Subject: [PATCH 0036/2320] Fixed: Update AppIndexerRegex to support indexer ids over 100 Fixed Update AppIndexerRegex to support /api trailing (Mylar3) --- src/NzbDrone.Core/Applications/ApplicationBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Applications/ApplicationBase.cs b/src/NzbDrone.Core/Applications/ApplicationBase.cs index 6989ad579..cb31fc7d8 100644 --- a/src/NzbDrone.Core/Applications/ApplicationBase.cs +++ b/src/NzbDrone.Core/Applications/ApplicationBase.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Core.Applications protected readonly IAppIndexerMapService _appIndexerMapService; protected readonly Logger _logger; - protected static readonly Regex AppIndexerRegex = new Regex(@"\/(?<indexer>\d.)\/?$", + protected static readonly Regex AppIndexerRegex = new Regex(@"\/(?<indexer>\d{1,3})(?:\/(?:api)?\/?)?$", RegexOptions.IgnoreCase | RegexOptions.Compiled); public abstract string Name { get; } From 0a17b7e8aefd07a1bf30de6c3b0ea461224e8c5a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 18 Aug 2021 22:23:22 -0400 Subject: [PATCH 0037/2320] Fixed: Send Link element in nab response --- src/NzbDrone.Core/IndexerSearch/NewznabResults.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs index 065da5964..c979bff96 100644 --- a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs +++ b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs @@ -80,6 +80,7 @@ namespace NzbDrone.Core.IndexerSearch r.InfoUrl == null ? null : new XElement("comments", r.InfoUrl), r.PublishDate == DateTime.MinValue ? new XElement("pubDate", XmlDateFormat(DateTime.Now)) : new XElement("pubDate", XmlDateFormat(r.PublishDate)), new XElement("size", r.Size), + new XElement("link", r.DownloadUrl ?? t.MagnetUrl ?? string.Empty), r.Categories == null ? null : from c in r.Categories select new XElement("category", c.Id), new XElement( "enclosure", From b46e2c6ad12ab853a4821a76177aa2fee9350447 Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Thu, 19 Aug 2021 22:50:12 +0100 Subject: [PATCH 0038/2320] New: Renamed Blacklist to Blocklist --- frontend/src/Helpers/Props/icons.js | 2 +- .../Indexer/Index/Table/IndexerStatusCell.js | 2 +- .../Actions/Creators/createHandleActions.js | 4 ++-- .../Checks/OutdatedDefinitionCheck.cs | 4 ++-- .../IndexerDefinitionUpdateService.cs | 10 +++++----- src/Prowlarr.Api.V1/swagger.json | 18 +++++++++--------- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/frontend/src/Helpers/Props/icons.js b/frontend/src/Helpers/Props/icons.js index 82f99ec90..01b4a3205 100644 --- a/frontend/src/Helpers/Props/icons.js +++ b/frontend/src/Helpers/Props/icons.js @@ -228,4 +228,4 @@ export const UNSAVED_SETTING = farDotCircle; export const VIEW = fasEye; export const WARNING = fasExclamationTriangle; export const WIKI = fasBookReader; -export const BLACKLIST = fasBan; +export const BLOCKLIST = fasBan; diff --git a/frontend/src/Indexer/Index/Table/IndexerStatusCell.js b/frontend/src/Indexer/Index/Table/IndexerStatusCell.js index 017c7a47f..303f7e714 100644 --- a/frontend/src/Indexer/Index/Table/IndexerStatusCell.js +++ b/frontend/src/Indexer/Index/Table/IndexerStatusCell.js @@ -31,7 +31,7 @@ function IndexerStatusCell(props) { <Icon className={styles.statusIcon} kind={enabled ? enableKind : kinds.DEFAULT} - name={enabled ? enableIcon: icons.BLACKLIST} + name={enabled ? enableIcon: icons.BLOCKLIST} title={enabled ? enableTitle : 'Indexer is Disabled'} /> } diff --git a/frontend/src/Store/Actions/Creators/createHandleActions.js b/frontend/src/Store/Actions/Creators/createHandleActions.js index 2f1954559..817cfda24 100644 --- a/frontend/src/Store/Actions/Creators/createHandleActions.js +++ b/frontend/src/Store/Actions/Creators/createHandleActions.js @@ -10,7 +10,7 @@ import { import getSectionState from 'Utilities/State/getSectionState'; import updateSectionState from 'Utilities/State/updateSectionState'; -const blacklistedProperties = [ +const omittedProperties = [ 'section', 'id' ]; @@ -31,7 +31,7 @@ export default function createHandleActions(handlers, defaultState, section) { if (section === baseSection) { const newState = Object.assign(getSectionState(state, payloadSection), - _.omit(payload, blacklistedProperties)); + _.omit(payload, omittedProperties)); return updateSectionState(state, payloadSection, newState); } diff --git a/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs index dd71e080a..f2e5bee0c 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs @@ -25,9 +25,9 @@ namespace NzbDrone.Core.HealthCheck.Checks public override HealthCheck Check() { - var blacklist = _indexerDefinitionUpdateService.GetBlacklist(); + var blocklist = _indexerDefinitionUpdateService.GetBlocklist(); - var oldIndexers = _indexerFactory.All().Where(i => i.Implementation == "Cardigann" && blacklist.Contains(((CardigannSettings)i.Settings).DefinitionFile)).ToList(); + var oldIndexers = _indexerFactory.All().Where(i => i.Implementation == "Cardigann" && blocklist.Contains(((CardigannSettings)i.Settings).DefinitionFile)).ToList(); if (oldIndexers.Count == 0) { diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index 956b3d6bb..02b38fa61 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -19,13 +19,13 @@ namespace NzbDrone.Core.IndexerVersions { List<CardigannMetaDefinition> All(); CardigannDefinition GetDefinition(string fileKey); - List<string> GetBlacklist(); + List<string> GetBlocklist(); } public class IndexerDefinitionUpdateService : IIndexerDefinitionUpdateService, IExecute<IndexerDefinitionUpdateCommand> { private const int DEFINITION_VERSION = 1; - private readonly List<string> _defintionBlacklist = new List<string>() + private readonly List<string> _defintionBlocklist = new List<string>() { "aither", "animeworld", @@ -69,7 +69,7 @@ namespace NzbDrone.Core.IndexerVersions { var request = new HttpRequest($"https://indexers.prowlarr.com/master/{DEFINITION_VERSION}"); var response = _httpClient.Get<List<CardigannMetaDefinition>>(request); - indexerList = response.Resource.Where(i => !_defintionBlacklist.Contains(i.File)).ToList(); + indexerList = response.Resource.Where(i => !_defintionBlocklist.Contains(i.File)).ToList(); var definitionFolder = Path.Combine(_appFolderInfo.AppDataFolder, "Definitions", "Custom"); @@ -125,9 +125,9 @@ namespace NzbDrone.Core.IndexerVersions return definition; } - public List<string> GetBlacklist() + public List<string> GetBlocklist() { - return _defintionBlacklist; + return _defintionBlocklist; } private CardigannDefinition GetHttpDefinition(string id) diff --git a/src/Prowlarr.Api.V1/swagger.json b/src/Prowlarr.Api.V1/swagger.json index 83dcb5b4a..a121bddfa 100644 --- a/src/Prowlarr.Api.V1/swagger.json +++ b/src/Prowlarr.Api.V1/swagger.json @@ -836,7 +836,7 @@ "description": "Invalid API Key" } }, - "description": "Pushes commands to Prowlarr using a key:value pair. The main key is \"name\" and below are acceptable values but it can also accept other key:value pairs (listed under each command):\n\n* ApplicationUpdate - Trigger an update of Prowlarr\n* Backup - Trigger a backup routine\n* CheckHealth - Trigger a system health check\n* ClearBlacklist - Triggers the removal of all blacklisted movies\n* CleanUpRecycleBin - Trigger a recycle bin cleanup check\n* DeleteLogFiles - Triggers the removal of all Info/Debug/Trace log files\n* DeleteUpdateLogFiles - Triggers the removal of all Update log files\n* DownloadedMoviesScan - Triggers the scan of downloaded movies\n* MissingMoviesSearch - Triggers a search of all missing movies\n* RefreshMonitoredDownloads - Triggers the scan of monitored downloads\n* RefreshMovie - Trigger a refresh / scan of library\n * movieIds:int[] - Specify a list of ids (comma separated) for individual movies to refresh", + "description": "Pushes commands to Prowlarr using a key:value pair. The main key is \"name\" and below are acceptable values but it can also accept other key:value pairs (listed under each command):\n\n* ApplicationUpdate - Trigger an update of Prowlarr\n* Backup - Trigger a backup routine\n* CheckHealth - Trigger a system health check\n* ClearBlocklist - Triggers the removal of all blocklisted movies\n* CleanUpRecycleBin - Trigger a recycle bin cleanup check\n* DeleteLogFiles - Triggers the removal of all Info/Debug/Trace log files\n* DeleteUpdateLogFiles - Triggers the removal of all Update log files\n* DownloadedMoviesScan - Triggers the scan of downloaded movies\n* MissingMoviesSearch - Triggers a search of all missing movies\n* RefreshMonitoredDownloads - Triggers the scan of monitored downloads\n* RefreshMovie - Trigger a refresh / scan of library\n * movieIds:int[] - Specify a list of ids (comma separated) for individual movies to refresh", "security": [ { "X-API-Key": [] @@ -2055,11 +2055,11 @@ ] } }, - "/blackList": { + "/blockList": { "get": { - "summary": "Get Prowlarr's blacklisted movies", + "summary": "Get Prowlarr's blocklisted movies", "tags": [ - "Blacklist" + "Blocklist" ], "responses": { "200": { @@ -2109,7 +2109,7 @@ "description": "Invalid API Key" } }, - "operationId": "get-blackList", + "operationId": "get-blockList", "description": "", "security": [ { @@ -2159,8 +2159,8 @@ ] }, "delete": { - "summary": "Remove a blacklisted movie", - "operationId": "delete-blackList", + "summary": "Remove a blocklisted movie", + "operationId": "delete-blockList", "responses": { "200": { "description": "Successful request" @@ -2169,7 +2169,7 @@ "description": "Invalid API Key" } }, - "description": "Removes a specific movie (the id provided) from the blacklist", + "description": "Removes a specific movie (the id provided) from the blocklist", "security": [ { "X-API-Key": [] @@ -2440,4 +2440,4 @@ } } } -} \ No newline at end of file +} From 1ef43c40c0600641abfefd21811549ef9122f3e1 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 19 Aug 2021 23:37:14 -0400 Subject: [PATCH 0039/2320] Fixed: (BakaBT) Torrent downloads failing Fixes #442 --- .../Exceptions/MovieNotFoundExceptions.cs | 33 ------------------- .../Indexers/Definitions/BakaBT.cs | 20 +++++++++++ 2 files changed, 20 insertions(+), 33 deletions(-) delete mode 100644 src/NzbDrone.Core/Exceptions/MovieNotFoundExceptions.cs diff --git a/src/NzbDrone.Core/Exceptions/MovieNotFoundExceptions.cs b/src/NzbDrone.Core/Exceptions/MovieNotFoundExceptions.cs deleted file mode 100644 index 5018b2889..000000000 --- a/src/NzbDrone.Core/Exceptions/MovieNotFoundExceptions.cs +++ /dev/null @@ -1,33 +0,0 @@ -using NzbDrone.Common.Exceptions; - -namespace NzbDrone.Core.Exceptions -{ - public class MovieNotFoundException : NzbDroneException - { - public int TmdbMovieId { get; set; } - - public MovieNotFoundException(int tmdbMovieId) - : base(string.Format("Movie with tmdbId {0} was not found, it may have been removed from TMDb.", tmdbMovieId)) - { - TmdbMovieId = tmdbMovieId; - } - - public MovieNotFoundException(string imdbId) - : base(string.Format("Movie with IMDBId {0} was not found, it may have been removed from TMDb.", imdbId)) - { - TmdbMovieId = 0; - } - - public MovieNotFoundException(int tmdbMovieId, string message, params object[] args) - : base(message, args) - { - TmdbMovieId = tmdbMovieId; - } - - public MovieNotFoundException(int tmdbMovieId, string message) - : base(message) - { - TmdbMovieId = tmdbMovieId; - } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs index 4266f7889..3a805f04c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs @@ -46,6 +46,26 @@ namespace NzbDrone.Core.Indexers.Definitions return new BakaBTParser(Settings, Capabilities.Categories); } + public override async Task<byte[]> Download(Uri link) + { + var request = new HttpRequestBuilder(link.ToString()) + .SetCookies(GetCookies() ?? new Dictionary<string, string>()) + .Build(); + + var response = await _httpClient.ExecuteAsync(request, Definition); + + var parser = new HtmlParser(); + var dom = parser.ParseDocument(response.Content); + var downloadLink = dom.QuerySelectorAll(".download_link").First().GetAttribute("href"); + + if (string.IsNullOrWhiteSpace(downloadLink)) + { + throw new Exception("Unable to find download link."); + } + + return await base.Download(new Uri(Settings.BaseUrl + downloadLink)); + } + protected override async Task DoLogin() { UpdateCookies(null, null); From 682afc2c75a16efdcedd21c6f16b31e1f9510c45 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 20 Aug 2021 22:50:59 -0400 Subject: [PATCH 0040/2320] Fixed: (Rarbg) Blank baseUrl drop-down (#443) * Fixed: (Rarbg) Blank baseUrl drop-down * fixup! Using missing --- src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs index 5ba132468..1ef5c112d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; @@ -167,6 +168,15 @@ namespace NzbDrone.Core.Indexers.Rarbg captchaToken = cfClearanceCookie }; } + else if (action == "getUrls") + { + var links = IndexerUrls; + + return new + { + options = links.Select(d => new { Value = d, Name = d }) + }; + } return new { }; } From b18e2267181b4532a69dba56db8af44a05b01744 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 20 Aug 2021 23:29:08 -0400 Subject: [PATCH 0041/2320] Bump to 0.1.1 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index cb4070b42..7380da790 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,7 +7,7 @@ variables: outputFolder: './_output' artifactsFolder: './_artifacts' testsFolder: './_tests' - majorVersion: '0.1.0' + majorVersion: '0.1.1' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From 1fe8c63d4168a5c4b1437434ff6f0a47ff3badd5 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 20 Aug 2021 23:45:24 -0400 Subject: [PATCH 0042/2320] Update README.md [skip ci] --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4fd485110..bdcb15a7e 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,12 @@ Prowlarr is a indexer manager/proxy built on the popular arr .net/reactjs base s - Usenet support for 24 indexers natively, including Headphones VIP, and support for any Newznab compatible indexer via "Generic Newznab" - Torrent support for over 500 trackers with more added all the time - Torrent support for any Torznab compatible tracker via "Generic Torznab" -- Indexer Sync to Sonarr/Radarr/Readarr/Lidarr, so no manual configuration of the other applications are required -- Indexer History and Statistics -- Manual Searching of Trackers & Indexers at a category level +- Indexer Sync to Sonarr/Radarr/Readarr/Lidarr/Mylar3, so no manual configuration of the other applications are required +- Indexer history and statistics +- Manual searching of Trackers & Indexers at a category level - Support for pushing releases directly to your download clients from Prowlarr - Indexer health and status notifications +- Per Indexer proxy support (SOCKS4, SOCKS5, HTTP, Flaresolverr) ## Support Note: Prowlarr is currently early in life, thus bugs should be expected From 27064cd2933afe328cfe0688b0361b2fd50507f6 Mon Sep 17 00:00:00 2001 From: PearsonFlyer <john@theediguy.com> Date: Sat, 21 Aug 2021 00:12:39 -0400 Subject: [PATCH 0043/2320] Fixed: Clarify IPT cookie help text (#421) * Fixed: Clarify IPT cookie help text * Update src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs Co-authored-by: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Co-authored-by: PearsonFlyer <PearsonFlyer@github.com> Co-authored-by: Qstick <qstick@gmail.com> Co-authored-by: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> --- src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs index e42c20979..31d651112 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs @@ -368,7 +368,7 @@ namespace NzbDrone.Core.Indexers.Definitions [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "Cookie", HelpText = "Site Cookie - Both the UID and Pass are required.")] + [FieldDefinition(2, Label = "Cookie", HelpText = "Enter the cookie for the site. Example: `cf_clearance=0f7e7f10c62fd069323da10dcad545b828a44b6-1622730685-9-100; uid=123456789; pass=passhashwillbehere`", HelpLink = "https://wiki.servarr.com/prowlarr/faq#finding-cookies")] public string Cookie { get; set; } [FieldDefinition(3, Label = "FreeLeech Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Search Freeleech torrents only")] From 368e0755a07ceb262b738539ca24590cdc5f6a53 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 21 Aug 2021 22:56:50 -0400 Subject: [PATCH 0044/2320] Update README.md [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bdcb15a7e..4ae370ed0 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![Backers on Open Collective](https://opencollective.com/Prowlarr/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Prowlarr/sponsors/badge.svg)](#sponsors) -Prowlarr is a indexer manager/proxy built on the popular arr .net/reactjs base stack to integrate with your various PVR apps. Prowlarr supports both Torrent Trackers and Usenet Indexers. It integrates seamlessly with Sonarr, Radarr, Lidarr, and Readarr offering complete management of your indexers with no per app Indexer setup required (we do it all). +Prowlarr is an indexer manager/proxy built on the popular arr .net/reactjs base stack to integrate with your various PVR apps. Prowlarr supports management of both Torrent Trackers and Usenet Indexers. It integrates seamlessly with Sonarr, Radarr, Lidarr, and Readarr offering complete management of your indexers with no per app Indexer setup required (we do it all). ## Major Features Include: - Usenet support for 24 indexers natively, including Headphones VIP, and support for any Newznab compatible indexer via "Generic Newznab" From b513fac2f7dd1647141037c9f2efbdc15ffa572e Mon Sep 17 00:00:00 2001 From: Steve Adams <stevezau@gmail.com> Date: Sun, 22 Aug 2021 12:59:53 +1000 Subject: [PATCH 0045/2320] Fixed: (HDBits) Not parsing the search term for TV (#444) * Fixing HDBits not parsing the search term * remove debug vars * Handle TVDB Properly --- .../Indexers/Definitions/HDBits/HDBitsRequestGenerator.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsRequestGenerator.cs index dc035f32e..35c258a6f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsRequestGenerator.cs @@ -78,19 +78,18 @@ namespace NzbDrone.Core.Indexers.HDBits { var pageableRequests = new IndexerPageableRequestChain(); var query = new TorrentQuery(); + var tvdbId = searchCriteria.TvdbId.GetValueOrDefault(0); if (searchCriteria.Categories?.Length > 0) { query.Category = Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories).Select(int.Parse).ToArray(); } - if (searchCriteria.TvdbId == 0 && searchCriteria.SearchTerm.IsNotNullOrWhiteSpace()) + if (tvdbId == 0 && searchCriteria.SearchTerm.IsNotNullOrWhiteSpace()) { query.Search = searchCriteria.SanitizedTvSearchString; } - var tvdbId = searchCriteria.TvdbId; - if (tvdbId != 0) { query.TvdbInfo = query.TvdbInfo ?? new TvdbInfo(); From c8cc48229ccaeb00f23c7d6ca31b29ad42807a06 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sat, 21 Aug 2021 02:51:03 +0000 Subject: [PATCH 0046/2320] Translated using Weblate (French) Currently translated at 97.9% (429 of 438 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (438 of 438 strings) Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com> Co-authored-by: ProBatou <baptiste2105@hotmail.fr> Co-authored-by: Weblate <noreply@weblate.org> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/fr.json | 15 ++++++++++----- src/NzbDrone.Core/Localization/Core/pt_BR.json | 8 ++++---- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index 09b276fc6..3c5506bd5 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -42,7 +42,7 @@ "CustomFilters": "Filtres personnalisés", "Crew": "Équipe", "Connections": "Connexions", - "Connect": "Connecter", + "Connect": "Notifications", "CompletedDownloadHandling": "Gestion des téléchargements terminés", "Clear": "Effacer", "ChooseAnotherFolder": "Choisir un autre dossier", @@ -196,7 +196,7 @@ "LastWriteTime": "Heure de la dernière écriture", "Languages": "Langues", "Language": "Langue", - "Indexer": "Indexer", + "Indexer": "Indexeur", "InCinemas": "Dans les cinémas", "Imported": "Importé", "Ignored": "Ignoré", @@ -207,7 +207,7 @@ "DigitalRelease": "Sortie numérique", "Details": "Détails", "Deleted": "Supprimé", - "ConnectSettingsSummary": "Notifications, connexions aux serveurs/lecteurs multimédias et scripts personnalisés", + "ConnectSettingsSummary": "Notifications et scripts personnalisés", "Collection": "Collection", "Certification": "Certification", "Added": "Ajoutée", @@ -873,7 +873,7 @@ "IndexerQuery": "Requête indexeur", "IndexerObsoleteCheckMessage": "Les indexeurs sont obsolètes ou ont été mis à jour : {0}. Veuillez supprimer et (ou) rajouter à Prowlarr", "IndexerHealthCheckNoIndexers": "Aucun indexeur activé, Prowlarr ne renverra pas de résultats de recherche", - "IndexerAuth": "Indexer Auth", + "IndexerAuth": "Authentification d’Indexeur", "EnableRssHelpText": "Activer le flux RSS pour l'indexeur", "EnableRss": "Activer RSS", "EnableIndexer": "Activer l'indexeur", @@ -934,5 +934,10 @@ "FullSync": "Synchronisation complète", "AddRemoveOnly": "Ajouter et supprimer uniquement", "AddDownloadClientToProwlarr": "L'ajout d'un client de téléchargement permet à Prowlarr d'envoyer des fichers directement depuis l'interface utilisateur tout en effectuant une recherche manuelle.", - "NoSearchResultsFound": "Aucun résultat de recherche trouvé, essayez d'effectuer une nouvelle recherche ci-dessous." + "NoSearchResultsFound": "Aucun résultat de recherche trouvé, essayez d'effectuer une nouvelle recherche ci-dessous.", + "DeleteIndexerProxy": "Supprimer le proxy indexeur", + "DeleteIndexerProxyMessageText": "Êtes-vous sur de vouloir supprimer le proxy '{0}'  ?", + "AddIndexerProxy": "Ajouter proxy indexeur", + "AppSettingsSummary": "Applications et paramètres pour configurer comment Prowlarr interagit avec vos programmes PVR", + "IndexerTagsHelpText": "Utilisez des balises pour spécifier des clients par défaut, spécifier les proxies d'indexeur ou pour organiser vos indexeurs." } diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index 0a904b31c..dcb1c3f1d 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -10,10 +10,10 @@ "CertificateValidationHelpText": "Alterar o quão estrita é a validação da certificação HTTPS", "ClientPriority": "Prioridade do cliente", "ConnectionLostAutomaticMessage": "O Prowlarr tentará se conectar automaticamente, ou você pode clicar em Recarregar abaixo.", - "ConnectSettingsSummary": "Notificações, conexões com servidores/reprodutores de mídia, e scripts personalizados", + "ConnectSettingsSummary": "Notificações e scripts personalizados", "DeleteIndexerMessageText": "Tem certeza de que deseja excluir o indexador \"{0}\"?", "IndexerObsoleteCheckMessage": "Os seguintes indexadores são obsoletos ou foram atualizados: {0}. Remova-os e/ou adicione-os novamente ao Prowlarr", - "DownloadClientsSettingsSummary": "Baixe a configuração dos clientes para integração na pesquisa de interface do usuário prowlarr", + "DownloadClientsSettingsSummary": "Configuração de clientes de download para integração com a pesquisa da interface do usuário do Prowlarr", "EnableAutoHelpText": "Se habilitada, os filmes serão automaticamente adicionados ao Prowlarr a partir desta lista", "EnableAutomaticSearchHelpTextWarning": "Será usado com a pesquisa interativa", "EnableColorImpairedModeHelpText": "Estilo alterado para permitir que usuários com daltonismo distingam melhor as informações codificadas por cores", @@ -104,7 +104,7 @@ "CloseCurrentModal": "Fechar modal atual", "Columns": "Colunas", "Component": "Componente", - "Connect": "Conexões", + "Connect": "Notificações", "ConnectionLost": "Conexão perdida", "ConnectionLostMessage": "O Prowlarr perdeu a conexão com o backend e precisará ser recarregado para restaurar a funcionalidade.", "Connections": "Conexões", @@ -341,7 +341,7 @@ "UILanguage": "Idioma da interface", "UILanguageHelpTextWarning": "É necessário recarregar o navegador", "UISettings": "Configurações da interface", - "UISettingsSummary": "Opções de daltonismo, data e calendário", + "UISettingsSummary": "Opções de daltonismo, data e idioma", "UnableToAddANewNotificationPleaseTryAgain": "Não foi possível adicionar uma nova notificação, tente novamente.", "UnableToLoadBackups": "Não foi possível carregar os backups", "UnableToLoadDevelopmentSettings": "Não foi possível carregar as configurações de desenvolvimento", From ab1545e83499361318dca7786521c8ebaa14b920 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 21 Aug 2021 22:41:25 -0400 Subject: [PATCH 0047/2320] Fixed: Mass Indexer delete fails with 415 --- src/Prowlarr.Api.V1/Indexers/IndexerEditorController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerEditorController.cs b/src/Prowlarr.Api.V1/Indexers/IndexerEditorController.cs index ffb0459f5..cdf6c2061 100644 --- a/src/Prowlarr.Api.V1/Indexers/IndexerEditorController.cs +++ b/src/Prowlarr.Api.V1/Indexers/IndexerEditorController.cs @@ -72,7 +72,7 @@ namespace Prowlarr.Api.V1.Indexers } [HttpDelete] - public object DeleteIndexers(IndexerEditorResource resource) + public object DeleteIndexers([FromBody] IndexerEditorResource resource) { _indexerService.DeleteIndexers(resource.IndexerIds); From d50e1d7cc08d994e94c67870fe6bbae1979732f7 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 21 Aug 2021 22:41:15 -0500 Subject: [PATCH 0048/2320] update readme [skip ci] --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4ae370ed0..e0e539918 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![Backers on Open Collective](https://opencollective.com/Prowlarr/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Prowlarr/sponsors/badge.svg)](#sponsors) -Prowlarr is an indexer manager/proxy built on the popular arr .net/reactjs base stack to integrate with your various PVR apps. Prowlarr supports management of both Torrent Trackers and Usenet Indexers. It integrates seamlessly with Sonarr, Radarr, Lidarr, and Readarr offering complete management of your indexers with no per app Indexer setup required (we do it all). +Prowlarr is an indexer manager/proxy built on the popular arr .net/reactjs base stack to integrate with your various PVR apps. Prowlarr supports management of both Torrent Trackers and Usenet Indexers. It integrates seamlessly with Lidarr, Mylar3, Radarr, Readarr, and Sonarr offering complete management of your indexers with no per app Indexer setup required (we do it all). ## Major Features Include: - Usenet support for 24 indexers natively, including Headphones VIP, and support for any Newznab compatible indexer via "Generic Newznab" @@ -36,9 +36,13 @@ Note: Prowlarr is currently early in life, thus bugs should be expected - Request or vote on an existing request for a new tracker/indexer ## Contributors & Developers -This project exists thanks to all the people who contribute. [Contribute](CONTRIBUTING.md). -<a href="https://github.com/Prowlarr/Prowlarr/graphs/contributors"><img src="https://opencollective.com/Prowlarr/contributors.svg?width=890&button=false" /></a> +- [Contribute (GitHub)](CONTRIBUTING.md) +- [Contribution (Wiki Article)](https://wiki.servarr.com/prowlarr/contributing) +- [YML Indexer Defintion (Wiki Article)](https://wiki.servarr.com/prowlarr/cardigann-yml-definition) + +This project exists thanks to all the people who contribute. +<a href="https://github.com/Prowlarr/Prowlarr/graphs/contributors"><img src="https://opencollective.com/Prowlarr/contributors.svg?width=890&button=false" /></a> ## Backers From ab7bc85368cfc6492d89e3bd61c69f955c76b61a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 22 Aug 2021 11:43:40 -0400 Subject: [PATCH 0049/2320] fix mass delete --- frontend/src/Utilities/createAjaxRequest.js | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/frontend/src/Utilities/createAjaxRequest.js b/frontend/src/Utilities/createAjaxRequest.js index 005f06936..a91619703 100644 --- a/frontend/src/Utilities/createAjaxRequest.js +++ b/frontend/src/Utilities/createAjaxRequest.js @@ -7,18 +7,6 @@ function isRelative(ajaxOptions) { return !absUrlRegex.test(ajaxOptions.url); } -function moveBodyToQuery(ajaxOptions) { - if (ajaxOptions.data && ajaxOptions.type === 'DELETE') { - if (ajaxOptions.url.contains('?')) { - ajaxOptions.url += '&'; - } else { - ajaxOptions.url += '?'; - } - ajaxOptions.url += $.param(ajaxOptions.data); - delete ajaxOptions.data; - } -} - function addRootUrl(ajaxOptions) { ajaxOptions.url = apiRoot + ajaxOptions.url; } @@ -32,7 +20,7 @@ function addContentType(ajaxOptions) { if ( ajaxOptions.contentType == null && ajaxOptions.dataType === 'json' && - (ajaxOptions.method === 'PUT' || ajaxOptions.method === 'POST')) { + (ajaxOptions.method === 'PUT' || ajaxOptions.method === 'POST' || ajaxOptions.method === 'DELETE')) { ajaxOptions.contentType = 'application/json'; } } @@ -52,7 +40,6 @@ export default function createAjaxRequest(originalAjaxOptions) { const ajaxOptions = { dataType: 'json', ...originalAjaxOptions }; if (isRelative(ajaxOptions)) { - moveBodyToQuery(ajaxOptions); addRootUrl(ajaxOptions); addApiKey(ajaxOptions); addContentType(ajaxOptions); From f4cee1d5f41cb8879aaf5ea95651f172f668d710 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 22 Aug 2021 10:40:24 -0500 Subject: [PATCH 0050/2320] Fixed: UserAgent Parsing Fixes #448 New - add user agent parser tests --- .../Http/UserAgentParserFixture.cs | 24 +++++++++++++++++++ src/NzbDrone.Common/Http/UserAgentParser.cs | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/NzbDrone.Common.Test/Http/UserAgentParserFixture.cs diff --git a/src/NzbDrone.Common.Test/Http/UserAgentParserFixture.cs b/src/NzbDrone.Common.Test/Http/UserAgentParserFixture.cs new file mode 100644 index 000000000..e262a1466 --- /dev/null +++ b/src/NzbDrone.Common.Test/Http/UserAgentParserFixture.cs @@ -0,0 +1,24 @@ +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Common.Http; +using NzbDrone.Test.Common; + +namespace NzbDrone.Common.Test.Http +{ + [TestFixture] + public class UserAgentParserFixture : TestBase + { + // Ref *Arr `_userAgent = $"{BuildInfo.AppName}/{BuildInfo.Version} ({osName} {osVersion})";` + // Ref Mylar `Mylar3/' +str(hash) +'(' +vers +') +http://www.github.com/mylar3/mylar3/` + [TestCase("Mylar3/ 3ee23rh23irqfq (13123123) http://www.github.com/mylar3/mylar3/", "Mylar3")] + [TestCase("Lidarr/1.0.0.2300 (ubuntu 20.04)", "Lidarr")] + [TestCase("Radarr/1.0.0.2300 (ubuntu 20.04)", "Radarr")] + [TestCase("Readarr/1.0.0.2300 (ubuntu 20.04)", "Readarr")] + [TestCase("Sonarr/3.0.6.9999 (ubuntu 20.04)", "Sonarr")] + [TestCase("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36", "Other")] + public void should_parse_user_agent(string userAgent, string parsedAgent) + { + UserAgentParser.ParseSource(userAgent).Should().Be(parsedAgent); + } + } +} diff --git a/src/NzbDrone.Common/Http/UserAgentParser.cs b/src/NzbDrone.Common/Http/UserAgentParser.cs index e1164b9e8..8eb5f6d6a 100644 --- a/src/NzbDrone.Common/Http/UserAgentParser.cs +++ b/src/NzbDrone.Common/Http/UserAgentParser.cs @@ -9,7 +9,7 @@ namespace NzbDrone.Common.Http { public static class UserAgentParser { - private static readonly Regex AppSourceRegex = new Regex(@"(?<agent>.*)\/.*(\(.*\))?", + private static readonly Regex AppSourceRegex = new Regex(@"(?<agent>[a-z0-9]*)\/.*(?:\(.*\))?", RegexOptions.IgnoreCase | RegexOptions.Compiled); public static string SimplifyUserAgent(string userAgent) From c72222a696752f837bcbb6001f5aaa0c4c9fdb77 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 22 Aug 2021 22:24:46 -0400 Subject: [PATCH 0051/2320] Mylar code cleanup --- src/NzbDrone.Core/Applications/Mylar/Mylar.cs | 12 +++++----- .../Applications/Mylar/MylarError.cs | 6 ----- .../Applications/Mylar/MylarField.cs | 22 ------------------- .../Applications/Mylar/MylarV3Proxy.cs | 3 --- 4 files changed, 6 insertions(+), 37 deletions(-) delete mode 100644 src/NzbDrone.Core/Applications/Mylar/MylarField.cs diff --git a/src/NzbDrone.Core/Applications/Mylar/Mylar.cs b/src/NzbDrone.Core/Applications/Mylar/Mylar.cs index bddf9baa0..195c3e555 100644 --- a/src/NzbDrone.Core/Applications/Mylar/Mylar.cs +++ b/src/NzbDrone.Core/Applications/Mylar/Mylar.cs @@ -19,10 +19,10 @@ namespace NzbDrone.Core.Applications.Mylar private readonly IMylarV3Proxy _mylarV3Proxy; private readonly IConfigFileProvider _configFileProvider; - public Mylar(IMylarV3Proxy lidarrV1Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, Logger logger) + public Mylar(IMylarV3Proxy mylarV3Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, Logger logger) : base(appIndexerMapService, logger) { - _mylarV3Proxy = lidarrV1Proxy; + _mylarV3Proxy = mylarV3Proxy; _configFileProvider = configFileProvider; } @@ -70,9 +70,9 @@ namespace NzbDrone.Core.Applications.Mylar { if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) { - var lidarrIndexer = BuildMylarIndexer(indexer, indexer.Protocol); + var mylarIndexer = BuildMylarIndexer(indexer, indexer.Protocol); - var remoteIndexer = _mylarV3Proxy.AddIndexer(lidarrIndexer, Settings); + var remoteIndexer = _mylarV3Proxy.AddIndexer(mylarIndexer, Settings); _appIndexerMapService.Insert(new AppIndexerMap { AppId = Definition.Id, IndexerId = indexer.Id, RemoteIndexerName = $"{remoteIndexer.Type},{remoteIndexer.Name}" }); } } @@ -137,7 +137,7 @@ namespace NzbDrone.Core.Applications.Mylar { var schema = protocol == DownloadProtocol.Usenet ? MylarProviderType.Newznab : MylarProviderType.Torznab; - var lidarrIndexer = new MylarIndexer + var mylarIndexer = new MylarIndexer { Name = originalName ?? $"{indexer.Name} (Prowlarr)", Altername = $"{indexer.Name} (Prowlarr)", @@ -148,7 +148,7 @@ namespace NzbDrone.Core.Applications.Mylar Type = schema, }; - return lidarrIndexer; + return mylarIndexer; } } } diff --git a/src/NzbDrone.Core/Applications/Mylar/MylarError.cs b/src/NzbDrone.Core/Applications/Mylar/MylarError.cs index d7d18a2dd..7592e4452 100644 --- a/src/NzbDrone.Core/Applications/Mylar/MylarError.cs +++ b/src/NzbDrone.Core/Applications/Mylar/MylarError.cs @@ -1,9 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - namespace NzbDrone.Core.Applications.Mylar { public class MylarError diff --git a/src/NzbDrone.Core/Applications/Mylar/MylarField.cs b/src/NzbDrone.Core/Applications/Mylar/MylarField.cs deleted file mode 100644 index 909aec6f1..000000000 --- a/src/NzbDrone.Core/Applications/Mylar/MylarField.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace NzbDrone.Core.Applications.Mylar -{ - public class MylarField - { - public int Order { get; set; } - public string Name { get; set; } - public string Label { get; set; } - public string Unit { get; set; } - public string HelpText { get; set; } - public string HelpLink { get; set; } - public object Value { get; set; } - public string Type { get; set; } - public bool Advanced { get; set; } - public string Section { get; set; } - public string Hidden { get; set; } - - public MylarField Clone() - { - return (MylarField)MemberwiseClone(); - } - } -} diff --git a/src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs b/src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs index bdd0654d8..ba271b53e 100644 --- a/src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs +++ b/src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs @@ -1,13 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Net; using FluentValidation.Results; using Newtonsoft.Json; using NLog; using NzbDrone.Common.Http; -using NzbDrone.Common.Serializer; -using NzbDrone.Core.Indexers; namespace NzbDrone.Core.Applications.Mylar { From 03f821f48437bfca9e316e16921f805c62eddc4e Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 23 Aug 2021 22:35:28 -0400 Subject: [PATCH 0052/2320] New: Make VIP Check Generic --- ...{NewznabVIPCheck.cs => IndexerVIPCheck.cs} | 26 ++++++++++++------- src/NzbDrone.Core/Localization/Core/en.json | 4 +-- 2 files changed, 18 insertions(+), 12 deletions(-) rename src/NzbDrone.Core/HealthCheck/Checks/{NewznabVIPCheck.cs => IndexerVIPCheck.cs} (75%) diff --git a/src/NzbDrone.Core/HealthCheck/Checks/NewznabVIPCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPCheck.cs similarity index 75% rename from src/NzbDrone.Core/HealthCheck/Checks/NewznabVIPCheck.cs rename to src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPCheck.cs index b832ce295..7c12348b7 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/NewznabVIPCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPCheck.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using NzbDrone.Common.Extensions; using NzbDrone.Core.Indexers; -using NzbDrone.Core.Indexers.Newznab; using NzbDrone.Core.Localization; using NzbDrone.Core.ThingiProvider.Events; @@ -12,11 +11,11 @@ namespace NzbDrone.Core.HealthCheck.Checks [CheckOn(typeof(ProviderAddedEvent<IIndexer>))] [CheckOn(typeof(ProviderUpdatedEvent<IIndexer>))] [CheckOn(typeof(ProviderDeletedEvent<IIndexer>))] - public class NewznabVIPCheck : HealthCheckBase + public class IndexerVIPCheck : HealthCheckBase { private readonly IIndexerFactory _indexerFactory; - public NewznabVIPCheck(IIndexerFactory indexerFactory, ILocalizationService localizationService) + public IndexerVIPCheck(IIndexerFactory indexerFactory, ILocalizationService localizationService) : base(localizationService) { _indexerFactory = indexerFactory; @@ -25,13 +24,20 @@ namespace NzbDrone.Core.HealthCheck.Checks public override HealthCheck Check() { var enabled = _indexerFactory.Enabled(false); - var newznabProviders = enabled.Where(i => i.Definition.Implementation == typeof(Newznab).Name); var expiringProviders = new List<IIndexer>(); var expiredProviders = new List<IIndexer>(); - foreach (var provider in newznabProviders) + foreach (var provider in enabled) { - var expiration = ((NewznabSettings)provider.Definition.Settings).VipExpiration; + var settingsType = provider.Definition.Settings.GetType(); + var vipProp = settingsType.GetProperty("VipExpiration"); + + if (vipProp == null) + { + continue; + } + + var expiration = (string)vipProp.GetValue(provider.Definition.Settings); if (expiration.IsNullOrWhiteSpace()) { @@ -53,18 +59,18 @@ namespace NzbDrone.Core.HealthCheck.Checks { return new HealthCheck(GetType(), HealthCheckResult.Warning, - string.Format(_localizationService.GetLocalizedString("NewznabVipCheckExpiringClientMessage"), + string.Format(_localizationService.GetLocalizedString("IndexerVipCheckExpiringClientMessage"), string.Join(", ", expiringProviders.Select(v => v.Definition.Name))), - "#newznab-vip-expiring"); + "#indexer-vip-expiring"); } if (!expiredProviders.Empty()) { return new HealthCheck(GetType(), HealthCheckResult.Warning, - string.Format(_localizationService.GetLocalizedString("NewznabVipCheckExpiredClientMessage"), + string.Format(_localizationService.GetLocalizedString("IndexerVipCheckExpiredClientMessage"), string.Join(", ", expiredProviders.Select(v => v.Definition.Name))), - "#newznab-vip-expired"); + "#indexer-vip-expired"); } return new HealthCheck(GetType()); diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index e5aee90c8..82bfa8088 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -239,8 +239,8 @@ "Name": "Name", "NetCore": ".NET", "New": "New", - "NewznabVipCheckExpiredClientMessage": "Indexer VIP benefits have expired: {0}", - "NewznabVipCheckExpiringClientMessage": "Indexer VIP benefits expiring soon: {0}", + "IndexerVipCheckExpiredClientMessage": "Indexer VIP benefits have expired: {0}", + "IndexerVipCheckExpiringClientMessage": "Indexer VIP benefits expiring soon: {0}", "NoBackupsAreAvailable": "No backups are available", "NoChange": "No Change", "NoChanges": "No Changes", From 46e1cce6322ab1fe7306f86a037bce712b9e1167 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Fri, 13 Aug 2021 11:08:05 -0500 Subject: [PATCH 0053/2320] New: (TorrentLeech) Add VIP Expiration Closes #419 bonus- sort en.json --- .../Indexers/Definitions/TorrentLeech.cs | 13 ++++++++++++- src/NzbDrone.Core/Localization/Core/en.json | 6 +++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs index 6b21342ee..c2c74d7f1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs @@ -329,6 +329,14 @@ namespace NzbDrone.Core.Indexers.Definitions { RuleFor(c => c.Username).NotEmpty(); RuleFor(c => c.Password).NotEmpty(); + + RuleFor(c => c.VipExpiration).Must(c => c.IsValidDate()) + .When(c => c.VipExpiration.IsNotNullOrWhiteSpace()) + .WithMessage("Correctly formatted date is required"); + + RuleFor(c => c.VipExpiration).Must(c => c.IsFutureDate()) + .When(c => c.VipExpiration.IsNotNullOrWhiteSpace()) + .WithMessage("Must be a future date"); } } @@ -354,7 +362,10 @@ namespace NzbDrone.Core.Indexers.Definitions [FieldDefinition(4, Label = "FreeLeech Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Search Freeleech torrents only")] public bool FreeLeechOnly { get; set; } - [FieldDefinition(5)] + [FieldDefinition(5, Label = "VIP Expiration", HelpText = "Enter date (yyyy-mm-dd) for VIP Expiration or blank, Prowlarr will notify 1 week from expiration of VIP")] + public string VipExpiration { get; set; } + + [FieldDefinition(6)] public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); public NzbDroneValidationResult Validate() diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 82bfa8088..f0c0a9047 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -191,16 +191,18 @@ "IndexerPriority": "Indexer Priority", "IndexerPriorityHelpText": "Indexer Priority from 1 (Highest) to 50 (Lowest). Default: 25.", "IndexerProxies": "Indexer Proxies", - "IndexerSettingsSummary": "Configure various global Indexer settings including Proxies.", "IndexerProxyStatusCheckAllClientMessage": "All proxies are unavailable due to failures", "IndexerProxyStatusCheckSingleClientMessage": "Proxies unavailable due to failures: {0}", "IndexerQuery": "Indexer Query", "IndexerRss": "Indexer Rss", "Indexers": "Indexers", + "IndexerSettingsSummary": "Configure various global Indexer settings including Proxies.", "IndexersSelectedInterp": "{0} Indexer(s) Selected", "IndexerStatusCheckAllClientMessage": "All indexers are unavailable due to failures", "IndexerStatusCheckSingleClientMessage": "Indexers unavailable due to failures: {0}", "IndexerTagsHelpText": "Use tags to specify default clients, specify Indexer Proxies, or just to organize your indexers.", + "IndexerVipCheckExpiredClientMessage": "Indexer VIP benefits have expired: {0}", + "IndexerVipCheckExpiringClientMessage": "Indexer VIP benefits expiring soon: {0}", "Info": "Info", "InteractiveSearch": "Interactive Search", "Interval": "Interval", @@ -239,8 +241,6 @@ "Name": "Name", "NetCore": ".NET", "New": "New", - "IndexerVipCheckExpiredClientMessage": "Indexer VIP benefits have expired: {0}", - "IndexerVipCheckExpiringClientMessage": "Indexer VIP benefits expiring soon: {0}", "NoBackupsAreAvailable": "No backups are available", "NoChange": "No Change", "NoChanges": "No Changes", From 1d20b9d429251ec3108568daee767c9904f3a217 Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Mon, 23 Aug 2021 22:12:40 +0100 Subject: [PATCH 0054/2320] Fixed: Don't delete tags used by indexer proxies --- .../Housekeepers/CleanupUnusedTagsFixture.cs | 27 +++++++++++++++++++ .../Housekeepers/CleanupUnusedTags.cs | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupUnusedTagsFixture.cs b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupUnusedTagsFixture.cs index 05e2b58df..4f9b7c0b9 100644 --- a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupUnusedTagsFixture.cs +++ b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupUnusedTagsFixture.cs @@ -2,6 +2,8 @@ using FizzWare.NBuilder; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Housekeeping.Housekeepers; +using NzbDrone.Core.IndexerProxies; +using NzbDrone.Core.IndexerProxies.Http; using NzbDrone.Core.Tags; using NzbDrone.Core.Test.Framework; @@ -22,5 +24,30 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers Subject.Clean(); AllStoredModels.Should().BeEmpty(); } + + [Test] + public void should_not_delete_used_tags() + { + var tags = Builder<Tag> + .CreateListOfSize(2) + .All() + .With(x => x.Id = 0) + .BuildList(); + + Db.InsertMany(tags); + + var settings = Builder<HttpSettings>.CreateNew().Build(); + + var restrictions = Builder<IndexerProxyDefinition>.CreateListOfSize(2) + .All() + .With(x => x.Id = 0) + .With(x => x.Settings = settings) + .With(v => v.Tags.Add(tags[0].Id)) + .BuildList(); + Db.InsertMany(restrictions); + + Subject.Clean(); + AllStoredModels.Should().HaveCount(1); + } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs index f23773660..4ee4afd78 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs @@ -19,7 +19,7 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers { using (var mapper = _database.OpenConnection()) { - var usedTags = new[] { "Notifications" } + var usedTags = new[] { "Notifications", "IndexerProxies", "Indexers", "Applications" } .SelectMany(v => GetUsedTags(v, mapper)) .Distinct() .ToArray(); From 77a76fe5a123d8a1f8258db3514c093131042499 Mon Sep 17 00:00:00 2001 From: Steve Adams <stevezau@gmail.com> Date: Thu, 26 Aug 2021 13:22:04 +1000 Subject: [PATCH 0055/2320] New: HDBits to parse IMDB using parser utils (#454) --- .../HDBits/HDBitsRequestGenerator.cs | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsRequestGenerator.cs index 35c258a6f..8c486c673 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsRequestGenerator.cs @@ -5,6 +5,7 @@ using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Common.Serializer; using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Parser; namespace NzbDrone.Core.Indexers.HDBits { @@ -17,26 +18,22 @@ namespace NzbDrone.Core.Indexers.HDBits { var pageableRequests = new IndexerPageableRequestChain(); var query = new TorrentQuery(); + var imdbId = ParseUtil.GetImdbID(searchCriteria.ImdbId).GetValueOrDefault(0); if (searchCriteria.Categories?.Length > 0) { query.Category = Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories).Select(int.Parse).ToArray(); } - if (searchCriteria.ImdbId.IsNullOrWhiteSpace() && searchCriteria.SearchTerm.IsNotNullOrWhiteSpace()) + if (imdbId == 0 && searchCriteria.SearchTerm.IsNotNullOrWhiteSpace()) { query.Search = searchCriteria.SanitizedSearchTerm; } - if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace()) + if (imdbId != 0) { - var imdbId = int.Parse(searchCriteria.ImdbId.Substring(2)); - - if (imdbId != 0) - { - query.ImdbInfo = query.ImdbInfo ?? new ImdbInfo(); - query.ImdbInfo.Id = imdbId; - } + query.ImdbInfo = query.ImdbInfo ?? new ImdbInfo(); + query.ImdbInfo.Id = imdbId; } pageableRequests.Add(GetRequest(query)); @@ -79,13 +76,14 @@ namespace NzbDrone.Core.Indexers.HDBits var pageableRequests = new IndexerPageableRequestChain(); var query = new TorrentQuery(); var tvdbId = searchCriteria.TvdbId.GetValueOrDefault(0); + var imdbId = ParseUtil.GetImdbID(searchCriteria.ImdbId).GetValueOrDefault(0); if (searchCriteria.Categories?.Length > 0) { query.Category = Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories).Select(int.Parse).ToArray(); } - if (tvdbId == 0 && searchCriteria.SearchTerm.IsNotNullOrWhiteSpace()) + if (tvdbId == 0 && imdbId == 0 && searchCriteria.SearchTerm.IsNotNullOrWhiteSpace()) { query.Search = searchCriteria.SanitizedTvSearchString; } @@ -98,6 +96,12 @@ namespace NzbDrone.Core.Indexers.HDBits query.TvdbInfo.Episode = searchCriteria.Episode; } + if (imdbId != 0) + { + query.ImdbInfo = query.ImdbInfo ?? new ImdbInfo(); + query.ImdbInfo.Id = imdbId; + } + pageableRequests.Add(GetRequest(query)); return pageableRequests; From 04e84f3a90b41ce1d8df5e94aae8459d004a8462 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Tue, 24 Aug 2021 16:13:31 +0000 Subject: [PATCH 0056/2320] Translated using Weblate (Hungarian) Currently translated at 100.0% (438 of 438 strings) Translated using Weblate (French) Currently translated at 97.7% (428 of 438 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (438 of 438 strings) Co-authored-by: Anonymous <noreply@weblate.org> Co-authored-by: Csaba <csab0825@gmail.com> Co-authored-by: Weblate <noreply@weblate.org> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/fr.json | 3 ++- src/NzbDrone.Core/Localization/Core/hu.json | 24 ++++++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index 3c5506bd5..c61038ace 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -939,5 +939,6 @@ "DeleteIndexerProxyMessageText": "Êtes-vous sur de vouloir supprimer le proxy '{0}'  ?", "AddIndexerProxy": "Ajouter proxy indexeur", "AppSettingsSummary": "Applications et paramètres pour configurer comment Prowlarr interagit avec vos programmes PVR", - "IndexerTagsHelpText": "Utilisez des balises pour spécifier des clients par défaut, spécifier les proxies d'indexeur ou pour organiser vos indexeurs." + "IndexerTagsHelpText": "Utilisez des balises pour spécifier des clients par défaut, spécifier les proxies d'indexeur ou pour organiser vos indexeurs.", + "Notifications": "Notifications" } diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index 7158fecff..d7a81553b 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -120,13 +120,13 @@ "CopyUsingHardlinksHelpTextWarning": "Esetenként az írásvédettség megakadályozza a Seedelt fájlok átnevezését. Ideiglenesen állítsd le a Seedelést, hogy a Prowlarr át tudja nevezni a fájlokat.", "CopyUsingHardlinksHelpText": "Használj Hardlininket, amikor megpróbálsz fájlokat másolni a még Seedelt torrentekből", "CopyToClipboard": "Másold a Vágólapra", - "ConnectSettingsSummary": "Értesítések, kapcsolatok médiaszerverekhez/lejátszókhoz, és egyéni szkriptek", + "ConnectSettingsSummary": "Értesítések és egyéni szkriptek", "ConnectSettings": "Kapcsolódási Beállítások", "Connections": "Kapcsolatok", "ConnectionLostMessage": "A Prowlarr elvesztette kapcsolatát a háttérrendszerrel, a funkciók helyreállításához frissíts.", "ConnectionLostAutomaticMessage": "A Prowlarr megpróbál automatikusan csatlakozni, vagy kattints a frissítés gombra.", "ConnectionLost": "Kapcsolódás Elveszett", - "Connect": "Kapcsolódás", + "Connect": "Értesítések", "Conditions": "Állapot", "Component": "Komponens", "CompletedDownloadHandling": "Kész Letöltések Kezelése", @@ -224,7 +224,7 @@ "GrabReleaseMessageText": "Prowlarr nem tudta meghatározni, hogy melyik filmhez készült ez a kiadás. Lehet, hogy a Prowlarr nem tudja automatikusan importálni ezt a kiadást. Meg szeretnéd ragadni a (z) „{0}”-t?", "GoToInterp": "Ugrás ide: {0}", "Genres": "Műfajok", - "GeneralSettingsSummary": "Port, SSL, felhasználónév / jelszó, proxy, elemzések és frissítések", + "GeneralSettingsSummary": "Port, SSL, felhasználónév / jelszó, proxy, elemzések, és frissítések", "FileChmodHelpTexts2": "Ugyanez a mód lesz alkalmazva azokra a filmekre / almappákra, amelyekhez a futtató bit hozzá lett adva, pl. A 0644-ból 0755 lesz", "FreeSpace": "Szabad Tárhely", "ForMoreInformationOnTheIndividualIndexers": "Az egyes indexerekről további információkért kattints az info gombokra.", @@ -685,7 +685,7 @@ "UnableToAddANewDownloadClientPleaseTryAgain": "Nem lehet új letöltőklienst hozzáadni, próbálkozz újra.", "UnableToAddANewCustomFormatPleaseTryAgain": "Nem lehet új egyéni formátumot hozzáadni, próbálkozz újra.", "UnableToAddANewConditionPleaseTryAgain": "Nem lehet új feltételt hozzáadni, próbáld meg újra.", - "UISettingsSummary": "A naptár, a dátum és a színtévesztő mód beállításai", + "UISettingsSummary": "Dátum-, nyelv- és színtévesztő lehetőségek", "UISettings": "A felhasználói felület beállításai", "UILanguageHelpTextWarning": "Böngésző újratöltése szükséges", "UILanguageHelpText": "A Prowlarr által a felhasználói felülethez használt nyelv", @@ -927,5 +927,19 @@ "AddRemoveOnly": "Csak hozzáadás és eltávolítás", "AddDownloadClientToProwlarr": "Letöltőkliens hozzáadásával a Prowlarr kézi keresés közben közvetlenül a felhasználói felületről küldhet kiadásokat.", "Add": "Hozzáadás", - "NoSearchResultsFound": "Nincs találat. Próbálkozzon új kereséssel." + "NoSearchResultsFound": "Nincs találat. Próbálkozzon új kereséssel.", + "AppSettingsSummary": "Alkalmazások és beállítások a Prowlarr interakciójának beállításához a PVR programjaiddal", + "DeleteIndexerProxy": "Indexer Proxy törlése", + "DeleteIndexerProxyMessageText": "Biztosan törlöd a(z) „{0}” proxyt?", + "IndexerProxies": "Indexer Proxy(k)", + "IndexerProxyStatusCheckAllClientMessage": "Az összes Proxy elérhetetlen, hiba miatt", + "IndexerProxyStatusCheckSingleClientMessage": "Proxyk elérhetetlenek az alábbi hibák miatt: {0}", + "IndexerTagsHelpText": "Címkékkel határozhatja meg az alapértelmezett ügyfeleket, adhat meg indexer proxyt, vagy csak rendszerezheti indexelőit.", + "UnableToLoadIndexerProxies": "Nem lehet betölteni az Indexer Proxyt", + "AddIndexerProxy": "Indexer Proxy hozzáadása", + "IndexerSettingsSummary": "Konfigurálja a különböző globális indexer beállításokat, beleértve a proxykat is.", + "Notifications": "Értesítések", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Nem lehet új Indexer Proxyt hozzáadni, próbálja újra.", + "IndexerVipCheckExpiredClientMessage": "Az Indexer VIP előnyei lejártak: {0}", + "IndexerVipCheckExpiringClientMessage": "Az Indexer VIP előnyei hamarosan lejárnak: {0}" } From 3c9fbeabaa7cda41792b83af842686e9a83539a9 Mon Sep 17 00:00:00 2001 From: Nyuels <53974940+Nyuels@users.noreply.github.com> Date: Sat, 28 Aug 2021 00:21:56 +0200 Subject: [PATCH 0057/2320] Fixed: Use Gazelle freelech tokens. (#465) --- src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs index f04f04bca..aa1a463c7 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs @@ -141,7 +141,7 @@ namespace NzbDrone.Core.Indexers.Gazelle var url = new HttpUri(_settings.BaseUrl) .CombinePath("/torrents.php") .AddQueryParam("action", "download") - .AddQueryParam("useToken", _settings.UseFreeleechToken ? "1" : "0") + .AddQueryParam("usetoken", _settings.UseFreeleechToken ? "1" : "0") .AddQueryParam("id", torrentId); return url.FullUri; From a2c8cec27ebd18d0310718ebb0e19e9baa54a0b5 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 21 Aug 2021 12:38:26 -0500 Subject: [PATCH 0058/2320] bug template fix [skip ci] [common] --- .github/ISSUE_TEMPLATE/bug_report.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index d858dcb24..a3863e2eb 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -68,6 +68,7 @@ body: description: | Trace Logs (https://wiki.servarr.com/prowlarr/troubleshooting#logging-and-log-files) Links? References? Anything that will give us more context about the issue you are encountering! + ***Generally speaking, all bug reports must have trace logs provided.*** Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. validations: From 658724b3154a3ba32fd4f53bab347a8ddd3c0801 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 29 Aug 2021 23:12:59 -0400 Subject: [PATCH 0059/2320] OpenAPI auto generation test --- src/Prowlarr.Api.V1/swagger.json | 8759 ++++++++++++++++++++++-------- 1 file changed, 6608 insertions(+), 2151 deletions(-) diff --git a/src/Prowlarr.Api.V1/swagger.json b/src/Prowlarr.Api.V1/swagger.json index a121bddfa..d739dd2cf 100644 --- a/src/Prowlarr.Api.V1/swagger.json +++ b/src/Prowlarr.Api.V1/swagger.json @@ -1,2443 +1,6900 @@ { - "openapi": "3.0.0", + "openapi": "3.0.1", "info": { "title": "Prowlarr", - "version": "3.0.0", - "description": "The way users should interact with Prowlarr programatically. To utilize any of these endpoints you will need a few pieces of information:\n\nex: localhost:9696/api/v1/movies?apiKey={key_here}\n\n* url: localhost, 10.1.0.1, 192.168.1.1, etc\n* port: 9696 (unless you modify it)\n* apiKey: Located in Settings > General > Security" + "version": "1.0.0" }, - "servers": [ - { - "url": "{protocol}://{hostPath}/api/v1", - "variables": { - "protocol": { - "enum": [ - "https", - "http" - ], - "default": "https" - }, - "hostPath": { - "default": "localhost:9696", - "description": "Your Prowlarr Server URL" - } - } - } - ], "paths": { - "/movie": { + "/api/v1/applications/{id}": { "get": { "tags": [ - "Movie" + "Application" ], - "summary": "Get all movies", - "description": "Returns all movies stored in the database", - "operationId": "getMovie", - "parameters": [ - { - "in": "query", - "name": "tmdbId", - "schema": { - "type": "integer" - }, - "required": false, - "description": "TMDb id of the movie to get" - } - ], - "responses": { - "200": { - "description": "Successful request", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Movie" - } - } - } - } - }, - "400": { - "description": "Invalid ID supplied" - }, - "401": { - "description": "Invalid API Key" - }, - "404": { - "description": "Movie not found" - } - }, - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ] - }, - "post": { - "tags": [ - "Movie" - ], - "summary": "Add new movie", - "requestBody": { - "description": "Movie object that needs to be added", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Movie" - } - } - } - }, - "responses": { - "200": { - "description": "Successful request", - "content": { - "application/json": { - "schema": { - "type": "integer" - } - } - } - }, - "401": { - "description": "Invalid API Key" - }, - "405": { - "description": "Validation exception" - } - }, - "security": [ - { - "X-API-Key": [] - } - ], - "description": "Adds a movie to the database" - }, - "put": { - "tags": [ - "Movie" - ], - "summary": "Edit existing movie", - "requestBody": { - "description": "Movie object that needs to be edited", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Movie" - } - } - } - }, - "parameters": [ - { - "in": "query", - "name": "movieFiles", - "schema": { - "type": "boolean" - }, - "required": false, - "description": "Have prowlarr move files when updating" - } - ], - "responses": { - "200": { - "description": "successful operation", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Movie" - } - } - } - }, - "404": { - "description": "Movie not found" - }, - "405": { - "description": "Validation exception" - } - }, - "security": [ - { - "X-API-Key": [] - } - ], - "description": "Updates a movie in the database" - } - }, - "/movie/{id}": { - "get": { - "tags": [ - "Movie" - ], - "summary": "Get movie by database id", - "description": "Returns a single movie", - "operationId": "getMovieById", "parameters": [ { "name": "id", "in": "path", - "description": "Database Id of movie to return", "required": true, "schema": { - "type": "integer" + "type": "integer", + "format": "int32" } } ], "responses": { "200": { - "description": "Successful request", + "description": "Success", "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, "application/json": { "schema": { - "$ref": "#/components/schemas/Movie" + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" } } } - }, - "400": { - "description": "Invalid ID supplied" - }, - "401": { - "description": "Invalid API Key" - }, - "404": { - "description": "Movie not found" } - }, - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ] + } }, - "delete": { + "put": { "tags": [ - "Movie" + "Application" ], - "summary": "Delete movie", - "description": "", - "operationId": "deleteMovie", "parameters": [ { "name": "id", "in": "path", - "description": "Database Id of movie to delete", "required": true, "schema": { - "type": "integer" - } - }, - { - "name": "addImportExclusion", - "in": "query", - "description": "Add deleted movies to List Exclusions", - "schema": { - "type": "boolean" - } - }, - { - "name": "deleteFiles", - "in": "query", - "description": "Delete movie files when deleting movies", - "schema": { - "type": "boolean" + "type": "string" } } ], - "responses": { - "400": { - "description": "Invalid ID supplied" - }, - "401": { - "description": "Invalid API Key" - }, - "404": { - "description": "Movie not found" + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } } }, - "security": [ - { - "X-API-Key": [] - } - ] - } - }, - "/tag/detail/{id}": { - "get": { - "tags": [ - "Tag" - ], - "summary": "Return usage details for a given tag id", - "description": "Returns the id of all items in the database which use the specified tag", - "operationId": "", "responses": { "200": { - "description": "Successful request", + "description": "Success", "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, "application/json": { "schema": { - "$ref": "#/components/schemas/TagDetail" + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" } } } - }, - "401": { - "description": "Invalid API Key" - } - }, - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ] - }, - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Database id of tag", - "required": true, - "schema": { - "type": "integer" } } - ] - }, - "/tag/detail": { - "get": { - "tags": [ - "Tag" - ], - "summary": "Return usage details for all tags in database", - "description": "Returns a list of tag detail objects for all tags in the database.", - "operationId": "", - "responses": { - "200": { - "description": "Successful request", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TagDetail" - } - } - } - } - }, - "401": { - "description": "Invalid API Key" - } - }, - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ] - }, - "parameters": [] - }, - "/tag/{id}": { - "get": { - "tags": [ - "Tag" - ], - "summary": "Get tag by database id", - "description": "Return a given tag and its label by the database id.", - "operationId": "", - "responses": { - "200": { - "description": "Successful request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Tag" - } - } - } - }, - "401": { - "description": "Invalid API Key" - } - }, - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ] }, "delete": { "tags": [ - "Tag" + "Application" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } ], - "summary": "Delete tag by database id", - "description": "Delete a tag", - "operationId": "", "responses": { "200": { - "description": "Successful request" - }, - "401": { - "description": "Invalid API Key" - } - }, - "security": [ - { - "X-API-Key": [] - } - ] - }, - "parameters": [ - { - "name": "id", - "in": "path", - "description": "ID of tag", - "required": true, - "schema": { - "type": "integer" + "description": "Success" } } - ] + } }, - "/tag": { + "/api/v1/applications": { "get": { "tags": [ - "Tag" + "Application" ], - "summary": "Get all tags", - "description": "Get all tags in the database", - "operationId": "", "responses": { "200": { - "description": "Successful request", + "description": "Success", "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + }, "application/json": { "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/Tag" + "$ref": "#/components/schemas/ApplicationResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationResource" } } } } - }, - "401": { - "description": "Invalid API Key" } - }, - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ] - }, - "put": { - "tags": [ - "Tag" - ], - "summary": "Update tag", - "description": "Update a tags label.", - "operationId": "", - "requestBody": { - "description": "Tag object that needs to be updated", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Tag" - } - } - } - }, - "responses": { - "200": { - "description": "Successful request" - }, - "401": { - "description": "Invalid API Key" - } - }, - "security": [ - { - "X-API-Key": [] - } - ] + } }, "post": { "tags": [ - "Tag" + "Application" ], - "summary": "Create a new tag", - "description": "Create a new tag that can be assigned to a movie, list, delay profile, notification, or restriction", - "operationId": "", "requestBody": { - "description": "Tag object that needs to be added", - "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Tag" + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" } } } }, "responses": { "200": { - "description": "Successful request" - }, - "401": { - "description": "Invalid API Key" + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + } + } + } + }, + "/api/v1/applications/schema": { + "get": { + "tags": [ + "Application" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + } + } + } + } + }, + "/api/v1/applications/test": { + "post": { + "tags": [ + "Application" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } } }, - "security": [ - { - "X-API-Key": [] + "responses": { + "200": { + "description": "Success" } - ] + } + } + }, + "/api/v1/applications/testall": { + "post": { + "tags": [ + "Application" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/applications/action/{name}": { + "post": { + "tags": [ + "Application" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/appprofile": { + "post": { + "tags": [ + "AppProfile" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + } + } }, - "parameters": [] - }, - "/diskspace": { "get": { - "summary": "Get system diskspace information", "tags": [ - "Disk Space" + "AppProfile" ], "responses": { "200": { - "description": "Successful request", + "description": "Success", "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + }, "application/json": { "schema": { - "type": "object", - "properties": { - "path": { - "type": "string" - }, - "label": { - "type": "string" - }, - "freeSpace": { - "type": "number", - "description": "bytes" - }, - "totalSpace": { - "type": "number", - "description": "bytes" - } + "type": "array", + "items": { + "$ref": "#/components/schemas/AppProfileResource" } - }, - "examples": { - "Response": { - "value": [ - { - "path": "D:\\", - "label": "DrivePool", - "freeSpace": 16187217043456, - "totalSpace": 56009755148288 - }, - { - "path": "C:\\", - "label": "Windows", - "freeSpace": 78659211264, - "totalSpace": 239409819648 - } - ] + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AppProfileResource" } } } } - }, - "401": { - "description": "Invalid API Key" } - }, - "operationId": "get-diskspace", - "description": "Query Prowlarr for disk usage information\n\nLocation: System > Status", - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ] + } } }, - "/status": { - "get": { - "summary": "Get internal information", + "/api/v1/appprofile/{id}": { + "delete": { "tags": [ - "Status" + "AppProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } ], "responses": { "200": { - "description": "Successful request", + "description": "Success" + } + } + }, + "put": { + "tags": [ + "AppProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, "application/json": { "schema": { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "buildTime": { - "type": "string" - }, - "isDebug": { - "type": "boolean" - }, - "isProduction": { - "type": "boolean" - }, - "isAdmin": { - "type": "boolean" - }, - "isUserInteractive": { - "type": "boolean" - }, - "startupPath": { - "type": "string" - }, - "appData": { - "type": "string" - }, - "osName": { - "type": "string" - }, - "osVersion": { - "type": "string" - }, - "isNetCore": { - "type": "boolean" - }, - "isMono": { - "type": "boolean" - }, - "isLinux": { - "type": "boolean" - }, - "isOsx": { - "type": "boolean" - }, - "isWindows": { - "type": "boolean" - }, - "isDocker": { - "type": "boolean" - }, - "mode": { - "type": "string" - }, - "branch": { - "type": "string" - }, - "authentication": { - "type": "string" - }, - "sqliteVersion": { - "type": "string" - }, - "migrationVersion": { - "type": "integer" - }, - "urlBase": { - "type": "string" - }, - "runtimeVersion": { - "type": "string" - }, - "runtimeName": { - "type": "string" - }, - "startTime": { - "type": "string" - }, - "packageUpdateMechanism": { - "type": "string" - } + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "AppProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + } + } + } + }, + "/login": { + "post": { + "tags": [ + "Authentication" + ], + "parameters": [ + { + "name": "returnUrl", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "Username": { + "type": "string" + }, + "Password": { + "type": "string" + }, + "RememberMe": { + "type": "string" } + } + }, + "encoding": { + "Username": { + "style": "form" }, - "examples": { - "Response": { - "value": { - "version": "10.0.0.34882", - "buildTime": "2020-09-01T23:23:23.9621974Z", - "isDebug": true, - "isProduction": false, - "isAdmin": false, - "isUserInteractive": true, - "startupPath": "C:\\ProgramData\\Prowlarr", - "appData": "C:\\ProgramData\\Prowlarr", - "osName": "Windows", - "osVersion": "10.0.18363.0", - "isNetCore": true, - "isMono": false, - "isLinux": false, - "isOsx": false, - "isWindows": true, - "isDocker": false, - "mode": "console", - "branch": "nightly", - "authentication": "none", - "sqliteVersion": "3.32.1", - "migrationVersion": 180, - "urlBase": "", - "runtimeVersion": "5.0.0", - "runtimeName": "netCore", - "startTime": "2020-09-01T23:50:20.2415965Z", - "packageUpdateMechanism": "builtIn" - } + "Password": { + "style": "form" + }, + "RememberMe": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + }, + "get": { + "tags": [ + "StaticResource" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/logout": { + "get": { + "tags": [ + "Authentication" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/system/backup": { + "get": { + "tags": [ + "Backup" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackupResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackupResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackupResource" } } } } - }, - "401": { - "description": "Invalid API Key" } - }, - "operationId": "get-status", - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ], - "description": "Find out information such as OS, version, paths used, etc", - "parameters": [] + } } }, - "/health": { + "/api/v1/system/backup/{id}": { + "delete": { + "tags": [ + "Backup" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/system/backup/restore/{id}": { + "post": { + "tags": [ + "Backup" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/system/backup/restore/upload": { + "post": { + "tags": [ + "Backup" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/command/{id}": { + "get": { + "tags": [ + "Command" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Command" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/command": { + "post": { + "tags": [ + "Command" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "Command" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommandResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommandResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommandResource" + } + } + } + } + } + } + } + }, + "/api/v1/customfilter/{id}": { + "get": { + "tags": [ + "CustomFilter" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "CustomFilter" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "CustomFilter" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/customfilter": { + "get": { + "tags": [ + "CustomFilter" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "CustomFilter" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + } + } + } + }, + "/api/v1/config/development/{id}": { + "put": { + "tags": [ + "DevelopmentConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "DevelopmentConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/development": { + "get": { + "tags": [ + "DevelopmentConfig" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + } + } + } + } + } + }, + "/api/v1/downloadclient/{id}": { + "get": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/downloadclient": { + "get": { + "tags": [ + "DownloadClient" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "DownloadClient" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + } + }, + "/api/v1/downloadclient/schema": { + "get": { + "tags": [ + "DownloadClient" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + } + } + }, + "/api/v1/downloadclient/test": { + "post": { + "tags": [ + "DownloadClient" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/downloadclient/testall": { + "post": { + "tags": [ + "DownloadClient" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/downloadclient/action/{name}": { + "post": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/config/downloadclient/{id}": { + "get": { + "tags": [ + "DownloadClientConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "DownloadClientConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/downloadclient": { + "get": { + "tags": [ + "DownloadClientConfig" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + } + } + } + } + } + }, + "/api/v1/filesystem": { + "get": { + "tags": [ + "FileSystem" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "includeFiles", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "allowFoldersWithoutTrailingSlashes", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/filesystem/type": { + "get": { + "tags": [ + "FileSystem" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/health/{id}": { + "get": { + "tags": [ + "Health" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/HealthResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/HealthResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HealthResource" + } + } + } + } + } + } + }, + "/api/v1/health": { "get": { - "summary": "Get Prowlarr's health information", "tags": [ "Health" ], "responses": { "200": { - "description": "Successful request", + "description": "Success", "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HealthResource" + } + } + }, "application/json": { "schema": { - "type": "object", - "properties": { - "source": { - "type": "string" - }, - "type": { - "type": "string" - }, - "message": { - "type": "string" - }, - "wikiUrl": { - "type": "string" - } + "type": "array", + "items": { + "$ref": "#/components/schemas/HealthResource" } - }, - "examples": { - "Response": { - "value": [ - { - "source": "ImportMechanismCheck", - "type": "warning", - "message": "Enable Completed Download Handling", - "wikiUrl": "https://wiki.servarr.com/prowlarr/system#completed.2FFailed_Download_Handling" - }, - { - "source": "DownloadClientCheck", - "type": "error", - "message": "Unable to communicate with qBittorrent. Failed to connect to qBittorrent, check your settings.", - "wikiUrl": "https://wiki.servarr.com/prowlarr/system#download-clients" - } - ] + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HealthResource" } } } } - }, - "401": { - "description": "Invalid API Key" } - }, - "operationId": "get-health", - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ], - "description": "Query prowlarr for health information\n\nLocation: System > Status" + } } }, - "/command": { - "post": { - "summary": "command", - "tags": [ - "Command" - ], - "operationId": "post-command", - "responses": { - "200": { - "description": "Successful request" - }, - "201": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "examples": { - "Example": { - "value": { - "name": "Backup" - } - } - } - } - } - }, - "401": { - "description": "Invalid API Key" - } - }, - "description": "Pushes commands to Prowlarr using a key:value pair. The main key is \"name\" and below are acceptable values but it can also accept other key:value pairs (listed under each command):\n\n* ApplicationUpdate - Trigger an update of Prowlarr\n* Backup - Trigger a backup routine\n* CheckHealth - Trigger a system health check\n* ClearBlocklist - Triggers the removal of all blocklisted movies\n* CleanUpRecycleBin - Trigger a recycle bin cleanup check\n* DeleteLogFiles - Triggers the removal of all Info/Debug/Trace log files\n* DeleteUpdateLogFiles - Triggers the removal of all Update log files\n* DownloadedMoviesScan - Triggers the scan of downloaded movies\n* MissingMoviesSearch - Triggers a search of all missing movies\n* RefreshMonitoredDownloads - Triggers the scan of monitored downloads\n* RefreshMovie - Trigger a refresh / scan of library\n * movieIds:int[] - Specify a list of ids (comma separated) for individual movies to refresh", - "security": [ - { - "X-API-Key": [] - } - ], - "parameters": [] - } - }, - "/update": { + "/api/v1/history": { "get": { - "summary": "List of recent updates", - "tags": [ - "Update" - ], - "responses": { - "200": { - "description": "Successful request", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "branch": { - "type": "string" - }, - "releaseDate": { - "type": "string" - }, - "fileName": { - "type": "string" - }, - "url": { - "type": "string" - }, - "installed": { - "type": "boolean" - }, - "installable": { - "type": "boolean" - }, - "latest": { - "type": "boolean" - }, - "changes": { - "type": "array", - "items": { - "type": "object", - "properties": { - "new": { - "type": "object" - }, - "fixed": { - "type": "object" - } - } - } - }, - "hash": { - "type": "string" - } - } - }, - "examples": { - "Example": { - "value": { - "version": "3.0.0.3553", - "branch": "nightly", - "releaseDate": "2020-09-02T05:36:13.047313Z", - "fileName": "Prowlarr.nightly.3.0.0.3553.windows-core-x64.zip", - "url": "https://dev.azure.com/Prowlarr/Prowlarr/_apis/build/builds/1896/artifacts?artifactName=Packages&fileId=A710686A9CB6848E73C3DDCA5F2B0D83C6189546E66DD3EF2D0D30B20735F6E802&fileName=Prowlarr.aphrodite.3.0.0.3553.windows-core-x64.zip&api-version=5.1", - "installed": false, - "installable": false, - "latest": false, - "changes": { - "new": [], - "fixed": [ - "Importing completed downloads from NZBGet with post processing script failing", - "Importing of completed download when not a child of the download client output path", - "Getting parent of UNC paths" - ] - }, - "hash": "a95c855cbc3ee253fd0b74181e866106daffc7b71b4a9e2d57cfbeede4333aee" - } - } - } - } - } - }, - "401": { - "description": "Invalid API Key" - } - }, - "operationId": "get-update", - "description": "Will return a list of recent updates to Prowlarr\n\nLocation: System > Updates", - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ] - } - }, - "/qualityProfile": { - "get": { - "summary": "Get Prowlarr's quality profiles", - "tags": [ - "Quality" - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "upgradeAllowed": { - "type": "boolean" - }, - "cutoff": { - "type": "integer" - }, - "preferredTags": { - "type": "string" - }, - "items": { - "type": "object", - "properties": { - "quality": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "source": { - "type": "string" - }, - "resolution": { - "type": "integer" - }, - "modifier": { - "type": "string" - } - } - }, - "items": { - "type": "object" - }, - "allowed": { - "type": "boolean" - } - } - }, - "id": { - "type": "integer" - }, - "minFormatScore": { - "type": "integer" - }, - "cutoffFormatScore": { - "type": "integer" - }, - "formatItems": { - "type": "object", - "properties": { - "format": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "score": { - "type": "integer" - } - } - }, - "language": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - } - } - } - } - } - }, - "examples": { - "Example": { - "value": [ - { - "name": "Any", - "upgradeAllowed": true, - "cutoff": 20, - "preferredTags": "freeleech", - "items": [ - { - "quality": { - "id": 0, - "name": "Unknown", - "source": "unknown", - "resolution": 0, - "modifier": "none" - }, - "items": [], - "allowed": true - } - ] - } - ] - } - } - } - } - }, - "401": { - "description": "Invalid API Key" - } - }, - "operationId": "get-add-discover", - "description": "Query Prowlarr for quality profiles ", - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ] - }, - "parameters": [] - }, - "/calendar": { - "get": { - "summary": "Get Prowlarr's calendar events", - "tags": [ - "Calendar" - ], - "responses": { - "200": { - "description": "Successful request" - }, - "401": { - "description": "Invalid API Key" - } - }, - "operationId": "get-calendar", - "description": "Get a list of movies based on calendar parameters", - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ], - "parameters": [ - { - "schema": { - "type": "boolean" - }, - "in": "query", - "name": "unmonitored", - "required": true - }, - { - "schema": { - "type": "string" - }, - "in": "query", - "name": "start", - "description": "ISO 8601", - "required": true - }, - { - "schema": { - "type": "string" - }, - "in": "query", - "name": "end", - "description": "ISO 8601", - "required": true - } - ] - } - }, - "/queue": { - "get": { - "summary": "Get Prowlarr's queue items", - "tags": [ - "Queue" - ], - "responses": { - "200": { - "description": "Successful request" - }, - "401": { - "description": "Invalid API Key" - } - }, - "operationId": "get-queue", - "description": "Return a json object list of items in the queue", - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ], - "parameters": [ - { - "schema": { - "type": "integer" - }, - "in": "query", - "name": "page", - "description": "1", - "required": true - }, - { - "schema": { - "type": "integer" - }, - "in": "query", - "name": "pageSize", - "description": "20", - "required": true - }, - { - "schema": { - "type": "string" - }, - "in": "query", - "name": "sortDirection", - "description": "ascending", - "required": true - }, - { - "schema": { - "type": "string" - }, - "in": "query", - "name": "sortKey", - "description": "timeLeft", - "required": true - }, - { - "schema": { - "type": "boolean" - }, - "in": "query", - "name": "includeUnknownMovieItems", - "description": "true", - "required": true - } - ] - } - }, - "/history": { - "get": { - "summary": "Get Prowlarr's history items", "tags": [ "History" ], "responses": { "200": { - "description": "Successful request", + "description": "Success", "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/HistoryResourcePagingResource" + } + }, "application/json": { "schema": { - "type": "object", - "properties": { - "page": { - "type": "integer" - }, - "pageSize": { - "type": "integer" - }, - "sortDirection": { - "type": "string" - }, - "totalRecords": { - "type": "integer" - }, - "records": { - "type": "array", - "items": { - "type": "object", - "properties": { - "movieId": { - "type": "integer" - }, - "sourceTitle": { - "type": "string" - }, - "languages": { - "type": [ - "string", - "array" - ], - "items": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - } - } - } - }, - "quality": { - "type": "array", - "items": { - "type": "object", - "properties": { - "quality": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "source": { - "type": "string" - }, - "resolution": { - "type": "integer" - }, - "modifier": { - "type": "string" - } - } - } - }, - "revision": { - "type": "array", - "items": { - "type": "object", - "properties": { - "version": { - "type": "integer" - }, - "real": { - "type": "integer" - }, - "isRepack": { - "type": "boolean" - } - } - } - } - } - } - }, - "customFormats": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "includeCustomFormatWhenRenaming": { - "type": "boolean" - }, - "specifications": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "implementation": { - "type": "string" - }, - "implementationName": { - "type": "string" - }, - "infoLink": { - "type": "string" - }, - "negate": { - "type": "boolean" - }, - "required": { - "type": "boolean" - }, - "fields": { - "type": "array", - "items": { - "type": "object", - "properties": { - "order": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "label": { - "type": "string" - }, - "value": { - "type": "integer" - }, - "type": { - "type": "string" - }, - "advanced": { - "type": "boolean" - }, - "selectOptions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "value": { - "type": "integer" - }, - "name": { - "type": "string" - } - } - } - } - } - } - } - } - } - } - } - } - }, - "qualityCutoffNotMet": { - "type": "boolean" - }, - "date": { - "type": "string", - "description": "ISO 8601" - }, - "eventType": { - "type": "string" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "properties": { - "reason": { - "type": "string" - } - } - } - }, - "id": { - "type": "integer" - } - } - } - } - } - }, - "examples": { - "Example": { - "value": { - "page": 1, - "pageSize": 20, - "sortKey": "date", - "sortDirection": "descending", - "totalRecords": 1998, - "records": [ - { - "movieId": 884, - "sourceTitle": "D:\\Plex\\Movies\\Dolittle (2019)\\Dolittle (2019) WEBDL-1080p.mkv", - "languages": [ - { - "id": 1, - "name": "English" - } - ], - "quality": { - "quality": { - "id": 3, - "name": "WEBDL-1080p", - "source": "webdl", - "resolution": 1080, - "modifier": "none" - }, - "revision": { - "version": 1, - "real": 0, - "isRepack": false - } - }, - "customFormats": [ - { - "id": 1, - "name": "WebDL", - "includeCustomFormatWhenRenaming": false, - "specifications": [ - { - "name": "WebDL", - "implementation": "SourceSpecification", - "implementationName": "Source", - "infoLink": "https://github.com/Prowlarr/Prowlarr/wiki/Custom-Formats-Aphrodite", - "negate": false, - "required": false, - "fields": [ - { - "order": 0, - "name": "value", - "label": "Source", - "value": 7, - "type": "select", - "advanced": false, - "selectOptions": [ - { - "value": 0, - "name": "UNKNOWN" - }, - { - "value": 1, - "name": "CAM" - }, - { - "value": 2, - "name": "TELESYNC" - }, - { - "value": 3, - "name": "TELECINE" - }, - { - "value": 4, - "name": "WORKPRINT" - }, - { - "value": 5, - "name": "DVD" - }, - { - "value": 6, - "name": "TV" - }, - { - "value": 7, - "name": "WEBDL" - }, - { - "value": 8, - "name": "WEBRIP" - }, - { - "value": 9, - "name": "BLURAY" - } - ] - } - ] - } - ] - }, - { - "id": 2, - "name": "1080", - "includeCustomFormatWhenRenaming": false, - "specifications": [ - { - "name": "1080", - "implementation": "ResolutionSpecification", - "implementationName": "Resolution", - "infoLink": "https://github.com/Prowlarr/Prowlarr/wiki/Custom-Formats-Aphrodite", - "negate": false, - "required": false, - "fields": [ - { - "order": 0, - "name": "value", - "label": "Resolution", - "value": 1080, - "type": "select", - "advanced": false, - "selectOptions": [ - { - "value": 0, - "name": "Unknown" - }, - { - "value": 360, - "name": "R360p" - }, - { - "value": 480, - "name": "R480p" - }, - { - "value": 576, - "name": "R576p" - }, - { - "value": 720, - "name": "R720p" - }, - { - "value": 1080, - "name": "R1080p" - }, - { - "value": 2160, - "name": "R2160p" - } - ] - } - ] - } - ] - } - ], - "qualityCutoffNotMet": true, - "date": "2020-08-30T00:09:52.3299253Z", - "eventType": "movieFileDeleted", - "data": { - "reason": "MissingFromDisk" - }, - "id": 2107 - } - ] - } - } + "$ref": "#/components/schemas/HistoryResourcePagingResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HistoryResourcePagingResource" } } } - }, - "401": { - "description": "Invalid API Key" - } - }, - "operationId": "get-history", - "description": "Return a json object list of items in your history", - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] } + } + } + }, + "/api/v1/history/since": { + "get": { + "tags": [ + "History" ], "parameters": [ { - "schema": { - "type": "integer" - }, + "name": "date", "in": "query", - "name": "page", - "description": "1", - "required": true - }, - { "schema": { - "type": "integer" - }, - "in": "query", - "name": "pageSize", - "description": "20", - "required": true + "type": "string", + "format": "date-time" + } }, { + "name": "eventType", + "in": "query", "schema": { - "type": "string" - }, - "in": "query", - "name": "sortDirection", - "description": "descending", - "required": true - }, - { - "schema": { - "type": "string" - }, - "in": "query", - "name": "sortKey", - "description": "date", - "required": true + "$ref": "#/components/schemas/HistoryEventType" + } } - ] - } - }, - "/customFilter": { - "get": { - "summary": "Get Prowlarr's custom filters", - "tags": [ - "Custom Filters" ], "responses": { "200": { - "description": "Successful response", + "description": "Success", "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + }, "application/json": { "schema": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "label": { - "type": "string" - }, - "Prowlarr's ": { - "type": "object", - "properties": { - "key": { - "type": "string" - }, - "value": { - "type": "array", - "items": { - "type": "object", - "properties": { - "time": { - "type": "string" - }, - "value": { - "type": "integer" - } - } - } - }, - "type": { - "type": "string" - } - } - }, - "id": { - "type": "integer" - } + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" } - }, - "examples": { - "Example": { - "value": [ - { - "type": "movieIndex", - "label": "not in last", - "filters": [ - { - "key": "inCinemas", - "value": { - "time": "months", - "value": 12 - }, - "type": "notInLast" - } - ], - "id": 2 - } - ] + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" } } } } - }, - "401": { - "description": "Invalid API Key" } - }, - "operationId": "get-customFilter", - "description": "Query Prowlarr for custom filters", - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ] + } } }, - "/importList": { + "/api/v1/history/indexer": { "get": { - "summary": "Get import list information", "tags": [ - "Import" - ], - "responses": { - "200": { - "description": "Succesful response ", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean" - }, - "enableAuto": { - "type": "boolean" - }, - "shouldMonitor": { - "type": "boolean" - }, - "rootFolderPath": { - "type": "string" - }, - "qualityProfile": { - "type": "integer" - }, - "searchOnAdd": { - "type": "boolean" - }, - "minimumAvailability": { - "type": "string" - }, - "listType": { - "type": "string" - }, - "listOrder": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "fields": { - "type": "object", - "properties": { - "order": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "label": { - "type": "string" - }, - "helpText": { - "type": "string" - }, - "value": { - "type": "string" - }, - "type": { - "type": "string" - }, - "advanced": { - "type": "boolean" - } - } - }, - "implementationName": { - "type": "string" - }, - "implementation": { - "type": "string" - }, - "configContract": { - "type": "string" - }, - "infoLink": { - "type": "string" - }, - "tags": { - "type": "object" - }, - "id": { - "type": "integer" - } - } - }, - "examples": { - "Example": { - "value": [ - { - "enabled": true, - "enableAuto": true, - "shouldMonitor": true, - "rootFolderPath": "D:\\Plex\\Movies\\", - "qualityProfileId": 4, - "searchOnAdd": false, - "minimumAvailability": "announced", - "listType": "other", - "listOrder": 3, - "name": "IMDb List", - "fields": [ - { - "order": 0, - "name": "listId", - "label": "List/User ID", - "helpText": "IMDb list ID (e.g ls12345678), IMDb user ID (e.g. ur12345678), 'top250' or 'popular'", - "value": "ur109135197", - "type": "textbox", - "advanced": false - } - ], - "implementationName": "IMDb Lists", - "implementation": "IMDbListImport", - "configContract": "IMDbListSettings", - "infoLink": "https://github.com/Prowlarr/Prowlarr/wiki/Supported-ImportLists#imdblistimport", - "tags": [ - 2 - ], - "id": 1 - } - ] - } - } - } - } - }, - "401": { - "description": "Invalid API Key" - } - }, - "operationId": "get-importList", - "description": "Query Prowlarr for all lists", - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ] - } - }, - "/ui": { - "get": { - "summary": "Get UI settings", - "tags": [ - "UI" - ], - "responses": { - "200": { - "description": "Successful request", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "firstDayOfWeek": { - "type": "integer" - }, - "calendarWeekColumnHeader": { - "type": "string" - }, - "shortDateFormat": { - "type": "string" - }, - "longDateFormat": { - "type": "string" - }, - "timeFormat": { - "type": "string" - }, - "showRelativeDates": { - "type": "boolean" - }, - "enableColorImpairedMode": { - "type": "boolean" - }, - "movieInfoLanguage": { - "type": "integer" - }, - "id": { - "type": "integer" - } - } - }, - "examples": { - "Example": { - "value": { - "firstDayOfWeek": 0, - "calendarWeekColumnHeader": "ddd M/D", - "shortDateFormat": "MMM D YYYY", - "longDateFormat": "dddd, MMMM D YYYY", - "timeFormat": "h(:mm)a", - "showRelativeDates": true, - "enableColorImpairedMode": false, - "movieInfoLanguage": 1, - "id": 1 - } - } - } - } - } - }, - "401": { - "description": "Invalid API Key" - } - }, - "operationId": "get-ui", - "description": "Query Prowlarr for UI settings", - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ] - } - }, - "/remotePathMapping": { - "get": { - "summary": "Get Prowlarr's remote path mappings", - "tags": [ - "Remote Path Mapping" - ], - "responses": { - "200": { - "description": "Successful request", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "host": { - "type": "string" - }, - "remotePath": { - "type": "string" - }, - "localPath": { - "type": "string" - }, - "id": { - "type": "integer" - } - } - }, - "examples": { - "Example": { - "value": [ - { - "host": "localhost", - "remotePath": "B:\\", - "localPath": "A:\\Movies\\", - "id": 1 - }, - { - "host": "localhost", - "remotePath": "C:\\", - "localPath": "A:\\Movies\\", - "id": 2 - } - ] - } - } - } - } - }, - "401": { - "description": "Invalid API Key" - } - }, - "operationId": "get-remotePathMapping", - "description": "Get a list of remote paths being mapped and used by Prowlarr", - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ] - } - }, - "/downloadClient": { - "get": { - "summary": "Get Prowlarr's download client list", - "tags": [ - "Download Client" - ], - "responses": { - "200": { - "description": "Successful request" - }, - "401": { - "description": "Invalid API Key" - } - }, - "operationId": "get-downloadClient", - "description": "Get a list of all the download clients added in Prowlarr", - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } - ] - } - }, - "/blockList": { - "get": { - "summary": "Get Prowlarr's blocklisted movies", - "tags": [ - "Blocklist" - ], - "responses": { - "200": { - "description": "Invalid API Key", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "page": { - "type": "integer", - "description": "1" - }, - "pageSize": { - "type": "integer", - "description": "20" - }, - "sortDirection": { - "type": "string", - "description": "descending" - }, - "sortKey": { - "type": "string", - "description": "date" - }, - "totalRecords": { - "type": "integer" - }, - "records": { - "type": "array", - "items": { - "type": "object" - } - } - }, - "required": [ - "page", - "pageSize", - "sortDirection", - "sortKey" - ] - } - } - } - }, - "401": { - "description": "Invalid API Key" - } - }, - "operationId": "get-blockList", - "description": "", - "security": [ - { - "X-API-Key": [] - }, - { - "api key": [] - } + "History" ], "parameters": [ { - "schema": { - "type": "integer" - }, + "name": "indexerId", "in": "query", - "name": "page", - "description": "1", - "required": true + "schema": { + "type": "integer", + "format": "int32" + } }, { - "schema": { - "type": "integer" - }, + "name": "eventType", "in": "query", - "name": "pageSize", - "description": "20", - "required": true - }, - { "schema": { - "type": "string" - }, - "in": "query", - "name": "sortDirection", - "description": "descending", - "required": true - }, - { - "schema": { - "type": "string" - }, - "in": "query", - "name": "sortKey", - "description": "date", - "required": true + "$ref": "#/components/schemas/HistoryEventType" + } } - ] + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + } + } + } + } + } + }, + "/api/v1/config/host/{id}": { + "get": { + "tags": [ + "HostConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "HostConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/host": { + "get": { + "tags": [ + "HostConfig" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + } + } + } + } + } + }, + "/api/v1/indexer/{id}": { + "get": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } }, "delete": { - "summary": "Remove a blocklisted movie", - "operationId": "delete-blockList", - "responses": { - "200": { - "description": "Successful request" - }, - "401": { - "description": "Invalid API Key" - } - }, - "description": "Removes a specific movie (the id provided) from the blocklist", - "security": [ - { - "X-API-Key": [] - } + "tags": [ + "Indexer" ], "parameters": [ { - "schema": { - "type": "integer" - }, - "in": "query", "name": "id", - "required": true + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } } - ] + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexer": { + "get": { + "tags": [ + "Indexer" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + } }, - "parameters": [] + "post": { + "tags": [ + "Indexer" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + } + }, + "/api/v1/indexer/schema": { + "get": { + "tags": [ + "Indexer" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + } + } + }, + "/api/v1/indexer/test": { + "post": { + "tags": [ + "Indexer" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexer/testall": { + "post": { + "tags": [ + "Indexer" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexer/action/{name}": { + "post": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/config/indexer/{id}": { + "get": { + "tags": [ + "IndexerConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "IndexerConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/indexer": { + "get": { + "tags": [ + "IndexerConfig" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerConfigResource" + } + } + } + } + } + } + }, + "/api/v1/indexer/categories": { + "get": { + "tags": [ + "IndexerDefaultCategories" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerCategory" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerCategory" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerCategory" + } + } + } + } + } + } + } + }, + "/api/v1/indexer/editor": { + "put": { + "tags": [ + "IndexerEditor" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerEditorResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerEditorResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerEditorResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "IndexerEditor" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerEditorResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerEditorResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerEditorResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexerproxy/{id}": { + "get": { + "tags": [ + "IndexerProxy" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "IndexerProxy" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "IndexerProxy" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexerproxy": { + "get": { + "tags": [ + "IndexerProxy" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "IndexerProxy" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + } + } + } + }, + "/api/v1/indexerproxy/schema": { + "get": { + "tags": [ + "IndexerProxy" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + } + } + } + } + }, + "/api/v1/indexerproxy/test": { + "post": { + "tags": [ + "IndexerProxy" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexerproxy/testall": { + "post": { + "tags": [ + "IndexerProxy" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexerproxy/action/{name}": { + "post": { + "tags": [ + "IndexerProxy" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexerstats": { + "get": { + "tags": [ + "IndexerStats" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerStatsResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerStatsResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerStatsResource" + } + } + } + } + } + } + }, + "/api/v1/indexerstatus/{id}": { + "get": { + "tags": [ + "IndexerStatus" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerStatusResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerStatusResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerStatusResource" + } + } + } + } + } + } + }, + "/api/v1/indexerstatus": { + "get": { + "tags": [ + "IndexerStatus" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerStatusResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerStatusResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerStatusResource" + } + } + } + } + } + } + } + }, + "/initialize.js": { + "get": { + "tags": [ + "InitializeJs" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/language/{id}": { + "get": { + "tags": [ + "Language" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/LanguageResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/LanguageResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/LanguageResource" + } + } + } + } + } + } + }, + "/api/v1/language": { + "get": { + "tags": [ + "Language" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LanguageResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LanguageResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LanguageResource" + } + } + } + } + } + } + } + }, + "/api/v1/localization": { + "get": { + "tags": [ + "Localization" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + }, + "application/json": { + "schema": { + "type": "string" + } + }, + "text/json": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/api/v1/log": { + "get": { + "tags": [ + "Log" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/LogResourcePagingResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/LogResourcePagingResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/LogResourcePagingResource" + } + } + } + } + } + } + }, + "/api/v1/log/file": { + "get": { + "tags": [ + "LogFile" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + } + } + } + } + } + }, + "/api/v1/log/file/{filename}": { + "get": { + "tags": [ + "LogFile" + ], + "parameters": [ + { + "name": "filename", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexer/{id}/newznab": { + "get": { + "tags": [ + "Newznab" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "t", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "q", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "cat", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "imdbid", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "tmdbid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "extended", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "offset", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "rid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tvmazeid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "traktid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tvdbid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "season", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "ep", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "album", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "artist", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "label", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "track", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "year", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "genre", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "author", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "title", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "configured", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "source", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "host", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "server", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/{id}/api": { + "get": { + "tags": [ + "Newznab" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "t", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "q", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "cat", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "imdbid", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "tmdbid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "extended", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "offset", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "rid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tvmazeid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "traktid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tvdbid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "season", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "ep", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "album", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "artist", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "label", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "track", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "year", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "genre", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "author", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "title", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "configured", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "source", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "host", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "server", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexer/{id}/download": { + "get": { + "tags": [ + "Newznab" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "link", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "file", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/{id}/download": { + "get": { + "tags": [ + "Newznab" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "link", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "file", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/notification/{id}": { + "get": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/notification": { + "get": { + "tags": [ + "Notification" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Notification" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + } + }, + "/api/v1/notification/schema": { + "get": { + "tags": [ + "Notification" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + } + } + }, + "/api/v1/notification/test": { + "post": { + "tags": [ + "Notification" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/notification/testall": { + "post": { + "tags": [ + "Notification" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/notification/action/{name}": { + "post": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/appprofile/schema": { + "get": { + "tags": [ + "QualityProfileSchema" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + } + } + } + }, + "/api/v1/search/{id}": { + "get": { + "tags": [ + "Search" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + } + } + } + } + } + }, + "/api/v1/search": { + "post": { + "tags": [ + "Search" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "Search" + ], + "parameters": [ + { + "name": "query", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "indexerIds", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "categories", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchResource" + } + } + } + } + } + } + } + }, + "/content/{path}": { + "get": { + "tags": [ + "StaticResource" + ], + "parameters": [ + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/": { + "get": { + "tags": [ + "StaticResource" + ], + "parameters": [ + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/{path}": { + "get": { + "tags": [ + "StaticResource" + ], + "parameters": [ + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/system/status": { + "get": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/system/routes": { + "get": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/system/routes/duplicate": { + "get": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/system/shutdown": { + "post": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/system/restart": { + "post": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/tag/{id}": { + "get": { + "tags": [ + "Tag" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "Tag" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Tag" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/tag": { + "get": { + "tags": [ + "Tag" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Tag" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + } + } + } + }, + "/api/v1/tag/detail/{id}": { + "get": { + "tags": [ + "TagDetails" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/TagDetailsResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDetailsResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TagDetailsResource" + } + } + } + } + } + } + }, + "/api/v1/tag/detail": { + "get": { + "tags": [ + "TagDetails" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDetailsResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDetailsResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDetailsResource" + } + } + } + } + } + } + } + }, + "/api/v1/system/task": { + "get": { + "tags": [ + "Task" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskResource" + } + } + } + } + } + } + } + }, + "/api/v1/system/task/{id}": { + "get": { + "tags": [ + "Task" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/TaskResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TaskResource" + } + } + } + } + } + } + }, + "/api/v1/config/ui/{id}": { + "get": { + "tags": [ + "UiConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "UiConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/ui": { + "get": { + "tags": [ + "UiConfig" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + } + } + } + }, + "/api/v1/update": { + "get": { + "tags": [ + "Update" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateResource" + } + } + } + } + } + } + } + }, + "/api/v1/log/file/update": { + "get": { + "tags": [ + "UpdateLogFile" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + } + } + } + } + } + }, + "/api/v1/log/file/update/{filename}": { + "get": { + "tags": [ + "UpdateLogFile" + ], + "parameters": [ + { + "name": "filename", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } } }, "components": { "schemas": { - "Movie": { + "ApplicationResource": { "type": "object", - "required": [ - "title" - ], "properties": { "id": { "type": "integer", - "format": "int64" + "format": "int32" }, - "title": { + "name": { "type": "string", - "example": "Dark Phoenix" + "nullable": true }, - "sortTitle": { - "type": "string", - "example": "dark phoenix" - }, - "sizeOnDisk": { - "type": "number" - }, - "overview": { - "type": "string" - }, - "inCinemas": { - "type": "string" - }, - "physicalRelease": { - "type": "string" - }, - "images": { + "fields": { "type": "array", "items": { - "$ref": "#/components/schemas/Image" - } + "$ref": "#/components/schemas/Field" + }, + "nullable": true }, - "website": { + "implementationName": { "type": "string", - "example": "http://darkphoenix.com" + "nullable": true }, - "year": { - "type": "integer" + "implementation": { + "type": "string", + "nullable": true }, - "hasFile": { + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationResource" + }, + "nullable": true + }, + "syncLevel": { + "$ref": "#/components/schemas/ApplicationSyncLevel" + }, + "testCommand": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "ApplicationSyncLevel": { + "enum": [ + "disabled", + "addOnly", + "fullSync" + ], + "type": "string" + }, + "ApplyTags": { + "enum": [ + "add", + "remove", + "replace" + ], + "type": "string" + }, + "AppProfileResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "enableRss": { "type": "boolean" }, - "youTubeTrailerId": { - "type": "string" + "enableInteractiveSearch": { + "type": "boolean" }, - "studio": { - "type": "string" + "enableAutomaticSearch": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "AuthenticationType": { + "enum": [ + "none", + "basic", + "forms" + ], + "type": "string" + }, + "BackupResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true }, "path": { - "type": "string" - }, - "qualityProfileId": { - "type": "integer" - }, - "monitored": { - "type": "boolean" - }, - "minimumAcailability": { "type": "string", - "enum": [ - "announced", - "inCinema", - "released" - ] + "nullable": true }, - "isAvailable": { + "type": { + "$ref": "#/components/schemas/BackupType" + }, + "time": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "BackupType": { + "enum": [ + "scheduled", + "manual", + "update" + ], + "type": "string" + }, + "CertificateValidationType": { + "enum": [ + "enabled", + "disabledForLocalAddresses", + "disabled" + ], + "type": "string" + }, + "Command": { + "type": "object", + "properties": { + "sendUpdatesToClient": { "type": "boolean" }, - "folderName": { - "type": "string" + "updateScheduledTask": { + "type": "boolean", + "readOnly": true }, - "runtime": { - "type": "integer" + "completionMessage": { + "type": "string", + "nullable": true, + "readOnly": true }, - "cleanTitle": { - "type": "string" + "requiresDiskAccess": { + "type": "boolean", + "readOnly": true }, - "imdbId": { - "type": "string" + "isExclusive": { + "type": "boolean", + "readOnly": true }, - "tmdbId": { - "type": "integer" + "isTypeExclusive": { + "type": "boolean", + "readOnly": true }, - "titleSlug": { - "type": "integer" + "name": { + "type": "string", + "nullable": true, + "readOnly": true }, - "certification": { - "type": "string" + "lastExecutionTime": { + "type": "string", + "format": "date-time", + "nullable": true }, - "genres": { + "lastStartTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "trigger": { + "$ref": "#/components/schemas/CommandTrigger" + }, + "suppressMessages": { + "type": "boolean" + }, + "clientUserAgent": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "CommandPriority": { + "enum": [ + "normal", + "high", + "low" + ], + "type": "string" + }, + "CommandResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "commandName": { + "type": "string", + "nullable": true + }, + "message": { + "type": "string", + "nullable": true + }, + "body": { + "$ref": "#/components/schemas/Command" + }, + "priority": { + "$ref": "#/components/schemas/CommandPriority" + }, + "status": { + "$ref": "#/components/schemas/CommandStatus" + }, + "queued": { + "type": "string", + "format": "date-time" + }, + "started": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "ended": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "duration": { + "$ref": "#/components/schemas/TimeSpan" + }, + "exception": { + "type": "string", + "nullable": true + }, + "trigger": { + "$ref": "#/components/schemas/CommandTrigger" + }, + "clientUserAgent": { + "type": "string", + "nullable": true + }, + "stateChangeTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "sendUpdatesToClient": { + "type": "boolean" + }, + "updateScheduledTask": { + "type": "boolean" + }, + "lastExecutionTime": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false + }, + "CommandStatus": { + "enum": [ + "queued", + "started", + "completed", + "failed", + "aborted", + "cancelled", + "orphaned" + ], + "type": "string" + }, + "CommandTrigger": { + "enum": [ + "unspecified", + "manual", + "scheduled" + ], + "type": "string" + }, + "CustomFilterResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "type": { + "type": "string", + "nullable": true + }, + "label": { + "type": "string", + "nullable": true + }, + "filters": { "type": "array", "items": { + "type": "object", + "additionalProperties": { } + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "DevelopmentConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "consoleLogLevel": { + "type": "string", + "nullable": true + }, + "logSql": { + "type": "boolean" + }, + "logIndexerResponse": { + "type": "boolean" + }, + "logRotate": { + "type": "integer", + "format": "int32" + }, + "filterSentryEvents": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "DownloadClientConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "downloadClientWorkingFolders": { + "type": "string", + "nullable": true + }, + "enableCompletedDownloadHandling": { + "type": "boolean" + }, + "removeCompletedDownloads": { + "type": "boolean" + }, + "checkForFinishedDownloadInterval": { + "type": "integer", + "format": "int32" + }, + "autoRedownloadFailed": { + "type": "boolean" + }, + "removeFailedDownloads": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "DownloadClientResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + }, + "nullable": true + }, + "enable": { + "type": "boolean" + }, + "protocol": { + "$ref": "#/components/schemas/DownloadProtocol" + }, + "priority": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "DownloadProtocol": { + "enum": [ + "unknown", + "usenet", + "torrent" + ], + "type": "string" + }, + "Field": { + "type": "object", + "properties": { + "order": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "label": { + "type": "string", + "nullable": true + }, + "unit": { + "type": "string", + "nullable": true + }, + "helpText": { + "type": "string", + "nullable": true + }, + "helpLink": { + "type": "string", + "nullable": true + }, + "value": { + "nullable": true + }, + "type": { + "type": "string", + "nullable": true + }, + "advanced": { + "type": "boolean" + }, + "selectOptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SelectOption" + }, + "nullable": true + }, + "selectOptionsProviderAction": { + "type": "string", + "nullable": true + }, + "section": { + "type": "string", + "nullable": true + }, + "hidden": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "HealthCheckResult": { + "enum": [ + "ok", + "notice", + "warning", + "error" + ], + "type": "string" + }, + "HealthResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "source": { + "type": "string", + "nullable": true + }, + "type": { + "$ref": "#/components/schemas/HealthCheckResult" + }, + "message": { + "type": "string", + "nullable": true + }, + "wikiUrl": { + "$ref": "#/components/schemas/HttpUri" + } + }, + "additionalProperties": false + }, + "HistoryEventType": { + "enum": [ + "unknown", + "releaseGrabbed", + "indexerQuery", + "indexerRss", + "indexerAuth", + "indexerInfo" + ], + "type": "string" + }, + "HistoryResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "indexerId": { + "type": "integer", + "format": "int32" + }, + "date": { + "type": "string", + "format": "date-time" + }, + "downloadId": { + "type": "string", + "nullable": true + }, + "successful": { + "type": "boolean" + }, + "eventType": { + "$ref": "#/components/schemas/HistoryEventType" + }, + "data": { + "type": "object", + "additionalProperties": { "type": "string" - } + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "HistoryResourcePagingResource": { + "type": "object", + "properties": { + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "sortKey": { + "type": "string", + "nullable": true + }, + "sortDirection": { + "$ref": "#/components/schemas/SortDirection" + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PagingResourceFilter" + }, + "nullable": true + }, + "totalRecords": { + "type": "integer", + "format": "int32" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "HostConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "bindAddress": { + "type": "string", + "nullable": true + }, + "port": { + "type": "integer", + "format": "int32" + }, + "sslPort": { + "type": "integer", + "format": "int32" + }, + "enableSsl": { + "type": "boolean" + }, + "launchBrowser": { + "type": "boolean" + }, + "authenticationMethod": { + "$ref": "#/components/schemas/AuthenticationType" + }, + "analyticsEnabled": { + "type": "boolean" + }, + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "logLevel": { + "type": "string", + "nullable": true + }, + "consoleLogLevel": { + "type": "string", + "nullable": true + }, + "branch": { + "type": "string", + "nullable": true + }, + "apiKey": { + "type": "string", + "nullable": true + }, + "sslCertPath": { + "type": "string", + "nullable": true + }, + "sslCertPassword": { + "type": "string", + "nullable": true + }, + "urlBase": { + "type": "string", + "nullable": true + }, + "updateAutomatically": { + "type": "boolean" + }, + "updateMechanism": { + "$ref": "#/components/schemas/UpdateMechanism" + }, + "updateScriptPath": { + "type": "string", + "nullable": true + }, + "proxyEnabled": { + "type": "boolean" + }, + "proxyType": { + "$ref": "#/components/schemas/ProxyType" + }, + "proxyHostname": { + "type": "string", + "nullable": true + }, + "proxyPort": { + "type": "integer", + "format": "int32" + }, + "proxyUsername": { + "type": "string", + "nullable": true + }, + "proxyPassword": { + "type": "string", + "nullable": true + }, + "proxyBypassFilter": { + "type": "string", + "nullable": true + }, + "proxyBypassLocalAddresses": { + "type": "boolean" + }, + "certificateValidation": { + "$ref": "#/components/schemas/CertificateValidationType" + }, + "backupFolder": { + "type": "string", + "nullable": true + }, + "backupInterval": { + "type": "integer", + "format": "int32" + }, + "backupRetention": { + "type": "integer", + "format": "int32" + }, + "historyCleanupDays": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "HostStatistics": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true + }, + "numberOfQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfGrabs": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "HttpUri": { + "type": "object", + "properties": { + "fullUri": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "scheme": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "host": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "port": { + "type": "integer", + "format": "int32", + "nullable": true, + "readOnly": true + }, + "path": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "query": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "fragment": { + "type": "string", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "IndexerCapabilityResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "limitsMax": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "limitsDefault": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "categories": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerCategory" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "IndexerCategory": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "description": { + "type": "string", + "nullable": true + }, + "subCategories": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerCategory" + }, + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "IndexerConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "minimumAge": { + "type": "integer", + "format": "int32" + }, + "maximumSize": { + "type": "integer", + "format": "int32" + }, + "retention": { + "type": "integer", + "format": "int32" + }, + "rssSyncInterval": { + "type": "integer", + "format": "int32" + }, + "preferIndexerFlags": { + "type": "boolean" + }, + "availabilityDelay": { + "type": "integer", + "format": "int32" + }, + "allowHardcodedSubs": { + "type": "boolean" + }, + "whitelistedHardcodedSubs": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "IndexerEditorResource": { + "type": "object", + "properties": { + "indexerIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "enable": { + "type": "string", + "nullable": true + }, + "appProfileId": { + "type": "integer", + "format": "int32", + "nullable": true }, "tags": { "type": "array", "items": { - "type": "integer" - } + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "applyTags": { + "$ref": "#/components/schemas/ApplyTags" + } + }, + "additionalProperties": false + }, + "IndexerPrivacy": { + "enum": [ + "public", + "semiPublic", + "private" + ], + "type": "string" + }, + "IndexerProxyResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + }, + "nullable": true + }, + "link": { + "type": "string", + "nullable": true + }, + "onHealthIssue": { + "type": "boolean" + }, + "supportsOnHealthIssue": { + "type": "boolean" + }, + "includeHealthWarnings": { + "type": "boolean" + }, + "testCommand": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "IndexerResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + }, + "nullable": true + }, + "indexerUrls": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "description": { + "type": "string", + "nullable": true + }, + "language": { + "type": "string", + "nullable": true + }, + "encoding": { + "type": "string", + "nullable": true + }, + "enable": { + "type": "boolean" + }, + "redirect": { + "type": "boolean" + }, + "supportsRss": { + "type": "boolean" + }, + "supportsSearch": { + "type": "boolean" + }, + "supportsRedirect": { + "type": "boolean" + }, + "appProfileId": { + "type": "integer", + "format": "int32" + }, + "protocol": { + "$ref": "#/components/schemas/DownloadProtocol" + }, + "privacy": { + "$ref": "#/components/schemas/IndexerPrivacy" + }, + "capabilities": { + "$ref": "#/components/schemas/IndexerCapabilityResource" + }, + "priority": { + "type": "integer", + "format": "int32" }, "added": { - "type": "string" - }, - "ratings": { - "$ref": "#/components/schemas/Rating" - }, - "collection": { - "$ref": "#/components/schemas/Collection" + "type": "string", + "format": "date-time" }, "status": { + "$ref": "#/components/schemas/IndexerStatusResource" + }, + "sortName": { "type": "string", - "description": "movie status", - "enum": [ - "deleted", - "tba", - "announced", - "inCinema", - "released" - ] + "nullable": true } }, - "xml": { - "name": "Movie" - } + "additionalProperties": false }, - "Image": { + "IndexerStatistics": { "type": "object", "properties": { - "coverType": { - "type": "string", - "enum": [ - "poster", - "fanart" - ] + "indexerId": { + "type": "integer", + "format": "int32" }, - "url": { - "type": "string" + "indexerName": { + "type": "string", + "nullable": true + }, + "averageResponseTime": { + "type": "integer", + "format": "int32" + }, + "numberOfQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfGrabs": { + "type": "integer", + "format": "int32" + }, + "numberOfRssQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfAuthQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfFailedQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfFailedGrabs": { + "type": "integer", + "format": "int32" + }, + "numberOfFailedRssQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfFailedAuthQueries": { + "type": "integer", + "format": "int32" } }, - "xml": { - "name": "Image" - } + "additionalProperties": false }, - "Collection": { + "IndexerStatsResource": { "type": "object", "properties": { - "name": { - "type": "string" + "id": { + "type": "integer", + "format": "int32" }, - "tmdbId": { - "type": "integer" - }, - "images": { + "indexers": { "type": "array", "items": { - "$ref": "#/components/schemas/Image" - } + "$ref": "#/components/schemas/IndexerStatistics" + }, + "nullable": true + }, + "userAgents": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserAgentStatistics" + }, + "nullable": true + }, + "hosts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HostStatistics" + }, + "nullable": true } }, - "xml": { - "name": "Collection" - } + "additionalProperties": false }, - "Rating": { + "IndexerStatusResource": { "type": "object", "properties": { - "votes": { - "type": "integer" + "id": { + "type": "integer", + "format": "int32" + }, + "indexerId": { + "type": "integer", + "format": "int32" + }, + "disabledTill": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false + }, + "LanguageResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "nameLower": { + "type": "string", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "LogFileResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "filename": { + "type": "string", + "nullable": true + }, + "lastWriteTime": { + "type": "string", + "format": "date-time" + }, + "contentsUrl": { + "type": "string", + "nullable": true + }, + "downloadUrl": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LogResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "time": { + "type": "string", + "format": "date-time" + }, + "exception": { + "type": "string", + "nullable": true + }, + "exceptionType": { + "type": "string", + "nullable": true + }, + "level": { + "type": "string", + "nullable": true + }, + "logger": { + "type": "string", + "nullable": true + }, + "message": { + "type": "string", + "nullable": true + }, + "method": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LogResourcePagingResource": { + "type": "object", + "properties": { + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "sortKey": { + "type": "string", + "nullable": true + }, + "sortDirection": { + "$ref": "#/components/schemas/SortDirection" + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PagingResourceFilter" + }, + "nullable": true + }, + "totalRecords": { + "type": "integer", + "format": "int32" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogResource" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "NotificationResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + }, + "nullable": true + }, + "link": { + "type": "string", + "nullable": true + }, + "onHealthIssue": { + "type": "boolean" + }, + "supportsOnHealthIssue": { + "type": "boolean" + }, + "includeHealthWarnings": { + "type": "boolean" + }, + "testCommand": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "PagingResourceFilter": { + "type": "object", + "properties": { + "key": { + "type": "string", + "nullable": true }, "value": { - "type": "integer" + "type": "string", + "nullable": true } }, - "xml": { - "name": "Rating" - } + "additionalProperties": false }, - "Tag": { + "ProviderMessage": { "type": "object", "properties": { - "id": { - "type": "integer" + "message": { + "type": "string", + "nullable": true }, - "label": { - "type": "string" + "type": { + "$ref": "#/components/schemas/ProviderMessageType" } - } + }, + "additionalProperties": false }, - "TagDetail": { + "ProviderMessageType": { + "enum": [ + "info", + "warning", + "error" + ], + "type": "string" + }, + "ProxyType": { + "enum": [ + "http", + "socks4", + "socks5" + ], + "type": "string" + }, + "SearchResource": { "type": "object", "properties": { "id": { - "type": "integer" + "type": "integer", + "format": "int32" }, - "label": { - "type": "string" + "guid": { + "type": "string", + "nullable": true }, - "delayProfileIds": { + "age": { + "type": "integer", + "format": "int32" + }, + "ageHours": { + "type": "number", + "format": "double" + }, + "ageMinutes": { + "type": "number", + "format": "double" + }, + "size": { + "type": "integer", + "format": "int64" + }, + "files": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "grabs": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "indexerId": { + "type": "integer", + "format": "int32" + }, + "indexer": { + "type": "string", + "nullable": true + }, + "subGroup": { + "type": "string", + "nullable": true + }, + "releaseHash": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "approved": { + "type": "boolean" + }, + "imdbId": { + "type": "integer", + "format": "int32" + }, + "publishDate": { + "type": "string", + "format": "date-time" + }, + "commentUrl": { + "type": "string", + "nullable": true + }, + "downloadUrl": { + "type": "string", + "nullable": true + }, + "infoUrl": { + "type": "string", + "nullable": true + }, + "posterUrl": { + "type": "string", + "nullable": true + }, + "indexerFlags": { "type": "array", "items": { - "type": "integer" - } + "type": "string" + }, + "nullable": true + }, + "categories": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerCategory" + }, + "nullable": true + }, + "magnetUrl": { + "type": "string", + "nullable": true + }, + "infoHash": { + "type": "string", + "nullable": true + }, + "seeders": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "leechers": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "protocol": { + "$ref": "#/components/schemas/DownloadProtocol" + } + }, + "additionalProperties": false + }, + "SelectOption": { + "type": "object", + "properties": { + "value": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "order": { + "type": "integer", + "format": "int32" + }, + "hint": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "SortDirection": { + "enum": [ + "default", + "ascending", + "descending" + ], + "type": "string" + }, + "TagDetailsResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "label": { + "type": "string", + "nullable": true }, "notificationIds": { "type": "array", "items": { - "type": "integer" - } + "type": "integer", + "format": "int32" + }, + "nullable": true }, - "restrictionIds": { + "indexerIds": { "type": "array", "items": { - "type": "integer" - } + "type": "integer", + "format": "int32" + }, + "nullable": true }, - "netImportIds": { + "indexerProxyIds": { "type": "array", "items": { - "type": "integer" - } - }, - "movieIds": { - "type": "array", - "items": { - "type": "integer" - } + "type": "integer", + "format": "int32" + }, + "nullable": true } - } - } - }, - "securitySchemes": { - "X-API-Key": { - "type": "http", - "scheme": "basic", - "description": "Used when not providing the key via URL" + }, + "additionalProperties": false }, - "api key": { - "name": "API Key", - "type": "apiKey", - "in": "query", - "description": "Used when not providing the key via header" + "TagResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "label": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "TaskResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "taskName": { + "type": "string", + "nullable": true + }, + "interval": { + "type": "integer", + "format": "int32" + }, + "lastExecution": { + "type": "string", + "format": "date-time" + }, + "lastStartTime": { + "type": "string", + "format": "date-time" + }, + "nextExecution": { + "type": "string", + "format": "date-time" + }, + "lastDuration": { + "$ref": "#/components/schemas/TimeSpan" + } + }, + "additionalProperties": false + }, + "TimeSpan": { + "type": "object", + "properties": { + "ticks": { + "type": "integer", + "format": "int64", + "readOnly": true + }, + "days": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "hours": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "milliseconds": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "minutes": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "seconds": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "totalDays": { + "type": "number", + "format": "double", + "readOnly": true + }, + "totalHours": { + "type": "number", + "format": "double", + "readOnly": true + }, + "totalMilliseconds": { + "type": "number", + "format": "double", + "readOnly": true + }, + "totalMinutes": { + "type": "number", + "format": "double", + "readOnly": true + }, + "totalSeconds": { + "type": "number", + "format": "double", + "readOnly": true + } + }, + "additionalProperties": false + }, + "UiConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "firstDayOfWeek": { + "type": "integer", + "format": "int32" + }, + "calendarWeekColumnHeader": { + "type": "string", + "nullable": true + }, + "shortDateFormat": { + "type": "string", + "nullable": true + }, + "longDateFormat": { + "type": "string", + "nullable": true + }, + "timeFormat": { + "type": "string", + "nullable": true + }, + "showRelativeDates": { + "type": "boolean" + }, + "enableColorImpairedMode": { + "type": "boolean" + }, + "movieInfoLanguage": { + "type": "integer", + "format": "int32" + }, + "uiLanguage": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "UpdateChanges": { + "type": "object", + "properties": { + "new": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "fixed": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "UpdateMechanism": { + "enum": [ + "builtIn", + "script", + "external", + "apt", + "docker" + ], + "type": "string" + }, + "UpdateResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "version": { + "$ref": "#/components/schemas/Version" + }, + "branch": { + "type": "string", + "nullable": true + }, + "releaseDate": { + "type": "string", + "format": "date-time" + }, + "fileName": { + "type": "string", + "nullable": true + }, + "url": { + "type": "string", + "nullable": true + }, + "installed": { + "type": "boolean" + }, + "installedOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "installable": { + "type": "boolean" + }, + "latest": { + "type": "boolean" + }, + "changes": { + "$ref": "#/components/schemas/UpdateChanges" + }, + "hash": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "UserAgentStatistics": { + "type": "object", + "properties": { + "userAgent": { + "type": "string", + "nullable": true + }, + "numberOfQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfGrabs": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "Version": { + "type": "object", + "properties": { + "major": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "minor": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "build": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "revision": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "majorRevision": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "minorRevision": { + "type": "integer", + "format": "int32", + "readOnly": true + } + }, + "additionalProperties": false } } } -} +} \ No newline at end of file From 16834e0f24bb833954754b7e223743d2ad314cc4 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 30 Aug 2021 18:24:19 -0500 Subject: [PATCH 0060/2320] Fixed: (TPB) No Results returned for Torznab searches Fixed: (TPB) Missing Magnet Download Link --- src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs b/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs index 047cb5ece..82bab9280 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs @@ -252,6 +252,11 @@ namespace NzbDrone.Core.Indexers.Definitions ImdbId = imdbId.GetValueOrDefault() }; + if (item.InfoHash != null) + { + torrentItem.MagnetUrl = MagnetLinkBuilder.BuildPublicMagnetLink(item.InfoHash, item.Name); + } + torrentInfos.Add(torrentItem); } From 1a6ea21b9fd111e7934b53844dd4ea3ab509c04d Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 29 Aug 2021 15:30:59 -0500 Subject: [PATCH 0061/2320] Fixed: Increased Xthor Rate Limit Time Fixes Logs of #472 > 2021-08-28 05:59:47.8|Error|Xthor|An error occurred while processing indexer feed. https://api.xthor.tk?passkey=(removed)&category=12%2B125%2B104%2B13%2B15%2B14%2B98%2B17%2B16%2B101%2B32%2B110%2B123%2B109%2B34%2B30&accent=1 [v0.1.1.875] System.Exception: Triggered AntiSpam Protection, please delay your requests! at NzbDrone.Core.Indexers.Definitions.Xthor.XthorParser.CheckApiState(XthorError state) in D:\a\1\s\src\NzbDrone.Core\Indexers\Definitions\Xthor\XthorParser.cs:line 112 at NzbDrone.Core.Indexers.Definitions.Xthor.XthorParser.ParseResponse(IndexerResponse indexerResponse) in D:\a\1\s\src\NzbDrone.Core\Indexers\Definitions\Xthor\XthorParser.cs:line 32 at NzbDrone.Core.Indexers.HttpIndexerBase`1.FetchPage(IndexerRequest request, IParseIndexerResponse parser) in D:\a\1\s\src\NzbDrone.Core\Indexers\HttpIndexerBase.cs:line 321 at NzbDrone.Core.Indexers.HttpIndexerBase`1.FetchReleases(Func`2 pageableRequestChainSelector, Boolean isRecent) in D:\a\1\s\src\NzbDrone.Core\Indexers\HttpIndexerBase.cs:line 174 RequestUri: https://api.xthor.tk?passkey=(removed)&category=12%2B125%2B104%2B13%2B15%2B14%2B98%2B17%2B16%2B101%2B32%2B110%2B123%2B109%2B34%2B30&accent=1;StatusCode: OK;ContentType: application/json;ContentLength: 133;ContentSample: { "error": { "code": 8, "descr": "Protection Anti-Spam: A.P.I limitee a 1 requete toutes les 2 secondes." } };FeedUrl: https://api.xthor.tk?passkey=(removed)&category=12%2B125%2B104%2B13%2B15%2B14%2B98%2B17%2B16%2B101%2B32%2B110%2B123%2B109%2B34%2B30&accent=1 --- src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs b/src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs index 108df2755..d72935287 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs @@ -18,7 +18,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Xthor public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public override TimeSpan RateLimit => TimeSpan.FromSeconds(2.1); + public override TimeSpan RateLimit => TimeSpan.FromSeconds(2.5); public override IndexerCapabilities Capabilities => SetCapabilities(); public Xthor(IIndexerHttpClient httpClient, From b4f8fb733f8c42b8cd0e7355eef2e65e17b2001b Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 30 Aug 2021 19:24:21 -0500 Subject: [PATCH 0062/2320] Fixed: Indexer Display Issue on Search Page Fixes #177 --- .../src/Components/Page/Header/IndexerSearchInputConnector.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Components/Page/Header/IndexerSearchInputConnector.js b/frontend/src/Components/Page/Header/IndexerSearchInputConnector.js index 6548826d6..4f94c4c7b 100644 --- a/frontend/src/Components/Page/Header/IndexerSearchInputConnector.js +++ b/frontend/src/Components/Page/Header/IndexerSearchInputConnector.js @@ -60,7 +60,7 @@ function createMapStateToProps() { function createMapDispatchToProps(dispatch, props) { return { onGoToAddNewMovie(query) { - dispatch(setSearchDefault({ searchQuery: query, searchIndexerIds: [-1, -2] })); + dispatch(setSearchDefault({ searchQuery: query })); dispatch(push(`${window.Prowlarr.urlBase}/search`)); } }; From e4ef1c3af0598c1aa73555ee43e27e51ae42433f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 30 Aug 2021 22:20:40 -0400 Subject: [PATCH 0063/2320] Fixed: Convert DesiTorrents to Gazelle Fixes #220 --- .../IndexerDefinitionUpdateService.cs | 1 + .../Indexers/Definitions/DesiTorrents.cs | 80 +++++++++++++++++++ .../Definitions/Gazelle/GazelleParser.cs | 2 +- 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index 02b38fa61..33e5eb487 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -33,6 +33,7 @@ namespace NzbDrone.Core.IndexerVersions "beyond-hd", "beyond-hd-oneurl", "danishbytes", + "desitorrents", "hdbits", "shareisland" }; diff --git a/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs new file mode 100644 index 000000000..f1c9e260d --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using NLog; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Gazelle; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser.Model; + +namespace NzbDrone.Core.Indexers.Definitions +{ + public class DesiTorrents : Gazelle.Gazelle + { + public override string Name => "DesiTorrents"; + public override string[] IndexerUrls => new string[] { "https://desitorrents.tv/" }; + public override string Description => "Desitorrents is a Private Torrent Tracker for BOLLYWOOD / TOLLYWOOD / GENERAL"; + public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + + public DesiTorrents(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) + { + } + + public override IParseIndexerResponse GetParser() + { + return new DesiTorrentsParser(Settings, Capabilities); + } + + protected override IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities + { + TvSearchParams = new List<TvSearchParam> + { + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep + }, + MovieSearchParams = new List<MovieSearchParam> + { + MovieSearchParam.Q + }, + MusicSearchParams = new List<MusicSearchParam> + { + MusicSearchParam.Q + }, + BookSearchParams = new List<BookSearchParam> + { + BookSearchParam.Q + } + }; + + caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movies"); + caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "Tv shows"); + caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Music"); + caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.BooksEBook, "ebooks"); + caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.TVSport, "Sports"); + caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.PCGames, "Games"); + + return caps; + } + } + + public class DesiTorrentsParser : Gazelle.GazelleParser + { + public DesiTorrentsParser(GazelleSettings settings, IndexerCapabilities capabilities) + : base(settings, capabilities) + { + } + + public override IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) + { + var releases = base.ParseResponse(indexerResponse); + + foreach (TorrentInfo release in releases) + { + release.MinimumRatio = 0.6; + release.MinimumSeedTime = 259200; + } + + return releases; + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs index aa1a463c7..48be951d2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs @@ -22,7 +22,7 @@ namespace NzbDrone.Core.Indexers.Gazelle public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) + public virtual IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List<ReleaseInfo>(); From baed2960b63842b71ce51569e7eaf282ca392723 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 30 Aug 2021 22:39:05 -0400 Subject: [PATCH 0064/2320] Fixed: (TorrentSeeds) new Login Fixes #460 --- .../Indexers/Definitions/TorrentSeeds.cs | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs index f6e400e0e..d27850ec9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs @@ -7,10 +7,12 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using AngleSharp.Html.Parser; using FluentValidation; +using Newtonsoft.Json.Linq; using NLog; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -26,6 +28,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string[] IndexerUrls => new string[] { "https://torrentseeds.org/" }; public override string Description => "TorrentSeeds is a Private site for MOVIES / TV / GENERAL"; private string LoginUrl => Settings.BaseUrl + "takelogin.php"; + private string CaptchaUrl => Settings.BaseUrl + "simpleCaptcha.php?numImages=1"; private string TokenUrl => Settings.BaseUrl + "login.php"; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; @@ -53,30 +56,32 @@ namespace NzbDrone.Core.Indexers.Definitions LogResponseContent = true }; - var loginPage = await ExecuteAuth(new HttpRequest(TokenUrl)); - var parser = new HtmlParser(); - var dom = parser.ParseDocument(loginPage.Content); - var token = dom.QuerySelector("form.form-horizontal > span"); - var csrf = token.Children[1].GetAttribute("value"); + Cookies = null; + + var loginPage = await ExecuteAuth(new HttpRequest(CaptchaUrl)); + var json1 = JObject.Parse(loginPage.Content); + var captchaSelection = json1["images"][0]["hash"]; requestBuilder.Method = HttpMethod.POST; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); + requestBuilder.SetCookies(loginPage.GetCookies()); - var cookies = Cookies; - - Cookies = null; var authLoginRequest = requestBuilder .AddFormParameter("username", Settings.Username) .AddFormParameter("password", Settings.Password) - .AddFormParameter("perm_ssl", "1") - .AddFormParameter("returnto", "/") - .AddFormParameter("csrf_token", csrf) + .AddFormParameter("submitme", "X") + .AddFormParameter("captchaSelection", (string)captchaSelection) .SetHeader("Content-Type", "multipart/form-data") .Build(); var response = await ExecuteAuth(authLoginRequest); - cookies = response.GetCookies(); + if (CheckIfLoginNeeded(response)) + { + throw new IndexerAuthException("TorrentSeeds Login Failed"); + } + + var cookies = response.GetCookies(); UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); _logger.Debug("TorrentSeeds authentication succeeded."); From 89a4c03dd2b34daab6f287c28fb2c2753286fbac Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 30 Aug 2021 22:48:24 -0400 Subject: [PATCH 0065/2320] Fixed: Translations for Tags setting page Fixes #471 --- frontend/src/Settings/Tags/Tag.js | 8 ++++---- src/NzbDrone.Core/Localization/Core/en.json | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/frontend/src/Settings/Tags/Tag.js b/frontend/src/Settings/Tags/Tag.js index eed93bd4e..7842b878f 100644 --- a/frontend/src/Settings/Tags/Tag.js +++ b/frontend/src/Settings/Tags/Tag.js @@ -85,21 +85,21 @@ class Tag extends Component { { !!indexerIds.length && <div> - {indexerIds.length} indexer{indexerIds.length > 1 && 's'} + {indexerIds.length} {indexerIds.length > 1 ? translate('Indexers') : translate('Indexer')} </div> } { !!notificationIds.length && <div> - {notificationIds.length} connection{notificationIds.length > 1 && 's'} + {notificationIds.length} {notificationIds.length > 1 ? translate('Notifications') : translate('Notification')} </div> } { !!indexerProxyIds.length && <div> - {indexerProxyIds.length} indexerProxy{indexerProxyIds.length > 1 && 's'} + {indexerProxyIds.length} {indexerProxyIds.length > 1 ? translate('IndexerProxies') : translate('IndexerProxy')} </div> } </div> @@ -108,7 +108,7 @@ class Tag extends Component { { !isTagUsed && <div> - No links + {translate('NoLinks')} </div> } diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index f0c0a9047..99d88cf71 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -191,6 +191,7 @@ "IndexerPriority": "Indexer Priority", "IndexerPriorityHelpText": "Indexer Priority from 1 (Highest) to 50 (Lowest). Default: 25.", "IndexerProxies": "Indexer Proxies", + "IndexerProxy": "Indexer Proxy", "IndexerProxyStatusCheckAllClientMessage": "All proxies are unavailable due to failures", "IndexerProxyStatusCheckSingleClientMessage": "Proxies unavailable due to failures: {0}", "IndexerQuery": "Indexer Query", @@ -246,10 +247,12 @@ "NoChanges": "No Changes", "NoLeaveIt": "No, Leave It", "NoLimitForAnyRuntime": "No limit for any runtime", + "NoLinks": "No Links", "NoLogFiles": "No log files", "NoMinimumForAnyRuntime": "No minimum for any runtime", "NoSearchResultsFound": "No search results found, try performing a new search below.", "NoTagsHaveBeenAddedYet": "No tags have been added yet", + "Notification": "Notification", "Notifications": "Notifications", "NotificationTriggers": "Notification Triggers", "NotificationTriggersHelpText": "Select which events should trigger this notification", From 4c7c7e8a623c134b40fd0136f36252f067b93706 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 31 Aug 2021 17:22:27 -0500 Subject: [PATCH 0066/2320] Fixed: (BTN) Daily Episode Searches failing Fixes #480 --- .../BroadcastheNetRequestGenerator.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNetRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNetRequestGenerator.cs index 89c610010..c36a90712 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNetRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNetRequestGenerator.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Text.RegularExpressions; +using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.IndexerSearch.Definitions; @@ -69,17 +71,26 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet } // If only the season/episode is searched for then change format to match expected format - if (searchCriteria.Season > 0 && searchCriteria.Episode == null) + if (searchCriteria.Season > 0 && searchCriteria.Episode.IsNullOrWhiteSpace()) { + // Season Only parameters.Name = string.Format("Season {0}%", searchCriteria.Season.Value); parameters.Category = "Season"; } - else if (searchCriteria.Season > 0 && int.Parse(searchCriteria.Episode) > 0) + else if (searchCriteria.Season > 0 && Regex.IsMatch(searchCriteria.EpisodeSearchString, "(\\d{4}\\.\\d{2}\\.\\d{2})")) { + // Daily Episode + parameters.Name = searchCriteria.EpisodeSearchString; + parameters.Category = "Episode"; + } + else if (searchCriteria.Season > 0 && int.Parse(searchCriteria.Episode) > 0) + { + // Standard (S/E) Episode parameters.Name = string.Format("S{0:00}E{1:00}", searchCriteria.Season.Value, int.Parse(searchCriteria.Episode)); parameters.Category = "Episode"; } + // Neither a season only search nor daily nor standard, fall back to query parameters.Search = searchString.Replace(" ", "%"); pageableRequests.Add(GetPagedRequests(parameters, btnResults, btnOffset)); From 043b1a0e46f1edfe4ad9ab954a1aff27812a535a Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 31 Aug 2021 14:55:25 -0500 Subject: [PATCH 0067/2320] Fixed: Better Log Cleansing Ref #280 YGG Comment --- .../InstrumentationTests/CleanseLogMessageFixture.cs | 1 + src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs index 04daad591..e046ab2c0 100644 --- a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs +++ b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs @@ -22,6 +22,7 @@ namespace NzbDrone.Common.Test.InstrumentationTests [TestCase(@" var authkey = ""2b51db35e1910123321025a12b9933d2"";")] [TestCase(@"https://hd-space.org/index.php?page=login: uid=mySecret&pwd=mySecret")] [TestCase(@"https://beyond-hd.me/api/torrents/2b51db35e1912ffc138825a12b9933d2")] + [TestCase(@"Req: [POST] https://www3.yggtorrent.nz/user/login: id=mySecret&pass=mySecret&ci_csrf_token=2b51db35e1912ffc138825a12b9933d2")] // NzbGet [TestCase(@"{ ""Name"" : ""ControlUsername"", ""Value"" : ""mySecret"" }, { ""Name"" : ""ControlPassword"", ""Value"" : ""mySecret"" }, ")] diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index d64cc7ad5..a7906e705 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -11,8 +11,8 @@ namespace NzbDrone.Common.Instrumentation private static readonly Regex[] CleansingRules = new[] { // Url - new Regex(@"(?<=\?|&|: |;)(apikey|token|passkey|auth|authkey|user|uid|api|[a-z_]*apikey|account|passwd|pwd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), - new Regex(@"(?<=\?|&| )[^=]*?(_?(?<!use)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"(?<=[?&: ;])(apikey|token|pass(?:key|wd)?|auth|authkey|user|u?id|api|[a-z_]*apikey|account|pwd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"(?<=[?& ])[^=]*?(_?(?<!use)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"rss\.torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"rss\.torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), From a854ce6f4e79dd9306b76e08f45190faf77903c6 Mon Sep 17 00:00:00 2001 From: Servarr <32001786+ServarrAdmin@users.noreply.github.com> Date: Fri, 3 Sep 2021 15:33:08 -0400 Subject: [PATCH 0068/2320] Translated using Weblate (Portuguese (Brazil)) (#484) Currently translated at 100.0% (441 of 441 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 62.5% (276 of 441 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (441 of 441 strings) Co-authored-by: Csaba <csab0825@gmail.com> Co-authored-by: Havok Dan <havokdan@yahoo.com.br> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: angelsky11 <angelsky11@gmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ Translation: Servarr/Prowlarr Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Csaba <csab0825@gmail.com> Co-authored-by: Havok Dan <havokdan@yahoo.com.br> Co-authored-by: angelsky11 <angelsky11@gmail.com> --- src/NzbDrone.Core/Localization/Core/hu.json | 5 ++++- src/NzbDrone.Core/Localization/Core/pt_BR.json | 7 ++++++- src/NzbDrone.Core/Localization/Core/zh_CN.json | 9 +++++---- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index d7a81553b..d7b060b16 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -941,5 +941,8 @@ "Notifications": "Értesítések", "UnableToAddANewIndexerProxyPleaseTryAgain": "Nem lehet új Indexer Proxyt hozzáadni, próbálja újra.", "IndexerVipCheckExpiredClientMessage": "Az Indexer VIP előnyei lejártak: {0}", - "IndexerVipCheckExpiringClientMessage": "Az Indexer VIP előnyei hamarosan lejárnak: {0}" + "IndexerVipCheckExpiringClientMessage": "Az Indexer VIP előnyei hamarosan lejárnak: {0}", + "IndexerProxy": "Indexelő Proxy", + "NoLinks": "Nincsenek Linkek", + "Notification": "Értesítés" } diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index dcb1c3f1d..33c4b46d3 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -437,5 +437,10 @@ "IndexerTagsHelpText": "Use etiquetas para especificar clientes padrão, especificar proxies indexadores ou apenas para organizar seus indexadores.", "Notifications": "Notificações", "UnableToAddANewIndexerProxyPleaseTryAgain": "Não foi possível adicionar um novo proxy indexador, tente novamente.", - "UnableToLoadIndexerProxies": "Incapaz de carregar proxies indexadores" + "UnableToLoadIndexerProxies": "Incapaz de carregar proxies indexadores", + "IndexerVipCheckExpiredClientMessage": "Benefícios VIP do Indexador expiraram: {0}", + "IndexerProxy": "Proxy do Indexador", + "IndexerVipCheckExpiringClientMessage": "Os benefícios VIPS do Indexador expirarão em breve: {0}", + "NoLinks": "Sem Links", + "Notification": "Notificação" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index d74524265..a0a5e2a2c 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -192,12 +192,12 @@ "BranchUpdateMechanism": "外部更新机制使用的分支", "BranchUpdate": "更新Prowlarr的分支", "Branch": "分支", - "BindAddressHelpText": "有效的IPV4地址或以“*”代表所以地址", + "BindAddressHelpText": "有效的IPV4地址或以'*'代表所有地址", "BindAddress": "绑定地址", "BeforeUpdate": "更新前", "Backups": "备份", "BackupRetentionHelpText": "早于保留周期的自动备份将被自动清除", - "BackupNow": "现在备份", + "BackupNow": "马上备份", "BackupFolderHelpText": "相对路径将在 Prowlarr 的 AppData 目录下", "Backup": "备份", "AutomaticSearch": "自动搜索", @@ -274,10 +274,11 @@ "NewznabVipCheckExpiredClientMessage": "搜刮器VIP权益已过期:{0}", "New": "新的", "NetCore": ".NET", - "Name": "名字", + "Name": "名称", "Movies": "电影", "MovieIndexScrollTop": "影片索引:滚动到顶部", "MovieIndexScrollBottom": "影片索引:滚动到底部", "MovieDetailsPreviousMovie": "影片详细:前一个", - "MovieDetailsNextMovie": "影片详细:下一个" + "MovieDetailsNextMovie": "影片详细:下一个", + "BackupIntervalHelpText": "自动备份时间间隔" } From 593a0e965867401ee9a007c16daeece9f667d7d9 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 31 Aug 2021 19:45:46 -0500 Subject: [PATCH 0069/2320] Fixed: (MAM) Don't Parse HTTP Error Responses --- .../Indexers/Definitions/MyAnonamouse.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs b/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs index 0e2db997e..02d30567b 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs @@ -3,12 +3,14 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Globalization; using System.Linq; +using System.Net; using FluentValidation; using Newtonsoft.Json; using NLog; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -269,6 +271,23 @@ namespace NzbDrone.Core.Indexers.Definitions public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { + // Throw common http errors here before we try to parse + if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) + { + // Remove cookie cache + CookiesUpdater(null, null); + + throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request"); + } + + if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value)) + { + // Remove cookie cache + CookiesUpdater(null, null); + + throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}"); + } + var torrentInfos = new List<TorrentInfo>(); var jsonResponse = JsonConvert.DeserializeObject<MyAnonamouseResponse>(indexerResponse.Content); From f3a33cf817abeb8dd09bc8dded8f14ab96d62327 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 31 Aug 2021 19:16:42 -0500 Subject: [PATCH 0070/2320] Fixed: Missing Proxy Validation Translations --- .../IndexerProxies/FlareSolverr/FlareSolverr.cs | 9 +++++---- src/NzbDrone.Core/IndexerProxies/Http/Http.cs | 5 +++-- src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs | 7 +++++-- src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs | 5 +++-- src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs | 5 +++-- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index f58f9ccaf..4c9b2b511 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -7,14 +7,15 @@ using NLog; using NzbDrone.Common.Cloud; using NzbDrone.Common.Http; using NzbDrone.Common.Serializer; +using NzbDrone.Core.Localization; using NzbDrone.Core.Validation; namespace NzbDrone.Core.IndexerProxies.FlareSolverr { public class FlareSolverr : HttpIndexerProxyBase<FlareSolverrSettings> { - public FlareSolverr(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger) - : base(cloudRequestBuilder, httpClient, logger) + public FlareSolverr(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger, ILocalizationService localizationService) + : base(cloudRequestBuilder, httpClient, logger, localizationService) { } @@ -133,13 +134,13 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr if (response.StatusCode == HttpStatusCode.BadRequest) { _logger.Error("Proxy Health Check failed: {0}", response.StatusCode); - failures.Add(new NzbDroneValidationFailure("Host", "ProxyCheckBadRequestMessage")); + failures.Add(new NzbDroneValidationFailure("Host", string.Format(_localizationService.GetLocalizedString("ProxyCheckBadRequestMessage"), response.StatusCode))); } } catch (Exception ex) { _logger.Error(ex, "Proxy Health Check failed"); - failures.Add(new NzbDroneValidationFailure("Host", "ProxyCheckFailedToTestMessage")); + failures.Add(new NzbDroneValidationFailure("Host", string.Format(_localizationService.GetLocalizedString("ProxyCheckFailedToTestMessage"), request.Url.Host))); } return new ValidationResult(failures); diff --git a/src/NzbDrone.Core/IndexerProxies/Http/Http.cs b/src/NzbDrone.Core/IndexerProxies/Http/Http.cs index 03ab6a802..838b3b2c8 100644 --- a/src/NzbDrone.Core/IndexerProxies/Http/Http.cs +++ b/src/NzbDrone.Core/IndexerProxies/Http/Http.cs @@ -3,13 +3,14 @@ using NLog; using NzbDrone.Common.Cloud; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.Localization; namespace NzbDrone.Core.IndexerProxies.Http { public class Http : HttpIndexerProxyBase<HttpSettings> { - public Http(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger) - : base(cloudRequestBuilder, httpClient, logger) + public Http(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger, ILocalizationService localizationService) + : base(cloudRequestBuilder, httpClient, logger, localizationService) { } diff --git a/src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs b/src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs index f37389b4d..6ddc8b6bc 100644 --- a/src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs +++ b/src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs @@ -6,6 +6,7 @@ using FluentValidation.Results; using NLog; using NzbDrone.Common.Cloud; using NzbDrone.Common.Http; +using NzbDrone.Core.Localization; using NzbDrone.Core.Validation; namespace NzbDrone.Core.IndexerProxies @@ -16,12 +17,14 @@ namespace NzbDrone.Core.IndexerProxies protected readonly IHttpClient _httpClient; protected readonly IHttpRequestBuilderFactory _cloudRequestBuilder; protected readonly Logger _logger; + protected readonly ILocalizationService _localizationService; - public HttpIndexerProxyBase(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger) + public HttpIndexerProxyBase(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger, ILocalizationService localizationService) { _httpClient = httpClient; _logger = logger; _cloudRequestBuilder = cloudRequestBuilder.Services; + _localizationService = localizationService; } public override ValidationResult Test() @@ -31,7 +34,7 @@ namespace NzbDrone.Core.IndexerProxies var addresses = Dns.GetHostAddresses(Settings.Host); if (!addresses.Any()) { - failures.Add(new NzbDroneValidationFailure("Host", "ProxyCheckResolveIpMessage")); + failures.Add(new NzbDroneValidationFailure("Host", string.Format(_localizationService.GetLocalizedString("ProxyCheckResolveIpMessage"), addresses))); } var request = PreRequest(_cloudRequestBuilder.Create() diff --git a/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs b/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs index 22ca0ce2c..54177a917 100644 --- a/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs +++ b/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs @@ -8,13 +8,14 @@ using NLog; using NzbDrone.Common.Cloud; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.Localization; namespace NzbDrone.Core.IndexerProxies.Socks4 { public class Socks4 : HttpIndexerProxyBase<Socks4Settings> { - public Socks4(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger) - : base(cloudRequestBuilder, httpClient, logger) + public Socks4(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger, ILocalizationService localizationService) + : base(cloudRequestBuilder, httpClient, logger, localizationService) { } diff --git a/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs b/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs index 3ad62e24a..c41c00549 100644 --- a/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs +++ b/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs @@ -8,13 +8,14 @@ using NLog; using NzbDrone.Common.Cloud; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.Localization; namespace NzbDrone.Core.IndexerProxies.Socks5 { public class Socks5 : HttpIndexerProxyBase<Socks5Settings> { - public Socks5(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger) - : base(cloudRequestBuilder, httpClient, logger) + public Socks5(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger, ILocalizationService localizationService) + : base(cloudRequestBuilder, httpClient, logger, localizationService) { } From 1de845c8f53a0708c4b0515cdc99698c2d803f0c Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 7 Sep 2021 17:28:07 -0500 Subject: [PATCH 0071/2320] (indexers) various - standardized language format with `{ISO 639-1}-{ISO 3166-1 alpha-2}` --- src/NzbDrone.Core/Indexers/Definitions/Aither.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Anidub.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Animedia.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/BB.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Redacted.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Shizaproject.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/SubsPlease.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/TVVault.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/TorrentsCSV.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/YTS.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs | 2 +- 28 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Aither.cs b/src/NzbDrone.Core/Indexers/Definitions/Aither.cs index 1aff169c4..1de88cea6 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Aither.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Aither.cs @@ -12,7 +12,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "Aither"; public override string[] IndexerUrls => new string[] { "https://aither.cc/" }; public override string Description => "Aither is a Private Torrent Tracker for HD MOVIES / TV"; - public override string Language => "en-us"; + public override string Language => "en-US"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public Aither(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs b/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs index c31bae08e..8905fddb4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "Anidub"; public override string[] IndexerUrls => new string[] { "https://tr.anidub.com/" }; public override string Description => "Anidub is russian anime voiceover group and eponymous anime tracker."; - public override string Language => "ru-ru"; + public override string Language => "ru-RU"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPublic; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs b/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs index fd8469149..59948371d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs @@ -22,7 +22,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "Anilibria"; public override string[] IndexerUrls => new string[] { "https://anilibria.tv/" }; public override string Description => "Anilibria is russian anime voiceover group and eponymous anime tracker."; - public override string Language => "ru-ru"; + public override string Language => "ru-RU"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Public; diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs index ec7c4adaf..90a50d753 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "AnimeBytes"; public override string[] IndexerUrls => new string[] { "https://animebytes.tv/" }; public override string Description => "AnimeBytes (AB) is the largest private torrent tracker that specialises in anime and anime-related content."; - public override string Language => "en-us"; + public override string Language => "en-US"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs index 55f871a0e..9a380fcf3 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs @@ -12,7 +12,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "AnimeWorld"; public override string[] IndexerUrls => new string[] { "https://animeworld.cx/" }; public override string Description => "AnimeWorld (AW) is a GERMAN Private site for ANIME / MANGA / HENTAI"; - public override string Language => "de-de"; + public override string Language => "de-DE"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public AnimeWorld(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs b/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs index 7d8297d69..855c6dade 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs @@ -23,7 +23,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "Animedia"; public override string[] IndexerUrls => new string[] { "https://tt.animedia.tv/" }; public override string Description => "Animedia is russian anime voiceover group and eponymous anime tracker."; - public override string Language => "ru-ru"; + public override string Language => "ru-RU"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Public; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs b/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs index b99807cdc..80189259b 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string[] IndexerUrls => new string[] { "https://anthelion.me/" }; private string LoginUrl => Settings.BaseUrl + "login.php"; public override string Description => "A movies tracker"; - public override string Language => "en-us"; + public override string Language => "en-US"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; diff --git a/src/NzbDrone.Core/Indexers/Definitions/BB.cs b/src/NzbDrone.Core/Indexers/Definitions/BB.cs index b6ecf0c38..6ec57e531 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BB.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BB.cs @@ -26,7 +26,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string[] IndexerUrls => new string[] { StringUtil.FromBase64("aHR0cHM6Ly9iYWNvbmJpdHMub3JnLw==") }; private string LoginUrl => Settings.BaseUrl + "login.php"; public override string Description => "bB is a Private Torrent Tracker for 0DAY / GENERAL"; - public override string Language => "en-us"; + public override string Language => "en-US"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; diff --git a/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs b/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs index a2cfdc38f..b1eab50c4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs @@ -24,7 +24,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "BinSearch"; public override string[] IndexerUrls => new string[] { "https://binsearch.info/" }; public override string Description => "The binary Usenet search engine"; - public override string Language => "en-us"; + public override string Language => "en-US"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Usenet; public override IndexerPrivacy Privacy => IndexerPrivacy.Public; diff --git a/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs b/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs index 01eb277e9..b69cf9595 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs @@ -24,7 +24,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "GazelleGames"; public override string[] IndexerUrls => new string[] { "https://gazellegames.net/" }; public override string Description => "GazelleGames (GGn) is a Private Torrent Tracker for GAMES"; - public override string Language => "en-us"; + public override string Language => "en-US"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs b/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs index b3a953b0b..de83b0fa5 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs @@ -26,7 +26,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string[] IndexerUrls => new string[] { "https://hd-space.org/" }; private string LoginUrl => Settings.BaseUrl + "index.php?page=login"; public override string Description => "HD-Space (HDS) is a Private Torrent Tracker for HD MOVIES / TV"; - public override string Language => "en-us"; + public override string Language => "en-US"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs index a73234f40..7776608fa 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs @@ -25,7 +25,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string[] IndexerUrls => new string[] { "https://nebulance.io/" }; private string LoginUrl => Settings.BaseUrl + "login.php"; public override string Description => "Nebulance (NBL) is a ratioless Private Torrent Tracker for TV"; - public override string Language => "en-us"; + public override string Language => "en-US"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; diff --git a/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs b/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs index c7e3e7390..f0d69065f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs @@ -26,7 +26,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string[] IndexerUrls => new string[] { "https://pretome.info/" }; public override string Description => "PreToMe is a ratioless 0Day/General tracker."; private string LoginUrl => Settings.BaseUrl + "takelogin.php"; - public override string Language => "en-us"; + public override string Language => "en-US"; public override Encoding Encoding => Encoding.GetEncoding("iso-8859-1"); public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs b/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs index 5f664cd05..445e90170 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs @@ -25,7 +25,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "Redacted"; public override string[] IndexerUrls => new string[] { "https://redacted.ch/" }; public override string Description => "REDActed (Aka.PassTheHeadPhones) is one of the most well-known music trackers."; - public override string Language => "en-us"; + public override string Language => "en-US"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; diff --git a/src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs b/src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs index f982bcdc3..12649f599 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs @@ -24,7 +24,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "SceneTime"; public override string[] IndexerUrls => new[] { "https://www.scenetime.com/" }; public override string Description => "Always on time"; - public override string Language => "en-us"; + public override string Language => "en-US"; public override Encoding Encoding => Encoding.GetEncoding("iso-8859-1"); public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; diff --git a/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs b/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs index 0698e0859..76bc55ab3 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs @@ -12,7 +12,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "ShareIsland"; public override string[] IndexerUrls => new string[] { "https://shareisland.org/" }; public override string Description => "A general italian tracker."; - public override string Language => "it-it"; + public override string Language => "it-IT"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public ShareIsland(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Shizaproject.cs b/src/NzbDrone.Core/Indexers/Definitions/Shizaproject.cs index 5ad5cbf9f..deff683cb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Shizaproject.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Shizaproject.cs @@ -23,7 +23,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "ShizaProject"; public override string[] IndexerUrls => new string[] { "https://shiza-project.com/" }; public override string Description => "Shizaproject is russian anime voiceover group and eponymous anime tracker."; - public override string Language => "ru-ru"; + public override string Language => "ru-RU"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Public; diff --git a/src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs b/src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs index 11ec011d1..6791b4276 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs @@ -20,7 +20,7 @@ namespace NzbDrone.Core.Indexers.Definitions { public override string Name => "ShowRSS"; public override string[] IndexerUrls => new string[] { "https://showrss.info/" }; - public override string Language => "en-us"; + public override string Language => "en-US"; public override string Description => "showRSS is a service that allows you to keep track of your favorite TV shows"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs index 316b3f7ba..686a417a9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Description => "SpeedApp is a ROMANIAN Private Torrent Tracker for MOVIES / TV / GENERAL"; - public override string Language => "ro-ro"; + public override string Language => "ro-RO"; public override Encoding Encoding => Encoding.UTF8; diff --git a/src/NzbDrone.Core/Indexers/Definitions/SubsPlease.cs b/src/NzbDrone.Core/Indexers/Definitions/SubsPlease.cs index 69e47b9d5..6c55b795c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SubsPlease.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SubsPlease.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Indexers.Definitions "https://subsplease.org/", "https://subsplease.nocensor.space/" }; - public override string Language => "en-us"; + public override string Language => "en-US"; public override string Description => "SubsPlease - A better HorribleSubs/Erai replacement"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; diff --git a/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs b/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs index 6f2891cb1..48958a972 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string[] IndexerUrls => new[] { "https://tv-vault.me/" }; private string LoginUrl => Settings.BaseUrl + "login.php"; public override string Description => "TV-Vault is a very unique tracker dedicated for old TV shows, TV movies and documentaries."; - public override string Language => "en-us"; + public override string Language => "en-US"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; diff --git a/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs b/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs index 82bab9280..a71a5da86 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs @@ -21,7 +21,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "ThePirateBay"; public override string[] IndexerUrls => new string[] { "https://thepiratebay.org/" }; public override string Description => "Pirate Bay(TPB) is the galaxy’s most resilient Public BitTorrent site"; - public override string Language => "en-us"; + public override string Language => "en-US"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Public; diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs index cf8973080..1d7761bc9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs @@ -22,7 +22,7 @@ namespace NzbDrone.Core.Indexers.Definitions { public override string Name => "TorrentParadiseMl"; public override string[] IndexerUrls => new[] { "https://torrent-paradise.ml/" }; - public override string Language => "en-us"; + public override string Language => "en-US"; public override string Description => "The most innovative torrent site"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs index ce819f2eb..7378803fd 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs @@ -23,7 +23,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "TorrentSyndikat"; public override string[] IndexerUrls => new[] { "https://torrent-syndikat.org/" }; public override string Description => "A German general tracker"; - public override string Language => "de-de"; + public override string Language => "de-DE"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentsCSV.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentsCSV.cs index 027febd03..648523ba8 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentsCSV.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentsCSV.cs @@ -21,7 +21,7 @@ namespace NzbDrone.Core.Indexers.Definitions { public override string Name => "TorrentsCSV"; public override string[] IndexerUrls => new[] { "https://torrents-csv.ml/" }; - public override string Language => "en-us"; + public override string Language => "en-US"; public override string Description => "Torrents.csv is a self-hostable open source torrent search engine and database"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs b/src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs index d72935287..8747fbc00 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs @@ -12,7 +12,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Xthor { public override string Name => "Xthor"; public override string[] IndexerUrls => new string[] { "https://api.xthor.tk/" }; - public override string Language => "fr-fr"; + public override string Language => "fr-FR"; public override string Description => "Xthor is a general Private torrent site"; public override Encoding Encoding => Encoding.GetEncoding("windows-1252"); public override DownloadProtocol Protocol => DownloadProtocol.Torrent; diff --git a/src/NzbDrone.Core/Indexers/Definitions/YTS.cs b/src/NzbDrone.Core/Indexers/Definitions/YTS.cs index 169835c23..0716f85f5 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/YTS.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/YTS.cs @@ -22,7 +22,7 @@ namespace NzbDrone.Core.Indexers.Definitions { public override string Name => "YTS"; public override string[] IndexerUrls => new string[] { "https://yts.mx/" }; - public override string Language => "en-us"; + public override string Language => "en-US"; public override string Description => "YTS is a Public torrent site specialising in HD movies of small size"; public override Encoding Encoding => Encoding.GetEncoding("windows-1252"); public override DownloadProtocol Protocol => DownloadProtocol.Torrent; diff --git a/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs b/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs index 80bb816c2..9ae731a0f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Indexers.Definitions private string Login3Url => Settings.BaseUrl + "retorno/include/puerta_8_ajax.php"; private string Login4Url => Settings.BaseUrl + "retorno/index.php"; public override string Description => "ZonaQ is a SPANISH Private Torrent Tracker for MOVIES / TV"; - public override string Language => "es-es"; + public override string Language => "es-ES"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; From 4ea0e6c016ec24623631a07ff1ea08dcc572ad89 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 7 Sep 2021 21:18:11 -0500 Subject: [PATCH 0072/2320] add various missing descriptions --- src/NzbDrone.Core/Indexers/Definitions/BB.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/FileList/FileList.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs | 2 +- .../Indexers/Definitions/PassThePopcorn/PassThePopcorn.cs | 2 +- .../Indexers/Definitions/TorrentPotato/TorrentPotato.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BB.cs b/src/NzbDrone.Core/Indexers/Definitions/BB.cs index 6ec57e531..5934fd4d3 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BB.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BB.cs @@ -25,7 +25,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "BB"; public override string[] IndexerUrls => new string[] { StringUtil.FromBase64("aHR0cHM6Ly9iYWNvbmJpdHMub3JnLw==") }; private string LoginUrl => Settings.BaseUrl + "login.php"; - public override string Description => "bB is a Private Torrent Tracker for 0DAY / GENERAL"; + public override string Description => "BB is a Private Torrent Tracker for 0DAY / GENERAL"; public override string Language => "en-US"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; diff --git a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileList.cs b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileList.cs index d07ac31c2..630283e80 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileList.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileList.cs @@ -10,7 +10,7 @@ namespace NzbDrone.Core.Indexers.FileList { public override string Name => "FileList.io"; public override string[] IndexerUrls => new string[] { "https://filelist.io" }; - public override string Description => ""; + public override string Description => "FileList (FL) is a ROMANIAN Private Torrent Tracker for 0DAY / GENERAL"; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override bool SupportsRss => true; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs index d6e73e22e..1aa1cfd6b 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs @@ -20,7 +20,7 @@ namespace NzbDrone.Core.Indexers.Newznab public override string Name => "Newznab"; public override string[] IndexerUrls => GetBaseUrlFromSettings(); - public override string Description => ""; + public override string Description => "Newznab is an API search specification for Usenet"; public override bool FollowRedirect => true; public override bool SupportsRedirect => true; diff --git a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcorn.cs b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcorn.cs index 9f76e5109..79f9f458a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcorn.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcorn.cs @@ -11,7 +11,7 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn { public override string Name => "PassThePopcorn"; public override string[] IndexerUrls => new string[] { "https://passthepopcorn.me" }; - public override string Description => ""; + public override string Description => "PassThePopcorn (PTP) is a Private site for MOVIES / TV"; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override bool SupportsRss => true; diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentPotato/TorrentPotato.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentPotato/TorrentPotato.cs index a75e3e67b..c6367c099 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentPotato/TorrentPotato.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentPotato/TorrentPotato.cs @@ -10,7 +10,7 @@ namespace NzbDrone.Core.Indexers.TorrentPotato { public override string Name => "TorrentPotato"; public override string[] IndexerUrls => new string[] { "http://127.0.0.1" }; - public override string Description => ""; + public override string Description => "A JSON based torrent provider previously developed for CouchPotato"; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs index 997a9477f..a7a97ea8e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs @@ -20,7 +20,7 @@ namespace NzbDrone.Core.Indexers.Torznab public override string Name => "Torznab"; public override string[] IndexerUrls => GetBaseUrlFromSettings(); - public override string Description => ""; + public override string Description => "A Newznab-like api for torrents."; public override bool FollowRedirect => true; public override bool SupportsRedirect => true; From 1bfcb99f313d86dabda48b9799306c745943efd1 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Thu, 16 Sep 2021 02:43:55 +0000 Subject: [PATCH 0073/2320] Translated using Weblate (Slovak) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 7.4% (33 of 441 strings) Added translation using Weblate (Slovak) Translated using Weblate (Norwegian Bokmål) Currently translated at 9.2% (41 of 441 strings) Added translation using Weblate (Norwegian Bokmål) Translated using Weblate (Portuguese) Currently translated at 83.6% (369 of 441 strings) Translated using Weblate (Dutch) Currently translated at 78.9% (348 of 441 strings) Co-authored-by: 7even <henning@wikene.no> Co-authored-by: Samuel Bartík <github.fundal@aleeas.com> Co-authored-by: Stevie Robinson <stevie.robinson@gmail.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: sergioquiterio <serquiterio@gmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nb_NO/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sk/ Translation: Servarr/Prowlarr --- .../Localization/Core/nb_NO.json | 43 +++++++++++++++++++ src/NzbDrone.Core/Localization/Core/nl.json | 4 +- src/NzbDrone.Core/Localization/Core/pt.json | 11 ++++- src/NzbDrone.Core/Localization/Core/sk.json | 35 +++++++++++++++ 4 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 src/NzbDrone.Core/Localization/Core/nb_NO.json create mode 100644 src/NzbDrone.Core/Localization/Core/sk.json diff --git a/src/NzbDrone.Core/Localization/Core/nb_NO.json b/src/NzbDrone.Core/Localization/Core/nb_NO.json new file mode 100644 index 000000000..f79e611da --- /dev/null +++ b/src/NzbDrone.Core/Localization/Core/nb_NO.json @@ -0,0 +1,43 @@ +{ + "Add": "Legge til", + "AddAppProfile": "Legg til app -synkroniseringsprofil", + "AddDownloadClient": "Legg til nedlastingsklient", + "Added": "La til", + "AddingTag": "Legger til tag", + "All": "Alle", + "Analytics": "Analyse", + "AppDataDirectory": "AppData -katalog", + "ApplyTags": "Bruk Tags", + "Authentication": "Godkjenning", + "Automatic": "Automatisk", + "Backup": "Sikkerhetskopiering", + "BackupIntervalHelpText": "Intervall mellom automatiske sikkerhetskopier", + "BackupNow": "Sikkerhetskopier nå", + "Backups": "Sikkerhetskopier", + "BeforeUpdate": "Før oppdatering", + "BindAddressHelpText": "Gyldig IP4 -adresse eller \"*\" for alle grensesnitt", + "Branch": "Gren", + "Cancel": "Avbryt", + "CertificateValidation": "Sertifikatvalidering", + "ChangeHasNotBeenSavedYet": "Endringen er ikke lagret ennå", + "Clear": "Klar", + "About": "Om", + "AcceptConfirmationModal": "Godta bekreftelsesmodal", + "Actions": "Handlinger", + "AddDownloadClientToProwlarr": "Ved å legge til en nedlastingsklient kan Prowlarr sende utgivelser direkte fra brukergrensesnittet mens du gjør et manuelt søk.", + "AddIndexer": "Legg til indekser", + "Age": "Alder", + "ApiKey": "API Nøkkel", + "AppDataLocationHealthCheckMessage": "Oppdatering vil ikke være mulig for å forhindre sletting av AppData på oppdateringen", + "Apply": "Bruk", + "ApplyTagsHelpTexts3": "Fjern: Fjern de angitte kodene", + "ApplyTagsHelpTexts4": "Erstatt: Erstatt taggene med de angitte kodene (skriv inn ingen tagger for å slette alle taggene)", + "AreYouSureYouWantToResetYourAPIKey": "Er du sikker på at du vil tilbakestille API -nøkkelen din?", + "AutomaticSearch": "Automatisk Søk", + "BackupRetentionHelpText": "Automatiske sikkerhetskopier som er eldre enn oppbevaringsperioden, blir ryddet opp automatisk", + "BindAddress": "Bind adresse", + "BranchUpdateMechanism": "Gren brukt av ekstern oppdateringsmekanisme", + "BypassProxyForLocalAddresses": "Omgå proxy for lokale adresser", + "CancelPendingTask": "Er du sikker på at du vil avbryte denne ventende oppgaven?", + "CertificateValidationHelpText": "Endre hvor streng HTTPS -sertifisering validering er" +} diff --git a/src/NzbDrone.Core/Localization/Core/nl.json b/src/NzbDrone.Core/Localization/Core/nl.json index 1f89bed9f..f83a43cd8 100644 --- a/src/NzbDrone.Core/Localization/Core/nl.json +++ b/src/NzbDrone.Core/Localization/Core/nl.json @@ -852,5 +852,7 @@ "AddToDownloadClient": "Release toevoegen aan download client", "AddNewIndexer": "Voeg nieuwe Indexeerder Toe", "AddedToDownloadClient": "Release toegevoegd aan client", - "PrioritySettings": "Prioriteit" + "PrioritySettings": "Prioriteit", + "AddDownloadClient": "Download Client Toevoegen", + "Add": "Toevoegen" } diff --git a/src/NzbDrone.Core/Localization/Core/pt.json b/src/NzbDrone.Core/Localization/Core/pt.json index f472a3e9b..e0c9daee7 100644 --- a/src/NzbDrone.Core/Localization/Core/pt.json +++ b/src/NzbDrone.Core/Localization/Core/pt.json @@ -538,7 +538,7 @@ "ApplyTagsHelpTexts2": "Adicionar: agregar as etiquetas à lista existente de etiquetas", "ApplyTagsHelpTexts1": "Como aplicar etiquetas aos indexadores selecionados", "AllowMovieChangeClickToChangeMovie": "Clique para trocar o filme", - "AddingTag": "Adicionando etiqueta", + "AddingTag": "A adicionar etiqueta", "AddImportExclusionHelpText": "Impedir filme de ser adicionado ao Prowlarr através de listas", "DelayingDownloadUntilInterp": "Suspendendo download até {0} às {1}", "CopyToClipboard": "Copiar à Área de Transferência", @@ -934,5 +934,12 @@ "FullSync": "Sincronização completa", "AddRemoveOnly": "Adicionar e remover apenas", "AddDownloadClientToProwlarr": "Adicionar um cliente de transferências possibilita ao Prowlarr enviar versões diretamente da IU ao realizar uma pesquisa manual.", - "Add": "Adicionar" + "Add": "Adicionar", + "DeleteIndexerProxy": "Apagar Proxy de Indexador", + "DeleteIndexerProxyMessageText": "Tem a certeza que quer apagar o proxy '{0}'?", + "IndexerProxy": "Proxy de Indexador", + "AddIndexerProxy": "Adicionar Proxy de Indexador", + "IndexerProxyStatusCheckSingleClientMessage": "Proxys indisponíveis devido a falhas: {0}", + "IndexerProxies": "Proxys de Indexadores", + "IndexerProxyStatusCheckAllClientMessage": "Todos os proxys estão indisponíveis devido a falhas" } diff --git a/src/NzbDrone.Core/Localization/Core/sk.json b/src/NzbDrone.Core/Localization/Core/sk.json new file mode 100644 index 000000000..64d835697 --- /dev/null +++ b/src/NzbDrone.Core/Localization/Core/sk.json @@ -0,0 +1,35 @@ +{ + "Actions": "Akcie", + "Add": "Pridať", + "AddDownloadClient": "Pridať klienta pre sťahovanie", + "Added": "Pridané", + "AddIndexer": "Pridať indexer", + "AddingTag": "Pridávanie značky", + "Age": "Vek", + "All": "Všetko", + "Analytics": "Analytika", + "ApiKey": "Kľúč API", + "AppDataDirectory": "Priečinok AppData", + "Apply": "Použiť", + "ApplyTags": "Použiť značky", + "ApplyTagsHelpTexts3": "Odobrať: Odoberie zadané značky", + "AreYouSureYouWantToResetYourAPIKey": "Naozaj chcete obnoviť kľúč API?", + "Authentication": "Overenie", + "Backup": "Záloha", + "BackupNow": "Zálohovať teraz", + "Backups": "Zálohy", + "BeforeUpdate": "Pred aktualizáciou", + "BindAddressHelpText": "Platná adresa IP4 alebo '*' pre všetky rozhrania", + "Branch": "Vetva", + "BypassProxyForLocalAddresses": "Obísť proxy pre miestne adresy", + "Cancel": "Zrušiť", + "About": "O", + "AcceptConfirmationModal": "Akceptujte potvrdenie Modal", + "AppDataLocationHealthCheckMessage": "Aktualizácia nebude možná, aby sa predišlo zmazaniu AppData v priebehu aktualizácie", + "ApplyTagsHelpTexts4": "Nahradiť: Nahradí značky zadanými značkami (pre vymazanie všetkých značiek, nezadávajte žiadne)", + "Automatic": "Automatický", + "AutomaticSearch": "Automatické vyhľadávanie", + "BackupIntervalHelpText": "Interval medzi automatickými zálohami", + "BackupRetentionHelpText": "Automatické zálohy staršie než doba uchovania budú automaticky vyčistené", + "BranchUpdateMechanism": "Vetva používaná externým mechanizmom aktualizácie" +} From f0f2c88c4a413993c727d9a10dd4cc4c1cab49dc Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 15 Sep 2021 22:03:36 -0500 Subject: [PATCH 0074/2320] Fixed: (qBittorrent) Don't fail if remove torrents is enabled We don't care about this in Prowlarr Fixes #499 --- .../Download/Clients/QBittorrent/QBittorrent.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs index 3330f01a9..70d17228b 100644 --- a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs @@ -214,16 +214,6 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent DetailedDescription = "Prowlarr will not attempt to import completed downloads without a category." }; } - - // Complain if qBittorrent is configured to remove torrents on max ratio - var config = Proxy.GetConfig(Settings); - if ((config.MaxRatioEnabled || config.MaxSeedingTimeEnabled) && (config.MaxRatioAction == QBittorrentMaxRatioAction.Remove || config.MaxRatioAction == QBittorrentMaxRatioAction.DeleteFiles)) - { - return new NzbDroneValidationFailure(string.Empty, "qBittorrent is configured to remove torrents when they reach their Share Ratio Limit") - { - DetailedDescription = "Prowlarr will be unable to perform Completed Download Handling as configured. You can fix this in qBittorrent ('Tools -> Options...' in the menu) by changing 'Options -> BitTorrent -> Share Ratio Limiting' from 'Remove them' to 'Pause them'." - }; - } } catch (DownloadClientAuthenticationException ex) { From dbbc91380920c203514d536f5c4ace527ac391b4 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 8 Sep 2021 15:36:14 -0500 Subject: [PATCH 0075/2320] New: (InternetArchive) Add Support for TV Categories ref API docs `movies: any item where the main media content is video files, like mpeg, mov, avi, etc` --- src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs b/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs index 91e01dded..0e1710969 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs @@ -71,10 +71,12 @@ namespace NzbDrone.Core.Indexers.Definitions }; // c.f. https://archive.org/services/docs/api/metadata-schema/index.html?highlight=mediatype#mediatype + // "Movies" is a catch all category for videos caps.Categories.AddCategoryMapping("texts", NewznabStandardCategory.Books); caps.Categories.AddCategoryMapping("etree", NewznabStandardCategory.Audio); caps.Categories.AddCategoryMapping("audio", NewznabStandardCategory.Audio); caps.Categories.AddCategoryMapping("movies", NewznabStandardCategory.Movies); + caps.Categories.AddCategoryMapping("movies", NewznabStandardCategory.TV); caps.Categories.AddCategoryMapping("software", NewznabStandardCategory.PC); caps.Categories.AddCategoryMapping("image", NewznabStandardCategory.OtherMisc); caps.Categories.AddCategoryMapping("data", NewznabStandardCategory.Other); From 063083a1f1a9f1d5dc2de6b5ae27aba09f0a9e3e Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 23 Sep 2021 20:28:22 -0500 Subject: [PATCH 0076/2320] Fixed: Search from header on Search Page Fixes #511 --- frontend/src/Search/SearchFooter.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/src/Search/SearchFooter.js b/frontend/src/Search/SearchFooter.js index a69ff04c6..4468e80f8 100644 --- a/frontend/src/Search/SearchFooter.js +++ b/frontend/src/Search/SearchFooter.js @@ -52,6 +52,7 @@ class SearchFooter extends Component { isFetching, defaultIndexerIds, defaultCategories, + defaultSearchQuery, searchError } = this.props; @@ -62,6 +63,10 @@ class SearchFooter extends Component { const newState = {}; + if (defaultSearchQuery && defaultSearchQuery !== prevProps.defaultSearchQuery) { + newState.searchQuery = defaultSearchQuery; + } + if (searchIndexerIds !== defaultIndexerIds) { newState.searchIndexerIds = defaultIndexerIds; } From 40c49bce9b88f6e277b5524fa34356da0f5a9390 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 23 Sep 2021 20:42:17 -0500 Subject: [PATCH 0077/2320] Fixed: Spinning of Test All Indexer icon #507 --- frontend/src/Components/SignalRConnector.js | 4 ++-- frontend/src/Indexer/Index/IndexerIndex.js | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/frontend/src/Components/SignalRConnector.js b/frontend/src/Components/SignalRConnector.js index c4766d149..5e3265cdf 100644 --- a/frontend/src/Components/SignalRConnector.js +++ b/frontend/src/Components/SignalRConnector.js @@ -168,9 +168,9 @@ class SignalRConnector extends Component { this.props.dispatchFetchIndexerStatus(); } - handleMovie = (body) => { + handleIndexer = (body) => { const action = body.action; - const section = 'movies'; + const section = 'indexers'; if (action === 'updated') { this.props.dispatchUpdateItem({ section, ...body.resource }); diff --git a/frontend/src/Indexer/Index/IndexerIndex.js b/frontend/src/Indexer/Index/IndexerIndex.js index 2fbcea39b..883a34f55 100644 --- a/frontend/src/Indexer/Index/IndexerIndex.js +++ b/frontend/src/Indexer/Index/IndexerIndex.js @@ -270,6 +270,7 @@ class IndexerIndex extends Component { isSaving, saveError, isDeleting, + isTestingAll, deleteError, onScroll, onSortSelect, @@ -310,7 +311,7 @@ class IndexerIndex extends Component { <PageToolbarButton label={'Test All Indexers'} iconName={icons.TEST} - spinningName={icons.TEST} + isSpinning={isTestingAll} isDisabled={hasNoIndexer} onPress={this.props.onTestAllPress} /> @@ -489,6 +490,7 @@ IndexerIndex.propTypes = { isSaving: PropTypes.bool.isRequired, saveError: PropTypes.object, isDeleting: PropTypes.bool.isRequired, + isTestingAll: PropTypes.bool.isRequired, deleteError: PropTypes.object, onSortSelect: PropTypes.func.isRequired, onFilterSelect: PropTypes.func.isRequired, From 5a3d429d52f762316a90e62c302d2ca72127ccd3 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 25 Aug 2021 23:54:36 -0400 Subject: [PATCH 0078/2320] Remove unused MovieMonitor input --- .../src/Components/Form/FormInputGroup.js | 4 -- .../Form/MovieMonitoredSelectInput.js | 52 ------------------- 2 files changed, 56 deletions(-) delete mode 100644 frontend/src/Components/Form/MovieMonitoredSelectInput.js diff --git a/frontend/src/Components/Form/FormInputGroup.js b/frontend/src/Components/Form/FormInputGroup.js index f95cd40bf..7bc031c9e 100644 --- a/frontend/src/Components/Form/FormInputGroup.js +++ b/frontend/src/Components/Form/FormInputGroup.js @@ -16,7 +16,6 @@ import FormInputHelpText from './FormInputHelpText'; import IndexerFlagsSelectInputConnector from './IndexerFlagsSelectInputConnector'; import InfoInput from './InfoInput'; import KeyValueListInput from './KeyValueListInput'; -import MovieMonitoredSelectInput from './MovieMonitoredSelectInput'; import NumberInput from './NumberInput'; import OAuthInputConnector from './OAuthInputConnector'; import PasswordInput from './PasswordInput'; @@ -69,9 +68,6 @@ function getComponent(type) { case inputTypes.PATH: return PathInputConnector; - case inputTypes.MOVIE_MONITORED_SELECT: - return MovieMonitoredSelectInput; - case inputTypes.INDEXER_FLAGS_SELECT: return IndexerFlagsSelectInputConnector; diff --git a/frontend/src/Components/Form/MovieMonitoredSelectInput.js b/frontend/src/Components/Form/MovieMonitoredSelectInput.js deleted file mode 100644 index 2e0139780..000000000 --- a/frontend/src/Components/Form/MovieMonitoredSelectInput.js +++ /dev/null @@ -1,52 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import SelectInput from './SelectInput'; - -const monitorTypesOptions = [ - { key: 'true', value: 'True' }, - { key: 'false', value: 'False' } -]; - -function MovieMonitoredSelectInput(props) { - const values = [...monitorTypesOptions]; - - const { - includeNoChange, - includeMixed - } = props; - - if (includeNoChange) { - values.unshift({ - key: 'noChange', - value: 'No Change', - disabled: true - }); - } - - if (includeMixed) { - values.unshift({ - key: 'mixed', - value: '(Mixed)', - disabled: true - }); - } - - return ( - <SelectInput - {...props} - values={values} - /> - ); -} - -MovieMonitoredSelectInput.propTypes = { - includeNoChange: PropTypes.bool.isRequired, - includeMixed: PropTypes.bool.isRequired -}; - -MovieMonitoredSelectInput.defaultProps = { - includeNoChange: false, - includeMixed: false -}; - -export default MovieMonitoredSelectInput; From 34a09af01e1e13cb65e37179b29d4916726facd2 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 3 Sep 2021 14:50:03 -0400 Subject: [PATCH 0079/2320] New: Advanced settings for Application category control --- .../Components/Form/ProviderFieldFormGroup.js | 3 +- src/NzbDrone.Core/Annotations/SelectOption.cs | 1 + .../Applications/Lidarr/LidarrSettings.cs | 6 ++- .../Applications/Mylar/MylarSettings.cs | 6 ++- .../Applications/Radarr/RadarrSettings.cs | 7 +++- .../Applications/Readarr/ReadarrSettings.cs | 7 +++- .../Applications/Sonarr/SonarrSettings.cs | 10 +++-- .../Indexers/NewznabCategoryFieldConverter.cs | 40 +++++++++++++++++++ 8 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 src/NzbDrone.Core/Indexers/NewznabCategoryFieldConverter.cs diff --git a/frontend/src/Components/Form/ProviderFieldFormGroup.js b/frontend/src/Components/Form/ProviderFieldFormGroup.js index 3a9a2f5a5..89b54369b 100644 --- a/frontend/src/Components/Form/ProviderFieldFormGroup.js +++ b/frontend/src/Components/Form/ProviderFieldFormGroup.js @@ -53,7 +53,8 @@ function getSelectValues(selectOptions) { result.push({ key: option.value, value: option.name, - hint: option.hint + hint: option.hint, + parentKey: option.parentValue }); return result; diff --git a/src/NzbDrone.Core/Annotations/SelectOption.cs b/src/NzbDrone.Core/Annotations/SelectOption.cs index feef0c342..0460c86e8 100644 --- a/src/NzbDrone.Core/Annotations/SelectOption.cs +++ b/src/NzbDrone.Core/Annotations/SelectOption.cs @@ -6,5 +6,6 @@ namespace NzbDrone.Core.Annotations public string Name { get; set; } public int Order { get; set; } public string Hint { get; set; } + public int? ParentValue { get; set; } } } diff --git a/src/NzbDrone.Core/Applications/Lidarr/LidarrSettings.cs b/src/NzbDrone.Core/Applications/Lidarr/LidarrSettings.cs index c73df32ab..d1b341529 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/LidarrSettings.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/LidarrSettings.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using FluentValidation; using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Applications.Lidarr @@ -26,8 +27,6 @@ namespace NzbDrone.Core.Applications.Lidarr SyncCategories = new[] { 3000, 3010, 3030, 3040, 3050, 3060 }; } - public IEnumerable<int> SyncCategories { get; set; } - [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Lidarr sees it, including http(s)://, port, and urlbase if needed")] public string ProwlarrUrl { get; set; } @@ -37,6 +36,9 @@ namespace NzbDrone.Core.Applications.Lidarr [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Lidarr in Settings/General")] public string ApiKey { get; set; } + [FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")] + public IEnumerable<int> SyncCategories { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs b/src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs index 250316528..1b2c38c36 100644 --- a/src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs +++ b/src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs @@ -13,6 +13,7 @@ namespace NzbDrone.Core.Applications.Mylar RuleFor(c => c.BaseUrl).IsValidUrl(); RuleFor(c => c.ProwlarrUrl).IsValidUrl(); RuleFor(c => c.ApiKey).NotEmpty(); + RuleFor(c => c.SyncCategories).NotEmpty(); } } @@ -27,8 +28,6 @@ namespace NzbDrone.Core.Applications.Mylar SyncCategories = new[] { NewznabStandardCategory.BooksComics.Id }; } - public IEnumerable<int> SyncCategories { get; set; } - [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Mylar sees it, including http(s)://, port, and urlbase if needed")] public string ProwlarrUrl { get; set; } @@ -38,6 +37,9 @@ namespace NzbDrone.Core.Applications.Mylar [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Mylar in Settings/Web Interface")] public string ApiKey { get; set; } + [FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")] + public IEnumerable<int> SyncCategories { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Applications/Radarr/RadarrSettings.cs b/src/NzbDrone.Core/Applications/Radarr/RadarrSettings.cs index 9e7d25946..08e9f6a69 100644 --- a/src/NzbDrone.Core/Applications/Radarr/RadarrSettings.cs +++ b/src/NzbDrone.Core/Applications/Radarr/RadarrSettings.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using FluentValidation; using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Applications.Radarr @@ -12,6 +13,7 @@ namespace NzbDrone.Core.Applications.Radarr RuleFor(c => c.BaseUrl).IsValidUrl(); RuleFor(c => c.ProwlarrUrl).IsValidUrl(); RuleFor(c => c.ApiKey).NotEmpty(); + RuleFor(c => c.SyncCategories).NotEmpty(); } } @@ -26,8 +28,6 @@ namespace NzbDrone.Core.Applications.Radarr SyncCategories = new[] { 2000, 2010, 2020, 2030, 2040, 2045, 2050, 2060, 2070, 2080 }; } - public IEnumerable<int> SyncCategories { get; set; } - [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Radarr sees it, including http(s)://, port, and urlbase if needed")] public string ProwlarrUrl { get; set; } @@ -37,6 +37,9 @@ namespace NzbDrone.Core.Applications.Radarr [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Radarr in Settings/General")] public string ApiKey { get; set; } + [FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")] + public IEnumerable<int> SyncCategories { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Applications/Readarr/ReadarrSettings.cs b/src/NzbDrone.Core/Applications/Readarr/ReadarrSettings.cs index c159ea0ad..7c97fa0d6 100644 --- a/src/NzbDrone.Core/Applications/Readarr/ReadarrSettings.cs +++ b/src/NzbDrone.Core/Applications/Readarr/ReadarrSettings.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using FluentValidation; using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Applications.Readarr @@ -12,6 +13,7 @@ namespace NzbDrone.Core.Applications.Readarr RuleFor(c => c.BaseUrl).IsValidUrl(); RuleFor(c => c.ProwlarrUrl).IsValidUrl(); RuleFor(c => c.ApiKey).NotEmpty(); + RuleFor(c => c.SyncCategories).NotEmpty(); } } @@ -26,8 +28,6 @@ namespace NzbDrone.Core.Applications.Readarr SyncCategories = new[] { 3030, 7000, 7010, 7020, 7030, 7040, 7050, 7060 }; } - public IEnumerable<int> SyncCategories { get; set; } - [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Readarr sees it, including http(s)://, port, and urlbase if needed")] public string ProwlarrUrl { get; set; } @@ -37,6 +37,9 @@ namespace NzbDrone.Core.Applications.Readarr [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Readarr in Settings/General")] public string ApiKey { get; set; } + [FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")] + public IEnumerable<int> SyncCategories { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs b/src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs index 0ab030ca4..26c2b90df 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using FluentValidation; using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Applications.Sonarr @@ -27,9 +28,6 @@ namespace NzbDrone.Core.Applications.Sonarr AnimeSyncCategories = new[] { 5070 }; } - public IEnumerable<int> SyncCategories { get; set; } - public IEnumerable<int> AnimeSyncCategories { get; set; } - [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Sonarr sees it, including http(s)://, port, and urlbase if needed")] public string ProwlarrUrl { get; set; } @@ -39,6 +37,12 @@ namespace NzbDrone.Core.Applications.Sonarr [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Sonarr in Settings/General")] public string ApiKey { get; set; } + [FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")] + public IEnumerable<int> SyncCategories { get; set; } + + [FieldDefinition(4, Label = "Anime Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")] + public IEnumerable<int> AnimeSyncCategories { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/NewznabCategoryFieldConverter.cs b/src/NzbDrone.Core/Indexers/NewznabCategoryFieldConverter.cs new file mode 100644 index 000000000..b6484d908 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/NewznabCategoryFieldConverter.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Linq; +using NzbDrone.Core.Annotations; + +namespace NzbDrone.Core.Indexers +{ + public class NewznabCategoryFieldConverter : ISelectOptionsConverter + { + public List<SelectOption> GetSelectOptions() + { + var result = new List<SelectOption>(); + + foreach (var category in NewznabStandardCategory.ParentCats) + { + result.Add(new SelectOption + { + Value = category.Id, + Name = category.Name, + Hint = $"({category.Id})" + }); + + if (category.SubCategories != null) + { + foreach (var subcat in category.SubCategories.OrderBy(cat => cat.Id)) + { + result.Add(new SelectOption + { + Value = subcat.Id, + Name = subcat.Name, + Hint = $"({subcat.Id})", + ParentValue = category.Id + }); + } + } + } + + return result; + } + } +} From 87650c83c6122c1a5ce6cc3585d30405be117788 Mon Sep 17 00:00:00 2001 From: Jayson Reis <santosdosreis@gmail.com> Date: Sun, 26 Sep 2021 05:03:42 +0200 Subject: [PATCH 0080/2320] New: (Indexer) lat-team.com (#505) * New: (Indexer) Torrent lat-team.com * Add lat-team to ignore definitions list * Fix lat-team name --- .../IndexerDefinitionUpdateService.cs | 3 +- .../Indexers/Definitions/LatTeam.cs | 51 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 src/NzbDrone.Core/Indexers/Definitions/LatTeam.cs diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index 33e5eb487..8f861e017 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -35,7 +35,8 @@ namespace NzbDrone.Core.IndexerVersions "danishbytes", "desitorrents", "hdbits", - "shareisland" + "shareisland", + "lat-team" }; private readonly IHttpClient _httpClient; diff --git a/src/NzbDrone.Core/Indexers/Definitions/LatTeam.cs b/src/NzbDrone.Core/Indexers/Definitions/LatTeam.cs new file mode 100644 index 000000000..9874e8338 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/LatTeam.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using NLog; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Definitions.UNIT3D; +using NzbDrone.Core.Messaging.Events; + +namespace NzbDrone.Core.Indexers.Definitions +{ + public class LatTeam : Unit3dBase + { + public override string Name => "Lat-Team"; + public override string Language => "es"; + public override string[] IndexerUrls => new[] { "https://lat-team.com/" }; + public override string Description => "Lat-Team is a Private Torrent Tracker for HD MOVIES / TV"; + public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + + public LatTeam(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) + { + } + + protected override IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities + { + TvSearchParams = new List<TvSearchParam> + { + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId + }, + MovieSearchParams = new List<MovieSearchParam> + { + MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId + }, + MusicSearchParams = new List<MusicSearchParam> + { + MusicSearchParam.Q + }, + }; + + caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Peliculas"); + caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.MoviesOther, "Retro Pelicula"); + caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.TVAnime, "Anime"); + caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "TV Series"); + caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.TVOther, "Retro Serie TV"); + caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.TVForeign, "Telenovelas y Teleseries"); + caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Musica"); + + return caps; + } + } +} From 2e56b7681e7cfcdbf42e44d2b145dff64bdb6d36 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sat, 25 Sep 2021 13:47:01 +0000 Subject: [PATCH 0081/2320] Translated using Weblate (Dutch) Currently translated at 100.0% (441 of 441 strings) Translated using Weblate (Bulgarian) Currently translated at 10.2% (45 of 441 strings) Translated using Weblate (Korean) Currently translated at 17.9% (79 of 441 strings) Translated using Weblate (Spanish) Currently translated at 76.1% (336 of 441 strings) Co-authored-by: COTMO <moermantom1@gmail.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: eslifos <eaaf_01@hotmail.com> Co-authored-by: keysuck <joshkkim@gmail.com> Co-authored-by: siankatabg <siankata91@gmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/bg/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ko/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/bg.json | 74 +++++++++++++- src/NzbDrone.Core/Localization/Core/es.json | 2 +- src/NzbDrone.Core/Localization/Core/ko.json | 82 +++++++++++++++- src/NzbDrone.Core/Localization/Core/nl.json | 103 ++++++++++++++++++-- 4 files changed, 250 insertions(+), 11 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/bg.json b/src/NzbDrone.Core/Localization/Core/bg.json index 0967ef424..99af5a167 100644 --- a/src/NzbDrone.Core/Localization/Core/bg.json +++ b/src/NzbDrone.Core/Localization/Core/bg.json @@ -1 +1,73 @@ -{} +{ + "Actions": "Действия", + "Added": "Добавено", + "ApiKey": "API ключ", + "Apply": "Приложи", + "DeleteBackup": "Изтриване на резервно копие", + "Add": "Добавяне", + "AddIndexer": "Добавете Indexer", + "Age": "Възраст", + "BranchUpdateMechanism": "Клон, използван от външен механизъм за актуализация", + "Cancel": "Отказ", + "Component": "Съставна част", + "ConnectionLost": "Изгубена връзка", + "Details": "Подробности", + "DownloadClient": "Клиент за изтегляне", + "AppDataDirectory": "Директория на AppData", + "Authentication": "Удостоверяване", + "Branch": "Клон", + "ApplyTagsHelpTexts2": "Добавяне: Добавете маркерите към съществуващия списък с маркери", + "ApplyTagsHelpTexts3": "Премахване: Премахнете въведените тагове", + "AppDataLocationHealthCheckMessage": "Актуализирането няма да е възможно, за да се предотврати изтриването на AppData при актуализация", + "ApplyTags": "Прилагане на тагове", + "ApplyTagsHelpTexts4": "Замяна: Заменете маркерите с въведените маркери (не въвеждайте маркери, за да изчистите всички маркери)", + "Automatic": "Автоматично", + "AutomaticSearch": "Автоматично търсене", + "Backup": "Архивиране", + "BackupFolderHelpText": "Относителните пътища ще бъдат в директорията AppData на Prowlarr", + "BackupIntervalHelpText": "Интервал между автоматичните архиви", + "BackupNow": "Архивиране сега", + "ChangeHasNotBeenSavedYet": "", + "Backups": "Архиви", + "BeforeUpdate": "Преди актуализация", + "CancelPendingTask": "Наистина ли искате да отмените тази чакаща задача?", + "BindAddress": "Адрес за обвързване", + "CertificateValidation": "Валидиране на сертификат", + "ConnectSettings": "Настройки за свързване", + "Custom": "Персонализиран", + "CustomFilters": "Персонализирани филтри", + "Date": "Дата", + "Dates": "Дати", + "DBMigration": "DB миграция", + "Delete": "Изтрий", + "DeleteDownloadClient": "Изтриване на клиент за изтегляне", + "DeleteDownloadClientMessageText": "Наистина ли искате да изтриете клиента за изтегляне '{0}'?", + "DeleteIndexer": "Изтрийте Indexer", + "DeleteNotification": "Изтриване на известието", + "DeleteNotificationMessageText": "Наистина ли искате да изтриете известието '{0}'?", + "Donations": "Дарения", + "DownloadClientCheckUnableToCommunicateMessage": "Не може да се комуникира с {0}.", + "About": "относно", + "AcceptConfirmationModal": "Приемете модал за потвърждение", + "AddDownloadClient": "Добавяне на клиент за изтегляне", + "AddingTag": "Добавяне на таг", + "All": "всичко", + "Analytics": "Анализ", + "AnalyticsEnabledHelpText": "Изпращайте анонимна информация за използването и грешките до сървърите на Prowlarr. Това включва информация за вашия браузър, кои страници на Prowlarr WebUI използвате, отчитане на грешки, както и версията на операционната система и времето за изпълнение. Ще използваме тази информация, за да дадем приоритет на функциите и корекциите на грешки.", + "AreYouSureYouWantToResetYourAPIKey": "Наистина ли искате да нулирате своя API ключ?", + "AuthenticationMethodHelpText": "Изисквайте потребителско име и парола за достъп до Prowlarr", + "BackupRetentionHelpText": "Автоматичните архиви, по-стари от периода на съхранение, ще бъдат почистени автоматично", + "BindAddressHelpText": "Валиден IP4 адрес или '*' за всички интерфейси", + "BypassProxyForLocalAddresses": "Заобикаляне на прокси за локални адреси", + "CertificateValidationHelpText": "Променете колко строго е валидирането на HTTPS сертифициране", + "Clear": "Ясно", + "ClientPriority": "Приоритет на клиента", + "ConnectionLostAutomaticMessage": "Prowlarr ще се опита да се свърже автоматично или можете да щракнете върху презареждане по-долу.", + "Connections": "Връзки", + "CouldNotConnectSignalR": "Не можах да се свържа със SignalR, потребителският интерфейс няма да се актуализира", + "DeleteBackupMessageText": "Наистина ли искате да изтриете резервното копие '{0}'?", + "DeleteIndexerMessageText": "Наистина ли искате да изтриете индексатора '{0}'?", + "DeleteTag": "Изтриване на маркера", + "DeleteTagMessageText": "Наистина ли искате да изтриете маркера '{0}'?", + "DownloadClientCheckNoneAvailableMessage": "Няма наличен клиент за изтегляне" +} diff --git a/src/NzbDrone.Core/Localization/Core/es.json b/src/NzbDrone.Core/Localization/Core/es.json index 6dfc95431..335cae12c 100644 --- a/src/NzbDrone.Core/Localization/Core/es.json +++ b/src/NzbDrone.Core/Localization/Core/es.json @@ -53,7 +53,7 @@ "Cast": "Reparto", "Calendar": "Calendario", "Blacklist": "Bloqueadas", - "BackupNow": "Backup Ahora", + "BackupNow": "Hacer copia de seguridad", "Backup": "Backup", "AppDataLocationHealthCheckMessage": "No será posible actualizar para prevenir que AppData se borre durante la actualización", "AndNot": "y no", diff --git a/src/NzbDrone.Core/Localization/Core/ko.json b/src/NzbDrone.Core/Localization/Core/ko.json index 0967ef424..8ab7b76e1 100644 --- a/src/NzbDrone.Core/Localization/Core/ko.json +++ b/src/NzbDrone.Core/Localization/Core/ko.json @@ -1 +1,81 @@ -{} +{ + "ChangeHasNotBeenSavedYet": "변경 사항이 아직 저장되지 않았습니다.", + "DownloadClientUnavailable": "다운로드 클라이언트를 사용할 수 없습니다.", + "Downloading": "다운로드 중", + "ConnectionLost": "연결이 끊어졌습니다.", + "Dates": "날짜", + "DeleteBackup": "백업 삭제", + "About": "정보", + "Actions": "동작", + "Analytics": "분석", + "ApiKey": "API 키", + "AppDataDirectory": "AppData 디렉토리", + "AcceptConfirmationModal": "확인 모달 수락", + "Added": "추가됨", + "AddIndexer": "인덱서 추가", + "AddingTag": "태그 추가", + "Age": "연령", + "All": "모두", + "DownloadClients": "클라이언트 다운로드", + "AddDownloadClient": "다운로드 클라이언트 추가", + "DeleteTag": "태그 삭제", + "ConnectSettings": "연결 설정", + "CloneIndexer": "인덱서 복제", + "CloneProfile": "프로필 복제", + "Close": "닫기", + "CloseCurrentModal": "현재 모달 닫기", + "Columns": "열", + "Component": "구성 요소", + "Connections": "연결", + "CouldNotConnectSignalR": "SignalR에 연결할 수 없습니다. UI가 업데이트되지 않습니다.", + "Custom": "사용자 지정", + "DBMigration": "DB 마이그레이션", + "DelayProfile": "지연 프로필", + "DeleteBackupMessageText": "백업 '{0}'을(를) 삭제하시겠습니까?", + "BackupNow": "지금 백업", + "Authentication": "인증", + "ApplyTags": "태그 적용", + "ApplyTagsHelpTexts4": "바꾸기 : 태그를 입력 한 태그로 바꿉니다 (모든 태그를 지우려면 태그를 입력하지 않음)", + "Automatic": "자동", + "AutomaticSearch": "자동 검색", + "Backup": "백업", + "BackupIntervalHelpText": "자동 백업 간격", + "BackupRetentionHelpText": "보존 기간보다 오래된 자동 백업은 자동으로 정리됩니다.", + "Backups": "백업", + "BeforeUpdate": "업데이트 전", + "BindAddress": "바인드 주소", + "BindAddressHelpText": "모든 인터페이스에 유효한 IP4 주소 또는 '*'", + "BypassProxyForLocalAddresses": "로컬 주소에 대한 프록시 우회", + "Cancel": "취소", + "CancelPendingTask": "이 보류 중인 작업을 취소하시겠습니까?", + "Delete": "삭제", + "DeleteDownloadClient": "다운로드 클라이언트 삭제", + "DeleteIndexer": "인덱서 삭제", + "DeleteIndexerMessageText": "인덱서 '{0}'을(를) 삭제하시겠습니까?", + "DeleteTagMessageText": "'{0}' 태그를 삭제하시겠습니까?", + "Details": "세부 정보", + "Disabled": "비활성화됨", + "Docker": "Docker", + "Donations": "기부", + "DownloadClient": "클라이언트 다운로드", + "DownloadClientCheckNoneAvailableMessage": "사용 가능한 다운로드 클라이언트가 없습니다.", + "DownloadClientSettings": "클라이언트 설정 다운로드", + "DownloadClientStatusCheckAllClientMessage": "실패로 인해 모든 다운로드 클라이언트를 사용할 수 없습니다.", + "Add": "추가", + "Apply": "적용", + "ApplyTagsHelpTexts3": "제거 : 입력한 태그를 제거합니다.", + "AppDataLocationHealthCheckMessage": "업데이트 시 AppData 삭제를 방지하기 위해 업데이트 할 수 없습니다.", + "AreYouSureYouWantToResetYourAPIKey": "API 키를 재설정하시겠습니까?", + "BranchUpdateMechanism": "외부 업데이트 메커니즘에서 사용하는 파생 버전", + "CertificateValidation": "인증서 검증", + "CertificateValidationHelpText": "HTTPS 인증 유효성 검사의 엄격한 방법 변경", + "Clear": "지우기", + "ClientPriority": "클라이언트 우선 순위", + "CustomFilters": "사용자 지정 필터", + "Date": "날짜", + "DeleteDownloadClientMessageText": "다운로드 클라이언트 '{0}'을(를) 삭제하시겠습니까?", + "DeleteNotification": "알림 삭제", + "DeleteNotificationMessageText": "알림 '{0}'을(를) 삭제하시겠습니까?", + "DownloadClientCheckUnableToCommunicateMessage": "{0}와(과) 통신할 수 없습니다.", + "DownloadClientStatusCheckSingleClientMessage": "실패로 인해 다운 불러올 수 없는 클라이언트 : {0}" +} diff --git a/src/NzbDrone.Core/Localization/Core/nl.json b/src/NzbDrone.Core/Localization/Core/nl.json index f83a43cd8..f5e7cb43f 100644 --- a/src/NzbDrone.Core/Localization/Core/nl.json +++ b/src/NzbDrone.Core/Localization/Core/nl.json @@ -48,7 +48,7 @@ "CustomFilters": "Aangepaste Filters", "Crew": "Filmploeg", "Connections": "Connecties", - "Connect": "Connecties", + "Connect": "Meldingen", "CompletedDownloadHandling": "Voltooide Download Afhandeling", "Clear": "Wissen", "ChooseAnotherFolder": "Kies een andere map", @@ -163,7 +163,7 @@ "MonoTlsCheckMessage": "Tijdelijke Prowlarr Mono 4.x TLS oplossing nog steeds ingeschakeld, overweeg de MONO_TLS_PROVIDER=legacy omgevingsvariabele te verwijderen", "Wanted": "Gezocht", "UpdateSelected": "Selectie Bijwerken", - "UISettingsSummary": "Kalender, datum en tijd, kleurenblindheid en taal instellingen", + "UISettingsSummary": "Datum, kleurenblindheid en taal instellingen", "Timeleft": "Resterende Tijd", "TagsSettingsSummary": "Bekijk alle tags en hun gebruik. Ongebruikte tags kunnen worden verwijderd", "SourceTitle": "Bron Titel", @@ -199,14 +199,14 @@ "Filename": "Bestandsnaam", "Failed": "Mislukt", "EventType": "Gebeurtenis Type", - "DownloadClientsSettingsSummary": "Download applicaties, download afhandeling en externe pad verwijzing", + "DownloadClientsSettingsSummary": "Clientconfiguratie downloaden voor integratie in Prowlarr UI-zoekopdracht", "DownloadClient": "Downloader", "DigitalRelease": "Digitale Uitgave", "Details": "Details", "Deleted": "Verwijderd", "CutoffUnmet": "Onbereikte Drempel", "CustomFormatsSettingsSummary": "Eigen Formaten en instellingen", - "ConnectSettingsSummary": "Notificaties, connecties met media servers/spelers en scripts", + "ConnectSettingsSummary": "Meldingen en aangepaste scripts", "Collection": "Collectie", "Certification": "Certificatie", "Added": "Toegevoegd", @@ -749,7 +749,7 @@ "RegularExpressionsCanBeTested": "Reguliere expressies kunnen worden getest ", "ProwlarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "Prowlarr ondersteunt aangepaste condities tegenover de uitgave eigenschappen hieronder.", "ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "Prowlarr ondersteunt elke RSS filmlijst, tevens ook de ander hieronder weergegeven lijsten.", - "ProwlarrSupportsAnyIndexer": "Prowlarr ondersteund elke indexeerder die gebruik maakt van de Newznab standaard, tevens ook de ander hieronder weergegeven indexeerders.", + "ProwlarrSupportsAnyIndexer": "Prowlarr ondersteunt veel indexeerders naast elke indexeerder die de Newznab/Torznab-standaard gebruikt met 'Generic Newznab' (voor usenet) of 'Generic Torznab' (voor torrents). Zoek en selecteer uw indexeerder hieronder.", "ProwlarrSupportsAnyDownloadClient": "Prowlarr ondersteund elke downloader die gebruik maakt van de Newznab standaard, tevens ook de ander hieronder weergegeven downloaders.", "NoTagsHaveBeenAddedYet": "Er zijn nog geen tags toegevoegd", "MissingMonitoredAndConsideredAvailable": "Ontbrekend, Bewaakt en beschouwd als Beschikbaar", @@ -790,7 +790,7 @@ "LoadingMovieCreditsFailed": "Laden van film aftiteling mislukt", "LinkHere": "hier", "IgnoredPlaceHolder": "Voeg nieuwe restrictie toe", - "FilterPlaceHolder": "Zoek films", + "FilterPlaceHolder": "Zoek indexeerder", "ExtraFileExtensionsHelpTexts2": "Voorbeelden: '.sub, .nfo' of 'sub,nfo'", "Excluded": "Uitgezonderd", "Exception": "Uitzondering", @@ -848,11 +848,98 @@ "ClearHistory": "Geschiedenis verwijderen", "ApplicationStatusCheckSingleClientMessage": "Applicaties niet toegankelijk door fouten", "ApplicationStatusCheckAllClientMessage": "Alle applicaties niet toegankelijk door fouten", - "AllIndexersHiddenDueToFilter": "Alle Indexeerders zijn verborgen door actieve filter", + "AllIndexersHiddenDueToFilter": "Alle indexeerders zijn verborgen door actieve filter", "AddToDownloadClient": "Release toevoegen aan download client", "AddNewIndexer": "Voeg nieuwe Indexeerder Toe", "AddedToDownloadClient": "Release toegevoegd aan client", "PrioritySettings": "Prioriteit", "AddDownloadClient": "Download Client Toevoegen", - "Add": "Toevoegen" + "Add": "Toevoegen", + "Applications": "Applicaties", + "AddRemoveOnly": "Alleen toevoegen en verwijderen", + "DeleteAppProfile": "App-profiel verwijderen", + "Discord": "Discord", + "Query": "Vraag", + "IndexerVipCheckExpiringClientMessage": "Indexeerder VIP-voordelen verlopen binnenkort: {0}", + "NoLinks": "Geen koppelingen", + "Privacy": "Privacy", + "RedirectHelpText": "Leid inkomend downloadverzoek voor indexeerder om en geef de grijper direct door in plaats van het verzoek via Prowlarr te proxyen", + "SettingsLogSql": "Log Sql", + "SettingsSqlLoggingHelpText": "Log alle SQL-query's van Prowlarr", + "Stats": "Statistieken", + "SyncLevel": "Synchronisatieniveau", + "Torrent": "Torrent", + "UnableToAddANewApplicationPleaseTryAgain": "Kan geen nieuwe toepassing toevoegen, probeer het opnieuw.", + "UnableToAddANewAppProfilePleaseTryAgain": "Kan geen nieuw applicatieprofiel toevoegen. Probeer het opnieuw.", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Kan geen nieuwe Indexeerder-proxy toevoegen. Probeer het opnieuw.", + "UnableToLoadAppProfiles": "Kan app-profielen niet laden", + "UnableToLoadDevelopmentSettings": "Kan ontwikkelingsinstellingen niet laden", + "UnableToLoadIndexerProxies": "Kan Indexeerder-proxy's niet laden", + "AppProfile": "App-profiel", + "SettingsFilterSentryEventsHelpText": "Filter bekende gebruikersfoutgebeurtenissen zodat ze niet als Analytiek worden verzonden", + "HomePage": "Startpagina", + "IndexerProxies": "Indexer-proxy's", + "IndexerObsoleteCheckMessage": "Indexeerders zijn verouderd of zijn bijgewerkt: {0}. Gelieve te verwijderen en (of) opnieuw toe te voegen aan Prowlarr", + "SettingsIndexerLogging": "Verbeterde logboekregistratie van Indexeerder", + "EnableRss": "RSS inschakelen", + "Reddit": "Reddit", + "Apps": "Applicaties", + "Auth": "Authenticatie", + "Custom": "Aangepast", + "DevelopmentSettings": "Ontwikkelingsinstellingen", + "Description": "Beschrijving", + "Donations": "Donaties", + "EnableRssHelpText": "Rss-feed voor Indexer inschakelen", + "IndexersSelectedInterp": "{0} Indexer(s) Geselecteerd", + "IndexerRss": "Indexeer RSS", + "IndexerAuth": "Indexer-authenticatie", + "FeatureRequests": "Functieverzoeken", + "IndexerSettingsSummary": "Configureer verschillende globale Indexer-instellingen, waaronder proxy's.", + "OpenThisModal": "Open deze modal", + "AppProfileDeleteConfirm": "Weet u zeker dat u {0} wilt verwijderen?", + "AppSettingsSummary": "Applicaties en instellingen om te configureren hoe Prowlarr met uw PVR-programma's omgaat", + "Category": "Categorie", + "IndexerTagsHelpText": "Gebruik tags om standaardclients op te geven, Indexeerder-proxy's op te geven of gewoon om uw indexeerders te ordenen.", + "IndexerVipCheckExpiredClientMessage": "Indexeerder VIP-voordelen zijn verlopen: {0}", + "NoSearchResultsFound": "Geen zoekresultaten gevonden, probeer hieronder een nieuwe zoekopdracht.", + "Notification": "Melding", + "Notifications": "Meldingen", + "Presets": "Voorinstellingen", + "Redirect": "Omleiden", + "RSS": "RSS", + "SearchIndexers": "Zoek indexeerders", + "SettingsConsoleLogLevel": "Console-logboekniveau", + "SettingsFilterSentryEvents": "Analytics-gebeurtenissen filteren", + "SettingsIndexerLoggingHelpText": "Log aanvullende Indexeerder-gegevens inclusief reactie", + "SettingsLogRotate": "Logboekrotatie", + "SettingsLogRotateHelpText": "Maximaal aantal logbestanden om te bewaren in de logboek-map", + "SyncAppIndexers": "App-indexeerders synchroniseren", + "SyncLevelAddRemove": "Alleen toevoegen en verwijderen: wanneer het wordt toegevoegd of verwijderd uit Prowlarr, wordt deze externe app bijgewerkt.", + "SyncLevelFull": "Volledige synchronisatie: houdt deze app volledig gesynchroniseerd. Wijzigingen in Prowlarr worden vervolgens gesynchroniseerd met deze app. Elke wijziging die op afstand wordt aangebracht, wordt bij de volgende synchronisatie overschreven door Prowlarr.", + "TestAllApps": "Alle apps testen", + "Wiki": "Wiki", + "Grabs": "Gegrepen", + "NotificationTriggersHelpText": "Selecteer welke gebeurtenissen deze melding moeten activeren", + "AddAppProfile": "Profiel voor app-synchronisatie toevoegen", + "AddDownloadClientToProwlarr": "Door een downloadclient toe te voegen, kan Prowlarr releases rechtstreeks vanuit de gebruikersinterface verzenden tijdens een handmatige zoekopdracht.", + "AddIndexerProxy": "Indexeerproxy toevoegen", + "AppProfileInUse": "App-profiel in gebruik", + "AppProfiles": "App-profielen", + "AppProfileSelectHelpText": "App-profielen worden gebruikt om de instellingen voor RSS, Automatisch zoeken en Interactief zoeken bij applicatiesynchronisatie te beheren", + "CouldNotConnectSignalR": "Kan geen verbinding maken met SignalR, gebruikersinterface wordt niet bijgewerkt", + "DeleteApplication": "Applicatie verwijderen", + "DeleteApplicationMessageText": "Weet u zeker dat u de applicatie '{0}' wilt verwijderen?", + "DeleteIndexerProxy": "Indexeerproxy verwijderen", + "DeleteIndexerProxyMessageText": "Weet u zeker dat u de proxy '{0}' wilt verwijderen?", + "EditAppProfile": "App-profiel bewerken", + "Enabled": "Ingeschakeld", + "EnableIndexer": "Indexer inschakelen", + "Encoding": "Coderen", + "FullSync": "Volledige synchronisatie", + "Id": "Id", + "IndexerHealthCheckNoIndexers": "Geen indexers ingeschakeld, Prowlarr geeft geen zoekresultaten terug", + "IndexerProxy": "Indexeerder-proxy", + "IndexerProxyStatusCheckAllClientMessage": "Alle proxy's zijn niet beschikbaar vanwege storingen", + "IndexerProxyStatusCheckSingleClientMessage": "Proxy's niet beschikbaar vanwege storingen: {0}", + "IndexerQuery": "Indexeer zoekopdracht" } From e73f2466cc0d11abfbde347086a7bdc7b9faa99a Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Fri, 1 Oct 2021 15:15:26 -0500 Subject: [PATCH 0082/2320] Fixed (Headphones): Add missing description --- src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs b/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs index c6afa18f1..7b2980045 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs @@ -18,7 +18,7 @@ namespace NzbDrone.Core.Indexers.Headphones public override DownloadProtocol Protocol => DownloadProtocol.Usenet; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override string[] IndexerUrls => new string[] { "https://indexer.codeshy.com" }; - public override string Description => ""; + public override string Description => "A Private Usenet indexer for music"; public override IndexerCapabilities Capabilities => SetCapabilities(); public override IIndexerRequestGenerator GetRequestGenerator() From 1ee79f16fc40b1da626e47240028e136c51bcb29 Mon Sep 17 00:00:00 2001 From: Servarr <32001786+ServarrAdmin@users.noreply.github.com> Date: Fri, 1 Oct 2021 16:17:59 -0400 Subject: [PATCH 0083/2320] Translated using Weblate (Turkish) (#516) Currently translated at 16.5% (73 of 441 strings) Translated using Weblate (French) Currently translated at 99.7% (440 of 441 strings) Co-authored-by: Francis Peixoto <peixoto.francis@gmail.com> Co-authored-by: Micky <ad312@pm.me> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/ Translation: Servarr/Prowlarr Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Francis Peixoto <peixoto.francis@gmail.com> Co-authored-by: Micky <ad312@pm.me> --- src/NzbDrone.Core/Localization/Core/fr.json | 15 +++++++++++++-- src/NzbDrone.Core/Localization/Core/tr.json | 3 ++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index c61038ace..5a5d0e1e6 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -74,7 +74,7 @@ "UpdateCheckStartupNotWritableMessage": "Impossible d'installer la mise à jour car le dossier de démarrage '{0}' n'est pas accessible en écriture par l'utilisateur '{1}'.", "UnselectAll": "Tout déselectionner", "Unmonitored": "Non surveillé", - "UISettingsSummary": "Calendrier, date et les options d'altération des couleurs", + "UISettingsSummary": "Options de date, de langue et de contraste de couleur", "TagsSettingsSummary": "Voir toutes les tags et leur utilisation. Les tags inutilisées peuvent être supprimées", "Style": "Style", "Studio": "Studio", @@ -940,5 +940,16 @@ "AddIndexerProxy": "Ajouter proxy indexeur", "AppSettingsSummary": "Applications et paramètres pour configurer comment Prowlarr interagit avec vos programmes PVR", "IndexerTagsHelpText": "Utilisez des balises pour spécifier des clients par défaut, spécifier les proxies d'indexeur ou pour organiser vos indexeurs.", - "Notifications": "Notifications" + "Notifications": "Notifications", + "IndexerVipCheckExpiredClientMessage": "Les avantages VIP de l'indexeur ont expiré: {0}", + "IndexerProxy": "Proxy d'indexation", + "IndexerSettingsSummary": "Configuration de divers paramètres globaux de l'indexeur, y compris les proxys.", + "IndexerProxies": "Proxys d'indexation", + "IndexerProxyStatusCheckAllClientMessage": "Tous les proxys sont indisponibles en raison d'échecs", + "IndexerProxyStatusCheckSingleClientMessage": "Proxys indisponibles en raison d'échecs: {0}", + "IndexerVipCheckExpiringClientMessage": "Les avantages VIP de l'indexeur arrivent bientôt à expiration: {0}", + "NoLinks": "Aucun liens", + "Notification": "Notification", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Impossible d'ajouter un nouveau proxy d'indexation, veuillez réessayer.", + "UnableToLoadIndexerProxies": "Impossible de charger les proxys d'indexation" } diff --git a/src/NzbDrone.Core/Localization/Core/tr.json b/src/NzbDrone.Core/Localization/Core/tr.json index 07acce62d..d71f5767d 100644 --- a/src/NzbDrone.Core/Localization/Core/tr.json +++ b/src/NzbDrone.Core/Localization/Core/tr.json @@ -172,5 +172,6 @@ "All": "Herşey", "Agenda": "Gündem", "Added": "Eklendi", - "Activity": "Aktivite" + "Activity": "Aktivite", + "Add": "Ekle" } From 6b39fa5ce6377e945d14d8a3c979ba93c1ea376f Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sat, 2 Oct 2021 14:34:24 +0000 Subject: [PATCH 0084/2320] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate <noreply@weblate.org> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/da.json | 37 --- src/NzbDrone.Core/Localization/Core/de.json | 305 ----------------- src/NzbDrone.Core/Localization/Core/el.json | 26 -- src/NzbDrone.Core/Localization/Core/es.json | 309 ------------------ src/NzbDrone.Core/Localization/Core/fr.json | 303 ----------------- src/NzbDrone.Core/Localization/Core/hu.json | 294 ----------------- src/NzbDrone.Core/Localization/Core/it.json | 301 ----------------- src/NzbDrone.Core/Localization/Core/nl.json | 301 ----------------- src/NzbDrone.Core/Localization/Core/pl.json | 9 - src/NzbDrone.Core/Localization/Core/pt.json | 305 ----------------- .../Localization/Core/pt_BR.json | 3 - src/NzbDrone.Core/Localization/Core/ro.json | 92 +----- src/NzbDrone.Core/Localization/Core/ru.json | 17 - src/NzbDrone.Core/Localization/Core/sv.json | 89 ----- src/NzbDrone.Core/Localization/Core/tr.json | 65 ---- .../Localization/Core/zh_CN.json | 1 - 16 files changed, 1 insertion(+), 2456 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/da.json b/src/NzbDrone.Core/Localization/Core/da.json index 617c0b721..0219aa8b6 100644 --- a/src/NzbDrone.Core/Localization/Core/da.json +++ b/src/NzbDrone.Core/Localization/Core/da.json @@ -6,48 +6,33 @@ "Info": "Information", "IndexerStatusCheckSingleClientMessage": "Indexere utilgængelige på grund af fejl: {0}", "IndexerStatusCheckAllClientMessage": "Alle indexere er utilgængelige på grund af fejl", - "IndexersSettingsSummary": "Indexer og ugivelses restriktioner", "IndexerSearchCheckNoInteractiveMessage": "Ingen indexere er tilgængelige med Interaktiv Søg aktiveret, Prowlarr vil ikke give nogle interaktive søge resultater", - "IndexerSearchCheckNoAvailableIndexersMessage": "Alle søge-mulige indexere er midlertidigt utilgængelige på grund af nylige indexer fejl", "IndexerSearchCheckNoAutomaticMessage": "Ingen indexere tilgængelige med Automatisk Søg aktiveret, Prowlarr vil ikke give nogle automatiske søge resultater", "Indexers": "Indexere", - "IndexerRssHealthCheckNoIndexers": "Ingen indexer tilgængelig med RSS sync aktiveret, Prowlarr vil ikke tage nye udgivelser automatisk", "IndexerRssHealthCheckNoAvailableIndexers": "Alle rss-mulige indexere er midlertidigt utilgængelige på grund af nylige indexer fejl", - "InCinemas": "I Biografen", "ImportTipsMessage": "Nogle tips for at sikre importeringen går glat:", - "ImportSecondTip": "Peg Prowlarr til mappen med alle dine film, ikke en specifik film. f.eks.", "ImportMechanismHealthCheckMessage": "Aktiver Fuldendt Download Håndtering", - "ImportHeader": "Importer film du allerede har", "ImportFirstTip": "Vær sikker på at dine filer inkluderer kvalitet i deres filnavn. f.eks.", - "ImportExistingMovies": "Importer Eksisterende Film", "Imported": "Importeret", - "Import": "Importer", "Ignored": "Ignoreret", "History": "Historie", "HideAdvanced": "Gemt Avancerede", "HealthNoIssues": "Ingen problemer med din konfiguration", "Health": "Helbred", - "HardlinkCopyFiles": "Hardlink/Kopir Filer", "GrabSelected": "Greb Valgt", "Grabbed": "Grebet", - "Genres": "Genrer", "GeneralSettingsSummary": "Port, SSL, brugernavn/adgangskode, proxy, analyser og opdateringer", "General": "Generelt", - "FreeSpace": "Frit Plads", "Formats": "Formater", "Folder": "Mappe", - "Filesize": "Filstørrelse", "Files": "Filer", "Filename": "Filnavn", - "FileManagement": "Fil Håndtering", "FailedDownloadHandling": "Fejlet Download Håndtering", "Failed": "Fejlet", - "Extension": "Tilføjelse", "EventType": "Begivenhed Type", "Events": "Begivenheder", "Error": "Fejl", "Edit": "Rediger", - "Downloaded": "Downloadet", "DownloadClientStatusCheckSingleClientMessage": "Download klienter er ikke tilgængelige på grund af fejl: {0}", "DownloadClientStatusCheckAllClientMessage": "Alle download klienter er utilgængelige på grund af fejl", "DownloadClientsSettingsSummary": "Download klienter, download håndtering og remote path mappings", @@ -55,23 +40,15 @@ "DownloadClientCheckUnableToCommunicateMessage": "Ude af stand til at kommunikere med {0}.", "DownloadClientCheckNoneAvailableMessage": "Ingen download klient tilgængelig", "DownloadClient": "Download Klient", - "DotNetVersionCheckOldUnsupportedMessage": "Aktuelt installeret .Net Framwork {0} er gammel og usupporteret. Vær venlig og opgrader .Net Framework til ihvertfald {1}.", "DotNetVersionCheckNotRecommendedMessage": "Aktuelt Installeret .Net Framework {0} er supporteret men vi foreslår at opgradere til ihvertfald {1}.", - "DiskSpace": "Disk Plads", "Discover": "Opdag", - "DigitalRelease": "Digital Udgivelse", "Details": "Detaljer", - "Deleted": "Slettet", "Delete": "Slet", - "DelayProfiles": "Udskyd Profiler", "Day": "Dag", "Dates": "Datoer", "Date": "Dato", - "CustomFormatsSettingsSummary": "Bruger Tilpassede Formater og Indstillinger", "CustomFormatScore": "Bruger Tilpasset Format score", - "CustomFormats": "Bruger Tilpasset Formater", "CustomFilters": "Bruger Tilpassede Filtere", - "Crew": "Besætning", "ConnectSettingsSummary": "Notifikationer, forbindelser til media servere/afspillere og custom scripts", "Connections": "Forbindelser", "ConnectionLostMessage": "Prowlarr har mistet sin forbindelse til backend og har brug for at blive genindlæst for at genetablere funktionalitet.", @@ -79,38 +56,24 @@ "ConnectionLost": "Forbindelse Mistet", "Connect": "Tilslut", "Component": "Komponent", - "CompletedDownloadHandling": "Færdig Download Håndtering", "Columns": "Kolonner", - "Collection": "Samling", "Close": "Luk", "Clear": "Ryd", - "ChooseAnotherFolder": "Vælg en anden mappe", "Certification": "Certifikation", - "Cast": "Medvirkende", "Cancel": "Afbryd", - "Calendar": "Kalender", "Blacklist": "Blacklist", "BackupNow": "Backup Nu", "Backup": "Backup", - "AudioInfo": "Lyd Info", "Apply": "Anvend", "AppDataLocationHealthCheckMessage": "Opdatering vil ikke være muligt for at undgå at slette AppData under opdatering", - "AndNot": "og ikke", "Analytics": "Analyser", - "AlternativeTitle": "Alternativ Titel", "AllMoviesHiddenDueToFilter": "Alle film er gemt på grund af aktivt filter.", "All": "Alt", - "Agenda": "Dagsorden", "Age": "Alder", - "AddNewTmdbIdMessage": "Du kan også søge ved at bruge TMDB Id af en film. f.eks tmdb:71663", "AddNewMovie": "Tilføj Ny Film", - "AddNewMessage": "Det er nemt at tilføje en ny film, bare start ved at skrive navnet på filmen du vil tilføje", "AddNew": "Tilføj Ny", - "AddMovies": "Tilføj Film", "AddList": "Tilføj Liste", - "AddExclusion": "Tilføj Undtagelse", "Added": "Tilføjet", - "Activity": "Aktivitet", "Actions": "Handlinger", "About": "Om", "Disabled": "deaktiveret", diff --git a/src/NzbDrone.Core/Localization/Core/de.json b/src/NzbDrone.Core/Localization/Core/de.json index ccddbf041..08cf78cf7 100644 --- a/src/NzbDrone.Core/Localization/Core/de.json +++ b/src/NzbDrone.Core/Localization/Core/de.json @@ -1,139 +1,90 @@ { "About": "Über", - "Activity": "Aktivität", "AddExclusion": "Ausschluss hinzufügen", - "AddMovies": "Filme hinzufügen", "AddNew": "Hinzufügen", - "AddNewMessage": "Es ist einfach einen neuen Film hinzuzufügen. Gib einfach den Namen des Filmes ein, den du hinzufügen möchtest", "AddNewTmdbIdMessage": "Du kannst auch mit der TMDb-ID eines Films suchen. Z.B. tmdb:71663", - "Agenda": "Agenda", "All": "Alle", "Analytics": "Statistiken", - "AndNot": "und nicht", "AppDataLocationHealthCheckMessage": "Ein Update ist nicht möglich, um das Löschen von AppData beim Update zu verhindern", "Backup": "Backups", "BackupNow": "Jetzt sichern", - "Blacklist": "Sperrliste", "Calendar": "Kalender", - "Cast": "Besetzung", "ChooseAnotherFolder": "Wähle einen anderen Ordner", "Clear": "Leeren", - "CompletedDownloadHandling": "Verarbeitung abgeschlossener Downloads", "Connect": "Verbindungen", "Connections": "Verbindungen", - "Crew": "Besetzung", "CustomFilters": "Filter anpassen", - "CustomFormats": "Eigene Formate", "Date": "Datum", "Dates": "Termine", - "Day": "Tag", "DelayProfiles": "Verzögerungsprofile", "Delete": "Löschen", - "Discover": "Entdecken", "DiskSpace": "Speicherplatz", - "DotNetVersionCheckNotRecommendedMessage": "Derzeit installiertes .NET Framework {0} wird unterstützt, wir empfehlen jedoch ein Upgrade auf mindestens {1}.", "DotNetVersionCheckOldUnsupportedMessage": "Derzeit installiert .Net Framework {0} ist alt und wird nicht unterstützt. Bitte aktualisieren Sie das .Net Framework auf mindestens {1}.", "DownloadClientCheckNoneAvailableMessage": "Es ist kein Downloader verfügbar", "DownloadClientCheckUnableToCommunicateMessage": "Kommunikation mit {0} nicht möglich.", "DownloadClientStatusCheckAllClientMessage": "Alle Downloader sind aufgrund von Fehlern nicht verfügbar", "DownloadClientStatusCheckSingleClientMessage": "Downloader aufgrund von Fehlern nicht verfügbar: {0}", "DownloadClients": "Downloader", - "Downloaded": "Heruntergeladen", "Edit": "Bearbeiten", "Events": "Events", - "FailedDownloadHandling": "Verarbeitung fehlgeschlagener Downloads", "FileManagement": "Dateiverwaltung", "Files": "Dateien", - "Filesize": "Dateigröße", "Filter": "Filter", "Folder": "Ordner", - "Forecast": "Prognose", "Formats": "Formate", - "FreeSpace": "Freier Speicher", "General": "Allgemein", - "GrabSelected": "Ausgw. erfassen", "Health": "Zustandsüberwachung", "HideAdvanced": "Erweiterte Ansicht", "History": "Verlauf", "Host": "Host", - "Import": "Importieren", "ImportFirstTip": "Stelle sicher, dass die Dateien die Qualität im Dateinamen enthalten. Z.B.", - "ImportHeader": "Importiere bereits vorhandene Filme", "ImportMechanismHealthCheckMessage": "Aktiviere die Verarbeitung der abgeschlossenen Downloads", - "ImportSecondTip": "Wähle den Ordner der alle deine Filme beinhaltet, nicht nur einen spezifischen Film. Z.B.", "ImportTipsMessage": "Einige Tipps um sicherzustellen, dass der Import reibungslos verläuft:", - "IndexerRssHealthCheckNoAvailableIndexers": "Alle RSS-fähigen Indexer sind aufgrund der kürzlichen Indexerfehler vorübergehend nicht verfügbar", "IndexerRssHealthCheckNoIndexers": "Da keine Indexer mit aktivierter RSS-Synchronisierung verfügbar sind, erfasst Prowlarr nicht automatisch neue Releases auf", - "IndexerSearchCheckNoAutomaticMessage": "Keine Indexer mit aktivierter automatischer Suche verfügbar. Prowlarr liefert keine automatischen Suchergebnisse", "IndexerSearchCheckNoAvailableIndexersMessage": "Alle suchfähigen Indexer sind aufgrund der kürzlichen Indexerfehler vorübergehend nicht verfügbar", - "IndexerSearchCheckNoInteractiveMessage": "Keine Indexer mit aktivierter interaktiver Suche verfügbar. Prowlarr liefert keine interaktiven Suchergebnisse", "IndexerStatusCheckAllClientMessage": "Alle Indexer sind aufgrund von Fehlern nicht verfügbar", "IndexerStatusCheckSingleClientMessage": "Indexer aufgrund von Fehlern nicht verfügbar: {0}", "Indexers": "Indexer", "Languages": "Sprachen", - "ListExclusions": "Listenausschlüsse", "Lists": "Listen", "LogFiles": "Protokolle", - "LogFilesLocationMessage": "Protokolldateien befinden sich in:", "Logging": "Protokollierung", - "ManualImport": "Manueller Import", "MediaInfoDllCheckMessage": "MediaInfo Bibliothek konnte nicht geladen werden {0}", - "MediaManagement": "Medien", "Metadata": "Metadaten", - "MinAvailability": "Min. Verfügbarkeit", "MinimumAvailability": "Mindestverfügbarkeit", - "Missing": "Fehlend", "Monitor": "Beobachten", "MonoNotNetCoreCheckMessage": "Bitte aktualisieren Sie auf die .NET Core-Version von Prowlarr", "MonoTlsCheckMessage": "Der Workaround für Prowlarr Mono 4.x TLS ist weiterhin aktiviert. Entferne möglicherweise die Option MONO_TLS_PROVIDER=legacy", - "Month": "Monat", "MoreInfo": "Mehr Infos", - "MountCheckMessage": "Der Einhängepunkt, welcher einen Filmpfad enthält, ist schreibgeschützt eingehängt: ", "Movie": "Film", - "MovieEditor": "Filmeditor", "MovieIndex": "Filmindex", - "MovieNaming": "Filmbenennung", "Movies": "Filme", - "ImportListStatusCheckAllClientMessage": "Alle Listen sind aufgrund von Fehlern nicht verfügbar", "ImportListStatusCheckSingleClientMessage": "Listen aufgrund von Fehlern nicht verfügbar: {0}", "NoChange": "Keine Änderung", "NoChanges": "Keine Änderungen", "Options": "Optionen", - "Path": "Pfad", "PreviewRename": "Umbenennen", - "Profiles": "Profile", "Proxy": "Proxy", "ProxyCheckBadRequestMessage": "Proxy konnte nicht getestet werden. StatusCode: {0}", "ProxyCheckFailedToTestMessage": "Proxy konnte nicht getestet werden: {0}", "ProxyCheckResolveIpMessage": "Fehler beim Auflösen der IP-Adresse für den konfigurierten Proxy-Host {0}", "PtpOldSettingsCheckMessage": "Die folgenden PassThePopcorn-Indexer haben veraltete Einstellungen und sollten aktualisiert werden: {0}", - "Quality": "Qualität", "QualityDefinitions": "Qualitätsdefinitionen", - "QualityProfile": "Qualitätsprofil", "QualityProfiles": "Qualitätsprofile", "Queue": "Warteschlange", - "RSSSync": "RSS Sync.", "Refresh": "Aktualisieren", - "RefreshAndScan": "Aktualisieren", "ReleaseBranchCheckOfficialBranchMessage": "Zweig {0} ist kein gültiger Prowlarr-Release-Zweig. Sie erhalten keine Updates", "ReleaseBranchCheckPreviousVersionMessage": "Zweig {0} ist für eine frühere Version von Prowlarr. Setzen Sie den Zweig für weitere Aktualisierungen auf 'nightly'", - "RemotePathMappings": "Remote-Pfadzuordnungen", "RemoveSelected": "Ausgw. entfernen", - "RemovedMovieCheckMultipleMessage": "Filme {0} wurden aus TMDb entfernt", "RemovedMovieCheckSingleMessage": "Film {0} wurde aus TMDb entfernt", - "RenameFiles": "Dateien umbenennen", "RestoreBackup": "Backup einspielen", "Restrictions": "Beschränkungen", - "RootFolder": "Stammordner", "RootFolderCheckMultipleMessage": "Es fehlen mehrere Stammordner: {0}", - "RootFolderCheckSingleMessage": "Fehlender Stammordner: {0}", "RootFolders": "Stammordner", "SaveChanges": "Änderungen speichern", "Scheduled": "Geplant", "Search": "Suche", - "SearchAll": "Suche alle", "SearchFiltered": "Suche gefilterte", - "SearchForMissing": "Suche fehlende", "SearchSelected": "Ausgw. suchen", "Security": "Sicherheit", "SelectAll": "Alle wählen", @@ -142,82 +93,53 @@ "ShowAdvanced": "Einfache Ansicht", "Sort": "Sortieren", "Status": "Status", - "Studio": "Studio", "Style": "Stil", "System": "System", "Tags": "Tags", "Tasks": "Aufgaben", - "Titles": "Titel", "UI": "Oberfläche", - "UnmappedFolders": "Nicht zugeordnete Ordner", "Unmonitored": "Nicht beobachtete", "UnselectAll": "Keine wählen", - "UpdateAll": "Alle aktualisieren", "UpdateCheckStartupNotWritableMessage": "Update kann nicht installiert werden, da der Startordner '{0}' vom Benutzer '{1}' nicht beschreibbar ist.", "UpdateCheckStartupTranslocationMessage": "Update kann nicht installiert werden, da sich der Startordner '{0}' in einem App Translocation-Ordner befindet.", "UpdateCheckUINotWritableMessage": "Update kann nicht installiert werden, da der Benutzeroberflächenordner '{0}' vom Benutzer '{1}' nicht beschreibbar ist.", "Updates": "Updates", "View": "Ansicht", - "Week": "Woche", "iCalLink": "iCal Link", "Language": "Sprache", - "MediaManagementSettingsSummary": "Einstellungen für Bennenung und Dateiverwaltung", "Year": "Jahr", - "Wanted": "› Gesuchte", "UpdateSelected": "Ausgw. aktualisieren", "UISettingsSummary": "Einstellungen für Kalender, Datumsformat und Farbbeeinträchtigung", - "Timeleft": "Restzeit", "TagsSettingsSummary": "Alle Tags und deren Benutzung anzeigen. Unbenutzte Tags können entfernt werden", - "SourceTitle": "Release Titel", "SizeOnDisk": "Größe", "Size": "Größe", - "Runtime": "Laufzeit", "Renamed": "Umbenannt", - "ReleaseTitle": "Release Titel", "ReleaseStatus": "Releasestatus", - "ReleaseGroup": "Release-Gruppe", "Ratings": "Bewertung", - "QualitySettingsSummary": "Qualitätgrößen und Bennenung", "Protocol": "Protokoll", - "Progress": "Fortschritt", "ProfilesSettingsSummary": "Profile für Qualität, Sprache und Verzögerung", - "PhysicalRelease": "VÖ Disc", "OutputPath": "Ausgabe-Pfad", - "MovieTitle": "Filmtitel", "MonitoredOnly": "Nur beobachtete", - "MetadataSettingsSummary": "Erstelle Metadaten wenn Filme importiert oder aktualisiert werden", "MassMovieSearch": "Massen Filmsuche", - "ListsSettingsSummary": "Listen importieren, Listenausschlüsse", "LastWriteTime": "Zuletzt beschrieben", - "IndexersSettingsSummary": "Indexer- und Releasebeschränkungen", "Indexer": "Indexer", - "InCinemas": "VÖ Kino", "Imported": "Importiert", - "Ignored": "Ignoriert", "DownloadClientsSettingsSummary": "Downloader, Downloadverarbeitung und Remote-Pfadzuordnungen", "Grabbed": "Erfasste", - "Genres": "Genres", "GeneralSettingsSummary": "Port, SSL, Benutzername/Passwort, Proxy, Statistik und Updates", "Filename": "Dateiname", "Failed": "Fehlgeschlagen", "EventType": "Event Typ", "DownloadClient": "Downloader", - "DigitalRelease": "VÖ Digital", "Details": "Details", - "Deleted": "Gelöscht", "CutoffUnmet": "› Schwelle nicht erreicht", - "CustomFormatsSettingsSummary": "Eigene Formate und Einstellungen", "ConnectSettingsSummary": "Benachrichtigungen, Verbindungen zu Medien Server/Clients und benutzerdefinierte Scripte", - "Collection": "Sammlung", "Certification": "Zertifizierung", "Added": "Hinzugefügt", "Actions": "Aktionen", - "CustomFormatScore": "Eigene Format Wertung", "Warn": "Warnung", - "VideoCodec": "Video Codec", "Unavailable": "Nicht verfügbar", "Type": "Typ", - "TotalSpace": "Speicherkapazität", "Title": "Titel", "Time": "Zeit", "TestAll": "Alle testen", @@ -229,31 +151,22 @@ "Seeders": "Seeders", "Save": "Speichern", "Restart": "Neustarten", - "RemoveRootFolder": "Stammverzeichnis entfernen", "Reload": "Neuladen", - "RelativePath": "Relativer Pfad", "RejectionCount": "Anzahl der Ablehnungen", "Peers": "Peers", "PageSize": "Einträge pro Seite", - "OrganizeModalSuccess": "Fertig! Keine weiteren Dateien zum umbennenen.", "OrganizeModalNamingPattern": "Benennungsmuster:", - "OrganizeModalDisabled": "Umbenennen ist deaktiviert, nichts zum umbennenen", "OrganizeModalAllPathsRelative": "Alle Pfade sind relativ zu:", - "OrganizeAndRename": "Organisieren & Umbenennen", "Organize": "Organisieren", "Ok": "OK", "OAuthPopupMessage": "Dein Browser blockiert Pop-ups", "Name": "Name", - "MoveFiles": "Dateien verschieben", "Monitored": "Beobachtet", "Message": "Nachricht", - "Location": "Speicherort", "Level": "Stufe", "KeyboardShortcuts": "Tastenkürzel", - "ImportExistingMovies": "Vorhandene Filme importieren", "Info": "Info", "HealthNoIssues": "Keine Probleme mit deiner Konfiguration", - "HardlinkCopyFiles": "Hardlink/Dateien kopieren", "Extension": "Erweiterung", "Error": "Fehler", "ConnectionLostMessage": "Prowlarr hat die Verbindung zum Backend verloren und muss neugeladen werden.", @@ -262,137 +175,87 @@ "Component": "Komponente", "Columns": "Spalten", "Close": "Schließen", - "AudioInfo": "Audio-Info", "Cancel": "Abbrechen", "Apply": "Anwenden", - "AlternativeTitle": "Alternative Titel", "AllMoviesHiddenDueToFilter": "Alle Filme sind wegen dem Filter ausgeblendet.", "Age": "Alter", - "AddNewMovie": "Neuer Film...", "AddList": "Liste hinzufügen", "SystemTimeCheckMessage": "Die Systemzeit ist um einen Tag versetzt. Bis die Zeit korrigiert wurde, könnten die geplanten Aufgaben nicht korrekt ausgeführt werden", "UnsavedChanges": "Ungespeicherte Änderungen", - "Table": "Tabelle", "ShowTitle": "Titel anzeigen", - "ShowStudio": "Studio anzeigen", "ShowSizeOnDisk": "Belegter Speicherplatz anzeigen", "ShowSearchHelpText": "Suchbutton anzeigen beim draufzeigen", "ShowSearch": "Suche anzeigen", - "ShowQualityProfile": "Qualitätsdefinition anzeigen", "ShowPath": "Pfad anzeigen", - "ShowMonitored": "Beobachtete anzeigen", "ShowDateAdded": "Datum \"Hinzugefügt\" anzeigen", - "SettingsWeekColumnHeaderHelpText": "Wird in der Wochenansicht über jeder Spalte angezeigt", "SettingsWeekColumnHeader": "Wochen Spalten Titel", - "SettingsUiLanguageHelpText": "Sprache die Prowlarr für die Oberfläche benutzt", "SettingsUiLanguage": "Sprache (Language)", "SettingsTimeFormat": "Zeitformat", "SettingsShowRelativeDatesHelpText": "Relatives (z.B.: Heute, gestern, etc) oder absolutes Datum anzeigen", "SettingsShowRelativeDates": "Relatives Datum anzeigen", "SettingsShortDateFormat": "Kurzes Datumsformat", - "SettingsRemotePathMappingRemotePathHelpText": "Root-Pfad zum Verzeichnis, auf das der Download-Client zugreift", "SettingsRemotePathMappingLocalPathHelpText": "Pfad, den Prowlarr verwenden sollte, um lokal auf den Entfernten-Pfad zuzugreifen", - "SettingsRemotePathMappingRemotePath": "Entfernter-Pfad", "SettingsRemotePathMappingLocalPath": "Lokaler Pfad", - "SettingsRemotePathMappingHostHelpText": "Derselbe Host, den du für den Remote-Download-Client angegeben hast", "SettingsLongDateFormat": "Langes Datumsformat", - "SettingsFirstDayOfWeek": "Erster Tag der Woche", "SettingsEnableColorImpairedMode": "Farbbeeinträchtigter Modus aktivieren", "SettingsEnableColorImpairedModeHelpText": "Alternativer Stil, um farbbeeinträchtigten Benutzern eine bessere Unterscheidung farbcodierter Informationen zu ermöglichen", - "SelectFolder": "Ordner auswählen", "SearchOnAdd": "Beim hinzufügen suchen", - "SearchMovie": "Film suchen", "RecentFolders": "Letzte Ordner", - "QuickImport": "Schnell Import", "PosterSize": "Plakatgröße", - "Posters": "Plakate", "PosterOptions": "Poster Optionen", "PendingChangesStayReview": "Auf der Seite bleiben", "PendingChangesMessage": "Es gibt noch ungespeicherte Änderungen, bist du sicher, dass du die Seite verlassen möchtest?", "PendingChangesDiscardChanges": "Änderungen verwerfen und schließen", - "OverviewOptions": "Übersichts Optionen", "Overview": "Übersicht", "MonoVersionCheckUpgradeRecommendedMessage": "Die momentane installierte Mono Version {0} wird unterstützt aber es wird empfohlen auf {1} zu updaten.", - "MonoVersionCheckOldNotSupportedMessage": "Die momentane installierte Mono Version {0} ist alt und wird nicht unterstützt. Bitte update Mono zur Version {1}.", "MonoVersionCheckNotSupportedMessage": "Die momentane installierte Mono Version {0} wird nicht länger unterstützt. Bitte update Mono zur Version {1}.", - "MonitorMovie": "Film beobachten", "InteractiveImport": "Interaktiver Import", "ExistingMovies": "Vorhandene Filme", - "EditRemotePathMapping": "Entfernte Pfadzuordnung bearbeiten", "DetailedProgressBarHelpText": "Text auf Fortschrittsbalken anzeigen", - "DetailedProgressBar": "Erweiterter Fortschrittsbalken", "AddRemotePathMapping": "Entfernte Pfadzuordnung hinzufügen", "UpdateAutomaticallyHelpText": "Updates automatisch herunteraden und installieren. Es kann weiterhin unter \"System -> Updates\" ein manuelles Update angestoßen werden", "UrlBaseHelpText": "Für Reverse-Proxy-Unterstützung. Die Standardeinstellung leer", - "UsenetDelayHelpText": "Verzögerung in Minuten before ein Usenet-Release erfasst wird", "WhitelistedHardcodedSubsHelpText": "Hier gesetzte Untertitel Tags werden nciht als hartcodiert erachtet", "EnableAutoHelpText": "Wenn aktiviert werden Filme dieser Liste automatisch hinzugefügt", - "AddImportExclusionHelpText": "Automatisches ( wieder- ) hinzufügen durch Listen verhindern", "AgeWhenGrabbed": "Alter (beim erfassen)", - "AllowHardcodedSubs": "Hartcodierte Untertitel erlauben", "AlreadyInYourLibrary": "Bereits in deiner Bibliothek", - "AnalyseVideoFiles": "Video Dateien analysieren", "AppDataDirectory": "AppData Ordner", "ApplyTags": "Tags setzen", - "AreYouSureYouWantToDeleteThisImportListExclusion": "Bist du sicher, dass du diesen Importlisten Ausschluss löschen willst?", "AreYouSureYouWantToDeleteThisRemotePathMapping": "Bist du sicher, dass du diese entfernte Pfadzuordnung löschen willst?", - "AsAllDayHelpText": "Events werden als ganztags Event in deinem Kalender angezeigt", "Authentication": "Authentifizierung", - "AutoDownloadPropersHelpText": "Wenn verfügbar, automatisch Proper-Releases upgraden?", "Automatic": "Automatisch", - "AutoUnmonitorPreviouslyDownloadedMoviesHelpText": "Auf der Festplatte gelöschte Filme auch automatisch in Prowlarr nicht mehr beobachten", "AvailabilityDelay": "Verfügbarkeits Verzögerung", - "AvailabilityDelayHelpText": "Zeit vor( - ) oder nach( + ) dem Verfügbarkeitsdatum für die Suche nach einem Film", "BackupIntervalHelpText": "Intervall zwischen automatischen Backups", "BackupRetentionHelpText": "Automatische Backups, die älter als die Aufbewahrungsfrist sind, werden automatisch gelöscht", "Backups": "Backups", "BindAddress": "Bindungsadresse", "BindAddressHelpText": "Gültige IPv4 Adresse oder \"*\" für alle Netzwerke", - "BlacklistRelease": "Release sperren", "Branch": "Branch", "BypassProxyForLocalAddresses": "Proxy für lokale Adressen umgehen", "CertificateValidation": "Zertifikat Validierung", "CertificateValidationHelpText": "Ändere wie streng die Validierung der HTTPS-Zertifizierung ist", - "CertificationCountry": "Zertifizierungs Land", "ChangeFileDate": "Datei Erstelldatum anpassen", "ChangeHasNotBeenSavedYet": "Änderung wurde noch nicht gespeichert", - "CheckForFinishedDownloadsInterval": "Intervall zum prüfen von fertigen Downloads", "CleanLibraryLevel": "Bibliothek aufräumen", - "ClickToChangeLanguage": "Sprache ändern...", "ClickToChangeQuality": "Qualität ändern...", "ClientPriority": "Priorität", - "CloneFormatTag": "Format Tag kopieren", "CloneProfile": "Profil kopieren", - "ColonReplacement": "Doppelpunkt-Ersatz", "ColonReplacementFormatHelpText": "Ändere wie Prowlarr Doppelpunkte ersetzt", - "Conditions": "Bedingungen", "CreateEmptyMovieFolders": "Leere Filmordner erstellen", - "CreateEmptyMovieFoldersHelpText": "Leere Filmordner für fehlende Filme beim Scan erstellen", "CreateGroup": "Gruppe erstellen", - "CustomFormatsSettings": "Einstellungen für eigene Formate", "CutoffFormatScoreHelpText": "Sobald dieser eigener Format Score erreicht wird, werden keine neuen Releases erfasst", - "CutoffHelpText": "Sobald diese Qualität erreicht wird, werden keine neuen Releases erfasst", "DeleteBackup": "Backup löschen", - "DeleteCustomFormat": "Eigenes Format löschen", "DeleteDelayProfile": "Verzögerungsprofil löschen", "DeleteDownloadClient": "Downloader löschen", - "DeleteEmptyFolders": "Leere Ordner löschen", "DeleteFile": "Datei löschen", - "DeleteImportListExclusion": "Importlisten Ausschluss löschen", "DeleteIndexer": "Indexer löschen", - "DeleteList": "Liste löschen", "DeleteRestriction": "Beschränkung löschen", - "DeleteSelectedMovieFiles": "Ausgewählte Filmdateien löschen", "DeleteTag": "Tag löschen", - "DestinationPath": "Zielpfad", "DestinationRelativePath": "Relativer Zielpfad", "Docker": "Docker", "DownloadClientSettings": "Downloader Einstellungen", - "DownloadPropers": "Proper-Releases herunterladen", "DownloadWarningCheckDownloadClientForMoreDetails": "Download Warnung: Prüfe den Downloader für mehr Details", - "Edition": "Auflage", "EditMovie": "Film bearbeiten", - "EditPerson": "Schausteller bearbeiten", "Enable": "Aktivieren", "EnableAutomaticAdd": "Automatisch hinzufügen", "EnableAutomaticSearch": "Automatisch suchen", @@ -401,125 +264,78 @@ "EnabledHelpText": "Aktiviere diese Liste", "EnableHelpText": "Metadaten Dateien erstellen für diesen Metadata Typ", "EnableInteractiveSearch": "Interaktive Suche", - "EnableRSS": "RSS Sync.", "EnableSSL": "SSL", "EnableSslHelpText": " Erfordert einen Neustart als Administrator", - "Ended": "Beendet", "Exluded": "Ausgeschlossen", - "FileChmodMode": "Datei CHMOD Modus", "FileDateHelpText": "Aktualisiere das Erstelldatum beim Import oder Re-Scan", - "FileNames": "Dateinamen", "FirstDayOfWeek": "Erster Tag der Woche", "Fixed": "Behoben", - "Folders": "Ordner", "FollowPerson": "Schausteller folgen", "GeneralSettings": "Allgemeine Einstellungen", - "Global": "Global", "Grab": "Erfasse", - "GrabID": "Erfass ID", "GrabRelease": "Release erfassen", - "Group": "Gruppe", "Hostname": "Hostname", - "ICalFeed": "iCal-Feed", "IconForCutoffUnmet": "Symbol für Schwelle nicht erreicht", "IgnoredAddresses": "Ignorierte Adressen", - "IgnoreDeletedMovies": "Gelöschte Filme ignorieren", "IllRestartLater": "Später neustarten", - "ImportExtraFiles": "Extra Dateien importieren", "Importing": "Importiere", - "ImportMovies": "Filme importieren", "IncludeCustomFormatWhenRenaming": "Eigenes Format beim umbennen einfügen", - "IncludeCustomFormatWhenRenamingHelpText": "In {Custom Formats} umbennenungs Format", "IncludeHealthWarningsHelpText": "Zustandswarnung", - "IncludeUnmonitored": "Nicht beobachtete", "IndexerFlags": "Indexer Flags", "Interval": "Intervall", - "LanguageHelpText": "Sprache für Releases", "Links": "Links", - "ListSettings": "Listen Einstellungen", "ListSyncLevelHelpText": "Filme in der Bibliothek werden gelöscht oder nicht weiter beobachtet wenn sie nicht in der Liste sind", - "ListUpdateInterval": "Aktualisierungs Intervall der Listen", "Local": "Lokal", "LogLevel": "Log Level", "Logs": "Logs", - "MarkAsFailed": "Als fehlgeschlagen markieren", "MaximumSize": "Maximale Größe", "Mechanism": "Verfahren", - "MediaInfo": "Medien Information", "MediaManagementSettings": "Medienverwaltungs Einstellungen", "MIA": "MIA", - "MinimumAge": "Mindestalter", "MinimumFreeSpace": "Mindest freier Speicher", - "MinimumFreeSpaceWhenImportingHelpText": "Importieren verhindern wenn weniger als dieser Wert als freier Speicher zur Verfügung steht", "MinimumLimits": "Mindest Grenzen", "Mode": "Modus", - "MonitoredHelpText": "Herunterladen wenn der Film verfügbar ist", "MonoVersion": "Mono Version", - "MovieAvailableButMissing": "Film verfügbar, aber fehlend", "MovieFiles": "Film Dateien", - "MovieFolderFormat": "Filmordner Format", "MovieID": "Film ID", - "MovieInfoLanguageHelpTextWarning": "Seite muss neugeladen werden", "MovieIsDownloading": "Film ist am herunterladen", - "MovieTitleHelpText": "Der Titel des Filmes der augeschlossen werden soll", "MovieYear": "Erscheinungsjahr", - "MovieYearHelpText": "Das Erscheinungsjahr des Filmes der ausgeschlossen werden soll", "MustContain": "Muss beinhalten", - "MustNotContain": "Darf nicht beinhalten", "NamingSettings": "Bennenungs Einstellungen", "NetCore": ".NET Core", "New": "Neu", "NoLeaveIt": "Nein, nicht ändern", "NoLimitForAnyRuntime": "Keine Begrenzung der Laufzeiten", - "NotAvailable": "Nicht verfügbar", "NotificationTriggers": "Benachrichtigungs Auslöser", - "NotMonitored": "Nicht beobachtet", "OnGrabHelpText": "Erfassen", "OnHealthIssueHelpText": "Zustandsproblem", - "OnRenameHelpText": "Umbennenen", "OnUpgradeHelpText": "Upgrade", "OpenBrowserOnStart": "Browser beim Start öffnen", - "Original": "Orginal", "PackageVersion": "Paket Version", "PageSizeHelpText": "Anzahl der Einträge pro Seite", "Password": "Passwort", "Port": "Port", "PortNumber": "Port Nummer", - "PreferIndexerFlagsHelpText": "Priorisiere Releases mit speziellen Flags", "PreferredSize": "Bevorzugte Größe", - "Proper": "Proper", "ProtocolHelpText": "Wählen Sie, welche(s) Protokoll(e) verwendet werden soll(en) und welches Protokoll bei der Wahl zwischen ansonsten gleichwertigen Releases bevorzugt wird", "ProxyBypassFilterHelpText": "Verwende ',' als Trennzeichen und '*.' als Platzhalter für Subdomains", "ProxyType": "Proxy Typ", "ProxyUsernameHelpText": "Nur wenn ein Benutzername und Passwort erforderlich ist, muss es eingegeben werden. Ansonsten leer lassen.", - "PublishedDate": "Veröffentlichungs Datum", "QualityCutoffHasNotBeenMet": "Qualitätsschwelle wurde noch nicht erreicht", "QualitySettings": "Qualitäts Einstellungen", - "Prowlarr": "Prowlarr", "ProwlarrTags": "Prowlarr Tags", - "Real": "Echt", "Reason": "Grund", - "RecycleBinCleanupDaysHelpText": "Auf 0 setzen um das automatische leeren des Papierkorbs zu deaktivieren", "RecycleBinHelpText": "Gelöschte Filmdateien werden hierher verschoben anstatt sie direkt endgültig zu löschen", - "RecyclingBin": "Papierkorb", "RecyclingBinCleanup": "Papierkorb aufräumen", - "Redownload": "Nochmal herunterladen", "RefreshInformationAndScanDisk": "Metadaten aktualisieren und Festplatte scannen", "RefreshMovie": "Film aktualisieren", - "ReleaseRejected": "Release abgelehnt", "Remove": "Entfernen", "RemovedFromTaskQueue": "Aus der Aufgabenwarteschlage entfernt", - "RemoveFailedDownloadsHelpText": "Fehlgeschlagene Downloads aus dem Downloader Verlauf entfernen", "RemoveFilter": "Filter entfernen", - "RemoveFromBlacklist": "Aus der Sperrliste entfernen", "RemoveFromQueue": "Aus der Warteschlage entfernen", - "RenameMovies": "Filme umbenennen", "RenameMoviesHelpText": "Wenn das umbennen deaktiviert ist, wird der vorhandene Dateiname benutzt", - "Reorder": "Neu sortieren", "ReplaceIllegalCharacters": "Sonderzeichen ersetzen", - "ReplaceIllegalCharactersHelpText": "Wenn nicht aktiviert, werden Sonderzeichen ganz entfernt", "RescanAfterRefreshHelpText": "Nach dem aktualisieren des Films, den Filmordner neu scannen", - "RescanAfterRefreshHelpTextWarning": "Wenn nicht \"Immer (Always)\" ausgewählt wird, werden Dateiänderungen nicht automatisch erkannt", "RescanMovieFolderAfterRefresh": "Nach dem aktualisieren den Filmordner neu scannen", "Reset": "Zurücksetzen", "ResetAPIKey": "API-Schlüssel zurücksetzen", @@ -527,273 +343,172 @@ "RestartProwlarr": "Prowlarr Neustarten", "Result": "Ergebnis", "Retention": "Aufbewahrung ( Retention )", - "RetentionHelpText": "Nur Usenet: Für eine umbegrenzte Aufbewahrung auf 0 setzen", "RSSSyncInterval": "RSS Synchronisierungs Intervall", "ScriptPath": "Script Pfad", - "SetPermissions": "Rechte setzen", "SetPermissionsLinuxHelpTextWarning": "Ändere diese Einstellung nur, wenn du weißt was sie bewirken.", - "ShouldMonitorHelpText": "Beobachte Filme die von dieser Liste hinzugefügt wurden", "ShowAsAllDayEvents": "Als Ganztags Events anzeigen", - "ShowCutoffUnmetIconHelpText": "Symbol zeigen wenn die Qualitätsschwelle noch nicht erreicht wurde", "ShowMovieInformationHelpText": "Genre und Zertifizierung anzeigen", - "ShowQualityProfileHelpText": "Qualitätsprofil unter dem Plakat anzeigen", "ShowMonitoredHelpText": "Beobachtungsstatus unter dem Plakat anzeigen", - "ShowMovieInformation": "Filminformationen anzeigen", "ShowTitleHelpText": "Filmtitel unter dem Plakat anzeigen", - "ShowUnknownMovieItems": "Unbekannt Filmeinträge anzeigen", "SkipFreeSpaceCheck": "Pürfung des freien Speichers überspringen", - "SkipFreeSpaceCheckWhenImportingHelpText": "Aktiviere dies wenn es nicht möglich ist, den freien Speicherplatz vom Stammverzeichnis zu ermitteln", "SorryThatMovieCannotBeFound": "Schade, dieser Film kann nicht gefunden werden.", - "SourcePath": "Quellpfad", "SourceRelativePath": "Relativer Quellpfad", "SSLCertPassword": "SSL Zertifikat Passwort", - "SslCertPasswordHelpText": "Passwort für die PFX Datei", "SslCertPathHelpText": "Pfad zur PFX Datei", "SSLPort": "SSL Port", "SSLCertPath": "Pfad zum SSL Zertifikat", - "StandardMovieFormat": "Standard Filmformat", "StartupDirectory": "Start-Verzeichnis", "SuggestTranslationChange": "Schlage eine Übersetzung vor", "TagsHelpText": "Wird auf Filme mit mindestens einem passenden Tag angewandt", "TestAllClients": "Alle testen", - "TestAllIndexers": "Alle testen", "TestAllLists": "Alle testen", - "TimeFormat": "Zeitformat", "UpdateMechanismHelpText": "Benutze den Built-In Updater oder ein Script", "UpdateScriptPathHelpText": "Pfad zu einem benutzerdefinierten Skript, das ein extrahiertes Update-Paket übernimmt und den Rest des Update-Prozesses abwickelt", - "UpgradeAllowedHelpText": "Wenn deaktiviert wird die Qualität nicht verbessert", "Uptime": "Laufzeit", "URLBase": "URL Base", - "TMDBId": "TMDb ID", "TmdbIdHelpText": "Die TMDb ID für den Ausschluss", - "TorrentDelay": "Torrent Verzögerung", "TorrentDelayHelpText": "Verzögerung in Minuten bevor ein Torrent-Release erfasst wird", "Torrents": "Torrents", - "TotalFileSize": "Gesamte Dateigröße", "UISettings": "Benutzeroberflächen Einstellungen", - "UnableToLoadCustomFormats": "Eigene Formate konnten nicht geladen werden", "UnableToLoadDelayProfiles": "Verzögerungsprofile konnten nicht geladen werden", "UnableToLoadDownloadClients": "Downloader konnten nicht geladen werden", "UnableToLoadIndexers": "Indexer konnten nicht geladen werden", - "UnableToLoadListExclusions": "Listenausschlüsse konnten nicht geladen werden", "UnableToLoadLists": "Listen konnten nicht geladen werden", - "UnableToLoadMetadata": "Metadaten konnten nicht geladen werden", "UnableToLoadNotifications": "Benachrichtigungen konnten nicht geladen werden", "UnableToLoadQualityDefinitions": "Qualitätsdefinitionen konnten nicht geladen werden", - "UnableToLoadQualityProfiles": "Qualitätsprofile konnten nicht geladen werden", "UnableToLoadRestrictions": "Beschränkungen konnten nicht geladen werden", "UnableToLoadTags": "Tags konnten nicht geladen werden", - "Ungroup": "Gruppe entfernen", "UnmonitoredHelpText": "Nicht beobachtete Filme im iCal-Feed einschließen", - "UseHardlinksInsteadOfCopy": "Hardlinks anstatt kopieren verwenden", "Usenet": "Usenet", - "UsenetDelay": "Usenet Verzögerung", "UseProxy": "Proxy benutzen", "Username": "Benutzername", "Version": "Version", - "WeekColumnHeader": "Titel der Wochenspalte", "WhitelistedSubtitleTags": "Erlaubte Untertitel Tags", "YesCancel": "Ja, abbrechen", "EnableColorImpairedModeHelpText": "Alternativer Style, um farbbeeinträchtigten Benutzern eine bessere Unterscheidung farbcodierter Informationen zu ermöglichen", - "MovieIsOnImportExclusionList": "Film ist auf der Net Import Ausschluss Liste", "RemoveHelpTextWarning": "Dies wird den Download und alle bereits heruntergeladenen Dateien aus dem Downloader entfernen.", "EnableMediaInfoHelpText": "Videoinformationen wie Auflösung, Laufzeit und Codec aus Datien erkennen. Dazu ist es erforderlich, dass Prowlarr Teile der Datei liest, was zu hoher Festplatten- oder Netzwerkaktivität während der Scans führen kann.", - "ImportListSyncIntervalHelpText": "Wie oft die Listen synchronisiert werden sollen.", "AddListExclusion": "Listenausschluss hinzufügen", - "AddMoviesMonitored": "Filme beobachtet hinzufügen", "HelpText": "Intervall in Minuten. Zum deaktivieren auf 0 setzen ( Dies wird das automatische Release erfassen deaktivieren )", - "RequiredHelpText": "Diese {0} Bedingungen müsen zutreffen damit das eigene Format zutrifft. Ansonsten reicht ein einzelner {1} Treffer.", "AllowHardcodedSubsHelpText": "Filme mit hartcodierten Untertiteln werden auch automatisch heruntergeladen", - "ICalHttpUrlHelpText": "Füge diese URL in deinen Client ein oder klicke auf abonnieren wenn dein Browser Webcal untertützt", "NoMinimumForAnyRuntime": "Kein Minimum für Laufzeiten", "AnalyticsEnabledHelpText": "Sende anonyme Nutzungs- und Fehlerinformationen an die Server von Prowlarr. Dazu gehören Informationen über Browser, welche Seiten der Prowlarr-Weboberfläche aufgerufen wurden, Fehlerberichte sowie Betriebssystem- und Laufzeitversion. Wir werden diese Informationen verwenden, um Funktionen und Fehlerbehebungen zu priorisieren.", - "IgnoredHelpText": "Ein Release wird abgelehnt, wenn es einen oder mehrere dieser Begriffe enthält (Groß- und Kleinschreibung wird nicht berücksichtigt)", "OnDownloadHelpText": "Import", "RestartRequiredHelpTextWarning": "Erfordert einen Neustart", "ApiKey": "API-Schlüssel", - "ImportedTo": "Importiert nach", "Permissions": "Rechte", - "AreYouSureYouWantToDeleteThisDelayProfile": "Bist du sicher, dass du dieses Verzögerungs-Profil löschen willst?", "ImportExtraFilesHelpText": "Importiere zutreffende Extra Dateien (Untertitel, nfo, etc.) nach dem Importieren einer Filmdatei", - "PreferIndexerFlags": "Bevorzugte Indexer Flags", "RssSyncIntervalHelpTextWarning": "Dies betrifft alle Indexer. Bitte beachte dessen API Regeln", "AreYouSureYouWantToResetYourAPIKey": "Bist du sicher, dass du den API-Schlüssel zurücksetzen willst?", - "CopyUsingHardlinksHelpText": "Hardlinks erstellen wenn Torrents die noch geseeded werden kopiert werden sollen", "IncludeUnknownMovieItemsHelpText": "Einträge ohne eine Zuordnung in der Warteschlange anzeigen. Dies könnten gelöschte Filme oder alles andere mit Prowlarrs Downloadkategorie sein", "PriorityHelpText": "Priorisiere mehrere Downloader. Rundlauf-Verfahren wird für Downloader mit der gleichen Priorität verwendet.", - "SearchForMovie": "Film suchen", "AuthenticationMethodHelpText": "Für den Zugriff auf Prowlarr sind Benutzername und Passwort erforderlich", - "CopyUsingHardlinksHelpTextWarning": "Dateisperren Gelegentlich kann es vorkommen, dass Dateisperren das Umbenennen von Dateien verhindern, die gerade geseeded werden. Sie können das Seeding vorübergehend deaktivieren und die Umbenennungsfunktion von Prowlarr als Workaround verwenden.", "IndexerSettings": "Indexer Einstellungen", "ProxyPasswordHelpText": "Nur wenn ein Benutzername und Passwort erforderlich ist, muss es eingegeben werden. Ansonsten leer lassen.", "SendAnonymousUsageData": "Anonyme Nutzungsdaten übertragen", - "AutoRedownloadFailedHelpText": "Automatisch nach einen anderen Release suchen", "DBMigration": "DB Migration", "LaunchBrowserHelpText": " Öffne die Startseite von Prowlarr im Webbrowser nach dem Start.", "ReadTheWikiForMoreInformation": "Lese das Wiki für mehr Informationen", - "SetPermissionsLinuxHelpText": "Soll CHMOD ausgeführt werden wenn Datien importiert/umbenannt werden?", "BackupFolderHelpText": "Relative Pfade befinden sich unter Prowlarrs AppData Ordner", "DelayProfile": "Verzögerungs Profil", "MaximumLimits": "Maximale Grenzen", - "RecycleBinCleanupDaysHelpTextWarning": "Datien im Papierkorb die älter sind als der gewählte Wert, werden endgültig gelöscht", "UnableToLoadRemotePathMappings": "Entfernte Pfadzuordnungen konnten nicht geladen werden", - "BlacklistHelpText": "Hindert Prowlarr daran, dieses Release automatisch erneut zu erfassen", "DeleteEmptyFoldersHelpText": "Lösche leere Filmeordner während des Scans oder wenn Filmdateien gelöscht werden", - "MaximumSizeHelpText": "Maximale Größe für ein zu erfassendes Release in MB. 0 bedeutet unbegrenzt", "ReleaseDates": "VÖ Termine", - "CertificationCountryHelpText": "Wähle ein Land für die Film Zertifizierungen", "DeleteNotification": "Benachrichtigung löschen", - "MetadataSettings": "Metadaten Einstellungen", "RemoveCompletedDownloadsHelpText": "Importierte Downloads aus dem Downloader Verlauf entfernen", "CloneIndexer": "Indexer kopieren", - "DeleteQualityProfile": "Qualitätsdefinition löschen", "MinFormatScoreHelpText": "Mindeste eigener Format Score bis zum download", "ConnectSettings": "Eintellungen für Verbindungen", - "DownloadFailedCheckDownloadClientForMoreDetails": "Download fehlgeschlagen: Prüfe den Downloader für mehr Details", "MinimumAgeHelpText": "Nur Usenet: Mindestalter in Minuten der NZBs bevor sie erfasst werden. Gebe damit neuen Releases Zeit, sich bei deinem Usenet Provider zu verbreiten.", - "RemoveFromDownloadClient": "Aus dem Downloader entfernen", "WaitingToProcess": "Wartet auf Verarbeitung", - "WaitingToImport": "Wartet auf Import", "UpgradeUntilThisQualityIsMetOrExceeded": "Solange bis die Qualität erreicht oder übertroffen wird verbessern", "TagCannotBeDeletedWhileInUse": "Kann während der Benutzung nicht gelöscht werden", - "SubfolderWillBeCreatedAutomaticallyInterp": "'{0}' Unterordner wird automatisch erstellt", "SSLCertPathHelpText": "Pfad zur PFX Datei", "SSLCertPasswordHelpText": "Passwort für die PFX Datei", - "ShowYear": "Jahr anzeigen", "ShowRatings": "Bewertungen anzeigen", "ShownClickToHide": "Angezeigt, zum verstecken klicken", - "ShowGenres": "Genres anzeigen", "ShowCertification": "Zertifikation anzeigen", - "SettingsRuntimeFormat": "Laufzeit Format", "SearchOnAddHelpText": "Suche nach den Filmen auf der Liste nach dem hinzufügen", - "RSSSyncIntervalHelpTextWarning": "Dies wird alle Indexer betreffen. Bitte folge deren Regeln", "RSSIsNotSupportedWithThisIndexer": "RSS wird von diesem Indexer nicht unterstützt", - "RetryingDownloadInterp": "Herunterladen nochmal versuchen {0} um {1}", "RemovingTag": "Tag entfernen", - "ReleaseWillBeProcessedInterp": "Release wird verarbeitet {0}", "Queued": "Eingereiht", - "QualityProfileDeleteConfirm": "Qualitätsprofil '{0}' wirklich löschen?", "Pending": "Ausstehend", - "Paused": "Pausiert", "NegateHelpText": "Wenn aktiviert wird das eigene Format nicht angewendet solange diese {0} Bedingung zutrifft.", - "MoviesSelectedInterp": "{0} Film(e) ausgewählt", "MovieIsUnmonitored": "Film wird nicht beobachtet", - "MovieIsMonitored": "Film wird beobachtet", "MovieIsDownloadingInterp": "Film lädt herunter - {0}% {1}", - "MovieExcludedFromAutomaticAdd": "Film vom automatischen hinzufügen ausgeschlossen", "MovieAlreadyExcluded": "Film ist schon ausgeschlossen", - "MarkAsFailedMessageText": "'{0}' wirklich als fehlgeschlagen markieren?", "Manual": "Manuell", "LogLevelTraceHelpTextWarning": "Trace logging sollte nur kurzzeitig aktiviert werden", - "LastDuration": "Letzte Laufzeit", "IncludeRecommendationsHelpText": "Prowlarrs Empfehlungen in der Entdeckungsansicht mit einbeziehen", - "IncludeProwlarrRecommendations": "Prowlarr Empfehlungen einbeziehen", "ImportFailedInterp": "Import fehlgeschlagen: {0}", - "ImportFailed": "Import fehlgeschlagen: {0}", "HiddenClickToShow": "Versteckt, klicken zum anzeigen", - "GrabReleaseMessageText": "Das Release konnte keinem Film zugeordnet werden. Ein automatischer Import wird nicht möglich sein. Trotzdem '{0}' erfassen?", "GoToInterp": "Zu {0} gehen", "ExistingTag": "Vorhandener Tag", - "ExcludeMovie": "Film ausschließen", "EnableInteractiveSearchHelpTextWarning": "Der Indexer unterstützt keine Suchen", "EnableInteractiveSearchHelpText": "Wird bei der manuellen Suche benutzt", "EnableAutomaticSearchHelpTextWarning": "Wird für die manuelle Suche benutzt", "EnableAutomaticSearchHelpText": "Wird für automatische Suchen genutzt die vom Benutzer oder von Prowlarr gestartet werden", - "DownloadWarning": "Download Warnung: {0}", "Downloading": "Lädt herunter", - "DownloadFailedInterp": "Download fehlgeschlagen: {0}", "DownloadFailed": "Download fehlgeschlagen", "DownloadClientUnavailable": "Downloader ist nicht verfügbar", "DeleteTagMessageText": "Tag '{0}' wirklich löschen?", - "DeleteSelectedMovieFilesMessage": "Ausgewählte Filme wirklich löschen?", "DeleteRestrictionHelpText": "Beschränkung '{0}' wirklich löschen?", "DeleteNotificationMessageText": "Benachrichtigung '{0}' wirklich löschen?", - "DeleteListMessageText": "Liste '{0}' wirklich löschen?", "DeleteIndexerMessageText": "Indexer '{0}' wirklich löschen?", "DeleteDownloadClientMessageText": "Downloader '{0}' wirklich löschen?", "DeleteBackupMessageText": "Backup '{0}' wirkich löschen?", - "DelayingDownloadUntilInterp": "Download verzögern bis {0} um {1}", "Cutoff": "Schwelle", - "ClickToChangeMovie": "Klicken um den Film zu bearbeiten", "CheckDownloadClientForDetails": "prüfe den Downloader für mehr Details", "CancelPendingTask": "Diese laufende Aufgabe wirklich abbrechen?", "BranchUpdateMechanism": "Branch für den externen Updateablauf", "BranchUpdate": "Verwendeter Branch zur Aktualisierung von Prowlarr", "BeforeUpdate": "Vor dem Update", - "AllowMovieChangeClickToChangeMovie": "Klicken um den Film zu bearbeiten", "AddingTag": "Tag hinzufügen", - "YouCanAlsoSearch": "Es kann auch nach der TMDb oder IMDb ID eines Filmes gesucht werden. Z.B.: 'tmdb:71663'", "VisitGithubCustomFormatsAphrodite": "Besuche Github für mehr details: ", - "Unreleased": "Unveröffentlicht", "UnableToLoadUISettings": "Oberflächen Einstellungen konnten nicht geladen werden", - "UnableToLoadTheCalendar": "Kalender konnte nicht geladen werden", "UnableToLoadRootFolders": "Stammordner konnten nicht geladen werden", - "UnableToLoadQualities": "Qualitätsprofile konnten nicht geladen werden", "UnableToLoadMediaManagementSettings": "Media Verwaltungseinstellungen konnten nicht geladen werden", - "UnableToLoadNamingSettings": "Umbenennungeinstellungen konnten nicht geladen werden", "UnableToLoadMovies": "Filme konnten nicht geladen werden", - "UnableToLoadListOptions": "Listen Einstellungen konnten nicht geladen werden", "UnableToLoadLanguages": "Sprachen konnten nicht geladen werden", - "UnableToLoadIndexerOptions": "Indexer Einstellungen konnten nicht geladen werden", "UnableToLoadHistory": "Verlauf konnte nicht geladen werden", "UnableToLoadGeneralSettings": "Allgemeine Einstellungen konnten nicht geladen werden", - "UnableToLoadDownloadClientOptions": "Downloader Einstellungen konnten nicht geladen werden", "UnableToLoadBlacklist": "Sperrliste konnte nicht geladen werden", "UnableToLoadBackups": "Backups konnten nicht geladen werden", - "UnableToAddANewRemotePathMappingPleaseTryAgain": "Die neue entfernte Pfadzuordnung konnte nicht hinzugefügt werden, bitte erneut probieren.", "UnableToAddANewQualityProfilePleaseTryAgain": "Das neue Qualitätsprofil konnte nicht hinzugefügt werden, bitte erneut probieren.", "UnableToAddANewNotificationPleaseTryAgain": "Die neue Benachrichtigung konnte nicht hinzugefügt werden, bitte erneut probieren.", - "UnableToAddANewListPleaseTryAgain": "Die neue Liste konnte nicht hinzugefügt werden, bitte erneut probieren.", "UnableToAddANewListExclusionPleaseTryAgain": "Der neue Listenausschluss konnte nicht hinzugefügt werden, bitte erneut probieren.", "UnableToAddANewIndexerPleaseTryAgain": "Der neue Indexer konnte nicht hinzugefügt werden, bitte erneut probieren.", "UnableToAddANewDownloadClientPleaseTryAgain": "Der neue Downloader konnte nicht hinzugefügt werden, bitte erneut probieren.", - "UnableToAddANewCustomFormatPleaseTryAgain": "Das neue eigene Format konnte nicht hinzugefügt werden, bitte erneut probieren.", "UnableToAddANewConditionPleaseTryAgain": "Die neue Bedingung konnte nicht hinzugefügt werden, bitte erneut probieren.", - "ThisConditionMatchesUsingRegularExpressions": "Diese Bedingung entspricht der Verwendung von Regulären Ausdrücken. Beachten Sie, dass die Zeichen {0} spezielle Bedeutungen haben und mit einem {1} maskiert werden müssen", "TagIsNotUsedAndCanBeDeleted": "Tag wird nicht benutzt und kann gelöscht werden", "StartTypingOrSelectAPathBelow": "Eingeben oder unten auswählen", "Restore": "Wiederherstellen", - "RequiredPlaceHolder": "Neue Beschränkung hinzufügen", "RegularExpressionsCanBeTested": "Reguläre Ausdrücke können getestet werden ", - "ProwlarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "Benutzerdefinierte Bedingungen gegen die unten aufgeführten Release-Eigenschaften werden unterstützt.", "ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "RSS Film Listen sowie unten aufgelistete werden untertützt.", "ProwlarrSupportsAnyIndexer": "Prowlarr unterstützt alle Indexer, welcher den Newznab/Torznab Standard implementiert (verwende 'Generic Newznab' (für Usenet) oder 'Generic Torznab' (für Torrents)) und darüber hinaus viele weitere Indexer. Wählen Sie im Folgenden Ihren Indexer aus der Liste.", "ProwlarrSupportsAnyDownloadClient": "Jeder Downloader der den Newznab-Standard verwendet oder unten aufgelistet ist wird untertützt.", - "OnDeleteHelpText": "Löschen", "NoUpdatesAreAvailable": "Es sind keine Updates verfügbar", "NoTagsHaveBeenAddedYet": "Es wurden noch keine Tags erstellt", "NoLogFiles": "Keine Log-Dateien", - "NoHistory": "Kein Verlauf", "NoBackupsAreAvailable": "Es sind keine Backups vorhanden", - "MoreDetails": "Mehr Details", "MissingMonitoredAndConsideredAvailable": "Fehlend, beobachtet und veröffentlicht", - "MissingNotMonitored": "Fehlen und nicht beobachtet", "MinutesSixty": "60 Minuten: {0}", "MinutesNinety": "90 Minuten: {0}", "MinutesHundredTwenty": "120 Minuten: {0}", "MaintenanceRelease": "Wartungsupdate", - "LoadingMovieFilesFailed": "Laden der Film-Dateien fehlgeschlagen", "LoadingMovieExtraFilesFailed": "Laden der Extra-Datien fehlgeschlagen", - "LoadingMovieCreditsFailed": "Laden von FIlmcredits fehlgeschlagen", "LinkHere": "hier", - "IgnoredPlaceHolder": "Neue Beschränkung hinzufügen", "HaveNotAddedMovies": "Es gibt noch keine FIlme in der Bibliothek. Sollen einige oder alles Filme zuerst importiert werden?", - "ForMoreInformationOnTheIndividualIndexers": "Für mehr Infomationen klicke auf die Info-Knöpfe.", "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Für mehr Infomationen klicke auf die Info-Knöpfe.", "ForMoreInformationOnTheIndividualDownloadClients": "Für mehr Infomationen klicke auf die Info-Knöpfe.", "FilterPlaceHolder": "Filme suchen", - "FileChmodHelpTexts2": "Der gleiche Modus wird auf Film-/Unterordner angewendet, bei denen das Ausführungsbit hinzugefügt wurde, z.B. 0644 wird zu 0755", "FileChmodHelpTexts1": "Oktal, wird beim Import oder Umbennen auf Mediendateien angewendet", - "FailedLoadingSearchResults": "Suchergebnisse konnten nicht geladen werden, bitte erneut versuchen.", "ExtraFileExtensionsHelpTexts2": "Vorschläge: sub, nfo, srt, jpg", - "ExtraFileExtensionsHelpTexts1": "Kommaseparierte Liste von Dateiendungen die als Extra Dateien importiert werden sollen ( .nfo wird in .nfo-orig umbenannt )", "Excluded": "Ausgeschlossen", "Exception": "Ausnahme", - "ErrorLoadingPreviews": "Fehler beim laden der Vorschauen", "ErrorLoadingContents": "Fehler beim laden der Inhalte", - "DownloadedButNotMonitored": "Heruntergeladen aber nicht beobachtet", "DownloadedAndMonitored": "Heruntergeladen und beobachtet", - "CouldNotFindResults": "Keine Ergebnisse für '{0}' gefunden", "CantFindMovie": "Warum kann der Film nicht gefunden werden?", "ApplyTagsHelpTexts4": "Ersetzen: Nur eingegebene Tags übernehmen und vorhandene entfernen( keine Tags eingeben um alle zu entfernen )", "ApplyTagsHelpTexts3": "Entfernen: Eingegebene Tags entfernen", @@ -802,19 +517,12 @@ "UILanguageHelpTextWarning": "Webseite muss neu geladen werden", "UILanguageHelpText": "Sprache für die gesamte Oberfläche", "UILanguage": "Oberflächen Sprache ( UI Language )", - "MovieInfoLanguageHelpText": "Sprache der Filminformationen", "MovieInfoLanguage": "Filminfo Sprache", - "ImportCustomFormat": "Eigenes Format importieren", "ExportCustomFormat": "Eigenes Format exportieren", - "CustomFormatUnknownConditionOption": "Unbekannte Option '{0}' für die Bedingung '{1}'", "CustomFormatUnknownCondition": "Unbekannte eigene Format Bedingung '{0}'", - "CustomFormatJSON": "Eigenes Format JSON", "DownloadPropersAndRepacksHelpText2": "Benutze 'Nicht bevorzugen' um den bevorzugte Wörter Score über Proper oder Repacks zu sortieren", - "DownloadPropersAndRepacksHelpTextWarning": "Benutze bevorzugte Wörter umd automatisch auf Proper oder Repack releases zu upgraden", "DownloadPropersAndRepacksHelpText1": "Automatisch Proper oder Repacks zum upgraden eines Filmes zulassen", - "DownloadPropersAndRepacks": "Propers und Repacks", "CopyToClipboard": "In die Zwischenablage kopieren", - "CloneCustomFormat": "Eigenes Format kopieren", "Priority": "Priorität", "InteractiveSearch": "Interaktive Suche", "IndexerPriorityHelpText": "Indexer Priorität von 1 (höchste) bis 50 (niedrigste). Standart: 25.", @@ -823,7 +531,6 @@ "Disabled": "Deaktiviert", "AutomaticSearch": "Automatische Suche", "AddIndexer": "Indexer hinzufügen", - "Blacklisted": "Gesperrt", "SaveSettings": "Einstellungen speichern", "OpenThisModal": "Dieses Modal öffnen", "MovieIndexScrollTop": "Filmindex: Nach oben scrollen", @@ -833,30 +540,19 @@ "FocusSearchBox": "Suchbox fokussieren", "CloseCurrentModal": "Momentanes Modal schließen", "AcceptConfirmationModal": "Bestätigung akzeptieren Modal", - "StartSearchForMissingMovie": "Suche für fehlenden Film starten", "StartImport": "Import starten", - "SearchFailedPleaseTryAgainLater": "Suche fehlgeschlagen, bitte versuche es später nocheinmal.", "RequiredRestrictionPlaceHolder": "Ein Release muss mindestens einen dieser Begriffe enthalten (Groß- und Kleinschreibung wird nicht berücksichtigt)", - "Released": "Veröffentlicht", "NoMatchFound": "Keine Übereinstimmung gefunden!", - "ImportRootPath": "Wähle den Ordner der alle deine Filme beinhaltet, nicht einen einzelnen Filmordner (z.B.: `{0}` und nicht `{1}`)", "ImportIncludeQuality": "Stelle sicher, dass die Qualität im Dateinamen vorkommt ( z.B.: {0} )", - "ImportErrors": "Import Fehler", "Existing": "Vorhanden", - "Digital": "Digital", "StartProcessing": "Verarbeitung starten", - "ProcessingFolders": "Verarbeitungsordner", "CancelProcessing": "Verarbeitung abbrechen", - "EditRestriction": "Beschränkung bearbeiten", "AddRestriction": "Beschränkung hinzufügen", - "AddMovie": "Film hinzufügen", "Yesterday": "Gestern", "Tomorrow": "Morgen", "Today": "Heute", - "ListTagsHelpText": "Tags Liseneinträge werden hinzugefügt mit", "IndexerLongTermStatusCheckSingleClientMessage": "Indexer wegen über 6 Stunden langen bestehenden Fehlern nicht verfügbar: {0}", "IndexerLongTermStatusCheckAllClientMessage": "Alle Indexer sind wegen über 6 Stunden langen bestehender Fehler nicht verfügbar", - "EditMovieFile": "FIlmdateil bearbeiten", "SyncAppIndexers": "App Indexer syncen", "UnableToLoadDevelopmentSettings": "Entwicklereinstellungen konnten nicht geladen werden", "TestAllApps": "Alle Apps testen", @@ -870,7 +566,6 @@ "SettingsFilterSentryEvents": "Analystische Ergeinisse filtern", "SettingsConsoleLogLevel": "Konsolen Log Level", "SearchIndexers": "Indexer suchen", - "NewznabVipCheckExpiringClientMessage": "Indexer VIP Status läuft bald ab: {0}", "NewznabVipCheckExpiredClientMessage": "Indexer VIP Status ist abgelaufen: {0}", "IndexersSelectedInterp": "{0} Indexer ausgewählt", "IndexerRss": "Indexer RSS", diff --git a/src/NzbDrone.Core/Localization/Core/el.json b/src/NzbDrone.Core/Localization/Core/el.json index a14c57882..d153e172b 100644 --- a/src/NzbDrone.Core/Localization/Core/el.json +++ b/src/NzbDrone.Core/Localization/Core/el.json @@ -1,56 +1,38 @@ { - "Downloaded": "Κατεβασμένα", "DownloadClients": "Προγράμματα Λήψης", "DownloadClientCheckUnableToCommunicateMessage": "Αδύνατο να επικοινωνήσει με {0}.", "DownloadClientCheckNoneAvailableMessage": "Δεν υπάρχει διαθέσιμο πρόγραμμα Λήψης", "DownloadClient": "Πρόγραμμα Λήψης", - "DiskSpace": "Ελληνικά", "Discover": "Ανακάλυψε", - "DigitalRelease": "Ψηφιακή Κυκλοφορία", "Details": "Λεπτομέρειες", - "Deleted": "Διαγράφηκε", "Delete": "Διαγραφή", - "Day": "Ημέρα", "Dates": "Ημερομηνίες", "Date": "Ημερομηνία", "Connections": "Συνδέσεις", "Connect": "Σύνδεση", - "CompletedDownloadHandling": "Διαχείριση Ολοκληρωμένων Λήψεων", "Collection": "Συλλογή", "Clear": "Καθαρισμός", - "ChooseAnotherFolder": "Διαλέξτε έναν άλλο Φάκελο", "Certification": "Πιστοποιητικό", - "Cast": "Διανομή Ρόλων", "Calendar": "Ημερολόγιο", - "Blacklist": "Αποριφθέντα", "BackupNow": "Δημιουργία Αντιγράφου Ασφαλείας", "Backup": "Αντίγραφο Ασφαλείας", - "AndNot": "και όχι", "Analytics": "Αναλύσεις", "All": "Όλα", - "Agenda": "Ατζέντα", "AddNew": "Προσθήκη Νέων", - "AddMovies": "Προσθήκη Ταινιών", "AddExclusion": "Προσθήκη Εξαίρεσης", "Added": "Προστέθηκε", - "Activity": "Δραστηριότητα", "Actions": "Ενέργειες", "About": "Σχετικά", "History": "Ιστορία", "HideAdvanced": "Απόκρυψη Προχωρημένων", "Health": "Υγεία", - "Genres": "Είδη", "GeneralSettingsSummary": "Θύρα, SSL, όνομα χρήστη/κωδικός, proxy, analytics και αναβαθμίσεις", "General": "Γενικά", - "FreeSpace": "Ελεύθερος Χώρος", "Formats": "Φορμάτ", - "Forecast": "Πρόβλεψη", "Folder": "Φάκελος", "Filter": "Φίλτρο", - "Filesize": "Μέγεθος Αρχείου", "Files": "Αρχεία", "Filename": "Όνομα Αρχείου", - "FileManagement": "Διαχείρηση Αρχείων", "FailedDownloadHandling": "Η Διαχείρηση Λήψης Απέτυχε", "Failed": "Απέτυχε", "EventType": "Είδος Γεγονότος", @@ -59,27 +41,19 @@ "DownloadClientStatusCheckSingleClientMessage": "Προγράμματα λήψης που είναι μη διαθέσιμα λόγων αποτυχιών: {0}", "DownloadClientStatusCheckAllClientMessage": "Όλα τα προγράμματα λήψης είναι μη διαθέσιμα λόγων αποτυχιών", "DownloadClientsSettingsSummary": "Προγράμματα λήψης, διαχείριση λήψεων και αντιστοίχηση remote path", - "DotNetVersionCheckOldUnsupportedMessage": "Η τρέχουσα εγκατάσταση του .Net Framework {0} είναι παλιά και δεν υποστηρίζεται. Παρακαλούμε αναβαθμίστε το .Net Framework σε τουλάχιστον {1}.", "DotNetVersionCheckNotRecommendedMessage": "Η τρέχουσα εγκατάσταση του .Net Framework {0} υποστηρίζεται αλλά θα σας συμβουλεύαμε να αναβαθμίσετε τουλάχιστον στην {1}.", - "DelayProfiles": "Προφίλ χρονοκαθυστέρησης", "CustomFormatsSettingsSummary": "Custom Formats και Ρυθμίσεις", - "CustomFormats": "Custom Formats", "CustomFilters": "Custom Φιλτρα", - "Crew": "Ομάδα", "ConnectSettingsSummary": "Ειδοποιήσεις, συνδέσεις σε media servers/players και custom scripts", "AppDataLocationHealthCheckMessage": "Η αναβάθμιση δεν είναι πιθανό να αποτρέψει την διαγραφή των AppData κατά την αναβάθμιση", - "AddNewTmdbIdMessage": "Μπορείτε επίσης να ψάξετε μέσω του TMDB Id της ταινίας. π.χ. tmdb:71663", "AddNewMessage": "Είναι εύκολο να προσθέσετε μια καινούρια ταινία, απλά πληκτρολογήστε το όνομα της ταινίας", "ConnectionLostAutomaticMessage": "Το Prowlarr θα προσπαθήσει να συνδεθεί αυτόματα, αλλιώς μπορείτε να κάνετε reload απο κάτω.", "Component": "Στοιχείο", "Columns": "Στήλες", "Close": "Κλείσιμο", "Cancel": "Ακύρωση", - "AudioInfo": "Στοιχεία ήχου", "Apply": "Εφαρμογή", - "AlternativeTitle": "Εναλακτικός Τίτλος", "AllMoviesHiddenDueToFilter": "Όλες οι ταινίες έχουν κρυφτεί λόγω εφαρμογής φίλτρου", "Age": "Ηλικία", - "AddNewMovie": "Προσθήκη Νέας Ταινίας", "AddList": "Προσθήκη Λίστας" } diff --git a/src/NzbDrone.Core/Localization/Core/es.json b/src/NzbDrone.Core/Localization/Core/es.json index 335cae12c..0a9e0454e 100644 --- a/src/NzbDrone.Core/Localization/Core/es.json +++ b/src/NzbDrone.Core/Localization/Core/es.json @@ -1,89 +1,60 @@ { - "IndexerSearchCheckNoAvailableIndexersMessage": "Todos los indexers están temporalmente inactivos debido a errores recientes con ellos", "IndexerSearchCheckNoAutomaticMessage": "No hay indexers con Búsqueda Automática disponibles, Prowlarr no dará ningún resultado de búsquedas automáticas", "Indexers": "Indexers", - "IndexerRssHealthCheckNoAvailableIndexers": "Todos los indexers capaces de RSS están temporalmente desactivados debido a errores recientes con el indexer", "ImportTipsMessage": "Algunos consejos para asegurarse de que la importación vaya sin problemas:", - "ImportSecondTip": "Enlazar Prowlarr a la carpeta con todas tus películas, no a una específica. ej.", "ImportMechanismHealthCheckMessage": "Activar Manipulación de Descargas Completadas", - "ImportHeader": "Importar películas que ya tienes", "ImportFirstTip": "Asegúrate de que tus archivos incluyen la calidad en el nombre del archivo. ej.", - "Import": "Importar", "iCalLink": "iCal Link", "Host": "Host", "History": "Historia", "HideAdvanced": "Ocultar Avanzado", "Health": "Salud", - "GrabSelected": "Capturar Seleccionados", "General": "General", - "FreeSpace": "Espacio Libre", "Formats": "Formatos", - "Forecast": "Pronóstico", "Folder": "Carpeta", "Filter": "Filtro", - "Filesize": "Taman̄o de archivo", "Files": "Archivos", - "FileManagement": "Administración de Archivos", "FailedDownloadHandling": "Manipulación de Descargas Fallidas", "Events": "Eventos", "Edit": "Editar", - "Downloaded": "Descargado", "DownloadClientStatusCheckSingleClientMessage": "Gestores de descargas no disponibles debido a errores: {0}", "DownloadClientStatusCheckAllClientMessage": "Los gestores de descargas no están disponibles debido a errores", "DownloadClients": "Gestores de Descargas", "DownloadClientCheckUnableToCommunicateMessage": "Incapaz de comunicarse con {0}.", "DownloadClientCheckNoneAvailableMessage": "Ningún gestor de descargas disponible", - "DotNetVersionCheckOldUnsupportedMessage": "El .Net Framework {0} instalado actualmente es antiguo y por lo tanto, no compatible. Por favor actualiza .Net Framework a por lo menos, {1}.", "DotNetVersionCheckNotRecommendedMessage": "El .Net Framework {0} instalado actualmente es compatible pero recomendamos actualizar a por lo menos {1}.", - "DiskSpace": "Espacio en Disco", "Discover": "Descubrir", "Delete": "Borrar", - "DelayProfiles": "Perfiles De Retraso", "Day": "Día", "Dates": "Fechas", "Date": "Fecha", - "CustomFormats": "Formatos Personalizados", "CustomFilters": "Filtros Personalizados", - "Crew": "Equipo", "Connections": "Conexiones", "Connect": "Conectar", - "CompletedDownloadHandling": "Manipulación de descargas completas", "Clear": "Borrar", - "ChooseAnotherFolder": "Elige otra Carpeta", "Cast": "Reparto", - "Calendar": "Calendario", "Blacklist": "Bloqueadas", "BackupNow": "Hacer copia de seguridad", "Backup": "Backup", "AppDataLocationHealthCheckMessage": "No será posible actualizar para prevenir que AppData se borre durante la actualización", - "AndNot": "y no", "Analytics": "Analíticas", "All": "Todas", - "Agenda": "Agenda", "AddNewTmdbIdMessage": "También puedes buscar usando el ID de TMDb de la película. Ej. tmdb:71663", - "AddNewMessage": "Es fácil añadir una película nueva, tan solo comienza a escribir el título de la que quieres añadir", "AddNew": "Añadir Nueva", - "AddMovies": "Añadir Películas", "AddExclusion": "An̄adir Exclusión", - "Activity": "Actividad", "About": "Acerca", - "Week": "Semana", "View": "Vista", "Updates": "Actualizaciones", "UpdateCheckUINotWritableMessage": "No se puede instalar la actualización porque la carpeta UI '{0}' no tiene permisos de escritura para el usuario '{1}'.", "UpdateCheckStartupTranslocationMessage": "No se puede instalar la actualización porque la carpeta de arranque '{0}' está en una carpeta de \"App Translocation\".", "UpdateCheckStartupNotWritableMessage": "No se puede instalar la actualización porque la carpeta de arranque '{0}' no tiene permisos de escritura para el usuario '{1}'.", - "UpdateAll": "Actualizar Todo", "UnselectAll": "Deseleccionar Todo", - "Unmonitored": "No monitoreadas", "UnmappedFolders": "Carpetas no Mapeadas", "UI": "UI", - "Titles": "Títulos", "Tasks": "Tareas", "Tags": "Etiquetas", "System": "Sistema", "Style": "Estilo", - "Studio": "Estudio", "Status": "Estado", "Sort": "Ordenar", "ShowAdvanced": "Mostrar Avanzado", @@ -91,132 +62,83 @@ "SetTags": "Poner Etiquetas", "SelectAll": "Seleccionar Todas", "Security": "Seguridad", - "SearchSelected": "Buscar Seleccionadas", "SearchForMissing": "Buscar faltantes", - "SearchFiltered": "Buscar Filtradas", "SearchAll": "Buscar Todas", "Search": "Buscar", "Scheduled": "Programado", "SaveChanges": "Guardar Cambios", - "RSSSync": "Sincronización RSS", "RootFolders": "Carpetas de Origen", - "RootFolderCheckSingleMessage": "La carpeta de origen no existe: {0}", "RootFolderCheckMultipleMessage": "Varias carpetas de origen no existen: {0}", - "RootFolder": "Carpeta de Origen", "Restrictions": "Restricciones", "RestoreBackup": "Recuperar Backup", - "RenameFiles": "Renombrar Archivos", "RemoveSelected": "Borrar Seleccionados", - "RemovedMovieCheckSingleMessage": "La película {0} ya no está en TMDb", "RemovedMovieCheckMultipleMessage": "Las películas {0} ya no están en TMDb", - "RemotePathMappings": "Mapeados de Rutas Remotas", "ReleaseBranchCheckPreviousVersionMessage": "La versión {0} es de una versión anterior de Prowlarr, ajusta la versión a 'Nightly' para recibir actualizaciones", "ReleaseBranchCheckOfficialBranchMessage": "Las versión {0} no es una versión válida de Prowlarr, no recibirás actualizaciones", - "RefreshAndScan": "Actualizar y Escanear", "Refresh": "Actualizar", "Queue": "Cola", - "QualityProfiles": "Perfiles de Calidad", "QualityProfile": "Perfil de Calidad", "QualityDefinitions": "Definiciones de Calidad", - "Quality": "Calidad", "PtpOldSettingsCheckMessage": "Los siguientes indexers PassThePopcorn tienen configuraciones obsoletas y deben de ser actualizados: {0}", "ProxyCheckResolveIpMessage": "No se pudo resolver la dirección IP del Host Proxy configurado {0}", "ProxyCheckFailedToTestMessage": "Fallo al comprobar el proxy: {0}", "ProxyCheckBadRequestMessage": "Fallo al comprobar el proxy. StatusCode: {0}", "Proxy": "Proxy", - "Profiles": "Perfiles", "PreviewRename": "Previsualizar Renombrado", - "Path": "Ruta", "Options": "Opciones", "NoChange": "Sin Cambio", "NoChanges": "Sin Cambios", - "ImportListStatusCheckSingleClientMessage": "Listas no disponibles debido a errores: {0}", "ImportListStatusCheckAllClientMessage": "Las listas no están disponibles debido a errores", "Movies": "Películas", - "MovieNaming": "Renombrar Películas", "MonoNotNetCoreCheckMessage": "Por favor actualiza a la versión .NET Core de Prowlarr", - "MovieIndex": "Índice de Películas", "MovieEditor": "Editor de Películas", - "Movie": "Película", "MoreInfo": "Más Información", - "Month": "Mes", "Monitor": "Monitorear", - "Missing": "Falta", "MinimumAvailability": "Disponibilidad Mínima", - "MinAvailability": "Disponibilidad mínima", "Metadata": "Metadatos", - "MediaManagement": "Multimedia", "MediaInfoDllCheckMessage": "La Librería MediaInfo no se ha cargado {0}", - "ManualImport": "Importación manual", "Logging": "Registro de eventos", - "LogFilesLocationMessage": "Los archivos de registro se encuentran en:", "LogFiles": "Archivos de Registro", - "Lists": "Listas", "ListExclusions": "Excluidas de las listas", "Languages": "Idiomas", "Language": "Idioma", "IndexerStatusCheckAllClientMessage": "Los indexers no están disponibles debido a errores", "Added": "An̄adida", "Actions": "Acciones", - "Year": "Año", "Wanted": "Buscado", - "UpdateSelected": "Actualizar Seleccionadas", "UISettingsSummary": "Calendario, fecha y opciones de color deteriorado", - "Timeleft": "Tiempo restante", "TagsSettingsSummary": "Ver todas las etiquetas y cómo se usan. Las etiquetas no utilizadas se pueden eliminar", - "SourceTitle": "Título de Origen", "SizeOnDisk": "Tamaño en Disco", "Size": "Tamaño", - "Runtime": "Duración", "Renamed": "Renombrado", - "ReleaseTitle": "Título del Estreno", "ReleaseStatus": "Estado del Estreno", - "ReleaseGroup": "Grupo de Estreno", "Ratings": "Calificaciones", - "QualitySettingsSummary": "Tamaños de calidad y nombrado", "Protocol": "Protocolo", - "Progress": "Progreso", "ProfilesSettingsSummary": "Calidad, Idioma y Perfiles de retraso", - "PhysicalRelease": "Estreno Físico", "OutputPath": "Ruta de Output", - "MovieTitle": "Título de la Película", "MountCheckMessage": "El punto de montaje que contiene la ruta de una película es de read-only: ", "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls todavía está habilitado, considera la posibilidad de eliminar la opción MONO_TLS_PROVIDER=legacy", - "MonitoredOnly": "Monitoreadas Solamente", "MetadataSettingsSummary": "Crear archivos de metadatos cuando las películas se importen ó actualicen", - "MediaManagementSettingsSummary": "Ajustes de nombrado y gestión de archivos", "MassMovieSearch": "Búsqueda en masa de películas", - "ListsSettingsSummary": "Listas de importación, excluidas de la lista", "LastWriteTime": "Última Fecha de Escritura", "IndexerStatusCheckSingleClientMessage": "Indexers no disponibles debido a errores: {0}", - "IndexersSettingsSummary": "Indexers y restricciones de lanzamientos", "IndexerSearchCheckNoInteractiveMessage": "No hay indexers con Búsqueda Interactiva activada, Prowlarr no obtendrá ningún resultado en las búsquedas", - "IndexerRssHealthCheckNoIndexers": "No hay indexers disponibles con sincronización RSS activada, Prowlarr no capturará nuevos estrenos automáticamente", "Indexer": "Indexer", - "InCinemas": "En cines", "Imported": "Importado", - "Ignored": "Ignorado", "Grabbed": "Capturado", - "Genres": "Géneros", "GeneralSettingsSummary": "Puerto, SSL, nombre de usuario/contraseña , proxy, analíticas y actualizaciones", "Filename": "Nombre del archivo", "Failed": "Ha fallado", "EventType": "Tipo de Evento", "DownloadClientsSettingsSummary": "Gestores de descargas, manipulación de descargas y mapeados remotos", "DownloadClient": "Gestor de Descargas", - "DigitalRelease": "Estreno Digital", "Details": "Detalles", - "Deleted": "Borrado", "CutoffUnmet": "Corte No Alcanzado", - "CustomFormatsSettingsSummary": "Formatos Personalizados y Ajustes", "ConnectSettingsSummary": "Notificaciones, conexiones a servidores/reproductores y scripts personalizados", - "Collection": "Colección", "Certification": "Certificación", "Warn": "Advertencia", - "VideoCodec": "Codec de Vídeo", "Unavailable": "No disponible", "Type": "Tipo", - "TotalSpace": "Espacio Total", "Title": "Título", "Time": "Fecha", "TestAll": "Testear Todo", @@ -228,34 +150,24 @@ "Seeders": "Seeders", "Save": "Guardar", "Restart": "Reiniciar", - "RemoveRootFolder": "Eliminar carpeta de origen", "Reload": "Recargar", - "RelativePath": "Ruta Relativa", "RejectionCount": "Número de Rechazos", "Peers": "Peers", "PageSize": "Tamaño de Página", - "OrganizeModalSuccess": "Éxito! Mi trabajo está hecho, no hay archivos pendientes de renombrar.", "OrganizeModalNamingPattern": "Modelo de Renombrado:", - "OrganizeModalDisabled": "El renombrado está inactivo, nada que renombrar", "OrganizeModalAllPathsRelative": "Todas las rutas son relativas a:", - "OrganizeAndRename": "Organizar y Renombrar", "Organize": "Organizar", "Ok": "Ok", "OAuthPopupMessage": "Pop-ups bloqueados por su navegador", "Name": "Nombre", - "MoveFiles": "Mover Archivos", "Monitored": "Monitoreadas", "Message": "Mensaje", - "Location": "Localización", "Level": "Nivel", "KeyboardShortcuts": "Atajos de Teclado", "Info": "Información", - "ImportExistingMovies": "Importar Películas Existentes", "HealthNoIssues": "No hay problemas con tu configuración", - "HardlinkCopyFiles": "Hardlink/Copia de Archivos", "Extension": "Extensión", "Error": "Error", - "CustomFormatScore": "Puntuación de Formato personalizado", "ConnectionLostMessage": "Prowlarr ha perdido su conexión con el backend y tendrá que ser recargado para recuperar su funcionalidad.", "ConnectionLostAutomaticMessage": "Prowlarr intentará conectarse automáticamente, o haz clic en el botón de recarga abajo.", "ConnectionLost": "Conexión perdida", @@ -263,239 +175,148 @@ "Columns": "Columnas", "Close": "Cerrar", "Cancel": "Cancelar", - "AudioInfo": "Audio Info", "Apply": "Aplicar", - "AlternativeTitle": "Título alternativo", "AllMoviesHiddenDueToFilter": "Todas las películas están ocultas debido al filtro aplicado.", "Age": "Edad", - "AddNewMovie": "Añadir película nueva", "AddList": "Añadir lista", "SystemTimeCheckMessage": "El reloj del sistema está retrasado más de un día. Las tareas de mantenimiento no se ejecutarán correctamente hasta que se haya corregido", - "MonitorMovie": "Monitorear Película", "ExistingMovies": "Película(s) Existente", - "EditRemotePathMapping": "Editar Mapping de Ruta Remota", "DetailedProgressBarHelpText": "Mostrar texto en la barra de progreso", - "InteractiveImport": "Importación Interactiva", "DetailedProgressBar": "Barra de Progreso Detallada", - "AddRemotePathMapping": "Añadir Mapping de la Ruta Remota", "UnsavedChanges": "Cambios no guardados", - "Table": "Tabla", "ShowTitle": "Mostrar Título", - "ShowStudio": "Mostrar Estudio", "ShowSizeOnDisk": "Mostrar Tamaño en Disco", "ShowSearchHelpText": "Mostrar botón de búsqueda al pasar el cursor por encima", "ShowSearch": "Mostrar Búsqueda", - "ShowQualityProfile": "Mostrar Perfil de Calidad", "ShowPath": "Mostrar Ruta", - "ShowMonitored": "Mostrar Monitoreadas", "ShowDateAdded": "Mostrar Fecha de Añadido", - "SettingsWeekColumnHeaderHelpText": "Mostrado sobre cada columna cuando la vista activa es semana", "SettingsWeekColumnHeader": "Encabezado de la columna semanal", - "SettingsUiLanguageHelpText": "Idioma que Prowlarr usará para el UI", "SettingsUiLanguage": "Idioma de UI", "SettingsTimeFormat": "Formato de Hora", "SettingsShowRelativeDatesHelpText": "Mostrar fechas relativas (Hoy/Ayer/etc) o absolutas", "SettingsShowRelativeDates": "Mostrar Fechas Relativas", "SettingsShortDateFormat": "Formato Corto de Fecha", - "SettingsRemotePathMappingRemotePathHelpText": "Ruta de origen al directorio al que accede el Gestor de Descargas", "SettingsRemotePathMappingRemotePath": "Ruta Remota", - "SettingsRemotePathMappingLocalPathHelpText": "La ruta que Prowlarr tiene que usar para acceder a la ruta remota localmente", "SettingsRemotePathMappingLocalPath": "Ruta Local", - "SettingsRemotePathMappingHostHelpText": "El mismo host especificado para el Gestor de Descargas remoto", "SettingsLongDateFormat": "Formato Largo de Fecha", - "SettingsFirstDayOfWeek": "Primer Día de la Semana", "SelectFolder": "Seleccionar Carpeta", - "SearchOnAdd": "Buscar al Añadir", "SearchMovie": "Buscar Película", - "RecentFolders": "Carpetas Recientes", "QuickImport": "Importación Rápida", - "PosterSize": "Tamaño del Poster", "Posters": "Posters", - "PosterOptions": "Opciones del Poster", "PendingChangesStayReview": "Permanecer y revisar cambios", "PendingChangesMessage": "Hay cambios sin salvar, estás seguro de que quieres salir de esta página?", "PendingChangesDiscardChanges": "Descartar cambios y salir", - "OverviewOptions": "Opciones de Resumen", "Overview": "Resumen", "MonoVersionCheckUpgradeRecommendedMessage": "Le versión de Mono {0} instalada actualmente es compatible pero se recomienda actualizar a {1}.", - "MonoVersionCheckOldNotSupportedMessage": "Le versión de Mono {0} instalada actualmente es antigua y no compatible. Por favor actualiza Mono a la versión {1}.", "MonoVersionCheckNotSupportedMessage": "La versión de Mono {0} instalada actualmente no es compatible. Por favor actualiza Mono a la versión {1}.", "SettingsEnableColorImpairedModeHelpText": "Estilo modificado para permitir que usuarios con problemas de color distingan mejor la información codificada por colores", "SettingsEnableColorImpairedMode": "Activar Modo De Color Degradado", - "Group": "Grupo", "GrabRelease": "Capturar Estreno", - "GrabID": "Capturar ID", "Grab": "Capturar", - "Global": "Global", "GeneralSettings": "Ajustes Generales", - "FollowPerson": "Seguir Persona", "Folders": "Carpetas", "Fixed": "Arreglado", - "FirstDayOfWeek": "Primer Día de la Semana", "FileNames": "Nombres de Archivos", - "FileDateHelpText": "Cambiar la fecha del archivo al importar/rescan", "Exluded": "Excluida", - "Ended": "Terminó", "EnableSslHelpText": " Requiere reiniciar la aplicación como administrador para que surta efecto", "EnableMediaInfoHelpText": "Extraiga información de video como resolución, tiempo de ejecución e información de códec de los archivos. Esto requiere que Prowlarr lea partes del archivo y puede causar una alta actividad en el disco o en la red durante los escaneos.", "Enable": "Habilitar", - "EditPerson": "Editar Persona", "EditMovie": "Editar Película", - "Edition": "Edición", "DownloadWarningCheckDownloadClientForMoreDetails": "Advertencia de descarga: consulte el gestor de descargas para obtener más detalles", - "DownloadPropers": "Descargar Propers", "DownloadFailedCheckDownloadClientForMoreDetails": "Error de descarga: consulte el gestor de descargas para obtener más detalles", "DownloadClientSettings": "Ajustes de Gestor de Descargas", "Docker": "Docker", - "DestinationRelativePath": "Ruta Relativa de Destino", "DestinationPath": "Ruta de Destino", "DeleteTag": "Borrar Etiqueta", - "DeleteSelectedMovieFiles": "Borrar Archivos Seleccionados", "DeleteRestriction": "Borrar Restricción", - "DeleteQualityProfile": "Borrar Perfil de Calidad", "DeleteNotification": "Borrar Notificación", - "DeleteList": "Borrar Lista", "DeleteIndexer": "Borrar Indexer", - "DeleteImportListExclusion": "Borrar exclusión de lista de importación", "DeleteFile": "Borrar archivo", - "DeleteEmptyFoldersHelpText": "Borrar carpetas vacías durante la exploración del disco y cuando se eliminen archivos", "DeleteEmptyFolders": "Borrar carpetas vacías", "DeleteDownloadClient": "Borrar Gestor de Descargas", - "DeleteDelayProfile": "Borrar Perfil de Retraso", "DeleteCustomFormat": "Borrar Formato Personalizado", "DeleteBackup": "Borrar Backup", "DelayProfile": "Perfil de Retraso", "DBMigration": "Migración de DB", - "CutoffHelpText": "Una vez que se alcanze esta calidad, Prowlarr no descargará películas", "CreateGroup": "Crear grupo", - "CreateEmptyMovieFoldersHelpText": "Crear carpetas de películas que faltan durante la exploración del disco", "CreateEmptyMovieFolders": "Crear carpetas de películas vacías", - "Conditions": "Condiciones", "ColonReplacementFormatHelpText": "Cambia la forma en que Prowlarr reemplaza el colon", - "ColonReplacement": "Reemplazo de colon", "CloneProfile": "Clonar Perfil", "CloneIndexer": "Clonar Indexer", - "CloneFormatTag": "Clonar Format Tag", "ClientPriority": "Prioridad de Cliente", - "ClickToChangeQuality": "Clic para cambiar la calidad", "ClickToChangeLanguage": "Clic para cambiar el idioma", - "CheckForFinishedDownloadsInterval": "Intervalo para verificar descargas terminadas", "ChangeHasNotBeenSavedYet": "El cambio aún no se ha guardado", - "ChangeFileDate": "Cambiar Fecha de Archivo", "CertificationCountryHelpText": "Seleccionar país para certificaciones de películas", - "CertificationCountry": "País de certificación", "CertificateValidationHelpText": "Cambiar la rigidez de la validación de la certificación HTTPS", "CertificateValidation": "Validación de certificado", "BypassProxyForLocalAddresses": "Omitir Proxy para Direcciones Locales", "Branch": "Rama", - "BlacklistRelease": "Bloquear este Estreno", "BlacklistHelpText": "Evita que Prowlarr vuelva a capturar esta película automáticamente", "BindAddressHelpText": "Dirección IP4 válida o '*' para todas las interfaces", "Backups": "Backups", "BackupRetentionHelpText": "Backups automáticos anteriores al período de retención serán borrados automáticamente", "BackupIntervalHelpText": "Intervalo entre backups automáticos", "BackupFolderHelpText": "Las rutas relativas estarán en el directorio AppData de Prowlarr", - "AvailabilityDelayHelpText": "Cantidad de tiempo antes o después de la fecha disponible para buscar Película", "AvailabilityDelay": "Retraso de Disponibilidad", - "AutoUnmonitorPreviouslyDownloadedMoviesHelpText": "Las películas eliminadas del disco son automáticamente umonitored en Prowlarr", "AutoRedownloadFailedHelpText": "Buscar e intentar descargar automáticamente una versión diferente", "Automatic": "Automático", - "AutoDownloadPropersHelpText": "Debería Prowlarr automáticamente actualizar a propers cuando estén disponible?", "AuthenticationMethodHelpText": "Requerir nombre de usuario y contraseña para acceder Prowlarr", "Authentication": "Autenticación", - "AsAllDayHelpText": "Los eventos aparecerán como eventos del día entero en su calendario", "AreYouSureYouWantToResetYourAPIKey": "¿Está seguro de que desea restablecer su clave API?", "ApiKey": "Clave API", - "AreYouSureYouWantToDeleteThisRemotePathMapping": "¿Está seguro de que desea eliminar esta ruta remota?", "AreYouSureYouWantToDeleteThisImportListExclusion": "Estás seguro que quieres borrar esta exclusión de lista de importación?", - "AreYouSureYouWantToDeleteThisDelayProfile": "Está seguro que quieres borrar este perfil de retraso?", "ApplyTags": "Aplicar Etiquetas", "AppDataDirectory": "Directorio de AppData", "AnalyticsEnabledHelpText": "Envíe información anónima de uso y error a los servidores de Prowlarr. Esto incluye información sobre su navegador, qué páginas de Prowlarr WebUI utiliza, informes de errores, así como el sistema operativo y la versión en tiempo de ejecución. Usaremos esta información para priorizar funciones y correcciones de errores.", - "AnalyseVideoFiles": "Analizar archivos de vídeo", "AlreadyInYourLibrary": "Ya esta en tu librería", - "AllowHardcodedSubsHelpText": "Hardcoded subs que sean detectados serán automáticamente descargados", "AllowHardcodedSubs": "Permitir Hardcoded Subs", - "AgeWhenGrabbed": "Edad (cuando capturada)", "AddImportExclusionHelpText": "Prevenir que la película sea añadida a Prowlarr mediante listas", - "AddMoviesMonitored": "Añadir Películas Monitoreadas", "AddListExclusion": "Añadir Exclusión De Lista", "YesCancel": "Si, Cancela", - "WhitelistedSubtitleTags": "Etiquetas de Subtítulos Permitidas", "WhitelistedHardcodedSubsHelpText": "Las etiquetas de los subtítulos aquí, no se considerarán incrustados", - "WeekColumnHeader": "Encabezado de la Columna de Semana", "Version": "Versión", "Username": "Nombre de usuario", "UseProxy": "Usar el Proxy", - "UsenetDelayHelpText": "Retraso en minutos a esperar antes de descargar un lanzamiento de Usenet", "UsenetDelay": "Retraso de Usenet", "Usenet": "Usenet", - "UseHardlinksInsteadOfCopy": "Usar Hardlinks en vez de Copia", "UrlBaseHelpText": "Para soporte de reverse proxy, vacio por defecto", "URLBase": "URL Base", "Uptime": "Tiempo de actividad", - "UpgradeAllowedHelpText": "Si está desactivado las calidades no serán actualizadas", "UpdateScriptPathHelpText": "Ruta del script propio que toma el paquete de actualización y se encarga del proceso de actualización restante", "UpdateMechanismHelpText": "Usar el actualizador de Prowlarr o un script", "UpdateAutomaticallyHelpText": "Descargar e instalar actualizaciones automáticamente. Se podrán instalar desde Sistema: Actualizaciones también", - "UnmonitoredHelpText": "Incluir las peliculas no monitoreadas en el feed de iCal", "Ungroup": "Desagrupar", "UnableToLoadTags": "No se pueden cargar las Etiquetas", - "UnableToLoadRestrictions": "No se pueden cargar las Restricciones", "UnableToLoadRemotePathMappings": "No se pueden cargar las Rutas de los Mapeados Remotos", - "UnableToLoadQualityProfiles": "No se puden cargar los Perfiles de Calidad", "UnableToLoadQualityDefinitions": "No se pueden cargar las Definiciones de Calidad", "UnableToLoadNotifications": "No se pueden cargar las Notificaciones", - "UnableToLoadMetadata": "No se pueden cargar los Metadatos", "UnableToLoadLists": "No se puden cargar las Listas", - "UnableToLoadListExclusions": "No se pueden cargas las Excluidas de la Lista", "UnableToLoadIndexers": "No se pueden cargar los indexers", "UnableToLoadDownloadClients": "No se puden cargar los gestores de descargas", - "UnableToLoadDelayProfiles": "No se pueden cargar los Perfiles de Retraso", "UnableToLoadCustomFormats": "No se pueden cargar los Formatos Propios", "UISettings": "Ajustes del UI", - "TotalFileSize": "Tamaño Total del Archivo", "Torrents": "Torrents", - "TorrentDelayHelpText": "Retraso en minutos a esperar antes de descargar un torrent", "TorrentDelay": "Retraso del Torrent", - "TmdbIdHelpText": "La Id de TMDb de la película a exluir", "TMDBId": "TMDb Id", - "TimeFormat": "Formato de Hora", "TestAllLists": "Comprobar Todas las Listas", - "TestAllIndexers": "Comprobar Todos los Indexers", "TestAllClients": "Comprobar Todos los Gestores", "TagsHelpText": "Se aplica a películas con al menos una etiqueta coincidente", "SuggestTranslationChange": "Sugerir un cambio en la traducción", "StartupDirectory": "Directorio de arranque", - "StandardMovieFormat": "Formato de Película Estándar", "SSLPort": "Puerto SSL", - "SslCertPathHelpText": "Ruta del archivo pfx", "SSLCertPath": "Ruta del Certificado SSL", - "SslCertPasswordHelpText": "Contraseña del archivo pfx", "SSLCertPassword": "Contraseña del Certificado SSL", - "SourceRelativePath": "Ruta de Origen Relativo", "SourcePath": "Ruta de Origen", - "SorryThatMovieCannotBeFound": "Lo siento, no he encontrado esa película.", "SkipFreeSpaceCheckWhenImportingHelpText": "Usar cuando Prowlarr no pueda detectar el espacio disponible en la carpeta de películas", - "SkipFreeSpaceCheck": "Saltarse Comprobación de Espacio Disponible", "ShowUnknownMovieItems": "Mostrar Elementos Desconocidos", - "ShowTitleHelpText": "Mostrar el título de la película debajo del poster", "ShowQualityProfileHelpText": "Mostrar el perfil de calidad debajo del poster", - "ShowMovieInformationHelpText": "Mostrar géneros y certificación", "ShowMovieInformation": "Mostrar Información de la Película", - "ShowMonitoredHelpText": "Mostrar el estado de monitoreo debajo del poster", "ShowCutoffUnmetIconHelpText": "Mostrar el icono para los ficheros cuando no se ha alcanzado el corte", - "ShowAsAllDayEvents": "Mostrar como Eventos de Todo el Día", "ShouldMonitorHelpText": "Si se habilita, las películas añadidas desde esta lista serán también monitoreadas", - "SetPermissionsLinuxHelpTextWarning": "Si no estas seguro de lo que hacen estos ajustes, no los modifiques.", "SetPermissionsLinuxHelpText": "Debe chmod ser ejecutado una vez los archivos hayan sido importados/renombrados?", - "SetPermissions": "Ajustar Permisos", "SendAnonymousUsageData": "Enviar Datos de Uso Anónimamente", - "SearchForMovie": "Buscar película", "ScriptPath": "Ruta del Script", - "RssSyncIntervalHelpTextWarning": "Se aplicará a todos los indexers, por favor sigue las reglas de los mismos", "RSSSyncInterval": "Intervalo de Sincronización de RSS", - "RetentionHelpText": "Sólo Usenet: Ajustar a cero para retención ilimitada", "Retention": "Retención", "Result": "Resultado", "RestartRequiredHelpTextWarning": "Requiere reiniciar para que surta efecto", @@ -503,132 +324,80 @@ "RestartNow": "Reiniciar Ahora", "ResetAPIKey": "Reajustar API", "Reset": "Reajustar", - "RescanMovieFolderAfterRefresh": "Reescanear la Carpeta de Películas después de Actualizar", "RescanAfterRefreshHelpTextWarning": "Prowlarr no detectará los cambios automáticamente en los ficheros si no se ajusta a 'Siempre'", - "RescanAfterRefreshHelpText": "Reescanear la carpeta de películas después de actualizar la película", "RequiredHelpText": "Esta condición {0} ha de igualar al formato propio para aplicarse. Si no, una sóla {1} es suficiente.", - "ReplaceIllegalCharactersHelpText": "Reemplazar caracteres ilegales. Si está desactivado, Prowlarr los eliminará si no", "ReplaceIllegalCharacters": "Reemplazar Caracteres Ilegales", - "Reorder": "Reordenar", "RenameMoviesHelpText": "Prowlarr usará el nombre del archivo si el renombrado está deshabilitado", - "RenameMovies": "Renombrar Películas", "RemoveHelpTextWarning": "Eliminar borrará la descarga y el/los fichero(s) del gestor de descargas.", - "RemoveFromQueue": "Eliminar de la cola", "RemoveFromDownloadClient": "Eliminar del Gestor de Descargas", - "RemoveFromBlacklist": "Eliminar de lista de bloqueados", "RemoveFilter": "Eliminar filtro", - "RemoveFailedDownloadsHelpText": "Eliminar descargas fallidas del historial del gestor de descargas", "RemovedFromTaskQueue": "Eliminar de la cola de tareas", - "RemoveCompletedDownloadsHelpText": "Eliminar las descargas ya importadas del historial del gestor de descargas", "Remove": "Eliminar", - "ReleaseRejected": "Lanzamiento Rechazado", "ReleaseDates": "Fechas de Estreno", "RefreshMovie": "Actualizar película", - "RefreshInformationAndScanDisk": "Actualizar la información al escanear el disco", "Redownload": "Volver a descargar", - "RecyclingBinCleanup": "Limpieza de Papelera de Reciclaje", "RecyclingBin": "Papelera de Reciclaje", - "RecycleBinHelpText": "Los archivos iran aquí una vez se hayan borrado en vez de ser borrados permanentemente", "RecycleBinCleanupDaysHelpTextWarning": "Los archivos en la papelera de reciclaje más antiguos que el número de días seleccionado serán limpiados automáticamente", - "RecycleBinCleanupDaysHelpText": "Ajustar a 0 para desactivar la limpieza automática", "Reason": "Razón", - "Real": "Real", "ReadTheWikiForMoreInformation": "Lee la Wiki para más información", - "ProwlarrTags": "Etiquetas de Prowlarr", "Prowlarr": "Prowlarr", "QualitySettings": "Ajustes de Calidad", - "QualityCutoffHasNotBeenMet": "Corte de calidad no ha sido alcanzado", "PublishedDate": "Fecha de Publicación", "ProxyUsernameHelpText": "Tienes que introducir tu nombre de usuario y contraseña sólo si son requeridos. Si no, déjalos vacios.", "ProxyType": "Tipo de Proxy", "ProxyPasswordHelpText": "Tienes que introducir tu nombre de usuario y contraseña sólo si son requeridos. Si no, déjalos vacios.", "ProxyBypassFilterHelpText": "Usa ',' como separador, y '*.' como wildcard para subdominios", - "ProtocolHelpText": "Elige qué protocolo(s) se usará y cual será el preferido cuando haya que elegir entre lanzamientos iguales", "Proper": "Apropiado", "PriorityHelpText": "Priorizar múltiples Gestores de Descargas. Se usa Round-Robin para gestores con la misma prioridad.", "PreferredSize": "Tamaño Preferido", - "PreferIndexerFlagsHelpText": "Priorizar lanzamientos con marcas especiales", "PreferIndexerFlags": "Preferir Marcas del Indexer", "PortNumber": "Número de Puerto", "Port": "Puerto", - "Permissions": "Permisos", "Password": "Contraseña", "PageSizeHelpText": "Número de elementos por página", "PackageVersion": "Versión del paquete", - "Original": "Original", "OnDownloadHelpText": "Notificar cuando las películas se hayan importado exitosamente", - "NotMonitored": "No Monitoreadas", "NotificationTriggers": "Desencadenantes de Notificaciones", - "NotAvailable": "No Disponible", "NoMinimumForAnyRuntime": "Sin mínimo para el tiempo de ejecución", "NoLimitForAnyRuntime": "SIn límite para el tiempo de ejecución", "NoLeaveIt": "No, Déjalo", "New": "Nueva", "NetCore": ".NET Core", - "NamingSettings": "Ajustes de Renombrado", "MustNotContain": "No Debe Contener", - "MustContain": "Debe Contener", "MovieYearHelpText": "Año de la película a excluir", - "MovieYear": "Año de la Película", "MovieTitleHelpText": "Ttítulo de la película a excluir (puedes ser cualquier cosa)", - "MovieIsDownloading": "Le película está descargando", "MovieInfoLanguageHelpTextWarning": "Recargar el Navegador", - "MovieID": "ID de Película", "MovieFolderFormat": "Formato de Carpeta de Película", - "MovieFiles": "Archivos", "MovieAvailableButMissing": "Película Disponible pero Ausente", "MonoVersion": "Version de Mono", - "MonitoredHelpText": "Descargar película si está disponible", "Mode": "Modo", "MinimumLimits": "Límites Mínimos", - "MinimumFreeSpaceWhenImportingHelpText": "Evitar importación si dejase menos de esta cantidad en disco disponible", "MinimumFreeSpace": "Espacio Libre Mínimo", - "MinimumAgeHelpText": "Sólo Usenet: Edad mínima en minutos de los NZB para ser descargados. Usa esto para dar a los nuevos lanzamientos tiempo de propagarse en tu proveedor de usenet.", "MinimumAge": "Edad Mínima", - "MinFormatScoreHelpText": "Puntuación mínima del formato propio permitida para descargar", "MIA": "MIA", - "MetadataSettings": "Ajustes de Metadatos", "MediaManagementSettings": "Ajustes Multimedia", - "MediaInfo": "Información Multimedia", "Mechanism": "Mecanismo", - "MaximumSizeHelpText": "Tamaño máximo de un lanzamiento para ser importado en MB. Ajustar a cero para ilimitado", "MaximumSize": "Tamaño Máximo", "MaximumLimits": "Límites Máximos", - "MarkAsFailed": "Marcar como Fallida", "Logs": "Registros", "LogLevel": "Nivel de Registro", - "Local": "Local", "ListUpdateInterval": "Intervalo de Actualización de Lista", - "ListSyncLevelHelpText": "Las películas en la librería se borrarán o desmonitorearán si no están en tu lista", "ListSettings": "Ajustes de Lista", - "Links": "Enlaces", "LaunchBrowserHelpText": " Abrir un navegador web e ir a la página de inicio de Prowlarr al arrancar la app.", - "LanguageHelpText": "Idioma de los Lanzamientos", "Interval": "Intervalo", - "IndexerSettings": "Ajustes de Indexer", "IndexerFlags": "Marcas de Indexer", - "IncludeUnmonitored": "Icluir No Monitoreados", "IncludeUnknownMovieItemsHelpText": "Mostrar items sin ninguna película en la cola, esto incluye películas renombradas o cualquier otra cosa en la categoría de Prowlarr", "IncludeHealthWarningsHelpText": "Incluir Alertas de Salud", - "IncludeCustomFormatWhenRenamingHelpText": "Incluir en el formato de renombrado {Formatos Propios}", "IncludeCustomFormatWhenRenaming": "Incluir el Formato Propio al Renombrar", - "ImportMovies": "Importar Películas", "Importing": "Importando", - "ImportExtraFilesHelpText": "Importar archivos extra (subtítulos, info, etc) después de importar una película", "ImportExtraFiles": "Importar Archivos Extra", - "ImportedTo": "Importado a", "IllRestartLater": "Lo reiniciaré más tarde", - "IgnoredHelpText": "Este lanzamiento será rechazado si contiene uno ó más de estos términos (mayúsculas ó minúsculas)", "IgnoreDeletedMovies": "Ignorar Películas Eliminadas", "IgnoredAddresses": "Direcciones Ignoradas", - "IconForCutoffUnmet": "Icono de Corte no alcanzado", "ICalHttpUrlHelpText": "Copia esta URL a tu gestor(es) o haz click en subscribir si tu navegador soporta webcal", - "ICalFeed": "iCal Feed", "Hostname": "Nombre del Host", - "HelpText": "Intervalo en minutos. Ajustar a cero para inhabilitar (esto dentendrá toda captura de estrenos automática)", "FileChmodMode": "Modo de chmod para el archivo", "EnableSSL": "Habilitar SSL", - "EnableRSS": "Habilitar RSS", "EnableInteractiveSearch": "Habilitar Búsqueda Interactiva", "EnableHelpText": "Habilitar la creación de un fichero de metadatos para este tipo de metadato", "EnabledHelpText": "Habilitar esta lista para usar en Prowlarr", @@ -638,162 +407,102 @@ "EnableAutomaticSearch": "Habilitar Búsqueda Automática", "EnableAutomaticAdd": "Habilitar Añadido Automático", "EnableAutoHelpText": "Si se habilita, las Películas en esta lista se añadirán automáticamente a Prowlarr", - "CutoffFormatScoreHelpText": "Una vez alcanzada esta puntuación del formato propio Prowlarr dejará de descargar películas", "CustomFormatsSettings": "Ajustes de Formatos Propios", - "CopyUsingHardlinksHelpTextWarning": "Ocasionalmente, los archivos blqoueados impiden renombrar los archivos que siguen seedeando. Puedes desactivar el seedeo temporalmete y usar la función de renombrado de Prowlarr como alternativa.", "CopyUsingHardlinksHelpText": "Usar Hardlinks al intentar copiar ficheros de los torrents que siguen seedeando", "ConnectSettings": "Conectar Ajustes", - "CleanLibraryLevel": "Limpiar el Nivel de la Librería", "BindAddress": "Dirección de Ligado", "OpenBrowserOnStart": "Abrir navegador al arrancar", - "OnUpgradeHelpText": "Notificar cuando las películas se hayan actualizado a mejor calidad", "OnRenameHelpText": "En Renombrado", "OnHealthIssueHelpText": "En Problema de Salud", - "OnGrabHelpText": "Al Capturar", "SettingsRuntimeFormat": "Formato de Tiempo de ejecución", - "ImportListSyncIntervalHelpText": "Frecuencia de sincronización de Prowlarr con tus listas.", "MovieIsOnImportExclusionList": "La película está en la Lista de Exclusión", - "WaitingToProcess": "Esperando para Procesar", "WaitingToImport": "Esperando para Importar", - "UpgradeUntilThisQualityIsMetOrExceeded": "Actualizar hasta que se alcance o supere esta calidad", "TagCannotBeDeletedWhileInUse": "No se puede eliminar estando en uso", - "SubfolderWillBeCreatedAutomaticallyInterp": "La subcarpeta '{0}' se creará automáticamente", "SSLCertPathHelpText": "Ruta al archivo pfx", "SSLCertPasswordHelpText": "Contraseña para el archivo pfx", - "ShowYear": "Mostrar Año", "ShowRatings": "Mostrar Calificaciones", "ShownClickToHide": "Mostrado, clic para ocultar", - "ShowGenres": "Mostrar Géneros", "ShowCertification": "Mostrar Certificación", - "SearchOnAddHelpText": "Buscar películas en esta lista cuando se añadan a Prowlarr", "RSSSyncIntervalHelpTextWarning": "Se aplicará a todos los indexers, por favor sigue las reglas de los mismos", "RSSIsNotSupportedWithThisIndexer": "RSS no son soportadas por este indexer", - "RetryingDownloadInterp": "Re-intentando descarga {0} en {1}", "RemovingTag": "Eliminando etiqueta", - "ReleaseWillBeProcessedInterp": "El lanzamiento será procesado {0}", "Queued": "En Cola", - "QualityProfileDeleteConfirm": "Seguro que quieres eliminar el perfil de calidad {0}", "Pending": "Pendiente", - "Paused": "Pausada", "NegateHelpText": "Si se activa, el formato propio no se aplicará si esta condición {0} se iguala.", - "MoviesSelectedInterp": "{0} Película(s) Seleccionada(s)", "MovieIsUnmonitored": "La película no está monitoreada", - "MovieIsMonitored": "La película está monitoreada", "MovieIsDownloadingInterp": "La película está descargando - {0}% {1}", - "MovieExcludedFromAutomaticAdd": "Película Excluida de Adición Automática", "MovieAlreadyExcluded": "Película ya Excluida", - "MarkAsFailedMessageText": "Seguro que quieres marcar '{0}' como fallida?", "Manual": "Manual", "LogLevelTraceHelpTextWarning": "El registro de seguimiento se ha de habilitar solo temporalmente", - "LastDuration": "Duración", "IncludeRecommendationsHelpText": "Incluir las películas recomendadas por Prowlarr en la vista de descubrir", - "IncludeProwlarrRecommendations": "Incluir Recomendaciones de Prowlarr", "ImportFailedInterp": "la importación ha fallado: {0}", - "ImportFailed": "Importación fallida: {0}", "HiddenClickToShow": "Oculto, clic para mostrar", - "GrabReleaseMessageText": "Prowlarr no pudo determinar para qué película es este lanzamiento. Prowlarr no podrá importar este lanzamiento automáticamente. Quieres descargar {0}?", "GoToInterp": "Ir a {0}", "ExistingTag": "Etiqueta existente", - "ExcludeMovie": "Excluir Película", "EnableInteractiveSearchHelpTextWarning": "Buscar no está soportado por este indexer", "EnableInteractiveSearchHelpText": "Se usará cuando se utilice la búsqueda interactiva", "EnableAutomaticSearchHelpText": "Se usará cuando las búsquedas automáticas se realicen desde el UI o por Prowlarr", "EnableAutomaticSearchHelpTextWarning": "Se usará cuando se utilice la búsqueda interactiva", - "DownloadWarning": "Alerta de descarga: {0}", "Downloading": "Descargando", - "DownloadFailedInterp": "Descarga fallida: {0}", "DownloadFailed": "La descarga ha fallado", "DownloadClientUnavailable": "El gestor de descargas no está disponible", "DeleteTagMessageText": "Seguro que quieres eliminar la etiqueta '{0}'?", - "DeleteSelectedMovieFilesMessage": "Seguro que quieres eliminar el archivo de la película seleccionada?", "DeleteRestrictionHelpText": "Seguro que quieres eliminar esta restricción?", "DeleteNotificationMessageText": "Seguro que quieres elminiar la notificación '{0}'?", - "DeleteListMessageText": "Seguro que quieres eliminar la lista '{0}'?", "DeleteBackupMessageText": "Seguro que quieres eliminar la copia de seguridad '{0}'?", "DeleteDownloadClientMessageText": "Seguro que quieres eliminar el gestor de descargas '{0}'?", "DeleteIndexerMessageText": "Seguro que quieres eliminar el indexer '{0}'?", - "DelayingDownloadUntilInterp": "Retrasar descarga hasta {0} en {1}", "Cutoff": "Corte", - "ClickToChangeMovie": "Clic para cambiar película", "CheckDownloadClientForDetails": "comprobar el gestor de descargas para más detalles", "CancelPendingTask": "Seguro que quieres cancelar esta tarea pendiente?", "BranchUpdateMechanism": "Rama usada por el mecanismo de actualización externo", "BranchUpdate": "Qué rama usar para actualizar Prowlarr", "BeforeUpdate": "Antes de actualizar", - "AllowMovieChangeClickToChangeMovie": "Clic para cambiar la película", "AddingTag": "Añadiendo etiqueta", - "ProwlarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "Prowlarr soporta condiciones personalizadas contra las propiedades de estrenos abajo.", "ThisConditionMatchesUsingRegularExpressions": "Esta condición coincide con el uso de Expresiones Regulares. Tenga en cuenta que los caracteres {0} tienen significados especiales y necesitan escapar con un {1}", - "YouCanAlsoSearch": "También puedes buscar usando la ID de TMDb o la ID de IMDb de una película. ej. tmdb:71663", "VisitGithubCustomFormatsAphrodite": "Visita Github para más detalles: ", - "Unreleased": "Inédita", "UnableToLoadUISettings": "No se han podido cargar los ajustes de UI", - "UnableToLoadTheCalendar": "No se ha podido cargar el calendario", "UnableToLoadRootFolders": "No se han podido cargar las carpetas raiz", - "UnableToLoadQualities": "No se han podido cargar las calidades", "UnableToLoadNamingSettings": "No se han podido cargar los ajustes de renombrado", - "UnableToLoadMovies": "No se han podido cargar las películas", "UnableToLoadMediaManagementSettings": "No se han podido cargar los ajustes de Manipulación multimedia", - "UnableToLoadListOptions": "No se tan podido cargar las opciones de lista", "UnableToLoadLanguages": "No se han podido cargar los idiomas", - "UnableToLoadIndexerOptions": "No se han podido cargar las opciones del indexer", "UnableToLoadHistory": "No se ha podido cargar la historia", "UnableToLoadGeneralSettings": "No se han podido cargar los ajustes Generales", - "UnableToLoadDownloadClientOptions": "No se han podido cargar las opciones del gestor de descargas", "UnableToLoadBlacklist": "No se han podido cargar las bloqueadas", "UnableToLoadBackups": "No se han podido cargar las copias de seguridad", - "UnableToAddANewRemotePathMappingPleaseTryAgain": "No se ha podido añadir una nueva ruta remota, prueba otra vez.", "UnableToAddANewQualityProfilePleaseTryAgain": "No se ha podido añadir un nuevo perfil de calidad, prueba otra vez.", "UnableToAddANewNotificationPleaseTryAgain": "No se ha podido añadir una nueva notificación, prueba otra vez.", - "UnableToAddANewListPleaseTryAgain": "No se ha podido añadir una nueva lista, prueba otra vez.", "UnableToAddANewListExclusionPleaseTryAgain": "No se ha podido añadir una nueva lista de exclusión, prueba otra vez.", "UnableToAddANewIndexerPleaseTryAgain": "No se ha podido añadir un nuevo indexer, prueba otra vez.", "UnableToAddANewDownloadClientPleaseTryAgain": "No se ha podido añadir un nuevo gestor de descargas, prueba otra vez.", - "UnableToAddANewCustomFormatPleaseTryAgain": "No se ha podido añadir un nuevo formato propio, prueba otra vez.", "UnableToAddANewConditionPleaseTryAgain": "No se ha podido añadir una nueva condición, prueba otra vez.", "TagIsNotUsedAndCanBeDeleted": "La etiqueta no se usa y puede ser borrada", "StartTypingOrSelectAPathBelow": "Comienza a escribir o selecciona una ruta debajo", "Restore": "Restaurar", - "RequiredPlaceHolder": "Añadir nueva restricción", "RegularExpressionsCanBeTested": "Las expresiones regulares se pueden testear ", - "ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "Prowlarr soporta cualquier lista RSS de películas, como también la listada debajo.", "ProwlarrSupportsAnyIndexer": "Prowlarr soporta cualquier indexer que utilice el estandar Newznab, como también cualquiera de los indexers listados debajo.", "ProwlarrSupportsAnyDownloadClient": "Raddar soporta cualquier gestor de descargas que utilice el estandar Newznab, como también los clientes indicados debajo.", - "OnDeleteHelpText": "Al Borrar", "NoUpdatesAreAvailable": "No hay actualizaciones disponibles", "NoTagsHaveBeenAddedYet": "No se han añadido etiquetas todavía", "NoLogFiles": "Sin archivos de registro", - "NoHistory": "Sin historia", "NoBackupsAreAvailable": "No hay copias de seguridad disponibles", - "MoreDetails": "Más detalles", "MissingNotMonitored": "No encontrada, no Monitoreada", - "MissingMonitoredAndConsideredAvailable": "No encontrada, Monitoreada y considerada Disponible", "MinutesSixty": "60 Minutos: {0}", "MinutesNinety": "90 Minutos: {0}", "MinutesHundredTwenty": "120 Minutos: {0}", "MaintenanceRelease": "Lanzamiento de mantenimiento", - "LoadingMovieFilesFailed": "La carga de los archivos ha fallado", "LoadingMovieExtraFilesFailed": "La carga de los extras de la película ha fallado", - "LoadingMovieCreditsFailed": "La carga de los créditos de la película ha fallado", "LinkHere": "aquí", - "IgnoredPlaceHolder": "Añadir nueva restricción", "HaveNotAddedMovies": "No has añadido películas todavía, quieres importar alguna o todas tus películas primero?", - "ForMoreInformationOnTheIndividualIndexers": "Para más información individual sobre los indexers, haz clic en los botones de información.", "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Para más información individual sobre las listas de importación, haz clic en los botones de información.", "ForMoreInformationOnTheIndividualDownloadClients": "Para más información individual de los gestores de descarga, haz clic en lls botones de información.", "FilterPlaceHolder": "Buscar películas", - "FileChmodHelpTexts2": "El mismo modo se aplica a las carpetas de pelicula/sub con el trizo de ejecutable añadido, ej., 0644 se convierte en 0755", "FileChmodHelpTexts1": "Octal, aplicado a los archivos multimedia importados/renombrados por Prowlarr", - "FailedLoadingSearchResults": "Error al cargar los resultados de la busqueda, prueba otra vez.", "ExtraFileExtensionsHelpTexts2": "Ejemplos : '.sub, .nfo' o 'sub,nfo'", - "ExtraFileExtensionsHelpTexts1": "Separar con cons la lista de los archivos extra a importar (.nfo será impotado como .nfo-orig)", "Excluded": "Excluida", "Exception": "Excepción", - "ErrorLoadingPreviews": "Error al cargar las previsualizaciones", "ErrorLoadingContents": "Error al cargar los contenidos", - "DownloadedButNotMonitored": "Descargada, pero no monitoreada", "DownloadedAndMonitored": "Descargada y Monitoreada", - "CouldNotFindResults": "No se pudieron encontrar resultados para '{0}'", "CantFindMovie": "Por qué no puedo encontrar mi película?", "ApplyTagsHelpTexts4": "Reemplazar: Reemplazar las etiquetas con las etiquetas introducidas (no introducir etiquetas para eliminar todas las etiquetas)", "ApplyTagsHelpTexts3": "Eliminar: Eliminar las etiquetas introducidas", @@ -802,19 +511,12 @@ "UILanguageHelpTextWarning": "Recargar el Navegador", "UILanguageHelpText": "Lenguaje que Prowlarr usara para el UI", "UILanguage": "Lenguaje de UI", - "MovieInfoLanguageHelpText": "Lenguaje que Prowlarr usara para el UI de Información de Película", "MovieInfoLanguage": "Lenguaje de la Información de Película", - "ImportCustomFormat": "Importar Formato Personalizado", "ExportCustomFormat": "Exportar Formato Personalizado", - "DownloadPropersAndRepacksHelpTextWarning": "Utilice palabras preferidas para actualizaciones automáticas a propers/repacks", "DownloadPropersAndRepacksHelpText2": "Utilice \"No Preferir\" para ordenar por puntuación de palabras preferidas en vez de proper/repacks", - "DownloadPropersAndRepacksHelpText1": "Decidir si automaticamente actualizar a Propers/Repacks", "DownloadPropersAndRepacks": "Propers y Repacks", - "CustomFormatUnknownConditionOption": "Opción Desconocida '{0}' para condición '{1}'", "CustomFormatUnknownCondition": "Condición de Formato Personalizado Desconocida '{0}'", - "CustomFormatJSON": "Formato Personalizado de JSON", "CopyToClipboard": "Copiar al portapapeles", - "CloneCustomFormat": "Clonar Formato Personalizado", "Priority": "Prioridad", "InteractiveSearch": "Búsqueda Interactiva", "IndexerPriorityHelpText": "Prioridad del Indexer de 1 (La más alta) a 50 (La más baja). Por defecto: 25.", @@ -823,7 +525,6 @@ "Disabled": "Deshabilitado", "AutomaticSearch": "Búsqueda Automática", "AddIndexer": "Añadir Indexer", - "Blacklisted": "Bloqueadas", "FocusSearchBox": "Enfocar Cuadro de búsqueda", "SaveSettings": "Grabar Ajustes", "OpenThisModal": "Abrir este Modal", @@ -833,26 +534,16 @@ "MovieDetailsNextMovie": "Detalles de la película: Siguiente Película", "CloseCurrentModal": "Cerrar Modal Actual", "AcceptConfirmationModal": "Aceptar el Modal de Confirmación", - "StartSearchForMissingMovie": "Empezar a buscar por película ausente", "StartProcessing": "Comenzar Procesado", - "StartImport": "Comenzar Importación", "SearchFailedPleaseTryAgainLater": "La búsqueda ha fallado, por favor inténtalo de nuevo más tarde.", - "RequiredRestrictionPlaceHolder": "El lanzamiento debe contener al menos uno de estos términos (no distingue entre mayúsculas y minúsculas)", "Released": "Estrenada", - "ProcessingFolders": "Procesando Carpetas", "NoMatchFound": "No se han encontrado coincidencias!", - "ImportRootPath": "Dirige Prowlarr a la carpeta con todas tus películas, no a una específica. ej. {0} y no {1}", "ImportIncludeQuality": "Asegúrate de que los archivos incluyen la calidad en el nombre. ej. {0}", - "ImportErrors": "Errores al importar", "Existing": "Existente", - "EditRestriction": "Editar Restricción", "Digital": "Digital", - "CancelProcessing": "Cancelar Procesamiento", "AddRestriction": "Añadir Restricción", - "AddMovie": "Añadir Película", "IndexerLongTermStatusCheckSingleClientMessage": "Indexers no disponible por errores durando más de 6 horas: {0}", "IndexerLongTermStatusCheckAllClientMessage": "Ningún indexer está disponible por errores durando más de 6 horas", - "EditMovieFile": "Editar Archivo de Película", "ListTagsHelpText": "Etiquetas con las que se añadirán los elementos", "PrioritySettings": "Prioridad" } diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index 5a5d0e1e6..feebe6c12 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -1,214 +1,138 @@ { - "DotNetVersionCheckNotRecommendedMessage": "Le .Net Framework actuellement installé {0} est pris en charge, mais nous vous recommandons de mettre à niveau vers au moins {1}.", "IndexerStatusCheckAllClientMessage": "Tous les indexeurs sont indisponibles en raison d'échecs", - "IndexerSearchCheckNoInteractiveMessage": "Aucun indexeur disponible avec la recherche interactive activée, Prowlarr ne fournira aucun résultat de recherche interactif", "IndexerSearchCheckNoAvailableIndexersMessage": "Tous les indexeurs compatibles avec la recherche sont temporairement indisponibles en raison d'erreurs d'indexation récentes", - "IndexerSearchCheckNoAutomaticMessage": "Aucun indexeur disponible avec la recherche automatique activée, Prowlarr ne fournira aucun résultat de recherche automatique", "Indexers": "Indexeurs", - "ImportTipsMessage": "Quelques conseils pour assurer le bon déroulement de l'importation  :", "ImportMechanismHealthCheckMessage": "Activer la gestion des téléchargements terminés", - "ImportHeader": "Importer des films que vous avez déjà", "Import": "Importer", - "iCalLink": "Lien iCal", "Host": "Hôte", "History": "Historique", "HideAdvanced": "Masquer avancé", "Health": "Santé", - "GrabSelected": "Saisir la sélection", "General": "Général", - "FreeSpace": "Espace libre", "Formats": "Formats", "Folder": "Dossier", "Filter": "Filtre", - "Filesize": "Taille du fichier", "Files": "Fichiers", - "FileManagement": "Gestion de fichiers", "FailedDownloadHandling": "Gestion des échecs de téléchargement", "Events": "Événements", "Edit": "Éditer", - "Downloaded": "Téléchargé", "DownloadClientStatusCheckAllClientMessage": "Aucun client de téléchargement n'est disponible en raison d'échecs", "DownloadClients": "Clients Télécharg.", "DownloadClientCheckNoneAvailableMessage": "Aucun client de téléchargement n'est disponible", "Dates": "Dates", "Date": "Date", - "Agenda": "Agenda", "DiskSpace": "Espace disque", - "Discover": "Découvrir", "Delete": "Supprimer", - "DelayProfiles": "Profils de retard", "Day": "Jour", - "CustomFormats": "Formats Persos", "CustomFilters": "Filtres personnalisés", - "Crew": "Équipe", "Connections": "Connexions", "Connect": "Notifications", - "CompletedDownloadHandling": "Gestion des téléchargements terminés", "Clear": "Effacer", - "ChooseAnotherFolder": "Choisir un autre dossier", "Cast": "Casting", - "Calendar": "Calendrier", "Blacklist": "Liste noire", "BackupNow": "Sauvegarder maintenant", "Backup": "Sauvegarde", "AppDataLocationHealthCheckMessage": "La mise à jour ne sera pas possible d'empêcher la suppression AppData sur mise à jour", - "AndNot": "et pas", "Analytics": "Analytique", "All": "Tout", - "AddNewTmdbIdMessage": "Vous pouvez également effectuer une recherche à l'aide de l'identifiant TMDb d'un film. exemple. tmdb:71663", "AddNewMessage": "Il est facile d'ajouter un nouveau film, commencez simplement à taper le nom du film que vous souhaitez ajouter", - "AddMovies": "Ajouter des films", "AddExclusion": "Ajouter une exclusion", - "AddNew": "Ajouter un nouveau", "Activity": "Activité", "About": "À propos", - "CustomFormatsSettingsSummary": "Paramètres et Formats personnalisés", "IndexerStatusCheckSingleClientMessage": "Indexeurs indisponibles en raison d'échecs : {0}", "DownloadClientStatusCheckSingleClientMessage": "Clients de Téléchargement indisponibles en raison d'échecs : {0}", "SetTags": "Définir Tags", - "ReleaseTitle": "Titre de la version", "ReleaseStatus": "Statut de la version", - "ReleaseGroup": "Groupe de versions", "UpdateCheckUINotWritableMessage": "Impossible d'installer la mise à jour car le dossier d'interface utilisateur '{0}' n'est pas accessible en écriture par l'utilisateur '{1}'.", "UpdateCheckStartupTranslocationMessage": "Impossible d'installer la mise à jour car le dossier de démarrage '{0}' se trouve dans un dossier App Translocation.", "UpdateCheckStartupNotWritableMessage": "Impossible d'installer la mise à jour car le dossier de démarrage '{0}' n'est pas accessible en écriture par l'utilisateur '{1}'.", "UnselectAll": "Tout déselectionner", - "Unmonitored": "Non surveillé", "UISettingsSummary": "Options de date, de langue et de contraste de couleur", "TagsSettingsSummary": "Voir toutes les tags et leur utilisation. Les tags inutilisées peuvent être supprimées", "Style": "Style", - "Studio": "Studio", "Status": "Statut", - "SourceTitle": "Titre de la source", "Sort": "Trier", - "SizeOnDisk": "Taille sur le disque", "Size": "Taille", "ShowAdvanced": "Afficher avancés", "Settings": "Paramètres", "SelectAll": "Tout sélectionner", "Security": "Sécurité", - "SearchSelected": "Recherche sélectionnée", "SearchForMissing": "Recherche les manquants", - "SearchFiltered": "Recherche filtrée", "SearchAll": "Rechercher tout", "Search": "Rechercher", "Scheduled": "Programmé", "SaveChanges": "Sauvegarder les modifications", - "Runtime": "Durée", "RSSSync": "Synchro RSS", - "RootFolders": "Dossiers racine", "RootFolderCheckSingleMessage": "Dossier racine manquant : {0}", - "RootFolderCheckMultipleMessage": "Plusieurs dossiers racine sont manquants : {0}", "RootFolder": "Dossier racine", "Restrictions": "Restrictions", "RestoreBackup": "Restaurer la sauvegarde", - "RenameFiles": "Renommer les fichiers", "Renamed": "Renommé", - "RemoveSelected": "Supprimer la sélection", "RemovedMovieCheckSingleMessage": "Le film {0} a été supprimé de TMDb", - "RemovedMovieCheckMultipleMessage": "Les films {0} ont été supprimés de TMDb", "RemotePathMappings": "Mappages de chemins distants", "ReleaseBranchCheckPreviousVersionMessage": "La branche {0} est pour une version précédente de Prowlarr, définissez la branche sur 'Nightly' pour d'autres mises à jour", "ReleaseBranchCheckOfficialBranchMessage": "La branche {0} n'est pas une branche de version Prowlarr valide, vous ne recevrez pas de mises à jour", - "RefreshAndScan": "Actualiser et analyser", "Refresh": "Rafraîchir", - "Ratings": "Évaluations", "Queue": "File d'attente", - "QualitySettingsSummary": "Tailles qualité et dénomination", "QualityProfiles": "Profils qualité", - "QualityProfile": "Profil qualité", "QualityDefinitions": "Définitions qualité", - "Quality": "Qualité", "PtpOldSettingsCheckMessage": "Les indexeurs PassThePopcorn suivants ont des paramètres obsolètes et doivent être mis à jour : {0}", "ProxyCheckResolveIpMessage": "Impossible de résoudre l'adresse IP de l'hôte proxy configuré {0}", "ProxyCheckFailedToTestMessage": "Échec du test du proxy : {0}", "ProxyCheckBadRequestMessage": "Échec du test du proxy. StatusCode : {0}", "Proxy": "Proxy", "Protocol": "Protocole", - "Progress": "Progression", "ProfilesSettingsSummary": "Profils de qualité, de langue et de délai", - "Profiles": "Profils", "PreviewRename": "Aperçu Renommage", - "PhysicalRelease": "Sortie Physique", "Path": "Chemin", - "OutputPath": "Chemin de sortie", "Options": "Options", "NoChanges": "Aucun changement", "NoChange": "Pas de changement", - "ImportListStatusCheckSingleClientMessage": "Listes indisponibles en raison d'échecs : {0}", "ImportListStatusCheckAllClientMessage": "Toutes les listes ne sont pas disponibles en raison d'échecs", - "MovieTitle": "Titre du film", "Movies": "Films", - "MovieNaming": "Nommage des films", "MovieIndex": "Index des films", - "MovieEditor": "Éditeur de films", "Movie": "Film", - "MountCheckMessage": "Le montage contenant un chemin de film est monté en lecture seule : ", "MoreInfo": "Plus d'informations", - "Month": "Mois", "MonoTlsCheckMessage": "Solution de contournement Prowlarr Mono 4.x tls toujours activée, pensez à supprimer l'option d'environnement MONO_TLS_PROVIDER = legacy", - "ListsSettingsSummary": "Importer listes, listes d'exclusions", "ListExclusions": "Liste des exclusions", - "IndexersSettingsSummary": "Indexeurs et restrictions de version", "ImportFirstTip": "Assurez-vous que vos fichiers incluent la qualité dans leurs noms de fichiers. par exemple.", "Grabbed": "Attrapé", - "Genres": "Genres", "Forecast": "Prévision", "DownloadClientsSettingsSummary": "Clients de Téléchargement configuration pour l'intégration dans la recherche de l'interface utilisateur Prowlarr", "DownloadClientCheckUnableToCommunicateMessage": "Impossible de communiquer avec {0}.", "DownloadClient": "Client de Téléchargement", - "DotNetVersionCheckOldUnsupportedMessage": "Le .Net Framework {0} actuellement installé est ancien et n'est pas pris en charge. Veuillez mettre à niveau .Net Framework à au moins {1}.", "CutoffUnmet": "Limite non satisfaite", "MonoNotNetCoreCheckMessage": "Veuillez mettre à niveau vers la version .NET Core de Prowlarr", - "MonitoredOnly": "Surveillé uniquement", "Monitor": "Surveiller", - "Missing": "Manquant", "MinimumAvailability": "Disponibilité minimale", - "MinAvailability": "Disponibilité minimale", "MetadataSettingsSummary": "Créer des fichiers de métadonnées lorsque des films sont importés ou actualisés", - "Metadata": "Métadonnées", "MediaManagementSettingsSummary": "Paramètres de dénomination et de gestion des fichiers", - "MediaManagement": "Gestion des médias", "MediaInfoDllCheckMessage": "Impossible de charger la bibliothèque MediaInfo {0}", - "MassMovieSearch": "Recherche de films en masse", "ManualImport": "Importation manuelle", "Logging": "Enregistrement", - "LogFilesLocationMessage": "Les fichiers journaux se trouvent dans  :", "LogFiles": "Fichiers Log", - "Lists": "Listes", "IndexerRssHealthCheckNoIndexers": "Aucun indexeur disponible avec la synchronisation RSS activée, Prowlarr ne récupérera pas automatiquement les nouvelles versions", - "IndexerRssHealthCheckNoAvailableIndexers": "Tous les indexeurs compatibles rss sont temporairement indisponibles en raison d'erreurs d'indexation récentes", "ImportSecondTip": "Pointer Prowlarr vers le dossier contenant tous vos films, pas un en particulier. par exemple.", - "Week": "Semaine", "Wanted": "Recherché", "View": "Vue", - "UpdateSelected": "Mettre à jour la sélection", "Updates": "Mises à jour", - "UpdateAll": "Tout actualiser", "UnmappedFolders": "Dossiers non mappés", "UI": "UI", - "Titles": "Titres", "Timeleft": "Temps restant", "Tasks": "Tâches", "Tags": "Tags", "System": "Système", - "Year": "Année", "LastWriteTime": "Heure de la dernière écriture", "Languages": "Langues", "Language": "Langue", "Indexer": "Indexeur", - "InCinemas": "Dans les cinémas", "Imported": "Importé", - "Ignored": "Ignoré", "GeneralSettingsSummary": "Port, SSL, nom d'utilisateur/mot de passe, proxy, analyses et mises à jour", "Filename": "Nom de fichier", "Failed": "Échoué", "EventType": "Type d'événement", - "DigitalRelease": "Sortie numérique", "Details": "Détails", - "Deleted": "Supprimé", "ConnectSettingsSummary": "Notifications et scripts personnalisés", - "Collection": "Collection", "Certification": "Certification", "Added": "Ajoutée", "Actions": "Actions", @@ -219,19 +143,14 @@ "Columns": "Colonnes", "Close": "Fermer", "Cancel": "Annuler", - "AudioInfo": "Info audio", "Apply": "Appliquer", - "AlternativeTitle": "Titre alternatif", "AllMoviesHiddenDueToFilter": "Tous les films sont masqués en raison du filtre appliqué.", "Age": "Âge", - "AddNewMovie": "Ajouter un nouveau film", "AddList": "Ajouter la liste", "ConnectionLostMessage": "Prowlarr a perdu sa connexion au backend et devra être rechargé pour fonctionner à nouveau.", "Warn": "Avertissement", - "VideoCodec": "Codec vidéo", "Unavailable": "Indisponible", "Type": "Type", - "TotalSpace": "Espace total", "Title": "Titre", "Time": "Heure", "TestAll": "Tout tester", @@ -243,157 +162,100 @@ "Seeders": "Seeders", "Save": "Sauvegarder", "Restart": "Redémarrer", - "RemoveRootFolder": "Supprimer le dossier racine", "Reload": "Recharger", - "RelativePath": "Chemin relatif", "RejectionCount": "Compteur de rejet", "Peers": "Pairs", "PageSize": "Pagination", - "OrganizeModalSuccess": "Victoire ! Mon travail est terminé, aucun fichier à renommer.", "OrganizeModalNamingPattern": "Motif de renommage :", - "OrganizeModalDisabled": "Renommer est désactivé, rien à renommer", "OrganizeModalAllPathsRelative": "Tous les chemins sont relatifs à :", - "OrganizeAndRename": "Organiser et renommer", "Organize": "Organiser", "Ok": "OK", "OAuthPopupMessage": "Les pop-ups sont bloquées par votre navigateur", "Name": "Nom", - "MoveFiles": "Déplacer les fichiers", "Monitored": "Surveillé", "Message": "Message", - "Location": "Emplacement", "Level": "Niveau", "KeyboardShortcuts": "Raccourcis clavier", - "ImportExistingMovies": "Importer des films existants", "HealthNoIssues": "Aucun problème avec votre configuration", - "HardlinkCopyFiles": "Lier/copier les fichiers", "Extension": "Extension", - "CustomFormatScore": "Score du format personnalisé", "ConnectionLostAutomaticMessage": "Prowlarr essaiera de se connecter automatiquement, ou bien vous pouvez cliquer sur \"Recharger\" en bas.", "SystemTimeCheckMessage": "L'heure du système est décalée de plus d'un jour. Les tâches planifiées peuvent ne pas s'exécuter correctement tant que l'heure ne sera pas corrigée", - "ShowMonitored": "Afficher les éléments surveillés", "SettingsWeekColumnHeaderHelpText": "Affiché au dessus de chaque colonne quand \"Semaine\" est l'affichage actif", "SettingsShowRelativeDates": "Afficher les dates relatives", - "OverviewOptions": "Aperçu des options", "UnsavedChanges": "Changement non sauvegardés", - "Table": "Tableau", "ShowTitle": "Afficher le titre", - "ShowStudio": "Afficher le studio", "ShowSizeOnDisk": "Afficher la taille sur le disque", "ShowSearchHelpText": "Afficher le bouton de recherche au survol de la souris", "ShowSearch": "Afficher la recherche", - "ShowQualityProfile": "Afficher le profil de qualité", "ShowPath": "Afficher le chemin", - "ShowDateAdded": "Afficher la date d'ajout", "SettingsWeekColumnHeader": "En-tête de la colonne : Semaine", - "SettingsUiLanguageHelpText": "Langue que Prowlarr utilisera pour l'interface", "SettingsUiLanguage": "Langue de l'interface", "SettingsTimeFormat": "Format de l'heure", "SettingsShowRelativeDatesHelpText": "Afficher les dates relatives (Aujourd'hui/ Hier/ etc) ou absolues", "SettingsShortDateFormat": "Format de date court", - "SettingsRemotePathMappingRemotePathHelpText": "Chemin racine du dossier auquel le client de téléchargement accède", "SettingsRemotePathMappingRemotePath": "Chemin distant", - "SettingsRemotePathMappingLocalPathHelpText": "Chemin local que Prowlarr doit utiliser pour accéder au chemin distant", "SettingsRemotePathMappingLocalPath": "Chemin local", - "SettingsRemotePathMappingHostHelpText": "Le même hôte spécifié dans le Client de téléchargement à distance", "SettingsLongDateFormat": "Format de date long", - "SettingsFirstDayOfWeek": "Premier jour de la semaine", "SettingsEnableColorImpairedModeHelpText": "Style altéré pour aider les personnes daltoniennes à distinguer les informations en couleurs", "SettingsEnableColorImpairedMode": "Activer le mode daltonien", - "SelectFolder": "Sélectionner le dossier", "SearchOnAdd": "Rechercher à l'ajout", - "SearchMovie": "Rechercher le Film", "RecentFolders": "Dossiers récents", - "QuickImport": "Importation rapide", "PosterSize": "Taille des posters", - "Posters": "Posters", "PosterOptions": "Options des posters", "PendingChangesStayReview": "Rester et vérifier les changements", "PendingChangesMessage": "Vous avez effectué des changements non sauvegardés, souhaitez vous quitter cette page ?", "PendingChangesDiscardChanges": "Abandonner les changements et quitter", - "Overview": "Aperçu", "MonoVersionCheckUpgradeRecommendedMessage": "La version installée de Mono {0} est supportée mais mettre à jour en version {1} est recommandé.", - "MonoVersionCheckOldNotSupportedMessage": "La version installée de Mono {0} est vieille est n'est plus supportée. Merci de mettre à jour Mono en version {1}.", "MonoVersionCheckNotSupportedMessage": "La version installée de Mono {0} n'est plus supportée. Veuillez mettre à jour Mono en version {1}.", - "MonitorMovie": "Surveiller le film", "InteractiveImport": "Importation interactive", "ExistingMovies": "Films existants", - "EditRemotePathMapping": "Éditer le chemin distant", "AddRemotePathMapping": "Ajouter un chemin distant", - "DetailedProgressBarHelpText": "Afficher le texte sur la barre de progression", "DetailedProgressBar": "Barre de progression détaillée", - "Conditions": "Conditions", "ColonReplacementFormatHelpText": "Changer la manière dont Prowlarr remplace les 'deux-points'", - "ColonReplacement": "Remplacement pour le 'deux-points'", "CloneProfile": "Cloner le profil", "CloneIndexer": "Cloner l'indexeur", - "CloneFormatTag": "Cloner le Tag de format", "ClientPriority": "Priorité du client", - "ClickToChangeQuality": "Cliquer pour changer la qualité", "ClickToChangeLanguage": "Cliquer pour changer la langue", - "CheckForFinishedDownloadsInterval": "Intervalle de vérification des téléchargements terminés", "ChangeHasNotBeenSavedYet": "Les changements n'ont pas encore été sauvegardés", - "ChangeFileDate": "Changer la date du fichier", "CertificationCountryHelpText": "Choisir un pays pour les classifications de films", "CertificateValidationHelpText": "Change la rigueur de la vérification du certificat HTTPS", "CertificateValidation": "Validation du certificat", "BypassProxyForLocalAddresses": "Contourner le proxy pour les adresses locales", "Branch": "Branche", - "BlacklistRelease": "Mettre cette release sur la liste noire", "BlacklistHelpText": "Empêche Prowlarr de récupérer automatiquement ce film", "BindAddressHelpText": "Adresse IP4 valide ou '*' pour toutes les interfaces", "BindAddress": "Adresse d'attache", "Backups": "Sauvegardes", "BackupRetentionHelpText": "Les sauvegardes automatiques plus anciennes que la période de conservation seront automatiquement effacées", "BackupIntervalHelpText": "Intervalle entre les sauvegardes automatiques", - "AvailabilityDelay": "Délai de disponibilité", "AutoUnmonitorPreviouslyDownloadedMoviesHelpText": "Les films qui sont effacés du disque dur sont automatiquement non-surveillés dans Prowlarr", - "AutoRedownloadFailedHelpText": "Chercher et essayer de télécharger une version différente automatiquement", "Automatic": "Automatique", - "AutoDownloadPropersHelpText": "Prowlarr devrait-il automatiquement télécharger les propers quand ils sont disponibles ?", "AuthenticationMethodHelpText": "Un nom d'utilisateur et un mot de passe sont nécessaires pour accéder à Prowlarr", "Authentication": "Authentification", - "AsAllDayHelpText": "Les événements apparaîtront comme des événements durant toute la journée dans votre calendrier", "AreYouSureYouWantToResetYourAPIKey": "Êtes vous sûr de vouloir réinitialiser votre clé API ?", - "AreYouSureYouWantToDeleteThisRemotePathMapping": "Êtes vous sûr de vouloir effacer ce chemin ?", "AreYouSureYouWantToDeleteThisImportListExclusion": "Êtes vous sûr de vouloir effacer cette exclusion de liste d'imports ?", - "AreYouSureYouWantToDeleteThisDelayProfile": "Êtes vous sûr de vouloir effacer ce profil de délai ?", "ApplyTags": "Appliquer les Tags", "AppDataDirectory": "Dossier AppData", "ApiKey": "Clé API", "AnalyticsEnabledHelpText": "Envoyer des informations anonymes sur l'utilisation et les erreurs vers les serveurs de Prowlarr. Cela inclut des informations sur votre navigateur, quelle page Prowlarr WebUI vous utilisez, les rapports d'erreur ainsi que le système d'exploitation et sa version. Nous utiliserons ces informations pour prioriser les nouvelles fonctionnalités et les corrections de bugs.", - "AnalyseVideoFiles": "Analyser les fichiers vidéo", "AlreadyInYourLibrary": "Déjà présent dans votre collection", - "AllowHardcodedSubsHelpText": "Les sous-titres incrustés détectés seront automatiquement téléchargés", "AllowHardcodedSubs": "Autoriser les sous-titres incrustés", - "AgeWhenGrabbed": "Age (au moment du téléchargement)", "AddMoviesMonitored": "Ajouter des films en mode surveillé", - "AddListExclusion": "Ajouter une exclusion de liste", "IgnoreDeletedMovies": "Ignorer les films effacés", "IgnoredAddresses": "Adresses ignorées", - "IconForCutoffUnmet": "Icône pour limite non atteinte", "ICalHttpUrlHelpText": "Copiez cette URL dans votre client ou cliquez pour souscrire si votre navigateur est compatible avec webcal", - "ICalFeed": "Flux iCal", "Hostname": "Nom d'hôte", - "HelpText": "Intervalle en minutes. Mettre à zéro pour désactiver (cela arrêtera tous les téléchargements automatiques)", "Group": "Groupe", - "GrabRelease": "Télécharger la version", "GrabID": "ID du grab", - "Grab": "Télécharger", "Global": "Global", "GeneralSettings": "Réglages Généraux", - "FollowPerson": "Suivre la personne", "Folders": "Dossiers", "Fixed": "Corrigé", - "FirstDayOfWeek": "Premier jour de la semaine", "FileNames": "Noms de fichier", - "FileDateHelpText": "Changer la date du fichier lors de l'import/re-scan", "FileChmodMode": "Mode chmod du fichier", - "Exluded": "Exclus", "Ended": "Terminé", "EnableSslHelpText": " Nécessite un redémarrage en tant qu'administrateur pour être effectif", "EnableSSL": "Activer le SSL", - "EnableRSS": "Activer le RSS", "EnableMediaInfoHelpText": "Extraire les informations de la vidéo (résolution, temps et codec par exemple) depuis les fichiers. Cela nécessite que Prowlarr lise des parties du fichier ce qui peut entraîner une forte utilisation du disque dur ou du réseau pendant les scans.", "EnableInteractiveSearch": "Activer la recherche interactive", "EnableHelpText": "Activer la création d'un fichier de métadonnées pour ce type de métadonnée", @@ -405,54 +267,33 @@ "EnableAutomaticAdd": "Activer l'ajout automatique", "EnableAutoHelpText": "En cas d'activation, les films seront automatiquement ajoutés à Prowlarr depuis cette liste", "Enable": "Activer", - "EditPerson": "Éditer la personne", "EditMovie": "Éditer le film", - "Edition": "Edition", "DownloadWarningCheckDownloadClientForMoreDetails": "Avertissement téléchargement : voir le client de téléchargement pour plus de détails", - "DownloadPropers": "Telecharger les propers", "DownloadFailedCheckDownloadClientForMoreDetails": "Téléchargement échoué : voir le client de téléchargement pour plus de détails", "DownloadClientSettings": "Réglages Clients de téléchargement", "Docker": "Docker", - "DestinationRelativePath": "Chemin relatif de destination", "DestinationPath": "Chemin de Destination", "DeleteTag": "Supprimer le tag", - "DeleteSelectedMovieFiles": "Supprimer les fichiers film sélectionnés", "DeleteRestriction": "Supprimer la restriction", - "DeleteQualityProfile": "Supprimer le profil qualité", "DeleteNotification": "Supprimer la notification", - "DeleteList": "Supprimer la liste", "DeleteIndexer": "Supprimer l'indexeur", - "DeleteImportListExclusion": "Supprimer les exclusions de liste d'imports", "DeleteFile": "Supprimer le fichier", - "DeleteEmptyFoldersHelpText": "Supprimer les dossiers film vides pendant le scan du disque dur et quand les fichiers du film sont supprimés", "DeleteEmptyFolders": "Supprimer les dossiers vides", "DeleteDownloadClient": "Supprimer le client de téléchargement", - "DeleteCustomFormat": "Supprimer le format personnalisé", "DeleteBackup": "Supprimer la sauvegarde", "DBMigration": "Migration de la base de données", - "CutoffHelpText": "Quand cette qualité est atteinte, Prowlarr ne téléchargera plus de films", "CutoffFormatScoreHelpText": "Quand ce score de format personnalisé est atteint, Prowlarr ne téléchargera plus de films", - "CustomFormatsSettings": "Réglages Formats Personnalisés", "CreateGroup": "Créer un groupe", - "CreateEmptyMovieFoldersHelpText": "Créer les dossiers films manquants pendant le scan du disque", "CreateEmptyMovieFolders": "Créer des dossiers films vides", - "CopyUsingHardlinksHelpTextWarning": "De temps en temps, des verrouillages de fichiers peuvent empêcher de renommer des fichiers qui sont en cours de partage. Vous pouvez temporairement arrêter le partage et utiliser la fonction de renommage de Prowlarr comme solution de contournement.", "CopyUsingHardlinksHelpText": "Utiliser des liens fixes quand on essaye de copier des fichiers appartenant à des torrents en cours de partage", "ConnectSettings": "Paramètres de connexion", - "CleanLibraryLevel": "Nettoyer au niveau de la collection", "CertificationCountry": "Pays de classification", "BackupFolderHelpText": "Les chemins correspondants seront sous le répertoire AppData de Prowlarr", - "AvailabilityDelayHelpText": "Temps à laisser s’écouler (avant ou après la date de disponibilité) avant de chercher le film", "AddImportExclusionHelpText": "Empêcher le film d’être ajouté automatiquement à Prowlarr par des listes", - "ImportExtraFilesHelpText": "Importer les fichiers extra correspondants (sous-titres, .nfo etc.) après avoir importé un fichier film", "ImportExtraFiles": "Importer les fichiers extra", - "ImportedTo": "Importé vers", "IllRestartLater": "Je redémarrerai plus tard", - "IgnoredHelpText": "La version sera rejetée si elle contient au moins l'un de ces termes (insensible à la casse)", "Cutoff": "Limite", - "CouldNotFindResults": "Pas de résultats pour '{0}'", "ClickToChangeMovie": "Cliquer pour changer le film", - "CheckDownloadClientForDetails": "Vérifier le client de téléchargement pour plus de détails", "CantFindMovie": "Pourquoi ne puis-je pas trouver mon film ?", "CancelPendingTask": "Êtes-vous sur de vouloir annuler cette tâche en attente ?", "BranchUpdateMechanism": "Branche utilisée par le mécanisme de mise à jour extérieur", @@ -462,7 +303,6 @@ "ApplyTagsHelpTexts3": "Retirer : Retire les tags renseignés", "ApplyTagsHelpTexts2": "Ajouter : Ajouter les tags à la liste de tags existants", "ApplyTagsHelpTexts1": "Comment appliquer des tags au film sélectionné", - "AllowMovieChangeClickToChangeMovie": "Cliquer pour changer le film", "DeleteDownloadClientMessageText": "Êtes-vous sûr de vouloir supprimer le client de téléchargement '{0}' ?", "DeleteBackupMessageText": "Êtes-vous sûr de vouloir supprimer la sauvegarde '{0}' ?", "ErrorLoadingContents": "Erreur lors du chargement du contenu", @@ -470,253 +310,159 @@ "EnableInteractiveSearchHelpText": "Sera utilisé lorsque la recherche interactive est utilisée", "EnableAutomaticSearchHelpTextWarning": "Sera utilisé lorsque la recherche interactive est utilisée", "EnableAutomaticSearchHelpText": "Sera utilisé lorsque les recherches automatiques sont effectuées via l'interface utilisateur ou par Prowlarr", - "DownloadWarning": "Avertissement de téléchargement : {0}", "Downloading": "Téléchargement", "DownloadClientUnavailable": "Le client de téléchargement n'est pas disponible", - "DeleteRestrictionHelpText": "Voulez-vous vraiment supprimer cette restriction ?", "DeleteListMessageText": "Voulez-vous vraiment supprimer la liste '{0}' ?", "DeleteIndexerMessageText": "Voulez-vous vraiment supprimer l'indexeur '{0}' ?", - "CopyToClipboard": "Copier dans le presse-papier", "GoToInterp": "Aller à {0}", - "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Pour plus d'informations sur les listes d'importation individuelles, cliquez sur les boutons d'information.", "ForMoreInformationOnTheIndividualDownloadClients": "Pour plus d'informations sur les clients de téléchargement individuels, cliquez sur les boutons d'information.", "FilterPlaceHolder": "Rechercher des indexeurs", - "FailedLoadingSearchResults": "Échec du chargement des résultats de la recherche, veuillez réessayer.", "Excluded": "Exclu", "Exception": "Exception", - "ErrorLoadingPreviews": "Erreur lors du chargement des aperçus", "EditIndexer": "Modifier l'indexeur", - "DownloadFailedInterp": "Échec du téléchargement : {0}", "DownloadFailed": "Échec du téléchargement", - "DownloadedButNotMonitored": "Téléchargé, mais non surveillé", "DownloadedAndMonitored": "Téléchargé et Surveillé", "Disabled": "Désactivé", "DeleteNotificationMessageText": "Êtes-vous sûr de vouloir supprimer la notification '{0}' ?", "AutomaticSearch": "Recherche automatique", "AddIndexer": "Ajouter un indexeur", - "ListUpdateInterval": "Intervalle de mise à jour de la liste", "ListSyncLevelHelpText": "Les films de la bibliothèque seront supprimés ou non surveillés s'ils ne figurent pas dans votre liste", - "Links": "Liens", "LinkHere": "ici", - "LanguageHelpText": "Langue pour les versions", "Interval": "Intervalle", "InteractiveSearch": "Recherche interactive", - "IndexerSettings": "Paramètres de l'indexeur", "IndexerPriorityHelpText": "Priorité de l'indexeur de 1 (la plus élevée) à 50 (la plus basse). Par défaut: 25.", "IndexerPriority": "Priorité de l'indexeur", - "IncludeUnmonitored": "Inclure non surveillé", "IncludeRecommendationsHelpText": "Inclure les films recommandés par Prowlarr dans la vue découverte", - "IncludeProwlarrRecommendations": "Inclure les recommandations de Prowlarr", "ImportMovies": "Importer Films", - "ImportListSyncIntervalHelpText": "À quelle fréquence Prowlarr se synchronise avec vos listes.", "Importing": "Importation", - "ImportFailed": "L'importation a échoué : {0}", "ImportCustomFormat": "Importer format personnalisé", - "IgnoredPlaceHolder": "Ajouter nouvelle restriction", "HaveNotAddedMovies": "Vous n'avez pas encore ajouté de films, voulez-vous d'abord importer certains ou tous vos films ?", - "ForMoreInformationOnTheIndividualIndexers": "Pour plus d'informations sur les indexeurs individuels, cliquez sur les boutons info.", "ExtraFileExtensionsHelpTexts2": "Exemples : '.sub, .nfo' ou 'sub,nfo'", - "ExportCustomFormat": "Exporter format personnalisé", "ExcludeMovie": "Exclure Film", - "DeleteSelectedMovieFilesMessage": "Voulez-vous vraiment supprimer les fichiers vidéo sélectionnés ?", "DelayingDownloadUntilInterp": "Retarder le téléchargement jusqu'au {0} à {1}", - "CustomFormatUnknownConditionOption": "Option inconnue '{0}' pour la condition '{1}'", "CustomFormatUnknownCondition": "Condition de format personnalisé inconnue '{0}'", - "CloneCustomFormat": "Cloner format personnalisé", "Blacklisted": "Liste noire", - "UnableToLoadRootFolders": "Impossible de charger les dossiers racine", "UnableToLoadRestrictions": "Impossible de charger les restrictions", - "UnableToLoadRemotePathMappings": "Impossible de charger les mappages de chemins distants", "UnableToLoadQualityProfiles": "Impossible de charger les profils de qualité", "UnableToLoadQualityDefinitions": "Impossible de charger les définitions de qualité", - "UnableToLoadQualities": "Impossible de charger les qualités", "UnableToLoadNotifications": "Impossible de charger les notifications", - "UnableToLoadNamingSettings": "Impossible de charger les paramètres de dénomination", "UnableToLoadMovies": "Impossible de charger les films", - "UnableToLoadMetadata": "Impossible de charger les métadonnées", "UnableToLoadMediaManagementSettings": "Impossible de charger les paramètres de gestion des médias", - "UnableToLoadLists": "Impossible de charger les listes", "UnableToLoadListOptions": "Impossible de charger les options de la liste", - "WaitingToProcess": "En attente de traitement", "WaitingToImport": "En attente d'importation", - "VisitGithubCustomFormatsAphrodite": "Visitez Github pour plus de détails: ", "Version": "Version", "Username": "Nom d'utilisateur", "UseProxy": "Utiliser un proxy", - "UsenetDelay": "Délai Usenet", "Usenet": "Usenet", - "UseHardlinksInsteadOfCopy": "Utiliser des liens physiques au lieu de copier", "UrlBaseHelpText": "Pour la prise en charge du proxy inverse, la valeur par défaut est vide", "URLBase": "Base URL", "YesCancel": "Oui, annuler", - "MovieIsMonitored": "Le film est surveillé", "MovieIsDownloadingInterp": "Le film est en cours de téléchargement - {0}% {1}", - "MovieIsDownloading": "Le film est en cours de téléchargement", "MovieInfoLanguageHelpTextWarning": "Rechargement du navigateur requis", - "MovieInfoLanguageHelpText": "Langue que Prowlarr utilisera pour les informations sur le film dans l'interface utilisateur", "MovieInfoLanguage": "Langue Infos sur le film", - "MovieID": "ID Film", "MovieFiles": "Fichiers vidéo", - "MovieExcludedFromAutomaticAdd": "Film exclu de l'ajout automatique", "MovieAvailableButMissing": "Film disponible, mais manquant", - "MovieAlreadyExcluded": "Film déjà exclu", "MoreDetails": "Plus de détails", "MonoVersion": "Mono Version", - "MonitoredHelpText": "Télécharger le film si disponible", "Mode": "Mode", - "MissingNotMonitored": "Manquant, non surveillé", "MissingMonitoredAndConsideredAvailable": "Manquant, surveillé et considéré comme disponible", "MinutesSixty": "60 Minutes : {0}", "MinutesNinety": "90 Minutes : {0}", "MinutesHundredTwenty": "120 Minutes : {0}", "MinimumLimits": "Limites minimales", - "MinimumFreeSpace": "Espace libre minimum", "MinimumAge": "Âge minimum", - "MetadataSettings": "Paramètres métadonnées", "MediaManagementSettings": "Paramètres de gestion des médias", - "MediaInfo": "Média Info", "Mechanism": "Mécanisme", - "MaximumSizeHelpText": "Taille maximale d'une version à saisir en Mo. Mettre à zéro pour définir sur illimité", "MaximumSize": "Taille maximum", "MaximumLimits": "Limites maximales", - "MarkAsFailed": "Marquer comme échoué", "Manual": "Manuel", "MaintenanceRelease": "Version de maintenance", "Logs": "Journaux", "LogLevelTraceHelpTextWarning": "La journalisation des traces ne doit être activée que temporairement", "LogLevel": "Niveau du journal", - "Local": "Local", "LoadingMovieFilesFailed": "Le chargement des fichiers vidéo a échoué", - "LoadingMovieExtraFilesFailed": "Échec du chargement des extra du film", "LoadingMovieCreditsFailed": "Échec du chargement des crédits du film", - "ListSettings": "Paramètres liste", "ImportFailedInterp": "Importation a échoué : {0}", "HiddenClickToShow": "Caché, cliquez pour afficher", "IncludeHealthWarningsHelpText": "Inclure avertissements santé", "FocusSearchBox": "Zone de recherche de focus", - "ThisConditionMatchesUsingRegularExpressions": "Cette condition correspond à l'utilisation d'expressions régulières. Notez que les caractères {0} ont des significations spéciales et doivent être échappés avec un {1}", "RequiredHelpText": "Cette {0} condition doit correspondre pour que le format personnalisé s'applique. Sinon, une seule correspondance {1} est suffisante.", - "ReleaseWillBeProcessedInterp": "La Version sera traitée {0}", "ProxyBypassFilterHelpText": "Utiliser ',' comme séparateur et '*.' comme caractère générique pour les sous-domaines", - "OnGrabHelpText": "Sur Récupération", "NegateHelpText": "Si coché, le format personnalisé ne s'appliquera pas si cette condition {0} correspond.", - "LastDuration": "dernière Durée", "IncludeCustomFormatWhenRenamingHelpText": "Inclus dans {Custom Formats} renommer le format", - "GrabReleaseMessageText": "Prowlarr n'a pas été en mesure de déterminer à quel film cette version était destinée. Prowlarr peut être incapable d'importer automatiquement cette version. Voulez-vous récupérer '{0}' ?", "FileChmodHelpTexts2": "Le même mode est appliqué aux films/sous-dossiers avec le bit d'exécution ajouté, par exemple, 0644 devient 0755", - "FileChmodHelpTexts1": "Octal, appliqué aux fichiers multimédias lorsqu'ils sont importés/renommés par Prowlarr", "ExtraFileExtensionsHelpTexts1": "Liste séparée par des virgules des fichiers supplémentaires à importer (.nfo sera importé en tant que .nfo-orig)", - "YouCanAlsoSearch": "Vous pouvez également effectuer une recherche à l'aide de l'ID TMDb ou de l'ID IMDb d'un film. par exemple. tmdb: 71663", "WhitelistedSubtitleTags": "Balises de sous-titres sur liste blanche", - "WhitelistedHardcodedSubsHelpText": "Les balises de sous-titres définies ici ne seront pas considérées comme codées en dur", "WeekColumnHeader": "En-tête de colonne de la semaine", - "UsenetDelayHelpText": "Délai en minutes avant de récupérer une version Usenet", "Uptime": "Durée de fonctionnent", - "UpgradeUntilThisQualityIsMetOrExceeded": "Mettre à niveau jusqu'à ce que cette qualité soit atteinte ou dépassée", "UpgradeAllowedHelpText": "Ne sera pas mis à jour si la qualité est désactivée", "UpdateScriptPathHelpText": "Chemin vers un script personnalisé qui prend un package de mise à jour extraite et gère le reste du processus de mise à jour", "UpdateMechanismHelpText": "Utiliser le programme de mise à jour intégré dans Prowlarr ou un script", "UpdateAutomaticallyHelpText": "Télécharger et installer automatiquement les mises à jour. Vous pourrez toujours installer à partir de System : Updates", - "Unreleased": "Inédit", "UnmonitoredHelpText": "Inclure les films non surveillés dans le flux iCal", - "Ungroup": "Dissocier", "UnableToLoadUISettings": "Impossible de charger les paramètres de l'interface utilisateur", - "UnableToLoadTheCalendar": "Impossible de charger le calendrier", "UnableToLoadTags": "Impossible de charger les balises", - "UnableToLoadListExclusions": "Impossible de charger les exclusions de liste", "UnableToLoadLanguages": "Impossible de charger les langues", "UnableToLoadIndexers": "Impossible de charger les indexeurs", - "UnableToLoadIndexerOptions": "Impossible de charger les options de l'indexeur", "UnableToLoadHistory": "Impossible de charger l'historique", "UnableToLoadGeneralSettings": "Impossible de charger les paramètres généraux", "UnableToLoadDownloadClients": "Impossible de charger les clients de téléchargement", - "UnableToLoadDownloadClientOptions": "Impossible de charger les options du client de téléchargement", "UnableToLoadDelayProfiles": "Impossible de charger les profils de délai", - "UnableToLoadCustomFormats": "Impossible de charger les formats personnalisés", "UnableToLoadBlacklist": "Impossible de charger la liste noire", "UnableToLoadBackups": "Impossible de charger les sauvegardes", - "UnableToAddANewRemotePathMappingPleaseTryAgain": "Impossible d'ajouter un nouveau mappage de chemin distant, veuillez réessayer.", "UnableToAddANewQualityProfilePleaseTryAgain": "Impossible d'ajouter un nouveau profil de qualité, veuillez réessayer.", "UnableToAddANewNotificationPleaseTryAgain": "Impossible d'ajouter une nouvelle notification, veuillez réessayer.", - "UnableToAddANewListPleaseTryAgain": "Impossible d'ajouter une nouvelle liste, veuillez réessayer.", "UnableToAddANewListExclusionPleaseTryAgain": "Impossible d'ajouter une nouvelle exclusion de liste, veuillez réessayer.", "UnableToAddANewIndexerPleaseTryAgain": "Impossible d'ajouter un nouvel indexeur, veuillez réessayer.", "UnableToAddANewDownloadClientPleaseTryAgain": "Impossible d'ajouter un nouveau client de téléchargement, veuillez réessayer.", - "UnableToAddANewCustomFormatPleaseTryAgain": "Impossible d'ajouter un nouveau format personnalisé, veuillez réessayer.", "UnableToAddANewConditionPleaseTryAgain": "Impossible d'ajouter une nouvelle condition, veuillez réessayer.", - "TorrentDelayHelpText": "Délia en minutes avant de récupérer un torrent", "TorrentDelay": "Torrent Délai", "PriorityHelpText": "Donnez la priorité à plusieurs clients de téléchargement. Le Round-Robin est utilisé pour les clients ayant la même priorité.", "TagIsNotUsedAndCanBeDeleted": "La balise n'est pas utilisée et peut être supprimée", "TagsHelpText": "S'applique aux films avec au moins une balise correspondante", "StartTypingOrSelectAPathBelow": "Commencer à taper ou sélectionner un chemin ci-dessous", - "RetryingDownloadInterp": "Nouvelle tentative de téléchargement {0} à {1}", "ProtocolHelpText": "Choisissez le(s) protocole(s) à utiliser et celui qui est préféré lors du choix entre des versions par ailleurs égales", - "PreferIndexerFlagsHelpText": "Prioriser les versions avec des indicateurs spéciaux", "PreferIndexerFlags": "Préférer les indicateurs d'indexation", "NoTagsHaveBeenAddedYet": "Aucune identification n'a été ajoutée pour l'instant", - "MinimumAgeHelpText": "Usenet uniquement: âge minimum en minutes des NZB avant qu'ils ne soient saisis. Utiliser ceci pour donner aux nouvelles versions le temps de se propager à votre fournisseur usenet.", "MinFormatScoreHelpText": "Score de format personnalisé minimum autorisé à télécharger", "IndexerFlags": "Indicateurs d'indexeur", - "IncludeUnknownMovieItemsHelpText": "Afficher les éléments sans film dans la file d'attente. Cela peut inclure des films supprimés ou tout autre élément de la catégorie de Prowlarr", "IncludeCustomFormatWhenRenaming": "Inclure un format personnalisé lors du changement de nom", "DeleteTagMessageText": "Voulez-vous vraiment supprimer la balise '{0}' ?", - "DeleteDelayProfile": "Supprimer le profil de délai", "DelayProfile": "Profil de delai", "UISettings": "Paramètres UI", "UILanguageHelpTextWarning": "Rechargement du navigateur requis", "UILanguageHelpText": "Langue que Prowlarr utilisera pour l'interface utilisateur", "UILanguage": "UI Langue", - "TotalFileSize": "Taille totale du fichier", "Torrents": "Torrents", - "TmdbIdHelpText": "L'ID TMDb du film à exclure", "TMDBId": "Identifiant TMDb", - "TimeFormat": "Format de l'heure", "TestAllLists": "Tester toutes les listes", - "TestAllIndexers": "Tester tous les indexeurs", "TestAllClients": "Tester tous les clients", "TagCannotBeDeletedWhileInUse": "Ne peut pas être supprimé pendant l'utilisation", "SuggestTranslationChange": "Suggérer un changement de traduction", - "SubfolderWillBeCreatedAutomaticallyInterp": "'{0}' le sous-dossier sera créé automatiquement", "StartupDirectory": "Répertoire de démarrage", - "StandardMovieFormat": "Format de film standard", "SSLPort": "Port SSL", "SSLCertPathHelpText": "Chemin vers le fichier pfx", "SSLCertPath": "Chemin du certificat SSL", "SSLCertPasswordHelpText": "Mot de passe pour le fichier pfx", "SSLCertPassword": "Mot de passe du certificat SSL", - "SourceRelativePath": "Chemin relatif de la source", "SourcePath": "Chemin source", - "SorryThatMovieCannotBeFound": "Désolé, ce film est introuvable.", "SkipFreeSpaceCheckWhenImportingHelpText": "À utiliser lorsque Prowlarr ne parvient pas à détecter l'espace libre dans le dossier racine de votre film", - "SkipFreeSpaceCheck": "Ignorer la vérification de l'espace libre", "ShowYear": "Afficher l'année", - "ShowUnknownMovieItems": "Afficher les éléments de film inconnus", "ShowTitleHelpText": "Afficher le titre du film sous l'affiche", - "ShowRatings": "Afficher les évaluations", "ShowQualityProfileHelpText": "Afficher le profil de qualité sous l'affiche", "ShownClickToHide": "Montré, cliquez pour masquer", - "ShowMovieInformationHelpText": "Afficher les genres de films et la certification", "ShowMovieInformation": "Afficher les informations sur le film", - "ShowMonitoredHelpText": "Afficher le statut surveillé sous l'affiche", "ShowGenres": "Afficher les genres", - "ShowCutoffUnmetIconHelpText": "Afficher l'icône des fichiers lorsque la limite n'a pas été atteinte", "ShowCertification": "Afficher la certification", - "ShowAsAllDayEvents": "Afficher comme événements d'une journée entière", "ShouldMonitorHelpText": "Si activé, les films ajoutés par cette liste sont ajoutés et surveillés", - "SettingsRuntimeFormat": "Format de durée", "SetPermissionsLinuxHelpTextWarning": "Si vous ne savez pas ce que font ces paramètres, ne les modifiez pas.", - "SetPermissionsLinuxHelpText": "Chmod doit-il être exécuté lorsque les fichiers sont importés/renommés?", "SetPermissions": "Définir les autorisations", "SendAnonymousUsageData": "Envoyer des données d'utilisation anonymes", - "SearchOnAddHelpText": "Rechercher des films dans cette liste lorsqu'ils sont ajoutés à Prowlarr", "SearchForMovie": "Rechercher un film", "ScriptPath": "Chemin du script", "SaveSettings": "Enregistrer les paramètres", - "RSSSyncIntervalHelpTextWarning": "Cela s'appliquera à tous les indexeurs, veuillez suivre les règles définies par eux", "RSSSyncInterval": "Intervalle de synchronisation RSS", "RSSIsNotSupportedWithThisIndexer": "RSS n'est pas pris en charge avec cet indexeur", - "RetentionHelpText": "Usenet uniquement: définir sur zéro pour une rétention illimitée", "Retention": "Rétention", "Result": "Résultat", "Restore": "Restaurer", @@ -725,131 +471,83 @@ "RestartNow": "Redémarrer maintenant", "ResetAPIKey": "Réinitialiser la clé API", "Reset": "Réinitialiser", - "RescanMovieFolderAfterRefresh": "Réanalyser le dossier de films après l'actualisation", "RescanAfterRefreshHelpTextWarning": "Prowlarr ne détectera pas automatiquement les modifications apportées aux fichiers lorsqu'il n'est pas défini sur «Toujours»", - "RescanAfterRefreshHelpText": "Réanalyser le dossier du film après avoir actualisé le film", "RequiredPlaceHolder": "Ajouter une nouvelle restriction", - "ReplaceIllegalCharactersHelpText": "Remplacer les caractères illégaux. Si elle n'est pas cochée, Prowlarr les supprimera à la place", "ReplaceIllegalCharacters": "Remplacer les caractères illégaux", - "Reorder": "Réorganiser", "RenameMoviesHelpText": "Prowlarr utilisera le nom de fichier existant si le changement de nom est désactivé", "RemovingTag": "Suppression du tag", - "ProwlarrTags": "Prowlarr Tags", "QualityProfileDeleteConfirm": "Voulez-vous vraiment supprimer le profil de qualité {0}", - "Paused": "En pause", "MarkAsFailedMessageText": "Voulez-vous vraiment marquer '{0}' comme échoué ?", "ExistingTag": "Tag existant", - "DownloadPropersAndRepacksHelpTextWarning": "Utiliser les mots préférés pour les mises à niveau automatiques des propres/repacks", "DownloadPropersAndRepacksHelpText2": "Utiliser 'Ne pas préférer' pour trier par score de mot préféré par rapport aux propres/repacks", - "DownloadPropersAndRepacksHelpText1": "S'il faut ou non mettre à niveau automatiquement vers Propres/Repacks", "DownloadPropersAndRepacks": "Propres et Repacks", - "RenameMovies": "Renommer films", "RemoveHelpTextWarning": "La suppression supprimera le téléchargement et le(s) fichier(s) du client de téléchargement.", - "RemoveFromQueue": "Supprimer de la file d'attente", "RemoveFromDownloadClient": "Supprimer du client de téléchargement", - "RemoveFromBlacklist": "Supprimer de la liste noire", "RemoveFilter": "Supprimer le filtre", - "RemoveFailedDownloadsHelpText": "Supprimer les téléchargements ayant échoué de l'historique du client de téléchargement", "RemovedFromTaskQueue": "Supprimé de la file d'attente des tâches", - "RemoveCompletedDownloadsHelpText": "Supprimer les téléchargements importés de l'historique du client de téléchargement", "Remove": "Retirer", - "ReleaseRejected": "Version rejetée", "ReleaseDates": "Date de sortie", - "RegularExpressionsCanBeTested": "Les expressions régulières peuvent être testées ", "RefreshMovie": "Actualiser film", - "RefreshInformationAndScanDisk": "Actualiser les informations et analyser le disque", "Redownload": "Télécharger à nouveau", - "RecyclingBinCleanup": "Nettoyage de la Corbeille", "RecyclingBin": "Corbeille", - "RecycleBinHelpText": "Les fichiers vidéo iront ici lorsqu'ils seront supprimés au lieu d'être supprimés définitivement", "RecycleBinCleanupDaysHelpTextWarning": "Les fichiers dans la corbeille plus anciens que le nombre de jours sélectionné seront nettoyés automatiquement", - "RecycleBinCleanupDaysHelpText": "Définir sur 0 pour désactiver le nettoyage automatique", "Reason": "Raison", - "Real": "Réel", "ReadTheWikiForMoreInformation": "Consultez le Wiki pour plus d'informations", - "ProwlarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "Prowlarr prend en charge les conditions personnalisées par rapport aux propriétés de publication ci-dessous.", "ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "Prowlarr prend en charge toutes les listes de films RSS ainsi que celle indiquée ci-dessous.", "ProwlarrSupportsAnyIndexer": "Prowlarr prend en charge de nombreux indexeurs en plus de tout indexeur qui utilise la norme Newznab/Torznab en utilisant « Generic Newznab » (pour usenet) ou « Generic Torznab » (pour les torrents). Recherchez et sélectionnez votre indexeur ci-dessous.", "ProwlarrSupportsAnyDownloadClient": "Prowlarr prend en charge tout client de téléchargement qui utilise le standard Newznab, ainsi que d'autres clients de téléchargement répertoriés ci-dessous.", - "Prowlarr": "Prowlarr", "Queued": "En file d'attente", "QualitySettings": "Paramètres Qualité", - "QualityCutoffHasNotBeenMet": "Le seuil de qualité n'a pas été atteint", "PublishedDate": "Date de publication", "ProxyUsernameHelpText": "Il vous suffit de saisir un nom d'utilisateur et un mot de passe si vous en avez besoin. Sinon, laissez-les vides.", "ProxyType": "Type de proxy", "ProxyPasswordHelpText": "Il vous suffit de saisir un nom d'utilisateur et un mot de passe si vous en avez besoin. Sinon, laissez-les vides.", - "Proper": "Proper", "Priority": "Priorité", "PreferredSize": "Taille préférée", "PortNumber": "Numéro de port", "Port": "Port", - "Permissions": "Autorisations", "Pending": "En attente", "Password": "Mot de passe", "PageSizeHelpText": "Nombre d'éléments à afficher sur chaque page", "PackageVersion": "Version du package", - "Original": "Original", "OpenBrowserOnStart": "Ouvrir le navigateur au démarrage", - "OnUpgradeHelpText": "Lors de la mise à niveau", "OnRenameHelpText": "Lors du changement de nom", - "OnDownloadHelpText": "À l'importation", "OnDeleteHelpText": "Lors de la suppression", "NoUpdatesAreAvailable": "Aucune mise à jour n'est disponible", - "NotMonitored": "Pas surveillé", "NotificationTriggers": "Déclencheurs de notification", - "NotAvailable": "Indisponible", "NoLimitForAnyRuntime": "Aucune limite pour aucune durée", "NoMinimumForAnyRuntime": "Aucun minimum pour n'importe quel durée", "NoLogFiles": "Aucun fichier journal", "NoLeaveIt": "Non, laisse-le", - "NoHistory": "Pas d'historique", "NoBackupsAreAvailable": "Aucune sauvegarde n'est disponible", "New": "Nouveau", "NetCore": ".NET Core", - "NamingSettings": "Paramètres dénomination", "MustNotContain": "Ne doit pas contenir", - "MovieYearHelpText": "L'année de film à exclure", "MustContain": "Doit contenir", - "MovieYear": "Année du film", "MovieTitleHelpText": "Le titre du film à exclure (peut être quelque chose de significatif)", "MovieIndexScrollTop": "Index des films : faire défiler vers le haut", "MovieIndexScrollBottom": "Index des Films : faire défiler vers le bas", "MovieDetailsPreviousMovie": "Détails du film : Film Précédent", "MovieDetailsNextMovie": "Détails du film : Prochain Film", - "MoviesSelectedInterp": "{0} Film(s) Sélectionner", "MovieIsUnmonitored": "Le film n'est pas surveillé", - "MovieIsOnImportExclusionList": "Film sur la liste d'exclusion d'importation", "MovieFolderFormat": "Format de dossier de film", - "MinimumFreeSpaceWhenImportingHelpText": "Empêcher l'importation si elle laisse moins d'espace disque disponible que cette quantité", "MIA": "MIA", "LaunchBrowserHelpText": " Ouvrer un navigateur Web et accéder à la page d'accueil de Prowlarr au démarrage de l'application.", - "CustomFormatJSON": "Format personnalisé JSON", "CloseCurrentModal": "Fermer le modal actuel", "AddingTag": "Ajouter un tag", "OnHealthIssueHelpText": "Sur un problème de santé", "AcceptConfirmationModal": "Accepter la modalité de confirmation", - "StartSearchForMissingMovie": "Lancer la recherche de film manquant", "StartProcessing": "Lancer le traitement", - "StartImport": "Lancer l'importation", "SearchFailedPleaseTryAgainLater": "La recherche a échoué, veuillez réessayer plus tard.", - "RequiredRestrictionPlaceHolder": "La version doit contenir au moins un de ces termes (insensible à la casse)", "Released": "Libéré", - "ProcessingFolders": "Traitement des dossiers", "OpenThisModal": "Ouvrer ce modal", - "NoMatchFound": "Pas de résultat trouvé !", "ImportRootPath": "Pointer Prowlarr vers le dossier contenant tous vos films, pas un en particulier. par exemple. {0} et non {1}", - "ImportIncludeQuality": "Assurez-vous que vos fichiers incluent la qualité dans leurs noms de fichiers. par exemple. {0}", "ImportErrors": "Erreurs d'importation", - "Existing": "Existant", "EditRestriction": "Modifier la restriction", - "Digital": "Numérique", "CancelProcessing": "Annuler le traitement", - "AddRestriction": "Ajouter Restriction", "AddMovie": "Ajouter Film", "IndexerLongTermStatusCheckSingleClientMessage": "Indexeurs indisponibles en raison de pannes pendant plus de 6 heures : {0}", "IndexerLongTermStatusCheckAllClientMessage": "Tous les indexeurs sont indisponibles en raison d'échecs de plus de 6 heures", - "EditMovieFile": "Modifier Fichier Vidéo", "Yesterday": "Hier", "Tomorrow": "Demain", "Today": "Aujourd'hui", @@ -866,7 +564,6 @@ "SettingsFilterSentryEvents": "Filtrer les événements d'analyse", "SettingsConsoleLogLevel": "Niveau de journalisation de la console", "SearchIndexers": "Recherche indexeurs", - "NewznabVipCheckExpiringClientMessage": "Les avantages VIP de l'indexeur arrivent bientôt à expiration : {0}", "NewznabVipCheckExpiredClientMessage": "Les avantages VIP de l'indexeur ont expiré : {0}", "IndexersSelectedInterp": "{0} indexeur(s) sélectionné(s)", "IndexerRss": "Indexeur Rss", diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index d7b060b16..62783df66 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -1,32 +1,19 @@ { - "ListUpdateInterval": "Lista frissítés gyakorisága", "About": "Névjegy", - "Year": "Év", "Analytics": "Analitika", - "AnalyseVideoFiles": "Videó fájlok analizálása", "AlternativeTitle": "Alternatív cím", - "AlreadyInYourLibrary": "Már hozzáadtad", "AllowHardcodedSubsHelpText": "Az észlelt beégetett feliratok automatikusan le lesznek töltve", - "AllowHardcodedSubs": "Beégetett feliratok engedélyezése", "AllMoviesHiddenDueToFilter": "Minden film el van rejtve a kiválasztott filter miatt.", - "AddNewTmdbIdMessage": "TMDb azonosító segítségével is kereshetsz filmre. Pl. tmdb:71663", "AddNewMovie": "Új film hozzáadása", - "AddNewMessage": "Könnyű hozzáadni egy filmet, csak kezd el gépelni a kívánt film nevét", "AddNew": "Új hozzáadása", - "AddMoviesMonitored": "Film hozzáadása monitorozva", "AddMovies": "Film hozzáadása", - "AddList": "Lista hozzáadása", "AddIndexer": "Indexer hozzáadása", "AddingTag": "Címke hozzáadása", - "AddImportExclusionHelpText": "Megakadályozza film hozzáadását Prowlarr-hoz listáról", "AddExclusion": "Kivétel hozzáadása", - "Activity": "Aktivitás", "Error": "Hiba", - "Ended": "Befejezve", "EnableCompletedDownloadHandlingHelpText": "A befejezett letöltések automatikus importálása a letöltési kliensből", "EnableColorImpairedModeHelpText": "Megváltoztatott színek, hogy a színvak felhasználók jobban meg tudják különböztetni a színkódolt információkat", "EnableAutomaticSearchHelpTextWarning": "Interaktív keresés esetén is felhasználható", - "DetailedProgressBar": "Részletes Folyamat Sáv", "DestinationRelativePath": "Célmappa Távoli Elérési Útvonala", "DeleteTag": "Címke Törlése", "EnableAutomaticSearchHelpText": "Akkor kerül felhasználásra, ha az automatikus kereséseket a kezelőfelületen vagy a Prowlarr-on keresztül hajtják végre", @@ -34,21 +21,14 @@ "EnableAutomaticAdd": "Engedélyezd az automatikus hozzáadást", "EnableAutoHelpText": "Ha engedélyezve van, a Filmek automatikusan hozzáadódnak a Prowlarr-hoz ebből a listából", "Enable": "Aktiválás", - "EditRestriction": "Korlátozás Szerkesztése", "EditRemotePathMapping": "Távoli Elérési Útvonal Módosítása", - "EditPerson": "Személy Szerkesztése", "EditMovie": "Film Szerkesztése", - "Edition": "Kiadás", "EditIndexer": "Indexer Szerkesztése", "Edit": "Szerkesztés", - "DownloadWarningCheckDownloadClientForMoreDetails": "Letöltési figyelmeztetés: Nézd meg a letöltőkliensed további információért", "DownloadWarning": "Letöltési figyelmeztetés: {0}", "Downloading": "Letöltés Alatt", - "DownloadFailedInterp": "Letöltés sikertelen: {0}", "DownloadFailedCheckDownloadClientForMoreDetails": "Letöltés Sikertelen : Nézd meg a letöltőkliensed további információért", - "DownloadFailed": "Letöltés Sikertelen", "DownloadedButNotMonitored": "Letöltve, de nincs Figyelve", - "DownloadedAndMonitored": "Letöltve és Figyelve", "Downloaded": "Letöltve", "DownloadClientUnavailable": "Letöltőkliens nem elérhető", "DownloadClientStatusCheckSingleClientMessage": "Letöltőkliens hiba miatt nem elérhető: {0}", @@ -59,66 +39,42 @@ "DownloadClientCheckUnableToCommunicateMessage": "Nem lehet kommunikálni a következővel: {0}.", "DownloadClientCheckNoneAvailableMessage": "Nem található letöltési kliens", "DownloadClient": "Letöltési Kliens", - "DotNetVersionCheckOldUnsupportedMessage": "A jelenleg telepített .Net Keretrendszer {0} régi és nem támogatott. Kérjük, frissítsd a .Net keretrendszert legalább {1} -ra.", "DotNetVersionCheckNotRecommendedMessage": "A jelenleg telepített .Net Framework {0} támogatott, de javasoljuk, hogy frissíts legalább {1} verzióra.", "Docker": "Docker", - "DiskSpace": "Szabad Tárhely", "Discover": "Felfedezés", "Disabled": "Letiltott", - "DigitalRelease": "Digitális Megjelenés", "Digital": "Digitális", "Details": "Részletek", - "DetailedProgressBarHelpText": "Szöveg megjelenítése a progess sávon", "DestinationPath": "Célmappa Útvonala", "DeleteTagMessageText": "Biztosan törlöd a(z) „{0}” címkét?", - "DeleteSelectedMovieFilesMessage": "Biztosan törlöd a kijelölt filmfájlokat?", "DeleteSelectedMovieFiles": "Töröld a Kiválaszott Film Fájlokat", - "DeleteRestrictionHelpText": "Biztosan törlöd ezt a korlátozást?", "DeleteRestriction": "Megkötés Törlése", - "DeleteQualityProfile": "Minőségi Profil Törlése", "DeleteNotificationMessageText": "Biztosan törlöd a(z) „{0}” értesítést?", "DeleteNotification": "Értesítés Törlése", - "DeleteListMessageText": "Biztosan törlöd a(z) „{0}” listát?", "DeleteList": "Lista Törlése", "DeleteIndexerMessageText": "Biztosan törlöd a(z) „{0}” indexert?", "DeleteIndexer": "Indexer Törlése", - "DeleteImportListExclusion": "Az importlista kizárásásainak törlése", "DeleteFile": "Fájl Törlése", - "DeleteEmptyFoldersHelpText": "Törölje az üres filmmappákat a lemezfrissítés és a filmfájlok törlése során", "DeleteEmptyFolders": "Üres Mappa Törlése", "DeleteDownloadClientMessageText": "Biztosan törlöd a(z) „{0}” letöltő klienst?", "DeleteDownloadClient": "Letöltőkliens Törlése", - "DeleteDelayProfile": "Késleltetési Profil Törlése", "Deleted": "Törölve", - "DeleteCustomFormat": "Egyéni Formátum Törlése", "DeleteBackupMessageText": "Biztosan törlöd a(z) „{0}” biztonsági mentést?", "DeleteBackup": "Biztonsági Mentés Törlése", "Delete": "Törlés", - "Cutoff": "Küszöbhatár", "DelayProfiles": "Késleltetési Profilok", "DelayProfile": "Késleltetési Profil", - "DelayingDownloadUntilInterp": "Késleltetni a letöltést {0} -tól {1} -ig", "DBMigration": "DB Migráció", - "Day": "Nap", "Dates": "Dátumok", "Date": "Dátum", - "CutoffUnmet": "Küszöbszint nincs elérve", "CutoffHelpText": "Amint ezt a minőséget eléri, a Prowlarr többé nem fog filmeket letölteni", - "CutoffFormatScoreHelpText": "Amint eléri ezt az egyéni minőséget, a Prowlarr többé nem fogja tovább keresni a filmet", "CustomFormatUnknownConditionOption": "Ismeretlen „{0}” opció a(z) „{1}” feltételhez", - "CustomFormatUnknownCondition": "Ismeretlen Egyéni Formátum állapota '{0}'", "CustomFormatsSettingsSummary": "Egyéni Formátum és Beállításai", - "CustomFormatsSettings": "Egyéni Formátum Beállításai", "CustomFormats": "Egyéni Formátumok", - "CustomFormatJSON": "Egyéni Formátumú JSON", "CustomFilters": "Egyéni Szűrők", - "Crew": "Stáb", "CreateGroup": "Csoport létrehozása", - "CreateEmptyMovieFoldersHelpText": "Hozzon létre mappákat a hiányzó filmeknek, filmkeresés közben", "CreateEmptyMovieFolders": "Készíts egy üres mappát", - "CouldNotFindResults": "Nincsen találat a következőre: \"{0}\"", "CopyUsingHardlinksHelpTextWarning": "Esetenként az írásvédettség megakadályozza a Seedelt fájlok átnevezését. Ideiglenesen állítsd le a Seedelést, hogy a Prowlarr át tudja nevezni a fájlokat.", - "CopyUsingHardlinksHelpText": "Használj Hardlininket, amikor megpróbálsz fájlokat másolni a még Seedelt torrentekből", "CopyToClipboard": "Másold a Vágólapra", "ConnectSettingsSummary": "Értesítések és egyéni szkriptek", "ConnectSettings": "Kapcsolódási Beállítások", @@ -127,45 +83,30 @@ "ConnectionLostAutomaticMessage": "A Prowlarr megpróbál automatikusan csatlakozni, vagy kattints a frissítés gombra.", "ConnectionLost": "Kapcsolódás Elveszett", "Connect": "Értesítések", - "Conditions": "Állapot", "Component": "Komponens", - "CompletedDownloadHandling": "Kész Letöltések Kezelése", "Columns": "Oszlopok", - "Collection": "Kollekció", "CloseCurrentModal": "Aktuális Mód Bezárása", "Close": "Bezárás", "CloneProfile": "Profil Klónozása", "CloneIndexer": "Indexer Klónozása", - "CloneFormatTag": "Címke Formázásának Klónozása", "CloneCustomFormat": "Egyéni Formátum Klónozása", "ClientPriority": "Kliens Prioritás", - "ClickToChangeQuality": "Kattints a minőség módosításához", "ClickToChangeMovie": "Kattints a film módosításához", - "ClickToChangeLanguage": "Kattints a nyelv változtatásáért", "Clear": "Törölni", - "ChooseAnotherFolder": "Válassz másik Mappát", "CheckForFinishedDownloadsInterval": "Befejezett letöltések átnézésének intervalluma", - "CheckDownloadClientForDetails": "nézd meg a letöltési kliensed több információért", "ChangeHasNotBeenSavedYet": "A változások még nem lettek elmentve", - "ChangeFileDate": "Fájl Dátumának Módosítása", "CertificationCountryHelpText": "Válasszd ki melyik ország korhatárbesorolása jelenjen meg", - "CertificationCountry": "Tanúsító Ország", "Certification": "Tanúsítvány", "CertificateValidationHelpText": "Módosítsa a HTTPS tanúsítás szigorúságát", "CertificateValidation": "Tanúsítvány érvényesítése", - "Cast": "Szereplők", "CantFindMovie": "Miért nem találom a filmemet?", - "CancelProcessing": "Feldolgozás Megállítása", "CancelPendingTask": "Biztosan törlöd ezt a függőben lévő feladatot?", "Cancel": "Vissza", - "Calendar": "Naptár", "BypassProxyForLocalAddresses": "Proxy megkerülése a helyi hálózatos címekhez", "BranchUpdateMechanism": "A külső frissítési mechanizmus által használt ágazat", "BranchUpdate": "Ágazattípus a Prowlarr frissítéseihez", "Branch": "Ágazat", - "BlacklistRelease": "Feketelistás Kiadás", "BlacklistHelpText": "Megakadályozza, hogy a Prowlarr automatikusan letöltse újra ezt a filmet", - "Blacklisted": "Feketelistás", "Blacklist": "Feketelista", "BindAddressHelpText": "Érvényes IP4-cím, vagy „*” minden interfészhez", "BindAddress": "Kapcsolási Cím", @@ -176,9 +117,7 @@ "BackupIntervalHelpText": "Időeltérés a biztonsági mentések között", "BackupFolderHelpText": "Az elérési útvonalak a Prowlarr AppData könyvtárában lesznek", "Backup": "Biztonsági Mentés", - "AvailabilityDelayHelpText": "A rendelkezésre álló dátum előtti vagy utáni idő a film kereséséhez", "AvailabilityDelay": "Elérhetőség Késleltetése", - "AutoUnmonitorPreviouslyDownloadedMoviesHelpText": "A lemezről törölt filmeket a Prowlarr automatikusan eltávolítja a megfigyelt filmek közül", "AutoRedownloadFailedHelpText": "Másik kiadás automatikus keresése és letöltése", "AutomaticSearch": "Automatikus Keresés", "Automatic": "Automatikus", @@ -187,87 +126,58 @@ "AnalyticsEnabledHelpText": "Küldjön névtelen használati és hibainformációkat a Prowlarr szervereire. Ez magában foglalja a böngészőjéről szóló információkat, mely Prowlarr WebUI oldalakat használja, a hibajelentést, valamint az operációs rendszer adatait. Ezeket az információkat a funkciók és a hibajavítások rangsorolására használjuk fel.", "AuthenticationMethodHelpText": "Felhasználónév és Jelszó szükséges a Prowlarr-hoz való hozzáféréshez", "Authentication": "Hitelesítés", - "AudioInfo": "Hang Infó", "AsAllDayHelpText": "Az események egész napos eseményként jelennek meg a naptáradban", "AreYouSureYouWantToResetYourAPIKey": "Biztos hogy vissza szeretnéd állítani az API-Kulcsod?", - "AreYouSureYouWantToDeleteThisRemotePathMapping": "Biztos, hogy törölni szeretnéd a távoli elérési útvonalat?", "AreYouSureYouWantToDeleteThisImportListExclusion": "Biztos, hogy törölni szeretnéd az importálási lista kivételeit?", - "AreYouSureYouWantToDeleteThisDelayProfile": "Biztos hogy törölni szeretnéd ezt a késleltetési profilt?", "ApplyTagsHelpTexts2": "Hozzáadás: Új címkék hozzáadása a meglévő címkékhez", "ApplyTagsHelpTexts1": "Hogyan adjunk hozzá címkéket a kiválasztott filmhez", "ApplyTags": "Címkék alkalmazása", - "AgeWhenGrabbed": "Kora (mikor hozzáadásra került)", "Age": "Kora", - "AddListExclusion": "Kizárási Lista Hozzáadása", "ApiKey": "API Kulcs", - "AllowMovieChangeClickToChangeMovie": "Kattints a film szerkesztéséhez", "All": "Összes", - "Agenda": "Teendők", "AcceptConfirmationModal": "Változás Megerősítése", "Apply": "Alkalmazás", "AppDataLocationHealthCheckMessage": "A frissítés nem lehetséges anélkül hogy az AppData ne törlődjön", "AppDataDirectory": "AppData Mappa", - "AddRestriction": "Korlátozás Hozzáadása", "AddRemotePathMapping": "Adj Meg Egy Távoli Elérési Útvonalat", - "AddMovie": "Film Hozzáadása", "Added": "Hozzáadva", "Actions": "Teendők", "History": "Történet", "HideAdvanced": "Haladó Elrejtése", "HiddenClickToShow": "Rejtett, kattints a megjelenítéshez", - "HelpText": "Intervallum percekben. A letiltáshoz állítsa nullára (ez megállítja az összes automatikus keresést)", "HealthNoIssues": "Nincs hiba a konfigurációval", "Health": "Állapot", - "HaveNotAddedMovies": "Még nem adottál hozzá egyetlen filmet sem. Először szeretnéd importálni néhány filmedet vagy az összes filmet?", "HardlinkCopyFiles": "Hardlinkelés/Fájl(ok) Másolása", - "Group": "Csoport", "GrabReleaseMessageText": "Prowlarr nem tudta meghatározni, hogy melyik filmhez készült ez a kiadás. Lehet, hogy a Prowlarr nem tudja automatikusan importálni ezt a kiadást. Meg szeretnéd ragadni a (z) „{0}”-t?", - "GoToInterp": "Ugrás ide: {0}", "Genres": "Műfajok", "GeneralSettingsSummary": "Port, SSL, felhasználónév / jelszó, proxy, elemzések, és frissítések", - "FileChmodHelpTexts2": "Ugyanez a mód lesz alkalmazva azokra a filmekre / almappákra, amelyekhez a futtató bit hozzá lett adva, pl. A 0644-ból 0755 lesz", "FreeSpace": "Szabad Tárhely", - "ForMoreInformationOnTheIndividualIndexers": "Az egyes indexerekről további információkért kattints az info gombokra.", "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Az egyes importálási listákkal kapcsolatos további információkért kattints az info gombokra.", "ForMoreInformationOnTheIndividualDownloadClients": "Ha többet szeretnél megtudni a különböző letöltési kliensekről, kattints az információs gombokra.", - "Formats": "Formátumok", "Forecast": "Előrejelzés", - "FollowPerson": "Személy Követése", "Folders": "Mappák", "Folder": "Mappa", "FocusSearchBox": "Fókusz Keresőmező", "Fixed": "Kijavítva", - "FirstDayOfWeek": "A Hét Első Napja", "FilterPlaceHolder": "Filmek Keresése", "Filter": "Szűrő", - "Filesize": "Fájlméret", "Files": "Fájl", - "FileNames": "Fájlnevek", "Filename": "Fájlnév", - "FileManagement": "Fájlkezelő", "FileDateHelpText": "A fájl dátumának módosítása az importáláskor / újrakereséskor", - "FileChmodMode": "Fájl CHMOD Mód", "FileChmodHelpTexts1": "Octal, médiafájlokra alkalmazva, amikor a Prowlarr importálja / átnevezi őket", - "FailedLoadingSearchResults": "Nem sikerült betölteni a keresési eredményeket, próbálkozz újra.", "FailedDownloadHandling": "Nem sikerült a letöltés kezelése", "Failed": "Sikertelen", - "ExtraFileExtensionsHelpTexts2": "Például: '.sub, .nfo' vagy 'sub, nfo'", "ExtraFileExtensionsHelpTexts1": "Az importálandó extra fájlok vesszővel lesznek elválasztva (.nfo .nfo-orig néven lesz importálva)", - "Extension": "Kiterjesztés", "ExportCustomFormat": "Egyéni Formátum Exportálása", "ExistingTag": "Meglévő Címke", "ExistingMovies": "Létező Film(ek)", - "Existing": "Létező", "ExcludeMovie": "Film Kizárása", - "Excluded": "Kizárt", "Exception": "Kivétel", "EventType": "Események Típusa", "Events": "Események", - "ErrorLoadingPreviews": "Hiba történt az előnézetek betöltése közben", "ErrorLoadingContents": "Hiba történt a tartalom betöltésekor", "EnableSslHelpText": " A hatálybalépéshez újra kell indítani rendszergazdaként", "EnableSSL": "SSL Engedélyezése", - "EnableRSS": "RSS Engedélyezése", "EnableMediaInfoHelpText": "Videofájlok, például felbontás, filmhossz és kodek információk kiolvasása fájlokból. Ehhez a Prowlarr-nak fel kell dolgoznia a fájl olyan részeit, amelyek nagy lemez, illetve hálózati aktivitást okozhatnak a vizsgálatok során.", "EnableInteractiveSearchHelpTextWarning": "A keresés nem támogatott ezzel az Indexerrel", "EnableInteractiveSearchHelpText": "Interaktív keresés esetén használható", @@ -277,110 +187,71 @@ "EnableColorImpairedMode": "Engedélyezze a színtévesztő módot", "System": "Rendszer", "SuggestTranslationChange": "Javasolj fordítási változtatást", - "SubfolderWillBeCreatedAutomaticallyInterp": "A(z) „{0}” almappa automatikusan létrehozásra kerül", "Style": "Stílus", - "Studio": "Stúdió", "Status": "Állapot", "StartupDirectory": "Indítási könyvtár", "StartTypingOrSelectAPathBelow": "Kezdd el gépelni, vagy válassz az alábbi útvonalak közül", - "StartSearchForMissingMovie": "Indítsd el a hiányzó film(ek) keresését", "StartProcessing": "Feldolgozás elindítása", - "StartImport": "Importálás elindítása", "StandardMovieFormat": "Normál filmformátum", "SSLPort": "SSL Port", "SSLCertPathHelpText": "A PFX fájl elérési útvonala", "SSLCertPath": "Az SSL tanúsítvány elérési útvonala", "SSLCertPasswordHelpText": "Jelszó a Pfx fájlhoz", "SSLCertPassword": "SSL Tanúsítvány jelszava", - "SourceTitle": "Forrás címe", "SourceRelativePath": "Forrás relatív útvonala", - "SourcePath": "Forrás útvonala", "Source": "Forrás", "Sort": "Rendezés", - "SorryThatMovieCannotBeFound": "Sajnáljuk, ez a film nem található.", "SkipFreeSpaceCheckWhenImportingHelpText": "Akkor használja, ha a Prowlarr nem képes felismerni a gyökérmappában lévő szabad helyet", - "SkipFreeSpaceCheck": "A szabad hely ellenőrzésének kihagyása", "SizeOnDisk": "Méret a lemezen", "Size": "Méret", "Shutdown": "Leállítás", - "ShowYear": "Év megjelenítése", "ShowUnknownMovieItems": "Ismeretlen filmelemek megjelenítése", - "ShowTitleHelpText": "Mutasd a filmcímet a poszter alatt", "ShowTitle": "Cím megjelenítése", - "ShowStudio": "Stúdió megjelenítése", "ShowSizeOnDisk": "Használt hely megjelenítése", "ShowSearchHelpText": "A kereső gomb megjelenítése az egérrel", - "MonoVersionCheckOldNotSupportedMessage": "A jelenleg telepített Mono {0} verzió régi és nem támogatott. Kérjük, frissítsd a Mono-t {1} verzióra.", "ShowRatings": "Értékelések mutatása", - "ShowQualityProfileHelpText": "Minőségi profil megjelenítése a poszter alatt", "SettingsWeekColumnHeaderHelpText": "Minden oszlop felett jelenjen meg, hogy melyik hét az aktuális", "MonoVersion": "Mono Verzió", "MonoTlsCheckMessage": "A Prowlarr Mono 4.x tls megoldás továbbra is engedélyezett, fontolja meg a MONO_TLS_PROVIDER =legacy opció eltávolítását", - "Global": "Globális", "CleanLibraryLevel": "Könyvtár tisztítása", - "iCalLink": "iCal Link(ek)", "ShowQualityProfile": "Minőségi profil megjelenítése", - "ShowPath": "Útvonal mutatása", "ShownClickToHide": "Kattints, hogy elrejtsd", - "ShowMovieInformationHelpText": "Film műfajának és korhatár besorolásának megjelenítése", "ShowMovieInformation": "Filminformációk megjelenítése", - "ShowMonitoredHelpText": "Monitorozott státusz kijelzése a poszter alatt", "ShowMonitored": "Monitorozottak mutatása", - "ShowGenres": "Műfaj mutatása", "ShowDateAdded": "Hozzáadás dátuma", - "ShowCutoffUnmetIconHelpText": "Szimbólum megjelenítése, ha a minőségi küszöböt még nem érték el", "ShowCertification": "Tanúsítvány megjelenítése", - "ShowAsAllDayEvents": "Megjelenítés egész napos eseményként", "ShowAdvanced": "Haladó nézet", - "ShouldMonitorHelpText": "Ha engedélyezve van, a lista által hozzáadott filmek automatikusan figyelve lesznek", "SettingsWeekColumnHeader": "Heti oszlopfejléc", "SettingsTimeFormat": "Időformátum", "SettingsShowRelativeDatesHelpText": "Relatív (Ma / Tegnap / stb.) vagy valós dátumok megjelenítése", "SettingsShowRelativeDates": "Relatív dátumok megjelenítése", "SettingsShortDateFormat": "Rövid dátumformátum", - "SettingsRuntimeFormat": "Futásidő formátuma", "SettingsRemotePathMappingRemotePathHelpText": "Gyökérútvonal a könyvtárhoz, amelyhez a letöltőkliens hozzáfér", - "SettingsRemotePathMappingRemotePath": "Távoli elérési útvonal", "SettingsRemotePathMappingLocalPathHelpText": "Elérési út, amelyet a Prowlarr használhat a távoli elérési út, helyi eléréséhez", - "SettingsRemotePathMappingLocalPath": "Helyi útvonal", "SettingsLongDateFormat": "Hosszú dátumformátum", - "SettingsFirstDayOfWeek": "A hét első napja", "SettingsEnableColorImpairedModeHelpText": "Megváltoztatott stílus, hogy a színtévesztő felhasználók jobban megkülönböztessék a színkódolt információkat", "SettingsEnableColorImpairedMode": "Színtévesztő mód bekapcsolása", "Settings": "Beállítások", - "SetPermissionsLinuxHelpTextWarning": "Ha nem vagy biztos abban, hogy ezek a beállítások mit csinálnak, ne változtasd meg őket.", "SetPermissionsLinuxHelpText": "Futtatni kell a chmod-ot fájlok importálásakor / átnevezésekor?", - "SetPermissions": "Engedélyek beállítása", "SendAnonymousUsageData": "Névtelen használati adatok küldése", - "SelectFolder": "Mappa kiválasztása", "SelectAll": "Összes kijelölése", "Seeders": "Seederek", "Security": "Biztonság", - "SearchSelected": "Kiválasztottak keresése", "SearchOnAddHelpText": "Keresse meg a listán található filmeket, ha hozzá van adva a Prowlarrhoz", - "SearchOnAdd": "Keresés hozzáadáskor", "SearchMovie": "Film keresés", - "SearchForMovie": "Film keresés", "SearchForMissing": "Hiányzó keresése", - "SearchFiltered": "Keresés szűrve", "SearchFailedPleaseTryAgainLater": "Keresés sikertelen, próbáld újra később.", - "SearchAll": "Összes keresése", "Search": "Keresés", "ScriptPath": "Script útvonal", "Scheduled": "Ütemezve", "SaveSettings": "Beállítások mentése", "SaveChanges": "Változtatások mentése", "Save": "Mentés", - "Runtime": "Futási idő", "RSSSyncIntervalHelpTextWarning": "Ez minden indexerre vonatkozni fog, kérjük, tartsa be az általuk meghatározott szabályokat", - "RSSSyncInterval": "RSS Szikronizálás Intervalluma", "RSSSync": "RSS Szinkronizálás", "RSSIsNotSupportedWithThisIndexer": "Az RSS nem támogatott ezzel az indexerrel", - "RootFolders": "Gyökérmappák", "RootFolderCheckSingleMessage": "Hiányzó gyökérmappa: {0}", - "RootFolderCheckMultipleMessage": "Több gyökérmappa hiányzik: {0}", "RootFolder": "Gyökérmappa", - "RetryingDownloadInterp": "A letöltés újrapróbálása {0} itt {1}", "RetentionHelpText": "Usenet: Állítsa nullára a korlátlan megőrzés beállításához", "Retention": "Visszatartás", "Result": "Eredmények", @@ -393,79 +264,46 @@ "Restart": "Újraindítás", "ResetAPIKey": "API Kulcs visszaállítása", "Reset": "Visszaállítás", - "RescanMovieFolderAfterRefresh": "Film mappa újraszkennelése a frissítés után", "RescanAfterRefreshHelpTextWarning": "A Prowlarr nem érzékeli automatikusan a fájlok változását, ha nincs beállítva „Always”-re", - "RescanAfterRefreshHelpText": "A film frissítése után vizsgálja át a filmmappát", "RequiredRestrictionPlaceHolder": "A kiadásnak tartalmaznia kell legalább egy ilyen kifejezést (a kis- és nagybetűket nem veszi figyelembe)", - "RequiredPlaceHolder": "Új korlátozás hozzáadása", "RequiredHelpText": "Ennek a {0} feltételnek meg kell egyeznie az egyéni formátum alkalmazásához. Ellenkező esetben egyetlen {1} egyezés elegendő.", - "ReplaceIllegalCharactersHelpText": "Helyettesítse az illegális karaktereket. Ha nincs bejelölve, akkor a Prowlarr eltávolítja őket", "ReplaceIllegalCharacters": "Az illegális karakterek cseréje", - "Reorder": "Átrendezés", "RenameMoviesHelpText": "A Prowlarr a meglévő fájlnevet fogja használni, ha az átnevezés le van tiltva", - "RenameMovies": "Film(ek) átnevezése", "RenameFiles": "Fájl(ok) átnevezése", - "Renamed": "Átnevezve", "RemovingTag": "Címke eltávolítása", - "RemoveSelected": "Kiválaszottak törlése", "RemoveRootFolder": "Gyökérmappa eltávolítása", - "RemoveHelpTextWarning": "Az eltávolítás eltávolítja a letöltést és a fájl(oka)t a letöltési kliensből.", "RemoveFromQueue": "Eltávolítás a sorból", - "RemoveFromDownloadClient": "Eltávolítás a letöltőkliensből", "RemoveFromBlacklist": "Eltávolítás a feketelistáról", "RemoveFilter": "Szűrő törlése", - "RemoveFailedDownloadsHelpText": "Távolítsa el a sikertelen letöltéseket a letöltési kliens előzményeiből", "RemovedMovieCheckSingleMessage": "A(z) {0} filmet eltávolították a TMDb-ről", - "RemovedMovieCheckMultipleMessage": "A(z) {0} filmet eltávolították a TMDb-ről", "RemovedFromTaskQueue": "Eltávolítva a feladatsorról", - "RemoveCompletedDownloadsHelpText": "Távolítsa el az importált letöltéseket a letöltési kliens előzményeiből", "Remove": "Eltávolítás", - "RemotePathMappings": "Távoli Elérési Útvonal", "Reload": "Újratöltés", - "ReleaseWillBeProcessedInterp": "A kiadás feldolgozása {0}", "ReleaseTitle": "Kiadás címe", "ReleaseStatus": "Kiadás státusza", - "ReleaseRejected": "Kiadás elutasítva", "ReleaseGroup": "Kiadási Csoport", - "ReleaseDates": "Megjelenés Dátuma", "Released": "Megjelent", "ReleaseBranchCheckPreviousVersionMessage": "Az ágazat {0} a Prowlarr előző verziójához tartozik, a további frissítések érdekében állítsd az ágat 'nightly'-ra", "ReleaseBranchCheckOfficialBranchMessage": "A(z) {0} nem érvényes Prowlarr frissítési ágazat, ezért nem kap frissítéseket", - "RelativePath": "Relatív Útvonal", "RejectionCount": "Elutasítások száma", "RefreshMovie": "Film frissítése", - "RefreshInformationAndScanDisk": "Információk frissítése és lemez átvizsgálása", "RefreshAndScan": "Frissítés & Keresés", "Refresh": "Frissítés", - "Redownload": "Letöltés újra", "RecyclingBinCleanup": "Lomtár kiürítése", - "RecyclingBin": "Lomtár", "RecycleBinHelpText": "A filmfájlok végleges törlés helyett ide kerülnek törléskor", - "RecycleBinCleanupDaysHelpTextWarning": "A kiválasztott napoknál régebbi fájlok a lomtárban automatikusan törlésre kerülnek", "RecycleBinCleanupDaysHelpText": "Állítsd 0-ra az automatikus tisztítás letiltásához", - "RecentFolders": "Legutóbbi mappák", "Reason": "Ok", - "Real": "Valódi", "ReadTheWikiForMoreInformation": "Olvasd el a Wiki-t további információkért", - "Ratings": "Értékelések", "ProwlarrTags": "Prowlarr Címkék", - "ProwlarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "A Prowlarr támogatja az egyéni feltételeket az alábbi kiadási tulajdonságokkal szemben.", "ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "A Prowlarr támogatja az RSS filmlistákat, valamint az alábbiakban felsoroltakat.", "ProwlarrSupportsAnyIndexer": "A Prowlarr számos indexert támogat, minden olyan indexelő mellett, amely a Newznab / Torznab szabványt használja, valamint a 'Generic Newznab' (usenethez) vagy a 'Generic Torznab' (torrentekhez) használatával. Keresés és az alább felsorolt indexelők kiválasztása.", "ProwlarrSupportsAnyDownloadClient": "A Prowlarr minden olyan letöltési klienst támogat, amely a Newznab szabványt használja, valamint az alább felsorolt letöltési klienseket.", - "Prowlarr": "Prowlarr", "QuickImport": "Gyors Importálás", - "Queued": "Sorban", "Queue": "Várakozási sor", - "QualitySettingsSummary": "Minőségi méretek és elnevezés", "QualitySettings": "Minőségi beállítások", - "QualityProfiles": "Minőségi profilok", "QualityProfileDeleteConfirm": "Biztosan törli a {0} minőségi profilt", - "QualityProfile": "Minőségi Profil", "QualityDefinitions": "Minőségi meghatározások", - "QualityCutoffHasNotBeenMet": "Minőségi küszöbhatár nincs elérve", "Quality": "Minőség", - "PublishedDate": "Közzététel dátuma", "PtpOldSettingsCheckMessage": "A következő PassThePopcorn indexerek elavult beállításokkal rendelkeznek, és frissíteni kell őket: {0}", "ProxyUsernameHelpText": "Csak akkor kell megadnod felhasználónevet és jelszót, ha szükséges. Egyébként hagyd üresen.", "ProxyType": "Proxy Típusa", @@ -475,151 +313,96 @@ "ProxyCheckBadRequestMessage": "Proxy tesztelése sikertelen. Állapotkód: {0}", "ProxyBypassFilterHelpText": "Használja elválasztóként a ',' és a '*' karaktereket, az aldomainek helyettesítőjeként", "Proxy": "Proxy", - "ProtocolHelpText": "Válasszd ki a használni kívánt protokoll(oka)t és melyiket részesíted előnyben, ha az egyébként egyforma kiadások közül választasz", "Protocol": "Protokoll", - "Proper": "Proper", "Progress": "Folyamat", - "ProfilesSettingsSummary": "Minőség, Nyelv, és Késleltetési profil", "Profiles": "Profil(ok)", - "ProcessingFolders": "Mappák feldolgozása", "PriorityHelpText": "Priorizálj több letöltési klienst. A Round-Robint azonos prioritású letöltőkliensek használják.", "Priority": "Prioritás", - "PreviewRename": "Előnézet átnevezése", "PreferIndexerFlagsHelpText": "Prioritizáld a kiadásokat speciális zászlók segítségével", - "Original": "Eredeti", "OnGrabHelpText": "Megfogva", - "MoreDetails": "További részletek", "Month": "Hónap", "MonoVersionCheckUpgradeRecommendedMessage": "A jelenleg telepített Mono {0} verzió támogatott, de ajánlott frissíteni a(z) {1} verzióra.", - "MonoVersionCheckNotSupportedMessage": "A jelenleg telepített Mono {0} verzió már nem támogatott. Kérjük, frissítsd a Mono-t {1} verzióra.", "PreferredSize": "Preferált méret", - "PreferIndexerFlags": "Indexelő Zászlók előnyben részesítése", "PosterSize": "Poszter mérete", - "Posters": "Poszterek", "PosterOptions": "Poszter beállítások", "PortNumber": "Port száma", "Port": "Port", - "PhysicalRelease": "Fizikális Megjelenés", "Permissions": "Engedélyek", "PendingChangesStayReview": "Maradj, és tekintsd át a változásokat", "PendingChangesMessage": "Nem mentett módosításaid vannak, biztosan el akarod hagyni ezt az oldalt?", "PendingChangesDiscardChanges": "Változtatások törlése és kilépés", "Pending": "Függőben", "Peers": "Peerek", - "Paused": "Megállítva", "Path": "Útvonal", "Password": "Jelszó", "PageSizeHelpText": "Az egyes oldalakon megjelenítendő elemek száma", "PageSize": "Oldal mérete", "PackageVersion": "Csomagverzió", - "OverviewOptions": "Áttekintési opciók", "Overview": "Áttekintés", - "OutputPath": "Kimeneti út", "OrganizeModalSuccess": "Siker! Befejeztem a munkám, nincsenek átnevezésre váró fájlok.", - "OrganizeModalNamingPattern": "Elnevezési minta:", "OrganizeModalDisabled": "Az átnevezés le van tiltva, nincs mit átnevezni", - "OrganizeAndRename": "Rendezés & Átnevezés", "Organize": "Rendezés", "Options": "Opciók", "OpenThisModal": "Nyissa meg ezt a modált", "OpenBrowserOnStart": "Indításkor nyissa meg a böngészőt", - "OnUpgradeHelpText": "Küldj értesítést, ha egy filmből letöltésre került egy jobb minőségű", "OnRenameHelpText": "Átnevezés alatt", "OnHealthIssueHelpText": "Állapotprobléma", - "OnDownloadHelpText": "Küldj értesítést, ha a filmet sikeresen importáltad", "OnDeleteHelpText": "Törlés alatt", "Ok": "Ok", "OAuthPopupMessage": "A böngésződ blokkolja az előugró ablakokat", "NoUpdatesAreAvailable": "Nincsenek elérhető frissítések", - "NotMonitored": "Nincs monitorozva", "NotAvailable": "Nem elérhető", "NoTagsHaveBeenAddedYet": "Még nem adtál hozzá címkéket", "NoMinimumForAnyRuntime": "Nincs minimális futásidő", - "NoMatchFound": "Nem található egyezés!", "NoLogFiles": "Nincsen log fájl", "NoLimitForAnyRuntime": "Nincs futási idő korlát", "NoLeaveIt": "Nem, hagyd így", - "NoHistory": "Nincs(enek) előzmény(ek)", "NoChanges": "Nincsenek változások", "NoChange": "Nincs változtatás", "NoBackupsAreAvailable": "Nincs elérhető biztonsági mentés", "New": "Új", "NetCore": ".NET", - "NegateHelpText": "Ha be van jelölve, az egyéni formátum nem lesz érvényes, ha ez a(z) {0} feltétel megegyezik.", "NamingSettings": "Elnevezési beállítások", "Name": "Név", - "MustNotContain": "Nem tartalmazhatja", "MustContain": "Tartalmaznia kell", - "MovieYearHelpText": "A kizárandó film(ek) éve", "MovieYear": "Kiadási év", - "MovieTitleHelpText": "A kizárandó film címe (bármi értelmes lehet)", "MovieTitle": "Filmcím", - "MoviesSelectedInterp": "{0} Kiválasztott film(ek)", "Movies": "Filmek", - "MovieNaming": "Film elnevezése", "MovieIsUnmonitored": "A film nincs monitorozva", - "MovieIsOnImportExclusionList": "A film az importkizárási listán található", "MovieIsMonitored": "A film monitorozva van", - "MovieIsDownloadingInterp": "A film letöltés alatt - {0}% {1}", "MovieIsDownloading": "A film letöltés alatt", - "MovieInfoLanguageHelpTextWarning": "Böngésző újratöltése szükséges", "MovieInfoLanguageHelpText": "A Prowlarr által a filminformációkhoz használt nyelv", - "MovieInfoLanguage": "Film információ nyelve", "MovieIndexScrollTop": "Film Index: Görgess fel", "MovieIndexScrollBottom": "Film Index: Görgess le", - "MovieIndex": "Film Index", "MovieID": "Film ID", - "MovieFolderFormat": "Film mappaformátum", "MovieFiles": "Filmfájl(ok)", - "MovieExcludedFromAutomaticAdd": "Az automatikus hozzáadásból kizárt film", "MovieEditor": "Filmszerkesztő", "MovieDetailsPreviousMovie": "A film részletei: Előző film", "MovieDetailsNextMovie": "A film részletei: Következő film", - "MovieAvailableButMissing": "A film elérhető, de hiányzik", "MovieAlreadyExcluded": "A film már ki lett zárva", - "Movie": "Film", "MoveFiles": "Fájl(ok) mozgatása", - "MountCheckMessage": "A filmútvonalat tartalmazó mappa csak olvasható: ", "MoreInfo": "Több Információ", - "YouCanAlsoSearch": "Kereshetsz a film TMDb azonosítójával vagy IMDb azonosítójával is. Például. tmdb: 71663", "MonoNotNetCoreCheckMessage": "Kérjük, frissítsd a Prowlarr .NET Core verzióját", - "MonitorMovie": "Film Monitorozása", "MonitoredOnly": "Csak a Megfigyelt", - "MonitoredHelpText": "Töltse le a filmet, ha elérhető", "Monitored": "Monitorozva", - "Monitor": "Monitorozni", "Mode": "Mód", - "MissingNotMonitored": "Hiányzó, nincs monitorozva", "MissingMonitoredAndConsideredAvailable": "Hiányzik, Monitorozva van és elérhetőnek tekintett", - "Missing": "Hiányzó", "MinutesSixty": "60 Perc: {0}", "MinutesNinety": "90 Perc: {0}", "MinutesHundredTwenty": "120 Perc: {0}", "MinimumLimits": "Minimális Határ", - "MinimumFreeSpaceWhenImportingHelpText": "Akadályozza meg az importálást, ha ennél kevesebb lemezterület maradna", "MinimumFreeSpace": "Minimális Szabad Tárhely", - "MinimumAvailability": "Minimális rendelkezésre állás", "MinimumAgeHelpText": "Usenet: Az NZB-k minimális életkora percekben, mielőtt megragadnák őket. Használja ezt arra, hogy időt biztosítson az új kiadásoknak az usenet-szolgáltatóhoz történő továbbterjesztésre.", - "MinimumAge": "Minimális Kor", "MinFormatScoreHelpText": "A letöltéshez engedélyezett minimális egyéni formátum pontszám", - "MinAvailability": "Minimum Elérhetőség", "MIA": "MIA", - "MetadataSettingsSummary": "Készítsen metadatafájlokat, amikor filmeket importál vagy frissít", "MetadataSettings": "Metadata Beállítások", - "Metadata": "Metaadat(ok)", "Message": "Üzenet", - "MediaManagementSettingsSummary": "Elnevezési és fájlkezelési beállítások", "MediaManagementSettings": "Média Kezelési Beállítások", - "MediaManagement": "Média Kezelés", "MediaInfoDllCheckMessage": "A MediaInfo könyvtár betöltése nem sikerült {0}", - "MediaInfo": "Média Információ", "Mechanism": "Mechanizmus", - "MaximumSizeHelpText": "A kiadás maximális mérete MB-ban. Állítsd nullára a korlátlan értékre", "MaximumSize": "Maximális Méret", "MaximumLimits": "Maximális Limit", - "MassMovieSearch": "Tömeges filmkeresés", "MarkAsFailedMessageText": "Biztosan sikertelennek szeretnéd jelölni a (z) „{0}”-t?", - "MarkAsFailed": "Megjelölés Sikertelenként", "ManualImport": "Manuális Importálás", "Manual": "Manuális", "MaintenanceRelease": "Karbantartási kiadás", @@ -627,63 +410,43 @@ "LogLevelTraceHelpTextWarning": "A nyomkövetést csak ideiglenesen szabad engedélyezni", "LogLevel": "Log Szint", "Logging": "Loggolás", - "LogFilesLocationMessage": "Log Fájlok Helye:", "LogFiles": "Log Fájlok", - "Location": "Lokáció", "Local": "Helyi", - "LoadingMovieFilesFailed": "A film fájljainak betöltése sikertelen", "LoadingMovieExtraFilesFailed": "A film extra fájljainak betöltése nem sikerült", - "LoadingMovieCreditsFailed": "Stáblista Betöltése Sikertelen", "ListSyncLevelHelpText": "A könyvtárban lévő filmeket eltávolítjuk vagy nem figyeljük meg, ha nem szerepelnek a listán", - "ListsSettingsSummary": "Lista Importálása, Kizárások listázása", "ListSettings": "Lista Beállítások", - "Lists": "Listák", "ListExclusions": "Kizárások listázása", - "Links": "Linkek", "LinkHere": "ide", "Level": "Szint", "LaunchBrowserHelpText": " Nyisson meg egy böngészőt, és az alkalmazás indításakor lépjen a Prowlarr kezdőlapjára.", "LastWriteTime": "Utolsó írási idő", - "LastDuration": "Utolsó Hossza", "Languages": "Nyelvek", - "LanguageHelpText": "Nyelv a Releasekhez", "Language": "Nyelv", "KeyboardShortcuts": "Gyorsbillentyűk", "Interval": "Intervallum", "InteractiveSearch": "Interaktív Keresés", - "InteractiveImport": "Interaktív Import", "Info": "Infó", "IndexerStatusCheckSingleClientMessage": "Indexerek elérhetetlenek a következő hiba miatt: {0}", "Hostname": "Hosztnév", "Host": "Hoszt", - "GrabSelected": "Kiválasztott Megfogása", "GrabID": "Megfogás ID", "Grabbed": "Megfogva", - "Grab": "Megfog", "GeneralSettings": "Általános Beállítások", "General": "Általános", - "DownloadPropersAndRepacksHelpText1": "Filmek Automatikus frissítése a következőre: Proper / Repack", "DownloadPropersAndRepacks": "Properek és Repackok", - "CustomFormatScore": "Egyéni formátum pontszám", "UnableToLoadLanguages": "Nem sikerült betölteni a nyelveket", "UnableToLoadIndexers": "Nem lehet betölteni az indexereket", - "UnableToLoadIndexerOptions": "Nem lehet betölteni az indexer beállításait", "UnableToLoadHistory": "Nem sikerült betölteni az előzményeket", "UnableToLoadGeneralSettings": "Nem sikerült betölteni az általános beállításokat", "UnableToLoadDownloadClients": "Nem sikerült betölteni a letöltőkliens(eke)t", - "UnableToLoadDownloadClientOptions": "Nem sikerült betölteni a letöltőkliens beállításait", "UnableToLoadDelayProfiles": "Nem lehet betölteni a késleltetési profilokat", - "UnableToLoadCustomFormats": "Nem lehet betölteni az egyéni formátumokat", "UnableToLoadBlacklist": "Nem sikerült betölteni a feketelistát", "UnableToLoadBackups": "Biztonsági mentés(ek) betöltése sikertelen", - "UnableToAddANewRemotePathMappingPleaseTryAgain": "Nem lehet új távoli elérési utat hozzáadni, próbálkozz újra.", "UnableToAddANewQualityProfilePleaseTryAgain": "Nem lehet új minőségi profilt hozzáadni, próbálkozz újra.", "UnableToAddANewNotificationPleaseTryAgain": "Nem lehet új értesítést hozzáadni, próbálkozz újra.", - "UnableToAddANewListPleaseTryAgain": "Nem lehet új listát hozzáadni, próbálkozz újra.", "UnableToAddANewListExclusionPleaseTryAgain": "Nem lehet új listakizárást hozzáadni, próbálkozz újra.", "UnableToAddANewIndexerPleaseTryAgain": "Nem lehet új indexert hozzáadni, próbálkozz újra.", "UnableToAddANewDownloadClientPleaseTryAgain": "Nem lehet új letöltőklienst hozzáadni, próbálkozz újra.", - "UnableToAddANewCustomFormatPleaseTryAgain": "Nem lehet új egyéni formátumot hozzáadni, próbálkozz újra.", "UnableToAddANewConditionPleaseTryAgain": "Nem lehet új feltételt hozzáadni, próbáld meg újra.", "UISettingsSummary": "Dátum-, nyelv- és színtévesztő lehetőségek", "UISettings": "A felhasználói felület beállításai", @@ -692,19 +455,13 @@ "UILanguage": "Felület nyelve", "UI": "Felület", "Type": "Típus", - "TotalSpace": "Összes szabad hely", "TotalFileSize": "Teljes fájl méret", "Torrents": "Torrentek", - "TorrentDelayHelpText": "Eltolás percekben, mielőtt a torrentkliens elkezdi a letöltést", "TorrentDelay": "Torrent késleltetés", - "TmdbIdHelpText": "A kizárandó film TMDb azonosítója", "TMDBId": "TMDb azonosító", - "Titles": "Címek", "Title": "Cím", - "Timeleft": "Hátralévő idő", "TimeFormat": "Időformátum", "Time": "Idő", - "TestAllLists": "Összes lista tesztelése", "TestAllIndexers": "Indexerek tesztelése", "TestAllClients": "Összes kliens tesztelése", "TestAll": "Összes tesztelése", @@ -717,86 +474,53 @@ "TagCannotBeDeletedWhileInUse": "Használat közben nem törölhető", "TableOptionsColumnsMessage": "Válasszd ki, mely oszlopok legyenek láthatóak, és milyen sorrendben jelenjenek meg", "SystemTimeCheckMessage": "A rendszeridő több mint 1 napja nem frissült. Előfordulhat, hogy az ütemezett feladatok az idő kijavításáig nem futnak megfelelően", - "ColonReplacementFormatHelpText": "Változtassa meg, hogy a Prowlarr hogyan helyettesíti a kettőspontokat", "ColonReplacement": "Kettőspont Helyettesítés", "IndexerStatusCheckAllClientMessage": "Az összes indexer elérhetetlen hiba miatt", - "IndexersSettingsSummary": "Indexer és kiadási korlátozások", "IndexerSettings": "Indexer Beállítások", - "IndexerSearchCheckNoInteractiveMessage": "Nincs elérhető indexelő, interaktív keresővel engedélyezve. A Prowlarr nem nyújt interaktív keresési eredményeket", "IndexerSearchCheckNoAvailableIndexersMessage": "Az összes keresésre képes indexer átmenetileg nem elérhető, a legutóbbi indexelő hibák miatt", - "IndexerSearchCheckNoAutomaticMessage": "Nincs elérhető indexelő Automatikus kereséssel engedélyezve. A Prowlarr nem nyújt automatikus keresési eredményt", "Indexers": "Indexerek", - "IndexerRssHealthCheckNoIndexers": "Nincs elérhető indexer RSS szinkronizálással, így a Prowlarr nem fogja automatikusan megragadni az új kiadásokat", "IndexerRssHealthCheckNoAvailableIndexers": "Az összes rss-képes indexer átmenetileg nem érhető el a legújabb indexelő hibák miatt", "IndexerPriorityHelpText": "Indexelő prioritás 1-től (legmagasabb) 50-ig (legalacsonyabb). Alapértelmezés: 25.", "IndexerPriority": "Indexer Prioritása", "IndexerFlags": "Indexer Zászló", "Indexer": "Indexelő", - "IncludeUnmonitored": "Figyelmen Kívül hagyott Filmeket is Tartalmazza", "IncludeUnknownMovieItemsHelpText": "Mutasson tételeket film nélkül a sorban. Ez tartalmazhat eltávolított filmeket vagy bármi mást a Prowlarr kategóriájából", - "IncludeRecommendationsHelpText": "Helyezze be a Prowlarr ajánlásait a felfedező nézetbe", "IncludeProwlarrRecommendations": "Tartalmazza a Prowlarr Ajánlásait", "IncludeHealthWarningsHelpText": "Tartalmazza a Állapot Figyelmeztetéseket", - "IncludeCustomFormatWhenRenamingHelpText": "Tartalmazza a(z) {Custom Formats} átnevezési formátumot", "IncludeCustomFormatWhenRenaming": "Az átnevezéskor vegye fel az egyéni formátumot", - "InCinemas": "Mozikban", "ImportTipsMessage": "Néhány tipp az importálás zökkenőmentes lebonyolításához:", - "ImportRootPath": "Mutasd meg a Prowlarr-nak a filmeket tartalmazó főkönyvtáradat, nem egy konkrét filmmappát. Például. {0} és nem {1}", "ImportMovies": "Filmek Importálása", - "ImportMechanismHealthCheckMessage": "Engedélyezd a befejezett letöltés(ek) kezelését", "ImportListSyncIntervalHelpText": "A Prowlarr milyen gyakran szinkronizáljon a listáival.", - "ImportListStatusCheckSingleClientMessage": "A listák nem érhetőek el a következő hiba miatt: {0}", "ImportListStatusCheckAllClientMessage": "Az összes lista elérhetetlen, hiba miatt", "Importing": "Importálás Folyamatban", - "ImportIncludeQuality": "Győződj meg arról, hogy a fájlok tartalmazzák-e minőséget a fájlneveikben. pl. {0}", "ImportHeader": "Importáld a már meglévő filmjeidet", - "ImportFailedInterp": "Importálás Sikertelen: {0}", "ImportFailed": "Importálás sikertelen: {0}", - "ImportExtraFilesHelpText": "A megfelelő extra fájlok importálása (feliratok, nfo stb.) a filmfájl importálása után", "ImportExtraFiles": "Extra Fájlok Importálása", - "ImportExistingMovies": "Meglévő Filmek Importálása", "ImportErrors": "Importálási Hiba", - "ImportedTo": "Importálva Ide", "Imported": "Importálva", - "ImportCustomFormat": "Egyéni Formátum Importálása", "Import": "Importálás", "IllRestartLater": "Később Újraindítom", - "IgnoredPlaceHolder": "Új korlátozás hozzáadása", "IgnoredHelpText": "A kiadás elutasításra kerül, ha egy vagy több kifejezést tartalmaz (A kis- és nagybetűket nem vesszük figyelembe)", - "IgnoreDeletedMovies": "Ignorált Törölt Filmek", "IgnoredAddresses": "Ignorált Címek", - "Ignored": "Ignorált", "IconForCutoffUnmet": "Ikon a Sikertelen Küszöbszint Elérésére", - "ICalHttpUrlHelpText": "Másolja ezt az URL-t az klienseihez, vagy kattintson a feliratkozáshoz, ha böngészője támogatja a webcal-t", "ICalFeed": "iCal-Feed", - "OrganizeModalAllPathsRelative": "Minden útvonal ide vezet:", "DownloadPropersAndRepacksHelpTextWarning": "Használjon előnyben részesített szavakat a Properek / Repackok automatikus frissítésére", - "DownloadPropersAndRepacksHelpText2": "Használja a „Ne részesítse előnyben” beállítást a kívánt szó pontszámának rendezéséhez a Proper / Repack helyett", "YesCancel": "Igen, Mégsem", - "WhitelistedSubtitleTags": "Az engedélyezőlistán szereplő feliratcímkék", "WhitelistedHardcodedSubsHelpText": "Az itt beállított feliratcímkék nem minősülnek keménykódoltaknak", - "WeekColumnHeader": "Heti oszlopfejléc", "Week": "Hét", "Warn": "Figyelmeztet", - "Wanted": "Keresett", "WaitingToProcess": "Várakozás feldolgozásra", - "WaitingToImport": "Várakozás importálásra", "VisitGithubCustomFormatsAphrodite": "Látogasd meg a GitHub-ot további információkért: ", "View": "Nézet", - "VideoCodec": "Videókodek", "Version": "Verzió", "Username": "Felhasználónév", "UseProxy": "Proxy használata", - "UsenetDelayHelpText": "Időeltolás percekben, mielőtt megkaparintana egy Usenet kiadást", "UsenetDelay": "Usenet késleltetés", "Usenet": "Usenet", - "UseHardlinksInsteadOfCopy": "A másolás helyett használjon Hardlinkeket", "UrlBaseHelpText": "Fordított proxy támogatás esetén az alapértelmezett érték üres", "URLBase": "URL Bázis", "Uptime": "Üzemidő", - "UpgradeUntilThisQualityIsMetOrExceeded": "Frissítsen, amíg ez a minőség nem teljesül vagy túllépi", "UpgradeAllowedHelpText": "Ha ki van kapcsolva, a meglévő minőségűnél nem lesz jobb minőségű letöltve", - "UpdateSelected": "Kiválasztottak frissítése", "UpdateScriptPathHelpText": "Keresse meg az egyéni parancsfájl elérési útját, amely kibontott frissítési csomagot vesz fel, és kezeli a frissítési folyamat fennmaradó részét", "Updates": "Frissítések", "UpdateMechanismHelpText": "Használja a Prowlarr beépített frissítőjét vagy egy szkriptet", @@ -804,44 +528,27 @@ "UpdateCheckStartupTranslocationMessage": "Nem lehet telepíteni a frissítést, mert a (z) „{0}” indítási mappa az Alkalmazások Transzlokációs mappájában található.", "UpdateCheckStartupNotWritableMessage": "A frissítés nem telepíthető, mert a (z) „{0}” indítási mappát a „{1}” felhasználó nem írhatja.", "UpdateAutomaticallyHelpText": "A frissítések automatikus letöltése és telepítése. A Rendszer: Frissítések alkalmazásból továbbra is telepíteni tudja", - "UpdateAll": "Összes frissítése", "UnselectAll": "Minden kijelölés megszüntetése", "UnsavedChanges": "Nem mentett változások", - "Unreleased": "Kiadatlan", "UnmonitoredHelpText": "A nem felügyelt filmek is bekerülnek az iCal hírcsatornába", - "Unmonitored": "Nem felügyelt", "UnmappedFolders": "Feltérképezetlen mappák", - "Ungroup": "Csoport eltávolítása", "Unavailable": "Nem érhető el", "UnableToLoadUISettings": "Nem sikerült betölteni a felhasználói felület beállításait", - "UnableToLoadTheCalendar": "Nem sikerült betölteni a naptárat", "UnableToLoadTags": "Nem sikerült betölteni a címkéket", - "UnableToLoadRootFolders": "Nem lehet betölteni a gyökérmappákat", "UnableToLoadRestrictions": "Nem lehet betölteni a korlátozásokat", - "UnableToLoadRemotePathMappings": "Nem lehet betölteni a Távoli útvonal-hozzárendeléseket", "UnableToLoadQualityProfiles": "Nem lehet betölteni a minőségi profilokat", "UnableToLoadQualityDefinitions": "Nem lehet betölteni a minőségi meghatározásokat", - "UnableToLoadQualities": "Nem lehet betölteni a minőségeket", "UnableToLoadNotifications": "Nem sikerült betölteni az Értesítéseket", - "UnableToLoadNamingSettings": "Nem sikerült betölteni az elnevezési beállításokat", "UnableToLoadMovies": "Nem sikerült betölteni a filmeket", - "UnableToLoadMetadata": "Nem sikerült betölteni a Metaadatokat", "UnableToLoadMediaManagementSettings": "Nem sikerült betölteni a Média Kezelés beállításait", - "UnableToLoadLists": "Listák betöltése sikertelen", "UnableToLoadListOptions": "A listaopciók betöltése sikertelen", - "UnableToLoadListExclusions": "Nem lehet betölteni a listakizárásokat", "ThisConditionMatchesUsingRegularExpressions": "Ez a feltétel megfelel a Reguláris kifejezések használatának. Ne feledje, hogy a karakterek {0} különleges jelentéssel bírnak, és el kell kerülniük egy {1} karakterrel", "TableOptions": "Táblázat beállításai", - "Table": "Táblázat", "ShowSearch": "Keresés(ek) megjelenítése", - "SettingsRemotePathMappingHostHelpText": "Ugyanaz a gazdagép, amelyet a távoli letöltési klienshez megadott", "SetTags": "Címkék beállítása", - "RegularExpressionsCanBeTested": "A reguláris kifejezések tesztelhetők ", "NotificationTriggers": "Értesítés(ek) kiváltója", - "GrabRelease": "Release megragadása", "IndexerLongTermStatusCheckSingleClientMessage": "Az összes indexer elérhetetlen több mint 6 órája, meghibásodás miatt: {0}", "IndexerLongTermStatusCheckAllClientMessage": "Az összes indexer elérhetetlen több mint 6 órája, meghibásodás miatt", - "EditMovieFile": "Filmfájl szerkesztése", "ListTagsHelpText": "A címkék listájának elemei hozzá lesznek adva", "SettingsLogSql": "SQL naplózás", "IndexerRss": "Indexer Rss", @@ -861,7 +568,6 @@ "SettingsFilterSentryEvents": "Az Analytics-események szűrése", "SettingsConsoleLogLevel": "Konzol naplószint", "SearchIndexers": "Indexelők keresése", - "NewznabVipCheckExpiringClientMessage": "Az Indexer VIP előnyei hamarosan lejárnak: {0}", "NewznabVipCheckExpiredClientMessage": "Az Indexer VIP előnyei lejártak: {0}", "IndexersSelectedInterp": "{0} Indexelő(k) kiválasztva", "IndexerQuery": "Indexelő lekérdezés", diff --git a/src/NzbDrone.Core/Localization/Core/it.json b/src/NzbDrone.Core/Localization/Core/it.json index 221efa70e..3bb26e2f6 100644 --- a/src/NzbDrone.Core/Localization/Core/it.json +++ b/src/NzbDrone.Core/Localization/Core/it.json @@ -1,77 +1,51 @@ { - "RootFolderCheckSingleMessage": "Cartella radice mancante: {0}", "Wanted": "Ricercato", "View": "Guarda", - "UpdateSelected": "Aggiorna i Film Selezionati", "UnselectAll": "Deseleziona Tutto", - "Unmonitored": "Non Seguito", "UnmappedFolders": "Cartelle Non Mappate", "UISettingsSummary": "Opzioni calendario, data e visione dei colori", "TagsSettingsSummary": "Controlla tutti i tag e come vengono utilizzati. I tag non utilizzati possono essere rimossi", - "Studio": "Studio", "SourceTitle": "Titolo Sorgente", "SetTags": "Imposta Tag", "SelectAll": "Seleziona Tutto", - "SearchForMissing": "Cerca i film mancanti", "SearchSelected": "Cerca il film selezionato", - "SearchFiltered": "Cerca con Filtri", "Scheduled": "In Programma", - "Runtime": "Tempo di esecuzione", "RootFolders": "Cartelle Radice", - "RootFolderCheckMultipleMessage": "Ci sono più cartelle radice mancanti: {0}", "RootFolder": "Cartella Radice", - "RemotePathMappings": "Collegamento Percorsi Remoti", "ReleaseBranchCheckPreviousVersionMessage": "Il Branch {0} corrisponde ad una versione precedente di Prowlarr, imposta il branch su \"Nightly\" per ricevere gli aggiornamenti futuri", "ReleaseBranchCheckOfficialBranchMessage": "Il Branch {0} non è un branch valido per le release di Prowlarr, non riceverai aggiornamenti", - "QualitySettingsSummary": "Dimensioni delle qualità e denominazione", "QualityProfiles": "Profili di Qualità", - "QualityProfile": "Profilo di Qualità", "QualityDefinitions": "Definizioni delle Qualità", "PtpOldSettingsCheckMessage": "Il seguente indexer PassThePopcorn ha delle impostazioni obsolete e deve essere aggiornato: {0}", "ProxyCheckResolveIpMessage": "Impossibile risolvere l'indirizzo IP per il Proxy {0}", - "ProfilesSettingsSummary": "Qualità, Lingua e Profili di ritardo", "PhysicalRelease": "Release Fisica", - "Path": "Percorso", "OutputPath": "Percorso di Destinazione", "NoChanges": "Nessuna Modifica", "NoChange": "Nessuna Modifica", - "MovieNaming": "Nomi dei Film", "MountCheckMessage": "La destinazione contenente il percorso di un film è montata in sola lettura: ", - "MonitoredOnly": "Solo Seguiti", "Monitor": "Segui", - "MediaManagementSettingsSummary": "Impostazioni di ridenominazione e gestione file", "MassMovieSearch": "Ricerca Film Multipla", - "ListsSettingsSummary": "Liste di Importazione, esclusioni dalle liste", "ListExclusions": "Esclusioni dalle Liste", "LastWriteTime": "Orario di Ultima Scrittura", - "IndexerRssHealthCheckNoIndexers": "Non è disponibile nessun indexer con la sincronizzazione RSS attiva, Prowlarr non recupererà nuove release automaticamente", "IndexerRssHealthCheckNoAvailableIndexers": "Tutti gli indexer RSS sono momentaneamente disabilitati a causa di errori", "Indexer": "Indicizzatore", "HideAdvanced": "Nascondi Avanzate", "Health": "Salute", - "GrabSelected": "Recupera selezione", "Grabbed": "Recuperato", - "Downloaded": "Scaricato", "DotNetVersionCheckOldUnsupportedMessage": "La versione di .Net Framework {0} attualmente installata è vecchia e non più supportata. Per favore aggiorna alla versione {1} o successiva.", - "DotNetVersionCheckNotRecommendedMessage": "La versione di .Net Framework {0} attualmente installata è supportata, ma è consigliato aggiornare ad una versione {1} o successiva.", "DigitalRelease": "Release Digitale", - "DelayProfiles": "Profili di Ritardo", "Crew": "Troupe", "Clear": "Cancella", - "Certification": "Certificazione", "AppDataLocationHealthCheckMessage": "Non è possibile effettuare l'aggiornamento per evitare di cancellare AppData", "Analytics": "Statistiche", "Added": "Aggiunto", "About": "Versione", - "Year": "Anno", "Week": "Settimana", "Updates": "Aggiornamenti", "UpdateCheckUINotWritableMessage": "Impossibile installare l'aggiornamento perché l'utente '{1}' non ha i permessi di scrittura per la cartella di interfaccia '{0}'.", "UpdateCheckStartupNotWritableMessage": "Impossibile installare l'aggiornamento perché l'utente '{1}' non ha i permessi di scrittura per la cartella di avvio '{0}'.", "UpdateCheckStartupTranslocationMessage": "Impossibile installare l'aggiornamento perché la cartella '{0}' si trova in una cartella App Translocation.", - "UpdateAll": "Aggiorna Tutto", "UI": "Interfaccia", - "Titles": "Titoli", "Timeleft": "Tempo Rimanente", "Tasks": "Funzioni", "Tags": "Tag", @@ -79,95 +53,60 @@ "Style": "Stile", "Status": "Stato", "Sort": "Ordina", - "SizeOnDisk": "Dimensione su Disco", "Size": "Dimensioni", "ShowAdvanced": "Mostra Avanzate", "Settings": "Impostazioni", "Security": "Sicurezza", - "SearchAll": "Cerca Tutto", "Search": "Cerca", "SaveChanges": "Salva Modifiche", - "RSSSync": "Sync RSS", "Restrictions": "Restrizioni", "RestoreBackup": "Ripristina Backup", - "RenameFiles": "Rinomina File", "Renamed": "Rinominato", - "RemoveSelected": "Rimuovi Selezionato", "RemovedMovieCheckSingleMessage": "Il Film {0} è stato rimosso da TMDb", - "RemovedMovieCheckMultipleMessage": "I Film {0} sono stati rimossi da TMDb", "ReleaseTitle": "Titolo Release", "ReleaseStatus": "Stato Release", - "ReleaseGroup": "Gruppo Release", "RefreshAndScan": "Aggiorna e Scansiona", "Refresh": "Aggiorna", - "Ratings": "Valutazioni", "Queue": "Coda", - "Quality": "Qualità", "ProxyCheckFailedToTestMessage": "Test del proxy fallito: {0}", "ProxyCheckBadRequestMessage": "Il test del proxy è fallito. Stato: {0}", "Proxy": "Proxy", "Protocol": "Protocollo", - "Progress": "Avanzamento", "Profiles": "Profili", - "PreviewRename": "Anteprima Rinomina", "Options": "Opzioni", - "ImportListStatusCheckSingleClientMessage": "Liste non disponibili a causa di errori: {0}", "ImportListStatusCheckAllClientMessage": "Tutte le liste non sono disponibili a causa di errori", - "MovieTitle": "Titolo Film", "Movies": "Film", - "MovieIndex": "Indice Film", "MovieEditor": "Modifica Film", - "Movie": "Film", "MoreInfo": "Maggiori Info", - "Month": "Mese", "MonoTlsCheckMessage": "Il workaround per Prowlarr Mono 4.x tls è ancora disabilitato, potresti considerare di rimuovere l'opzione ambiente MONO_TLS_PROVIDER=legacy", "MonoNotNetCoreCheckMessage": "Per favore aggiorna alla versione .NET Core di Prowlarr", - "Missing": "Mancante", "MinimumAvailability": "Disponibilità Minima", - "MinAvailability": "Disponibilità Min", "MetadataSettingsSummary": "Crea file metadata quando i film vengono importati o aggiornati", - "Metadata": "Metadata", "MediaManagement": "Gestione Media", - "MediaInfoDllCheckMessage": "La libreria MediaInfo non è stata caricata {0}", "ManualImport": "Import Manuale", "Logging": "Logging", - "LogFilesLocationMessage": "I FIle di Log si trovano in:", "LogFiles": "File di Log", - "Lists": "Liste", "Languages": "Lingue", "Language": "Lingua", "IndexerStatusCheckSingleClientMessage": "Indexer non disponibili a causa di errori: {0}", "IndexerStatusCheckAllClientMessage": "Tutti gli indexer non sono disponibili a causa di errori", - "IndexersSettingsSummary": "Restrizioni per indexer e release", "IndexerSearchCheckNoInteractiveMessage": "Non è disponibile nessun indexer con abilitata la Ricerca Interattiva, Prowlarr non fornirà nessun risultato tramite la ricerca interattiva", - "IndexerSearchCheckNoAvailableIndexersMessage": "Tutti gli indexer abilitati alla ricerca sono momentaneamente non disponibili a causa di errori", "IndexerSearchCheckNoAutomaticMessage": "Non è disponibile nessun indexer con abilitata la Ricerca Automatica, Prowlarr non fornirà nessun risultato tramite la ricerca automatica", "Indexers": "Indexer", - "AndNot": "e non", "InCinemas": "Nei Cinema", - "ImportTipsMessage": "Alcuni consigli affinché l'importazione vada a buon fine:", "ImportSecondTip": "Indirizza Prowlarr alla cartella che contiene tutti i tuoi film, non a cartelle specifiche. Ad esempio:", - "ImportMechanismHealthCheckMessage": "Abilita la Gestione dei Download Completati", "ImportHeader": "Importa dei film che hai già", - "ImportFirstTip": "Assicurati che i tuoi file includano la qualità nel nome del file, ad es.", "Imported": "Importato", - "Import": "Importa", "Ignored": "Ignorato", - "iCalLink": "Link iCal", "Host": "Host", "History": "Storia", - "Genres": "Generi", "GeneralSettingsSummary": "Porta, SSL, Nome utente/password, proxy, statistiche e aggiornamenti", "General": "Generale", - "FreeSpace": "Spazio Libero", "Formats": "Formati", - "Forecast": "Previsione", "Folder": "Cartella", "Filter": "Filtro", "Filename": "Nome del File", - "Filesize": "Dimensione del File", "Files": "File", - "FileManagement": "Gestione dei File", "FailedDownloadHandling": "Gestione dei Download Falliti", "Failed": "Fallito", "EventType": "Tipo di Evento", @@ -180,65 +119,43 @@ "DownloadClientCheckUnableToCommunicateMessage": "Impossibile comunicare con {0}.", "DownloadClientCheckNoneAvailableMessage": "Non è disponibile nessun client per il download", "DownloadClient": "Client Download", - "DiskSpace": "Spazio su Disco", "Discover": "Scopri", "Details": "Dettagli", - "Deleted": "Cancellato", "Delete": "Cancella", - "Day": "Giorno", "Dates": "Date", "Date": "Data", - "CutoffUnmet": "Soglia Non Raggiunta", "CustomFormatsSettingsSummary": "Formati Personalizzati e Impostazioni", - "CustomFormats": "Formati Personalizzati", "CustomFilters": "Filtri Personalizzati", "Connect": "Collega", "Connections": "Collegamenti", "ConnectSettingsSummary": "Notifiche, collegamenti a media server/player e script personalizzati", - "CompletedDownloadHandling": "Gestione dei Download Completati", "Collection": "Collezione", - "ChooseAnotherFolder": "Scegli un'altra Cartella", "Cast": "Cast", - "Calendar": "Calendario", "Blacklist": "Lista Nera", "BackupNow": "Effettua ora il Backup", "Backup": "Backup", "All": "Tutti", - "Agenda": "Agenda", "AddNew": "Aggiungi Nuovo", - "AddExclusion": "Aggiungi Esclusione", "Actions": "Azioni", - "AddNewTmdbIdMessage": "Puoi anche cercare un film a partire dall'id TMDb. Ad esempio: tmdb:71663", "AddNewMessage": "È facile aggiungere un nuovo film, inizia a scrivere il titolo del film che vuoi aggiungere", - "AddMovies": "Aggiungi Film", "Activity": "Attività", - "AllMoviesHiddenDueToFilter": "Tutti i film sono nascosti a causa del filtro applicato.", "AgeWhenGrabbed": "Età (quando trovato)", "Age": "Età", - "AddRemotePathMapping": "Aggiungi un percorso remoto", "AddNewMovie": "Aggiungi Nuovo Film", - "AddMoviesMonitored": "Aggiungi Film Monitorato", "AddListExclusion": "Aggiungi Lista Esclusioni", - "AddList": "Aggiungi Lista", "Close": "Chiudi", "CloneProfile": "Clona il Profilo", "CloneIndexer": "Clona Indexer", - "CloneFormatTag": "Clona il Tag di formato", "ClientPriority": "Priorità del Client", - "ClickToChangeQuality": "Clicca per cambiare qualità", "ClickToChangeLanguage": "Clicca per cambiare lingua", - "CleanLibraryLevel": "Livello di pulizia della Libreria", "CheckForFinishedDownloadsInterval": "Intervallo per il controllo dei download finiti", "ChangeHasNotBeenSavedYet": "Il cambiamento non è stato ancora salvato", - "ChangeFileDate": "Cambiare la data del file", "CertificationCountryHelpText": "Seleziona il paese per le certificazioni dei film", - "CertificationCountry": "Paese di certificazione", "CertificateValidationHelpText": "Cambiare il \"grado di severità\" della convalida del certificato HTTPS", "CertificateValidation": "Convalida del certificato", "Cancel": "Cancella", "BypassProxyForLocalAddresses": "Evita il Proxy per gli indirizzi locali", "Branch": "Ramo", - "BlacklistRelease": "Release in blacklist", "BlacklistHelpText": "Impedisci a Prowlarr di acquisire automaticamente questo film", "BindAddressHelpText": "Indirizzo IPV4 valido o '*' per tutte le interfacce", "BindAddress": "Indirizzo per il collegamento", @@ -246,35 +163,24 @@ "BackupRetentionHelpText": "I backup automatici più vecchi del periodo di conservazione verranno eliminati automaticamente", "BackupIntervalHelpText": "Intervallo tra i backup automatici", "BackupFolderHelpText": "I percorsi relativi saranno sotto la directory AppData di Prowlarr", - "AvailabilityDelayHelpText": "Quantità di tempo prima o dopo la data di disponibità per la ricerca di un film", "AvailabilityDelay": "Ritardo su disponibilità", - "AutoUnmonitorPreviouslyDownloadedMoviesHelpText": "I film cancellati dal disco sono automaticamente non monitorati in Prowlarr", "AutoRedownloadFailedHelpText": "Ricerca automatica e tentativo di scaricare un'altra versione", "Automatic": "Automatico", - "AutoDownloadPropersHelpText": "Deve Prowlarr aggiornare automaticamente i \"propers\", quando disponibili?", "AuthenticationMethodHelpText": "Utilizza nome utente e password per accedere a Prowlarr", "Authentication": "Autenticazione", - "AudioInfo": "Informazioni Audio", "AsAllDayHelpText": "Gli eventi appariranno come eventi di un giorno intero nel tuo calendario", "AreYouSureYouWantToResetYourAPIKey": "Sei sicuro di voler reimpostare la tua chiave API?", - "AreYouSureYouWantToDeleteThisRemotePathMapping": "Sei sicuro di voler cancellare questa mappatura del percorso remoto?", "AreYouSureYouWantToDeleteThisImportListExclusion": "Sei sicuro di voler cancellare questa lista di esclusioni delle importazioni?", - "AreYouSureYouWantToDeleteThisDelayProfile": "Sei sicuro di voler cancellare questo profilo di ritardo?", "ApplyTags": "Applica Etichette", "Apply": "Applica", "AppDataDirectory": "Cartella AppData", "ApiKey": "Chiave API", "AnalyticsEnabledHelpText": "Inviare informazioni anonime sull'utilizzo e sugli errori ai server di Prowlarr. Ciò include informazioni sul tuo browser, come le pagine di Prowlarr che utilizzi, la segnalazione di errori e la versione del sistema operativo e del runtime. Utilizzeremo queste informazioni per dare priorità alle funzioni e alle correzioni di bug.", - "AnalyseVideoFiles": "Analizza i file video", "AlternativeTitle": "Titolo Alternativo", - "AlreadyInYourLibrary": "Già presente nella libreria", "AllowHardcodedSubsHelpText": "Se verranno rilevati sottotitoli impressi il film verrà comunque scaricato", - "AllowHardcodedSubs": "Permetti i sottotitoli hardcoded (impressi direttamente nel file)", "Warn": "Attenzione", - "VideoCodec": "Codec Video", "Unavailable": "Non disponibile", "Type": "Tipo", - "TotalSpace": "Spazio Totale", "Title": "Titolo", "Time": "Orario", "TestAll": "Prova Tutti", @@ -287,147 +193,90 @@ "Seeders": "Seeders", "Save": "Salva", "Restart": "Riavvia", - "RemoveRootFolder": "Rimuovi cartella radice", "Reload": "Ricarica", - "RelativePath": "Percorso Relativo", "Peers": "Peers", "PageSize": "Dimensione Pagina", - "OrganizeModalSuccess": "Successo! Il mio lavoro è finito, nessun file da rinominare.", "OrganizeModalNamingPattern": "Schema di Denominazione:", - "OrganizeModalDisabled": "La funzione di rinomina è disabilitata, niente da rinominare", "OrganizeModalAllPathsRelative": "Tutti i percorsi sono relativi a:", - "OrganizeAndRename": "Organizza & Rinomina", "Organize": "Organizza", "Ok": "Ok", "OAuthPopupMessage": "I Pop-ups sono bloccati dal tuo browser", "Name": "Nome", - "MoveFiles": "Sposta Files", "MonoVersionCheckUpgradeRecommendedMessage": "La versione di Mono {0} attualmente installata è supportata ma è raccomandato l'aggiornamento alla versione {1}.", - "MonoVersionCheckOldNotSupportedMessage": "La versione di Mono {0} attualmente installata è obsoleta e non supportata. Per favore procedi con l'aggiornamento di Mono alla versione {1}.", "MonoVersionCheckNotSupportedMessage": "La versione di Mono {0} attualmente installata non è più supportata. Per favore procedi con l'aggiornamento di Mono alla versione {1}.", - "Monitored": "Monitorato", "Message": "Messaggio", - "Location": "Posizione", "Level": "Livello", "KeyboardShortcuts": "Scorciatoie Tastiera", "Info": "Info", - "ImportExistingMovies": "Importa Film Esistenti", "HealthNoIssues": "La tua configurazione non presenta problemi", - "HardlinkCopyFiles": "Hardlink/Copia Files", "Extension": "Estensione", "Error": "Errore", "EnableAutoHelpText": "Se abilitato, i film saranno aggiunti automaticamente a Prowlarr da questa lista", "Enable": "Abilita", - "EditRemotePathMapping": "Modificare la mappatura dei percorsi", "EditPerson": "Modifica persona", - "EditMovie": "Modifica film", "Edition": "Edizione", - "DownloadWarningCheckDownloadClientForMoreDetails": "Problema di download: controllare il client di download per maggiori dettagli", "DownloadPropers": "Scarica Propers", - "DownloadFailedCheckDownloadClientForMoreDetails": "Download fallito: controllare il client di download per maggiori dettagli", "DownloadClientSettings": "Impostazioni del client di download", "Docker": "Docker", - "DetailedProgressBarHelpText": "Mostra testo sulla barra di progressione", "DetailedProgressBar": "Barra di avanzamento dettagliata", - "DestinationPath": "Percorso di destinazione", "DeleteTag": "Cancella Tag", - "DeleteSelectedMovieFiles": "Cancellare i film selezionati", "DeleteRestriction": "Cancellare la restrizione", - "DeleteQualityProfile": "Cancellare il profilo di qualità", "DeleteNotification": "Cancellare la notifica", - "DeleteList": "Cancellare l'elenco", "DeleteIndexer": "Cancella Indexer", - "DeleteImportListExclusion": "Cancellare la lista delle esclusioni", "DeleteFile": "Cancellare il file", - "DeleteEmptyFoldersHelpText": "Cancellare le cartelle vuote dei film durante la scansione del disco e quando i file di film vengono cancellati", "DeleteEmptyFolders": "Cancellare le cartelle vuote", "DeleteDownloadClient": "Cancellare il client di download", - "DeleteDelayProfile": "Cancellare il profilo di ritardo", "DeleteCustomFormat": "Cancellare il formato personalizzato", "DeleteBackup": "Cancellare il backup", "DelayProfile": "Profili di Ritardo", "DBMigration": "Migrazione del DataBase", - "CutoffHelpText": "Una volta raggiunta questa qualità, Prowlarr non scaricherà più film", "CutoffFormatScoreHelpText": "Una volta raggiunto questo formato personalizzato, Prowlarr non scaricherà più i film", - "CustomFormatsSettings": "Impostazioni dei formati personalizzati", "CustomFormatScore": "Punteggio del formato personalizzato", - "CreateGroup": "Crea gruppo", "CreateEmptyMovieFoldersHelpText": "Crea le cartelle dei film mancanti durante la scansione del disco", - "CreateEmptyMovieFolders": "Crea le cartelle dei film se non esistono", "CopyUsingHardlinksHelpTextWarning": "Occasionalmente, i blocchi dei file possono impedire la ridenominazione dei file in fase di seeding. È possibile disattivare temporaneamente il seeding e utilizzare la funzione di rinomina di Prowlarr per evitare il problema.", - "CopyUsingHardlinksHelpText": "Utilizzare gli Hardlink quando si cerca di copiare file da un torrent che è ancora in fase di seeding", "ConnectSettings": "Impostazioni di connessione", "ConnectionLostMessage": "Prowlarr ha perso la connessione al backend e dovrà essere ricaricato per ripristinare la funzionalità.", "ConnectionLostAutomaticMessage": "Prowlarr cercherà di connettersi automaticamente, oppure potete cliccare su ricarica qui sotto.", "ConnectionLost": "Connessione persa", - "Conditions": "Condizioni", "Component": "Componente", "Columns": "Colonne", - "ColonReplacementFormatHelpText": "Cambia il modo in cui Prowlarr gestisce la sostituzione dei due punti", "ColonReplacement": "Sostituzione due punti", - "DestinationRelativePath": "Relative Path della destinazione", "CouldNotFindResults": "Non ho trovato risultati per '{0}'", - "DelayingDownloadUntilInterp": "Ritardare il download fino al {0} a {1}", "DeleteBackupMessageText": "Sei sicuro di voler cancellare il backup '{0}'?", - "ClickToChangeMovie": "Clicca per cambiare film", "CheckDownloadClientForDetails": "controlla il client di download per maggiori dettagli", - "CantFindMovie": "Perché non riesco a trovare il film?", "CancelPendingTask": "Sei sicuro di voler cancellare questa operazione in sospeso?", "BranchUpdateMechanism": "Branch utilizzato dal sistema di aggiornamento esterno", "BranchUpdate": "Branch da utilizzare per aggiornare Prowlarr", "ApplyTagsHelpTexts2": "Aggiungi: Aggiungere i tag la lista esistente di tag", "ApplyTagsHelpTexts1": "Come applicare i tag ai film selezionati", - "AllowMovieChangeClickToChangeMovie": "Clicca per cambiare film", "AddingTag": "Aggiungi tag", - "AddImportExclusionHelpText": "Impedire che il film venga aggiunto a Prowlarr da liste", "ProwlarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "Prowlarr supporta condizioni personalizzate verso le seguenti release.", - "Prowlarr": "Prowlarr", "Proper": "Proper", - "Posters": "Locandine", "Password": "Password", - "OnRenameHelpText": "Durante la rinomina", "OnHealthIssueHelpText": "Quando c'è un problema", - "OnGrabHelpText": "Quando viene prelevato", "NotificationTriggers": "Selettori di notifica", "NetCore": ".NET", - "MinimumAgeHelpText": "Solo Usenet: Età minima in minuti di NZB prima di essere prelevati. Usalo per dare tempo alle nuove release di propagarsi al vostro provider usenet.", "Logs": "Logs", - "Links": "Collegamenti", "LastDuration": "Ultima Durata", - "ICalFeed": "iCal Feed", "Hostname": "Hostname", - "GrabRelease": "Preleva Release", "GrabID": "ID di Prelievo", - "Grab": "Preleva", "FileChmodHelpTexts2": "La stessa modalità viene applicata alle cartelle di film/sub con il bit di esecuzione aggiunto, ad esempio, 0644 diventa 0755", "MIA": "MIA", - "MediaInfo": "Info Media", "IndexerFlags": "Etichetta indexer", - "IncludeCustomFormatWhenRenamingHelpText": "Includi {Custom Formats} nel formato di rinominazione", "FileNames": "Nomi file", - "FileChmodMode": "Modalità file chmod", "ExtraFileExtensionsHelpTexts1": "Liste di file Extra da importare separate da virgola (.nfo saranno importate come .nfo-orig)", "EnableSSL": "Abilita SSL", "EnableColorImpairedModeHelpText": "Stile alterato per permettere agli utenti daltonici di distinguere meglio le informazioni con colori codificati", - "YouCanAlsoSearch": "Puoi cercare anche usando l'ID del film di TMDB o di IMDB. Per es. tmdb:71663", "CustomFormatUnknownCondition": "Condizione per il Formato personalizzato sconosciuta '{0}'", "SettingsLongDateFormat": "Formato Data Lungo", - "SettingsFirstDayOfWeek": "Primo giorno della settimana", "SettingsEnableColorImpairedMode": "Abilità la modalità colori alternati", - "SetPermissionsLinuxHelpTextWarning": "Se non sei sicuro di cosa facciano queste impostazioni, non cambiarle.", "SetPermissionsLinuxHelpText": "Eseguire chmod quando i file sono importati/rinominati?", - "SetPermissions": "Imposta permessi", "SendAnonymousUsageData": "Invia dati sull'uso anonimamente", - "SelectFolder": "Seleziona cartella", "SearchOnAddHelpText": "Cerca i film in questa lista quando aggiunti a Prowlarr", - "SearchOnAdd": "Cerca dopo aggiunta", "SearchMovie": "Trova Film", - "SearchForMovie": "Trova Film", "ScriptPath": "Percorso dello script", - "RSSSyncIntervalHelpTextWarning": "Questo verrà applicato a tutti gli indexer, segui le regole impostate da loro", "RSSSyncInterval": "Intervallo di Sync RSS", "RSSIsNotSupportedWithThisIndexer": "RSS non è supportato con questo indexer", - "RetryingDownloadInterp": "Riprovando il download {0} a {1}", "RetentionHelpText": "Solo Usenet: Imposta a zero per una conservazione illimitata", "Retention": "Memorizzazione", "Result": "Risultato", @@ -437,209 +286,129 @@ "RestartNow": "Riavvia adesso", "ResetAPIKey": "Resetta la Chiave API", "Reset": "Resetta", - "RescanMovieFolderAfterRefresh": "Riscansiona la cartella del Film dopo il refresh", "RescanAfterRefreshHelpTextWarning": "Prowlarr non identificherà in automatico i cambiamenti ai file quando non impostato a \"Sempre\"", - "RescanAfterRefreshHelpText": "Riscansiona la cartella dopo aver ricaricato il film", "RequiredPlaceHolder": "Aggiunge una nuova restrizione", - "RequiredHelpText": "Questa {0} condizione deve soddisfare il formato personalizzato per l'applicazione. Altrimenti una sola {1} corrispondenza è sufficiente.", "ReplaceIllegalCharactersHelpText": "Sostituisci i caratteri non consentiti. Se non selezionato, Prowlarr invece li rimuoverà", - "ReplaceIllegalCharacters": "Sostituisci i caratteri non consentiti", "Reorder": "Riordina", - "RenameMoviesHelpText": "Prowlarr userà i nomi dei file se rinomina è disabilitato", "RenameMovies": "Rinomina i Film", "RemovingTag": "Sto eliminando il tag", - "RemoveHelpTextWarning": "La rimozione eliminerà il download e i file dal client di download.", "RemoveFromQueue": "Rimuovi dalla coda", - "RemoveFromDownloadClient": "Rimuovi dal client di download", "RemoveFromBlacklist": "Rimuovi della blacklist", "RemoveFilter": "Rimuovi filtro", - "RemoveFailedDownloadsHelpText": "Rimuovi i download falliti dalla storia del client di download", "RemovedFromTaskQueue": "Rimuovi dalla coda di lavoro", - "RemoveCompletedDownloadsHelpText": "Rimuovi i download importati dalla storia del client di download", "Remove": "Rimuovi", - "ReleaseWillBeProcessedInterp": "La release sarà processata {0}", "ReleaseRejected": "Release rifiutata", - "ReleaseDates": "Date di rilascio", "RejectionCount": "Rifiuta il conteggio", - "RegularExpressionsCanBeTested": "Le espressioni regolari possono essere testate ", "RefreshMovie": "Aggiorna il Film", - "RefreshInformationAndScanDisk": "Aggiorna le informazioni e scansiona il disco", "Redownload": "Riscarica", - "RecyclingBinCleanup": "Pulizia del cestino", "RecyclingBin": "Cestino", - "RecycleBinHelpText": "I file dei film andranno qui quando cancellati invece che venire eliminati definitivamente", "RecycleBinCleanupDaysHelpTextWarning": "I file nel cestino più vecchi del numero selezionato di giorni saranno eliminati automaticamente", - "RecycleBinCleanupDaysHelpText": "Imposta a 0 per disabilitare la pulizia automatica", "RecentFolders": "Cartelle recenti", - "Reason": "Ragione", "Real": "Reale", "ReadTheWikiForMoreInformation": "Leggi le Wiki per maggiori informazioni", "ProwlarrSupportsAnyIndexer": "Prowlarr supporta qualunque indexer che usi gli standard Newznab, cosi come gli altri Indexer sotto.", - "ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "Prowlarr supporta qualunque Lista di film RSS, cosi come le altre sotto.", "ProwlarrSupportsAnyDownloadClient": "Prowlarr supporta qualunque client di download che usi gli standard Newznab, cosi come gli altri client sotto.", - "QuickImport": "Importazione veloce", "Queued": "Messo in coda", "QualitySettings": "Impostazione di Qualità", - "QualityProfileDeleteConfirm": "Sicuro di voler cancellare il profilo di qualità {0}", "QualityCutoffHasNotBeenMet": "Il qualità di taglio non è stata raggiunta", - "PublishedDate": "Data di pubblicazione", "ProxyUsernameHelpText": "Devi inserire nome utente e password solo se richiesto. Altrimenti lascia vuoto.", "ProxyType": "Tipo di proxy", "ProxyPasswordHelpText": "Devi inserire nome utente e password solo se richiesto. Altrimenti lascia vuoto.", "ProxyBypassFilterHelpText": "Usa ',' come separatore, e '*.' come jolly per i sottodomini", - "ProtocolHelpText": "Scegli che protocollo(i) usare e quale è preferito quando si deve scegliere tra release altrimenti uguali", "PriorityHelpText": "Dai priorità ai client di download multipli. Round-Robin è usato per i client con la stessa priorità.", "PreferredSize": "Dimensione preferita", - "PreferIndexerFlagsHelpText": "Dai priorità alle release con etichette speciali", "PreferIndexerFlags": "Etichetta dell'indexer preferita", - "PosterSize": "Dimensione del poster", "PosterOptions": "Opzioni dei poster", "PortNumber": "Numero di porta", "Port": "Porta", - "Permissions": "Permessi", "PendingChangesStayReview": "Rimani e rivedi modifiche", "PendingChangesMessage": "Hai cambiamenti non salvati, sicuro di voler abbandonare la pagina?", "PendingChangesDiscardChanges": "Abbandona le modifiche ed esci", "Pending": "In sospeso", - "Paused": "Pausa", "PageSizeHelpText": "Numero di voci da mostrare in ogni pagina", "PackageVersion": "Versione del pacchetto", - "OverviewOptions": "Opzioni panoramiche", "Overview": "Panoramica", - "Original": "Originale", "OpenBrowserOnStart": "Apri il browser all'avvio", - "OnUpgradeHelpText": "Notifica quando i film sono aggiornati ad una qualità migliore", "OnDownloadHelpText": "Notifica quando i film sono stati importati con successo", - "OnDeleteHelpText": "In cancellazione", "NoUpdatesAreAvailable": "Nessun aggiornamento disponibile", - "NotMonitored": "Non monitorato", "NotAvailable": "Non disponibile", "NoTagsHaveBeenAddedYet": "Nessun tag è ancora stato aggiunto", "NoMinimumForAnyRuntime": "Nessuna durata minima", "NoLogFiles": "Nessun file di log", "NoLimitForAnyRuntime": "Nessun limite di durata", "NoLeaveIt": "No, lascialo", - "NoHistory": "Nessuna Storia", "NoBackupsAreAvailable": "Nessun Backup disponibile", "New": "Nuovo", - "NegateHelpText": "Se selezionato, il formato personalizzato non verrà applicato a questa {0} condizione.", "NamingSettings": "Impostazioni di denominazione", - "MustNotContain": "Non deve contenere", "MustContain": "Deve contenere", - "MovieYearHelpText": "Anno del film da escludere", "MovieYear": "Anno del film", - "MovieTitleHelpText": "Titolo del Film da escludere (può essere qualunque cosa significativa)", "MoviesSelectedInterp": "{0} Film selezionato(i)", - "MovieIsUnmonitored": "Il film è non monitorato", "MovieIsOnImportExclusionList": "Il Film è nella lista di esclusione dell'importazione", - "MovieIsMonitored": "Il film è monitorato", "MovieIsDownloadingInterp": "Film in download - {0}% {1}", - "MovieIsDownloading": "Film in Download", "MovieInfoLanguageHelpTextWarning": "Richiede il reload del Browser", - "MovieInfoLanguageHelpText": "Lingua che Prowlarr userà per le info del Film nella UI", "MovieInfoLanguage": "Lingua delle info del film", - "MovieID": "ID del Film", "MovieFolderFormat": "Formato della cartella del film", - "MovieFiles": "File del Film", "MovieExcludedFromAutomaticAdd": "Film escluso dall'aggiunta automatica", - "MovieAvailableButMissing": "Film disponibile, ma Mancante", "MovieAlreadyExcluded": "Film già escluso", - "MoreDetails": "Più dettagli", "MonoVersion": "Versione Mono", - "MonitorMovie": "Monitora Film", "MonitoredHelpText": "Scarica film se disponibile", "Mode": "Modo", - "MissingNotMonitored": "Mancante, non Monitorato", "MissingMonitoredAndConsideredAvailable": "Mancante, Monitorato e considerato disponibile", "MinutesSixty": "60 Minuti: {0}", "MinutesNinety": "90 Minuti: {0}", "MinutesHundredTwenty": "120 Minuti: {0}", "MinimumLimits": "Limiti minimi", - "MinimumFreeSpaceWhenImportingHelpText": "Previeni l'importazione se resterebbe uno spazio libero inferiore a questo", "MinimumFreeSpace": "Spazio libero minimo", - "MinimumAge": "Età minima", "MinFormatScoreHelpText": "Punteggio minimo del formato personalizzato abilitato al download", - "MetadataSettings": "Impostazioni Metadati", "MediaManagementSettings": "Impostazione gestione Media", "Mechanism": "Meccanismo", - "MaximumSizeHelpText": "La dimensione massima in MB di una release affinchè sia presa, imposta zero per illimitata", "MaximumSize": "Dimensione massima", "MaximumLimits": "Limiti massimi", - "MarkAsFailedMessageText": "Sei sicuro di voler segnare '{0}' come fallito?", "MarkAsFailed": "Segna come fallito", "Manual": "Manuale", "MaintenanceRelease": "Release di Manutenzione", "LogLevelTraceHelpTextWarning": "Il Trace Log dovrebbe essere abilitato solo temporaneamente", "LogLevel": "Livello di Log", - "Local": "Locale", "LoadingMovieFilesFailed": "Caricamento dei file del Film fallito", - "LoadingMovieExtraFilesFailed": "Caricamento degli Extra del Film fallito", "LoadingMovieCreditsFailed": "Caricamento dei crediti del film fallito", - "ListUpdateInterval": "Intervallo di aggiornamento lista", "ListSyncLevelHelpText": "I Film nella libreria saranno rimossi o non monitorati se non presenti nella tua lista", - "ListSettings": "Impostazioni delle Lsite", "LinkHere": "qui", "LaunchBrowserHelpText": " Apri un browser e vai all'homepage di Prowlarr all'avvio dell'app.", - "LanguageHelpText": "Lingua dell'uscita", "Interval": "Intervallo", - "InteractiveImport": "Importazione interattiva", "IndexerSettings": "Impostazioni dell'Indexer", - "IncludeUnmonitored": "Includi non Monitorati", "IncludeUnknownMovieItemsHelpText": "Mostra le voci senza un film nella coda. Ciò potrebbe include film spostati o altro nelle categorie di Prowlarr", - "IncludeRecommendationsHelpText": "Includi le raccomandazioni di Prowlarr nella vista scoperta", "IncludeProwlarrRecommendations": "Includi le raccomandazioni di Prowlarr", "IncludeHealthWarningsHelpText": "Includi gli avvisi di salute", - "IncludeCustomFormatWhenRenaming": "Includi formati personalizzati quando rinomini", "ImportMovies": "Importa Film", - "ImportListSyncIntervalHelpText": "Quanto spesso Prowlarr sincronizza le tue liste.", "Importing": "Importazione", - "ImportFailedInterp": "Importazione fallita: {0}", "ImportFailed": "Importazione fallita: {0}", - "ImportExtraFilesHelpText": "Importa file Extra corrispondenti (sottotitoli, nfo, ecc) dopo aver importato un film", "ImportExtraFiles": "Importa file Extra", - "ImportedTo": "Importato verso", "ImportCustomFormat": "Importa formati personalizzati", "IllRestartLater": "Riavvierò più tardi", - "IgnoredPlaceHolder": "Aggiungi una nuova restrizione", "IgnoredHelpText": "Questa release sarà respinta se contiene uno o più di questi termini (Sensibile al maiuscolo)", - "IgnoreDeletedMovies": "Ignora i film cancellati", "IgnoredAddresses": "Indirizzi ignorati", - "IconForCutoffUnmet": "L'icona per il taglio non è soddisfatta", "ICalHttpUrlHelpText": "Copia questo URL sul tuo client o clicca per sottoscrivere se il tuo browser supporta Webcal", "HiddenClickToShow": "Nascosto, premi per mostrare", - "HelpText": "Intervallo in minuti. Imposta zero per disabilitarlo (ciò fermerà il recupero automatico di tutte le release)", "HaveNotAddedMovies": "Non hai ancora aggiunto nessun film, vuoi prima importarne alcuni o tutti i tuoi film?", - "Group": "Gruppo", "GrabReleaseMessageText": "Prowlarr non è stato in grado di determinare a quale film si riferisce questa release. Prowlarr potrebbe non essere in grado di importarla automaticamente. Vuoi catturare '{0}'?", - "GoToInterp": "Vai a {0}", "Global": "Globale", "GeneralSettings": "Impostazioni Generali", - "ForMoreInformationOnTheIndividualIndexers": "Per maggiori informazioni sui singoli Indexer clicca sul pulsante info.", "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Per maggiori informazioni sulle singole liste di importazione clicca sul pulsante info.", "ForMoreInformationOnTheIndividualDownloadClients": "Per maggiori informazioni sui singoli client di download clicca sul pulsante info.", - "FollowPerson": "Segui Persona", "Folders": "Cartelle", "Fixed": "Fissato", - "FirstDayOfWeek": "Primo giorno della settimana", "FailedLoadingSearchResults": "Caricamento dei risultati della ricerca fallito, prova ancora.", - "ExportCustomFormat": "Esporta formato personalizzato", "ExistingMovies": "Film esistente(i)", - "Excluded": "Escluso", "ErrorLoadingPreviews": "Errore nel caricare le anteprime", - "Ended": "Finito", "EnableInteractiveSearchHelpTextWarning": "La ricerca non è supportata dal questo indexer", "FilterPlaceHolder": "Cerca Films", - "FileDateHelpText": "Modifica la data dei file in importazione/rescan", "FileChmodHelpTexts1": "Octal, applicato a file media quando sono importati/rinominati da Prowlarr", - "ExtraFileExtensionsHelpTexts2": "Esempi: '.sub, .nfo' or 'sub,nfo'", "ExistingTag": "Tag esistente", - "ExcludeMovie": "Escludi Film", "Exception": "Eccezione", "ErrorLoadingContents": "Errore nel caricare i contenuti", "EnableSslHelpText": " Richiede il riavvio come amministratore per avere effetto", "EnableMediaInfoHelpText": "Estrai le informazioni video tipo risoluzione, durata, codec dai file. Questo richiede che Prowlarr legga delle parti di file, ciò potrebbe causare un alto utilizzo del disco e della rete durante le scansioni.", "EnableInteractiveSearchHelpText": "Verrà usato quando la ricerca interattiva sarà utilizzata", - "EnableRSS": "Abilita RSS", "EnableInteractiveSearch": "Abilita la ricerca interattiva", "EnableHelpText": "Abilita la creazione del file di metadati per questo tipo di metadati", "EnabledHelpText": "Abilita questa lista per essere usata in Prowlarr", @@ -649,166 +418,107 @@ "EnableAutomaticSearchHelpText": "Sarà usata quando la ricerca automatica è eseguita dalla UI o da Prowlarr", "EnableAutomaticSearch": "Attiva la ricerca automatica", "EnableAutomaticAdd": "Attiva l'aggiunta automatica", - "DownloadWarning": "Avviso di download: {0}", "Downloading": "Scaricando", - "DownloadFailedInterp": "Download fallito: {0}", "DownloadFailed": "Download fallito", - "DownloadedButNotMonitored": "Scaricato, ma non monitorato", "DownloadedAndMonitored": "Scaricato e Monitorato", "DownloadClientUnavailable": "Il client di download non è disponibile", "DeleteTagMessageText": "Sei sicuro di voler eliminare il tag '{0}'?", - "DeleteSelectedMovieFilesMessage": "Sei sicuro di voler eliminare i file del film selezionato?", "DeleteRestrictionHelpText": "Sei sicuro di voler eliminare questa limitazione?", "DeleteNotificationMessageText": "Sei sicuro di voler eliminare la notifica '{0}'?", - "DeleteListMessageText": "Sei sicuro di voler eliminare la lista '{0}'?", "DeleteIndexerMessageText": "Sei sicuro di voler eliminare l'indexer '{0}'?", "DeleteDownloadClientMessageText": "Sei sicuro di voler eliminare il client di download '{0}'?", - "Cutoff": "Taglio", "CustomFormatUnknownConditionOption": "Opzione sconosciuta '{0}' per la condizione '{1}'", - "CustomFormatJSON": "Formato JSON personalizzato", "BeforeUpdate": "Prima di aggiornare", "ApplyTagsHelpTexts4": "Sostituire: sostituisci le tag con le tag inserite (non inserire nessuna tag per pulirle tutte)", "ApplyTagsHelpTexts3": "Rimuovere: rimuovi le tag inserite", "Usenet": "Usenet", "Uptime": "Tempo di attività", "YesCancel": "Si, annulla", - "WhitelistedSubtitleTags": "Tag dei sottotitoli nella whitelist", "WhitelistedHardcodedSubsHelpText": "I tag dei sottotitoli impostati qui non saranno considerati incorporati", - "WeekColumnHeader": "Intestazione colonna settimana", "WaitingToProcess": "In attesa di processo", - "WaitingToImport": "In attesa di importazione", "VisitGithubCustomFormatsAphrodite": "Visita Github per maggiori dettagli: ", "Version": "Versione", "Username": "Nome utente", "UseProxy": "Usa Proxy", - "UsenetDelayHelpText": "Minuti di attesa prima di prendere una release da Usenet", "UsenetDelay": "Ritardo della Usenet", - "UseHardlinksInsteadOfCopy": "Usa Hardlink invece che copiare", "UrlBaseHelpText": "Per il supporto al reverse proxy, di default è vuoto", "URLBase": "URL di Base", - "UpgradeUntilThisQualityIsMetOrExceeded": "Aggiorna finchè questa qualità non è raggiunta o superata", "UpgradeAllowedHelpText": "Se disabilitato la qualità non verrà incrementata", "UpdateScriptPathHelpText": "Percorso verso uno script che prende un pacchetto di aggiornamento estratto e gestisce il resto del processo di aggiornamento", "UpdateMechanismHelpText": "Usa il programma di aggiornamento incorporato in Prowlarr o uno script", "UpdateAutomaticallyHelpText": "Download e installazione automatica degli aggiornamenti. Sarai comunque in grado in installarli dal menu Sistema: Aggiornamenti", "UnsavedChanges": "Modifiche non salvate", - "UnmonitoredHelpText": "Includi i film non monitorati nei feed di iCal", "Unreleased": "Inedito", - "Ungroup": "Separa", "UnableToLoadUISettings": "Non riesco a caricare le impostazioni della UI", - "UnableToLoadTheCalendar": "Non riesco a caricare il calendario", "UnableToLoadTags": "Non riesco a caricare i tag", - "UnableToLoadRootFolders": "Non riesco a caricare la cartella root", "UnableToLoadRestrictions": "Non riesco a caricare le restrizioni", - "UnableToLoadRemotePathMappings": "Non riesco a caricare le mappature del percorso remoto", "UnableToLoadQualityProfiles": "Non riesco a caricare i profili della qualità", "UnableToLoadQualityDefinitions": "Non riesco a caricare le definizioni della qualità", - "UnableToLoadQualities": "Non riesco a caricare le qualità", "UnableToLoadNotifications": "Non riesco a caricare le notifiche", - "UnableToLoadNamingSettings": "Non riesco a caricare le impostazioni di denominazione", "UnableToLoadMovies": "Non riesco a caricare i film", - "UnableToLoadMetadata": "Non riesco a caricare i metadati", "UnableToLoadMediaManagementSettings": "Non riesco a caricare le impostazioni di Gestione dei Media", - "UnableToLoadLists": "Non riesco a caricare le liste", "UnableToLoadListOptions": "Non riesco a caricare le opzione delle liste", - "UnableToLoadListExclusions": "Non riesco a caricare le liste di esclusione", "UnableToLoadLanguages": "Non riesco a caricare le lingue", "UnableToLoadIndexers": "Non riesco a caricare l'indexer", - "UnableToLoadIndexerOptions": "Non riesco a caricare le opzioni dell'indexer", "UnableToLoadHistory": "Non riesco a caricare la storia", "UnableToLoadGeneralSettings": "Non riesco a caricare le impostazioni generali", "UnableToLoadDownloadClients": "Non riesco a caricare i client di download", - "UnableToLoadDownloadClientOptions": "Non riesco a caricare le opzioni del client di download", "UnableToLoadDelayProfiles": "Non riesco a caricare i profili di ritardo", - "UnableToLoadCustomFormats": "Non riesco a caricare i formati personalizzati", "UnableToLoadBackups": "Non riesco a caricare i backup", - "UnableToAddANewRemotePathMappingPleaseTryAgain": "Non riesco ad aggiungere la mappatura di un nuovo percorso remoto, riprova.", "UnableToAddANewQualityProfilePleaseTryAgain": "Non riesco ad aggiungere un nuovo profilo di qualità, riprova.", "UnableToAddANewNotificationPleaseTryAgain": "Non riesco ad aggiungere una nuova notifica, riprova.", - "UnableToAddANewListPleaseTryAgain": "Non riesco ad aggiungere una nuova lista, riprova.", "UnableToAddANewListExclusionPleaseTryAgain": "Non riesco ad aggiungere una nuova lista di esclusione, riprova.", "UnableToAddANewIndexerPleaseTryAgain": "Non riesco ad aggiungere un nuovo indexer, riprova.", "UnableToAddANewDownloadClientPleaseTryAgain": "Non riesco ad aggiungere un nuovo client di download, riprova.", - "UnableToAddANewCustomFormatPleaseTryAgain": "Non riesco ad aggiungere un nuovo formato personalizzato, riprova.", "UnableToAddANewConditionPleaseTryAgain": "Non riesco ad aggiungere una nuova condizione, riprova.", - "UnableToLoadBlacklist": "Non riesco a caricare la BlackList", "UISettings": "Impostazioni UI", "UILanguageHelpTextWarning": "E' richiesto il reload del browser", "UILanguageHelpText": "Lingua che Prowlarr userà per la UI", "UILanguage": "Lingua della UI", - "TotalFileSize": "Dimensione totale dei file", "Torrents": "Torrent", - "TorrentDelayHelpText": "Ritardo in minuti da aspettare prima di prendere un torrent", "TorrentDelay": "Ritardo del torrent", - "TmdbIdHelpText": "Id di TMDb del film da escludere", "TMDBId": "ID di TMDb", - "TimeFormat": "Formato orario", "ThisConditionMatchesUsingRegularExpressions": "Questa condizione si applica usando espressione regolari. Nota che i caratteri {0} hanno significati speciali e devono essere evitati con un {1}", - "TestAllLists": "Testa tutte le liste", "TestAllIndexers": "Testa tutti gli indexer", "TestAllClients": "Testa tutti i client", "TagsHelpText": "Si applica ai film con almeno un tag corrispondente", "TagIsNotUsedAndCanBeDeleted": "Il tag non è usato e può essere eliminato", "TagCannotBeDeletedWhileInUse": "Non può essere cancellato mentre è in uso", - "Table": "Tavola", "SuggestTranslationChange": "Richiedi cambio di traduzione", - "SubfolderWillBeCreatedAutomaticallyInterp": "La sottocartella '{0}' verrà creata automaticamente", "StartupDirectory": "Cartella di avvio", "StartTypingOrSelectAPathBelow": "Comincia a digitare o seleziona un percorso sotto", - "StandardMovieFormat": "Formato Film Standard", "SSLPort": "Porta SSL", "SSLCertPathHelpText": "Percorso file pfx", "SSLCertPath": "Percorso Cert SSL", "SSLCertPasswordHelpText": "Password del file pfx", "SSLCertPassword": "Password Cert SSL", - "SourceRelativePath": "Percorso relativo origine", "SourcePath": "Percorso origine", - "SorryThatMovieCannotBeFound": "Mi spiace, impossibile trovare il film.", "SkipFreeSpaceCheckWhenImportingHelpText": "Usa quando Prowlarr non è in grado di determinare lo spazio libero della cartella di root dei film", - "SkipFreeSpaceCheck": "Salta controllo spazio libero", "ShowYear": "Mostra anno", - "ShowUnknownMovieItems": "Mostra film sconosciuti", "ShowTitleHelpText": "Mostra il titolo del film sotto il poster", - "ShowTitle": "Mostra Titolo", "ShowStudio": "Mostra Studio", - "ShowSizeOnDisk": "Mostra spazio su disco", "ShowSearchHelpText": "Mostra pulsante ricerca al passaggio", "ShowSearch": "Mostra ricerca", - "ShowRatings": "Mostra votazione", "ShowQualityProfileHelpText": "Mostra profilo qualità sotto il poster", - "ShowQualityProfile": "Mostra Profilo Qualità", "ShowPath": "Mostra percorso", "ShownClickToHide": "Visibile, clicca per nascondere", - "ShowMovieInformationHelpText": "Mostra genere e certificazione del Film", "ShowMovieInformation": "Mostra le info del Film", - "ShowMonitoredHelpText": "Mostra lo stato Monitorato sotto il poster", "ShowMonitored": "Mostra i monitorati", - "ShowGenres": "Mostra generi", "ShowDateAdded": "Mostra data di aggiunta", - "ShowCutoffUnmetIconHelpText": "Mostra l'icona dei file quando il taglio non è stato raggiunto", "ShowCertification": "Mostra certificato", - "ShowAsAllDayEvents": "Mostra come eventi di tutta la giornata", "ShouldMonitorHelpText": "Se abilitato, i film aggiunti da questa lista sono aggiunti e monitorati", - "SettingsWeekColumnHeaderHelpText": "Mostra sopra ogni colonna quando la settimana è la vista attiva", "SettingsWeekColumnHeader": "Intestazione colonna settimana", "SettingsTimeFormat": "Formato orario", "SettingsShowRelativeDatesHelpText": "Mostra date relative (Oggi/Ieri/ecc) o assolute", "SettingsShowRelativeDates": "Mostra date relative", "SettingsShortDateFormat": "Formato Data Corto", - "SettingsRuntimeFormat": "Formato Durata", "SettingsRemotePathMappingRemotePathHelpText": "Percorso root alla cartella a cui accede il client di download", - "SettingsRemotePathMappingRemotePath": "Percorso remoto", "SettingsRemotePathMappingLocalPathHelpText": "Percorso che Prowlarr dovrebbe usare per accedere localmente al percorso remoto", - "SettingsRemotePathMappingLocalPath": "Percorso locale", "SettingsRemotePathMappingHostHelpText": "Lo stesso host specificato per il client di download remoto", "SettingsEnableColorImpairedModeHelpText": "Stile alterato per permettere agli utenti daltonici di distinguere meglio le informazioni con colori codificati", - "ProwlarrTags": "Tag di Prowlarr", "DownloadPropersAndRepacksHelpTextWarning": "Usa le parole preferite per aggiornare automaticamente a proper/repack", - "DownloadPropersAndRepacksHelpText2": "Usa \"Preferisco di no\" per ordinare i punteggi della parola preferita più di proper/repack", "DownloadPropersAndRepacksHelpText1": "Aggiornare o meno automaticamente a Proper/Repack", - "DownloadPropersAndRepacks": "Propers e Repack", "CopyToClipboard": "Copia negli appunti", - "CloneCustomFormat": "Duplica i formati personalizzati", "Priority": "Priorità", "InteractiveSearch": "Ricerca interattiva", "IndexerPriorityHelpText": "Priorità dell'indexer da 1 (più alto) a 50 (più basso). Default: 25.", @@ -825,29 +535,18 @@ "MovieDetailsPreviousMovie": "Dettagli del film: film precedente", "FocusSearchBox": "Attiva casella di ricerca", "CloseCurrentModal": "Chiudi la modalità corrente", - "Blacklisted": "Nella Blacklist", "AcceptConfirmationModal": "Accetta modalità di conferma", - "StartSearchForMissingMovie": "Avvia ricerca film mancanti", "StartProcessing": "Avvia Lavorazione", - "StartImport": "Avvia Importazione", "SearchFailedPleaseTryAgainLater": "Ricerca fallita, provare più tardi.", - "RequiredRestrictionPlaceHolder": "Il rilascio deve contenere almeno uno di questi termini (case insensitive)", "Released": "Rilasciato", - "ProcessingFolders": "Elaborazione cartelle", "NoMatchFound": "Nessuna corrispondenza trovata!", - "ImportRootPath": "Punta Prowlarr alla cartella contenente tutti i tuoi film, non ad una specifica. Es. {0} e non {1}", "ImportIncludeQuality": "Assicurati che i tuoi file includano la qualità nel nome. Es. {0}", - "ImportErrors": "Importa Errori", "Existing": "Esistente", - "EditRestriction": "Edita Limitazioni", "Digital": "Digitale", - "CancelProcessing": "Annulla lavoro", "AddRestriction": "Aggiungi Limitazioni", - "AddMovie": "Aggiungi FIlm", "ListTagsHelpText": "Gli elementi dell'elenco dei tag saranno aggiunti con", "IndexerLongTermStatusCheckSingleClientMessage": "Alcuni indexer non disponibili da più di 6 ore a causa di errori: {0}", "IndexerLongTermStatusCheckAllClientMessage": "Nessun indexer è disponibile da più di 6 ore a causa di errori", - "EditMovieFile": "Edita File del Film", "PrioritySettings": "Priorità", "Description": "Descrizione", "Add": "Aggiungi", diff --git a/src/NzbDrone.Core/Localization/Core/nl.json b/src/NzbDrone.Core/Localization/Core/nl.json index f5e7cb43f..0c41c8945 100644 --- a/src/NzbDrone.Core/Localization/Core/nl.json +++ b/src/NzbDrone.Core/Localization/Core/nl.json @@ -1,78 +1,51 @@ { - "IndexerSearchCheckNoAvailableIndexersMessage": "Alle indexeerders met zoekcapaciteit zijn tijdelijk onbeschikbaar wegens recente fouten", "IndexerSearchCheckNoAutomaticMessage": "Geen indexeerders beschikbaar met \"Automatisch Zoeken\" ingeschakeld, Prowlarr zal geen automatische zoekopdrachten uitvoeren", "Indexers": "Indexeerders", - "IndexerRssHealthCheckNoIndexers": "Geen indexeerders beschikbaar met \"RSS Synchronisatie\" ingeschakeld, Prowlarr zal niet automatisch nieuwe uitgaves ophalen", "IndexerRssHealthCheckNoAvailableIndexers": "Alle RSS-capabele indexeerders zijn tijdelijk onbeschikbaar wegens recente fouten", - "ImportTipsMessage": "Enkele tips om het importeren soepel te laten verlopen:", "ImportSecondTip": "Wijs Prowlarr naar de map die al je films bevat, niet naar een map met slechts één specifieke film. Bijv.", - "ImportMechanismHealthCheckMessage": "Activeer Voltooide Download Afhandeling", "Week": "Week", - "ImportHeader": "Importeer films die je al hebt", "ImportFirstTip": "Zorg ervoor dat je bestanden de kwaliteit in hun bestandsnaam bevatten. Bijv.", - "Import": "Importeer", "iCalLink": "iCal Koppeling", "Host": "Host", "History": "Geschiedenis", "HideAdvanced": "Verberg Gevorderd", "Health": "Gezondheid", - "GrabSelected": "Selectie Ophalen", "General": "Algemeen", - "FreeSpace": "Vrije Ruimte", "Formats": "Formaten", - "Forecast": "Verwachting", "Folder": "Map", "Filter": "Filter", - "Filesize": "Bestandsgrootte", "Files": "Bestanden", - "FileManagement": "Bestandsbeheer", "FailedDownloadHandling": "Mislukte Download Afhandeling", "Events": "Gebeurtenissen", "Edit": "Bewerk", - "Downloaded": "Gedownload", "DownloadClientStatusCheckSingleClientMessage": "Downloaders onbeschikbaar wegens fouten: {0}", "DownloadClientStatusCheckAllClientMessage": "Alle downloaders zijn onbeschikbaar wegens fouten", "DownloadClients": "Downloaders", "DownloadClientCheckUnableToCommunicateMessage": "Niet in staat om te communiceren met {0}.", "DownloadClientCheckNoneAvailableMessage": "Er is geen downloader beschikbaar", - "DotNetVersionCheckOldUnsupportedMessage": "Het huidige geïnstalleerde .NET Framework {0} is verouderd en wordt niet langer ondersteund. Gelieve het .NET Framework te opwaarderen naar minstens {1}.", "DotNetVersionCheckNotRecommendedMessage": "Het momenteel geïnstalleerde .NET Framework {0} wordt ondersteund, maar we raden aan om te opwaarderen naar minstens {1}.", - "DiskSpace": "Schijfruimte", "Discover": "Ontdekken", "Delete": "Verwijderen", - "DelayProfiles": "Vertragingsprofielen", "Day": "Dag", "Dates": "Datum en tijd", "Date": "Datum", - "CustomFormats": "Eigen Formaten", "CustomFilters": "Aangepaste Filters", - "Crew": "Filmploeg", "Connections": "Connecties", "Connect": "Meldingen", - "CompletedDownloadHandling": "Voltooide Download Afhandeling", "Clear": "Wissen", - "ChooseAnotherFolder": "Kies een andere map", "Cast": "Acteurs", - "Calendar": "Kalender", "Blacklist": "Zwarte lijst", "BackupNow": "Veiligheidskopie Maken", - "Agenda": "Agenda", "Analytics": "Statistieken", "Backup": "Veiligheidskopie", "AppDataLocationHealthCheckMessage": "Bijwerken zal niet mogelijk zijn om het verwijderen van AppData te voorkomen", - "AndNot": "en niet", "All": "Alles", - "AddNewTmdbIdMessage": "Je kunt ook zoeken met het TMDb id van een film. Bijv. tmdb:71663", "AddNewMessage": "Het is gemakkelijk om een nieuwe film toe te voegen, begin gewoon met de naam te typen van de film die je wilt toevoegen", - "AddNew": "Toevoegen", "AddExclusion": "Uitzondering(en) Toevoegen", - "AddMovies": "Film(s) Toevoegen", "Activity": "Activiteit", "About": "Over", "View": "Weergave", - "UpdateAll": "Alles Bijwerken", "UnselectAll": "Alles Deselecteren", - "Unmonitored": "Onbewaakt", "Titles": "Titels", "Tasks": "Taken", "System": "Systeem", @@ -82,60 +55,40 @@ "Settings": "Instellingen", "SelectAll": "Alles Selecteren", "Security": "Beveiliging", - "SearchSelected": "Selectie Zoeken", "SearchForMissing": "Ontbrekende Zoeken", - "SearchFiltered": "Gefilterde Zoeken", "SearchAll": "Alles Zoeken", "Search": "Zoeken", "Scheduled": "Gepland", "SaveChanges": "Wijzigingen Opslaan", "Restrictions": "Restricties", "RestoreBackup": "Veiligheidskopie Herstellen", - "RenameFiles": "Hernoem Bestanden", "RemoveSelected": "Selectie Verwijderen", - "RefreshAndScan": "Vernieuw & Scan", "Refresh": "Vernieuw", "Queue": "Wachtrij", - "QualityProfiles": "Kwaliteitsprofielen", "QualityProfile": "Kwaliteitsprofiel", "QualityDefinitions": "Kwaliteitsdefinities", - "Quality": "Kwaliteit", "Proxy": "Proxy", - "Profiles": "Profielen", "PreviewRename": "Voorbeeldweergave Naamswijziging", - "Path": "Pad", "Options": "Opties", "NoChanges": "Geen Wijzigingen", "NoChange": "Geen Wijziging", - "ImportListStatusCheckSingleClientMessage": "Lijsten onbeschikbaar wegens fouten: {0}", "ImportListStatusCheckAllClientMessage": "Alle lijsten zijn onbeschikbaar wegens fouten", "Movies": "Films", - "MovieNaming": "Naamgeving", "MovieIndex": "Film Overzicht", - "MovieEditor": "Film Bewerker", "Movie": "Film", "MoreInfo": "Meer Info", - "Month": "Maand", "MonoNotNetCoreCheckMessage": "Gelieve te opwaarderen naar de .NET Core versie van Prowlarr", - "Monitor": "Bewaak", "Missing": "Ontbrekend", - "MinimumAvailability": "Minimale Beschikbaarheid", "MinAvailability": "Min Beschikbaarheid", - "Metadata": "Metadata", "MediaManagement": "Mediabeheer", - "MediaInfoDllCheckMessage": "MediaInfo Bibliotheek kon niet worden geladen {0}", "ManualImport": "Manuele Import", "Logging": "Logbeheer", - "LogFilesLocationMessage": "Logbestanden bevinden zich in:", "LogFiles": "Logbestanden", - "Lists": "Lijsten", "ListExclusions": "Uitzonderingenlijst", "Languages": "Talen", "Language": "Taal", "ShowAdvanced": "Toon Gevorderd", - "RootFolderCheckSingleMessage": "Ontbrekende hoofdmap: {0}", "RSSSync": "RSS Sync.", - "IndexerSearchCheckNoInteractiveMessage": "Geen indexeerders beschikbaar met \"Interactief Zoeken\" ingeschakeld, Prowlarr zal geen interactieve zoekopdrachten uitvoeren", "UpdateCheckUINotWritableMessage": "Kan de update niet installeren omdat de UI map '{0}' niet schrijfbaar is voor de gebruiker '{1}'.", "UpdateCheckStartupTranslocationMessage": "Kan de update niet installeren omdat de map '{0}' zich in een 'App Translocation' map bevindt.", "UpdateCheckStartupNotWritableMessage": "Kan de update niet installeren omdat de map '{0}' niet schrijfbaar is voor de gebruiker '{1}'.", @@ -144,81 +97,51 @@ "IndexerStatusCheckSingleClientMessage": "Indexeerders onbeschikbaar wegens fouten: {0}", "IndexerStatusCheckAllClientMessage": "Alle indexeerders zijn onbeschikbaar wegens fouten", "Updates": "Updates", - "UnmappedFolders": "Niet-toegewezen Mappen", "Tags": "Tags", - "Studio": "Studio", "SetTags": "Tags Toepassen", - "RootFolders": "Hoofdmappen", "RootFolderCheckMultipleMessage": "Meerdere hoofdmappen ontbreken: {0}", - "RootFolder": "Hoofdmap", "UI": "Gebruikersinterface", - "RemovedMovieCheckSingleMessage": "De film {0} is verwijderd van TMDb", "RemovedMovieCheckMultipleMessage": "De films {0} zijn verwijderd van TMDb", - "RemotePathMappings": "Externe Pad Verwijzing", "ReleaseBranchCheckOfficialBranchMessage": "Branch {0} is geen geldige Prowlarr release branch, u zult geen updates ontvangen", "ProxyCheckResolveIpMessage": "Achterhalen van het IP-adres voor de geconfigureerde proxy host {0} is mislukt", "ProxyCheckFailedToTestMessage": "Testen van proxy is mislukt: {0}", "ProxyCheckBadRequestMessage": "Testen van proxy is mislukt. Statuscode: {0}", - "MountCheckMessage": "Een mount dat een film pad bevat is gemount als alleen-lezen: ", "MonoTlsCheckMessage": "Tijdelijke Prowlarr Mono 4.x TLS oplossing nog steeds ingeschakeld, overweeg de MONO_TLS_PROVIDER=legacy omgevingsvariabele te verwijderen", - "Wanted": "Gezocht", "UpdateSelected": "Selectie Bijwerken", "UISettingsSummary": "Datum, kleurenblindheid en taal instellingen", - "Timeleft": "Resterende Tijd", "TagsSettingsSummary": "Bekijk alle tags en hun gebruik. Ongebruikte tags kunnen worden verwijderd", - "SourceTitle": "Bron Titel", "SizeOnDisk": "Grootte op Schijf", "Size": "Grootte", - "Runtime": "Speelduur", "Renamed": "Hernoemd", - "ReleaseTitle": "Uitgave Titel", "ReleaseStatus": "Uitgave Status", - "ReleaseGroup": "Uitgave Groep", "Ratings": "Waardering", - "QualitySettingsSummary": "Kwaliteitsdefinities en benaming", "Protocol": "Protocol", - "Progress": "Voortgang", "ProfilesSettingsSummary": "Kwaliteits- en vertragingsprofielen", - "PhysicalRelease": "Fysieke Uitgave", "OutputPath": "Uitvoer Pad", - "MovieTitle": "Film Titel", "MonitoredOnly": "Bewaakt", - "MetadataSettingsSummary": "Metadata bestanden aanmaken wanneer films worden geïmporteerd of vernieuwd", "MediaManagementSettingsSummary": "Naamgeving en bestandsbeheer instellingen", - "MassMovieSearch": "Bulk Films Zoeken", "ListsSettingsSummary": "Lijsten en uitzonderingen", "LastWriteTime": "Laatste Modificatietijd", - "IndexersSettingsSummary": "Indexeerders en uitgave restricties", "Indexer": "Indexeerder", - "InCinemas": "In de Bioscoop", "Imported": "Geïmporteerd", - "Ignored": "Genegeerde", "Grabbed": "Opgehaalde", - "Genres": "Genres", "GeneralSettingsSummary": "Poort, SSL, gebruikersnaam/wachtwoord, proxy, statistieken en updates", "Filename": "Bestandsnaam", "Failed": "Mislukt", "EventType": "Gebeurtenis Type", "DownloadClientsSettingsSummary": "Clientconfiguratie downloaden voor integratie in Prowlarr UI-zoekopdracht", "DownloadClient": "Downloader", - "DigitalRelease": "Digitale Uitgave", "Details": "Details", - "Deleted": "Verwijderd", "CutoffUnmet": "Onbereikte Drempel", - "CustomFormatsSettingsSummary": "Eigen Formaten en instellingen", "ConnectSettingsSummary": "Meldingen en aangepaste scripts", - "Collection": "Collectie", "Certification": "Certificatie", "Added": "Toegevoegd", "Actions": "Acties", - "Year": "Jaar", "Seeders": "Seeders", "Peers": "Peers", "Warn": "Waarschuwing", - "VideoCodec": "Video Codec", "Unavailable": "Onbeschikbaar", "Type": "Type", - "TotalSpace": "Totale Ruimte", "Title": "Titel", "Time": "Tijd", "TestAll": "Test Alle", @@ -230,33 +153,23 @@ "Shutdown": "Afsluiten", "Save": "Opslaan", "Restart": "Herstart", - "RemoveRootFolder": "Verwijder hoofdmap", "Reload": "Herlaad", - "RelativePath": "Relatief Pad", "RejectionCount": "Afwijzingsniveau", "PageSize": "Pagina Grootte", - "OrganizeModalSuccess": "Success! Mijn werk zit erop, geen bestanden te hernoemen.", "OrganizeModalNamingPattern": "Naamgeving Sjabloon:", - "OrganizeModalDisabled": "Hernoemen is uitgeschakeld, niks te doen", "OrganizeModalAllPathsRelative": "Alle paden zijn relatief t.o.v.:", - "OrganizeAndRename": "Organiseer & Hernoem", "Organize": "Organiseer", "Ok": "Ok", "OAuthPopupMessage": "Pop-ups worden geblokkeerd door uw browser", "Name": "Naam", - "MoveFiles": "Verplaats Bestanden", "Monitored": "Bewaakt", "Message": "Bericht", - "Location": "Locatie", "Level": "Niveau", "KeyboardShortcuts": "Sneltoetsen", "Info": "Info", - "ImportExistingMovies": "Importeer Filmbestanden", "HealthNoIssues": "Geen problemen gevonden met uw configuratie", - "HardlinkCopyFiles": "Hardlink/Kopieer Bestanden", "Extension": "Extensie", "Error": "Fout", - "CustomFormatScore": "Eigen Formaat score", "ConnectionLostMessage": "Prowlarr heeft zijn verbinding met de backend verloren en zal moeten worden herladen om functionaliteit te herstellen.", "ConnectionLostAutomaticMessage": "Prowlarr zal automatisch proberen te verbinden, of u kunt hieronder op herladen klikken.", "ConnectionLost": "Verbinding Onderbroken", @@ -264,135 +177,84 @@ "Columns": "Kolommen", "Close": "Sluit", "Cancel": "Annuleer", - "AudioInfo": "Audio Info", "Apply": "Toepassen", - "AlternativeTitle": "Alternatieve Titel", "AllMoviesHiddenDueToFilter": "Alle films zijn verborgen wegens de toegepaste filter.", "Age": "Leeftijd", - "AddNewMovie": "Film Toevoegen", "AddList": "Lijst Toevoegen", - "PosterSize": "Affiche Grootte", "Posters": "Affiches", - "PosterOptions": "Affiche Opties", "UnsavedChanges": "Onopgeslagen Wijzigingen", - "Table": "Tabel", "ShowTitle": "Toon Titel", - "ShowStudio": "Toon Studio", "ShowSizeOnDisk": "Toon Grootte op Schijf", "ShowSearchHelpText": "Toon zoeken knop bij zweven", "ShowSearch": "Toon Zoeken", - "ShowQualityProfile": "Toon Kwaliteitsprofielen", "ShowPath": "Toon Pad", - "ShowMonitored": "Toon Bewaakte", "ShowDateAdded": "Toon Datum Toegevoegd", - "SettingsWeekColumnHeaderHelpText": "Wordt getoond boven elke kolom wanneer de actieve weergave Week is", "SettingsWeekColumnHeader": "Week Kolom Koptekst", - "SettingsUiLanguageHelpText": "Taal die Prowlarr zal gebruiken voor de gebruikersinterface", "SettingsUiLanguage": "Gebruikersinterface Taal", "SettingsTimeFormat": "Tijdsformaat", "SettingsShowRelativeDatesHelpText": "Toon relatieve (Vandaag/Gisteren/enz.) of absolute datums", "SettingsShowRelativeDates": "Toon Relatieve Datums", "SettingsShortDateFormat": "Korte Datumnotatie", - "SettingsRemotePathMappingRemotePathHelpText": "Map dat de Downloader gebruikt", "SettingsRemotePathMappingRemotePath": "Extern Pad", - "SettingsRemotePathMappingLocalPathHelpText": "Het pad dat Prowlarr lokaal moet gebruiken om toegang te krijgen tot het externe pad", "SettingsRemotePathMappingLocalPath": "Lokaal Pad", - "SettingsRemotePathMappingHostHelpText": "Dezelfde host als gespecificeerd voor de Downloader", "SettingsLongDateFormat": "Lange Datumnotatie", - "SettingsFirstDayOfWeek": "Eerste Dag van de Week", "SettingsEnableColorImpairedModeHelpText": "Aangepaste stijl voor gebruikers die kleurenblind zijn om gemakkelijker kleurgecodeerde informatie te onderscheiden", "SettingsEnableColorImpairedMode": "Activeer Kleurenblindheid-modus", - "SelectFolder": "Selecteer Map", "SearchOnAdd": "Zoeken bij Toevoegen", - "SearchMovie": "Zoek Film", "RecentFolders": "Recente Mappen", - "QuickImport": "Snelle Import", "PendingChangesStayReview": "Blijf en bekijk de wijzigingen", "PendingChangesMessage": "U heeft onopgeslagen wijzigingen, bent u zeker dat u deze pagina wilt sluiten?", "PendingChangesDiscardChanges": "Wijzigingen verwerpen en verdergaan", - "OverviewOptions": "Overzicht Opties", "Overview": "Overzicht", "MonoVersionCheckUpgradeRecommendedMessage": "De huidige geïnstalleerde Mono versie {0} wordt ondersteund, maar het is aangeraden om te opwaarderen naar versie {1}.", - "MonoVersionCheckOldNotSupportedMessage": "De huidige geïnstalleerde Mono versie {0} is verouderd en wordt niet langer ondersteund. Gelieve te opwaarderen naar versie {1}.", "MonoVersionCheckNotSupportedMessage": "De huidige geïnstalleerde Mono versie {0} wordt niet langer ondersteund. Gelieve te opwaarderen naar versie {1}.", - "MonitorMovie": "Bewaak Film", "InteractiveImport": "Interactieve Import", "ExistingMovies": "Bestaande Film(s)", - "AddRemotePathMapping": "Voeg Externe Pad Verwijzing Toe", "EditRemotePathMapping": "Bewerk Externe Pad Verwijzing", - "DetailedProgressBarHelpText": "Toon tekst op voortgangsbalk", "DetailedProgressBar": "Gedetailleerde voortgangsbalk", "Interval": "Tussentijd", - "ICalFeed": "iCal Informatiestroom", "Fixed": "Opgelost", - "FileChmodMode": "Bestand chmod modus", "Automatic": "Automatisch", "AuthenticationMethodHelpText": "Gebruikersnaam en wachtwoord nodig voor toegang tot Prowlarr", "Authentication": "Authenticatie", - "AreYouSureYouWantToDeleteThisDelayProfile": "Weet u zeker dat u dit vertragingsprofiel wilt verwijderen?", "AppDataDirectory": "AppData map", - "AddImportExclusionHelpText": "Voorkom dat een film wordt toegevoegd door een lijst", "AgeWhenGrabbed": "Leeftijd (op moment van ophalen)", "AnalyticsEnabledHelpText": "Stuur anonieme gebruiks- en foutinformatie naar de servers van Prowlarr. Dit omvat informatie over uw browser, welke Prowlarr WebUI pagina's u gebruikt, foutrapportage en OS en runtime versie. We zullen deze informatie gebruiken om prioriteiten te stellen voor functies en het verhelpen van fouten.", - "AllowHardcodedSubsHelpText": "Gedetecteerde ingebrande ondertiteling zal automatisch worden gedownload", "AnalyseVideoFiles": "Analyseer videobestanden", - "AlreadyInYourLibrary": "Reeds in uw bibliotheek", "AllowHardcodedSubs": "Sta Ingebrande Ondertiteling Toe", "YesCancel": "Ja, Annuleren", - "AddListExclusion": "Toevoegen aan Uitzonderingenlijst", "AddMoviesMonitored": "Film(s) Bewaakt Toevoegen", - "GrabID": "ID Ophalen", "CleanLibraryLevel": "Bibliotheek Opschonen Niveau", "DeleteTag": "Verwijder Tag", - "DeleteSelectedMovieFiles": "Verwijder Geselecteerde Filmbestanden", "DeleteRestriction": "Verwijder Restrictie", - "DeleteQualityProfile": "Verwijder Kwaliteitsprofiel", "DeleteNotification": "Verwijder Notificatie", - "DeleteList": "Verwijder Lijst", "DeleteIndexer": "Verwijder Indexeerder", - "DeleteImportListExclusion": "Verwijder van Uitzonderingenlijst", "DeleteFile": "Verwijder Bestand", - "DeleteEmptyFolders": "Verwijder lege mappen", "DeleteDownloadClient": "Verwijder Downloader", - "DeleteDelayProfile": "Verwijder Vertragingsprofiel", "DeleteCustomFormat": "Verwijder Eigen Formaat", "Enable": "Activeer", - "EditPerson": "Bewerk Persoon", "EditMovie": "Bewerk Film", - "Edition": "Editie", "DownloadPropers": "Download PROPERS", "DownloadClientSettings": "Downloader Instellingen", "Docker": "Docker", - "DestinationRelativePath": "Relatieve Doelmap", "DestinationPath": "Doelmap", - "DeleteEmptyFoldersHelpText": "Lege mappen verwijderen, tijdens de schijfscan en wanneer filmbestanden worden verwijderd", "DelayProfile": "Vertragingsprofiel", "DBMigration": "DB Migratie", - "CutoffHelpText": "Wanneer deze kwaliteit is behaald, zal Prowlarr niet langer films downloaden", "CutoffFormatScoreHelpText": "Wanneer deze eigen formaat score is behaald, zal Prowlarr niet langer films downloaden", - "CustomFormatsSettings": "Eigen Formaten Instellingen", "CreateGroup": "Groep aanmaken", - "CreateEmptyMovieFoldersHelpText": "Film mappen aanmaken voor ontbrekende films tijdens schijfscan", "CreateEmptyMovieFolders": "Lege film mappen aanmaken", "ConnectSettings": "Connecties Instellingen", - "Conditions": "Condities", "ColonReplacementFormatHelpText": "Wijzig hoe Prowlarr omgaat met dubbele punt vervanging", - "ColonReplacement": "Dubbelepunt Vervanging", "CloneProfile": "Dupliceer Profiel", "CloneIndexer": "Dupliceer Indexeerder", - "CloneFormatTag": "Dupliceer Formaat Tag", "ClientPriority": "Client Prioriteit", - "ClickToChangeQuality": "Klik om kwaliteit te wijzigen", "ClickToChangeLanguage": "Klik om taal te wijzigen", "ChangeHasNotBeenSavedYet": "Wijziging is nog niet opgeslagen", - "ChangeFileDate": "Wijzig Bestandsdatum", "CertificationCountryHelpText": "Selecteer Land voor Film Certificatie", - "CertificationCountry": "Certificatie Land", "CertificateValidationHelpText": "Wijzig hoe strikt HTTPS certificaat validatie is", "CertificateValidation": "Certificaat Validatie", "BypassProxyForLocalAddresses": "Omzeil Proxy voor Lokale Adressen", "Branch": "Branch", - "BlacklistRelease": "Uitgave op Zwarte lijst zetten", "BlacklistHelpText": "Voorkomt dat Prowlarr deze film nogmaals automatisch ophaalt", "BindAddressHelpText": "Geldig IPv4 adres of '*' voor alle interfaces", "DeleteBackup": "Verwijder Veiligheidskopie", @@ -400,44 +262,27 @@ "Backups": "Veiligheidskopieën", "BackupRetentionHelpText": "Automatische veiligheidskopieën ouder dan de retentie periode zullen worden opgeruimd", "BackupFolderHelpText": "Relatieve paden zullen t.o.v. de Prowlarr AppData map bekeken worden", - "AvailabilityDelayHelpText": "Hoeveelheid tijd voor of na de beschikbaarheidsdatum dat er gezocht moet worden naar een film", "AvailabilityDelay": "Beschikbaarheidsvertraging", - "AutoUnmonitorPreviouslyDownloadedMoviesHelpText": "Verwijderde films zullen automatisch als onbewaakt worden gemarkeerd in Prowlarr", "AutoRedownloadFailedHelpText": "Automatisch zoeken en probeer een andere release te downloaden", - "AutoDownloadPropersHelpText": "Moet Prowlarr automatisch bijwerken naar PROPERS wanneer beschikbaar?", "AsAllDayHelpText": "Gebeurtenissen zullen als hele-dag gebeurtenissen verschijnen in uw kalender", "AreYouSureYouWantToResetYourAPIKey": "Bent u zeker dat u uw API-sleutel wilt resetten?", - "AreYouSureYouWantToDeleteThisRemotePathMapping": "Bent u zeker dat u deze externe pad verwijzing wilt verwijderen?", "AreYouSureYouWantToDeleteThisImportListExclusion": "Bent u zeker dat u dit van de uitzonderingenlijst wilt verwijderen?", "ApplyTags": "Tags Toepassen", "ApiKey": "API-sleutel", - "IncludeCustomFormatWhenRenaming": "Eigen Formaat toevoegen bij het hernoemen", "ImportMovies": "Importeer Films", "Importing": "Importeren", - "ImportExtraFilesHelpText": "Importeer bijhorende extra bestanden (ondertitels, nfo, enz.) na het importeren van een film", "ImportExtraFiles": "Importeer Extra Bestanden", - "ImportedTo": "Geïmporteerd Naar", "IllRestartLater": "Ik zal later herstarten", - "IgnoredHelpText": "De uitgave zal worden afgekeurd als het één of meerdere van deze termen bevat (hoofdletter ongevoelig)", "GrabRelease": "Uitgave Ophalen", - "Grab": "Ophalen", "IgnoreDeletedMovies": "Negeer Verwijderde Films", "IgnoredAddresses": "Genegeerde Adressen", - "ICalHttpUrlHelpText": "Kopieer deze URL naar je cliënt(en) of klik om te abonneren als je browser Webcal ondersteunt", "Hostname": "Hostnaam", - "HelpText": "Tussentijd in minuten. Schakel uit met 0 (dit stopt het automatisch ophalen van uitgaves)", "Group": "Groep", - "Global": "Globaal", "GeneralSettings": "Algemene Instellingen", - "FollowPerson": "Volg Persoon", "Folders": "Mappen", - "FirstDayOfWeek": "Eerste Dag van de Week", "FileNames": "Bestandsnamen", - "FileDateHelpText": "Pas bestandsdatum aan tijdens het importeren/herscannen", "Exluded": "Uitgesloten", - "Ended": "Beëindigd", "EnableSSL": "Activeer SSL", - "EnableRSS": "Activeer RSS Synchronisatie", "EnableInteractiveSearch": "Activeer Interactief Zoeken", "EnableHelpText": "Schakel het maken van metadata bestanden in voor dit metadata type", "EnabledHelpText": "Activeer deze lijst voor gebruik in Prowlarr", @@ -447,103 +292,63 @@ "EnableAutomaticSearch": "Activeer Automatisch Zoeken", "EnableAutomaticAdd": "Activeer Automatisch Toevoegen", "EnableAutoHelpText": "Indien ingeschakeld, zullen films automatisch aan Prowlarr worden toegevoegd van deze lijst", - "DownloadWarningCheckDownloadClientForMoreDetails": "Download waarschuwing: controleer de downloader voor meer details", "DownloadFailedCheckDownloadClientForMoreDetails": "Download mislukt: controleer de downloader voor meer details", - "CopyUsingHardlinksHelpTextWarning": "Sporadisch kan bestandsvergrendeling het hernoemen van in gebruik zijnde bestanden blokkeren. Als noodoplossing kunt u de hernoem functie van Prowlarr gebruiken na het opheffen van de bestandsvergrendeling.", "CopyUsingHardlinksHelpText": "Gebruik hardlinks bij het kopiëren van torrent bestanden die nog actief zijn", - "CheckForFinishedDownloadsInterval": "Controle Van Voltooide Downloads Tussentijd", "PreferIndexerFlags": "Verkies Indexeerder Flags", "PortNumber": "Poort Nummer", "Port": "Poort", - "Permissions": "Permissies", "Password": "Wachtwoord", "PackageVersion": "Pakket Versie", - "Original": "Origineel", "OnRenameHelpText": "Bij Hernoemen", "OnHealthIssueHelpText": "Bij Gezondheidsprobleem", - "OnGrabHelpText": "Bij Ophalen", "NotMonitored": "Niet Bewaakt", - "NotAvailable": "Niet Beschikbaar", "NoLeaveIt": "Nee, Ongemoeid Laten", "New": "Nieuw", - "NamingSettings": "Naamgeving Instellingen", "MustNotContain": "Mag Niet Bevatten", - "MustContain": "Moet Bevatten", "MovieYear": "Film Jaar", - "MovieIsDownloading": "Film is aan het downloaden", "MovieInfoLanguageHelpTextWarning": "Browser Herladen Vereist", - "MovieID": "Film ID", "MovieFolderFormat": "Film Map Formaat", - "MovieFiles": "Filmbestanden", "MovieAvailableButMissing": "Film Beschikbaar, maar Ontbrekend", "MonoVersion": "Mono Versie", - "MonitoredHelpText": "Download film indien beschikbaar", "Mode": "Modus", "MinimumLimits": "Minimum Limieten", - "MinimumFreeSpace": "Minimum Vrije Ruimte", "MinimumAge": "Minumum Leeftijd", - "MetadataSettings": "Metadata Instellingen", "MediaManagementSettings": "Mediabeheer Instellingen", - "MediaInfo": "Media Informatie", "Mechanism": "Mechanisme", - "MaximumSize": "Maximum Grootte", "MaximumLimits": "Maximum Limiet", - "MarkAsFailed": "Markeer als Mislukt", "Logs": "Logbestanden", "LogLevel": "Log Niveau", - "Local": "Lokaal", "ListUpdateInterval": "Lijst Bijwerken Tussentijd", - "ListSettings": "Lijst Instellingen", "Links": "Koppelingen", - "IconForCutoffUnmet": "Icoon voor Onbereikte Drempel", "EnableMediaInfoHelpText": "Video informatie extraheren zoals resolutie, speelduur en codec informatie van bestanden. Dit maakt het noodzakelijk dat Prowlarr delen van een bestand moet inlezen dewelke hoge schijf- of netwerkactiviteit kan veroorzaken tijdens het scannen.", "BindAddress": "Aanhaak Adres", - "PreferIndexerFlagsHelpText": "Verkies uitgaves met speciale flags", "MinimumAgeHelpText": "Enkel Usenet: Minimale leeftijd in minuten voor NZB bestanden alvorens ze worden opgehaald. Gebruik dit om nieuwe uitgaves de tijd te geven om tot bij uw Usenet provider toe te komen.", - "LanguageHelpText": "Taal voor Uitgaves", "IndexerSettings": "Indexeerder Instellingen", "IndexerFlags": "Indexeerder Flags", - "IncludeCustomFormatWhenRenamingHelpText": "Voeg toe aan het {Eigen Formaten} hernoemingsformaat", "EnableSslHelpText": " Vereist herstart als administrator om in werking te treden", "PriorityHelpText": "Geef prioriteit aan meerdere downloaders. Round-Robin wordt gebruikt voor downloaders met dezelfde prioriteit.", - "ProtocolHelpText": "Kies welk(e) protocol(len) te gebruiken en welke de voorkeur krijgt bij het kiezen tussen anders gelijke uitgaves", "RecycleBinCleanupDaysHelpText": "Zet op 0 om automatisch opschonen uit te schakelen", - "RecycleBinHelpText": "Filmbestanden zullen bij verwijdering hier naartoe gaan in plaats van permanent te worden verwijderd", "RemoveCompletedDownloadsHelpText": "Verwijder geïmporteerde downloads uit de downloader geschiedenis", - "RemoveHelpTextWarning": "Het verwijderen zal zowel de download als de bestanden verwijderen bij de downloader.", "ReplaceIllegalCharactersHelpText": "Vervang illegale karakters. Indien niet aangevinkt, zal Prowlarr ze in de plaats daarvan verwijderen", - "RescanAfterRefreshHelpTextWarning": "Prowlarr zal niet automatisch aanpassingen aan bestanden detecteren als dit niet op 'Altijd' staat", "RssSyncIntervalHelpTextWarning": "Dit zal van toepassing zijn op alle indexeerders, gelieve de door hen opgelegde regels te volgen", "SendAnonymousUsageData": "Zend Anonieme Gebruiksdata", - "SetPermissionsLinuxHelpText": "Moet chmod worden uitgevoerd wanneer bestanden worden geïmporteerd/hernoemd?", "ShowCutoffUnmetIconHelpText": "Toon icoon voor bestanden waarbij de drempel niet behaald werd", - "ShowUnknownMovieItems": "Toon onbekende film items", "SkipFreeSpaceCheckWhenImportingHelpText": "Gebruik dit wanneer Prowlarr geen vrije schijfruimte kan detecteren voor de hoofdmap van je films", - "SorryThatMovieCannotBeFound": "Sorry, deze film kan niet worden gevonden.", "StandardMovieFormat": "Standaard Film Formaat", - "TestAllIndexers": "Test Alle Indexeerders", "TorrentDelayHelpText": "Wachttijd in minuten alvorens een torrent op te halen", "UnableToLoadIndexers": "Indexeerders kunnen niet worden geladen", "UnableToLoadNotifications": "Notificaties kunnen niet worden geladen", - "UnableToLoadRestrictions": "Restricties kunnen niet worden geladen", "UpdateAutomaticallyHelpText": "Download en installeer updates automatisch. Je zal nog steeds kunnen installeren vanuit Systeem: Updates", "UrlBaseHelpText": "Voor reverse proxy ondersteuning, leeg is standaard", - "UsenetDelayHelpText": "Vertraging in minuten om te wachten voordat een uitgave wordt opgehaald van Usenet", "IncludeUnknownMovieItemsHelpText": "Toon items zonder een film in de wachtrij, dit kan verwijderde films, TV series of iets anders in Prowlarr zijn categorie omvatten", "IncludeHealthWarningsHelpText": "Voeg Gezondheidswaarschuwingen Toe", - "IncludeUnmonitored": "Voeg Onbewaakte Toe", "ListSyncLevelHelpText": "Films in de bibliotheek zullen onbewaakt of verwijderd worden als ze niet in je lijst voorkomen", "LaunchBrowserHelpText": " Open een web browser en navigeer naar de Prowlarr startpagina bij het starten van de app.", - "MaximumSizeHelpText": "Maximale grootte in MB voor een op te halen uitgave. Zet op nul voor ongelimiteerd", "MIA": "MIA", - "MinFormatScoreHelpText": "Minimum eigen formaat score toegelaten om te downloaden", "MinimumFreeSpaceWhenImportingHelpText": "Voorkom importeren indien de resulterende schijfruimte minder is dan deze hoeveelheid", - "MovieIsOnImportExclusionList": "Film staat op de uitzonderingenlijst voor importeren", "MovieTitleHelpText": "De titel van de uit te sluiten film (kan van alles zijn)", - "MovieYearHelpText": "Het jaar van de uit te sluiten film", "ImportListSyncIntervalHelpText": "Hoe vaak Prowlarr je lijsten synchroniseert.", "NotificationTriggers": "Melding Reactiestarters", - "OnDownloadHelpText": "Word op de hoogte gebracht wanneer films succesvol geïmporteerd zijn", "OnUpgradeHelpText": "Word op de hoogte gebracht wanneer films worden bijgewerkt naar een betere kwaliteit", "OpenBrowserOnStart": "Open de browser bij het starten", "PageSizeHelpText": "Aantal items om te tonen op iedere pagina", @@ -553,38 +358,23 @@ "PreferredSize": "Gewenste Grootte", "ProxyPasswordHelpText": "Je moet alleen een gebruikersnaam en wachtwoord ingeven als dit vereist is, laat ze anders leeg.", "ProxyUsernameHelpText": "Je moet alleen een gebruikersnaam en wachtwoord ingeven als dit vereist is, laat ze anders leeg.", - "PublishedDate": "Publicatie Datum", "QualityCutoffHasNotBeenMet": "Kwaliteitsdrempel werd niet behaald", "QualitySettings": "Kwaliteitsinstellingen", "ReadTheWikiForMoreInformation": "Lees de Wiki voor meer informatie", - "Real": "REAL", "Reason": "Reden", - "RecycleBinCleanupDaysHelpTextWarning": "Bestanden in de prullenbak ouder dan het geselecteerde aantal dagen zullen automatisch opgeschoond worden", "RecyclingBin": "Prullenbak", - "RecyclingBinCleanup": "Prullenbak Opruimen", "Redownload": "Opnieuw downloaden", - "RefreshInformationAndScanDisk": "Informatie vernieuwen en schijf herscannen", "RefreshMovie": "Film vernieuwen", "ProxyType": "Proxy Type", - "Proper": "PROPER", "ProxyBypassFilterHelpText": "Gebruik ',' als scheidingsteken en '*' als wildcard voor subdomeinen", - "Prowlarr": "Prowlarr", "ProwlarrTags": "Prowlarr Tags", - "ReleaseDates": "Uitgave Datums", "ReleaseRejected": "Uitgave Afgekeurd", - "Remove": "Verwijder", "RemovedFromTaskQueue": "Verwijderd uit taken wachtrij", - "RemoveFailedDownloadsHelpText": "Verwijder mislukte downloads uit de downloader geschiedenis", "RemoveFilter": "Verwijder filter", - "RemoveFromBlacklist": "Verwijder van zwarte lijst", "RemoveFromDownloadClient": "Verwijder uit downloader", - "RemoveFromQueue": "Verwijder uit wachtrij", "RenameMovies": "Hernoem Films", - "RenameMoviesHelpText": "Prowlarr zal de bestaande bestandsnaam gebruiken als hernoemen uitgeschakeld is", "Reorder": "Herordenen", - "ReplaceIllegalCharacters": "Vervang Illegale Karakters", "RequiredHelpText": "Deze {0} conditie moet overeenstemmen om het eigen formaat te kunnen toepassen. Anders is een enkele {1} overeenstemming voldoende.", - "RescanAfterRefreshHelpText": "De film map herscannen na het vernieuwen van de film", "RescanMovieFolderAfterRefresh": "De film map herscannen na vernieuwen", "Reset": "Reset", "RestartNow": "Herstart Nu", @@ -592,229 +382,143 @@ "RestartRequiredHelpTextWarning": "Herstarten vereist om in werking te treden", "Result": "Resultaat", "Retention": "Retentie", - "RetentionHelpText": "Enkel Usenet: zet op 0 voor ongelimiteerde retentie", "RSSSyncInterval": "RSS Sync. Tussentijd", "ScriptPath": "Script Pad", - "SearchForMovie": "Zoek naar film", "ResetAPIKey": "Reset API-sleutel", - "SetPermissions": "Stel Machtigingen In", "SetPermissionsLinuxHelpTextWarning": "Als je onzeker bent over deze instellingen en hun functie, pas ze dan niet aan.", - "ShouldMonitorHelpText": "Indien ingeschakeld, worden films van deze lijst toegevoegd en bewaakt", "ShowAsAllDayEvents": "Weergeven als evenementen die de hele dag duren", - "ShowMonitoredHelpText": "Toon bewakingsstatus onder de poster", "ShowMovieInformation": "Toon film informatie", - "ShowMovieInformationHelpText": "Toon film genre en certificering", "ShowQualityProfileHelpText": "Toon kwaliteitsprofiel onder poster", - "ShowTitleHelpText": "Toon filmtitel onder poster", "SkipFreeSpaceCheck": "Vrije schijfruimte controle overslaan", - "SourcePath": "Bron Pad", "SourceRelativePath": "Relatief Bron Pad", "SSLCertPassword": "SSL Certificaat Wachtwoord", - "SslCertPasswordHelpText": "Wachtwoord voor pfx bestand", "SSLCertPath": "SSL Certificaat Pad", - "SslCertPathHelpText": "Pad naar pfx bestand", "SSLPort": "SSL Poort", "StartupDirectory": "Opstart map", "SuggestTranslationChange": "Stel vertaling voor", "TagsHelpText": "Is van toepassing op films met minstens één overeenkomende tag", "TestAllClients": "Test Alle Downloaders", - "TestAllLists": "Test Alle Lijsten", "TimeFormat": "Tijdsformaat", - "TMDBId": "TMDb Id", "TmdbIdHelpText": "De TMDb Id van de uit te sluiten film", - "TorrentDelay": "Torrent Vertraging", "Torrents": "Torrents", - "TotalFileSize": "Totale Bestandsgrootte", "UISettings": "Gebruikersinterface Instellingen", - "UnableToLoadCustomFormats": "Eigen formaten kunnen niet worden geladen", "UnableToLoadDelayProfiles": "Vertragingsprofielen kunnen niet worden geladen", "UnableToLoadDownloadClients": "Downloaders kunnen niet worden geladen", - "UnableToLoadListExclusions": "Uitzonderingenlijst kan niet worden geladen", "UnableToLoadLists": "Lijsten kunnen niet worden geladen", - "UnableToLoadMetadata": "Metadata kan niet worden geladen", "UnableToLoadQualityDefinitions": "Kwaliteitsdefinities kunnen niet worden geladen", - "UnableToLoadQualityProfiles": "Kwaliteitsprofielen kunnen niet worden geladen", "UnableToLoadRemotePathMappings": "Externe pad verwijzingen kunnen niet worden geladen", "UnableToLoadTags": "Tags kunnen niet worden geladen", - "Ungroup": "Degroeperen", "UnmonitoredHelpText": "Voeg onbewaakte films toe aan de iCal informatiestrrom", "UpdateMechanismHelpText": "Gebruik het ingebouwde updatemechanisme of een extern script", "UpdateScriptPathHelpText": "Pad naar een aangepast script dat een uitgepakt updatepakket accepteert en de rest van het updateproces afhandelt", - "UpgradeAllowedHelpText": "Indien uitgeschakeld zullen kwaliteitsprofielen niet worden bijgewerkt", "Uptime": "Bedrijfstijd", "URLBase": "URL Basis", - "UseHardlinksInsteadOfCopy": "Gebruik hardlinks in plaats van kopiëren", "Usenet": "Usenet", - "UsenetDelay": "Usenet Vertraging", "UseProxy": "Gebruik Proxy", "Username": "Gebruikersnaam", "Version": "Versie", - "WeekColumnHeader": "Week Kolom Koptekst", "WhitelistedHardcodedSubsHelpText": "Deze ondertiteling tags zullen niet als ingebrand worden beschouwd", - "WhitelistedSubtitleTags": "Ondertiteling tags op de witte lijst", "SettingsRuntimeFormat": "Speelduur Formaat", - "WaitingToProcess": "Wachten tot Verwerking", "WaitingToImport": "Wachten tot Importeren", - "UpgradeUntilThisQualityIsMetOrExceeded": "Bijwerken totdat deze kwaliteit is behaald of overschreden", "TagCannotBeDeletedWhileInUse": "Kan niet verwijderd worden terwijl in gebruik", - "SubfolderWillBeCreatedAutomaticallyInterp": "'{0}' submap zal automatisch worden aangemaakt", "SSLCertPathHelpText": "Pad naar pfx bestand", "SSLCertPasswordHelpText": "Wachtwoord voor pfx bestand", - "ShowYear": "Toon Jaar", "ShowRatings": "Toon Waarderingen", "ShownClickToHide": "Getoond, klik om te verbergen", - "ShowGenres": "Toon Genres", "ShowCertification": "Toon Certificatie", - "SearchOnAddHelpText": "Zoek naar films op deze lijst wanneer toegevoegd aan Prowlarr", "RSSSyncIntervalHelpTextWarning": "Dit zal van toepassing zijn op alle indexeerders, gelieve de door hen opgelegde regels te volgen", "RSSIsNotSupportedWithThisIndexer": "RSS wordt niet ondersteund door deze indexeerder", - "RetryingDownloadInterp": "Download opnieuw proberen {0} op {1}", "RemovingTag": "Tag verwijderen", - "ReleaseWillBeProcessedInterp": "Uitgave zal worden verwerkt {0}", "Queued": "Afwachtend", - "QualityProfileDeleteConfirm": "Bent u zeker dat u het kwaliteitsprofiel {0} wilt verwijderen", "Pending": "In afwachting", - "Paused": "Gepauzeerd", "NegateHelpText": "Indien aangevinkt, zal het eigen formaat niet worden toegepast indien deze {0} conditie overeenstemt.", - "MoviesSelectedInterp": "{0} Film(s) Geselecteerd", "MovieIsUnmonitored": "Film wordt niet bewaakt", - "MovieIsMonitored": "Film wordt bewaakt", "MovieIsDownloadingInterp": "Film is aan het downloaden - {0}% {1}", - "MovieExcludedFromAutomaticAdd": "Film Uitgesloten Van Automatisch Toevoegen", "MovieAlreadyExcluded": "Film werd al Uitgesloten", - "MarkAsFailedMessageText": "Bent u zeker dat u '{0}' als mislukt wilt markeren?", "Manual": "Manueel", "LogLevelTraceHelpTextWarning": "Trace log niveau moet enkel tijdelijk worden gebruikt", - "LastDuration": "Laatste Looptijd", "IncludeRecommendationsHelpText": "Voeg Prowlarr aanbevolen films toe aan ontdekken weergave", - "IncludeProwlarrRecommendations": "Voeg Prowlarr Aanbevelingen Toe", "ImportFailedInterp": "Importeren mislukt: {0}", - "ImportFailed": "Importeren mislukt: {0}", "HiddenClickToShow": "Verborgen, klik om te tonen", - "GrabReleaseMessageText": "Prowlarr was niet in staat om deze uitgave aan een film te koppelen. Prowlarr zal waarschijnlijk deze uitgave niet automatisch kunnen importeren. Wilt u '{0}' ophalen?", "GoToInterp": "Ga naar {0}", "ExistingTag": "Bestaande tag", - "ExcludeMovie": "Film Uitsluiten", "EnableInteractiveSearchHelpTextWarning": "Zoeken wordt niet ondersteund door deze indexeerder", "EnableInteractiveSearchHelpText": "Zal worden gebruikt wanneer interactief zoeken wordt gebruikt", "EnableAutomaticSearchHelpTextWarning": "Zal worden gebruikt wanneer interactief zoeken wordt gebruikt", "EnableAutomaticSearchHelpText": "Zal worden gebruikt wanneer automatische zoekopdrachten worden uitgevoerd via de gebruikersinterface of door Prowlarr", - "DownloadWarning": "Download waarschuwing: {0}", "Downloading": "Downloaden", - "DownloadFailedInterp": "Download mislukt: {0}", "DownloadFailed": "Download mislukt", "DownloadClientUnavailable": "Downloader is onbeschikbaar", "DeleteTagMessageText": "Bent u zeker dat u de tag '{0}' wilt verwijderen?", - "DeleteSelectedMovieFilesMessage": "Bent u zeker dat u de geselecteerde filmbestanden wilt verwijderen?", "DeleteRestrictionHelpText": "Bent u zeker dat u deze restrictie wilt verwijderen?", "DeleteNotificationMessageText": "Bent u zeker dat u de notificatie '{0}' wilt verwijderen?", - "DeleteListMessageText": "Bent u zeker dat u de lijst '{0}' wilt verwijderen?", "DeleteIndexerMessageText": "Bent u zeker dat u de indexeerder '{0}' wilt verwijderen?", "DeleteDownloadClientMessageText": "Bent u zeker dat u de downloader '{0}' wilt verwijderen?", "DeleteBackupMessageText": "Bent u zeker dat u de veiligheidskopie '{0}' wilt verwijderen?", - "DelayingDownloadUntilInterp": "Vertraag download tot {0} op {1}", "Cutoff": "Drempel", - "ClickToChangeMovie": "Klik om film te wijzigen", "CheckDownloadClientForDetails": "controleer downloader voor meer details", "CancelPendingTask": "Bent u zeker dat u deze taak in afwachting wilt annuleren?", "BranchUpdateMechanism": "Gebruikte branch door extern update mechanisme", "BranchUpdate": "Te gebruiken branch om Prowlarr bij te werken", "BeforeUpdate": "Voor de update", - "AllowMovieChangeClickToChangeMovie": "Klik om film te wijzigen", "AddingTag": "Tag toevoegen", - "YouCanAlsoSearch": "U kunt ook zoeken met het TMDb Id of het IMDb Id van een film. Bijv. tmdb:71663", "VisitGithubCustomFormatsAphrodite": "Bezoek GitHub voor meer details: ", - "Unreleased": "Niet Uitgebracht", "UnableToLoadUISettings": "Kon gebruikersinterface instellingen niet inladen", - "UnableToLoadTheCalendar": "Kon kalender niet inladen", "UnableToLoadRootFolders": "Kon hoofdmappen niet inladen", - "UnableToLoadQualities": "Kon kwaliteitsprofielen niet inladen", "UnableToLoadNamingSettings": "Kon Naamgevingsinstellingen niet inladen", - "UnableToLoadMovies": "Kon films niet inladen", "UnableToLoadMediaManagementSettings": "Kon Mediabeheer instellingen niet inladen", - "UnableToLoadListOptions": "Kon lijst opties niet inladen", "UnableToLoadIndexerOptions": "Kon indexeerder opties niet inladen", "UnableToLoadGeneralSettings": "Kon Algemene instellingen niet inladen", - "UnableToLoadDownloadClientOptions": "Kon downloader opties niet inladen", "UnableToAddANewRemotePathMappingPleaseTryAgain": "Kon geen nieuw externe pad verwijzing toevoegen, gelieve opnieuw te proberen.", - "UnableToAddANewQualityProfilePleaseTryAgain": "Kon geen nieuw kwaliteitsprofiel toevoegen, gelieve opnieuw te proberen.", "UnableToAddANewNotificationPleaseTryAgain": "Kon geen nieuwe notificatie toevoegen, gelieve opnieuw te proberen.", - "UnableToAddANewListPleaseTryAgain": "Kon geen nieuwe lijst toevoegen, gelieve opnieuw te proberen.", "UnableToAddANewListExclusionPleaseTryAgain": "Kon geen nieuw item toevoegen aan de uitzonderingenlijst, gelieve opnieuw te proberen.", "UnableToAddANewIndexerPleaseTryAgain": "Kon geen nieuwe indexeerder toevoegen, gelieve opnieuw te proberen.", "UnableToAddANewDownloadClientPleaseTryAgain": "Kon geen nieuwe downloader toevoegen, gelieve opnieuw te proberen.", - "UnableToAddANewCustomFormatPleaseTryAgain": "Kon geen nieuw eigen formaat toevoegen, gelieve opnieuw te proberen.", "UnableToAddANewConditionPleaseTryAgain": "Kon geen nieuwe conditie toevoegen, gelieve opnieuw te proberen.", - "ThisConditionMatchesUsingRegularExpressions": "Deze conditie toont een overeenkomst vanwege Reguliere Expressie. Merk op dat de karakters {0} een speciale betekenis hebben en met {1} moeten worden voorgegaan om hun oorspronkelijke betekenis te krijgen", "RegularExpressionsCanBeTested": "Reguliere expressies kunnen worden getest ", - "ProwlarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "Prowlarr ondersteunt aangepaste condities tegenover de uitgave eigenschappen hieronder.", "ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "Prowlarr ondersteunt elke RSS filmlijst, tevens ook de ander hieronder weergegeven lijsten.", "ProwlarrSupportsAnyIndexer": "Prowlarr ondersteunt veel indexeerders naast elke indexeerder die de Newznab/Torznab-standaard gebruikt met 'Generic Newznab' (voor usenet) of 'Generic Torznab' (voor torrents). Zoek en selecteer uw indexeerder hieronder.", "ProwlarrSupportsAnyDownloadClient": "Prowlarr ondersteund elke downloader die gebruik maakt van de Newznab standaard, tevens ook de ander hieronder weergegeven downloaders.", "NoTagsHaveBeenAddedYet": "Er zijn nog geen tags toegevoegd", - "MissingMonitoredAndConsideredAvailable": "Ontbrekend, Bewaakt en beschouwd als Beschikbaar", "HaveNotAddedMovies": "U heeft nog geen films toegevoegd, wilt u eerst enkele of al uw films importeren?", - "ForMoreInformationOnTheIndividualIndexers": "Voor meer informatie over de individuele indexeerders, klik op de info knoppen.", "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Voor meer informatie over de individuele lijsten, klik op de info knoppen.", "ForMoreInformationOnTheIndividualDownloadClients": "Voor meer informatie over de individuele downloaders, klik op de info knoppen.", - "FileChmodHelpTexts2": "Dezelfde modus wordt toegepast op film-/submappen, maar met de uitvoeren bit, bijv. 0644 wordt 0755", "FileChmodHelpTexts1": "Octaal, wordt toegepast op mediabestanden bij het importeren/hernoemen door Prowlarr", - "FailedLoadingSearchResults": "Laden van zoekresultaten is mislukt, gelieve opnieuw te proberen.", "ExtraFileExtensionsHelpTexts1": "Komma gescheiden lijst met extra bestanden om te importeren (.nfo zal als .nfo-orig worden geïmporteerd)", - "CouldNotFindResults": "Kon geen resultaten vinden voor '{0}'", "ApplyTagsHelpTexts4": "Vervangen: Vervang de tags met de ingevoerde tags (voer geen tags in om alle tags te wissen)", "ApplyTagsHelpTexts3": "Verwijderen: Verwijder de ingevoerde tags", "ApplyTagsHelpTexts2": "Toevoegen: Voeg de tags toe aan de lijst met bestaande tags", "ApplyTagsHelpTexts1": "Hoe tags toe te passen op de geselecteerd films", - "UnableToLoadLanguages": "Kon talen niet laden", "UnableToLoadHistory": "Kon geschiedenis niet laden", - "UnableToLoadBlacklist": "Kon zwarte lijst niet laden", "UnableToLoadBackups": "Kon geen veiligheidskopieën laden", "TagIsNotUsedAndCanBeDeleted": "Tag is niet in gebruik en kan verwijderd worden", "StartTypingOrSelectAPathBelow": "Begin met typen of selecteer een pad hier beneden", "Restore": "Herstellen", - "RequiredPlaceHolder": "Voeg nieuwe restrictie toe", "OnDeleteHelpText": "Bij Verwijderen", "NoUpdatesAreAvailable": "Geen updates beschikbaar", "NoLogFiles": "Geen logbestanden", - "NoHistory": "Geen geschiedenis", "NoBackupsAreAvailable": "Geen veiligheidskopieën beschikbaar", - "MoreDetails": "Meer details", "MissingNotMonitored": "Ontbrekend, niet Bewaakt", "MinutesSixty": "60 Minuten: {0}", "MinutesNinety": "90 Minuten: {0}", "MinutesHundredTwenty": "120 Minuten: {0}", "MaintenanceRelease": "Onderhoudsuitgave", - "LoadingMovieFilesFailed": "Laden van filmbestanden is mislukt", "LoadingMovieExtraFilesFailed": "Laden van film extra bestanden is mislukt", - "LoadingMovieCreditsFailed": "Laden van film aftiteling mislukt", "LinkHere": "hier", - "IgnoredPlaceHolder": "Voeg nieuwe restrictie toe", "FilterPlaceHolder": "Zoek indexeerder", - "ExtraFileExtensionsHelpTexts2": "Voorbeelden: '.sub, .nfo' of 'sub,nfo'", "Excluded": "Uitgezonderd", "Exception": "Uitzondering", - "ErrorLoadingPreviews": "Fout bij laden van voorvertoningen", "ErrorLoadingContents": "Fout bij laden van inhoud", - "DownloadedButNotMonitored": "Gedownload, maar niet Bewaakt", "DownloadedAndMonitored": "Gedownload en Bewaakt", - "CantFindMovie": "Waarom kan ik mijn film niet vinden?", "UILanguageHelpTextWarning": "Browser Herladen Vereist", "UILanguageHelpText": "Taal die Prowlarr zal gebruiken voor de gebruikersinterface", "UILanguage": "Gebruikersinterface Taal", - "MovieInfoLanguageHelpText": "Taal die Prowlarr zal gebruiken voor Film Informatie in de gebruikersinterface", "MovieInfoLanguage": "Film Informatie Taal", - "ImportCustomFormat": "Importeer Eigen Formaat", "ExportCustomFormat": "Exporteer Eigen Formaat", - "DownloadPropersAndRepacksHelpTextWarning": "Gebruik voorkeur woorden voor automatische opwaarderingen naar PROPERS/REPACKS", "DownloadPropersAndRepacksHelpText2": "Gebruik 'Geen Voorkeur' om te sorteren volgens voorkeur woord score boven PROPERS/REPACKS", - "DownloadPropersAndRepacksHelpText1": "Of dat er al dan niet moet worden bijgewerkt naar PROPERS/REPACKS", "DownloadPropersAndRepacks": "PROPERS en REPACKS", - "CustomFormatUnknownConditionOption": "Onbekende optie '{0}' voor conditie '{1}'", "CustomFormatUnknownCondition": "Onbekende Eigen Formaat conditie '{0}'", - "CustomFormatJSON": "Aangepast Formaat JSON", "CopyToClipboard": "Kopieer naar Klembord", - "CloneCustomFormat": "Dupliceer Eigen Formaat", "Priority": "Prioriteit", "InteractiveSearch": "Interactief Zoeken", "IndexerPriorityHelpText": "Indexeerder Prioriteit van 1 (Hoogste) tot 50 (Laagste). Standaard: 25.", @@ -823,15 +527,10 @@ "Disabled": "Uitgeschakeld", "AutomaticSearch": "Automatisch Zoeken", "AddIndexer": "Voeg Indexeerder Toe", - "ImportErrors": "Importeer Fouten", "FocusSearchBox": "Focus Zoekvak", - "Existing": "Bestaande", "EditRestriction": "Bewerk Restrictie", - "Digital": "Digitaal", "CloseCurrentModal": "Sluit Huidig Bericht", - "CancelProcessing": "Annuleer Verwerking", "Blacklisted": "Op de zwarte lijst", - "AddRestriction": "Voeg Restrictie Toe", "AddMovie": "Voeg Film Toe", "AcceptConfirmationModal": "Accepteer Bevestigingsbericht", "Yesterday": "Gisteren", diff --git a/src/NzbDrone.Core/Localization/Core/pl.json b/src/NzbDrone.Core/Localization/Core/pl.json index 7e6973b15..85d4dc82e 100644 --- a/src/NzbDrone.Core/Localization/Core/pl.json +++ b/src/NzbDrone.Core/Localization/Core/pl.json @@ -1,25 +1,16 @@ { - "Collection": "Kolekcja", "Clear": "Wyczyść", - "ChooseAnotherFolder": "Wybierz inny folder", "Certification": "Certyfikacja", - "Cast": "Reżyseria", "Calendar": "Kalendarz", - "Blacklist": "Czarna lista", "BackupNow": "Zrób kopię zapasową teraz", "Backup": "Kopia zapasowa", "AppDataLocationHealthCheckMessage": "Aktualizacja nie będzie możliwa w celu uniknięcia usunięcia danych aplikacji", - "AndNot": "i nie", "Analytics": "Analityka", "All": "Wszystkie", - "Agenda": "Agenda", "AddNewTmdbIdMessage": "Możesz również użyć ID TMDB, np. tmdb:71663", - "AddNewMessage": "Bardzo łatwo dodać nowy film, po prostu zacznij wpisywać nazwę jakiegoś filmu", "AddNew": "Dodaj nowe", - "AddMovies": "Dodaj filmy", "AddExclusion": "Dodaj wyjątek", "Added": "Dodane", - "Activity": "Aktywność", "Actions": "Aktywności", "About": "O" } diff --git a/src/NzbDrone.Core/Localization/Core/pt.json b/src/NzbDrone.Core/Localization/Core/pt.json index e0c9daee7..9f071f334 100644 --- a/src/NzbDrone.Core/Localization/Core/pt.json +++ b/src/NzbDrone.Core/Localization/Core/pt.json @@ -1,30 +1,22 @@ { "Peers": "Elementos", "AppDataLocationHealthCheckMessage": "Não será possível atualizar para evitar a exclusão de AppData", - "Year": "Ano", "Week": "Semana", "Warn": "Avisar", - "Wanted": "Desejado", "View": "Ver", - "VideoCodec": "Codec de Video", "UpdateSelected": "Atualização Selecionada", "Updates": "Atualizações", "UpdateCheckUINotWritableMessage": "Não é possível instalar a atualização porque a pasta da IU \"{0}\" não tem permissões de escrita para o utilizador \"{1}\".", "UpdateCheckStartupNotWritableMessage": "Não é possível instalar a atualização porque a pasta de arranque \"{0}\" não tem permissões de escrita para o utilizador \"{1}\".", "UpdateCheckStartupTranslocationMessage": "Não é possível instalar a atualização porque a pasta de arranque \"{0}\" está em uma pasta de transposição de aplicações.", - "UpdateAll": "Atualizar Tudo", "UnselectAll": "Desmarcar todos", "UnsavedChanges": "Mudanças não guardadas", - "UnmappedFolders": "Pastas Não Mapeadas", "Unmonitored": "Não Monitorado", - "Unavailable": "Indisponível", "UISettingsSummary": "Opções de calendário, data e modo de daltonismo", "UI": "IU", "Type": "Tipo", - "TotalSpace": "Espaço Total", "Titles": "Títulos", "Title": "Título", - "Timeleft": "Tempo Restante", "Time": "Hora", "TestAll": "Testar todos", "Test": "Testar", @@ -33,227 +25,146 @@ "Tags": "Etiquetas", "TableOptionsColumnsMessage": "Escolha quais colunas são visíveis e em qual ordem aparecem", "TableOptions": "Opções da tabela", - "Table": "Tabela", "SystemTimeCheckMessage": "A hora do sistema está atrasada em mais de 1 dia. As tarefas agendadas podem não ocorrer corretamente até a hora ser corrigida", "System": "Sistema", "Style": "Estilo", - "Studio": "Estúdio", "Status": "Estado", - "SourceTitle": "Título de Origem", "Source": "Origem", "Sort": "Ordenar", - "SizeOnDisk": "Tamanho em Disco", "Size": "Tamanho", "Shutdown": "Encerrar", - "ShowTitle": "Mostrar Título", "ShowStudio": "Mostrar Estúdio", - "ShowSizeOnDisk": "Mostrar Tamanho em Disco", "ShowSearchHelpText": "Mostrar botão de pesquisa ao passar o cursor", "ShowSearch": "Mostrar pesquisa", - "ShowQualityProfile": "Mostrar Qualidade de Perfil", "ShowPath": "Mostrar Caminho", - "ShowMonitored": "Mostrar Monitorado", "ShowDateAdded": "Mostrar Data Adicionado", "ShowAdvanced": "Mostrar avançado", - "SettingsWeekColumnHeaderHelpText": "Mostrar acima de cada coluna quando a semana é a visualização ativa", "SettingsWeekColumnHeader": "Cabeçalho de Coluna Semanal", - "SettingsUiLanguageHelpText": "Idioma que o Prowlarr usará para a UI", "SettingsUiLanguage": "Idioma da UI", "SettingsTimeFormat": "Formato de hora", "SettingsShowRelativeDatesHelpText": "Mostrar datas relativas (Hoje, Ontem, etc.) ou absolutas", "SettingsShowRelativeDates": "Mostrar datas relativas", "SettingsShortDateFormat": "Formato curto de data", - "SettingsRemotePathMappingRemotePathHelpText": "Caminho raiz para o diretório que o Cliente de Download acessa", "SettingsRemotePathMappingRemotePath": "Caminho Remoto", - "SettingsRemotePathMappingLocalPathHelpText": "Caminho que o Prowlarr deve usar para acessar localmente o caminho remoto", "SettingsRemotePathMappingLocalPath": "Caminho Local", - "SettingsRemotePathMappingHostHelpText": "O mesmo host que você especificou para o Cliente de Download remoto", "SettingsLongDateFormat": "Formato longo de data", - "SettingsFirstDayOfWeek": "Primeiro Dia da Semana", "SettingsEnableColorImpairedMode": "Ativar modo de daltonismo", "SettingsEnableColorImpairedModeHelpText": "Estilo alterado para permitir que utilizadores com daltonismo possam melhor distinguir informações de cores", "Settings": "Definições", "SetTags": "Definir etiquetas", - "SelectFolder": "Selecionar Pasta", "SelectAll": "Selecionar todos", "Seeders": "Semeadores", "Security": "Segurança", - "SearchSelected": "Buscar Selecionado", "SearchOnAdd": "Buscar ao Adicionar", - "SearchMovie": "Buscar Filme", "SearchForMissing": "Buscar Ausentes", - "SearchFiltered": "Pesquisa Filtrada", "SearchAll": "Buscar Todos", "Search": "Pesquisar", "Scheduled": "Agendado", "SaveChanges": "Guardar mudanças", "Save": "Guardar", - "Runtime": "Tempo de Execução", "RSSSync": "Sincronia RSS", - "RootFolders": "Pastas Raiz", "RootFolderCheckSingleMessage": "Pasta raiz não encontrada: {0}", - "RootFolderCheckMultipleMessage": "Múltiplas pastas raízes não foram encontradas: {0}", "RootFolder": "Pasta Raiz", "Restrictions": "Restrições", "RestoreBackup": "Restaurar cópia de segurança", "Restart": "Reiniciar", - "RenameFiles": "Renomear Arquivos", "Renamed": "Renomeado", - "RemoveSelected": "Remover Selecionado", "RemoveRootFolder": "Remover pasta raiz", - "RemovedMovieCheckSingleMessage": "O filme {0} foi removido do TMDb", "RemovedMovieCheckMultipleMessage": "Os filmes {0} foram removidos do TMDb", - "RemotePathMappings": "Mapeamento de Caminho Remoto", "Reload": "Recarregar", - "ReleaseTitle": "Título da Versão", "ReleaseStatus": "Estado da versão", - "ReleaseGroup": "Grupo da Versão", "ReleaseBranchCheckPreviousVersionMessage": "A ramificação {0} é para versões anteriores do Prowlarr, utilize a ramificação \"Nightly\" para futuras atualizações", "ReleaseBranchCheckOfficialBranchMessage": "A ramificação {0} não é uma ramificação de versões válida do Prowlarr, você não receberá atualizações", - "RelativePath": "Caminho Relativo", "RejectionCount": "Contagem de Rejeição", - "RefreshAndScan": "Atualizar & Varrer", "Refresh": "Atualizar", - "RecentFolders": "Pastas Recentes", "Ratings": "Avaliações", - "QuickImport": "Importação Rápida", "Queue": "Fila", - "QualitySettingsSummary": "Tamanhos de qualidade e nomeamento", "QualityProfiles": "Perfis de Qualidades", - "QualityProfile": "Perfil de Qualidade", "QualityDefinitions": "Definições de qualidade", - "Quality": "Qualidade", "PtpOldSettingsCheckMessage": "As definições dos seguintes indexadores do PassThePopcorn são obsoletas e precisam ser atualizadas: {0}", "ProxyCheckResolveIpMessage": "Não é possível resolver o Endereço IP para o Anfitrião de proxy {0} definido", "ProxyCheckFailedToTestMessage": "Falha ao testar o proxy: {0}", "ProxyCheckBadRequestMessage": "Falha ao testar o proxy. Código de estado: {0}", "Proxy": "Proxy", "Protocol": "Protocolo", - "Progress": "Progresso", "ProfilesSettingsSummary": "Qualidade, Idioma e Perfis de Espera", - "Profiles": "Perfis", "PreviewRename": "Pré-visualizar Renomear", - "PosterSize": "Tamanho do Poster", "Posters": "Posters", - "PosterOptions": "Opções de Poster", "PhysicalRelease": "Versão Física", "PendingChangesStayReview": "Ficar e rever mudanças", "PendingChangesMessage": "Há mudanças não guardadas, tem a certeza que quer sair dessa página?", "PendingChangesDiscardChanges": "Descartar mudanças e sair", - "Path": "Caminho", "PageSize": "Tamanho da página", - "OverviewOptions": "Opções de Resumo", "Overview": "Resumo", - "OutputPath": "Caminho de Saida", "OrganizeModalSuccess": "Sucesso! Meu trabalho está feito, sem arquivos para renomear.", - "OrganizeModalNamingPattern": "Padrão de Nomeamento:", "OrganizeModalDisabled": "O renomeamento esta desativado, nada para renomear", - "OrganizeModalAllPathsRelative": "Todos caminhos relativos a:", "OrganizeAndRename": "Organizar & Renomear", - "Organize": "Organizar", "Options": "Opções", "Ok": "Ok", "OAuthPopupMessage": "Os pop-ups estão sendo bloqueados por seu browser", "NoChanges": "Sem mudanças", "NoChange": "Sem mudança", - "NetImportStatusCheckSingleClientMessage": "Listas indisponíveis devido a falhas: {0}", "NetImportStatusCheckAllClientMessage": "Todas listas estão indisponíveis devido a falhas", "Name": "Nome", - "MovieTitle": "Título do Filme", "Movies": "Filmes", - "MovieNaming": "Nomeação de Filmes", "MovieIndex": "Índice de Filmes", - "MovieEditor": "Editor de Filmes", "Movie": "Filme", - "MoveFiles": "Mover Arquivos", "MountCheckMessage": "O ponto de montagem que leva a um filme esta montado como apenas leitura: ", "MoreInfo": "Mais informações", - "Month": "Mes", "MonoVersionCheckUpgradeRecommendedMessage": "A versão Mono {0} atualmente instalada é suportada, mas recomenda-se atualizar para {1}.", - "MonoVersionCheckOldNotSupportedMessage": "O Mono versão {0} instalado atualmente é velho e obsoleto. Por favor atualize para o Mono versão {1}.", "MonoVersionCheckNotSupportedMessage": "Instalado atualmente o Mono versão {0} o qual não é mais suportado. Por favor atualize para o Mono versão {1}.", "MonoTlsCheckMessage": "Uma solução para o Prowlarr Mono 4.x tls ainda está ativa, considere remover a opção de ambiente MONO_TLS_PROVIDER=legacy", "MonoNotNetCoreCheckMessage": "Atualiza para a versão .NET Core do Prowlarr", - "MonitorMovie": "Monitorar Filme", "MonitoredOnly": "Apenas Monitorado", - "Monitored": "Monitorado", "Monitor": "Monitorar", - "Missing": "Ausente", "MinimumAvailability": "Disponibilidade Mínima", - "MinAvailability": "Disponibilidade Min", "MetadataSettingsSummary": "Criar arquivos de metadados quando os filmes são importados ou atualizados", - "Metadata": "Metadados", "Message": "Mensagem", - "MediaManagementSettingsSummary": "Configurações de nomes e gerenciamento de arquivos", "MediaManagement": "Gerenciamento de Mídia", - "MediaInfoDllCheckMessage": "A biblioteca MediaInfo no pôde ser carregado {0}", "MassMovieSearch": "Pesquisa de Filmes em Massa", - "ManualImport": "Importação Manual", "Logging": "Registo em log", - "LogFilesLocationMessage": "Os logs estão localizados em:", "LogFiles": "Ficheiros de log", - "Location": "Localização", "ListsSettingsSummary": "Listas de Importações, listas de exclusões", - "Lists": "Listas", "ListExclusions": "Lista de Exclusões", "Level": "Nível", "LastWriteTime": "Hora da última escrita", "Language": "Idioma", "Languages": "Idiomas", "KeyboardShortcuts": "Atalhos do teclado", - "InteractiveImport": "Importação Interativa", "Info": "Informações", "IndexerStatusCheckSingleClientMessage": "Indexadores indisponíveis devido a falhas: {0}", "IndexerStatusCheckAllClientMessage": "Todos os indexadores estão indisponíveis devido a falhas", - "IndexersSettingsSummary": "Indexadores e restrições de versões", "IndexerSearchCheckNoInteractiveMessage": "Sem indexadores disponíveis com Pesquisa Interativa ativada, o Prowlarr não proverá nenhum resultado de pesquisa interativa", - "IndexerSearchCheckNoAutomaticMessage": "Sem indexadores disponíveis com pesquisa automática ativada, o Prowlarr não proverá nenhum resultado de pesquisas automáticas", "IndexerSearchCheckNoAvailableIndexersMessage": "Todos indexadores capazes de pesquisar estão indisponíveis devido a recente erros de indexadores", "Indexers": "Indexadores", - "IndexerRssHealthCheckNoIndexers": "Nenhum indexador disponível com sincronia RSS ativado, o Prowlarr não irá capturar novas versões automaticamente", "IndexerRssHealthCheckNoAvailableIndexers": "Todos indexadores com rss estão temporariamente indisponíveis devido a erros recentes de indexadores", "Indexer": "Indexador", - "InCinemas": "Nos Cinemas", "ImportTipsMessage": "Algumas dicas para garantir que a importação funcione perfeitamente:", - "ImportSecondTip": "Direcione o Prowlarr para a pasta que contém todos seus filmes, não um específico. ex.", "ImportMechanismHealthCheckMessage": "Ativar Manipulação de Download Completado", - "ImportHeader": "Importar filmes que você ja tem", "ImportFirstTip": "Garanta que seus arquivos incluam a qualidade no nome. ex.", - "ImportExistingMovies": "Importar Filmes Existentes", "Imported": "Importado", - "Import": "Importar", "Ignored": "Ignorado", - "iCalLink": "Vincular iCal", "Host": "Anfitrião", "History": "Histórico", "HideAdvanced": "Ocultar avançado", "HealthNoIssues": "Não há problemas com suas definições", "Health": "Estado de funcionamento", - "HardlinkCopyFiles": "Hardlink/Copiar Arquivos", "GrabSelected": "Capturar Selecionado", "Grabbed": "Capturado", - "Genres": "Gêneros", "GeneralSettingsSummary": "Porta, SSL, utilizador/palavra-passe, proxy, análises e atualizações", "General": "Geral", - "FreeSpace": "Espaço Livre", "Formats": "Formatos", - "Forecast": "Previsão", "Folder": "Pasta", "Filter": "Filtrar", - "Filesize": "Tamanho do Arquivo", "Files": "Ficheiros", "Filename": "Nome do ficheiro", - "FileManagement": "Gerenciamento de Arquivo", "FailedDownloadHandling": "Manuseio de Download Falhado", "Failed": "Falhado", - "Extension": "Extensão", "ExistingMovies": "Filme(s) existente(s)", "EventType": "Tipo de evento", "Events": "Eventos", "Error": "Erro", - "EditRemotePathMapping": "Editar Mapeamento de Caminho Remoto", "Edit": "Editar", - "Downloaded": "Baixado", "DownloadClientStatusCheckSingleClientMessage": "Clientes de transferências indisponíveis devido a falhas: {0}", "DownloadClientStatusCheckAllClientMessage": "Todos os clientes de transferências estão indisponíveis devido a falhas", "DownloadClientsSettingsSummary": "Definições do cliente de transferências para integração à pesquisa da IU do Prowlarr", @@ -261,26 +172,17 @@ "DownloadClientCheckUnableToCommunicateMessage": "Não é possível ligar-se a {0}.", "DownloadClientCheckNoneAvailableMessage": "Nenhum cliente de transferências disponível", "DownloadClient": "Cliente de transferências", - "DotNetVersionCheckOldUnsupportedMessage": "O Framework .Net {0} instalado atualmente é velho e não suportado. Por favor atualize para o Framework .Net para ao menos {1}.", "DotNetVersionCheckNotRecommendedMessage": "O Framework .Net {0} instalado atualmente é suportado, mas nós recomendamos atualizar para ao menos {1}.", - "DiskSpace": "Espaço em Disco", "Discover": "Descobrir", - "DigitalRelease": "Versão Digital", "Details": "Detalhes", - "DetailedProgressBarHelpText": "Mostrar texto na barra de progresso", "DetailedProgressBar": "Barra de Progresso Detalhada", - "Deleted": "Excluído", "Delete": "Eliminar", - "DelayProfiles": "Perfis de Espera", "Day": "Dia", "Dates": "Datas", "Date": "Data", - "CutoffUnmet": "Ignorar Não-correspondido", "CustomFormatsSettingsSummary": "Formatos Customizados e Configurações", - "CustomFormatScore": "Pontos do Formato Customizado", "CustomFormats": "Formatos Customizados", "CustomFilters": "Filtros personalizados", - "Crew": "Equipe Técnica", "ConnectSettingsSummary": "Notificações, ligações para servidores/leitores de multimédia e scripts personalizados", "Connections": "Ligações", "ConnectionLostMessage": "O Prowlarr perdeu a ligação com o back-end e precisará recarregar para restaurar a funcionalidade.", @@ -288,166 +190,101 @@ "ConnectionLost": "Ligação perdida", "Connect": "Conexões", "Component": "Componente", - "CompletedDownloadHandling": "Manuseio de Download Completado", "Columns": "Colunas", - "Collection": "Coleção", "Close": "Fechar", "Clear": "Limpar", - "ChooseAnotherFolder": "Escolher outra Pasta", "Certification": "Certificação", - "Cast": "Elenco", "Cancel": "Cancelar", - "Calendar": "Calendário", "Blacklist": "Lista Negra", "BackupNow": "Criar cópia de segurança", "Backup": "Cópia de segurança", - "AudioInfo": "Info de Audio", "Apply": "Aplicar", - "AndNot": "e não", "Analytics": "Análises", - "AlternativeTitle": "Título Alternativo", "AllMoviesHiddenDueToFilter": "Todos os filmes estão ocultos devido ao filtro aplicado.", "All": "Todos", - "Agenda": "Agenda", "Age": "Tempo de vida", - "AddRemotePathMapping": "Adicionar Mapeamento de Caminho Remoto", "AddNewTmdbIdMessage": "Você também pode procurar usando o ID de um filme no TMDb. P. ex. tmdb:71663", - "AddNewMovie": "Adicionar Novo Filme", "AddNewMessage": "É facil adicionar um novo filme, apenas comece a escrever o nome do filme que quer adicionar", - "AddNew": "Adicionar Novo", "AddMovies": "Adicionar Filmes", - "AddList": "Adicionar Lista", "AddExclusion": "Adicionar Exclusão", "Added": "Adicionado", - "Activity": "Atividade", "Actions": "Ações", "About": "Informações", - "AvailabilityDelay": "Espera de Disponibilidade", "AutoUnmonitorPreviouslyDownloadedMoviesHelpText": "Filmes deletados no disco deixam automaticamente de ser monitorados no Prowlarr", - "AutoRedownloadFailedHelpText": "Automaticamente busque e tente baixar uma versão diferente", "Automatic": "Automático", - "AutoDownloadPropersHelpText": "O Prowlarr deve automaticamente atualizar para propers quando disponível?", "AuthenticationMethodHelpText": "Solicitar nome de utilizador e palavra-passe para acessar ao Prowlarr", "Authentication": "Autenticação", - "AsAllDayHelpText": "Eventos aparecerão como eventos de dia inteiro em seu calendário", "AreYouSureYouWantToResetYourAPIKey": "Tem a certeza que quer repor a Chave da API?", - "AreYouSureYouWantToDeleteThisRemotePathMapping": "Tem certeza que quer deletar este mapeamento de pasta remota?", "AreYouSureYouWantToDeleteThisImportListExclusion": "Tem certeza que quer deletar esta exclusão de lista de importação?", - "AreYouSureYouWantToDeleteThisDelayProfile": "Tem certeza que quer deletar este perfil de espera?", "ApplyTags": "Aplicar etiquetas", "AppDataDirectory": "Pasta AppData", "ApiKey": "Chave da API", "AnalyticsEnabledHelpText": "Envia informações anônimas de uso e de erros aos servidores do Prowlarr. Isso inclui informações sobre seu browser, páginas utilizadas na WebUI do Prowlarr, relatórios de erros, bem como as versões do sistema operativo e da aplicação. Utilizaremos essas informações para priorizar funcionalidades e correções de bugs.", - "AnalyseVideoFiles": "Analizar arquivos de vídeo", "AlreadyInYourLibrary": "Já está em sua biblioteca", - "AllowHardcodedSubsHelpText": "Legendas embutidas que sejam detectadas serão automaticamente baixadas", "AllowHardcodedSubs": "Permitir Legendas Embutidas", - "AgeWhenGrabbed": "Tempo de vida (quando capturado)", "AddMoviesMonitored": "Adicionar Filmes Monitorados", - "AddListExclusion": "Adicionar Exclusão de Lista", "QualitySettings": "Definições de qualidade", - "QualityCutoffHasNotBeenMet": "Ponto de corte de qualidade não foi alcançado", "PublishedDate": "Data de Publicação", "ProxyType": "Tipo de proxy", - "ProtocolHelpText": "Escolha que protocolo(s) utilizar e qual o preferido ao escolher entre versões iguais", "PreferIndexerFlagsHelpText": "Priorizar versões com marcas especiais", - "PreferIndexerFlags": "Preferir Flags do Indexador", "PortNumber": "Número da porta", "Port": "Porta", - "Permissions": "Permissões", "Password": "Palavra-passe", "PageSizeHelpText": "Número de itens por página", "PackageVersion": "Versão do pacote", - "Original": "Original", "OpenBrowserOnStart": "Abrir browser ao iniciar", - "OnUpgradeHelpText": "Notificar quando filmes tiverem upgrade para uma melhor qualidade", "OnRenameHelpText": "Ao Renomear", "OnHealthIssueHelpText": "Ao ter problemas no estado de funcionamento", - "OnGrabHelpText": "Ao Capturar", "OnDownloadHelpText": "Notificar quando os filmes forem importados com sucesso", - "NotMonitored": "Não Monitorado", "NotificationTriggers": "Acionadores de notificação", - "NotAvailable": "Não Disponível", "NoMinimumForAnyRuntime": "Sem mínimo para tempo de execução", "NoLimitForAnyRuntime": "Sem limite de tempo de execução", "NoLeaveIt": "Não, deixe-o", "New": "Novo", "NetCore": ".NET", - "NamingSettings": "Ajustes de Nomeação", "MustNotContain": "Não Deve Conter", - "MustContain": "Deve Conter", "MovieYearHelpText": "Ano do filme a excluir", - "MovieYear": "Ano do Filme", "MovieTitleHelpText": "Título do filme para excluir (pode ser qualquer palavra)", - "MovieIsDownloading": "O Filme está baixando", "MovieInfoLanguageHelpTextWarning": "Será necessário reiniciar o navegador", - "MovieID": "ID do Filme", "MovieFolderFormat": "Formato da Pasta de Filme", - "MovieFiles": "Arquivos de Filme", "MovieAvailableButMissing": "Filme Disponível, mas Ausente", "MonoVersion": "Versão do Mono", - "MonitoredHelpText": "Baixar Filme se disponível", "Mode": "Modo", "MinimumLimits": "Limites mínimos", - "MinimumFreeSpaceWhenImportingHelpText": "Evitar a importação caso deixe menos espaço livre em disco que esta quantidade", "MinimumFreeSpace": "Espaço Livre Mínimo", - "MinimumAgeHelpText": "Somente Usenet: Tempo de espera mínimo, em minutos, dos NZBs, para que sejam baixados. Use isto para dar às novas versões tempo de propagar-se em seu provedor de usenet.", "MinimumAge": "Tempo de Vida Mínimo", - "MinFormatScoreHelpText": "Pontuação mínima permitida no formato personalizado para baixar", "MetadataSettings": "Ajustes de Metadados", - "MediaManagementSettings": "Ajustes de Gerenciamento Multimídia", "MediaInfo": "Informação Multimídia", "Mechanism": "Mecanismo", - "MaximumSizeHelpText": "Tamanho máximo de uma versão para ser importada, em MB. Ajuste para zero para ilimitado", "MaximumSize": "Tamanho Máximo", "MaximumLimits": "Limites máximos", "Logs": "Logs", "LogLevel": "Nível de log", - "Local": "Local", "ListUpdateInterval": "Intervalo de Atualização das Listas", - "ListSettings": "Ajustes da Lista", "Links": "Links", - "LanguageHelpText": "Idioma das Versões", "Interval": "Intervalo", - "IndexerSettings": "Ajustes do Indexador", "IndexerFlags": "Sinalizadores do indexador", - "IncludeUnmonitored": "Incluir Não Monitorados", "IncludeUnknownMovieItemsHelpText": "Mostrar items sem um filme na fila, isso pode incluir filmes removidos, filmes ou qualquer outra coisa na categoria Prowlarr", "IncludeHealthWarningsHelpText": "Incluir avisos de estado de funcionamento", - "IncludeCustomFormatWhenRenamingHelpText": "Incluir no formato de renomeação {Custom Formats}", "IncludeCustomFormatWhenRenaming": "Incluir Formato Personalizado ao Renomear", - "ImportMovies": "Importar Filmes", "Importing": "Importando", - "ImportExtraFilesHelpText": "Importar arquivos extras correspondentes (legendas, nfo, etc.) depois de importar o arquivo do filme", "ImportExtraFiles": "Importar Arquivos Extras", - "ImportedTo": "Importado Para", "IllRestartLater": "Reiniciarei mais tarde", - "IgnoredHelpText": "A versão será rejeitada caso contenha um ou mais destes termos (sem distinção de maiúsculas ou minúsculas)", "IgnoreDeletedMovies": "Ignorar Filmes Deletados", "IgnoredAddresses": "Endereços ignorados", - "IconForCutoffUnmet": "Ícone para Ponto de Corte Não-alcançado", "ICalHttpUrlHelpText": "Copie este endereço para sua aplicação ou clique para registrar-se caso seu navegador suporte webcal", - "ICalFeed": "Feed iCal", "Hostname": "Nome do anfitrião", - "HelpText": "Intervalo em minutos. Coloque zero para desabilitar (isso irá parar toda a captura automática)", "Group": "Grupo", - "GrabRelease": "Capturar Versão", "GrabID": "Capturar ID", - "Grab": "Capturar", "Global": "Global", "GeneralSettings": "Definições gerais", - "FollowPerson": "Seguir Pessoa", "Folders": "Pastas", "Fixed": "Corrigido", - "FirstDayOfWeek": "Primeiro Dia da Semana", "FileNames": "Nomes de Arquivos", - "FileDateHelpText": "Mudar data do arquivo ao importar/varrer", "FileChmodMode": "Modo CHMOD de arquivo", - "Exluded": "Excluído", "Ended": "Finalizado", "EnableSslHelpText": " Requer reinício da aplicação como administrador para aplicar alterações", "EnableSSL": "Ativar SSL", - "EnableRSS": "Ativar RSS", "EnableMediaInfoHelpText": "Extraia informações de vídeo como resolução, tempo de execução e informações de codec dos ficheiros. Isso requer que o Prowlarr leia partes do ficheiro, o que pode causar alta atividade do disco ou da rede durante as análises.", "EnableInteractiveSearch": "Ativar pesquisa interativa", "EnableHelpText": "Ativar criação do ficheiro de metadados para este tipo de metadados", @@ -459,61 +296,39 @@ "EnableAutomaticAdd": "Ativar adição automática", "EnableAutoHelpText": "Se ativado, os filmes desta lista serão automaticamente adicionados ao Prowlarr", "Enable": "Ativar", - "EditPerson": "Editar Pessoa", "EditMovie": "Editar Filme", - "Edition": "Edição", "DownloadWarningCheckDownloadClientForMoreDetails": "Alerta de download: verifique mais detalhes no gerenciador de downloads", - "DownloadPropers": "Baixar Propers", "DownloadFailedCheckDownloadClientForMoreDetails": "Falha no download: verifique mais detalhes no gerenciador de downloads", "DownloadClientSettings": "Definições do cliente de transferências", "Docker": "Docker", - "DestinationRelativePath": "Caminho Relativo de Destino", "DestinationPath": "Caminho de Destino", "DeleteTag": "Eliminar etiqueta", - "DeleteSelectedMovieFiles": "Deletar Arquivos de Filme Selecionados", "DeleteRestriction": "Deletar Restrição", - "DeleteQualityProfile": "Deletar Perfil de Qualidade", "DeleteNotification": "Eliminar notificação", - "DeleteList": "Deletar Lista", "DeleteIndexer": "Eliminar indexador", - "DeleteImportListExclusion": "Apagar Exclusão de Lista de Importação", "DeleteFile": "Apagar arquivo", - "DeleteEmptyFoldersHelpText": "Deletar pastas de filmes vazias durante a varredura de disco e quando arquivos de filmes são apagados", "DeleteEmptyFolders": "Deletar pastas vazias", "DeleteDownloadClient": "Eliminar cliente de transferências", - "DeleteDelayProfile": "Deletar Perfil de Espera", "DeleteCustomFormat": "Deletar Formato Personalizado", "DeleteBackup": "Eliminar cópia de segurança", "DelayProfile": "Perfil de atraso", "DBMigration": "Migração da base de dados", - "CutoffHelpText": "Quando esta qualidade for alcançada, o Prowlarr não irá mais baixar filmes", "CutoffFormatScoreHelpText": "Quando esta pontuação do formato personalizado for alcançada, o Prowlarr não irá mais baixar filmes", - "CustomFormatsSettings": "Ajustes Personalizados de Formatos", "CreateGroup": "Criar grupo", - "CreateEmptyMovieFoldersHelpText": "Criar pastas ausentes para filmes durante a varredura de disco", "CreateEmptyMovieFolders": "Criar pastas vazias para filmes", - "CopyUsingHardlinksHelpTextWarning": "Ocasionalmente, bloqueios de arquivos podem impedir a renomeação de arquivos que ainda estão em modo seed. Você pode temporariamente desabilitar o seeding e usar a função de renomeação do Prowlarr como uma solução alternativa.", "CopyUsingHardlinksHelpText": "Usar Hardlinks ao tentar copiar arquivos a partir de torrents que ainda estão em modo seed", "ConnectSettings": "Definições de ligação", - "Conditions": "Condições", "ColonReplacementFormatHelpText": "Mude a forma como o Prowlarr lida com a substituição de dois-pontos", - "ColonReplacement": "Substituição de dois-pontos", "CloneProfile": "Clonar perfil", "CloneIndexer": "Clonar indexador", - "CloneFormatTag": "Clonar Tag de Formato", "ClickToChangeQuality": "Clique para mudar a qualidade", - "ClickToChangeLanguage": "Clique para mudar o idioma", "CleanLibraryLevel": "Limpar Nível da Biblioteca", - "CheckForFinishedDownloadsInterval": "Intervalo de verificação de Downloads Terminados", "ChangeHasNotBeenSavedYet": "A mudança ainda não foi guardada", - "ChangeFileDate": "Modificar Data do Arquivo", "CertificationCountryHelpText": "Selecionar País para Certificação de Filmes", - "CertificationCountry": "País de certificação", "CertificateValidationHelpText": "Mudar nível de restrição da validação da certificação HTTPS", "CertificateValidation": "Validação de certificado", "BypassProxyForLocalAddresses": "Ignorar proxy para endereços locais", "Branch": "Ramificação", - "BlacklistRelease": "Bloquear Versão", "BlacklistHelpText": "Evite que o Prowlarr tente automaticamente capturar esta versão do filme novamente", "BindAddressHelpText": "Endereço IP4 válido ou \"*\" para todas as interfaces", "BindAddress": "Endereço de vínculo", @@ -521,57 +336,38 @@ "BackupFolderHelpText": "Caminhos relativos estarão na pasta AppData do Prowlarr", "BackupIntervalHelpText": "Intervalo entre cópias de segurança automáticas", "BackupRetentionHelpText": "Cópias de segurança automáticas anteriores ao período de retenção serão eliminadas automaticamente", - "Cutoff": "Corte", "CustomFormatJSON": "JSON Personalizado", - "CouldNotFindResults": "Nenhum resultado encontrado para '{0}'", "ClientPriority": "Prioridade do cliente", - "ClickToChangeMovie": "Clique para modificar filme", "CheckDownloadClientForDetails": "verifique o gerenciador de downloads para mais detalhes", - "CantFindMovie": "Por que não consigo encontrar meu filme?", "CancelPendingTask": "Tem a certeza que quer cancelar esta tarefa pendente?", "BranchUpdateMechanism": "Ramificação utilizada pelo mecanismo externo de atualização", "BranchUpdate": "Ramificação utilizada para atualizar o Prowlarr", "BeforeUpdate": "Antes de atualizar", - "AvailabilityDelayHelpText": "Quantidade de tempo antes ou depois da data de disponibilidade para buscar por Filme", "ApplyTagsHelpTexts4": "Substituir: mudar as etiquetas pelas adicionadas (deixe em branco para limpar todas as etiquetas)", "ApplyTagsHelpTexts3": "Remover: eliminar as etiquetas adicionadas", "ApplyTagsHelpTexts2": "Adicionar: agregar as etiquetas à lista existente de etiquetas", "ApplyTagsHelpTexts1": "Como aplicar etiquetas aos indexadores selecionados", - "AllowMovieChangeClickToChangeMovie": "Clique para trocar o filme", "AddingTag": "A adicionar etiqueta", - "AddImportExclusionHelpText": "Impedir filme de ser adicionado ao Prowlarr através de listas", "DelayingDownloadUntilInterp": "Suspendendo download até {0} às {1}", - "CopyToClipboard": "Copiar à Área de Transferência", "VisitGithubCustomFormatsAphrodite": "Acesse o Github para mais detalhes: ", - "UnableToLoadCustomFormats": "Não é possível carregar Formatos Personalizados", "UnableToAddANewCustomFormatPleaseTryAgain": "Não foi possível adicionar um novo formato personalizado, tente novamente.", - "RequiredHelpText": "Esta condição {0} deve ser atendida para que o formato personalizado seja aplicado. Caso contrário, apenas correspondendo a {1} é suficiente.", "NegateHelpText": "Se marcado, o formato personalizado não se aplicará se esta condição {0} for atendida.", - "ImportCustomFormat": "Importar Formato Personalizado", "ExportCustomFormat": "Exportar Formato Personalizado", - "CustomFormatUnknownConditionOption": "Opção '{0}' desconhecida para condição '{1}'", "CustomFormatUnknownCondition": "Condição de Formato Personalizado '{0}' desconhecida", - "CloneCustomFormat": "Clonar Formato Personalizado", "AutomaticSearch": "Pesquisa automática", "UnableToLoadIndexers": "Não foi possível carregar os indexadores", - "UnableToLoadIndexerOptions": "Não é possível carregar as opções do indexador", "UnableToAddANewIndexerPleaseTryAgain": "Não foi possível adicionar um novo indexador, tenta novamente.", - "TestAllIndexers": "Testar Todos os Indexadores", "RSSSyncIntervalHelpTextWarning": "Isto se aplicará a todos os indexadores, siga as regras estabelecidas por eles", "RSSIsNotSupportedWithThisIndexer": "RSS não é suportado por esse indexador", "ProwlarrSupportsAnyIndexer": "O Prowlarr suporta qualquer indexador que usa o padrão Newznab, bem como os outros indexadores listados abaixo.", "IndexerPriorityHelpText": "Prioridade do indexador de 1 (mais alta) a 50 (mais baixa). Padrão: 25.", "IndexerPriority": "Prioridade do indexador", - "ForMoreInformationOnTheIndividualIndexers": "Para mais informações sobre cada indexador, clique nos botões de informação.", "EnableInteractiveSearchHelpTextWarning": "Este indexador não suporta pesquisas", "EditIndexer": "Editar indexador", "DeleteIndexerMessageText": "Tem a certeza que quer eliminar o indexador \"{0}\"?", "AddIndexer": "Adicionar indexador", - "UsenetDelayHelpText": "Tempo de espera, em minutos, para aguardar antes de capturar uma versão de Usenet", "ShowCutoffUnmetIconHelpText": "Mostrar ícone para arquivos quando o ponto de corte não tiver sido alcançado", - "ReleaseRejected": "Versão Rejeitada", "SetPermissions": "Definir Permissões", - "SearchForMovie": "Buscar filme", "ScriptPath": "Caminho do script", "Retention": "Retenção", "Result": "Resultado", @@ -580,247 +376,156 @@ "RestartNow": "Reiniciar agora", "ResetAPIKey": "Repor chave da API", "Reset": "Repor", - "RequiredPlaceHolder": "Adicionar nova restrição", "ReplaceIllegalCharacters": "Substituir Caracteres Ilegais", - "Reorder": "Reordenar", "RenameMovies": "Renomear Filmes", "RemovingTag": "Eliminando etiqueta", - "RemoveFromQueue": "Remover da fila", "RemoveFromDownloadClient": "Remover do Gerenciador de Downloads", - "RemoveFromBlacklist": "Remover da blacklist", "RemoveFilter": "Remover filtro", - "Remove": "Remover", "RefreshMovie": "Atualizar filme", - "RefreshInformationAndScanDisk": "Atualizar informações e varrer o disco", "Redownload": "Baixar novamente", - "RecyclingBinCleanup": "Limpeza da Lixeira", "RecyclingBin": "Lixeira", - "Reason": "Razão", "Real": "Real", "ReadTheWikiForMoreInformation": "Leia a Wiki para obter mais informações", - "ProwlarrTags": "Tags do Prowlarr", "Prowlarr": "Prowlarr", - "Queued": "Em Fila", "Priority": "Prioridade", "Pending": "Pendente", - "Paused": "Pausado", "OnDeleteHelpText": "Ao Apagar", "NoUpdatesAreAvailable": "Não há atualizações disponíveis", "NoTagsHaveBeenAddedYet": "Você ainda não adicionou etiquetas", "NoLogFiles": "Sem ficheiros de log", - "NoHistory": "Sem histórico", "NoBackupsAreAvailable": "Não há cópias de segurança disponíveis", - "MoviesSelectedInterp": "{0} Filme(s) Selecionado(s)", "MovieIsUnmonitored": "O filme não é monitorado", "MinutesSixty": "60 minutos: {0}", "MinutesNinety": "90 minutos: {0}", "MinutesHundredTwenty": "120 minutos: {0}", "MIA": "Desaparecidos", - "MarkAsFailedMessageText": "Tem certeza de que quer marcar '{0}' como falhado?", "MarkAsFailed": "Marcar como falhado", "Manual": "Manual", - "LoadingMovieFilesFailed": "Falha no carregamento dos arquivos do filme", "LoadingMovieExtraFilesFailed": "Falha no carregamento dos arquivos extras do filme", - "LoadingMovieCreditsFailed": "Falha no carregamento dos créditos do filme", "LinkHere": "aqui", - "LastDuration": "Duração", "InteractiveSearch": "Pesquisa interativa", - "IncludeProwlarrRecommendations": "Incluir recomendações do Prowlarr", "ImportListSyncIntervalHelpText": "Frequência com que o Prowlarr sincroniza suas listas.", - "ImportListStatusCheckSingleClientMessage": "Listas indisponíveis devido a erros: {0}", "ImportListStatusCheckAllClientMessage": "Todas as listas estão indisponíveis devido a erros", - "ImportFailedInterp": "Falha na importação: {0}", "ImportFailed": "Falha na importação: {0}", - "IgnoredPlaceHolder": "Adicionar nova restrição", "HiddenClickToShow": "Oculto, clique para mostrar", - "HaveNotAddedMovies": "Você ainda não adicionou nenhum filme ainda. Você quer importar alguns ou todos seus filmes primeiro?", "GrabReleaseMessageText": "O Prowlarr não foi capaz de determinar a que filme pertence esta versão. O Prowlarr pode ser incapaz de automaticamente importar esta versão. Deseja capturar '{0}'?", - "GoToInterp": "Ir para {0}", "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Para mais informações sobre cada lista de importação, clique nos botões de informação.", "ForMoreInformationOnTheIndividualDownloadClients": "Para obter mais informações sobre cada cliente de transferências, clique nos botões de informação.", "FilterPlaceHolder": "Indexadores de pesquisa", - "FileChmodHelpTexts2": "O mesmo modo é aplicado às pastas e subpastas dos filmes com o bit de executável adicionado. P. ex. 0644 torna-se 0755", "FileChmodHelpTexts1": "Octal, aplicado aos arquivos multimídia ao serem importados/renomeados pelo Prowlarr", - "FailedLoadingSearchResults": "Erro ao carregar resultados da busca. Por favor, tente novamente.", "ExtraFileExtensionsHelpTexts2": "Exemplos: '.sub, .nfo' ou 'sub,nfo'", - "ExtraFileExtensionsHelpTexts1": "Lista separada por vírgulas de arquivos extras a importar (.nfo será importado como .nfo-orig)", "ExistingTag": "Etiqueta existente", - "TmdbIdHelpText": "ID TMDb do filme a ser ignorado", "MovieExcludedFromAutomaticAdd": "Filme Ignorado da Inclusão Automática", - "MovieAlreadyExcluded": "Filme já Ignorado", "ExcludeMovie": "Ignorar Filme", - "Excluded": "Ignorado", "Exception": "Exceção", - "ErrorLoadingPreviews": "Erro ao carregar pré-visualizações", "ErrorLoadingContents": "Erro ao carregar conteúdo", "EnableInteractiveSearchHelpText": "Será utilizado ao realizar uma pesquisa interativa", "EnableAutomaticSearchHelpTextWarning": "Será utilizado ao realizar uma pesquisa interativa", "EnableAutomaticSearchHelpText": "Será utilizado ao realizar pesquisas automáticas através da IU ou pelo Prowlarr", - "DownloadWarning": "Alerta de download: {0}", "DownloadPropersAndRepacksHelpTextWarning": "Use palavras preferidas para atualizações automáticas a propers/repacks", "PreferredSize": "Tamanho preferido", - "DownloadPropersAndRepacksHelpText2": "Use 'Não Preferir' para ordenar por score de palavras preferidas em vez de propers/repacks", "DownloadPropersAndRepacksHelpText1": "Atualizar automaticamente ou não para Propers/Repacks", - "DownloadPropersAndRepacks": "Propers e Repacks", "Downloading": "Transferindo", - "DownloadFailedInterp": "Falha no download: {0}", "DownloadFailed": "Falha no download", - "DownloadedButNotMonitored": "Baixado, mas não Monitorado", "DownloadedAndMonitored": "Baixado e Monitorado", "DownloadClientUnavailable": "O cliente de transferências está indisponível", "Disabled": "Desativado", "DeleteTagMessageText": "Tem a certeza que quer eliminar a etiqueta \"{0}\"?", - "DeleteSelectedMovieFilesMessage": "Tem certeza que quer apagar os arquivos de filme selecionados?", "DeleteRestrictionHelpText": "Tem certeza que quer deletar esta restrição?", "DeleteNotificationMessageText": "Tem a certeza que quer eliminar a notificação \"{0}\"?", - "DeleteListMessageText": "Tem certeza que quer deletar a lista '{0}'?", "DeleteDownloadClientMessageText": "Tem a certeza que quer eliminar o cliente de transferências \"{0}\"?", "DeleteBackupMessageText": "Tem a certeza que quer eliminar a cópia de segurança \"{0}\"?", - "RenameMoviesHelpText": "O Prowlarr usará o nome atual do arquivo se a renomeação estiver desabilitada", "IncludeRecommendationsHelpText": "Incluir filmes recomendados pelo Prowlarr na visão de descobrimento", - "YouCanAlsoSearch": "Você também pode buscar utilizando o ID TMDb ou IMDb de um filme, p. ex. tmdb:71663", "WhitelistedSubtitleTags": "Tags de Legendas Permitidas", - "WhitelistedHardcodedSubsHelpText": "As tags de legenda aqui definidas não serão consideradas como hardcoded", "WeekColumnHeader": "Cabeçalho da Coluna de Semanas", "UrlBaseHelpText": "Para suporte a proxy inverso, vazio por padrão", - "UpgradeUntilThisQualityIsMetOrExceeded": "Atualizar até que esta qualidade seja atingida ou superada", "UpgradeAllowedHelpText": "Se desabilitado, as qualidades não serão atualizadas", "UpdateScriptPathHelpText": "Caminho para um script personalizado que toma um pacote de atualização extraído e lida com o restante do processo da atualização", "UpdateMechanismHelpText": "Utilizar o atualizador do Prowlarr ou um script", "UpdateAutomaticallyHelpText": "Transferir e instalar automaticamente as atualizações. Ainda é possível instalar a partir de Sistema: Atualizações", - "UnmonitoredHelpText": "Incluir filmes não monitorados no feed iCal", "TMDBId": "ID TMDb", - "TimeFormat": "Formato de Hora", "ThisConditionMatchesUsingRegularExpressions": "Esta condição utiliza expressões regulares. Note que os caracteres {0} têm significados especiais e precisam de escape com um {1}", - "TestAllLists": "Testar Todas as Listas", "TestAllClients": "Testar todos os clientes", "TagsHelpText": "Aplica-se a indexadores com pelo menos uma etiqueta correspondente", "TagIsNotUsedAndCanBeDeleted": "A etiqueta não é utilizada e pode ser eliminada", - "SubfolderWillBeCreatedAutomaticallyInterp": "A subpasta '{0}' será criada automaticamente", "StartTypingOrSelectAPathBelow": "Começa a digitar ou seleciona um caminho abaixo", - "StandardMovieFormat": "Formato Padrão de Filme", "SSLCertPathHelpText": "Caminho para o ficheiro PFX", "SSLCertPath": "Caminho do certificado SSL", "SSLCertPasswordHelpText": "Palavra-passe do ficheiro PFX", "SSLCertPassword": "Palavra-passe do certificado SSL", - "SourceRelativePath": "Caminho Relativo de Origem", "SourcePath": "Caminho de Origem", - "SorryThatMovieCannotBeFound": "Desculpe, este filme não foi encontrado.", "SkipFreeSpaceCheckWhenImportingHelpText": "Usar quando o Prowlarr não puder determinar o espaço livre em sua pasta raiz de filmes", - "SkipFreeSpaceCheck": "Pular Verificação de Espaço Livre", "ShowYear": "Mostrar Ano", - "ShowUnknownMovieItems": "Mostrar Itens Desconhecidos do Filme", "ShowTitleHelpText": "Mostrar título do filme abaixo do poster", - "ShowRatings": "Mostrar Avaliações", "ShowQualityProfileHelpText": "Mostrar qualidade do filme abaixo do poster", "ShownClickToHide": "Visível, clique para ocultar", - "ShowMovieInformationHelpText": "Mostrar categorias de filmes e certificação", "ShowMovieInformation": "Mostrar Informações do Filme", - "ShowMonitoredHelpText": "Mostrar status de monitoramento abaixo do poster", "ShowGenres": "Mostrar Categorias", - "ShowCertification": "Mostrar Certificação", "ShowAsAllDayEvents": "Mostar como Eventos de Dia Inteiro", - "ShouldMonitorHelpText": "Se habilitado, filmes desta lista serão adicionados e monitorados", "SettingsRuntimeFormat": "Formato de Tempo de Execução", - "SetPermissionsLinuxHelpTextWarning": "Se você não conhece essa configuração, não a altere.", "SetPermissionsLinuxHelpText": "Deve-se executar CHMOD ao importar/renomear arquivos?", "SendAnonymousUsageData": "Enviar dados anônimos de uso", - "SearchOnAddHelpText": "Buscar os filmes desta lista ao ser adicionada ao Prowlarr", "RSSSyncInterval": "Intervalo de Sincronização de RSS", - "RetryingDownloadInterp": "Nova tentativa de download {0} às {1}", "RetentionHelpText": "Somente Usenet: ajustar para zero para retenção ilimitada", "RestartRequiredHelpTextWarning": "Requer reinício para aplicar alterações", - "RescanMovieFolderAfterRefresh": "Varrer novamente a Pasta do Filme após Atualizar", "RescanAfterRefreshHelpTextWarning": "O Prowlarr não irá automaticamente detectar mudanças nos arquivos quando a opção selecionada não for \"Sempre\"", - "RescanAfterRefreshHelpText": "Efetuar uma nova varredura na pasta do filme após atualizar o filme", "ReplaceIllegalCharactersHelpText": "Substituir caracteres ilegais. Se desmarcado, o Prowlarr irá removê-los", - "ReleaseDates": "Datas de Lançamento", "RemoveHelpTextWarning": "Remover irá apagar o download e o(s) arquivo(s) do gerenciador de downloads.", - "RemoveFailedDownloadsHelpText": "Remover downloads falhados do histórico do gerenciador de downloads", "RemoveCompletedDownloadsHelpText": "Remover downloads importados do histórico do gerenciador de downloads", - "RecycleBinCleanupDaysHelpText": "Ajuste para 0 para desabilitar a limpeza automática", "ProwlarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "O Radar suporta condições personalizadas em relação às propriedades das versões abaixo.", - "ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "O Prowlarr suporta qualquer lista RSS de filmes, bem como os demais listados abaixo.", "ProwlarrSupportsAnyDownloadClient": "O Prowlarr suporta qualquer dos clientes de transferências listados abaixo.", - "QualityProfileDeleteConfirm": "Tem certeza que quer deletar o perfil de qualidade {0}", "ProxyUsernameHelpText": "Apenas insira o utilizador e a palavra-passe caso seja requerido. Caso contrário, deixe em branco.", "ProxyPasswordHelpText": "Apenas insira o utilizador e a palavra-passe caso seja requerido. Caso contrário, deixe em branco.", "ProxyBypassFilterHelpText": "Utilizar \",\" como separador e \"*.\" como caráter universal para subdomínios", - "Proper": "Proper", "MovieInfoLanguage": "Idioma das Informações dos Filmes", "MaintenanceRelease": "Versão de manutenção", - "TorrentDelay": "Espera para Torrents", "UsenetDelay": "Espera para Usenet", - "UnableToLoadDelayProfiles": "Não foi possível carregar os Perfis de Espera", "TorrentDelayHelpText": "Espera em minutos para aguardar antes de capturar um torrent", "PriorityHelpText": "Priorizar múltiplos clientes de transferências. Utilizaremos round robin para clientes com a mesma prioridade.", "RemovedFromTaskQueue": "Eliminado da fila de tarefas", - "ReleaseWillBeProcessedInterp": "A versão será processada {0}", "RegularExpressionsCanBeTested": "Expressões regulares podem ser testadas ", - "RecycleBinHelpText": "Arquivos de filmes virão para cá ao serem deletados em vez de serem permanentemente apagados", "RecycleBinCleanupDaysHelpTextWarning": "Arquivos na lixeira serão excluídos automaticamente após o número de dias selecionado", - "MovieIsOnImportExclusionList": "O filme está na Lista de Exclusão de Importação", "MovieIsMonitored": "Filme é monitorado", - "MovieIsDownloadingInterp": "Filme baixando - {0}% {1}", "MovieInfoLanguageHelpText": "Idioma usado pelo Prowlarr na UI para as Informações dos Filmes", - "MoreDetails": "Mais detalhes", "MissingNotMonitored": "Ausente, não Monitorado", - "MissingMonitoredAndConsideredAvailable": "Ausente, Monitorado e considerado Disponível", "LogLevelTraceHelpTextWarning": "O registo de rasteio somente deve ser ativado temporariamente", - "ListSyncLevelHelpText": "Filmes na biblioteca serão removidos ou não mais monitorados se não estiverem em sua lista", "LaunchBrowserHelpText": " Abrir o browser e a home page do Prowlarr ao iniciar a aplicação.", "TagCannotBeDeletedWhileInUse": "Não é possível eliminar enquanto estiver em uso", "SuggestTranslationChange": "Sugerir mudança na tradução", "StartupDirectory": "Diretório de arranque", "SSLPort": "Porta SSL", "YesCancel": "Sim, cancelar", - "WaitingToProcess": "Aguardando para Processar", "WaitingToImport": "Aguardando para Importar", "Version": "Versão", "Username": "Nome de utilizador", "UseProxy": "Usar proxy", "Usenet": "Usenet", - "UseHardlinksInsteadOfCopy": "Usar Hardlinks em vez de Copiar", "URLBase": "URL base", "Uptime": "Tempo de atividade", - "Unreleased": "Não Lançado", "Ungroup": "Desagrupar", "UnableToLoadUISettings": "Não foi possível carregar as definições da IU", - "UnableToLoadTheCalendar": "Não foi possível carregar o calendário", "UnableToLoadTags": "Não foi possível carregar as etiquetas", - "UnableToLoadRootFolders": "Não foi possível carregar as pastas raízes", "UnableToLoadRestrictions": "Não foi possível carregar as Restrições", - "UnableToLoadRemotePathMappings": "Não foi possível carregar os Mapeamentos de Caminhos Remotos", "UnableToLoadQualityProfiles": "Não foi possível carregar os Perfis de Qualidade", "UnableToLoadQualityDefinitions": "Não foi possível carregar as definições de qualidade", - "UnableToLoadQualities": "Não foi possível carregar as qualidades", "UnableToLoadNotifications": "Não foi possível carregar as notificações", - "UnableToLoadNamingSettings": "Não foi possível carregar os ajustes de Nomenclatura", "UnableToLoadMovies": "Não foi possível carregar os filmes", - "UnableToLoadMetadata": "Não foi possível carregar os Metadados", "UnableToLoadMediaManagementSettings": "Não foi possível carregar os ajustes de Gerenciamento Multimídia", - "UnableToLoadLists": "Não foi possível carregar as Listas", "UnableToLoadListOptions": "Não foi possível carregar as opções de lista", - "UnableToLoadListExclusions": "Não foi possível carregar as Exclusões de Lista", "UnableToLoadLanguages": "Não foi possível carregar os idiomas", "UnableToLoadHistory": "Não foi possível carregar o histórico", "UnableToLoadGeneralSettings": "Não foi possível carregar as definições gerais", "UnableToLoadDownloadClients": "Não foi possível carregar os clientes de transferências", - "UnableToLoadDownloadClientOptions": "Não foi possível carregar as opções do gerenciador de downloads", "UnableToLoadBlacklist": "Não foi possível carregar a blacklist", - "UnableToAddANewConditionPleaseTryAgain": "Não foi possível adicionar uma nova condição, tente novamente.", "UnableToAddANewDownloadClientPleaseTryAgain": "Não foi possível adicionar um novo cliente de transferências, tenta novamente.", "UnableToLoadBackups": "Não foi possível carregar as cópias de segurança", - "UnableToAddANewRemotePathMappingPleaseTryAgain": "Não foi possível adicionar um novo caminho remoto, tente novamente.", "UnableToAddANewQualityProfilePleaseTryAgain": "Não foi possível adicionar um novo perfil de qualidade, tente novamente.", "UnableToAddANewNotificationPleaseTryAgain": "Não foi possível adicionar uma nova notificação, tenta novamente.", - "UnableToAddANewListExclusionPleaseTryAgain": "Não foi possível adicionar uma nova exclusão de lista, tente novamente.", "UnableToAddANewListPleaseTryAgain": "Não foi possível adicionar uma nova lista, tente novamente.", "UISettings": "Definições da IU", "UILanguageHelpTextWarning": "É preciso reiniciar o browser", "UILanguageHelpText": "Idioma que o Prowlarr usará para a IU", "UILanguage": "Idioma da IU", - "TotalFileSize": "Tamanho Total do Arquivo", "Torrents": "Torrents", "FocusSearchBox": "Focar no campo de pesquisa", "CloseCurrentModal": "Fechar pop-up atual", @@ -831,27 +536,17 @@ "MovieIndexScrollBottom": "Índice do filme: deslocar para baixo", "MovieDetailsPreviousMovie": "Detalhes do filme: filme anterior", "MovieDetailsNextMovie": "Detalhes do filme: próximo filme", - "Blacklisted": "Na Lista Negra", "StartSearchForMissingMovie": "Iniciar busca por filme", - "StartProcessing": "Iniciar Processamento", "StartImport": "Iniciar Importação", - "SearchFailedPleaseTryAgainLater": "Falha na busca, tente novamente.", "RequiredRestrictionPlaceHolder": "A versão deve conter pelo menos um destes termos (maiúsculas ou minúsculas)", - "Released": "Lançado", "ProcessingFolders": "Processando Pastas", - "NoMatchFound": "Nenhum resultado encontrado!", "ImportRootPath": "Indique para o Prowlarr a pasta que contém todos os seus filmes, não um filme específico. p.ex. {0} e não {1}", - "ImportIncludeQuality": "Certifique-se que seus arquivos indiquem a qualidade em seus nomes, p.ex. {0}", "ImportErrors": "Importar Erros", - "Existing": "Presente", "EditRestriction": "Editar Restrição", - "Digital": "Digital", "CancelProcessing": "Cancelar Processamento", - "AddRestriction": "Adicionar Restrição", "AddMovie": "Adicionar Filme", "SettingsConsoleLogLevel": "Nível de registo do console", "SearchIndexers": "Pesquisar indexadores", - "NewznabVipCheckExpiringClientMessage": "Os benefícios VIP do indexador estão prestes a expirar: {0}", "NewznabVipCheckExpiredClientMessage": "Os benefícios VIP do indexador expiraram: {0}", "IndexersSelectedInterp": "{0} indexador(es) selecionado(s)", "IndexerRss": "RSS do indexador", diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index 33c4b46d3..a81c9b7e1 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -28,7 +28,6 @@ "LaunchBrowserHelpText": " Abrir o navegador Web e navegar até a página inicial do Prowlarr ao iniciar o aplicativo.", "MonoNotNetCoreCheckMessage": "Atualize para a versão .NET Core do Prowlarr", "MonoTlsCheckMessage": "Solução alternativa para o Prowlarr Mono 4.x tls ainda habilitada, considere remover a opção de ambiente MONO_TLS_PROVIDER=legacy", - "NewznabVipCheckExpiringClientMessage": "Os benefícios VIP do indexador estão prestes a expirar: {0}", "NoTagsHaveBeenAddedYet": "Você ainda não adicionou tags", "NotificationTriggers": "Acionadores da notificação", "NoUpdatesAreAvailable": "Não há atualizações disponíveis", @@ -148,7 +147,6 @@ "EnableIndexer": "Habilitar indexador", "EnableInteractiveSearch": "Habilitar pesquisa interativa", "EnableInteractiveSearchHelpTextWarning": "A pesquisa não é compatível com este indexador", - "EnableRSS": "Habilitar RSS", "EnableSSL": "Habilitar SSL", "EnableSslHelpText": " Requer a reinicialização com a execução como administrador para fazer efeito", "Error": "Erro", @@ -223,7 +221,6 @@ "Name": "Nome", "NetCore": ".NET", "New": "Novo", - "NewznabVipCheckExpiredClientMessage": "Os benefícios VIP do indexador expiraram: {0}", "NoBackupsAreAvailable": "Não há backups disponíveis", "NoChange": "Sem alteração", "NoChanges": "Sem alterações", diff --git a/src/NzbDrone.Core/Localization/Core/ro.json b/src/NzbDrone.Core/Localization/Core/ro.json index fa9d01e1a..0632da932 100644 --- a/src/NzbDrone.Core/Localization/Core/ro.json +++ b/src/NzbDrone.Core/Localization/Core/ro.json @@ -1,152 +1,97 @@ { "DownloadClientsSettingsSummary": "Clienți de descărcare, abordarea descărcărilor și configurarea căilor externe de stocare", - "CutoffUnmet": "Calitate maximă neatinsă", "DownloadClients": "Clienți de descărcare", "DownloadClientCheckUnableToCommunicateMessage": "Nu pot comunica cu {0}.", "DownloadClientCheckNoneAvailableMessage": "Niciun client de descărcare disponibil", "DownloadClient": "Client de descărcare", - "DotNetVersionCheckOldUnsupportedMessage": "Versiunea {0} de .Net Framework instalată este veche și nesuportată. Fă upgrade la cel puțin versiunea {1}.", "DotNetVersionCheckNotRecommendedMessage": "Versiunea {0} de .Net Framework instalată este acceptată, dar recomandăm instalarea cel puțin a versiunii {1}.", - "DiskSpace": "Spațiul pe disc", "Discover": "Descoperă", - "DigitalRelease": "Lansare Digitală", "Details": "Detalii", - "Deleted": "Șters", "Delete": "Șterge", - "DelayProfiles": "Profile de întârziere", "Day": "Zi", "Dates": "Date", "Date": "Dată", - "CustomFormatsSettingsSummary": "Formate personalizate și setări", "CustomFormats": "Formate personalizate", "CustomFilters": "Filtre personalizate", - "Crew": "Echipa", "ConnectSettingsSummary": "Notificări, conexiuni la servere și aplicații media, scripturi personale", "Connections": "Conexiuni", "Connect": "Conectează", - "CompletedDownloadHandling": "Am finalizat procesarea descărcării", "Collection": "Colecție", "Clear": "Șterge", - "ChooseAnotherFolder": "Alege alt Folder", "Certification": "Certificare", - "Cast": "Distribuție", "Calendar": "Calendar", - "Blacklist": "Listă Neagră", "BackupNow": "Fă o copie de siguranță", "Backup": "Copie de siguranță", "AppDataLocationHealthCheckMessage": "Pentru a preveni ștergerea AppData, update-ul nu este posibil", - "AndNot": "și nu", "Analytics": "Statistici", "All": "Toate", - "Agenda": "Agendă", "AddNewTmdbIdMessage": "Poți căuta și folosind id-ul TMDB al unui film. Ex. tmdb:71663", - "AddNewMessage": "Este ușor să adaugi un film nou, începe să tastezi numele filmului pe care vrei să-l adaugi", "AddNew": "Adaugă", - "AddMovies": "Adaugă Filme", "AddExclusion": "Adaugă Excluziune", "Added": "Adăugat", - "Activity": "Activitate", "Actions": "Acțiuni", "About": "Despre", "IndexerStatusCheckAllClientMessage": "Niciun indexator nu este disponibil datorită eșuărilor", - "IndexersSettingsSummary": "Restricții pentru indexatori și apariții", "IndexerSearchCheckNoInteractiveMessage": "Niciun indexator cu Căutare interactivă nu este activ, Prowlarr nu va afișa niciun rezultat de căutare interactivă", - "IndexerSearchCheckNoAvailableIndexersMessage": "Toți indexatorii ce suportă căutare sunt indisponibili temporar datorită erorilor", "IndexerSearchCheckNoAutomaticMessage": "Niciun indexator cu Căutare automată nu este activ, Prowlarr nu va afișa niciun rezultat de căutare automată", "Indexers": "Indexatori", - "IndexerRssHealthCheckNoIndexers": "Niciun indexator cu sincronizare RSS nu este activ, Prowlarr nu va descărca apariții noi automat", "IndexerRssHealthCheckNoAvailableIndexers": "Toți indexatorii ce suportă rss sunt indisponibili temporar datorită erorilor", "Indexer": "Indexator", - "InCinemas": "În Cinema", "ImportTipsMessage": "Câteva sfaturi pentru a ne asigura că importul este cu succes:", - "ImportSecondTip": "Indică Prowlarr dosarul ce conține toate filmele tale, nu unul specific. Ex.", "ImportMechanismHealthCheckMessage": "Activează Procesarea Descărcărilor finalizate", - "ImportHeader": "Importă filme pe care le ai deja", "ImportFirstTip": "Asigură-te că fișierele au calitatea în nume. Ex.", - "Imported": "Importat", "Import": "Importă", - "Ignored": "Ignorat", "iCalLink": "Legătură iCal", "Host": "Gazdă", "History": "Istorie", "HideAdvanced": "Ascunde Avansat", "Health": "Sănătate", - "GrabSelected": "Prinderea selectată", "Grabbed": "Prins", - "Genres": "Genuri", "GeneralSettingsSummary": "Port, SSL, utilizator/parolă, proxy, statistici și actualizări", "General": "General", - "FreeSpace": "Spațiu Liber", "Formats": "Formate", - "Forecast": "Prognoză", "Folder": "Dosar", "Filter": "Filtru", - "Filesize": "Mărimea fișierului", "Files": "Fișiere", "Filename": "Numele Fișierului", - "FileManagement": "Administrarea de fișiere", "FailedDownloadHandling": "Procesarea descărcării a eșuat", "Failed": "Eșuat", "EventType": "Tip de eveniment", "Events": "Evenimente", "Edit": "Editează", - "Downloaded": "Descărcat", "DownloadClientStatusCheckSingleClientMessage": "Clienții de descărcare sunt indisponibili datorită erorii: {0}", "DownloadClientStatusCheckAllClientMessage": "Toți clienții de descărcare sunt indisponibili datorită erorilor", - "ProfilesSettingsSummary": "Calitate, Limbă și Profile de Întârziere", "Profiles": "Profile", - "PreviewRename": "Previzualizare Redenumire", "PhysicalRelease": "Lansare fizică", "Peers": "Parteneri", - "Path": "Cale", "PageSize": "Mărimea Paginii", - "OutputPath": "Calea pentru Output", "OrganizeModalSuccess": "Succes! Mi-am terminat treaba, niciun fișier de redenumit.", - "OrganizeModalNamingPattern": "Tipar de denumire:", "OrganizeModalDisabled": "Redenumirea este dezactivată, nimic de redenumit", - "OrganizeModalAllPathsRelative": "Toate căile sunt relative față de:", "OrganizeAndRename": "Organizează și Redenumește", - "Organize": "Organizează", "Options": "Opțiuni", "Ok": "Ok", "OAuthPopupMessage": "Browser-ul tău blochează pop-upurile", "NoChanges": "Nicio Modificare", "NoChange": "Nicio Modificare", - "ImportListStatusCheckSingleClientMessage": "Liste indisponibile datorită erorilor: {0}", "ImportListStatusCheckAllClientMessage": "Toate listele sunt indisponibile datorită erorilor", "Name": "Nume", - "MovieTitle": "Titlu Film", "Movies": "Filme", - "MovieNaming": "Denumire Filme", "MovieIndex": "Index Filme", - "MovieEditor": "Editor Filme", "Movie": "Film", - "MoveFiles": "Mută Fișiere", "MountCheckMessage": "Calea ce conține filme este montată în mod de read-only: ", "MoreInfo": "Mai multă informație", - "Month": "Lună", "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls este încă activ, ia în calcul să configurezi MONO_TLS_PROVIDER=legacy în opțiunile de mediu", "MonoNotNetCoreCheckMessage": "Actualizează versiunea de .NET Core a Prowlarr", - "MonitoredOnly": "Doar monitorizate", "Monitored": "Monitorizat", - "Monitor": "Monitorizează", "Missing": "Lipsește", - "MinimumAvailability": "Disponibilitate minimă", "MinAvailability": "Disponibilitate minimă", - "MetadataSettingsSummary": "Creează fișiere de metadata atunci când filmele sunt importate sau reîmprospătate", "Metadata": "Metadata", "Message": "Mesaj", - "MediaManagementSettingsSummary": "Setări administrare denumiri și fișiere", "MediaManagement": "Administrare media", - "MediaInfoDllCheckMessage": "Librăria cu informații media nu a putut fi încărcată {0}", "MassMovieSearch": "Caută filme în masa", - "ManualImport": "Import Manual", "Logging": "Logare", - "LogFilesLocationMessage": "Fișierele de log se află în:", "LogFiles": "Fișiere de loguri", - "Location": "Locație", "ListsSettingsSummary": "Importă Liste, excluderi din listă", - "Lists": "Liste", "ListExclusions": "Excluderi din listă", "Level": "Nivel", "LastWriteTime": "Data ultimei scrieri", @@ -155,12 +100,9 @@ "KeyboardShortcuts": "Scurtături din tastatură", "Info": "Info", "IndexerStatusCheckSingleClientMessage": "Indexator indisponibil datorită erorilor: {0}", - "ImportExistingMovies": "Importă Filme Existente", "HealthNoIssues": "Nicio problemă în configurare", - "HardlinkCopyFiles": "Hardlink/Copiază Fișiere", "Extension": "Extensie", "Error": "Eroare", - "CustomFormatScore": "Scorul formatului personalizat", "ConnectionLostMessage": "Prowlarr a pierdut conexiunea cu backend-ul și trebuie reîncărcat pentru a restabili funcționalitatea.", "ConnectionLostAutomaticMessage": "Prowlarr va încerca să se reconecteze automat sau poți apăsa reîncarcă mai jos.", "ConnectionLost": "Conexiune Pierdută", @@ -168,47 +110,33 @@ "Columns": "Coloane", "Close": "Închide", "Cancel": "Anulează", - "AudioInfo": "Info Audio", "Apply": "Aplică", - "AlternativeTitle": "Titlu alternativ", "AllMoviesHiddenDueToFilter": "Toate filmele sunt ascunse datorită filtrelor aplicate.", "Age": "Vechime", - "AddNewMovie": "Adaugă un film nou", "AddList": "Adaugă listă", - "QualityProfiles": "Profile de Calitate", "QualityProfile": "Profil de Calitate", "QualityDefinitions": "Definiții de calitate", - "Quality": "Calitate", "PtpOldSettingsCheckMessage": "Următorul indexer PassThePopcorn are setări depreciate și ar trebui actualizate: {0}", "ProxyCheckResolveIpMessage": "Nu am putut găsi adresa IP pentru Hostul Proxy Configurat {0}", "ProxyCheckFailedToTestMessage": "Nu am putut testa proxy: {0}", "ProxyCheckBadRequestMessage": "Testul proxy a eșuat. StatusCode: {0}", "Proxy": "Proxy", "Protocol": "Protocol", - "Progress": "Progres", "Year": "An", - "Week": "Săptămână", "Warn": "Atenționare", - "Wanted": "Dorite", "View": "Vizualizare", - "VideoCodec": "Codec Video", "UpdateSelected": "Actualizează selecția", "Updates": "Actualizări", "UpdateCheckUINotWritableMessage": "Nu pot instala actualizarea pentru că dosarul UI '{0}' nu poate fi scris de către utilizatorul '{1}'.", "UpdateCheckStartupTranslocationMessage": "Nu pot instala actualizarea pentru că folderul de pornire '{0}' este într-un folder de App Translocation.", "UpdateCheckStartupNotWritableMessage": "Nu pot instala actualizarea pentru că dosarul '{0}' nu poate fi scris de către utilizatorul '{1}'.", - "UpdateAll": "Actualizează tot", "UnselectAll": "Deselectează tot", - "Unmonitored": "Nemonitorizat", "UnmappedFolders": "Foldere nemapate", - "Unavailable": "Indisponibil", "UISettingsSummary": "Calendar, dată și setări pentru probleme de vedere", "UI": "Interfață Grafica", "Type": "Tip", - "TotalSpace": "Spațiu Total", "Titles": "Titluri", "Title": "Titlu", - "Timeleft": "Timp rămas", "Time": "Timp", "TestAll": "Testează Tot", "Test": "Testează", @@ -220,12 +148,9 @@ "SystemTimeCheckMessage": "Ora sistemului este diferită cu mai mult de 1 zi. Operațiunile programate s-ar putea să nu funcționeze corect până când ora nu este corectată", "System": "Sistem", "Style": "Stil", - "Studio": "Studio", "Status": "Status", - "SourceTitle": "Titlul sursei", "Source": "Sursă", "Sort": "Sortează", - "SizeOnDisk": "Mărime pe disc", "Size": "Mărime", "Shutdown": "Oprește", "ShowAdvanced": "Arată setări avansate", @@ -234,41 +159,26 @@ "SelectAll": "SelecteazăTot", "Seeders": "Partajatori", "Security": "Securitate", - "SearchSelected": "Caută selecția", "SearchForMissing": "Caută ce lipsește", - "SearchFiltered": "Căutare filtrată", "SearchAll": "Caută în toate", "Search": "Caută", "Scheduled": "Programat", "SaveChanges": "Salvează modificările", "Save": "Salvează", - "Runtime": "Durată", "RSSSync": "Sincronizare RSS", - "RootFolders": "Foldere Rădăcină", "RootFolderCheckSingleMessage": "Folder rădăcină lipsă: {0}", - "RootFolderCheckMultipleMessage": "Lipsesc multiple foldere rădăcină: {0}", "RootFolder": "Folder Rădăcină", "Restrictions": "Restricții", "RestoreBackup": "Restaurează salvarea", "Restart": "Repornește", - "RenameFiles": "Redenumește Fișiere", "Renamed": "Redenumit", - "RemoveSelected": "Șterge selecția", "RemoveRootFolder": "Elimină folder rădăcină", - "RemovedMovieCheckSingleMessage": "Filmul {0} a fost șters de pe TMDb", "RemovedMovieCheckMultipleMessage": "Filmele {0} au fost șterse de pe TMBd", - "RemotePathMappings": "Mapări pentru căi externe", "Reload": "Reîncarcă", - "ReleaseTitle": "Titlul Apariției", "ReleaseStatus": "Statusul apariției", - "ReleaseGroup": "Grup de apariție", "ReleaseBranchCheckPreviousVersionMessage": "Branch {0} este pentru o versiune precedentă a Prowlarr, configurează branchul 'Aphrodite' pentru a primi updateuri", "ReleaseBranchCheckOfficialBranchMessage": "Branchul {0} nu este un branch Prowlarr valid, nu vei primi actualizări", - "RelativePath": "Calea Relativă", "RejectionCount": "Numărul Respingerilor", - "RefreshAndScan": "Reîmprospătează și scanează", "Refresh": "Reîmprospătează", - "Ratings": "Recenzii", - "Queue": "Coadă", - "QualitySettingsSummary": "Calitate - mărimi și denumiri" + "Queue": "Coadă" } diff --git a/src/NzbDrone.Core/Localization/Core/ru.json b/src/NzbDrone.Core/Localization/Core/ru.json index 9dbf4612d..f84637fd7 100644 --- a/src/NzbDrone.Core/Localization/Core/ru.json +++ b/src/NzbDrone.Core/Localization/Core/ru.json @@ -1,28 +1,20 @@ { - "Collection": "Коллекция", "Close": "Закрыть", "CloneProfile": "Клонировать профиль", "CloneIndexer": "Клонировать индексер", - "CloneFormatTag": "Клонировать тэг формата", "CloneCustomFormat": "Клонировать пользовательский формат", "ClientPriority": "Приоритет клиента", - "ClickToChangeQuality": "Нажмите чтобы изменить качество", "YouCanAlsoSearch": "Вы так же можете искать используя TMDb id или IMDb id фильма. На пример tmdb:71663", - "AddNewTmdbIdMessage": "Вы так же можете искать, используя TMDb id фильма. На пример tmdb:71663", "Activity": "Активность", - "BlacklistHelpText": "Запретить Prowlarr автоматически добавлять этот фильм", "Blacklisted": "В черном списке", - "Blacklist": "Черный список", "Backups": "Резервные копии", "BackupRetentionHelpText": "Автоматические резервные копии старше указанного периода будут автоматически удалены", "BackupNow": "Сделать резервную копию", "BackupIntervalHelpText": "Периодичность автоматического резервного копирования", "Backup": "Резервная копия", - "AutoUnmonitorPreviouslyDownloadedMoviesHelpText": "Фильмы, удаленные с диска, автоматически перестают отслеживаться", "AutoRedownloadFailedHelpText": "Автоматически искать и пытаться скачать разные релизы", "AutomaticSearch": "Автоматический поиск", "Authentication": "Аутентификация", - "AudioInfo": "Информация о аудио", "AsAllDayHelpText": "События появятся как события на весь день в Вашем календаре", "AreYouSureYouWantToResetYourAPIKey": "Вы уверены, что хотите сбросить Ваш API ключ?", "ApplyTagsHelpTexts3": "Убрать: Убрать введенные тэги", @@ -31,27 +23,18 @@ "AppDataLocationHealthCheckMessage": "Обновление будет не возможно, во избежание удаления данных программы во время обновления", "ApiKey": "API ключ", "Analytics": "Аналитика", - "AlternativeTitle": "Альтернативное название", "AlreadyInYourLibrary": "Уже в вашей библиотеке", - "AllowHardcodedSubs": "Разрешить хардсабы", "AllMoviesHiddenDueToFilter": "Все фильмы спрятаны в соответствии с фильтром.", - "AddRestriction": "Добавить ограничение", "AddRemotePathMapping": "Добавить удаленный путь", - "AddNewMovie": "Добавить новый фильм", "AddNewMessage": "Добавить новый фильм очень просто! Начни печатать название фильма, который хочешь добавить", - "AddNew": "Добавить", "AddMoviesMonitored": "Добавить отслеживаемые фильмы", - "AddMovies": "Добавить фильмы", "AddMovie": "Добавить фильм", - "AddListExclusion": "Добавить исключения списка", "AddList": "Добавить список", "AddIndexer": "Добавить индексер", - "AddImportExclusionHelpText": "Запретить добавлять фильм в Prowlarr из списков", "AddExclusion": "Добавить исключение", "Added": "Добавлено", "Actions": "Действия", "About": "Подробности", - "Deleted": "Удалено", "DeleteCustomFormat": "Удалить пользовательский формат", "DeleteBackupMessageText": "Вы уверены, что хотите удалить резервную копию '{0}'?", "DeleteBackup": "Удалить резервную копию", diff --git a/src/NzbDrone.Core/Localization/Core/sv.json b/src/NzbDrone.Core/Localization/Core/sv.json index 718aa2d70..06bf49e4a 100644 --- a/src/NzbDrone.Core/Localization/Core/sv.json +++ b/src/NzbDrone.Core/Localization/Core/sv.json @@ -1,157 +1,104 @@ { - "AddNew": "Lägg till ny", "AddMovies": "Lägg till film(er)", - "AddExclusion": "Lägg till uteslutning(ar)", "Activity": "Aktivitet", "About": "Om", - "ListExclusions": "Listuteslutningar", "Languages": "Språk", "Language": "Språk", "IndexerStatusCheckSingleClientMessage": "Indexerare otillgängliga på grund av fel: {0}", "IndexerStatusCheckAllClientMessage": "Samtliga indexerare otillgängliga på grund av fel", - "IndexerSearchCheckNoInteractiveMessage": "Inga indexerare tillgängliga med Interaktiv Sök aktiverat, Prowlarr kommer ej tillhandahålla interaktiva sökresultat", "IndexerSearchCheckNoAvailableIndexersMessage": "På grund av nyligen inträffade indexerarfel är alla sök-kapabla indexerare tillfälligt otillgängliga", - "IndexerRssHealthCheckNoAvailableIndexers": "På grund av nyligen inträffade indexerarfel är alla RSS-kapabla indexerare tillfälligt otillgängliga", "IndexerSearchCheckNoAutomaticMessage": "Inga indexerare tillgängliga med Automatisk Sök aktiverat, Prowlarr kommer inte tillhandahålla automatiska sökresultat", "Indexers": "Indexerare", - "IndexerRssHealthCheckNoIndexers": "Inga indexerare med RSS-synk aktiverade, Prowlarr kommer ej hämta nya utgåvor automatiskt", "ImportTipsMessage": "Några tips för att försäkra oss om att importen går smärtfritt:", - "ImportSecondTip": "Peka Prowlarr till mappen som innehåller alla dina filmer, inte en specifik film. T.ex.", "ImportMechanismHealthCheckMessage": "Aktivera Avklarad nedladdningshantering", - "ImportHeader": "Importera filmer du redan har", "ImportFirstTip": "Var noga med att dina filer inkluderar kvalitet i filnamnet. T.ex.", - "Import": "Import", "iCalLink": "iCal-länk", "Host": "Värd", "History": "Historia", "HideAdvanced": "Dölj avancerat", "Health": "Hälsa", - "GrabSelected": "Hämta markerade", "General": "Generell", - "FreeSpace": "Ledigt utrymme", "Formats": "Format", - "Forecast": "Prognos", "Folder": "Mapp", "Filter": "Filter", - "Filesize": "Filstorlek", "Files": "Filer", - "FileManagement": "Filhantering", "FailedDownloadHandling": "Misslyckad nedladdningshantering", "Events": "Händelser", "Edit": "Redigera", - "Downloaded": "Nedladdat", "DownloadClientStatusCheckSingleClientMessage": "Otillgängliga nedladdningsklienter på grund av misslyckade anslutningsförsök: {0}", "DownloadClientStatusCheckAllClientMessage": "Samtliga nedladdningsklienter är otillgängliga på grund av misslyckade anslutningsförsök", "DownloadClients": "Nedladdningsklienter", "DownloadClientCheckUnableToCommunicateMessage": "Kommunikation med {0} ej möjlig.", "DownloadClientCheckNoneAvailableMessage": "Ingen nedladdningsklient tillgänglig", - "DotNetVersionCheckOldUnsupportedMessage": "Nuvarande installationen av .Net Framework {0} är gammal och stöds ej. Var vänlig uppgradera till minst .Net Framework {1}.", "DotNetVersionCheckNotRecommendedMessage": "Nuvarande installationen av .Net Framework {0} har stöd men vi rekommenderar att uppgradera till minst {1}.", - "DiskSpace": "Diskutrymme", "Discover": "Upptäck", "Delete": "Radera", - "DelayProfiles": "Fördröjande profiler", "Day": "Dag", "Dates": "Datum", "Date": "Datum", - "CustomFormats": "Anpassade format", "CustomFilters": "Anpassade Filter", - "Crew": "Filmteam", "Connections": "Anslutningar", "Connect": "Anslut", - "CompletedDownloadHandling": "Avklarad nedladdningshantering", "Clear": "Rensa", - "ChooseAnotherFolder": "Välj annan Mapp", "Cast": "Rollista", - "Calendar": "Kalender", "Blacklist": "Svartlista", "BackupNow": "Säkerhets- kopiera", "Backup": "Säkerhetskopiering", "AppDataLocationHealthCheckMessage": "Uppdatering ej möjlig för att AppData inte skall raderas", - "AndNot": "och ej", "Analytics": "Analys", "All": "Samtliga", - "Agenda": "Agenda", "AddNewTmdbIdMessage": "Du kan även söka genom filmens TMDB-Id, t.ex. tmdb:71663", - "AddNewMessage": "För att lägga till en ny film, börja skriva namnet på filmen du vill lägga till", "MoreInfo": "Mer info", - "Month": "Månad", "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls workaround är aktiverad, överväg att ta bort \"MONO_TLS_PROVIDER=legacy environment\"-alternativet", "MonoNotNetCoreCheckMessage": "Var vänlig uppgradera till .NET Core-versionen av Prowlarr", - "Monitor": "Bevakning", "Missing": "Saknas", - "MinimumAvailability": "Minsta tillgänglighet", "MinAvailability": "Minsta tillgänglighet", - "Metadata": "Metadata", "MediaManagement": "Mediahantering", - "MediaInfoDllCheckMessage": "Bibliotek med mediainfo kunde ej laddas {0}", "ManualImport": "Manuell import", "Logging": "Loggning", - "LogFilesLocationMessage": "Loggfiler är placerade i:", "LogFiles": "Loggfiler", - "Lists": "Listor", "Year": "År", - "Week": "Vecka", "Wanted": "Önskade", "View": "Vy", - "UpdateSelected": "Uppdatera markerade", "Updates": "Uppdateringar", "UpdateCheckUINotWritableMessage": "Ej möjligt att installera uppdatering då användargränssnittsmappen '{0}' inte är skrivbar för användaren '{1}'.", "UpdateCheckStartupTranslocationMessage": "Ej möjligt att installera uppdatering då uppstartsmappen '{0}' är i en \"App translocation\"-mapp.", "UpdateCheckStartupNotWritableMessage": "Ej möjligt att installera uppdatering då uppstartsmappen '{0}' inte är skrivbar för användaren '{1}'.", - "UpdateAll": "Uppdatera samtliga", "UnselectAll": "Avmarkera samtliga", - "Unmonitored": "Obevakade", "UnmappedFolders": "Omappade kataloger", "UISettingsSummary": "Alternativ för kalender, datum och färgblindhet", "UI": "Användargränssnitt", - "Titles": "Titlar", "Timeleft": "Tid kvar", "Tasks": "Uppgifter", "TagsSettingsSummary": "Se samtliga taggar och hur de används. Oanvända taggar kan tas bort", "Tags": "Taggar", "System": "System", "Style": "Stil", - "Studio": "Studio", "Status": "Status", - "SourceTitle": "Källtitel", "Sort": "Sortera", - "SizeOnDisk": "Storlek på disk", "Size": "Storlek", "ShowAdvanced": "Visa avancerat", "Settings": "Inställningar", "SetTags": "Ange taggar", "SelectAll": "Välj samtliga", "Security": "Säkerhet", - "SearchSelected": "Sök markerade", "SearchForMissing": "Sök efter saknade", - "SearchFiltered": "Sök filtrerade", "SearchAll": "Sök samtliga", "Search": "Sök", "Scheduled": "Schemalagt", "SaveChanges": "Spara ändringar", - "Runtime": "Körtid", "RSSSync": "RSS-synk", - "RootFolders": "Rotmappar", "RootFolderCheckSingleMessage": "Rotmapp saknas: {0}", - "RootFolderCheckMultipleMessage": "Flera rotmappar saknas: {0}", "RootFolder": "Rotmapp", "Restrictions": "Restriktioner", - "RemoveSelected": "Radera markerade", "RestoreBackup": "Återställ säkerhetskopia", - "RenameFiles": "Byt namn på filer", "Renamed": "Omdöpt", - "RemovedMovieCheckSingleMessage": "Filmen {0} är borttagen från TMDb", "RemovedMovieCheckMultipleMessage": "Filmerna {0} är borttagna från TMDb", "ReleaseBranchCheckOfficialBranchMessage": "Gren {0} är inte en giltig gren av Prowlarr, du kommer ej erhålla uppdateringar", "ReleaseBranchCheckPreviousVersionMessage": "Gren {0} är ämnad en tidigare version av Prowlarr, välj gren 'Aphrodite' för ytterligare uppdateringar", - "RefreshAndScan": "Uppdatera & Skanna", "Refresh": "Uppdatera", - "Ratings": "Betyg", "Queue": "Kö", - "Quality": "Kvalitet", "QualitySettingsSummary": "Namn och storleksdefinitioner på kvaliteterna", - "QualityProfiles": "Kvalitetsprofiler", "QualityProfile": "Kvalitetsprofil", "QualityDefinitions": "Kvalitetsdefinitioner", "PtpOldSettingsCheckMessage": "Följande PassThePopcorn-indexerare har inaktuella inställningar och bör uppdateras: {0}", @@ -160,63 +107,40 @@ "ProxyCheckBadRequestMessage": "Test av proxy misslyckades. Statuskod: {0}", "Proxy": "Proxy", "Protocol": "Protokoll", - "Progress": "Progress", "ProfilesSettingsSummary": "Profiler för kvalitet, språk och fördröjning", - "Profiles": "Profiler", "PreviewRename": "Förhandsvisa namnbyte", - "PhysicalRelease": "Fysisk release", "Path": "Sökväg", - "OutputPath": "Output-sökväg", "MonitoredOnly": "Endast Bevakade", - "MetadataSettingsSummary": "Skapa metadatafiler när filmer importeras eller uppdateras", "MediaManagementSettingsSummary": "Namngivning- och filhanteringsinställningar", - "MassMovieSearch": "Mass-sök filmer", "ListsSettingsSummary": "Importera listor, listuteslutningar", "LastWriteTime": "Senast skriven tid", - "IndexersSettingsSummary": "Indexerare och releaserestriktioner", "Indexer": "Indexerare", - "InCinemas": "På bio", "Imported": "Importerad", - "Ignored": "Ignorerad", "Grabbed": "Hämtad", - "Genres": "Genrer", "GeneralSettingsSummary": "Port, SSL, användarnamn/lösenord, proxy, analys och uppdateringar", "Filename": "Filnamn", "Failed": "Misslyckad", "EventType": "Händelsetyp", "DownloadClientsSettingsSummary": "Nedladdningsklienter, nedladdningshantering och fjärrsökvägar", - "RemotePathMappings": "Fjärrsökvägar", "DownloadClient": "Nedladdningsklient", - "DigitalRelease": "Digital release", "ReleaseGroup": "Releasegrupp", "ReleaseStatus": "Releasestatus", - "ReleaseTitle": "Releasetitel", "Details": "Detaljer", - "Deleted": "Raderad", "CutoffUnmet": "Avgränsande ej tillgodosedd", - "CustomFormatsSettingsSummary": "Anpassade format och Inställningar", "ConnectSettingsSummary": "Aviseringar, anslutningar till media-servrar/klienter och anpassade script", - "Collection": "Samling", "Certification": "Certifikation", "Added": "Tillagd", "Actions": "Åtgärder", "Options": "Alternativ", "NoChanges": "Inga ändringar", "NoChange": "Ingen förändring", - "ImportListStatusCheckSingleClientMessage": "Listor otillgängliga på grund av fel: {0}", "ImportListStatusCheckAllClientMessage": "Samtliga listor otillgängliga på grund av fel", - "MovieTitle": "Filmtitel", "Movies": "Filmer", - "MovieNaming": "Namngivning av film", "MovieIndex": "Filmindex", - "MovieEditor": "Filmredigerare", "Movie": "Film", - "MountCheckMessage": "Montering (eng. Mount) innehållande filmsökväg är monterad med endast Läs-behörighet: ", "Warn": "Varna", - "VideoCodec": "Video codec", "Unavailable": "Otillgänglig", "Type": "Typ", - "TotalSpace": "Totalt utrymme", "Title": "Titel", "Time": "Tid", "TestAll": "Testa samtliga", @@ -228,34 +152,24 @@ "Seeders": "Seeders", "Save": "Spara", "Restart": "Starta om", - "RemoveRootFolder": "Ta bort rotmapp", "Reload": "Ladda om", - "RelativePath": "Relativ sökväg", "RejectionCount": "Antal avslag", "Peers": "Peers", "PageSize": "Sidstorlek", - "OrganizeModalSuccess": "Klart! Jobbet avslutat, inga fler filer att byta namn på.", "OrganizeModalNamingPattern": "Namnmönster:", - "OrganizeModalDisabled": "Namnbyte är avaktiverad, det finns inget att byta namn på", "OrganizeModalAllPathsRelative": "Samtliga sögvägar är relativa till:", "OAuthPopupMessage": "Popups blockeras av din webbläsare", - "OrganizeAndRename": "Organisera & byt namn", "Organize": "Organisera", "Ok": "Ok", "Name": "Namn", - "MoveFiles": "Flytta filer", "Monitored": "Bevakad", "Message": "Meddelande", - "Location": "Lagringsplats", "Level": "Nivå", "KeyboardShortcuts": "Tangentbordsgenvägar", "Info": "Info", - "ImportExistingMovies": "Importera befintliga filmer", "HealthNoIssues": "Inga problem hittades med din konfiguration", - "HardlinkCopyFiles": "Hardlink/kopiera filer", "Extension": "Filändelse", "Error": "Fel", - "CustomFormatScore": "Poäng för Anpassade format", "ConnectionLostMessage": "Prowlarr har tappat anslutningen till sin backend och behöver laddas om för att återställa funktionalitet.", "ConnectionLostAutomaticMessage": "Prowlarr kommer försöka ansluta automatiskt, du kan även klicka på ladda om nedan.", "ConnectionLost": "Anslutning saknas", @@ -263,12 +177,9 @@ "Columns": "Kolumner", "Close": "Avsluta", "Cancel": "Avbryt", - "AudioInfo": "Ljudinformation", "Apply": "TIllämpa", - "AlternativeTitle": "Alternativ titel", "AllMoviesHiddenDueToFilter": "Samtliga filmer är dolda på grund av tillämpade filter.", "Age": "Ålder", - "AddNewMovie": "Lägg till ny film", "AddList": "Lägg till lista", "SystemTimeCheckMessage": "Systemklockan går fel med mer än en dag. Schemalagda uppgifter kan få problem att köras innan tiden är korrigerad" } diff --git a/src/NzbDrone.Core/Localization/Core/tr.json b/src/NzbDrone.Core/Localization/Core/tr.json index d71f5767d..6e61a25a0 100644 --- a/src/NzbDrone.Core/Localization/Core/tr.json +++ b/src/NzbDrone.Core/Localization/Core/tr.json @@ -1,177 +1,112 @@ { - "DiskSpace": "Disk Alanı", "Discover": "Keşfet", "Details": "Detaylar", - "Deleted": "Silindi", "Delete": "Sil", - "Day": "Gün", "Dates": "Tarih", "Date": "Tarih", "Connections": "Bağlantılar", "Connect": "Bağlan", - "Collection": "Koleksiyon", "Clear": "Temizle", - "Cast": "Oyuncular", "Calendar": "Takvim", - "AddNew": "Yeni ekle", "AddMovies": "Filimler ekle", - "Unmonitored": "İzlenenmiyen", "Sort": "Çeşitle", "SetTags": "Etiketleri Ayarla", "Scheduled": "Tarifeli", - "RootFolders": "Kök klasörler", "RootFolderCheckSingleMessage": "Eksik kök klasör: {0}", - "RootFolderCheckMultipleMessage": "Birden fazla kök klasörler eksik: {0}", "RootFolder": "Kök Klasör", - "Ratings": "Puanlar", "ProxyCheckResolveIpMessage": "{0} Yapılandırılmış Proxy Ana Bilgisayarının IP Adresi çözülemedi", "ProxyCheckFailedToTestMessage": "Proxy ile test edilemedi: {0}", "ProxyCheckBadRequestMessage": "Proxy ile test edilemedi. DurumKodu: {0}", "Proxy": "Proxy", - "PreviewRename": "Ad değiştirmeyi ön izle", "ImportListStatusCheckSingleClientMessage": "Hatalar nedeniyle kullanılamayan listeler: {0}", - "ImportListStatusCheckAllClientMessage": "Hatalar nedeniyle tüm listeler kullanılamıyor", "MonitoredOnly": "Sadece İzlenenler", - "MetadataSettingsSummary": "Filmler içe aktarıldığında veya yenilenince meta veri dosyaları oluştur", "Metadata": "Meta veri", - "MediaManagement": "Medya işletme", "Logging": "Logging", - "LogFilesLocationMessage": "Log dosyaları burada bulunur:", "LogFiles": "Log dosyaları", - "ListsSettingsSummary": "Listeleri İçe Aktar, hariç tutulanları listele", "ImportTipsMessage": "İçe aktarmanın sorunsuz geçmesini sağlamak için bazı ipuçları:", - "ImportHeader": "Zaten sahip olduğunuz filmleri içe aktarın", "ImportFirstTip": "Dosyalarınızın dosya adlarında kaliteyi dahil etmeyi emin olun. Örneğin.", "Host": "Ana bilgisayar", - "GrabSelected": "Seçilenleri Kap", "GeneralSettingsSummary": "Port, SSL, kullanıcı adı/şifre, proxy, analitikler ve güncellemeler", "Folder": "Klasör", - "Filesize": "Dosya ölçü", "Files": "Dosyalar", "Filename": "Dosya adı", - "FailedDownloadHandling": "Başarısız İndirme İşlemi", "CustomFormatsSettingsSummary": "Özel Biçimler ve Ayarlar", - "CustomFormats": "Özel Biçimler", "Crew": "Oyuncular", - "Blacklist": "Kara liste", "AppDataLocationHealthCheckMessage": "Güncellemede AppData'nın silinmesini önlemek için güncelleme mümkün olmayacak", - "AddNewTmdbIdMessage": "Ayrıca bir filmin TMDB kimliğini kullanarak da arama yapabilirsiniz. Örneğin. tmdb:71663", "AddNewMessage": "Yeni bir film eklemek kolaydır, eklemek istediğiniz filmin adını yazmaya başlayın", - "AddExclusion": "Hariç Ekle", "Actions": "Etkiler", "About": "Hakkında", - "Year": "Yıl", "Week": "Hafta", - "Wanted": "İstenenler", "View": "Görünüm", - "UpdateSelected": "Seçilmişleri güncelle", "Updates": "Güncellemeler", "UpdateCheckUINotWritableMessage": "'{0}' UI klasörü '{1}' kullanıcısı tarafından yazılamadığından güncelleme yüklenemiyor.", "UpdateCheckStartupTranslocationMessage": "Başlangıç klasörü '{0}' bir Uygulama Yer Değiştirme klasöründe olduğu için güncelleme yüklenemiyor.", "UpdateCheckStartupNotWritableMessage": "'{0}' başlangıç klasörü '{1}' kullanıcısı tarafından yazılamadığından güncelleme yüklenemiyor.", - "UpdateAll": "Tümünü Güncelle", "UnselectAll": "Tüm Seçimleri Kaldır", - "UnmappedFolders": "Eşlenmemiş Klasörler", "UISettingsSummary": "Takvim, tarih ve renk engelli seçenekler", "UI": "UI", - "Titles": "Başlıklar", "Timeleft": "Kalan zaman", "Tasks": "Görevler", "TagsSettingsSummary": "Tüm etiketleri ve nasıl kullanıldıklarını göster. Kullanılmayan etiketler kaldırılabilinir", "Tags": "Etiketler", "System": "Sistem", "Style": "Tarz", - "Studio": "Stüdyo", "Status": "Durum", - "SizeOnDisk": "Diskteki ölçü", "Size": "Ölçü", "ShowAdvanced": "Gelişmiş'i Göster", "Settings": "Ayarlar", "SelectAll": "Hepsini seç", "Security": "Güvenlik", - "SearchSelected": "Seçilenleri Ara", "SearchForMissing": "Kayıpları Ara", - "SearchFiltered": "Filtrelenmişleri Ara", "SearchAll": "Tümünü ara", "Search": "Ara", "SaveChanges": "Değişiklikleri Kaydet", - "Runtime": "Süresi", "RSSSync": "RSS Senkronizasyonu", "Restrictions": "Kısıtlamalar", - "RenameFiles": "Yeniden Adlandır", "Renamed": "Yeniden adlandırıldı", - "RemoveSelected": "Seçilenleri Kaldır", "RemovedMovieCheckSingleMessage": "{0} filmi TMDb'den çıkarıldı", - "RemovedMovieCheckMultipleMessage": "{0} filmleri TMDb'den çıkarıldı", "ReleaseTitle": "Yayin Başlığı", "ReleaseStatus": "Yayın Durumu", - "ReleaseGroup": "Yayın Grubu", "ReleaseBranchCheckPreviousVersionMessage": "Dal {0}, Prowlarr'ın önceki bir versiyon için, dalı daha fazla güncelleme için 'Aphrodite' olarak ayarlayın", "ReleaseBranchCheckOfficialBranchMessage": "Dal {0} geçerli bir Prowlarr sürüm dalı değil, güncelleme almayacaksınız", - "RefreshAndScan": "Yenile ve Tara", "Refresh": "Yenile", "Queue": "Sıra", - "QualitySettingsSummary": "Kalite boyutları ve adlandırma", "QualityProfiles": "Kalite Profileri", - "QualityProfile": "Kalite Profili", "QualityDefinitions": "Kalite Tanımları", - "Quality": "Kalite", "Protocol": "Protokol", - "Progress": "İlerleme", "ProfilesSettingsSummary": "Kalite, Dil ve Gecikme profilleri", - "Profiles": "Profiller", "Options": "Seçenekler", "NoChanges": "Değişiklikler yok", "NoChange": "Değişiklik yok", - "MovieTitle": "Film başlığı", "Movies": "Filmler", - "MovieNaming": "Film Adlandırma", "MovieEditor": "Film Editörü", - "Movie": "Film", "MoreInfo": "Daha fazla bilgi", - "Month": "Ay", "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls geçici çözümü hala etkin, MONO_TLS_PROVIDER=legacy seçeneğini kaldırmayı düşünün", "MonoNotNetCoreCheckMessage": "Lütfen Prowlarr'ın .NET Core sürümüne güncelle", - "Monitor": "monitor", "Missing": "Eksik", - "MediaManagementSettingsSummary": "Adlandırma ve dosya yönetimi ayarları", "MediaInfoDllCheckMessage": "Medya Bilgi Kütüphanesi yüklenemedi {0}", - "MassMovieSearch": "Toplu Film Arama", "Lists": "Listeler", - "ListExclusions": "Hariç Tutulanları Listele", "LastWriteTime": "Son Yazma Zamanı", "Languages": "Diller", "Language": "Dil", - "InCinemas": "Sinemalarda", "ImportSecondTip": "Prowlarr'ı belirli bir filmi değil, tüm filmlerinizi içeren klasöre yönlendirin. Örneğin.", - "ImportMechanismHealthCheckMessage": "Tamamlanan İndirme İşlemini Etkinleştir", "iCalLink": "iCal Bağlantısı", "History": "Tarih", "HideAdvanced": "Gelişmiş'i Gizle", "Health": "Sağlık", "General": "Genel", - "FreeSpace": "Boş alan", "Formats": "Biçimler", - "Forecast": "Tahmin", "Filter": "Filtre", - "FileManagement": "Dosya idare", "Failed": "Başarısız oldu", "Edit": "Düzenle", - "Downloaded": "İndirildi", "DownloadClientCheckUnableToCommunicateMessage": "{0} ile iletişim kurulamıyor.", - "DotNetVersionCheckOldUnsupportedMessage": "Şu anda yüklü .Net Framework {0} eski ve desteklenmiyor. Lütfen .Net Framework'ü en az {1} sürümüne güncelleştir.", "DotNetVersionCheckNotRecommendedMessage": "Şu anda yüklü .Net Framework {0} desteklenmektedir, fakat en az {1} sürümüne güncelleştirmeyi öneririz.", - "DigitalRelease": "Dijital Yayın", "DelayProfiles": "Gecikme Profilleri", "CustomFilters": "Özel Filtreler", "ConnectSettingsSummary": "Bildirimler, medya sunucularına/oynatıcılara bağlantılar ve özel komut kodları", - "CompletedDownloadHandling": "Tamamlanan İndirme İşlemleri", "ChooseAnotherFolder": "Başka bir dosya seç", - "AndNot": "ve değil", "Analytics": "Analitik", "All": "Herşey", - "Agenda": "Gündem", "Added": "Eklendi", - "Activity": "Aktivite", "Add": "Ekle" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index a0a5e2a2c..2e836e821 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -270,7 +270,6 @@ "NoChanges": "无修改", "NoChange": "无修改", "NoBackupsAreAvailable": "无备份可用", - "NewznabVipCheckExpiringClientMessage": "搜刮器VIP权益即将到期:{0}", "NewznabVipCheckExpiredClientMessage": "搜刮器VIP权益已过期:{0}", "New": "新的", "NetCore": ".NET", From af03c178927305074ceabddfcfe82951645d6501 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sat, 2 Oct 2021 14:36:15 +0000 Subject: [PATCH 0085/2320] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate <noreply@weblate.org> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/da.json | 15 -- src/NzbDrone.Core/Localization/Core/de.json | 145 ------------------ src/NzbDrone.Core/Localization/Core/el.json | 12 +- src/NzbDrone.Core/Localization/Core/es.json | 140 ----------------- src/NzbDrone.Core/Localization/Core/fr.json | 138 ----------------- src/NzbDrone.Core/Localization/Core/hu.json | 138 ----------------- src/NzbDrone.Core/Localization/Core/it.json | 143 ----------------- src/NzbDrone.Core/Localization/Core/nl.json | 139 ----------------- src/NzbDrone.Core/Localization/Core/pl.json | 3 - src/NzbDrone.Core/Localization/Core/pt.json | 141 ----------------- src/NzbDrone.Core/Localization/Core/ro.json | 37 ----- src/NzbDrone.Core/Localization/Core/ru.json | 11 -- src/NzbDrone.Core/Localization/Core/sv.json | 37 ----- src/NzbDrone.Core/Localization/Core/tr.json | 23 --- .../Localization/Core/zh_CN.json | 1 - 15 files changed, 1 insertion(+), 1122 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/da.json b/src/NzbDrone.Core/Localization/Core/da.json index 0219aa8b6..bafe069f4 100644 --- a/src/NzbDrone.Core/Localization/Core/da.json +++ b/src/NzbDrone.Core/Localization/Core/da.json @@ -6,28 +6,21 @@ "Info": "Information", "IndexerStatusCheckSingleClientMessage": "Indexere utilgængelige på grund af fejl: {0}", "IndexerStatusCheckAllClientMessage": "Alle indexere er utilgængelige på grund af fejl", - "IndexerSearchCheckNoInteractiveMessage": "Ingen indexere er tilgængelige med Interaktiv Søg aktiveret, Prowlarr vil ikke give nogle interaktive søge resultater", "IndexerSearchCheckNoAutomaticMessage": "Ingen indexere tilgængelige med Automatisk Søg aktiveret, Prowlarr vil ikke give nogle automatiske søge resultater", "Indexers": "Indexere", - "IndexerRssHealthCheckNoAvailableIndexers": "Alle rss-mulige indexere er midlertidigt utilgængelige på grund af nylige indexer fejl", "ImportTipsMessage": "Nogle tips for at sikre importeringen går glat:", - "ImportMechanismHealthCheckMessage": "Aktiver Fuldendt Download Håndtering", "ImportFirstTip": "Vær sikker på at dine filer inkluderer kvalitet i deres filnavn. f.eks.", - "Imported": "Importeret", "Ignored": "Ignoreret", "History": "Historie", "HideAdvanced": "Gemt Avancerede", "HealthNoIssues": "Ingen problemer med din konfiguration", "Health": "Helbred", - "GrabSelected": "Greb Valgt", "Grabbed": "Grebet", "GeneralSettingsSummary": "Port, SSL, brugernavn/adgangskode, proxy, analyser og opdateringer", "General": "Generelt", - "Formats": "Formater", "Folder": "Mappe", "Files": "Filer", "Filename": "Filnavn", - "FailedDownloadHandling": "Fejlet Download Håndtering", "Failed": "Fejlet", "EventType": "Begivenhed Type", "Events": "Begivenheder", @@ -40,14 +33,11 @@ "DownloadClientCheckUnableToCommunicateMessage": "Ude af stand til at kommunikere med {0}.", "DownloadClientCheckNoneAvailableMessage": "Ingen download klient tilgængelig", "DownloadClient": "Download Klient", - "DotNetVersionCheckNotRecommendedMessage": "Aktuelt Installeret .Net Framework {0} er supporteret men vi foreslår at opgradere til ihvertfald {1}.", "Discover": "Opdag", "Details": "Detaljer", "Delete": "Slet", - "Day": "Dag", "Dates": "Datoer", "Date": "Dato", - "CustomFormatScore": "Bruger Tilpasset Format score", "CustomFilters": "Bruger Tilpassede Filtere", "ConnectSettingsSummary": "Notifikationer, forbindelser til media servere/afspillere og custom scripts", "Connections": "Forbindelser", @@ -59,20 +49,15 @@ "Columns": "Kolonner", "Close": "Luk", "Clear": "Ryd", - "Certification": "Certifikation", "Cancel": "Afbryd", - "Blacklist": "Blacklist", "BackupNow": "Backup Nu", "Backup": "Backup", "Apply": "Anvend", "AppDataLocationHealthCheckMessage": "Opdatering vil ikke være muligt for at undgå at slette AppData under opdatering", "Analytics": "Analyser", - "AllMoviesHiddenDueToFilter": "Alle film er gemt på grund af aktivt filter.", "All": "Alt", "Age": "Alder", - "AddNewMovie": "Tilføj Ny Film", "AddNew": "Tilføj Ny", - "AddList": "Tilføj Liste", "Added": "Tilføjet", "Actions": "Handlinger", "About": "Om", diff --git a/src/NzbDrone.Core/Localization/Core/de.json b/src/NzbDrone.Core/Localization/Core/de.json index 08cf78cf7..c2186580c 100644 --- a/src/NzbDrone.Core/Localization/Core/de.json +++ b/src/NzbDrone.Core/Localization/Core/de.json @@ -1,14 +1,11 @@ { "About": "Über", - "AddExclusion": "Ausschluss hinzufügen", "AddNew": "Hinzufügen", - "AddNewTmdbIdMessage": "Du kannst auch mit der TMDb-ID eines Films suchen. Z.B. tmdb:71663", "All": "Alle", "Analytics": "Statistiken", "AppDataLocationHealthCheckMessage": "Ein Update ist nicht möglich, um das Löschen von AppData beim Update zu verhindern", "Backup": "Backups", "BackupNow": "Jetzt sichern", - "Calendar": "Kalender", "ChooseAnotherFolder": "Wähle einen anderen Ordner", "Clear": "Leeren", "Connect": "Verbindungen", @@ -16,9 +13,7 @@ "CustomFilters": "Filter anpassen", "Date": "Datum", "Dates": "Termine", - "DelayProfiles": "Verzögerungsprofile", "Delete": "Löschen", - "DiskSpace": "Speicherplatz", "DotNetVersionCheckOldUnsupportedMessage": "Derzeit installiert .Net Framework {0} ist alt und wird nicht unterstützt. Bitte aktualisieren Sie das .Net Framework auf mindestens {1}.", "DownloadClientCheckNoneAvailableMessage": "Es ist kein Downloader verfügbar", "DownloadClientCheckUnableToCommunicateMessage": "Kommunikation mit {0} nicht möglich.", @@ -27,64 +22,49 @@ "DownloadClients": "Downloader", "Edit": "Bearbeiten", "Events": "Events", - "FileManagement": "Dateiverwaltung", "Files": "Dateien", "Filter": "Filter", "Folder": "Ordner", - "Formats": "Formate", "General": "Allgemein", "Health": "Zustandsüberwachung", "HideAdvanced": "Erweiterte Ansicht", "History": "Verlauf", "Host": "Host", - "ImportFirstTip": "Stelle sicher, dass die Dateien die Qualität im Dateinamen enthalten. Z.B.", "ImportMechanismHealthCheckMessage": "Aktiviere die Verarbeitung der abgeschlossenen Downloads", - "ImportTipsMessage": "Einige Tipps um sicherzustellen, dass der Import reibungslos verläuft:", "IndexerRssHealthCheckNoIndexers": "Da keine Indexer mit aktivierter RSS-Synchronisierung verfügbar sind, erfasst Prowlarr nicht automatisch neue Releases auf", - "IndexerSearchCheckNoAvailableIndexersMessage": "Alle suchfähigen Indexer sind aufgrund der kürzlichen Indexerfehler vorübergehend nicht verfügbar", "IndexerStatusCheckAllClientMessage": "Alle Indexer sind aufgrund von Fehlern nicht verfügbar", "IndexerStatusCheckSingleClientMessage": "Indexer aufgrund von Fehlern nicht verfügbar: {0}", "Indexers": "Indexer", "Languages": "Sprachen", - "Lists": "Listen", "LogFiles": "Protokolle", "Logging": "Protokollierung", - "MediaInfoDllCheckMessage": "MediaInfo Bibliothek konnte nicht geladen werden {0}", "Metadata": "Metadaten", - "MinimumAvailability": "Mindestverfügbarkeit", "Monitor": "Beobachten", "MonoNotNetCoreCheckMessage": "Bitte aktualisieren Sie auf die .NET Core-Version von Prowlarr", "MonoTlsCheckMessage": "Der Workaround für Prowlarr Mono 4.x TLS ist weiterhin aktiviert. Entferne möglicherweise die Option MONO_TLS_PROVIDER=legacy", "MoreInfo": "Mehr Infos", - "Movie": "Film", "MovieIndex": "Filmindex", "Movies": "Filme", - "ImportListStatusCheckSingleClientMessage": "Listen aufgrund von Fehlern nicht verfügbar: {0}", "NoChange": "Keine Änderung", "NoChanges": "Keine Änderungen", "Options": "Optionen", - "PreviewRename": "Umbenennen", "Proxy": "Proxy", "ProxyCheckBadRequestMessage": "Proxy konnte nicht getestet werden. StatusCode: {0}", "ProxyCheckFailedToTestMessage": "Proxy konnte nicht getestet werden: {0}", "ProxyCheckResolveIpMessage": "Fehler beim Auflösen der IP-Adresse für den konfigurierten Proxy-Host {0}", "PtpOldSettingsCheckMessage": "Die folgenden PassThePopcorn-Indexer haben veraltete Einstellungen und sollten aktualisiert werden: {0}", "QualityDefinitions": "Qualitätsdefinitionen", - "QualityProfiles": "Qualitätsprofile", "Queue": "Warteschlange", "Refresh": "Aktualisieren", "ReleaseBranchCheckOfficialBranchMessage": "Zweig {0} ist kein gültiger Prowlarr-Release-Zweig. Sie erhalten keine Updates", "ReleaseBranchCheckPreviousVersionMessage": "Zweig {0} ist für eine frühere Version von Prowlarr. Setzen Sie den Zweig für weitere Aktualisierungen auf 'nightly'", - "RemoveSelected": "Ausgw. entfernen", "RemovedMovieCheckSingleMessage": "Film {0} wurde aus TMDb entfernt", "RestoreBackup": "Backup einspielen", "Restrictions": "Beschränkungen", - "RootFolderCheckMultipleMessage": "Es fehlen mehrere Stammordner: {0}", "RootFolders": "Stammordner", "SaveChanges": "Änderungen speichern", "Scheduled": "Geplant", "Search": "Suche", - "SearchFiltered": "Suche gefilterte", "SearchSelected": "Ausgw. suchen", "Security": "Sicherheit", "SelectAll": "Alle wählen", @@ -98,32 +78,23 @@ "Tags": "Tags", "Tasks": "Aufgaben", "UI": "Oberfläche", - "Unmonitored": "Nicht beobachtete", "UnselectAll": "Keine wählen", "UpdateCheckStartupNotWritableMessage": "Update kann nicht installiert werden, da der Startordner '{0}' vom Benutzer '{1}' nicht beschreibbar ist.", "UpdateCheckStartupTranslocationMessage": "Update kann nicht installiert werden, da sich der Startordner '{0}' in einem App Translocation-Ordner befindet.", "UpdateCheckUINotWritableMessage": "Update kann nicht installiert werden, da der Benutzeroberflächenordner '{0}' vom Benutzer '{1}' nicht beschreibbar ist.", "Updates": "Updates", "View": "Ansicht", - "iCalLink": "iCal Link", "Language": "Sprache", - "Year": "Jahr", "UpdateSelected": "Ausgw. aktualisieren", "UISettingsSummary": "Einstellungen für Kalender, Datumsformat und Farbbeeinträchtigung", "TagsSettingsSummary": "Alle Tags und deren Benutzung anzeigen. Unbenutzte Tags können entfernt werden", - "SizeOnDisk": "Größe", "Size": "Größe", - "Renamed": "Umbenannt", "ReleaseStatus": "Releasestatus", - "Ratings": "Bewertung", "Protocol": "Protokoll", - "ProfilesSettingsSummary": "Profile für Qualität, Sprache und Verzögerung", "OutputPath": "Ausgabe-Pfad", - "MonitoredOnly": "Nur beobachtete", "MassMovieSearch": "Massen Filmsuche", "LastWriteTime": "Zuletzt beschrieben", "Indexer": "Indexer", - "Imported": "Importiert", "DownloadClientsSettingsSummary": "Downloader, Downloadverarbeitung und Remote-Pfadzuordnungen", "Grabbed": "Erfasste", "GeneralSettingsSummary": "Port, SSL, Benutzername/Passwort, Proxy, Statistik und Updates", @@ -132,13 +103,10 @@ "EventType": "Event Typ", "DownloadClient": "Downloader", "Details": "Details", - "CutoffUnmet": "› Schwelle nicht erreicht", "ConnectSettingsSummary": "Benachrichtigungen, Verbindungen zu Medien Server/Clients und benutzerdefinierte Scripte", - "Certification": "Zertifizierung", "Added": "Hinzugefügt", "Actions": "Aktionen", "Warn": "Warnung", - "Unavailable": "Nicht verfügbar", "Type": "Typ", "Title": "Titel", "Time": "Zeit", @@ -152,22 +120,17 @@ "Save": "Speichern", "Restart": "Neustarten", "Reload": "Neuladen", - "RejectionCount": "Anzahl der Ablehnungen", "Peers": "Peers", "PageSize": "Einträge pro Seite", - "OrganizeModalNamingPattern": "Benennungsmuster:", "OrganizeModalAllPathsRelative": "Alle Pfade sind relativ zu:", - "Organize": "Organisieren", "Ok": "OK", "OAuthPopupMessage": "Dein Browser blockiert Pop-ups", "Name": "Name", - "Monitored": "Beobachtet", "Message": "Nachricht", "Level": "Stufe", "KeyboardShortcuts": "Tastenkürzel", "Info": "Info", "HealthNoIssues": "Keine Probleme mit deiner Konfiguration", - "Extension": "Erweiterung", "Error": "Fehler", "ConnectionLostMessage": "Prowlarr hat die Verbindung zum Backend verloren und muss neugeladen werden.", "ConnectionLostAutomaticMessage": "Prowlarr wird automatisch versuchen zu verbinden oder klicke unten auf neuladen.", @@ -177,54 +140,39 @@ "Close": "Schließen", "Cancel": "Abbrechen", "Apply": "Anwenden", - "AllMoviesHiddenDueToFilter": "Alle Filme sind wegen dem Filter ausgeblendet.", "Age": "Alter", - "AddList": "Liste hinzufügen", "SystemTimeCheckMessage": "Die Systemzeit ist um einen Tag versetzt. Bis die Zeit korrigiert wurde, könnten die geplanten Aufgaben nicht korrekt ausgeführt werden", "UnsavedChanges": "Ungespeicherte Änderungen", - "ShowTitle": "Titel anzeigen", "ShowSizeOnDisk": "Belegter Speicherplatz anzeigen", "ShowSearchHelpText": "Suchbutton anzeigen beim draufzeigen", "ShowSearch": "Suche anzeigen", - "ShowPath": "Pfad anzeigen", "ShowDateAdded": "Datum \"Hinzugefügt\" anzeigen", - "SettingsWeekColumnHeader": "Wochen Spalten Titel", "SettingsUiLanguage": "Sprache (Language)", "SettingsTimeFormat": "Zeitformat", "SettingsShowRelativeDatesHelpText": "Relatives (z.B.: Heute, gestern, etc) oder absolutes Datum anzeigen", "SettingsShowRelativeDates": "Relatives Datum anzeigen", "SettingsShortDateFormat": "Kurzes Datumsformat", - "SettingsRemotePathMappingLocalPathHelpText": "Pfad, den Prowlarr verwenden sollte, um lokal auf den Entfernten-Pfad zuzugreifen", "SettingsRemotePathMappingLocalPath": "Lokaler Pfad", "SettingsLongDateFormat": "Langes Datumsformat", "SettingsEnableColorImpairedMode": "Farbbeeinträchtigter Modus aktivieren", "SettingsEnableColorImpairedModeHelpText": "Alternativer Stil, um farbbeeinträchtigten Benutzern eine bessere Unterscheidung farbcodierter Informationen zu ermöglichen", - "SearchOnAdd": "Beim hinzufügen suchen", "RecentFolders": "Letzte Ordner", - "PosterSize": "Plakatgröße", "PosterOptions": "Poster Optionen", "PendingChangesStayReview": "Auf der Seite bleiben", "PendingChangesMessage": "Es gibt noch ungespeicherte Änderungen, bist du sicher, dass du die Seite verlassen möchtest?", "PendingChangesDiscardChanges": "Änderungen verwerfen und schließen", - "Overview": "Übersicht", "MonoVersionCheckUpgradeRecommendedMessage": "Die momentane installierte Mono Version {0} wird unterstützt aber es wird empfohlen auf {1} zu updaten.", - "MonoVersionCheckNotSupportedMessage": "Die momentane installierte Mono Version {0} wird nicht länger unterstützt. Bitte update Mono zur Version {1}.", "InteractiveImport": "Interaktiver Import", "ExistingMovies": "Vorhandene Filme", - "DetailedProgressBarHelpText": "Text auf Fortschrittsbalken anzeigen", "AddRemotePathMapping": "Entfernte Pfadzuordnung hinzufügen", "UpdateAutomaticallyHelpText": "Updates automatisch herunteraden und installieren. Es kann weiterhin unter \"System -> Updates\" ein manuelles Update angestoßen werden", "UrlBaseHelpText": "Für Reverse-Proxy-Unterstützung. Die Standardeinstellung leer", - "WhitelistedHardcodedSubsHelpText": "Hier gesetzte Untertitel Tags werden nciht als hartcodiert erachtet", "EnableAutoHelpText": "Wenn aktiviert werden Filme dieser Liste automatisch hinzugefügt", - "AgeWhenGrabbed": "Alter (beim erfassen)", "AlreadyInYourLibrary": "Bereits in deiner Bibliothek", "AppDataDirectory": "AppData Ordner", "ApplyTags": "Tags setzen", - "AreYouSureYouWantToDeleteThisRemotePathMapping": "Bist du sicher, dass du diese entfernte Pfadzuordnung löschen willst?", "Authentication": "Authentifizierung", "Automatic": "Automatisch", - "AvailabilityDelay": "Verfügbarkeits Verzögerung", "BackupIntervalHelpText": "Intervall zwischen automatischen Backups", "BackupRetentionHelpText": "Automatische Backups, die älter als die Aufbewahrungsfrist sind, werden automatisch gelöscht", "Backups": "Backups", @@ -234,27 +182,18 @@ "BypassProxyForLocalAddresses": "Proxy für lokale Adressen umgehen", "CertificateValidation": "Zertifikat Validierung", "CertificateValidationHelpText": "Ändere wie streng die Validierung der HTTPS-Zertifizierung ist", - "ChangeFileDate": "Datei Erstelldatum anpassen", "ChangeHasNotBeenSavedYet": "Änderung wurde noch nicht gespeichert", - "CleanLibraryLevel": "Bibliothek aufräumen", "ClickToChangeQuality": "Qualität ändern...", "ClientPriority": "Priorität", "CloneProfile": "Profil kopieren", - "ColonReplacementFormatHelpText": "Ändere wie Prowlarr Doppelpunkte ersetzt", "CreateEmptyMovieFolders": "Leere Filmordner erstellen", - "CreateGroup": "Gruppe erstellen", "CutoffFormatScoreHelpText": "Sobald dieser eigener Format Score erreicht wird, werden keine neuen Releases erfasst", "DeleteBackup": "Backup löschen", - "DeleteDelayProfile": "Verzögerungsprofil löschen", "DeleteDownloadClient": "Downloader löschen", - "DeleteFile": "Datei löschen", "DeleteIndexer": "Indexer löschen", - "DeleteRestriction": "Beschränkung löschen", "DeleteTag": "Tag löschen", - "DestinationRelativePath": "Relativer Zielpfad", "Docker": "Docker", "DownloadClientSettings": "Downloader Einstellungen", - "DownloadWarningCheckDownloadClientForMoreDetails": "Download Warnung: Prüfe den Downloader für mehr Details", "EditMovie": "Film bearbeiten", "Enable": "Aktivieren", "EnableAutomaticAdd": "Automatisch hinzufügen", @@ -266,50 +205,34 @@ "EnableInteractiveSearch": "Interaktive Suche", "EnableSSL": "SSL", "EnableSslHelpText": " Erfordert einen Neustart als Administrator", - "Exluded": "Ausgeschlossen", "FileDateHelpText": "Aktualisiere das Erstelldatum beim Import oder Re-Scan", - "FirstDayOfWeek": "Erster Tag der Woche", "Fixed": "Behoben", - "FollowPerson": "Schausteller folgen", "GeneralSettings": "Allgemeine Einstellungen", - "Grab": "Erfasse", "GrabRelease": "Release erfassen", "Hostname": "Hostname", - "IconForCutoffUnmet": "Symbol für Schwelle nicht erreicht", "IgnoredAddresses": "Ignorierte Adressen", "IllRestartLater": "Später neustarten", "Importing": "Importiere", - "IncludeCustomFormatWhenRenaming": "Eigenes Format beim umbennen einfügen", "IncludeHealthWarningsHelpText": "Zustandswarnung", "IndexerFlags": "Indexer Flags", "Interval": "Intervall", - "Links": "Links", "ListSyncLevelHelpText": "Filme in der Bibliothek werden gelöscht oder nicht weiter beobachtet wenn sie nicht in der Liste sind", - "Local": "Lokal", "LogLevel": "Log Level", "Logs": "Logs", - "MaximumSize": "Maximale Größe", "Mechanism": "Verfahren", - "MediaManagementSettings": "Medienverwaltungs Einstellungen", "MIA": "MIA", - "MinimumFreeSpace": "Mindest freier Speicher", "MinimumLimits": "Mindest Grenzen", "Mode": "Modus", "MonoVersion": "Mono Version", - "MovieFiles": "Film Dateien", "MovieID": "Film ID", - "MovieIsDownloading": "Film ist am herunterladen", "MovieYear": "Erscheinungsjahr", - "MustContain": "Muss beinhalten", "NamingSettings": "Bennenungs Einstellungen", "NetCore": ".NET Core", "New": "Neu", "NoLeaveIt": "Nein, nicht ändern", "NoLimitForAnyRuntime": "Keine Begrenzung der Laufzeiten", "NotificationTriggers": "Benachrichtigungs Auslöser", - "OnGrabHelpText": "Erfassen", "OnHealthIssueHelpText": "Zustandsproblem", - "OnUpgradeHelpText": "Upgrade", "OpenBrowserOnStart": "Browser beim Start öffnen", "PackageVersion": "Paket Version", "PageSizeHelpText": "Anzahl der Einträge pro Seite", @@ -317,93 +240,63 @@ "Port": "Port", "PortNumber": "Port Nummer", "PreferredSize": "Bevorzugte Größe", - "ProtocolHelpText": "Wählen Sie, welche(s) Protokoll(e) verwendet werden soll(en) und welches Protokoll bei der Wahl zwischen ansonsten gleichwertigen Releases bevorzugt wird", "ProxyBypassFilterHelpText": "Verwende ',' als Trennzeichen und '*.' als Platzhalter für Subdomains", "ProxyType": "Proxy Typ", "ProxyUsernameHelpText": "Nur wenn ein Benutzername und Passwort erforderlich ist, muss es eingegeben werden. Ansonsten leer lassen.", - "QualityCutoffHasNotBeenMet": "Qualitätsschwelle wurde noch nicht erreicht", "QualitySettings": "Qualitäts Einstellungen", - "ProwlarrTags": "Prowlarr Tags", "Reason": "Grund", - "RecycleBinHelpText": "Gelöschte Filmdateien werden hierher verschoben anstatt sie direkt endgültig zu löschen", "RecyclingBinCleanup": "Papierkorb aufräumen", - "RefreshInformationAndScanDisk": "Metadaten aktualisieren und Festplatte scannen", "RefreshMovie": "Film aktualisieren", - "Remove": "Entfernen", "RemovedFromTaskQueue": "Aus der Aufgabenwarteschlage entfernt", "RemoveFilter": "Filter entfernen", - "RemoveFromQueue": "Aus der Warteschlage entfernen", "RenameMoviesHelpText": "Wenn das umbennen deaktiviert ist, wird der vorhandene Dateiname benutzt", - "ReplaceIllegalCharacters": "Sonderzeichen ersetzen", "RescanAfterRefreshHelpText": "Nach dem aktualisieren des Films, den Filmordner neu scannen", - "RescanMovieFolderAfterRefresh": "Nach dem aktualisieren den Filmordner neu scannen", "Reset": "Zurücksetzen", "ResetAPIKey": "API-Schlüssel zurücksetzen", "RestartNow": "Jetzt neustarten", "RestartProwlarr": "Prowlarr Neustarten", "Result": "Ergebnis", "Retention": "Aufbewahrung ( Retention )", - "RSSSyncInterval": "RSS Synchronisierungs Intervall", "ScriptPath": "Script Pfad", - "SetPermissionsLinuxHelpTextWarning": "Ändere diese Einstellung nur, wenn du weißt was sie bewirken.", "ShowAsAllDayEvents": "Als Ganztags Events anzeigen", - "ShowMovieInformationHelpText": "Genre und Zertifizierung anzeigen", "ShowMonitoredHelpText": "Beobachtungsstatus unter dem Plakat anzeigen", - "ShowTitleHelpText": "Filmtitel unter dem Plakat anzeigen", "SkipFreeSpaceCheck": "Pürfung des freien Speichers überspringen", - "SorryThatMovieCannotBeFound": "Schade, dieser Film kann nicht gefunden werden.", "SourceRelativePath": "Relativer Quellpfad", "SSLCertPassword": "SSL Zertifikat Passwort", - "SslCertPathHelpText": "Pfad zur PFX Datei", "SSLPort": "SSL Port", "SSLCertPath": "Pfad zum SSL Zertifikat", "StartupDirectory": "Start-Verzeichnis", "SuggestTranslationChange": "Schlage eine Übersetzung vor", "TagsHelpText": "Wird auf Filme mit mindestens einem passenden Tag angewandt", "TestAllClients": "Alle testen", - "TestAllLists": "Alle testen", "UpdateMechanismHelpText": "Benutze den Built-In Updater oder ein Script", "UpdateScriptPathHelpText": "Pfad zu einem benutzerdefinierten Skript, das ein extrahiertes Update-Paket übernimmt und den Rest des Update-Prozesses abwickelt", "Uptime": "Laufzeit", "URLBase": "URL Base", - "TmdbIdHelpText": "Die TMDb ID für den Ausschluss", "TorrentDelayHelpText": "Verzögerung in Minuten bevor ein Torrent-Release erfasst wird", "Torrents": "Torrents", "UISettings": "Benutzeroberflächen Einstellungen", - "UnableToLoadDelayProfiles": "Verzögerungsprofile konnten nicht geladen werden", "UnableToLoadDownloadClients": "Downloader konnten nicht geladen werden", "UnableToLoadIndexers": "Indexer konnten nicht geladen werden", - "UnableToLoadLists": "Listen konnten nicht geladen werden", "UnableToLoadNotifications": "Benachrichtigungen konnten nicht geladen werden", "UnableToLoadQualityDefinitions": "Qualitätsdefinitionen konnten nicht geladen werden", - "UnableToLoadRestrictions": "Beschränkungen konnten nicht geladen werden", "UnableToLoadTags": "Tags konnten nicht geladen werden", - "UnmonitoredHelpText": "Nicht beobachtete Filme im iCal-Feed einschließen", "Usenet": "Usenet", "UseProxy": "Proxy benutzen", "Username": "Benutzername", "Version": "Version", - "WhitelistedSubtitleTags": "Erlaubte Untertitel Tags", "YesCancel": "Ja, abbrechen", "EnableColorImpairedModeHelpText": "Alternativer Style, um farbbeeinträchtigten Benutzern eine bessere Unterscheidung farbcodierter Informationen zu ermöglichen", - "RemoveHelpTextWarning": "Dies wird den Download und alle bereits heruntergeladenen Dateien aus dem Downloader entfernen.", "EnableMediaInfoHelpText": "Videoinformationen wie Auflösung, Laufzeit und Codec aus Datien erkennen. Dazu ist es erforderlich, dass Prowlarr Teile der Datei liest, was zu hoher Festplatten- oder Netzwerkaktivität während der Scans führen kann.", - "AddListExclusion": "Listenausschluss hinzufügen", "HelpText": "Intervall in Minuten. Zum deaktivieren auf 0 setzen ( Dies wird das automatische Release erfassen deaktivieren )", - "AllowHardcodedSubsHelpText": "Filme mit hartcodierten Untertiteln werden auch automatisch heruntergeladen", "NoMinimumForAnyRuntime": "Kein Minimum für Laufzeiten", "AnalyticsEnabledHelpText": "Sende anonyme Nutzungs- und Fehlerinformationen an die Server von Prowlarr. Dazu gehören Informationen über Browser, welche Seiten der Prowlarr-Weboberfläche aufgerufen wurden, Fehlerberichte sowie Betriebssystem- und Laufzeitversion. Wir werden diese Informationen verwenden, um Funktionen und Fehlerbehebungen zu priorisieren.", - "OnDownloadHelpText": "Import", "RestartRequiredHelpTextWarning": "Erfordert einen Neustart", "ApiKey": "API-Schlüssel", - "Permissions": "Rechte", "ImportExtraFilesHelpText": "Importiere zutreffende Extra Dateien (Untertitel, nfo, etc.) nach dem Importieren einer Filmdatei", - "RssSyncIntervalHelpTextWarning": "Dies betrifft alle Indexer. Bitte beachte dessen API Regeln", "AreYouSureYouWantToResetYourAPIKey": "Bist du sicher, dass du den API-Schlüssel zurücksetzen willst?", - "IncludeUnknownMovieItemsHelpText": "Einträge ohne eine Zuordnung in der Warteschlange anzeigen. Dies könnten gelöschte Filme oder alles andere mit Prowlarrs Downloadkategorie sein", "PriorityHelpText": "Priorisiere mehrere Downloader. Rundlauf-Verfahren wird für Downloader mit der gleichen Priorität verwendet.", "AuthenticationMethodHelpText": "Für den Zugriff auf Prowlarr sind Benutzername und Passwort erforderlich", - "IndexerSettings": "Indexer Einstellungen", "ProxyPasswordHelpText": "Nur wenn ein Benutzername und Passwort erforderlich ist, muss es eingegeben werden. Ansonsten leer lassen.", "SendAnonymousUsageData": "Anonyme Nutzungsdaten übertragen", "DBMigration": "DB Migration", @@ -412,79 +305,55 @@ "BackupFolderHelpText": "Relative Pfade befinden sich unter Prowlarrs AppData Ordner", "DelayProfile": "Verzögerungs Profil", "MaximumLimits": "Maximale Grenzen", - "UnableToLoadRemotePathMappings": "Entfernte Pfadzuordnungen konnten nicht geladen werden", "DeleteEmptyFoldersHelpText": "Lösche leere Filmeordner während des Scans oder wenn Filmdateien gelöscht werden", - "ReleaseDates": "VÖ Termine", "DeleteNotification": "Benachrichtigung löschen", - "RemoveCompletedDownloadsHelpText": "Importierte Downloads aus dem Downloader Verlauf entfernen", "CloneIndexer": "Indexer kopieren", - "MinFormatScoreHelpText": "Mindeste eigener Format Score bis zum download", "ConnectSettings": "Eintellungen für Verbindungen", - "MinimumAgeHelpText": "Nur Usenet: Mindestalter in Minuten der NZBs bevor sie erfasst werden. Gebe damit neuen Releases Zeit, sich bei deinem Usenet Provider zu verbreiten.", "WaitingToProcess": "Wartet auf Verarbeitung", - "UpgradeUntilThisQualityIsMetOrExceeded": "Solange bis die Qualität erreicht oder übertroffen wird verbessern", "TagCannotBeDeletedWhileInUse": "Kann während der Benutzung nicht gelöscht werden", "SSLCertPathHelpText": "Pfad zur PFX Datei", "SSLCertPasswordHelpText": "Passwort für die PFX Datei", - "ShowRatings": "Bewertungen anzeigen", "ShownClickToHide": "Angezeigt, zum verstecken klicken", - "ShowCertification": "Zertifikation anzeigen", "SearchOnAddHelpText": "Suche nach den Filmen auf der Liste nach dem hinzufügen", "RSSIsNotSupportedWithThisIndexer": "RSS wird von diesem Indexer nicht unterstützt", "RemovingTag": "Tag entfernen", - "Queued": "Eingereiht", "Pending": "Ausstehend", - "NegateHelpText": "Wenn aktiviert wird das eigene Format nicht angewendet solange diese {0} Bedingung zutrifft.", "MovieIsUnmonitored": "Film wird nicht beobachtet", - "MovieIsDownloadingInterp": "Film lädt herunter - {0}% {1}", "MovieAlreadyExcluded": "Film ist schon ausgeschlossen", "Manual": "Manuell", "LogLevelTraceHelpTextWarning": "Trace logging sollte nur kurzzeitig aktiviert werden", - "IncludeRecommendationsHelpText": "Prowlarrs Empfehlungen in der Entdeckungsansicht mit einbeziehen", "ImportFailedInterp": "Import fehlgeschlagen: {0}", "HiddenClickToShow": "Versteckt, klicken zum anzeigen", - "GoToInterp": "Zu {0} gehen", "ExistingTag": "Vorhandener Tag", "EnableInteractiveSearchHelpTextWarning": "Der Indexer unterstützt keine Suchen", "EnableInteractiveSearchHelpText": "Wird bei der manuellen Suche benutzt", "EnableAutomaticSearchHelpTextWarning": "Wird für die manuelle Suche benutzt", "EnableAutomaticSearchHelpText": "Wird für automatische Suchen genutzt die vom Benutzer oder von Prowlarr gestartet werden", "Downloading": "Lädt herunter", - "DownloadFailed": "Download fehlgeschlagen", "DownloadClientUnavailable": "Downloader ist nicht verfügbar", "DeleteTagMessageText": "Tag '{0}' wirklich löschen?", - "DeleteRestrictionHelpText": "Beschränkung '{0}' wirklich löschen?", "DeleteNotificationMessageText": "Benachrichtigung '{0}' wirklich löschen?", "DeleteIndexerMessageText": "Indexer '{0}' wirklich löschen?", "DeleteDownloadClientMessageText": "Downloader '{0}' wirklich löschen?", "DeleteBackupMessageText": "Backup '{0}' wirkich löschen?", - "Cutoff": "Schwelle", "CheckDownloadClientForDetails": "prüfe den Downloader für mehr Details", "CancelPendingTask": "Diese laufende Aufgabe wirklich abbrechen?", "BranchUpdateMechanism": "Branch für den externen Updateablauf", "BranchUpdate": "Verwendeter Branch zur Aktualisierung von Prowlarr", "BeforeUpdate": "Vor dem Update", "AddingTag": "Tag hinzufügen", - "VisitGithubCustomFormatsAphrodite": "Besuche Github für mehr details: ", "UnableToLoadUISettings": "Oberflächen Einstellungen konnten nicht geladen werden", - "UnableToLoadRootFolders": "Stammordner konnten nicht geladen werden", "UnableToLoadMediaManagementSettings": "Media Verwaltungseinstellungen konnten nicht geladen werden", - "UnableToLoadMovies": "Filme konnten nicht geladen werden", "UnableToLoadLanguages": "Sprachen konnten nicht geladen werden", "UnableToLoadHistory": "Verlauf konnte nicht geladen werden", "UnableToLoadGeneralSettings": "Allgemeine Einstellungen konnten nicht geladen werden", - "UnableToLoadBlacklist": "Sperrliste konnte nicht geladen werden", "UnableToLoadBackups": "Backups konnten nicht geladen werden", - "UnableToAddANewQualityProfilePleaseTryAgain": "Das neue Qualitätsprofil konnte nicht hinzugefügt werden, bitte erneut probieren.", "UnableToAddANewNotificationPleaseTryAgain": "Die neue Benachrichtigung konnte nicht hinzugefügt werden, bitte erneut probieren.", - "UnableToAddANewListExclusionPleaseTryAgain": "Der neue Listenausschluss konnte nicht hinzugefügt werden, bitte erneut probieren.", "UnableToAddANewIndexerPleaseTryAgain": "Der neue Indexer konnte nicht hinzugefügt werden, bitte erneut probieren.", "UnableToAddANewDownloadClientPleaseTryAgain": "Der neue Downloader konnte nicht hinzugefügt werden, bitte erneut probieren.", - "UnableToAddANewConditionPleaseTryAgain": "Die neue Bedingung konnte nicht hinzugefügt werden, bitte erneut probieren.", "TagIsNotUsedAndCanBeDeleted": "Tag wird nicht benutzt und kann gelöscht werden", "StartTypingOrSelectAPathBelow": "Eingeben oder unten auswählen", "Restore": "Wiederherstellen", - "RegularExpressionsCanBeTested": "Reguläre Ausdrücke können getestet werden ", "ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "RSS Film Listen sowie unten aufgelistete werden untertützt.", "ProwlarrSupportsAnyIndexer": "Prowlarr unterstützt alle Indexer, welcher den Newznab/Torznab Standard implementiert (verwende 'Generic Newznab' (für Usenet) oder 'Generic Torznab' (für Torrents)) und darüber hinaus viele weitere Indexer. Wählen Sie im Folgenden Ihren Indexer aus der Liste.", "ProwlarrSupportsAnyDownloadClient": "Jeder Downloader der den Newznab-Standard verwendet oder unten aufgelistet ist wird untertützt.", @@ -492,23 +361,17 @@ "NoTagsHaveBeenAddedYet": "Es wurden noch keine Tags erstellt", "NoLogFiles": "Keine Log-Dateien", "NoBackupsAreAvailable": "Es sind keine Backups vorhanden", - "MissingMonitoredAndConsideredAvailable": "Fehlend, beobachtet und veröffentlicht", "MinutesSixty": "60 Minuten: {0}", "MinutesNinety": "90 Minuten: {0}", "MinutesHundredTwenty": "120 Minuten: {0}", "MaintenanceRelease": "Wartungsupdate", - "LoadingMovieExtraFilesFailed": "Laden der Extra-Datien fehlgeschlagen", "LinkHere": "hier", - "HaveNotAddedMovies": "Es gibt noch keine FIlme in der Bibliothek. Sollen einige oder alles Filme zuerst importiert werden?", "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Für mehr Infomationen klicke auf die Info-Knöpfe.", "ForMoreInformationOnTheIndividualDownloadClients": "Für mehr Infomationen klicke auf die Info-Knöpfe.", "FilterPlaceHolder": "Filme suchen", - "FileChmodHelpTexts1": "Oktal, wird beim Import oder Umbennen auf Mediendateien angewendet", "ExtraFileExtensionsHelpTexts2": "Vorschläge: sub, nfo, srt, jpg", - "Excluded": "Ausgeschlossen", "Exception": "Ausnahme", "ErrorLoadingContents": "Fehler beim laden der Inhalte", - "DownloadedAndMonitored": "Heruntergeladen und beobachtet", "CantFindMovie": "Warum kann der Film nicht gefunden werden?", "ApplyTagsHelpTexts4": "Ersetzen: Nur eingegebene Tags übernehmen und vorhandene entfernen( keine Tags eingeben um alle zu entfernen )", "ApplyTagsHelpTexts3": "Entfernen: Eingegebene Tags entfernen", @@ -517,11 +380,8 @@ "UILanguageHelpTextWarning": "Webseite muss neu geladen werden", "UILanguageHelpText": "Sprache für die gesamte Oberfläche", "UILanguage": "Oberflächen Sprache ( UI Language )", - "MovieInfoLanguage": "Filminfo Sprache", "ExportCustomFormat": "Eigenes Format exportieren", - "CustomFormatUnknownCondition": "Unbekannte eigene Format Bedingung '{0}'", "DownloadPropersAndRepacksHelpText2": "Benutze 'Nicht bevorzugen' um den bevorzugte Wörter Score über Proper oder Repacks zu sortieren", - "DownloadPropersAndRepacksHelpText1": "Automatisch Proper oder Repacks zum upgraden eines Filmes zulassen", "CopyToClipboard": "In die Zwischenablage kopieren", "Priority": "Priorität", "InteractiveSearch": "Interaktive Suche", @@ -540,13 +400,9 @@ "FocusSearchBox": "Suchbox fokussieren", "CloseCurrentModal": "Momentanes Modal schließen", "AcceptConfirmationModal": "Bestätigung akzeptieren Modal", - "StartImport": "Import starten", "RequiredRestrictionPlaceHolder": "Ein Release muss mindestens einen dieser Begriffe enthalten (Groß- und Kleinschreibung wird nicht berücksichtigt)", - "NoMatchFound": "Keine Übereinstimmung gefunden!", "ImportIncludeQuality": "Stelle sicher, dass die Qualität im Dateinamen vorkommt ( z.B.: {0} )", - "Existing": "Vorhanden", "StartProcessing": "Verarbeitung starten", - "CancelProcessing": "Verarbeitung abbrechen", "AddRestriction": "Beschränkung hinzufügen", "Yesterday": "Gestern", "Tomorrow": "Morgen", @@ -566,7 +422,6 @@ "SettingsFilterSentryEvents": "Analystische Ergeinisse filtern", "SettingsConsoleLogLevel": "Konsolen Log Level", "SearchIndexers": "Indexer suchen", - "NewznabVipCheckExpiredClientMessage": "Indexer VIP Status ist abgelaufen: {0}", "IndexersSelectedInterp": "{0} Indexer ausgewählt", "IndexerRss": "Indexer RSS", "IndexerQuery": "Indexer Anfrage", diff --git a/src/NzbDrone.Core/Localization/Core/el.json b/src/NzbDrone.Core/Localization/Core/el.json index d153e172b..5a970d5ff 100644 --- a/src/NzbDrone.Core/Localization/Core/el.json +++ b/src/NzbDrone.Core/Localization/Core/el.json @@ -3,22 +3,18 @@ "DownloadClientCheckUnableToCommunicateMessage": "Αδύνατο να επικοινωνήσει με {0}.", "DownloadClientCheckNoneAvailableMessage": "Δεν υπάρχει διαθέσιμο πρόγραμμα Λήψης", "DownloadClient": "Πρόγραμμα Λήψης", - "Discover": "Ανακάλυψε", "Details": "Λεπτομέρειες", "Delete": "Διαγραφή", "Dates": "Ημερομηνίες", "Date": "Ημερομηνία", "Connections": "Συνδέσεις", "Connect": "Σύνδεση", - "Collection": "Συλλογή", "Clear": "Καθαρισμός", - "Certification": "Πιστοποιητικό", "Calendar": "Ημερολόγιο", "BackupNow": "Δημιουργία Αντιγράφου Ασφαλείας", "Backup": "Αντίγραφο Ασφαλείας", "Analytics": "Αναλύσεις", "All": "Όλα", - "AddNew": "Προσθήκη Νέων", "AddExclusion": "Προσθήκη Εξαίρεσης", "Added": "Προστέθηκε", "Actions": "Ενέργειες", @@ -28,12 +24,10 @@ "Health": "Υγεία", "GeneralSettingsSummary": "Θύρα, SSL, όνομα χρήστη/κωδικός, proxy, analytics και αναβαθμίσεις", "General": "Γενικά", - "Formats": "Φορμάτ", "Folder": "Φάκελος", "Filter": "Φίλτρο", "Files": "Αρχεία", "Filename": "Όνομα Αρχείου", - "FailedDownloadHandling": "Η Διαχείρηση Λήψης Απέτυχε", "Failed": "Απέτυχε", "EventType": "Είδος Γεγονότος", "Events": "Γεγονότα", @@ -41,19 +35,15 @@ "DownloadClientStatusCheckSingleClientMessage": "Προγράμματα λήψης που είναι μη διαθέσιμα λόγων αποτυχιών: {0}", "DownloadClientStatusCheckAllClientMessage": "Όλα τα προγράμματα λήψης είναι μη διαθέσιμα λόγων αποτυχιών", "DownloadClientsSettingsSummary": "Προγράμματα λήψης, διαχείριση λήψεων και αντιστοίχηση remote path", - "DotNetVersionCheckNotRecommendedMessage": "Η τρέχουσα εγκατάσταση του .Net Framework {0} υποστηρίζεται αλλά θα σας συμβουλεύαμε να αναβαθμίσετε τουλάχιστον στην {1}.", "CustomFormatsSettingsSummary": "Custom Formats και Ρυθμίσεις", "CustomFilters": "Custom Φιλτρα", "ConnectSettingsSummary": "Ειδοποιήσεις, συνδέσεις σε media servers/players και custom scripts", "AppDataLocationHealthCheckMessage": "Η αναβάθμιση δεν είναι πιθανό να αποτρέψει την διαγραφή των AppData κατά την αναβάθμιση", - "AddNewMessage": "Είναι εύκολο να προσθέσετε μια καινούρια ταινία, απλά πληκτρολογήστε το όνομα της ταινίας", "ConnectionLostAutomaticMessage": "Το Prowlarr θα προσπαθήσει να συνδεθεί αυτόματα, αλλιώς μπορείτε να κάνετε reload απο κάτω.", "Component": "Στοιχείο", "Columns": "Στήλες", "Close": "Κλείσιμο", "Cancel": "Ακύρωση", "Apply": "Εφαρμογή", - "AllMoviesHiddenDueToFilter": "Όλες οι ταινίες έχουν κρυφτεί λόγω εφαρμογής φίλτρου", - "Age": "Ηλικία", - "AddList": "Προσθήκη Λίστας" + "Age": "Ηλικία" } diff --git a/src/NzbDrone.Core/Localization/Core/es.json b/src/NzbDrone.Core/Localization/Core/es.json index 0a9e0454e..2ee39f81b 100644 --- a/src/NzbDrone.Core/Localization/Core/es.json +++ b/src/NzbDrone.Core/Localization/Core/es.json @@ -1,20 +1,15 @@ { - "IndexerSearchCheckNoAutomaticMessage": "No hay indexers con Búsqueda Automática disponibles, Prowlarr no dará ningún resultado de búsquedas automáticas", "Indexers": "Indexers", - "ImportTipsMessage": "Algunos consejos para asegurarse de que la importación vaya sin problemas:", "ImportMechanismHealthCheckMessage": "Activar Manipulación de Descargas Completadas", - "ImportFirstTip": "Asegúrate de que tus archivos incluyen la calidad en el nombre del archivo. ej.", "iCalLink": "iCal Link", "Host": "Host", "History": "Historia", "HideAdvanced": "Ocultar Avanzado", "Health": "Salud", "General": "General", - "Formats": "Formatos", "Folder": "Carpeta", "Filter": "Filtro", "Files": "Archivos", - "FailedDownloadHandling": "Manipulación de Descargas Fallidas", "Events": "Eventos", "Edit": "Editar", "DownloadClientStatusCheckSingleClientMessage": "Gestores de descargas no disponibles debido a errores: {0}", @@ -22,26 +17,21 @@ "DownloadClients": "Gestores de Descargas", "DownloadClientCheckUnableToCommunicateMessage": "Incapaz de comunicarse con {0}.", "DownloadClientCheckNoneAvailableMessage": "Ningún gestor de descargas disponible", - "DotNetVersionCheckNotRecommendedMessage": "El .Net Framework {0} instalado actualmente es compatible pero recomendamos actualizar a por lo menos {1}.", "Discover": "Descubrir", "Delete": "Borrar", - "Day": "Día", "Dates": "Fechas", "Date": "Fecha", "CustomFilters": "Filtros Personalizados", "Connections": "Conexiones", "Connect": "Conectar", "Clear": "Borrar", - "Cast": "Reparto", "Blacklist": "Bloqueadas", "BackupNow": "Hacer copia de seguridad", "Backup": "Backup", "AppDataLocationHealthCheckMessage": "No será posible actualizar para prevenir que AppData se borre durante la actualización", "Analytics": "Analíticas", "All": "Todas", - "AddNewTmdbIdMessage": "También puedes buscar usando el ID de TMDb de la película. Ej. tmdb:71663", "AddNew": "Añadir Nueva", - "AddExclusion": "An̄adir Exclusión", "About": "Acerca", "View": "Vista", "Updates": "Actualizaciones", @@ -49,7 +39,6 @@ "UpdateCheckStartupTranslocationMessage": "No se puede instalar la actualización porque la carpeta de arranque '{0}' está en una carpeta de \"App Translocation\".", "UpdateCheckStartupNotWritableMessage": "No se puede instalar la actualización porque la carpeta de arranque '{0}' no tiene permisos de escritura para el usuario '{1}'.", "UnselectAll": "Deseleccionar Todo", - "UnmappedFolders": "Carpetas no Mapeadas", "UI": "UI", "Tasks": "Tareas", "Tags": "Etiquetas", @@ -62,69 +51,50 @@ "SetTags": "Poner Etiquetas", "SelectAll": "Seleccionar Todas", "Security": "Seguridad", - "SearchForMissing": "Buscar faltantes", "SearchAll": "Buscar Todas", "Search": "Buscar", "Scheduled": "Programado", "SaveChanges": "Guardar Cambios", - "RootFolders": "Carpetas de Origen", "RootFolderCheckMultipleMessage": "Varias carpetas de origen no existen: {0}", "Restrictions": "Restricciones", "RestoreBackup": "Recuperar Backup", - "RemoveSelected": "Borrar Seleccionados", "RemovedMovieCheckMultipleMessage": "Las películas {0} ya no están en TMDb", "ReleaseBranchCheckPreviousVersionMessage": "La versión {0} es de una versión anterior de Prowlarr, ajusta la versión a 'Nightly' para recibir actualizaciones", "ReleaseBranchCheckOfficialBranchMessage": "Las versión {0} no es una versión válida de Prowlarr, no recibirás actualizaciones", "Refresh": "Actualizar", "Queue": "Cola", - "QualityProfile": "Perfil de Calidad", "QualityDefinitions": "Definiciones de Calidad", "PtpOldSettingsCheckMessage": "Los siguientes indexers PassThePopcorn tienen configuraciones obsoletas y deben de ser actualizados: {0}", "ProxyCheckResolveIpMessage": "No se pudo resolver la dirección IP del Host Proxy configurado {0}", "ProxyCheckFailedToTestMessage": "Fallo al comprobar el proxy: {0}", "ProxyCheckBadRequestMessage": "Fallo al comprobar el proxy. StatusCode: {0}", "Proxy": "Proxy", - "PreviewRename": "Previsualizar Renombrado", "Options": "Opciones", "NoChange": "Sin Cambio", "NoChanges": "Sin Cambios", - "ImportListStatusCheckAllClientMessage": "Las listas no están disponibles debido a errores", "Movies": "Películas", "MonoNotNetCoreCheckMessage": "Por favor actualiza a la versión .NET Core de Prowlarr", - "MovieEditor": "Editor de Películas", "MoreInfo": "Más Información", - "Monitor": "Monitorear", "MinimumAvailability": "Disponibilidad Mínima", - "Metadata": "Metadatos", "MediaInfoDllCheckMessage": "La Librería MediaInfo no se ha cargado {0}", "Logging": "Registro de eventos", "LogFiles": "Archivos de Registro", - "ListExclusions": "Excluidas de las listas", "Languages": "Idiomas", "Language": "Idioma", "IndexerStatusCheckAllClientMessage": "Los indexers no están disponibles debido a errores", "Added": "An̄adida", "Actions": "Acciones", - "Wanted": "Buscado", "UISettingsSummary": "Calendario, fecha y opciones de color deteriorado", "TagsSettingsSummary": "Ver todas las etiquetas y cómo se usan. Las etiquetas no utilizadas se pueden eliminar", - "SizeOnDisk": "Tamaño en Disco", "Size": "Tamaño", - "Renamed": "Renombrado", "ReleaseStatus": "Estado del Estreno", - "Ratings": "Calificaciones", "Protocol": "Protocolo", - "ProfilesSettingsSummary": "Calidad, Idioma y Perfiles de retraso", "OutputPath": "Ruta de Output", - "MountCheckMessage": "El punto de montaje que contiene la ruta de una película es de read-only: ", "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls todavía está habilitado, considera la posibilidad de eliminar la opción MONO_TLS_PROVIDER=legacy", - "MetadataSettingsSummary": "Crear archivos de metadatos cuando las películas se importen ó actualicen", "MassMovieSearch": "Búsqueda en masa de películas", "LastWriteTime": "Última Fecha de Escritura", "IndexerStatusCheckSingleClientMessage": "Indexers no disponibles debido a errores: {0}", - "IndexerSearchCheckNoInteractiveMessage": "No hay indexers con Búsqueda Interactiva activada, Prowlarr no obtendrá ningún resultado en las búsquedas", "Indexer": "Indexer", - "Imported": "Importado", "Grabbed": "Capturado", "GeneralSettingsSummary": "Puerto, SSL, nombre de usuario/contraseña , proxy, analíticas y actualizaciones", "Filename": "Nombre del archivo", @@ -133,11 +103,8 @@ "DownloadClientsSettingsSummary": "Gestores de descargas, manipulación de descargas y mapeados remotos", "DownloadClient": "Gestor de Descargas", "Details": "Detalles", - "CutoffUnmet": "Corte No Alcanzado", "ConnectSettingsSummary": "Notificaciones, conexiones a servidores/reproductores y scripts personalizados", - "Certification": "Certificación", "Warn": "Advertencia", - "Unavailable": "No disponible", "Type": "Tipo", "Title": "Título", "Time": "Fecha", @@ -151,22 +118,17 @@ "Save": "Guardar", "Restart": "Reiniciar", "Reload": "Recargar", - "RejectionCount": "Número de Rechazos", "Peers": "Peers", "PageSize": "Tamaño de Página", - "OrganizeModalNamingPattern": "Modelo de Renombrado:", "OrganizeModalAllPathsRelative": "Todas las rutas son relativas a:", - "Organize": "Organizar", "Ok": "Ok", "OAuthPopupMessage": "Pop-ups bloqueados por su navegador", "Name": "Nombre", - "Monitored": "Monitoreadas", "Message": "Mensaje", "Level": "Nivel", "KeyboardShortcuts": "Atajos de Teclado", "Info": "Información", "HealthNoIssues": "No hay problemas con tu configuración", - "Extension": "Extensión", "Error": "Error", "ConnectionLostMessage": "Prowlarr ha perdido su conexión con el backend y tendrá que ser recargado para recuperar su funcionalidad.", "ConnectionLostAutomaticMessage": "Prowlarr intentará conectarse automáticamente, o haz clic en el botón de recarga abajo.", @@ -176,108 +138,77 @@ "Close": "Cerrar", "Cancel": "Cancelar", "Apply": "Aplicar", - "AllMoviesHiddenDueToFilter": "Todas las películas están ocultas debido al filtro aplicado.", "Age": "Edad", - "AddList": "Añadir lista", "SystemTimeCheckMessage": "El reloj del sistema está retrasado más de un día. Las tareas de mantenimiento no se ejecutarán correctamente hasta que se haya corregido", "ExistingMovies": "Película(s) Existente", - "DetailedProgressBarHelpText": "Mostrar texto en la barra de progreso", "DetailedProgressBar": "Barra de Progreso Detallada", "UnsavedChanges": "Cambios no guardados", - "ShowTitle": "Mostrar Título", "ShowSizeOnDisk": "Mostrar Tamaño en Disco", "ShowSearchHelpText": "Mostrar botón de búsqueda al pasar el cursor por encima", "ShowSearch": "Mostrar Búsqueda", - "ShowPath": "Mostrar Ruta", "ShowDateAdded": "Mostrar Fecha de Añadido", - "SettingsWeekColumnHeader": "Encabezado de la columna semanal", "SettingsUiLanguage": "Idioma de UI", "SettingsTimeFormat": "Formato de Hora", "SettingsShowRelativeDatesHelpText": "Mostrar fechas relativas (Hoy/Ayer/etc) o absolutas", "SettingsShowRelativeDates": "Mostrar Fechas Relativas", "SettingsShortDateFormat": "Formato Corto de Fecha", - "SettingsRemotePathMappingRemotePath": "Ruta Remota", "SettingsRemotePathMappingLocalPath": "Ruta Local", "SettingsLongDateFormat": "Formato Largo de Fecha", - "SelectFolder": "Seleccionar Carpeta", "SearchMovie": "Buscar Película", - "QuickImport": "Importación Rápida", "Posters": "Posters", "PendingChangesStayReview": "Permanecer y revisar cambios", "PendingChangesMessage": "Hay cambios sin salvar, estás seguro de que quieres salir de esta página?", "PendingChangesDiscardChanges": "Descartar cambios y salir", - "Overview": "Resumen", "MonoVersionCheckUpgradeRecommendedMessage": "Le versión de Mono {0} instalada actualmente es compatible pero se recomienda actualizar a {1}.", - "MonoVersionCheckNotSupportedMessage": "La versión de Mono {0} instalada actualmente no es compatible. Por favor actualiza Mono a la versión {1}.", "SettingsEnableColorImpairedModeHelpText": "Estilo modificado para permitir que usuarios con problemas de color distingan mejor la información codificada por colores", "SettingsEnableColorImpairedMode": "Activar Modo De Color Degradado", - "GrabRelease": "Capturar Estreno", "Grab": "Capturar", "GeneralSettings": "Ajustes Generales", - "Folders": "Carpetas", "Fixed": "Arreglado", - "FileNames": "Nombres de Archivos", "Exluded": "Excluida", "EnableSslHelpText": " Requiere reiniciar la aplicación como administrador para que surta efecto", "EnableMediaInfoHelpText": "Extraiga información de video como resolución, tiempo de ejecución e información de códec de los archivos. Esto requiere que Prowlarr lea partes del archivo y puede causar una alta actividad en el disco o en la red durante los escaneos.", "Enable": "Habilitar", - "EditMovie": "Editar Película", "DownloadWarningCheckDownloadClientForMoreDetails": "Advertencia de descarga: consulte el gestor de descargas para obtener más detalles", - "DownloadFailedCheckDownloadClientForMoreDetails": "Error de descarga: consulte el gestor de descargas para obtener más detalles", "DownloadClientSettings": "Ajustes de Gestor de Descargas", "Docker": "Docker", - "DestinationPath": "Ruta de Destino", "DeleteTag": "Borrar Etiqueta", - "DeleteRestriction": "Borrar Restricción", "DeleteNotification": "Borrar Notificación", "DeleteIndexer": "Borrar Indexer", - "DeleteFile": "Borrar archivo", "DeleteEmptyFolders": "Borrar carpetas vacías", "DeleteDownloadClient": "Borrar Gestor de Descargas", - "DeleteCustomFormat": "Borrar Formato Personalizado", "DeleteBackup": "Borrar Backup", "DelayProfile": "Perfil de Retraso", "DBMigration": "Migración de DB", - "CreateGroup": "Crear grupo", "CreateEmptyMovieFolders": "Crear carpetas de películas vacías", - "ColonReplacementFormatHelpText": "Cambia la forma en que Prowlarr reemplaza el colon", "CloneProfile": "Clonar Perfil", "CloneIndexer": "Clonar Indexer", "ClientPriority": "Prioridad de Cliente", - "ClickToChangeLanguage": "Clic para cambiar el idioma", "ChangeHasNotBeenSavedYet": "El cambio aún no se ha guardado", - "CertificationCountryHelpText": "Seleccionar país para certificaciones de películas", "CertificateValidationHelpText": "Cambiar la rigidez de la validación de la certificación HTTPS", "CertificateValidation": "Validación de certificado", "BypassProxyForLocalAddresses": "Omitir Proxy para Direcciones Locales", "Branch": "Rama", - "BlacklistHelpText": "Evita que Prowlarr vuelva a capturar esta película automáticamente", "BindAddressHelpText": "Dirección IP4 válida o '*' para todas las interfaces", "Backups": "Backups", "BackupRetentionHelpText": "Backups automáticos anteriores al período de retención serán borrados automáticamente", "BackupIntervalHelpText": "Intervalo entre backups automáticos", "BackupFolderHelpText": "Las rutas relativas estarán en el directorio AppData de Prowlarr", - "AvailabilityDelay": "Retraso de Disponibilidad", "AutoRedownloadFailedHelpText": "Buscar e intentar descargar automáticamente una versión diferente", "Automatic": "Automático", "AuthenticationMethodHelpText": "Requerir nombre de usuario y contraseña para acceder Prowlarr", "Authentication": "Autenticación", "AreYouSureYouWantToResetYourAPIKey": "¿Está seguro de que desea restablecer su clave API?", "ApiKey": "Clave API", - "AreYouSureYouWantToDeleteThisImportListExclusion": "Estás seguro que quieres borrar esta exclusión de lista de importación?", "ApplyTags": "Aplicar Etiquetas", "AppDataDirectory": "Directorio de AppData", "AnalyticsEnabledHelpText": "Envíe información anónima de uso y error a los servidores de Prowlarr. Esto incluye información sobre su navegador, qué páginas de Prowlarr WebUI utiliza, informes de errores, así como el sistema operativo y la versión en tiempo de ejecución. Usaremos esta información para priorizar funciones y correcciones de errores.", - "AlreadyInYourLibrary": "Ya esta en tu librería", "AllowHardcodedSubs": "Permitir Hardcoded Subs", - "AddImportExclusionHelpText": "Prevenir que la película sea añadida a Prowlarr mediante listas", "AddListExclusion": "Añadir Exclusión De Lista", "YesCancel": "Si, Cancela", - "WhitelistedHardcodedSubsHelpText": "Las etiquetas de los subtítulos aquí, no se considerarán incrustados", "Version": "Versión", "Username": "Nombre de usuario", "UseProxy": "Usar el Proxy", - "UsenetDelay": "Retraso de Usenet", "Usenet": "Usenet", "UrlBaseHelpText": "Para soporte de reverse proxy, vacio por defecto", "URLBase": "URL Base", @@ -285,20 +216,14 @@ "UpdateScriptPathHelpText": "Ruta del script propio que toma el paquete de actualización y se encarga del proceso de actualización restante", "UpdateMechanismHelpText": "Usar el actualizador de Prowlarr o un script", "UpdateAutomaticallyHelpText": "Descargar e instalar actualizaciones automáticamente. Se podrán instalar desde Sistema: Actualizaciones también", - "Ungroup": "Desagrupar", "UnableToLoadTags": "No se pueden cargar las Etiquetas", - "UnableToLoadRemotePathMappings": "No se pueden cargar las Rutas de los Mapeados Remotos", "UnableToLoadQualityDefinitions": "No se pueden cargar las Definiciones de Calidad", "UnableToLoadNotifications": "No se pueden cargar las Notificaciones", - "UnableToLoadLists": "No se puden cargar las Listas", "UnableToLoadIndexers": "No se pueden cargar los indexers", "UnableToLoadDownloadClients": "No se puden cargar los gestores de descargas", - "UnableToLoadCustomFormats": "No se pueden cargar los Formatos Propios", "UISettings": "Ajustes del UI", "Torrents": "Torrents", - "TorrentDelay": "Retraso del Torrent", "TMDBId": "TMDb Id", - "TestAllLists": "Comprobar Todas las Listas", "TestAllClients": "Comprobar Todos los Gestores", "TagsHelpText": "Se aplica a películas con al menos una etiqueta coincidente", "SuggestTranslationChange": "Sugerir un cambio en la traducción", @@ -306,17 +231,12 @@ "SSLPort": "Puerto SSL", "SSLCertPath": "Ruta del Certificado SSL", "SSLCertPassword": "Contraseña del Certificado SSL", - "SourcePath": "Ruta de Origen", "SkipFreeSpaceCheckWhenImportingHelpText": "Usar cuando Prowlarr no pueda detectar el espacio disponible en la carpeta de películas", - "ShowUnknownMovieItems": "Mostrar Elementos Desconocidos", "ShowQualityProfileHelpText": "Mostrar el perfil de calidad debajo del poster", - "ShowMovieInformation": "Mostrar Información de la Película", "ShowCutoffUnmetIconHelpText": "Mostrar el icono para los ficheros cuando no se ha alcanzado el corte", - "ShouldMonitorHelpText": "Si se habilita, las películas añadidas desde esta lista serán también monitoreadas", "SetPermissionsLinuxHelpText": "Debe chmod ser ejecutado una vez los archivos hayan sido importados/renombrados?", "SendAnonymousUsageData": "Enviar Datos de Uso Anónimamente", "ScriptPath": "Ruta del Script", - "RSSSyncInterval": "Intervalo de Sincronización de RSS", "Retention": "Retención", "Result": "Resultado", "RestartRequiredHelpTextWarning": "Requiere reiniciar para que surta efecto", @@ -324,79 +244,55 @@ "RestartNow": "Reiniciar Ahora", "ResetAPIKey": "Reajustar API", "Reset": "Reajustar", - "RescanAfterRefreshHelpTextWarning": "Prowlarr no detectará los cambios automáticamente en los ficheros si no se ajusta a 'Siempre'", "RequiredHelpText": "Esta condición {0} ha de igualar al formato propio para aplicarse. Si no, una sóla {1} es suficiente.", - "ReplaceIllegalCharacters": "Reemplazar Caracteres Ilegales", "RenameMoviesHelpText": "Prowlarr usará el nombre del archivo si el renombrado está deshabilitado", - "RemoveHelpTextWarning": "Eliminar borrará la descarga y el/los fichero(s) del gestor de descargas.", "RemoveFromDownloadClient": "Eliminar del Gestor de Descargas", "RemoveFilter": "Eliminar filtro", "RemovedFromTaskQueue": "Eliminar de la cola de tareas", - "Remove": "Eliminar", "ReleaseDates": "Fechas de Estreno", "RefreshMovie": "Actualizar película", - "Redownload": "Volver a descargar", "RecyclingBin": "Papelera de Reciclaje", - "RecycleBinCleanupDaysHelpTextWarning": "Los archivos en la papelera de reciclaje más antiguos que el número de días seleccionado serán limpiados automáticamente", "Reason": "Razón", "ReadTheWikiForMoreInformation": "Lee la Wiki para más información", - "Prowlarr": "Prowlarr", "QualitySettings": "Ajustes de Calidad", - "PublishedDate": "Fecha de Publicación", "ProxyUsernameHelpText": "Tienes que introducir tu nombre de usuario y contraseña sólo si son requeridos. Si no, déjalos vacios.", "ProxyType": "Tipo de Proxy", "ProxyPasswordHelpText": "Tienes que introducir tu nombre de usuario y contraseña sólo si son requeridos. Si no, déjalos vacios.", "ProxyBypassFilterHelpText": "Usa ',' como separador, y '*.' como wildcard para subdominios", - "Proper": "Apropiado", "PriorityHelpText": "Priorizar múltiples Gestores de Descargas. Se usa Round-Robin para gestores con la misma prioridad.", "PreferredSize": "Tamaño Preferido", - "PreferIndexerFlags": "Preferir Marcas del Indexer", "PortNumber": "Número de Puerto", "Port": "Puerto", "Password": "Contraseña", "PageSizeHelpText": "Número de elementos por página", "PackageVersion": "Versión del paquete", - "OnDownloadHelpText": "Notificar cuando las películas se hayan importado exitosamente", "NotificationTriggers": "Desencadenantes de Notificaciones", "NoMinimumForAnyRuntime": "Sin mínimo para el tiempo de ejecución", "NoLimitForAnyRuntime": "SIn límite para el tiempo de ejecución", "NoLeaveIt": "No, Déjalo", "New": "Nueva", "NetCore": ".NET Core", - "MustNotContain": "No Debe Contener", "MovieYearHelpText": "Año de la película a excluir", - "MovieTitleHelpText": "Ttítulo de la película a excluir (puedes ser cualquier cosa)", "MovieInfoLanguageHelpTextWarning": "Recargar el Navegador", - "MovieFolderFormat": "Formato de Carpeta de Película", "MovieAvailableButMissing": "Película Disponible pero Ausente", "MonoVersion": "Version de Mono", "Mode": "Modo", "MinimumLimits": "Límites Mínimos", - "MinimumFreeSpace": "Espacio Libre Mínimo", "MinimumAge": "Edad Mínima", "MIA": "MIA", - "MediaManagementSettings": "Ajustes Multimedia", "Mechanism": "Mecanismo", - "MaximumSize": "Tamaño Máximo", "MaximumLimits": "Límites Máximos", "Logs": "Registros", "LogLevel": "Nivel de Registro", - "ListUpdateInterval": "Intervalo de Actualización de Lista", "ListSettings": "Ajustes de Lista", "LaunchBrowserHelpText": " Abrir un navegador web e ir a la página de inicio de Prowlarr al arrancar la app.", "Interval": "Intervalo", "IndexerFlags": "Marcas de Indexer", - "IncludeUnknownMovieItemsHelpText": "Mostrar items sin ninguna película en la cola, esto incluye películas renombradas o cualquier otra cosa en la categoría de Prowlarr", "IncludeHealthWarningsHelpText": "Incluir Alertas de Salud", - "IncludeCustomFormatWhenRenaming": "Incluir el Formato Propio al Renombrar", "Importing": "Importando", - "ImportExtraFiles": "Importar Archivos Extra", "IllRestartLater": "Lo reiniciaré más tarde", - "IgnoreDeletedMovies": "Ignorar Películas Eliminadas", "IgnoredAddresses": "Direcciones Ignoradas", - "ICalHttpUrlHelpText": "Copia esta URL a tu gestor(es) o haz click en subscribir si tu navegador soporta webcal", "Hostname": "Nombre del Host", - "FileChmodMode": "Modo de chmod para el archivo", "EnableSSL": "Habilitar SSL", "EnableInteractiveSearch": "Habilitar Búsqueda Interactiva", "EnableHelpText": "Habilitar la creación de un fichero de metadatos para este tipo de metadato", @@ -407,102 +303,74 @@ "EnableAutomaticSearch": "Habilitar Búsqueda Automática", "EnableAutomaticAdd": "Habilitar Añadido Automático", "EnableAutoHelpText": "Si se habilita, las Películas en esta lista se añadirán automáticamente a Prowlarr", - "CustomFormatsSettings": "Ajustes de Formatos Propios", "CopyUsingHardlinksHelpText": "Usar Hardlinks al intentar copiar ficheros de los torrents que siguen seedeando", "ConnectSettings": "Conectar Ajustes", "BindAddress": "Dirección de Ligado", "OpenBrowserOnStart": "Abrir navegador al arrancar", - "OnRenameHelpText": "En Renombrado", "OnHealthIssueHelpText": "En Problema de Salud", - "SettingsRuntimeFormat": "Formato de Tiempo de ejecución", "MovieIsOnImportExclusionList": "La película está en la Lista de Exclusión", - "WaitingToImport": "Esperando para Importar", "TagCannotBeDeletedWhileInUse": "No se puede eliminar estando en uso", "SSLCertPathHelpText": "Ruta al archivo pfx", "SSLCertPasswordHelpText": "Contraseña para el archivo pfx", - "ShowRatings": "Mostrar Calificaciones", "ShownClickToHide": "Mostrado, clic para ocultar", - "ShowCertification": "Mostrar Certificación", "RSSSyncIntervalHelpTextWarning": "Se aplicará a todos los indexers, por favor sigue las reglas de los mismos", "RSSIsNotSupportedWithThisIndexer": "RSS no son soportadas por este indexer", "RemovingTag": "Eliminando etiqueta", - "Queued": "En Cola", "Pending": "Pendiente", - "NegateHelpText": "Si se activa, el formato propio no se aplicará si esta condición {0} se iguala.", "MovieIsUnmonitored": "La película no está monitoreada", - "MovieIsDownloadingInterp": "La película está descargando - {0}% {1}", "MovieAlreadyExcluded": "Película ya Excluida", "Manual": "Manual", "LogLevelTraceHelpTextWarning": "El registro de seguimiento se ha de habilitar solo temporalmente", - "IncludeRecommendationsHelpText": "Incluir las películas recomendadas por Prowlarr en la vista de descubrir", "ImportFailedInterp": "la importación ha fallado: {0}", "HiddenClickToShow": "Oculto, clic para mostrar", - "GoToInterp": "Ir a {0}", "ExistingTag": "Etiqueta existente", "EnableInteractiveSearchHelpTextWarning": "Buscar no está soportado por este indexer", "EnableInteractiveSearchHelpText": "Se usará cuando se utilice la búsqueda interactiva", "EnableAutomaticSearchHelpText": "Se usará cuando las búsquedas automáticas se realicen desde el UI o por Prowlarr", "EnableAutomaticSearchHelpTextWarning": "Se usará cuando se utilice la búsqueda interactiva", "Downloading": "Descargando", - "DownloadFailed": "La descarga ha fallado", "DownloadClientUnavailable": "El gestor de descargas no está disponible", "DeleteTagMessageText": "Seguro que quieres eliminar la etiqueta '{0}'?", - "DeleteRestrictionHelpText": "Seguro que quieres eliminar esta restricción?", "DeleteNotificationMessageText": "Seguro que quieres elminiar la notificación '{0}'?", "DeleteBackupMessageText": "Seguro que quieres eliminar la copia de seguridad '{0}'?", "DeleteDownloadClientMessageText": "Seguro que quieres eliminar el gestor de descargas '{0}'?", "DeleteIndexerMessageText": "Seguro que quieres eliminar el indexer '{0}'?", - "Cutoff": "Corte", "CheckDownloadClientForDetails": "comprobar el gestor de descargas para más detalles", "CancelPendingTask": "Seguro que quieres cancelar esta tarea pendiente?", "BranchUpdateMechanism": "Rama usada por el mecanismo de actualización externo", "BranchUpdate": "Qué rama usar para actualizar Prowlarr", "BeforeUpdate": "Antes de actualizar", "AddingTag": "Añadiendo etiqueta", - "ThisConditionMatchesUsingRegularExpressions": "Esta condición coincide con el uso de Expresiones Regulares. Tenga en cuenta que los caracteres {0} tienen significados especiales y necesitan escapar con un {1}", "VisitGithubCustomFormatsAphrodite": "Visita Github para más detalles: ", "UnableToLoadUISettings": "No se han podido cargar los ajustes de UI", - "UnableToLoadRootFolders": "No se han podido cargar las carpetas raiz", "UnableToLoadNamingSettings": "No se han podido cargar los ajustes de renombrado", - "UnableToLoadMediaManagementSettings": "No se han podido cargar los ajustes de Manipulación multimedia", "UnableToLoadLanguages": "No se han podido cargar los idiomas", "UnableToLoadHistory": "No se ha podido cargar la historia", "UnableToLoadGeneralSettings": "No se han podido cargar los ajustes Generales", - "UnableToLoadBlacklist": "No se han podido cargar las bloqueadas", "UnableToLoadBackups": "No se han podido cargar las copias de seguridad", - "UnableToAddANewQualityProfilePleaseTryAgain": "No se ha podido añadir un nuevo perfil de calidad, prueba otra vez.", "UnableToAddANewNotificationPleaseTryAgain": "No se ha podido añadir una nueva notificación, prueba otra vez.", - "UnableToAddANewListExclusionPleaseTryAgain": "No se ha podido añadir una nueva lista de exclusión, prueba otra vez.", "UnableToAddANewIndexerPleaseTryAgain": "No se ha podido añadir un nuevo indexer, prueba otra vez.", "UnableToAddANewDownloadClientPleaseTryAgain": "No se ha podido añadir un nuevo gestor de descargas, prueba otra vez.", - "UnableToAddANewConditionPleaseTryAgain": "No se ha podido añadir una nueva condición, prueba otra vez.", "TagIsNotUsedAndCanBeDeleted": "La etiqueta no se usa y puede ser borrada", "StartTypingOrSelectAPathBelow": "Comienza a escribir o selecciona una ruta debajo", "Restore": "Restaurar", - "RegularExpressionsCanBeTested": "Las expresiones regulares se pueden testear ", "ProwlarrSupportsAnyIndexer": "Prowlarr soporta cualquier indexer que utilice el estandar Newznab, como también cualquiera de los indexers listados debajo.", "ProwlarrSupportsAnyDownloadClient": "Raddar soporta cualquier gestor de descargas que utilice el estandar Newznab, como también los clientes indicados debajo.", "NoUpdatesAreAvailable": "No hay actualizaciones disponibles", "NoTagsHaveBeenAddedYet": "No se han añadido etiquetas todavía", "NoLogFiles": "Sin archivos de registro", "NoBackupsAreAvailable": "No hay copias de seguridad disponibles", - "MissingNotMonitored": "No encontrada, no Monitoreada", "MinutesSixty": "60 Minutos: {0}", "MinutesNinety": "90 Minutos: {0}", "MinutesHundredTwenty": "120 Minutos: {0}", "MaintenanceRelease": "Lanzamiento de mantenimiento", - "LoadingMovieExtraFilesFailed": "La carga de los extras de la película ha fallado", "LinkHere": "aquí", - "HaveNotAddedMovies": "No has añadido películas todavía, quieres importar alguna o todas tus películas primero?", "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Para más información individual sobre las listas de importación, haz clic en los botones de información.", "ForMoreInformationOnTheIndividualDownloadClients": "Para más información individual de los gestores de descarga, haz clic en lls botones de información.", "FilterPlaceHolder": "Buscar películas", - "FileChmodHelpTexts1": "Octal, aplicado a los archivos multimedia importados/renombrados por Prowlarr", "ExtraFileExtensionsHelpTexts2": "Ejemplos : '.sub, .nfo' o 'sub,nfo'", - "Excluded": "Excluida", "Exception": "Excepción", "ErrorLoadingContents": "Error al cargar los contenidos", - "DownloadedAndMonitored": "Descargada y Monitoreada", "CantFindMovie": "Por qué no puedo encontrar mi película?", "ApplyTagsHelpTexts4": "Reemplazar: Reemplazar las etiquetas con las etiquetas introducidas (no introducir etiquetas para eliminar todas las etiquetas)", "ApplyTagsHelpTexts3": "Eliminar: Eliminar las etiquetas introducidas", @@ -511,11 +379,8 @@ "UILanguageHelpTextWarning": "Recargar el Navegador", "UILanguageHelpText": "Lenguaje que Prowlarr usara para el UI", "UILanguage": "Lenguaje de UI", - "MovieInfoLanguage": "Lenguaje de la Información de Película", "ExportCustomFormat": "Exportar Formato Personalizado", - "DownloadPropersAndRepacksHelpText2": "Utilice \"No Preferir\" para ordenar por puntuación de palabras preferidas en vez de proper/repacks", "DownloadPropersAndRepacks": "Propers y Repacks", - "CustomFormatUnknownCondition": "Condición de Formato Personalizado Desconocida '{0}'", "CopyToClipboard": "Copiar al portapapeles", "Priority": "Prioridad", "InteractiveSearch": "Búsqueda Interactiva", @@ -534,16 +399,11 @@ "MovieDetailsNextMovie": "Detalles de la película: Siguiente Película", "CloseCurrentModal": "Cerrar Modal Actual", "AcceptConfirmationModal": "Aceptar el Modal de Confirmación", - "StartProcessing": "Comenzar Procesado", "SearchFailedPleaseTryAgainLater": "La búsqueda ha fallado, por favor inténtalo de nuevo más tarde.", - "Released": "Estrenada", "NoMatchFound": "No se han encontrado coincidencias!", - "ImportIncludeQuality": "Asegúrate de que los archivos incluyen la calidad en el nombre. ej. {0}", "Existing": "Existente", - "Digital": "Digital", "AddRestriction": "Añadir Restricción", "IndexerLongTermStatusCheckSingleClientMessage": "Indexers no disponible por errores durando más de 6 horas: {0}", "IndexerLongTermStatusCheckAllClientMessage": "Ningún indexer está disponible por errores durando más de 6 horas", - "ListTagsHelpText": "Etiquetas con las que se añadirán los elementos", "PrioritySettings": "Prioridad" } diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index feebe6c12..8fcf02b53 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -1,19 +1,15 @@ { "IndexerStatusCheckAllClientMessage": "Tous les indexeurs sont indisponibles en raison d'échecs", - "IndexerSearchCheckNoAvailableIndexersMessage": "Tous les indexeurs compatibles avec la recherche sont temporairement indisponibles en raison d'erreurs d'indexation récentes", "Indexers": "Indexeurs", - "ImportMechanismHealthCheckMessage": "Activer la gestion des téléchargements terminés", "Import": "Importer", "Host": "Hôte", "History": "Historique", "HideAdvanced": "Masquer avancé", "Health": "Santé", "General": "Général", - "Formats": "Formats", "Folder": "Dossier", "Filter": "Filtre", "Files": "Fichiers", - "FailedDownloadHandling": "Gestion des échecs de téléchargement", "Events": "Événements", "Edit": "Éditer", "DownloadClientStatusCheckAllClientMessage": "Aucun client de téléchargement n'est disponible en raison d'échecs", @@ -21,23 +17,18 @@ "DownloadClientCheckNoneAvailableMessage": "Aucun client de téléchargement n'est disponible", "Dates": "Dates", "Date": "Date", - "DiskSpace": "Espace disque", "Delete": "Supprimer", - "Day": "Jour", "CustomFilters": "Filtres personnalisés", "Connections": "Connexions", "Connect": "Notifications", "Clear": "Effacer", - "Cast": "Casting", "Blacklist": "Liste noire", "BackupNow": "Sauvegarder maintenant", "Backup": "Sauvegarde", "AppDataLocationHealthCheckMessage": "La mise à jour ne sera pas possible d'empêcher la suppression AppData sur mise à jour", "Analytics": "Analytique", "All": "Tout", - "AddNewMessage": "Il est facile d'ajouter un nouveau film, commencez simplement à taper le nom du film que vous souhaitez ajouter", "AddExclusion": "Ajouter une exclusion", - "Activity": "Activité", "About": "À propos", "IndexerStatusCheckSingleClientMessage": "Indexeurs indisponibles en raison d'échecs : {0}", "DownloadClientStatusCheckSingleClientMessage": "Clients de Téléchargement indisponibles en raison d'échecs : {0}", @@ -57,24 +48,18 @@ "Settings": "Paramètres", "SelectAll": "Tout sélectionner", "Security": "Sécurité", - "SearchForMissing": "Recherche les manquants", "SearchAll": "Rechercher tout", "Search": "Rechercher", "Scheduled": "Programmé", "SaveChanges": "Sauvegarder les modifications", - "RSSSync": "Synchro RSS", "RootFolderCheckSingleMessage": "Dossier racine manquant : {0}", - "RootFolder": "Dossier racine", "Restrictions": "Restrictions", "RestoreBackup": "Restaurer la sauvegarde", - "Renamed": "Renommé", "RemovedMovieCheckSingleMessage": "Le film {0} a été supprimé de TMDb", - "RemotePathMappings": "Mappages de chemins distants", "ReleaseBranchCheckPreviousVersionMessage": "La branche {0} est pour une version précédente de Prowlarr, définissez la branche sur 'Nightly' pour d'autres mises à jour", "ReleaseBranchCheckOfficialBranchMessage": "La branche {0} n'est pas une branche de version Prowlarr valide, vous ne recevrez pas de mises à jour", "Refresh": "Rafraîchir", "Queue": "File d'attente", - "QualityProfiles": "Profils qualité", "QualityDefinitions": "Définitions qualité", "PtpOldSettingsCheckMessage": "Les indexeurs PassThePopcorn suivants ont des paramètres obsolètes et doivent être mis à jour : {0}", "ProxyCheckResolveIpMessage": "Impossible de résoudre l'adresse IP de l'hôte proxy configuré {0}", @@ -82,43 +67,29 @@ "ProxyCheckBadRequestMessage": "Échec du test du proxy. StatusCode : {0}", "Proxy": "Proxy", "Protocol": "Protocole", - "ProfilesSettingsSummary": "Profils de qualité, de langue et de délai", "PreviewRename": "Aperçu Renommage", - "Path": "Chemin", "Options": "Options", "NoChanges": "Aucun changement", "NoChange": "Pas de changement", - "ImportListStatusCheckAllClientMessage": "Toutes les listes ne sont pas disponibles en raison d'échecs", "Movies": "Films", - "MovieIndex": "Index des films", "Movie": "Film", "MoreInfo": "Plus d'informations", "MonoTlsCheckMessage": "Solution de contournement Prowlarr Mono 4.x tls toujours activée, pensez à supprimer l'option d'environnement MONO_TLS_PROVIDER = legacy", - "ListExclusions": "Liste des exclusions", "ImportFirstTip": "Assurez-vous que vos fichiers incluent la qualité dans leurs noms de fichiers. par exemple.", "Grabbed": "Attrapé", - "Forecast": "Prévision", "DownloadClientsSettingsSummary": "Clients de Téléchargement configuration pour l'intégration dans la recherche de l'interface utilisateur Prowlarr", "DownloadClientCheckUnableToCommunicateMessage": "Impossible de communiquer avec {0}.", "DownloadClient": "Client de Téléchargement", - "CutoffUnmet": "Limite non satisfaite", "MonoNotNetCoreCheckMessage": "Veuillez mettre à niveau vers la version .NET Core de Prowlarr", - "Monitor": "Surveiller", "MinimumAvailability": "Disponibilité minimale", - "MetadataSettingsSummary": "Créer des fichiers de métadonnées lorsque des films sont importés ou actualisés", "MediaManagementSettingsSummary": "Paramètres de dénomination et de gestion des fichiers", - "MediaInfoDllCheckMessage": "Impossible de charger la bibliothèque MediaInfo {0}", "ManualImport": "Importation manuelle", "Logging": "Enregistrement", "LogFiles": "Fichiers Log", - "IndexerRssHealthCheckNoIndexers": "Aucun indexeur disponible avec la synchronisation RSS activée, Prowlarr ne récupérera pas automatiquement les nouvelles versions", "ImportSecondTip": "Pointer Prowlarr vers le dossier contenant tous vos films, pas un en particulier. par exemple.", - "Wanted": "Recherché", "View": "Vue", "Updates": "Mises à jour", - "UnmappedFolders": "Dossiers non mappés", "UI": "UI", - "Timeleft": "Temps restant", "Tasks": "Tâches", "Tags": "Tags", "System": "Système", @@ -126,14 +97,12 @@ "Languages": "Langues", "Language": "Langue", "Indexer": "Indexeur", - "Imported": "Importé", "GeneralSettingsSummary": "Port, SSL, nom d'utilisateur/mot de passe, proxy, analyses et mises à jour", "Filename": "Nom de fichier", "Failed": "Échoué", "EventType": "Type d'événement", "Details": "Détails", "ConnectSettingsSummary": "Notifications et scripts personnalisés", - "Certification": "Certification", "Added": "Ajoutée", "Actions": "Actions", "Info": "Info", @@ -144,12 +113,9 @@ "Close": "Fermer", "Cancel": "Annuler", "Apply": "Appliquer", - "AllMoviesHiddenDueToFilter": "Tous les films sont masqués en raison du filtre appliqué.", "Age": "Âge", - "AddList": "Ajouter la liste", "ConnectionLostMessage": "Prowlarr a perdu sa connexion au backend et devra être rechargé pour fonctionner à nouveau.", "Warn": "Avertissement", - "Unavailable": "Indisponible", "Type": "Type", "Title": "Titre", "Time": "Heure", @@ -163,97 +129,69 @@ "Save": "Sauvegarder", "Restart": "Redémarrer", "Reload": "Recharger", - "RejectionCount": "Compteur de rejet", "Peers": "Pairs", "PageSize": "Pagination", - "OrganizeModalNamingPattern": "Motif de renommage :", "OrganizeModalAllPathsRelative": "Tous les chemins sont relatifs à :", - "Organize": "Organiser", "Ok": "OK", "OAuthPopupMessage": "Les pop-ups sont bloquées par votre navigateur", "Name": "Nom", - "Monitored": "Surveillé", "Message": "Message", "Level": "Niveau", "KeyboardShortcuts": "Raccourcis clavier", "HealthNoIssues": "Aucun problème avec votre configuration", - "Extension": "Extension", "ConnectionLostAutomaticMessage": "Prowlarr essaiera de se connecter automatiquement, ou bien vous pouvez cliquer sur \"Recharger\" en bas.", "SystemTimeCheckMessage": "L'heure du système est décalée de plus d'un jour. Les tâches planifiées peuvent ne pas s'exécuter correctement tant que l'heure ne sera pas corrigée", - "SettingsWeekColumnHeaderHelpText": "Affiché au dessus de chaque colonne quand \"Semaine\" est l'affichage actif", "SettingsShowRelativeDates": "Afficher les dates relatives", "UnsavedChanges": "Changement non sauvegardés", - "ShowTitle": "Afficher le titre", "ShowSizeOnDisk": "Afficher la taille sur le disque", "ShowSearchHelpText": "Afficher le bouton de recherche au survol de la souris", "ShowSearch": "Afficher la recherche", - "ShowPath": "Afficher le chemin", "SettingsWeekColumnHeader": "En-tête de la colonne : Semaine", - "SettingsUiLanguage": "Langue de l'interface", "SettingsTimeFormat": "Format de l'heure", "SettingsShowRelativeDatesHelpText": "Afficher les dates relatives (Aujourd'hui/ Hier/ etc) ou absolues", "SettingsShortDateFormat": "Format de date court", - "SettingsRemotePathMappingRemotePath": "Chemin distant", "SettingsRemotePathMappingLocalPath": "Chemin local", "SettingsLongDateFormat": "Format de date long", "SettingsEnableColorImpairedModeHelpText": "Style altéré pour aider les personnes daltoniennes à distinguer les informations en couleurs", "SettingsEnableColorImpairedMode": "Activer le mode daltonien", - "SearchOnAdd": "Rechercher à l'ajout", "RecentFolders": "Dossiers récents", - "PosterSize": "Taille des posters", "PosterOptions": "Options des posters", "PendingChangesStayReview": "Rester et vérifier les changements", "PendingChangesMessage": "Vous avez effectué des changements non sauvegardés, souhaitez vous quitter cette page ?", "PendingChangesDiscardChanges": "Abandonner les changements et quitter", "MonoVersionCheckUpgradeRecommendedMessage": "La version installée de Mono {0} est supportée mais mettre à jour en version {1} est recommandé.", - "MonoVersionCheckNotSupportedMessage": "La version installée de Mono {0} n'est plus supportée. Veuillez mettre à jour Mono en version {1}.", "InteractiveImport": "Importation interactive", "ExistingMovies": "Films existants", - "AddRemotePathMapping": "Ajouter un chemin distant", "DetailedProgressBar": "Barre de progression détaillée", - "ColonReplacementFormatHelpText": "Changer la manière dont Prowlarr remplace les 'deux-points'", "CloneProfile": "Cloner le profil", "CloneIndexer": "Cloner l'indexeur", "ClientPriority": "Priorité du client", - "ClickToChangeLanguage": "Cliquer pour changer la langue", "ChangeHasNotBeenSavedYet": "Les changements n'ont pas encore été sauvegardés", - "CertificationCountryHelpText": "Choisir un pays pour les classifications de films", "CertificateValidationHelpText": "Change la rigueur de la vérification du certificat HTTPS", "CertificateValidation": "Validation du certificat", "BypassProxyForLocalAddresses": "Contourner le proxy pour les adresses locales", "Branch": "Branche", - "BlacklistHelpText": "Empêche Prowlarr de récupérer automatiquement ce film", "BindAddressHelpText": "Adresse IP4 valide ou '*' pour toutes les interfaces", "BindAddress": "Adresse d'attache", "Backups": "Sauvegardes", "BackupRetentionHelpText": "Les sauvegardes automatiques plus anciennes que la période de conservation seront automatiquement effacées", "BackupIntervalHelpText": "Intervalle entre les sauvegardes automatiques", - "AutoUnmonitorPreviouslyDownloadedMoviesHelpText": "Les films qui sont effacés du disque dur sont automatiquement non-surveillés dans Prowlarr", "Automatic": "Automatique", "AuthenticationMethodHelpText": "Un nom d'utilisateur et un mot de passe sont nécessaires pour accéder à Prowlarr", "Authentication": "Authentification", "AreYouSureYouWantToResetYourAPIKey": "Êtes vous sûr de vouloir réinitialiser votre clé API ?", - "AreYouSureYouWantToDeleteThisImportListExclusion": "Êtes vous sûr de vouloir effacer cette exclusion de liste d'imports ?", "ApplyTags": "Appliquer les Tags", "AppDataDirectory": "Dossier AppData", "ApiKey": "Clé API", "AnalyticsEnabledHelpText": "Envoyer des informations anonymes sur l'utilisation et les erreurs vers les serveurs de Prowlarr. Cela inclut des informations sur votre navigateur, quelle page Prowlarr WebUI vous utilisez, les rapports d'erreur ainsi que le système d'exploitation et sa version. Nous utiliserons ces informations pour prioriser les nouvelles fonctionnalités et les corrections de bugs.", - "AlreadyInYourLibrary": "Déjà présent dans votre collection", "AllowHardcodedSubs": "Autoriser les sous-titres incrustés", - "AddMoviesMonitored": "Ajouter des films en mode surveillé", "IgnoreDeletedMovies": "Ignorer les films effacés", "IgnoredAddresses": "Adresses ignorées", - "ICalHttpUrlHelpText": "Copiez cette URL dans votre client ou cliquez pour souscrire si votre navigateur est compatible avec webcal", "Hostname": "Nom d'hôte", - "Group": "Groupe", "GrabID": "ID du grab", - "Global": "Global", "GeneralSettings": "Réglages Généraux", - "Folders": "Dossiers", "Fixed": "Corrigé", - "FileNames": "Noms de fichier", "FileChmodMode": "Mode chmod du fichier", - "Ended": "Terminé", "EnableSslHelpText": " Nécessite un redémarrage en tant qu'administrateur pour être effectif", "EnableSSL": "Activer le SSL", "EnableMediaInfoHelpText": "Extraire les informations de la vidéo (résolution, temps et codec par exemple) depuis les fichiers. Cela nécessite que Prowlarr lise des parties du fichier ce qui peut entraîner une forte utilisation du disque dur ou du réseau pendant les scans.", @@ -267,34 +205,23 @@ "EnableAutomaticAdd": "Activer l'ajout automatique", "EnableAutoHelpText": "En cas d'activation, les films seront automatiquement ajoutés à Prowlarr depuis cette liste", "Enable": "Activer", - "EditMovie": "Éditer le film", "DownloadWarningCheckDownloadClientForMoreDetails": "Avertissement téléchargement : voir le client de téléchargement pour plus de détails", - "DownloadFailedCheckDownloadClientForMoreDetails": "Téléchargement échoué : voir le client de téléchargement pour plus de détails", "DownloadClientSettings": "Réglages Clients de téléchargement", "Docker": "Docker", - "DestinationPath": "Chemin de Destination", "DeleteTag": "Supprimer le tag", - "DeleteRestriction": "Supprimer la restriction", "DeleteNotification": "Supprimer la notification", "DeleteIndexer": "Supprimer l'indexeur", - "DeleteFile": "Supprimer le fichier", "DeleteEmptyFolders": "Supprimer les dossiers vides", "DeleteDownloadClient": "Supprimer le client de téléchargement", "DeleteBackup": "Supprimer la sauvegarde", "DBMigration": "Migration de la base de données", - "CutoffFormatScoreHelpText": "Quand ce score de format personnalisé est atteint, Prowlarr ne téléchargera plus de films", "CreateGroup": "Créer un groupe", - "CreateEmptyMovieFolders": "Créer des dossiers films vides", "CopyUsingHardlinksHelpText": "Utiliser des liens fixes quand on essaye de copier des fichiers appartenant à des torrents en cours de partage", "ConnectSettings": "Paramètres de connexion", - "CertificationCountry": "Pays de classification", "BackupFolderHelpText": "Les chemins correspondants seront sous le répertoire AppData de Prowlarr", - "AddImportExclusionHelpText": "Empêcher le film d’être ajouté automatiquement à Prowlarr par des listes", "ImportExtraFiles": "Importer les fichiers extra", "IllRestartLater": "Je redémarrerai plus tard", - "Cutoff": "Limite", "ClickToChangeMovie": "Cliquer pour changer le film", - "CantFindMovie": "Pourquoi ne puis-je pas trouver mon film ?", "CancelPendingTask": "Êtes-vous sur de vouloir annuler cette tâche en attente ?", "BranchUpdateMechanism": "Branche utilisée par le mécanisme de mise à jour extérieur", "BranchUpdate": "Branche à utiliser pour mettre Prowlarr à jour", @@ -312,43 +239,30 @@ "EnableAutomaticSearchHelpText": "Sera utilisé lorsque les recherches automatiques sont effectuées via l'interface utilisateur ou par Prowlarr", "Downloading": "Téléchargement", "DownloadClientUnavailable": "Le client de téléchargement n'est pas disponible", - "DeleteListMessageText": "Voulez-vous vraiment supprimer la liste '{0}' ?", "DeleteIndexerMessageText": "Voulez-vous vraiment supprimer l'indexeur '{0}' ?", - "GoToInterp": "Aller à {0}", "ForMoreInformationOnTheIndividualDownloadClients": "Pour plus d'informations sur les clients de téléchargement individuels, cliquez sur les boutons d'information.", "FilterPlaceHolder": "Rechercher des indexeurs", - "Excluded": "Exclu", "Exception": "Exception", "EditIndexer": "Modifier l'indexeur", - "DownloadFailed": "Échec du téléchargement", "DownloadedAndMonitored": "Téléchargé et Surveillé", "Disabled": "Désactivé", "DeleteNotificationMessageText": "Êtes-vous sûr de vouloir supprimer la notification '{0}' ?", "AutomaticSearch": "Recherche automatique", "AddIndexer": "Ajouter un indexeur", - "ListSyncLevelHelpText": "Les films de la bibliothèque seront supprimés ou non surveillés s'ils ne figurent pas dans votre liste", "LinkHere": "ici", "Interval": "Intervalle", "InteractiveSearch": "Recherche interactive", "IndexerPriorityHelpText": "Priorité de l'indexeur de 1 (la plus élevée) à 50 (la plus basse). Par défaut: 25.", "IndexerPriority": "Priorité de l'indexeur", - "IncludeRecommendationsHelpText": "Inclure les films recommandés par Prowlarr dans la vue découverte", "ImportMovies": "Importer Films", "Importing": "Importation", - "ImportCustomFormat": "Importer format personnalisé", "HaveNotAddedMovies": "Vous n'avez pas encore ajouté de films, voulez-vous d'abord importer certains ou tous vos films ?", - "ExtraFileExtensionsHelpTexts2": "Exemples : '.sub, .nfo' ou 'sub,nfo'", "ExcludeMovie": "Exclure Film", - "DelayingDownloadUntilInterp": "Retarder le téléchargement jusqu'au {0} à {1}", "CustomFormatUnknownCondition": "Condition de format personnalisé inconnue '{0}'", - "Blacklisted": "Liste noire", "UnableToLoadRestrictions": "Impossible de charger les restrictions", - "UnableToLoadQualityProfiles": "Impossible de charger les profils de qualité", "UnableToLoadQualityDefinitions": "Impossible de charger les définitions de qualité", "UnableToLoadNotifications": "Impossible de charger les notifications", - "UnableToLoadMovies": "Impossible de charger les films", "UnableToLoadMediaManagementSettings": "Impossible de charger les paramètres de gestion des médias", - "UnableToLoadListOptions": "Impossible de charger les options de la liste", "WaitingToImport": "En attente d'importation", "Version": "Version", "Username": "Nom d'utilisateur", @@ -357,76 +271,54 @@ "UrlBaseHelpText": "Pour la prise en charge du proxy inverse, la valeur par défaut est vide", "URLBase": "Base URL", "YesCancel": "Oui, annuler", - "MovieIsDownloadingInterp": "Le film est en cours de téléchargement - {0}% {1}", "MovieInfoLanguageHelpTextWarning": "Rechargement du navigateur requis", - "MovieInfoLanguage": "Langue Infos sur le film", "MovieFiles": "Fichiers vidéo", - "MovieAvailableButMissing": "Film disponible, mais manquant", "MoreDetails": "Plus de détails", "MonoVersion": "Mono Version", "Mode": "Mode", - "MissingMonitoredAndConsideredAvailable": "Manquant, surveillé et considéré comme disponible", "MinutesSixty": "60 Minutes : {0}", "MinutesNinety": "90 Minutes : {0}", "MinutesHundredTwenty": "120 Minutes : {0}", "MinimumLimits": "Limites minimales", - "MinimumAge": "Âge minimum", "MediaManagementSettings": "Paramètres de gestion des médias", "Mechanism": "Mécanisme", - "MaximumSize": "Taille maximum", "MaximumLimits": "Limites maximales", "Manual": "Manuel", "MaintenanceRelease": "Version de maintenance", "Logs": "Journaux", "LogLevelTraceHelpTextWarning": "La journalisation des traces ne doit être activée que temporairement", "LogLevel": "Niveau du journal", - "LoadingMovieFilesFailed": "Le chargement des fichiers vidéo a échoué", "LoadingMovieCreditsFailed": "Échec du chargement des crédits du film", - "ImportFailedInterp": "Importation a échoué : {0}", "HiddenClickToShow": "Caché, cliquez pour afficher", "IncludeHealthWarningsHelpText": "Inclure avertissements santé", "FocusSearchBox": "Zone de recherche de focus", - "RequiredHelpText": "Cette {0} condition doit correspondre pour que le format personnalisé s'applique. Sinon, une seule correspondance {1} est suffisante.", "ProxyBypassFilterHelpText": "Utiliser ',' comme séparateur et '*.' comme caractère générique pour les sous-domaines", - "NegateHelpText": "Si coché, le format personnalisé ne s'appliquera pas si cette condition {0} correspond.", "IncludeCustomFormatWhenRenamingHelpText": "Inclus dans {Custom Formats} renommer le format", - "FileChmodHelpTexts2": "Le même mode est appliqué aux films/sous-dossiers avec le bit d'exécution ajouté, par exemple, 0644 devient 0755", "ExtraFileExtensionsHelpTexts1": "Liste séparée par des virgules des fichiers supplémentaires à importer (.nfo sera importé en tant que .nfo-orig)", - "WhitelistedSubtitleTags": "Balises de sous-titres sur liste blanche", "WeekColumnHeader": "En-tête de colonne de la semaine", "Uptime": "Durée de fonctionnent", - "UpgradeAllowedHelpText": "Ne sera pas mis à jour si la qualité est désactivée", "UpdateScriptPathHelpText": "Chemin vers un script personnalisé qui prend un package de mise à jour extraite et gère le reste du processus de mise à jour", "UpdateMechanismHelpText": "Utiliser le programme de mise à jour intégré dans Prowlarr ou un script", "UpdateAutomaticallyHelpText": "Télécharger et installer automatiquement les mises à jour. Vous pourrez toujours installer à partir de System : Updates", - "UnmonitoredHelpText": "Inclure les films non surveillés dans le flux iCal", "UnableToLoadUISettings": "Impossible de charger les paramètres de l'interface utilisateur", "UnableToLoadTags": "Impossible de charger les balises", - "UnableToLoadLanguages": "Impossible de charger les langues", "UnableToLoadIndexers": "Impossible de charger les indexeurs", "UnableToLoadHistory": "Impossible de charger l'historique", "UnableToLoadGeneralSettings": "Impossible de charger les paramètres généraux", "UnableToLoadDownloadClients": "Impossible de charger les clients de téléchargement", - "UnableToLoadDelayProfiles": "Impossible de charger les profils de délai", "UnableToLoadBlacklist": "Impossible de charger la liste noire", "UnableToLoadBackups": "Impossible de charger les sauvegardes", - "UnableToAddANewQualityProfilePleaseTryAgain": "Impossible d'ajouter un nouveau profil de qualité, veuillez réessayer.", "UnableToAddANewNotificationPleaseTryAgain": "Impossible d'ajouter une nouvelle notification, veuillez réessayer.", - "UnableToAddANewListExclusionPleaseTryAgain": "Impossible d'ajouter une nouvelle exclusion de liste, veuillez réessayer.", "UnableToAddANewIndexerPleaseTryAgain": "Impossible d'ajouter un nouvel indexeur, veuillez réessayer.", "UnableToAddANewDownloadClientPleaseTryAgain": "Impossible d'ajouter un nouveau client de téléchargement, veuillez réessayer.", - "UnableToAddANewConditionPleaseTryAgain": "Impossible d'ajouter une nouvelle condition, veuillez réessayer.", "TorrentDelay": "Torrent Délai", "PriorityHelpText": "Donnez la priorité à plusieurs clients de téléchargement. Le Round-Robin est utilisé pour les clients ayant la même priorité.", "TagIsNotUsedAndCanBeDeleted": "La balise n'est pas utilisée et peut être supprimée", "TagsHelpText": "S'applique aux films avec au moins une balise correspondante", "StartTypingOrSelectAPathBelow": "Commencer à taper ou sélectionner un chemin ci-dessous", - "ProtocolHelpText": "Choisissez le(s) protocole(s) à utiliser et celui qui est préféré lors du choix entre des versions par ailleurs égales", "PreferIndexerFlags": "Préférer les indicateurs d'indexation", "NoTagsHaveBeenAddedYet": "Aucune identification n'a été ajoutée pour l'instant", - "MinFormatScoreHelpText": "Score de format personnalisé minimum autorisé à télécharger", "IndexerFlags": "Indicateurs d'indexeur", - "IncludeCustomFormatWhenRenaming": "Inclure un format personnalisé lors du changement de nom", "DeleteTagMessageText": "Voulez-vous vraiment supprimer la balise '{0}' ?", "DelayProfile": "Profil de delai", "UISettings": "Paramètres UI", @@ -434,7 +326,6 @@ "UILanguageHelpText": "Langue que Prowlarr utilisera pour l'interface utilisateur", "UILanguage": "UI Langue", "Torrents": "Torrents", - "TMDBId": "Identifiant TMDb", "TestAllLists": "Tester toutes les listes", "TestAllClients": "Tester tous les clients", "TagCannotBeDeletedWhileInUse": "Ne peut pas être supprimé pendant l'utilisation", @@ -445,23 +336,15 @@ "SSLCertPath": "Chemin du certificat SSL", "SSLCertPasswordHelpText": "Mot de passe pour le fichier pfx", "SSLCertPassword": "Mot de passe du certificat SSL", - "SourcePath": "Chemin source", "SkipFreeSpaceCheckWhenImportingHelpText": "À utiliser lorsque Prowlarr ne parvient pas à détecter l'espace libre dans le dossier racine de votre film", - "ShowYear": "Afficher l'année", "ShowTitleHelpText": "Afficher le titre du film sous l'affiche", - "ShowQualityProfileHelpText": "Afficher le profil de qualité sous l'affiche", "ShownClickToHide": "Montré, cliquez pour masquer", - "ShowMovieInformation": "Afficher les informations sur le film", "ShowGenres": "Afficher les genres", - "ShowCertification": "Afficher la certification", "ShouldMonitorHelpText": "Si activé, les films ajoutés par cette liste sont ajoutés et surveillés", - "SetPermissionsLinuxHelpTextWarning": "Si vous ne savez pas ce que font ces paramètres, ne les modifiez pas.", "SetPermissions": "Définir les autorisations", "SendAnonymousUsageData": "Envoyer des données d'utilisation anonymes", - "SearchForMovie": "Rechercher un film", "ScriptPath": "Chemin du script", "SaveSettings": "Enregistrer les paramètres", - "RSSSyncInterval": "Intervalle de synchronisation RSS", "RSSIsNotSupportedWithThisIndexer": "RSS n'est pas pris en charge avec cet indexeur", "Retention": "Rétention", "Result": "Résultat", @@ -471,34 +354,23 @@ "RestartNow": "Redémarrer maintenant", "ResetAPIKey": "Réinitialiser la clé API", "Reset": "Réinitialiser", - "RescanAfterRefreshHelpTextWarning": "Prowlarr ne détectera pas automatiquement les modifications apportées aux fichiers lorsqu'il n'est pas défini sur «Toujours»", "RequiredPlaceHolder": "Ajouter une nouvelle restriction", - "ReplaceIllegalCharacters": "Remplacer les caractères illégaux", "RenameMoviesHelpText": "Prowlarr utilisera le nom de fichier existant si le changement de nom est désactivé", "RemovingTag": "Suppression du tag", - "QualityProfileDeleteConfirm": "Voulez-vous vraiment supprimer le profil de qualité {0}", "MarkAsFailedMessageText": "Voulez-vous vraiment marquer '{0}' comme échoué ?", "ExistingTag": "Tag existant", - "DownloadPropersAndRepacksHelpText2": "Utiliser 'Ne pas préférer' pour trier par score de mot préféré par rapport aux propres/repacks", "DownloadPropersAndRepacks": "Propres et Repacks", - "RemoveHelpTextWarning": "La suppression supprimera le téléchargement et le(s) fichier(s) du client de téléchargement.", "RemoveFromDownloadClient": "Supprimer du client de téléchargement", "RemoveFilter": "Supprimer le filtre", "RemovedFromTaskQueue": "Supprimé de la file d'attente des tâches", - "Remove": "Retirer", "ReleaseDates": "Date de sortie", "RefreshMovie": "Actualiser film", - "Redownload": "Télécharger à nouveau", "RecyclingBin": "Corbeille", - "RecycleBinCleanupDaysHelpTextWarning": "Les fichiers dans la corbeille plus anciens que le nombre de jours sélectionné seront nettoyés automatiquement", "Reason": "Raison", "ReadTheWikiForMoreInformation": "Consultez le Wiki pour plus d'informations", - "ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "Prowlarr prend en charge toutes les listes de films RSS ainsi que celle indiquée ci-dessous.", "ProwlarrSupportsAnyIndexer": "Prowlarr prend en charge de nombreux indexeurs en plus de tout indexeur qui utilise la norme Newznab/Torznab en utilisant « Generic Newznab » (pour usenet) ou « Generic Torznab » (pour les torrents). Recherchez et sélectionnez votre indexeur ci-dessous.", "ProwlarrSupportsAnyDownloadClient": "Prowlarr prend en charge tout client de téléchargement qui utilise le standard Newznab, ainsi que d'autres clients de téléchargement répertoriés ci-dessous.", - "Queued": "En file d'attente", "QualitySettings": "Paramètres Qualité", - "PublishedDate": "Date de publication", "ProxyUsernameHelpText": "Il vous suffit de saisir un nom d'utilisateur et un mot de passe si vous en avez besoin. Sinon, laissez-les vides.", "ProxyType": "Type de proxy", "ProxyPasswordHelpText": "Il vous suffit de saisir un nom d'utilisateur et un mot de passe si vous en avez besoin. Sinon, laissez-les vides.", @@ -511,7 +383,6 @@ "PageSizeHelpText": "Nombre d'éléments à afficher sur chaque page", "PackageVersion": "Version du package", "OpenBrowserOnStart": "Ouvrir le navigateur au démarrage", - "OnRenameHelpText": "Lors du changement de nom", "OnDeleteHelpText": "Lors de la suppression", "NoUpdatesAreAvailable": "Aucune mise à jour n'est disponible", "NotificationTriggers": "Déclencheurs de notification", @@ -522,14 +393,11 @@ "NoBackupsAreAvailable": "Aucune sauvegarde n'est disponible", "New": "Nouveau", "NetCore": ".NET Core", - "MustNotContain": "Ne doit pas contenir", "MustContain": "Doit contenir", - "MovieTitleHelpText": "Le titre du film à exclure (peut être quelque chose de significatif)", "MovieIndexScrollTop": "Index des films : faire défiler vers le haut", "MovieIndexScrollBottom": "Index des Films : faire défiler vers le bas", "MovieDetailsPreviousMovie": "Détails du film : Film Précédent", "MovieDetailsNextMovie": "Détails du film : Prochain Film", - "MovieIsUnmonitored": "Le film n'est pas surveillé", "MovieFolderFormat": "Format de dossier de film", "MIA": "MIA", "LaunchBrowserHelpText": " Ouvrer un navigateur Web et accéder à la page d'accueil de Prowlarr au démarrage de l'application.", @@ -537,15 +405,10 @@ "AddingTag": "Ajouter un tag", "OnHealthIssueHelpText": "Sur un problème de santé", "AcceptConfirmationModal": "Accepter la modalité de confirmation", - "StartProcessing": "Lancer le traitement", "SearchFailedPleaseTryAgainLater": "La recherche a échoué, veuillez réessayer plus tard.", - "Released": "Libéré", "OpenThisModal": "Ouvrer ce modal", - "ImportRootPath": "Pointer Prowlarr vers le dossier contenant tous vos films, pas un en particulier. par exemple. {0} et non {1}", "ImportErrors": "Erreurs d'importation", - "EditRestriction": "Modifier la restriction", "CancelProcessing": "Annuler le traitement", - "AddMovie": "Ajouter Film", "IndexerLongTermStatusCheckSingleClientMessage": "Indexeurs indisponibles en raison de pannes pendant plus de 6 heures : {0}", "IndexerLongTermStatusCheckAllClientMessage": "Tous les indexeurs sont indisponibles en raison d'échecs de plus de 6 heures", "Yesterday": "Hier", @@ -564,7 +427,6 @@ "SettingsFilterSentryEvents": "Filtrer les événements d'analyse", "SettingsConsoleLogLevel": "Niveau de journalisation de la console", "SearchIndexers": "Recherche indexeurs", - "NewznabVipCheckExpiredClientMessage": "Les avantages VIP de l'indexeur ont expiré : {0}", "IndexersSelectedInterp": "{0} indexeur(s) sélectionné(s)", "IndexerRss": "Indexeur Rss", "IndexerQuery": "Requête indexeur", diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index 62783df66..1b1a08e23 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -1,35 +1,26 @@ { "About": "Névjegy", "Analytics": "Analitika", - "AlternativeTitle": "Alternatív cím", "AllowHardcodedSubsHelpText": "Az észlelt beégetett feliratok automatikusan le lesznek töltve", - "AllMoviesHiddenDueToFilter": "Minden film el van rejtve a kiválasztott filter miatt.", "AddNewMovie": "Új film hozzáadása", - "AddNew": "Új hozzáadása", "AddMovies": "Film hozzáadása", "AddIndexer": "Indexer hozzáadása", "AddingTag": "Címke hozzáadása", - "AddExclusion": "Kivétel hozzáadása", "Error": "Hiba", "EnableCompletedDownloadHandlingHelpText": "A befejezett letöltések automatikus importálása a letöltési kliensből", "EnableColorImpairedModeHelpText": "Megváltoztatott színek, hogy a színvak felhasználók jobban meg tudják különböztetni a színkódolt információkat", "EnableAutomaticSearchHelpTextWarning": "Interaktív keresés esetén is felhasználható", - "DestinationRelativePath": "Célmappa Távoli Elérési Útvonala", "DeleteTag": "Címke Törlése", "EnableAutomaticSearchHelpText": "Akkor kerül felhasználásra, ha az automatikus kereséseket a kezelőfelületen vagy a Prowlarr-on keresztül hajtják végre", "EnableAutomaticSearch": "Engedélyezd az Automatikus Keresést", "EnableAutomaticAdd": "Engedélyezd az automatikus hozzáadást", "EnableAutoHelpText": "Ha engedélyezve van, a Filmek automatikusan hozzáadódnak a Prowlarr-hoz ebből a listából", "Enable": "Aktiválás", - "EditRemotePathMapping": "Távoli Elérési Útvonal Módosítása", "EditMovie": "Film Szerkesztése", "EditIndexer": "Indexer Szerkesztése", "Edit": "Szerkesztés", - "DownloadWarning": "Letöltési figyelmeztetés: {0}", "Downloading": "Letöltés Alatt", - "DownloadFailedCheckDownloadClientForMoreDetails": "Letöltés Sikertelen : Nézd meg a letöltőkliensed további információért", "DownloadedButNotMonitored": "Letöltve, de nincs Figyelve", - "Downloaded": "Letöltve", "DownloadClientUnavailable": "Letöltőkliens nem elérhető", "DownloadClientStatusCheckSingleClientMessage": "Letöltőkliens hiba miatt nem elérhető: {0}", "DownloadClientStatusCheckAllClientMessage": "Az összes letöltőkliens elérhetetlen, hiba miatt", @@ -39,42 +30,29 @@ "DownloadClientCheckUnableToCommunicateMessage": "Nem lehet kommunikálni a következővel: {0}.", "DownloadClientCheckNoneAvailableMessage": "Nem található letöltési kliens", "DownloadClient": "Letöltési Kliens", - "DotNetVersionCheckNotRecommendedMessage": "A jelenleg telepített .Net Framework {0} támogatott, de javasoljuk, hogy frissíts legalább {1} verzióra.", "Docker": "Docker", - "Discover": "Felfedezés", "Disabled": "Letiltott", - "Digital": "Digitális", "Details": "Részletek", - "DestinationPath": "Célmappa Útvonala", "DeleteTagMessageText": "Biztosan törlöd a(z) „{0}” címkét?", - "DeleteSelectedMovieFiles": "Töröld a Kiválaszott Film Fájlokat", "DeleteRestriction": "Megkötés Törlése", "DeleteNotificationMessageText": "Biztosan törlöd a(z) „{0}” értesítést?", "DeleteNotification": "Értesítés Törlése", - "DeleteList": "Lista Törlése", "DeleteIndexerMessageText": "Biztosan törlöd a(z) „{0}” indexert?", "DeleteIndexer": "Indexer Törlése", - "DeleteFile": "Fájl Törlése", "DeleteEmptyFolders": "Üres Mappa Törlése", "DeleteDownloadClientMessageText": "Biztosan törlöd a(z) „{0}” letöltő klienst?", "DeleteDownloadClient": "Letöltőkliens Törlése", - "Deleted": "Törölve", "DeleteBackupMessageText": "Biztosan törlöd a(z) „{0}” biztonsági mentést?", "DeleteBackup": "Biztonsági Mentés Törlése", "Delete": "Törlés", - "DelayProfiles": "Késleltetési Profilok", "DelayProfile": "Késleltetési Profil", "DBMigration": "DB Migráció", "Dates": "Dátumok", "Date": "Dátum", - "CutoffHelpText": "Amint ezt a minőséget eléri, a Prowlarr többé nem fog filmeket letölteni", "CustomFormatUnknownConditionOption": "Ismeretlen „{0}” opció a(z) „{1}” feltételhez", - "CustomFormatsSettingsSummary": "Egyéni Formátum és Beállításai", "CustomFormats": "Egyéni Formátumok", "CustomFilters": "Egyéni Szűrők", - "CreateGroup": "Csoport létrehozása", "CreateEmptyMovieFolders": "Készíts egy üres mappát", - "CopyUsingHardlinksHelpTextWarning": "Esetenként az írásvédettség megakadályozza a Seedelt fájlok átnevezését. Ideiglenesen állítsd le a Seedelést, hogy a Prowlarr át tudja nevezni a fájlokat.", "CopyToClipboard": "Másold a Vágólapra", "ConnectSettingsSummary": "Értesítések és egyéni szkriptek", "ConnectSettings": "Kapcsolódási Beállítások", @@ -89,24 +67,18 @@ "Close": "Bezárás", "CloneProfile": "Profil Klónozása", "CloneIndexer": "Indexer Klónozása", - "CloneCustomFormat": "Egyéni Formátum Klónozása", "ClientPriority": "Kliens Prioritás", - "ClickToChangeMovie": "Kattints a film módosításához", "Clear": "Törölni", - "CheckForFinishedDownloadsInterval": "Befejezett letöltések átnézésének intervalluma", "ChangeHasNotBeenSavedYet": "A változások még nem lettek elmentve", - "CertificationCountryHelpText": "Válasszd ki melyik ország korhatárbesorolása jelenjen meg", "Certification": "Tanúsítvány", "CertificateValidationHelpText": "Módosítsa a HTTPS tanúsítás szigorúságát", "CertificateValidation": "Tanúsítvány érvényesítése", - "CantFindMovie": "Miért nem találom a filmemet?", "CancelPendingTask": "Biztosan törlöd ezt a függőben lévő feladatot?", "Cancel": "Vissza", "BypassProxyForLocalAddresses": "Proxy megkerülése a helyi hálózatos címekhez", "BranchUpdateMechanism": "A külső frissítési mechanizmus által használt ágazat", "BranchUpdate": "Ágazattípus a Prowlarr frissítéseihez", "Branch": "Ágazat", - "BlacklistHelpText": "Megakadályozza, hogy a Prowlarr automatikusan letöltse újra ezt a filmet", "Blacklist": "Feketelista", "BindAddressHelpText": "Érvényes IP4-cím, vagy „*” minden interfészhez", "BindAddress": "Kapcsolási Cím", @@ -117,7 +89,6 @@ "BackupIntervalHelpText": "Időeltérés a biztonsági mentések között", "BackupFolderHelpText": "Az elérési útvonalak a Prowlarr AppData könyvtárában lesznek", "Backup": "Biztonsági Mentés", - "AvailabilityDelay": "Elérhetőség Késleltetése", "AutoRedownloadFailedHelpText": "Másik kiadás automatikus keresése és letöltése", "AutomaticSearch": "Automatikus Keresés", "Automatic": "Automatikus", @@ -126,9 +97,7 @@ "AnalyticsEnabledHelpText": "Küldjön névtelen használati és hibainformációkat a Prowlarr szervereire. Ez magában foglalja a böngészőjéről szóló információkat, mely Prowlarr WebUI oldalakat használja, a hibajelentést, valamint az operációs rendszer adatait. Ezeket az információkat a funkciók és a hibajavítások rangsorolására használjuk fel.", "AuthenticationMethodHelpText": "Felhasználónév és Jelszó szükséges a Prowlarr-hoz való hozzáféréshez", "Authentication": "Hitelesítés", - "AsAllDayHelpText": "Az események egész napos eseményként jelennek meg a naptáradban", "AreYouSureYouWantToResetYourAPIKey": "Biztos hogy vissza szeretnéd állítani az API-Kulcsod?", - "AreYouSureYouWantToDeleteThisImportListExclusion": "Biztos, hogy törölni szeretnéd az importálási lista kivételeit?", "ApplyTagsHelpTexts2": "Hozzáadás: Új címkék hozzáadása a meglévő címkékhez", "ApplyTagsHelpTexts1": "Hogyan adjunk hozzá címkéket a kiválasztott filmhez", "ApplyTags": "Címkék alkalmazása", @@ -139,7 +108,6 @@ "Apply": "Alkalmazás", "AppDataLocationHealthCheckMessage": "A frissítés nem lehetséges anélkül hogy az AppData ne törlődjön", "AppDataDirectory": "AppData Mappa", - "AddRemotePathMapping": "Adj Meg Egy Távoli Elérési Útvonalat", "Added": "Hozzáadva", "Actions": "Teendők", "History": "Történet", @@ -147,14 +115,10 @@ "HiddenClickToShow": "Rejtett, kattints a megjelenítéshez", "HealthNoIssues": "Nincs hiba a konfigurációval", "Health": "Állapot", - "HardlinkCopyFiles": "Hardlinkelés/Fájl(ok) Másolása", "GrabReleaseMessageText": "Prowlarr nem tudta meghatározni, hogy melyik filmhez készült ez a kiadás. Lehet, hogy a Prowlarr nem tudja automatikusan importálni ezt a kiadást. Meg szeretnéd ragadni a (z) „{0}”-t?", - "Genres": "Műfajok", "GeneralSettingsSummary": "Port, SSL, felhasználónév / jelszó, proxy, elemzések, és frissítések", - "FreeSpace": "Szabad Tárhely", "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Az egyes importálási listákkal kapcsolatos további információkért kattints az info gombokra.", "ForMoreInformationOnTheIndividualDownloadClients": "Ha többet szeretnél megtudni a különböző letöltési kliensekről, kattints az információs gombokra.", - "Forecast": "Előrejelzés", "Folders": "Mappák", "Folder": "Mappa", "FocusSearchBox": "Fókusz Keresőmező", @@ -163,15 +127,11 @@ "Filter": "Szűrő", "Files": "Fájl", "Filename": "Fájlnév", - "FileDateHelpText": "A fájl dátumának módosítása az importáláskor / újrakereséskor", "FileChmodHelpTexts1": "Octal, médiafájlokra alkalmazva, amikor a Prowlarr importálja / átnevezi őket", - "FailedDownloadHandling": "Nem sikerült a letöltés kezelése", "Failed": "Sikertelen", - "ExtraFileExtensionsHelpTexts1": "Az importálandó extra fájlok vesszővel lesznek elválasztva (.nfo .nfo-orig néven lesz importálva)", "ExportCustomFormat": "Egyéni Formátum Exportálása", "ExistingTag": "Meglévő Címke", "ExistingMovies": "Létező Film(ek)", - "ExcludeMovie": "Film Kizárása", "Exception": "Kivétel", "EventType": "Események Típusa", "Events": "Események", @@ -191,55 +151,41 @@ "Status": "Állapot", "StartupDirectory": "Indítási könyvtár", "StartTypingOrSelectAPathBelow": "Kezdd el gépelni, vagy válassz az alábbi útvonalak közül", - "StartProcessing": "Feldolgozás elindítása", "StandardMovieFormat": "Normál filmformátum", "SSLPort": "SSL Port", "SSLCertPathHelpText": "A PFX fájl elérési útvonala", "SSLCertPath": "Az SSL tanúsítvány elérési útvonala", "SSLCertPasswordHelpText": "Jelszó a Pfx fájlhoz", "SSLCertPassword": "SSL Tanúsítvány jelszava", - "SourceRelativePath": "Forrás relatív útvonala", "Source": "Forrás", "Sort": "Rendezés", - "SkipFreeSpaceCheckWhenImportingHelpText": "Akkor használja, ha a Prowlarr nem képes felismerni a gyökérmappában lévő szabad helyet", "SizeOnDisk": "Méret a lemezen", "Size": "Méret", "Shutdown": "Leállítás", - "ShowUnknownMovieItems": "Ismeretlen filmelemek megjelenítése", "ShowTitle": "Cím megjelenítése", - "ShowSizeOnDisk": "Használt hely megjelenítése", "ShowSearchHelpText": "A kereső gomb megjelenítése az egérrel", - "ShowRatings": "Értékelések mutatása", "SettingsWeekColumnHeaderHelpText": "Minden oszlop felett jelenjen meg, hogy melyik hét az aktuális", "MonoVersion": "Mono Verzió", "MonoTlsCheckMessage": "A Prowlarr Mono 4.x tls megoldás továbbra is engedélyezett, fontolja meg a MONO_TLS_PROVIDER =legacy opció eltávolítását", - "CleanLibraryLevel": "Könyvtár tisztítása", "ShowQualityProfile": "Minőségi profil megjelenítése", "ShownClickToHide": "Kattints, hogy elrejtsd", - "ShowMovieInformation": "Filminformációk megjelenítése", "ShowMonitored": "Monitorozottak mutatása", - "ShowDateAdded": "Hozzáadás dátuma", "ShowCertification": "Tanúsítvány megjelenítése", "ShowAdvanced": "Haladó nézet", - "SettingsWeekColumnHeader": "Heti oszlopfejléc", "SettingsTimeFormat": "Időformátum", "SettingsShowRelativeDatesHelpText": "Relatív (Ma / Tegnap / stb.) vagy valós dátumok megjelenítése", "SettingsShowRelativeDates": "Relatív dátumok megjelenítése", "SettingsShortDateFormat": "Rövid dátumformátum", - "SettingsRemotePathMappingRemotePathHelpText": "Gyökérútvonal a könyvtárhoz, amelyhez a letöltőkliens hozzáfér", "SettingsRemotePathMappingLocalPathHelpText": "Elérési út, amelyet a Prowlarr használhat a távoli elérési út, helyi eléréséhez", "SettingsLongDateFormat": "Hosszú dátumformátum", "SettingsEnableColorImpairedModeHelpText": "Megváltoztatott stílus, hogy a színtévesztő felhasználók jobban megkülönböztessék a színkódolt információkat", "SettingsEnableColorImpairedMode": "Színtévesztő mód bekapcsolása", "Settings": "Beállítások", - "SetPermissionsLinuxHelpText": "Futtatni kell a chmod-ot fájlok importálásakor / átnevezésekor?", "SendAnonymousUsageData": "Névtelen használati adatok küldése", "SelectAll": "Összes kijelölése", "Seeders": "Seederek", "Security": "Biztonság", - "SearchOnAddHelpText": "Keresse meg a listán található filmeket, ha hozzá van adva a Prowlarrhoz", "SearchMovie": "Film keresés", - "SearchForMissing": "Hiányzó keresése", "SearchFailedPleaseTryAgainLater": "Keresés sikertelen, próbáld újra később.", "Search": "Keresés", "ScriptPath": "Script útvonal", @@ -247,12 +193,9 @@ "SaveSettings": "Beállítások mentése", "SaveChanges": "Változtatások mentése", "Save": "Mentés", - "RSSSyncIntervalHelpTextWarning": "Ez minden indexerre vonatkozni fog, kérjük, tartsa be az általuk meghatározott szabályokat", "RSSSync": "RSS Szinkronizálás", "RSSIsNotSupportedWithThisIndexer": "Az RSS nem támogatott ezzel az indexerrel", - "RootFolderCheckSingleMessage": "Hiányzó gyökérmappa: {0}", "RootFolder": "Gyökérmappa", - "RetentionHelpText": "Usenet: Állítsa nullára a korlátlan megőrzés beállításához", "Retention": "Visszatartás", "Result": "Eredmények", "Restrictions": "Korlátozások", @@ -264,46 +207,29 @@ "Restart": "Újraindítás", "ResetAPIKey": "API Kulcs visszaállítása", "Reset": "Visszaállítás", - "RescanAfterRefreshHelpTextWarning": "A Prowlarr nem érzékeli automatikusan a fájlok változását, ha nincs beállítva „Always”-re", "RequiredRestrictionPlaceHolder": "A kiadásnak tartalmaznia kell legalább egy ilyen kifejezést (a kis- és nagybetűket nem veszi figyelembe)", - "RequiredHelpText": "Ennek a {0} feltételnek meg kell egyeznie az egyéni formátum alkalmazásához. Ellenkező esetben egyetlen {1} egyezés elegendő.", "ReplaceIllegalCharacters": "Az illegális karakterek cseréje", - "RenameMoviesHelpText": "A Prowlarr a meglévő fájlnevet fogja használni, ha az átnevezés le van tiltva", "RenameFiles": "Fájl(ok) átnevezése", "RemovingTag": "Címke eltávolítása", - "RemoveRootFolder": "Gyökérmappa eltávolítása", "RemoveFromQueue": "Eltávolítás a sorból", - "RemoveFromBlacklist": "Eltávolítás a feketelistáról", "RemoveFilter": "Szűrő törlése", - "RemovedMovieCheckSingleMessage": "A(z) {0} filmet eltávolították a TMDb-ről", "RemovedFromTaskQueue": "Eltávolítva a feladatsorról", - "Remove": "Eltávolítás", "Reload": "Újratöltés", - "ReleaseTitle": "Kiadás címe", "ReleaseStatus": "Kiadás státusza", - "ReleaseGroup": "Kiadási Csoport", "Released": "Megjelent", "ReleaseBranchCheckPreviousVersionMessage": "Az ágazat {0} a Prowlarr előző verziójához tartozik, a további frissítések érdekében állítsd az ágat 'nightly'-ra", "ReleaseBranchCheckOfficialBranchMessage": "A(z) {0} nem érvényes Prowlarr frissítési ágazat, ezért nem kap frissítéseket", - "RejectionCount": "Elutasítások száma", "RefreshMovie": "Film frissítése", - "RefreshAndScan": "Frissítés & Keresés", "Refresh": "Frissítés", - "RecyclingBinCleanup": "Lomtár kiürítése", "RecycleBinHelpText": "A filmfájlok végleges törlés helyett ide kerülnek törléskor", - "RecycleBinCleanupDaysHelpText": "Állítsd 0-ra az automatikus tisztítás letiltásához", "Reason": "Ok", "ReadTheWikiForMoreInformation": "Olvasd el a Wiki-t további információkért", - "ProwlarrTags": "Prowlarr Címkék", "ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "A Prowlarr támogatja az RSS filmlistákat, valamint az alábbiakban felsoroltakat.", "ProwlarrSupportsAnyIndexer": "A Prowlarr számos indexert támogat, minden olyan indexelő mellett, amely a Newznab / Torznab szabványt használja, valamint a 'Generic Newznab' (usenethez) vagy a 'Generic Torznab' (torrentekhez) használatával. Keresés és az alább felsorolt indexelők kiválasztása.", "ProwlarrSupportsAnyDownloadClient": "A Prowlarr minden olyan letöltési klienst támogat, amely a Newznab szabványt használja, valamint az alább felsorolt letöltési klienseket.", - "QuickImport": "Gyors Importálás", "Queue": "Várakozási sor", "QualitySettings": "Minőségi beállítások", - "QualityProfileDeleteConfirm": "Biztosan törli a {0} minőségi profilt", "QualityDefinitions": "Minőségi meghatározások", - "Quality": "Minőség", "PtpOldSettingsCheckMessage": "A következő PassThePopcorn indexerek elavult beállításokkal rendelkeznek, és frissíteni kell őket: {0}", "ProxyUsernameHelpText": "Csak akkor kell megadnod felhasználónevet és jelszót, ha szükséges. Egyébként hagyd üresen.", "ProxyType": "Proxy Típusa", @@ -314,44 +240,33 @@ "ProxyBypassFilterHelpText": "Használja elválasztóként a ',' és a '*' karaktereket, az aldomainek helyettesítőjeként", "Proxy": "Proxy", "Protocol": "Protokoll", - "Progress": "Folyamat", "Profiles": "Profil(ok)", "PriorityHelpText": "Priorizálj több letöltési klienst. A Round-Robint azonos prioritású letöltőkliensek használják.", "Priority": "Prioritás", - "PreferIndexerFlagsHelpText": "Prioritizáld a kiadásokat speciális zászlók segítségével", "OnGrabHelpText": "Megfogva", - "Month": "Hónap", "MonoVersionCheckUpgradeRecommendedMessage": "A jelenleg telepített Mono {0} verzió támogatott, de ajánlott frissíteni a(z) {1} verzióra.", "PreferredSize": "Preferált méret", - "PosterSize": "Poszter mérete", "PosterOptions": "Poszter beállítások", "PortNumber": "Port száma", "Port": "Port", - "Permissions": "Engedélyek", "PendingChangesStayReview": "Maradj, és tekintsd át a változásokat", "PendingChangesMessage": "Nem mentett módosításaid vannak, biztosan el akarod hagyni ezt az oldalt?", "PendingChangesDiscardChanges": "Változtatások törlése és kilépés", "Pending": "Függőben", "Peers": "Peerek", - "Path": "Útvonal", "Password": "Jelszó", "PageSizeHelpText": "Az egyes oldalakon megjelenítendő elemek száma", "PageSize": "Oldal mérete", "PackageVersion": "Csomagverzió", - "Overview": "Áttekintés", "OrganizeModalSuccess": "Siker! Befejeztem a munkám, nincsenek átnevezésre váró fájlok.", - "OrganizeModalDisabled": "Az átnevezés le van tiltva, nincs mit átnevezni", "Organize": "Rendezés", "Options": "Opciók", "OpenThisModal": "Nyissa meg ezt a modált", "OpenBrowserOnStart": "Indításkor nyissa meg a böngészőt", - "OnRenameHelpText": "Átnevezés alatt", "OnHealthIssueHelpText": "Állapotprobléma", - "OnDeleteHelpText": "Törlés alatt", "Ok": "Ok", "OAuthPopupMessage": "A böngésződ blokkolja az előugró ablakokat", "NoUpdatesAreAvailable": "Nincsenek elérhető frissítések", - "NotAvailable": "Nem elérhető", "NoTagsHaveBeenAddedYet": "Még nem adtál hozzá címkéket", "NoMinimumForAnyRuntime": "Nincs minimális futásidő", "NoLogFiles": "Nincsen log fájl", @@ -362,47 +277,31 @@ "NoBackupsAreAvailable": "Nincs elérhető biztonsági mentés", "New": "Új", "NetCore": ".NET", - "NamingSettings": "Elnevezési beállítások", "Name": "Név", - "MustContain": "Tartalmaznia kell", "MovieYear": "Kiadási év", - "MovieTitle": "Filmcím", "Movies": "Filmek", - "MovieIsUnmonitored": "A film nincs monitorozva", "MovieIsMonitored": "A film monitorozva van", - "MovieIsDownloading": "A film letöltés alatt", "MovieInfoLanguageHelpText": "A Prowlarr által a filminformációkhoz használt nyelv", "MovieIndexScrollTop": "Film Index: Görgess fel", "MovieIndexScrollBottom": "Film Index: Görgess le", - "MovieID": "Film ID", "MovieFiles": "Filmfájl(ok)", - "MovieEditor": "Filmszerkesztő", "MovieDetailsPreviousMovie": "A film részletei: Előző film", "MovieDetailsNextMovie": "A film részletei: Következő film", - "MovieAlreadyExcluded": "A film már ki lett zárva", "MoveFiles": "Fájl(ok) mozgatása", "MoreInfo": "Több Információ", "MonoNotNetCoreCheckMessage": "Kérjük, frissítsd a Prowlarr .NET Core verzióját", - "MonitoredOnly": "Csak a Megfigyelt", "Monitored": "Monitorozva", "Mode": "Mód", - "MissingMonitoredAndConsideredAvailable": "Hiányzik, Monitorozva van és elérhetőnek tekintett", "MinutesSixty": "60 Perc: {0}", "MinutesNinety": "90 Perc: {0}", "MinutesHundredTwenty": "120 Perc: {0}", "MinimumLimits": "Minimális Határ", - "MinimumFreeSpace": "Minimális Szabad Tárhely", "MinimumAgeHelpText": "Usenet: Az NZB-k minimális életkora percekben, mielőtt megragadnák őket. Használja ezt arra, hogy időt biztosítson az új kiadásoknak az usenet-szolgáltatóhoz történő továbbterjesztésre.", - "MinFormatScoreHelpText": "A letöltéshez engedélyezett minimális egyéni formátum pontszám", "MIA": "MIA", - "MetadataSettings": "Metadata Beállítások", "Message": "Üzenet", - "MediaManagementSettings": "Média Kezelési Beállítások", "MediaInfoDllCheckMessage": "A MediaInfo könyvtár betöltése nem sikerült {0}", "Mechanism": "Mechanizmus", - "MaximumSize": "Maximális Méret", "MaximumLimits": "Maximális Limit", - "MarkAsFailedMessageText": "Biztosan sikertelennek szeretnéd jelölni a (z) „{0}”-t?", "ManualImport": "Manuális Importálás", "Manual": "Manuális", "MaintenanceRelease": "Karbantartási kiadás", @@ -411,11 +310,8 @@ "LogLevel": "Log Szint", "Logging": "Loggolás", "LogFiles": "Log Fájlok", - "Local": "Helyi", "LoadingMovieExtraFilesFailed": "A film extra fájljainak betöltése nem sikerült", - "ListSyncLevelHelpText": "A könyvtárban lévő filmeket eltávolítjuk vagy nem figyeljük meg, ha nem szerepelnek a listán", "ListSettings": "Lista Beállítások", - "ListExclusions": "Kizárások listázása", "LinkHere": "ide", "Level": "Szint", "LaunchBrowserHelpText": " Nyisson meg egy böngészőt, és az alkalmazás indításakor lépjen a Prowlarr kezdőlapjára.", @@ -429,25 +325,19 @@ "IndexerStatusCheckSingleClientMessage": "Indexerek elérhetetlenek a következő hiba miatt: {0}", "Hostname": "Hosztnév", "Host": "Hoszt", - "GrabID": "Megfogás ID", "Grabbed": "Megfogva", "GeneralSettings": "Általános Beállítások", "General": "Általános", - "DownloadPropersAndRepacks": "Properek és Repackok", "UnableToLoadLanguages": "Nem sikerült betölteni a nyelveket", "UnableToLoadIndexers": "Nem lehet betölteni az indexereket", "UnableToLoadHistory": "Nem sikerült betölteni az előzményeket", "UnableToLoadGeneralSettings": "Nem sikerült betölteni az általános beállításokat", "UnableToLoadDownloadClients": "Nem sikerült betölteni a letöltőkliens(eke)t", - "UnableToLoadDelayProfiles": "Nem lehet betölteni a késleltetési profilokat", "UnableToLoadBlacklist": "Nem sikerült betölteni a feketelistát", "UnableToLoadBackups": "Biztonsági mentés(ek) betöltése sikertelen", - "UnableToAddANewQualityProfilePleaseTryAgain": "Nem lehet új minőségi profilt hozzáadni, próbálkozz újra.", "UnableToAddANewNotificationPleaseTryAgain": "Nem lehet új értesítést hozzáadni, próbálkozz újra.", - "UnableToAddANewListExclusionPleaseTryAgain": "Nem lehet új listakizárást hozzáadni, próbálkozz újra.", "UnableToAddANewIndexerPleaseTryAgain": "Nem lehet új indexert hozzáadni, próbálkozz újra.", "UnableToAddANewDownloadClientPleaseTryAgain": "Nem lehet új letöltőklienst hozzáadni, próbálkozz újra.", - "UnableToAddANewConditionPleaseTryAgain": "Nem lehet új feltételt hozzáadni, próbáld meg újra.", "UISettingsSummary": "Dátum-, nyelv- és színtévesztő lehetőségek", "UISettings": "A felhasználói felület beállításai", "UILanguageHelpTextWarning": "Böngésző újratöltése szükséges", @@ -455,14 +345,10 @@ "UILanguage": "Felület nyelve", "UI": "Felület", "Type": "Típus", - "TotalFileSize": "Teljes fájl méret", "Torrents": "Torrentek", - "TorrentDelay": "Torrent késleltetés", "TMDBId": "TMDb azonosító", "Title": "Cím", - "TimeFormat": "Időformátum", "Time": "Idő", - "TestAllIndexers": "Indexerek tesztelése", "TestAllClients": "Összes kliens tesztelése", "TestAll": "Összes tesztelése", "Test": "Teszt", @@ -474,53 +360,36 @@ "TagCannotBeDeletedWhileInUse": "Használat közben nem törölhető", "TableOptionsColumnsMessage": "Válasszd ki, mely oszlopok legyenek láthatóak, és milyen sorrendben jelenjenek meg", "SystemTimeCheckMessage": "A rendszeridő több mint 1 napja nem frissült. Előfordulhat, hogy az ütemezett feladatok az idő kijavításáig nem futnak megfelelően", - "ColonReplacement": "Kettőspont Helyettesítés", "IndexerStatusCheckAllClientMessage": "Az összes indexer elérhetetlen hiba miatt", - "IndexerSettings": "Indexer Beállítások", "IndexerSearchCheckNoAvailableIndexersMessage": "Az összes keresésre képes indexer átmenetileg nem elérhető, a legutóbbi indexelő hibák miatt", "Indexers": "Indexerek", - "IndexerRssHealthCheckNoAvailableIndexers": "Az összes rss-képes indexer átmenetileg nem érhető el a legújabb indexelő hibák miatt", "IndexerPriorityHelpText": "Indexelő prioritás 1-től (legmagasabb) 50-ig (legalacsonyabb). Alapértelmezés: 25.", "IndexerPriority": "Indexer Prioritása", "IndexerFlags": "Indexer Zászló", "Indexer": "Indexelő", - "IncludeUnknownMovieItemsHelpText": "Mutasson tételeket film nélkül a sorban. Ez tartalmazhat eltávolított filmeket vagy bármi mást a Prowlarr kategóriájából", "IncludeProwlarrRecommendations": "Tartalmazza a Prowlarr Ajánlásait", "IncludeHealthWarningsHelpText": "Tartalmazza a Állapot Figyelmeztetéseket", - "IncludeCustomFormatWhenRenaming": "Az átnevezéskor vegye fel az egyéni formátumot", "ImportTipsMessage": "Néhány tipp az importálás zökkenőmentes lebonyolításához:", - "ImportMovies": "Filmek Importálása", "ImportListSyncIntervalHelpText": "A Prowlarr milyen gyakran szinkronizáljon a listáival.", - "ImportListStatusCheckAllClientMessage": "Az összes lista elérhetetlen, hiba miatt", "Importing": "Importálás Folyamatban", - "ImportHeader": "Importáld a már meglévő filmjeidet", "ImportFailed": "Importálás sikertelen: {0}", - "ImportExtraFiles": "Extra Fájlok Importálása", "ImportErrors": "Importálási Hiba", - "Imported": "Importálva", "Import": "Importálás", "IllRestartLater": "Később Újraindítom", - "IgnoredHelpText": "A kiadás elutasításra kerül, ha egy vagy több kifejezést tartalmaz (A kis- és nagybetűket nem vesszük figyelembe)", "IgnoredAddresses": "Ignorált Címek", - "IconForCutoffUnmet": "Ikon a Sikertelen Küszöbszint Elérésére", "ICalFeed": "iCal-Feed", - "DownloadPropersAndRepacksHelpTextWarning": "Használjon előnyben részesített szavakat a Properek / Repackok automatikus frissítésére", "YesCancel": "Igen, Mégsem", - "WhitelistedHardcodedSubsHelpText": "Az itt beállított feliratcímkék nem minősülnek keménykódoltaknak", "Week": "Hét", "Warn": "Figyelmeztet", - "WaitingToProcess": "Várakozás feldolgozásra", "VisitGithubCustomFormatsAphrodite": "Látogasd meg a GitHub-ot további információkért: ", "View": "Nézet", "Version": "Verzió", "Username": "Felhasználónév", "UseProxy": "Proxy használata", - "UsenetDelay": "Usenet késleltetés", "Usenet": "Usenet", "UrlBaseHelpText": "Fordított proxy támogatás esetén az alapértelmezett érték üres", "URLBase": "URL Bázis", "Uptime": "Üzemidő", - "UpgradeAllowedHelpText": "Ha ki van kapcsolva, a meglévő minőségűnél nem lesz jobb minőségű letöltve", "UpdateScriptPathHelpText": "Keresse meg az egyéni parancsfájl elérési útját, amely kibontott frissítési csomagot vesz fel, és kezeli a frissítési folyamat fennmaradó részét", "Updates": "Frissítések", "UpdateMechanismHelpText": "Használja a Prowlarr beépített frissítőjét vagy egy szkriptet", @@ -530,18 +399,13 @@ "UpdateAutomaticallyHelpText": "A frissítések automatikus letöltése és telepítése. A Rendszer: Frissítések alkalmazásból továbbra is telepíteni tudja", "UnselectAll": "Minden kijelölés megszüntetése", "UnsavedChanges": "Nem mentett változások", - "UnmonitoredHelpText": "A nem felügyelt filmek is bekerülnek az iCal hírcsatornába", "UnmappedFolders": "Feltérképezetlen mappák", - "Unavailable": "Nem érhető el", "UnableToLoadUISettings": "Nem sikerült betölteni a felhasználói felület beállításait", "UnableToLoadTags": "Nem sikerült betölteni a címkéket", - "UnableToLoadRestrictions": "Nem lehet betölteni a korlátozásokat", "UnableToLoadQualityProfiles": "Nem lehet betölteni a minőségi profilokat", "UnableToLoadQualityDefinitions": "Nem lehet betölteni a minőségi meghatározásokat", "UnableToLoadNotifications": "Nem sikerült betölteni az Értesítéseket", - "UnableToLoadMovies": "Nem sikerült betölteni a filmeket", "UnableToLoadMediaManagementSettings": "Nem sikerült betölteni a Média Kezelés beállításait", - "UnableToLoadListOptions": "A listaopciók betöltése sikertelen", "ThisConditionMatchesUsingRegularExpressions": "Ez a feltétel megfelel a Reguláris kifejezések használatának. Ne feledje, hogy a karakterek {0} különleges jelentéssel bírnak, és el kell kerülniük egy {1} karakterrel", "TableOptions": "Táblázat beállításai", "ShowSearch": "Keresés(ek) megjelenítése", @@ -549,7 +413,6 @@ "NotificationTriggers": "Értesítés(ek) kiváltója", "IndexerLongTermStatusCheckSingleClientMessage": "Az összes indexer elérhetetlen több mint 6 órája, meghibásodás miatt: {0}", "IndexerLongTermStatusCheckAllClientMessage": "Az összes indexer elérhetetlen több mint 6 órája, meghibásodás miatt", - "ListTagsHelpText": "A címkék listájának elemei hozzá lesznek adva", "SettingsLogSql": "SQL naplózás", "IndexerRss": "Indexer Rss", "IndexerAuth": "Indexelő auth", @@ -568,7 +431,6 @@ "SettingsFilterSentryEvents": "Az Analytics-események szűrése", "SettingsConsoleLogLevel": "Konzol naplószint", "SearchIndexers": "Indexelők keresése", - "NewznabVipCheckExpiredClientMessage": "Az Indexer VIP előnyei lejártak: {0}", "IndexersSelectedInterp": "{0} Indexelő(k) kiválasztva", "IndexerQuery": "Indexelő lekérdezés", "IndexerHealthCheckNoIndexers": "Nincs engedélyezve indexelő, a Prowlarr nem ad vissza keresési eredményeket", diff --git a/src/NzbDrone.Core/Localization/Core/it.json b/src/NzbDrone.Core/Localization/Core/it.json index 3bb26e2f6..7eed8ac91 100644 --- a/src/NzbDrone.Core/Localization/Core/it.json +++ b/src/NzbDrone.Core/Localization/Core/it.json @@ -1,52 +1,38 @@ { - "Wanted": "Ricercato", "View": "Guarda", "UnselectAll": "Deseleziona Tutto", - "UnmappedFolders": "Cartelle Non Mappate", "UISettingsSummary": "Opzioni calendario, data e visione dei colori", "TagsSettingsSummary": "Controlla tutti i tag e come vengono utilizzati. I tag non utilizzati possono essere rimossi", - "SourceTitle": "Titolo Sorgente", "SetTags": "Imposta Tag", "SelectAll": "Seleziona Tutto", - "SearchSelected": "Cerca il film selezionato", "Scheduled": "In Programma", - "RootFolders": "Cartelle Radice", "RootFolder": "Cartella Radice", "ReleaseBranchCheckPreviousVersionMessage": "Il Branch {0} corrisponde ad una versione precedente di Prowlarr, imposta il branch su \"Nightly\" per ricevere gli aggiornamenti futuri", "ReleaseBranchCheckOfficialBranchMessage": "Il Branch {0} non è un branch valido per le release di Prowlarr, non riceverai aggiornamenti", - "QualityProfiles": "Profili di Qualità", "QualityDefinitions": "Definizioni delle Qualità", "PtpOldSettingsCheckMessage": "Il seguente indexer PassThePopcorn ha delle impostazioni obsolete e deve essere aggiornato: {0}", "ProxyCheckResolveIpMessage": "Impossibile risolvere l'indirizzo IP per il Proxy {0}", - "PhysicalRelease": "Release Fisica", "OutputPath": "Percorso di Destinazione", "NoChanges": "Nessuna Modifica", "NoChange": "Nessuna Modifica", - "MountCheckMessage": "La destinazione contenente il percorso di un film è montata in sola lettura: ", "Monitor": "Segui", - "MassMovieSearch": "Ricerca Film Multipla", "ListExclusions": "Esclusioni dalle Liste", "LastWriteTime": "Orario di Ultima Scrittura", - "IndexerRssHealthCheckNoAvailableIndexers": "Tutti gli indexer RSS sono momentaneamente disabilitati a causa di errori", "Indexer": "Indicizzatore", "HideAdvanced": "Nascondi Avanzate", "Health": "Salute", "Grabbed": "Recuperato", - "DotNetVersionCheckOldUnsupportedMessage": "La versione di .Net Framework {0} attualmente installata è vecchia e non più supportata. Per favore aggiorna alla versione {1} o successiva.", "DigitalRelease": "Release Digitale", - "Crew": "Troupe", "Clear": "Cancella", "AppDataLocationHealthCheckMessage": "Non è possibile effettuare l'aggiornamento per evitare di cancellare AppData", "Analytics": "Statistiche", "Added": "Aggiunto", "About": "Versione", - "Week": "Settimana", "Updates": "Aggiornamenti", "UpdateCheckUINotWritableMessage": "Impossibile installare l'aggiornamento perché l'utente '{1}' non ha i permessi di scrittura per la cartella di interfaccia '{0}'.", "UpdateCheckStartupNotWritableMessage": "Impossibile installare l'aggiornamento perché l'utente '{1}' non ha i permessi di scrittura per la cartella di avvio '{0}'.", "UpdateCheckStartupTranslocationMessage": "Impossibile installare l'aggiornamento perché la cartella '{0}' si trova in una cartella App Translocation.", "UI": "Interfaccia", - "Timeleft": "Tempo Rimanente", "Tasks": "Funzioni", "Tags": "Tag", "System": "Sistema", @@ -61,28 +47,20 @@ "SaveChanges": "Salva Modifiche", "Restrictions": "Restrizioni", "RestoreBackup": "Ripristina Backup", - "Renamed": "Rinominato", "RemovedMovieCheckSingleMessage": "Il Film {0} è stato rimosso da TMDb", - "ReleaseTitle": "Titolo Release", "ReleaseStatus": "Stato Release", - "RefreshAndScan": "Aggiorna e Scansiona", "Refresh": "Aggiorna", "Queue": "Coda", "ProxyCheckFailedToTestMessage": "Test del proxy fallito: {0}", "ProxyCheckBadRequestMessage": "Il test del proxy è fallito. Stato: {0}", "Proxy": "Proxy", "Protocol": "Protocollo", - "Profiles": "Profili", "Options": "Opzioni", - "ImportListStatusCheckAllClientMessage": "Tutte le liste non sono disponibili a causa di errori", "Movies": "Film", - "MovieEditor": "Modifica Film", "MoreInfo": "Maggiori Info", "MonoTlsCheckMessage": "Il workaround per Prowlarr Mono 4.x tls è ancora disabilitato, potresti considerare di rimuovere l'opzione ambiente MONO_TLS_PROVIDER=legacy", "MonoNotNetCoreCheckMessage": "Per favore aggiorna alla versione .NET Core di Prowlarr", - "MinimumAvailability": "Disponibilità Minima", "MetadataSettingsSummary": "Crea file metadata quando i film vengono importati o aggiornati", - "MediaManagement": "Gestione Media", "ManualImport": "Import Manuale", "Logging": "Logging", "LogFiles": "File di Log", @@ -90,24 +68,18 @@ "Language": "Lingua", "IndexerStatusCheckSingleClientMessage": "Indexer non disponibili a causa di errori: {0}", "IndexerStatusCheckAllClientMessage": "Tutti gli indexer non sono disponibili a causa di errori", - "IndexerSearchCheckNoInteractiveMessage": "Non è disponibile nessun indexer con abilitata la Ricerca Interattiva, Prowlarr non fornirà nessun risultato tramite la ricerca interattiva", "IndexerSearchCheckNoAutomaticMessage": "Non è disponibile nessun indexer con abilitata la Ricerca Automatica, Prowlarr non fornirà nessun risultato tramite la ricerca automatica", "Indexers": "Indexer", - "InCinemas": "Nei Cinema", "ImportSecondTip": "Indirizza Prowlarr alla cartella che contiene tutti i tuoi film, non a cartelle specifiche. Ad esempio:", - "ImportHeader": "Importa dei film che hai già", "Imported": "Importato", - "Ignored": "Ignorato", "Host": "Host", "History": "Storia", "GeneralSettingsSummary": "Porta, SSL, Nome utente/password, proxy, statistiche e aggiornamenti", "General": "Generale", - "Formats": "Formati", "Folder": "Cartella", "Filter": "Filtro", "Filename": "Nome del File", "Files": "File", - "FailedDownloadHandling": "Gestione dei Download Falliti", "Failed": "Fallito", "EventType": "Tipo di Evento", "Events": "Eventi", @@ -119,67 +91,51 @@ "DownloadClientCheckUnableToCommunicateMessage": "Impossibile comunicare con {0}.", "DownloadClientCheckNoneAvailableMessage": "Non è disponibile nessun client per il download", "DownloadClient": "Client Download", - "Discover": "Scopri", "Details": "Dettagli", "Delete": "Cancella", "Dates": "Date", "Date": "Data", - "CustomFormatsSettingsSummary": "Formati Personalizzati e Impostazioni", "CustomFilters": "Filtri Personalizzati", "Connect": "Collega", "Connections": "Collegamenti", "ConnectSettingsSummary": "Notifiche, collegamenti a media server/player e script personalizzati", - "Collection": "Collezione", "Cast": "Cast", - "Blacklist": "Lista Nera", "BackupNow": "Effettua ora il Backup", "Backup": "Backup", "All": "Tutti", - "AddNew": "Aggiungi Nuovo", "Actions": "Azioni", - "AddNewMessage": "È facile aggiungere un nuovo film, inizia a scrivere il titolo del film che vuoi aggiungere", "Activity": "Attività", - "AgeWhenGrabbed": "Età (quando trovato)", "Age": "Età", - "AddNewMovie": "Aggiungi Nuovo Film", "AddListExclusion": "Aggiungi Lista Esclusioni", "Close": "Chiudi", "CloneProfile": "Clona il Profilo", "CloneIndexer": "Clona Indexer", "ClientPriority": "Priorità del Client", - "ClickToChangeLanguage": "Clicca per cambiare lingua", "CheckForFinishedDownloadsInterval": "Intervallo per il controllo dei download finiti", "ChangeHasNotBeenSavedYet": "Il cambiamento non è stato ancora salvato", - "CertificationCountryHelpText": "Seleziona il paese per le certificazioni dei film", "CertificateValidationHelpText": "Cambiare il \"grado di severità\" della convalida del certificato HTTPS", "CertificateValidation": "Convalida del certificato", "Cancel": "Cancella", "BypassProxyForLocalAddresses": "Evita il Proxy per gli indirizzi locali", "Branch": "Ramo", - "BlacklistHelpText": "Impedisci a Prowlarr di acquisire automaticamente questo film", "BindAddressHelpText": "Indirizzo IPV4 valido o '*' per tutte le interfacce", "BindAddress": "Indirizzo per il collegamento", "Backups": "I Backup", "BackupRetentionHelpText": "I backup automatici più vecchi del periodo di conservazione verranno eliminati automaticamente", "BackupIntervalHelpText": "Intervallo tra i backup automatici", "BackupFolderHelpText": "I percorsi relativi saranno sotto la directory AppData di Prowlarr", - "AvailabilityDelay": "Ritardo su disponibilità", "AutoRedownloadFailedHelpText": "Ricerca automatica e tentativo di scaricare un'altra versione", "Automatic": "Automatico", "AuthenticationMethodHelpText": "Utilizza nome utente e password per accedere a Prowlarr", "Authentication": "Autenticazione", - "AsAllDayHelpText": "Gli eventi appariranno come eventi di un giorno intero nel tuo calendario", "AreYouSureYouWantToResetYourAPIKey": "Sei sicuro di voler reimpostare la tua chiave API?", - "AreYouSureYouWantToDeleteThisImportListExclusion": "Sei sicuro di voler cancellare questa lista di esclusioni delle importazioni?", "ApplyTags": "Applica Etichette", "Apply": "Applica", "AppDataDirectory": "Cartella AppData", "ApiKey": "Chiave API", "AnalyticsEnabledHelpText": "Inviare informazioni anonime sull'utilizzo e sugli errori ai server di Prowlarr. Ciò include informazioni sul tuo browser, come le pagine di Prowlarr che utilizzi, la segnalazione di errori e la versione del sistema operativo e del runtime. Utilizzeremo queste informazioni per dare priorità alle funzioni e alle correzioni di bug.", - "AlternativeTitle": "Titolo Alternativo", "AllowHardcodedSubsHelpText": "Se verranno rilevati sottotitoli impressi il film verrà comunque scaricato", "Warn": "Attenzione", - "Unavailable": "Non disponibile", "Type": "Tipo", "Title": "Titolo", "Time": "Orario", @@ -196,43 +152,31 @@ "Reload": "Ricarica", "Peers": "Peers", "PageSize": "Dimensione Pagina", - "OrganizeModalNamingPattern": "Schema di Denominazione:", "OrganizeModalAllPathsRelative": "Tutti i percorsi sono relativi a:", - "Organize": "Organizza", "Ok": "Ok", "OAuthPopupMessage": "I Pop-ups sono bloccati dal tuo browser", "Name": "Nome", "MonoVersionCheckUpgradeRecommendedMessage": "La versione di Mono {0} attualmente installata è supportata ma è raccomandato l'aggiornamento alla versione {1}.", - "MonoVersionCheckNotSupportedMessage": "La versione di Mono {0} attualmente installata non è più supportata. Per favore procedi con l'aggiornamento di Mono alla versione {1}.", "Message": "Messaggio", "Level": "Livello", "KeyboardShortcuts": "Scorciatoie Tastiera", "Info": "Info", "HealthNoIssues": "La tua configurazione non presenta problemi", - "Extension": "Estensione", "Error": "Errore", "EnableAutoHelpText": "Se abilitato, i film saranno aggiunti automaticamente a Prowlarr da questa lista", "Enable": "Abilita", - "EditPerson": "Modifica persona", "Edition": "Edizione", - "DownloadPropers": "Scarica Propers", "DownloadClientSettings": "Impostazioni del client di download", "Docker": "Docker", - "DetailedProgressBar": "Barra di avanzamento dettagliata", "DeleteTag": "Cancella Tag", - "DeleteRestriction": "Cancellare la restrizione", "DeleteNotification": "Cancellare la notifica", "DeleteIndexer": "Cancella Indexer", - "DeleteFile": "Cancellare il file", "DeleteEmptyFolders": "Cancellare le cartelle vuote", "DeleteDownloadClient": "Cancellare il client di download", - "DeleteCustomFormat": "Cancellare il formato personalizzato", "DeleteBackup": "Cancellare il backup", "DelayProfile": "Profili di Ritardo", "DBMigration": "Migrazione del DataBase", - "CutoffFormatScoreHelpText": "Una volta raggiunto questo formato personalizzato, Prowlarr non scaricherà più i film", "CustomFormatScore": "Punteggio del formato personalizzato", - "CreateEmptyMovieFoldersHelpText": "Crea le cartelle dei film mancanti durante la scansione del disco", "CopyUsingHardlinksHelpTextWarning": "Occasionalmente, i blocchi dei file possono impedire la ridenominazione dei file in fase di seeding. È possibile disattivare temporaneamente il seeding e utilizzare la funzione di rinomina di Prowlarr per evitare il problema.", "ConnectSettings": "Impostazioni di connessione", "ConnectionLostMessage": "Prowlarr ha perso la connessione al backend e dovrà essere ricaricato per ripristinare la funzionalità.", @@ -240,44 +184,33 @@ "ConnectionLost": "Connessione persa", "Component": "Componente", "Columns": "Colonne", - "ColonReplacement": "Sostituzione due punti", "CouldNotFindResults": "Non ho trovato risultati per '{0}'", "DeleteBackupMessageText": "Sei sicuro di voler cancellare il backup '{0}'?", - "CheckDownloadClientForDetails": "controlla il client di download per maggiori dettagli", "CancelPendingTask": "Sei sicuro di voler cancellare questa operazione in sospeso?", "BranchUpdateMechanism": "Branch utilizzato dal sistema di aggiornamento esterno", "BranchUpdate": "Branch da utilizzare per aggiornare Prowlarr", "ApplyTagsHelpTexts2": "Aggiungi: Aggiungere i tag la lista esistente di tag", "ApplyTagsHelpTexts1": "Come applicare i tag ai film selezionati", "AddingTag": "Aggiungi tag", - "ProwlarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "Prowlarr supporta condizioni personalizzate verso le seguenti release.", "Proper": "Proper", "Password": "Password", "OnHealthIssueHelpText": "Quando c'è un problema", "NotificationTriggers": "Selettori di notifica", "NetCore": ".NET", "Logs": "Logs", - "LastDuration": "Ultima Durata", "Hostname": "Hostname", - "GrabID": "ID di Prelievo", "FileChmodHelpTexts2": "La stessa modalità viene applicata alle cartelle di film/sub con il bit di esecuzione aggiunto, ad esempio, 0644 diventa 0755", "MIA": "MIA", "IndexerFlags": "Etichetta indexer", - "FileNames": "Nomi file", "ExtraFileExtensionsHelpTexts1": "Liste di file Extra da importare separate da virgola (.nfo saranno importate come .nfo-orig)", "EnableSSL": "Abilita SSL", "EnableColorImpairedModeHelpText": "Stile alterato per permettere agli utenti daltonici di distinguere meglio le informazioni con colori codificati", - "CustomFormatUnknownCondition": "Condizione per il Formato personalizzato sconosciuta '{0}'", "SettingsLongDateFormat": "Formato Data Lungo", "SettingsEnableColorImpairedMode": "Abilità la modalità colori alternati", - "SetPermissionsLinuxHelpText": "Eseguire chmod quando i file sono importati/rinominati?", "SendAnonymousUsageData": "Invia dati sull'uso anonimamente", - "SearchOnAddHelpText": "Cerca i film in questa lista quando aggiunti a Prowlarr", "SearchMovie": "Trova Film", "ScriptPath": "Percorso dello script", - "RSSSyncInterval": "Intervallo di Sync RSS", "RSSIsNotSupportedWithThisIndexer": "RSS non è supportato con questo indexer", - "RetentionHelpText": "Solo Usenet: Imposta a zero per una conservazione illimitata", "Retention": "Memorizzazione", "Result": "Risultato", "Restore": "Ripristina", @@ -286,38 +219,26 @@ "RestartNow": "Riavvia adesso", "ResetAPIKey": "Resetta la Chiave API", "Reset": "Resetta", - "RescanAfterRefreshHelpTextWarning": "Prowlarr non identificherà in automatico i cambiamenti ai file quando non impostato a \"Sempre\"", "RequiredPlaceHolder": "Aggiunge una nuova restrizione", - "ReplaceIllegalCharactersHelpText": "Sostituisci i caratteri non consentiti. Se non selezionato, Prowlarr invece li rimuoverà", "Reorder": "Riordina", - "RenameMovies": "Rinomina i Film", "RemovingTag": "Sto eliminando il tag", - "RemoveFromQueue": "Rimuovi dalla coda", "RemoveFromBlacklist": "Rimuovi della blacklist", "RemoveFilter": "Rimuovi filtro", "RemovedFromTaskQueue": "Rimuovi dalla coda di lavoro", - "Remove": "Rimuovi", "ReleaseRejected": "Release rifiutata", - "RejectionCount": "Rifiuta il conteggio", "RefreshMovie": "Aggiorna il Film", - "Redownload": "Riscarica", "RecyclingBin": "Cestino", - "RecycleBinCleanupDaysHelpTextWarning": "I file nel cestino più vecchi del numero selezionato di giorni saranno eliminati automaticamente", "RecentFolders": "Cartelle recenti", - "Real": "Reale", "ReadTheWikiForMoreInformation": "Leggi le Wiki per maggiori informazioni", "ProwlarrSupportsAnyIndexer": "Prowlarr supporta qualunque indexer che usi gli standard Newznab, cosi come gli altri Indexer sotto.", "ProwlarrSupportsAnyDownloadClient": "Prowlarr supporta qualunque client di download che usi gli standard Newznab, cosi come gli altri client sotto.", - "Queued": "Messo in coda", "QualitySettings": "Impostazione di Qualità", - "QualityCutoffHasNotBeenMet": "Il qualità di taglio non è stata raggiunta", "ProxyUsernameHelpText": "Devi inserire nome utente e password solo se richiesto. Altrimenti lascia vuoto.", "ProxyType": "Tipo di proxy", "ProxyPasswordHelpText": "Devi inserire nome utente e password solo se richiesto. Altrimenti lascia vuoto.", "ProxyBypassFilterHelpText": "Usa ',' come separatore, e '*.' come jolly per i sottodomini", "PriorityHelpText": "Dai priorità ai client di download multipli. Round-Robin è usato per i client con la stessa priorità.", "PreferredSize": "Dimensione preferita", - "PreferIndexerFlags": "Etichetta dell'indexer preferita", "PosterOptions": "Opzioni dei poster", "PortNumber": "Numero di porta", "Port": "Porta", @@ -327,11 +248,8 @@ "Pending": "In sospeso", "PageSizeHelpText": "Numero di voci da mostrare in ogni pagina", "PackageVersion": "Versione del pacchetto", - "Overview": "Panoramica", "OpenBrowserOnStart": "Apri il browser all'avvio", - "OnDownloadHelpText": "Notifica quando i film sono stati importati con successo", "NoUpdatesAreAvailable": "Nessun aggiornamento disponibile", - "NotAvailable": "Non disponibile", "NoTagsHaveBeenAddedYet": "Nessun tag è ancora stato aggiunto", "NoMinimumForAnyRuntime": "Nessuna durata minima", "NoLogFiles": "Nessun file di log", @@ -339,70 +257,42 @@ "NoLeaveIt": "No, lascialo", "NoBackupsAreAvailable": "Nessun Backup disponibile", "New": "Nuovo", - "NamingSettings": "Impostazioni di denominazione", "MustContain": "Deve contenere", - "MovieYear": "Anno del film", "MoviesSelectedInterp": "{0} Film selezionato(i)", - "MovieIsOnImportExclusionList": "Il Film è nella lista di esclusione dell'importazione", "MovieIsDownloadingInterp": "Film in download - {0}% {1}", - "MovieInfoLanguageHelpTextWarning": "Richiede il reload del Browser", "MovieInfoLanguage": "Lingua delle info del film", - "MovieFolderFormat": "Formato della cartella del film", "MovieExcludedFromAutomaticAdd": "Film escluso dall'aggiunta automatica", - "MovieAlreadyExcluded": "Film già escluso", "MonoVersion": "Versione Mono", - "MonitoredHelpText": "Scarica film se disponibile", "Mode": "Modo", - "MissingMonitoredAndConsideredAvailable": "Mancante, Monitorato e considerato disponibile", "MinutesSixty": "60 Minuti: {0}", "MinutesNinety": "90 Minuti: {0}", "MinutesHundredTwenty": "120 Minuti: {0}", "MinimumLimits": "Limiti minimi", - "MinimumFreeSpace": "Spazio libero minimo", "MinFormatScoreHelpText": "Punteggio minimo del formato personalizzato abilitato al download", - "MediaManagementSettings": "Impostazione gestione Media", "Mechanism": "Meccanismo", - "MaximumSize": "Dimensione massima", "MaximumLimits": "Limiti massimi", - "MarkAsFailed": "Segna come fallito", "Manual": "Manuale", "MaintenanceRelease": "Release di Manutenzione", "LogLevelTraceHelpTextWarning": "Il Trace Log dovrebbe essere abilitato solo temporaneamente", "LogLevel": "Livello di Log", - "LoadingMovieFilesFailed": "Caricamento dei file del Film fallito", "LoadingMovieCreditsFailed": "Caricamento dei crediti del film fallito", - "ListSyncLevelHelpText": "I Film nella libreria saranno rimossi o non monitorati se non presenti nella tua lista", "LinkHere": "qui", "LaunchBrowserHelpText": " Apri un browser e vai all'homepage di Prowlarr all'avvio dell'app.", "Interval": "Intervallo", - "IndexerSettings": "Impostazioni dell'Indexer", "IncludeUnknownMovieItemsHelpText": "Mostra le voci senza un film nella coda. Ciò potrebbe include film spostati o altro nelle categorie di Prowlarr", - "IncludeProwlarrRecommendations": "Includi le raccomandazioni di Prowlarr", "IncludeHealthWarningsHelpText": "Includi gli avvisi di salute", - "ImportMovies": "Importa Film", "Importing": "Importazione", - "ImportFailed": "Importazione fallita: {0}", "ImportExtraFiles": "Importa file Extra", - "ImportCustomFormat": "Importa formati personalizzati", "IllRestartLater": "Riavvierò più tardi", - "IgnoredHelpText": "Questa release sarà respinta se contiene uno o più di questi termini (Sensibile al maiuscolo)", "IgnoredAddresses": "Indirizzi ignorati", - "ICalHttpUrlHelpText": "Copia questo URL sul tuo client o clicca per sottoscrivere se il tuo browser supporta Webcal", "HiddenClickToShow": "Nascosto, premi per mostrare", - "HaveNotAddedMovies": "Non hai ancora aggiunto nessun film, vuoi prima importarne alcuni o tutti i tuoi film?", "GrabReleaseMessageText": "Prowlarr non è stato in grado di determinare a quale film si riferisce questa release. Prowlarr potrebbe non essere in grado di importarla automaticamente. Vuoi catturare '{0}'?", - "Global": "Globale", "GeneralSettings": "Impostazioni Generali", - "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Per maggiori informazioni sulle singole liste di importazione clicca sul pulsante info.", "ForMoreInformationOnTheIndividualDownloadClients": "Per maggiori informazioni sui singoli client di download clicca sul pulsante info.", - "Folders": "Cartelle", "Fixed": "Fissato", - "FailedLoadingSearchResults": "Caricamento dei risultati della ricerca fallito, prova ancora.", "ExistingMovies": "Film esistente(i)", - "ErrorLoadingPreviews": "Errore nel caricare le anteprime", "EnableInteractiveSearchHelpTextWarning": "La ricerca non è supportata dal questo indexer", "FilterPlaceHolder": "Cerca Films", - "FileChmodHelpTexts1": "Octal, applicato a file media quando sono importati/rinominati da Prowlarr", "ExistingTag": "Tag esistente", "Exception": "Eccezione", "ErrorLoadingContents": "Errore nel caricare i contenuti", @@ -419,66 +309,49 @@ "EnableAutomaticSearch": "Attiva la ricerca automatica", "EnableAutomaticAdd": "Attiva l'aggiunta automatica", "Downloading": "Scaricando", - "DownloadFailed": "Download fallito", "DownloadedAndMonitored": "Scaricato e Monitorato", "DownloadClientUnavailable": "Il client di download non è disponibile", "DeleteTagMessageText": "Sei sicuro di voler eliminare il tag '{0}'?", - "DeleteRestrictionHelpText": "Sei sicuro di voler eliminare questa limitazione?", "DeleteNotificationMessageText": "Sei sicuro di voler eliminare la notifica '{0}'?", "DeleteIndexerMessageText": "Sei sicuro di voler eliminare l'indexer '{0}'?", "DeleteDownloadClientMessageText": "Sei sicuro di voler eliminare il client di download '{0}'?", - "CustomFormatUnknownConditionOption": "Opzione sconosciuta '{0}' per la condizione '{1}'", "BeforeUpdate": "Prima di aggiornare", "ApplyTagsHelpTexts4": "Sostituire: sostituisci le tag con le tag inserite (non inserire nessuna tag per pulirle tutte)", "ApplyTagsHelpTexts3": "Rimuovere: rimuovi le tag inserite", "Usenet": "Usenet", "Uptime": "Tempo di attività", "YesCancel": "Si, annulla", - "WhitelistedHardcodedSubsHelpText": "I tag dei sottotitoli impostati qui non saranno considerati incorporati", "WaitingToProcess": "In attesa di processo", - "VisitGithubCustomFormatsAphrodite": "Visita Github per maggiori dettagli: ", "Version": "Versione", "Username": "Nome utente", "UseProxy": "Usa Proxy", - "UsenetDelay": "Ritardo della Usenet", "UrlBaseHelpText": "Per il supporto al reverse proxy, di default è vuoto", "URLBase": "URL di Base", - "UpgradeAllowedHelpText": "Se disabilitato la qualità non verrà incrementata", "UpdateScriptPathHelpText": "Percorso verso uno script che prende un pacchetto di aggiornamento estratto e gestisce il resto del processo di aggiornamento", "UpdateMechanismHelpText": "Usa il programma di aggiornamento incorporato in Prowlarr o uno script", "UpdateAutomaticallyHelpText": "Download e installazione automatica degli aggiornamenti. Sarai comunque in grado in installarli dal menu Sistema: Aggiornamenti", "UnsavedChanges": "Modifiche non salvate", - "Unreleased": "Inedito", "UnableToLoadUISettings": "Non riesco a caricare le impostazioni della UI", "UnableToLoadTags": "Non riesco a caricare i tag", - "UnableToLoadRestrictions": "Non riesco a caricare le restrizioni", "UnableToLoadQualityProfiles": "Non riesco a caricare i profili della qualità", "UnableToLoadQualityDefinitions": "Non riesco a caricare le definizioni della qualità", "UnableToLoadNotifications": "Non riesco a caricare le notifiche", - "UnableToLoadMovies": "Non riesco a caricare i film", "UnableToLoadMediaManagementSettings": "Non riesco a caricare le impostazioni di Gestione dei Media", - "UnableToLoadListOptions": "Non riesco a caricare le opzione delle liste", "UnableToLoadLanguages": "Non riesco a caricare le lingue", "UnableToLoadIndexers": "Non riesco a caricare l'indexer", "UnableToLoadHistory": "Non riesco a caricare la storia", "UnableToLoadGeneralSettings": "Non riesco a caricare le impostazioni generali", "UnableToLoadDownloadClients": "Non riesco a caricare i client di download", - "UnableToLoadDelayProfiles": "Non riesco a caricare i profili di ritardo", "UnableToLoadBackups": "Non riesco a caricare i backup", - "UnableToAddANewQualityProfilePleaseTryAgain": "Non riesco ad aggiungere un nuovo profilo di qualità, riprova.", "UnableToAddANewNotificationPleaseTryAgain": "Non riesco ad aggiungere una nuova notifica, riprova.", - "UnableToAddANewListExclusionPleaseTryAgain": "Non riesco ad aggiungere una nuova lista di esclusione, riprova.", "UnableToAddANewIndexerPleaseTryAgain": "Non riesco ad aggiungere un nuovo indexer, riprova.", "UnableToAddANewDownloadClientPleaseTryAgain": "Non riesco ad aggiungere un nuovo client di download, riprova.", - "UnableToAddANewConditionPleaseTryAgain": "Non riesco ad aggiungere una nuova condizione, riprova.", "UISettings": "Impostazioni UI", "UILanguageHelpTextWarning": "E' richiesto il reload del browser", "UILanguageHelpText": "Lingua che Prowlarr userà per la UI", "UILanguage": "Lingua della UI", "Torrents": "Torrent", - "TorrentDelay": "Ritardo del torrent", "TMDBId": "ID di TMDb", - "ThisConditionMatchesUsingRegularExpressions": "Questa condizione si applica usando espressione regolari. Nota che i caratteri {0} hanno significati speciali e devono essere evitati con un {1}", "TestAllIndexers": "Testa tutti gli indexer", "TestAllClients": "Testa tutti i client", "TagsHelpText": "Si applica ai film con almeno un tag corrispondente", @@ -492,33 +365,22 @@ "SSLCertPath": "Percorso Cert SSL", "SSLCertPasswordHelpText": "Password del file pfx", "SSLCertPassword": "Password Cert SSL", - "SourcePath": "Percorso origine", "SkipFreeSpaceCheckWhenImportingHelpText": "Usa quando Prowlarr non è in grado di determinare lo spazio libero della cartella di root dei film", - "ShowYear": "Mostra anno", "ShowTitleHelpText": "Mostra il titolo del film sotto il poster", - "ShowStudio": "Mostra Studio", "ShowSearchHelpText": "Mostra pulsante ricerca al passaggio", "ShowSearch": "Mostra ricerca", - "ShowQualityProfileHelpText": "Mostra profilo qualità sotto il poster", "ShowPath": "Mostra percorso", "ShownClickToHide": "Visibile, clicca per nascondere", - "ShowMovieInformation": "Mostra le info del Film", "ShowMonitored": "Mostra i monitorati", - "ShowDateAdded": "Mostra data di aggiunta", "ShowCertification": "Mostra certificato", - "ShouldMonitorHelpText": "Se abilitato, i film aggiunti da questa lista sono aggiunti e monitorati", "SettingsWeekColumnHeader": "Intestazione colonna settimana", "SettingsTimeFormat": "Formato orario", "SettingsShowRelativeDatesHelpText": "Mostra date relative (Oggi/Ieri/ecc) o assolute", "SettingsShowRelativeDates": "Mostra date relative", "SettingsShortDateFormat": "Formato Data Corto", - "SettingsRemotePathMappingRemotePathHelpText": "Percorso root alla cartella a cui accede il client di download", "SettingsRemotePathMappingLocalPathHelpText": "Percorso che Prowlarr dovrebbe usare per accedere localmente al percorso remoto", - "SettingsRemotePathMappingHostHelpText": "Lo stesso host specificato per il client di download remoto", "SettingsEnableColorImpairedModeHelpText": "Stile alterato per permettere agli utenti daltonici di distinguere meglio le informazioni con colori codificati", - "DownloadPropersAndRepacksHelpTextWarning": "Usa le parole preferite per aggiornare automaticamente a proper/repack", "DownloadPropersAndRepacksHelpText1": "Aggiornare o meno automaticamente a Proper/Repack", - "CopyToClipboard": "Copia negli appunti", "Priority": "Priorità", "InteractiveSearch": "Ricerca interattiva", "IndexerPriorityHelpText": "Priorità dell'indexer da 1 (più alto) a 50 (più basso). Default: 25.", @@ -536,15 +398,10 @@ "FocusSearchBox": "Attiva casella di ricerca", "CloseCurrentModal": "Chiudi la modalità corrente", "AcceptConfirmationModal": "Accetta modalità di conferma", - "StartProcessing": "Avvia Lavorazione", "SearchFailedPleaseTryAgainLater": "Ricerca fallita, provare più tardi.", - "Released": "Rilasciato", "NoMatchFound": "Nessuna corrispondenza trovata!", - "ImportIncludeQuality": "Assicurati che i tuoi file includano la qualità nel nome. Es. {0}", "Existing": "Esistente", - "Digital": "Digitale", "AddRestriction": "Aggiungi Limitazioni", - "ListTagsHelpText": "Gli elementi dell'elenco dei tag saranno aggiunti con", "IndexerLongTermStatusCheckSingleClientMessage": "Alcuni indexer non disponibili da più di 6 ore a causa di errori: {0}", "IndexerLongTermStatusCheckAllClientMessage": "Nessun indexer è disponibile da più di 6 ore a causa di errori", "PrioritySettings": "Priorità", diff --git a/src/NzbDrone.Core/Localization/Core/nl.json b/src/NzbDrone.Core/Localization/Core/nl.json index 0c41c8945..9074fb5c4 100644 --- a/src/NzbDrone.Core/Localization/Core/nl.json +++ b/src/NzbDrone.Core/Localization/Core/nl.json @@ -1,21 +1,15 @@ { - "IndexerSearchCheckNoAutomaticMessage": "Geen indexeerders beschikbaar met \"Automatisch Zoeken\" ingeschakeld, Prowlarr zal geen automatische zoekopdrachten uitvoeren", "Indexers": "Indexeerders", - "IndexerRssHealthCheckNoAvailableIndexers": "Alle RSS-capabele indexeerders zijn tijdelijk onbeschikbaar wegens recente fouten", "ImportSecondTip": "Wijs Prowlarr naar de map die al je films bevat, niet naar een map met slechts één specifieke film. Bijv.", - "Week": "Week", "ImportFirstTip": "Zorg ervoor dat je bestanden de kwaliteit in hun bestandsnaam bevatten. Bijv.", - "iCalLink": "iCal Koppeling", "Host": "Host", "History": "Geschiedenis", "HideAdvanced": "Verberg Gevorderd", "Health": "Gezondheid", "General": "Algemeen", - "Formats": "Formaten", "Folder": "Map", "Filter": "Filter", "Files": "Bestanden", - "FailedDownloadHandling": "Mislukte Download Afhandeling", "Events": "Gebeurtenissen", "Edit": "Bewerk", "DownloadClientStatusCheckSingleClientMessage": "Downloaders onbeschikbaar wegens fouten: {0}", @@ -23,30 +17,24 @@ "DownloadClients": "Downloaders", "DownloadClientCheckUnableToCommunicateMessage": "Niet in staat om te communiceren met {0}.", "DownloadClientCheckNoneAvailableMessage": "Er is geen downloader beschikbaar", - "DotNetVersionCheckNotRecommendedMessage": "Het momenteel geïnstalleerde .NET Framework {0} wordt ondersteund, maar we raden aan om te opwaarderen naar minstens {1}.", "Discover": "Ontdekken", "Delete": "Verwijderen", - "Day": "Dag", "Dates": "Datum en tijd", "Date": "Datum", "CustomFilters": "Aangepaste Filters", "Connections": "Connecties", "Connect": "Meldingen", "Clear": "Wissen", - "Cast": "Acteurs", "Blacklist": "Zwarte lijst", "BackupNow": "Veiligheidskopie Maken", "Analytics": "Statistieken", "Backup": "Veiligheidskopie", "AppDataLocationHealthCheckMessage": "Bijwerken zal niet mogelijk zijn om het verwijderen van AppData te voorkomen", "All": "Alles", - "AddNewMessage": "Het is gemakkelijk om een nieuwe film toe te voegen, begin gewoon met de naam te typen van de film die je wilt toevoegen", "AddExclusion": "Uitzondering(en) Toevoegen", - "Activity": "Activiteit", "About": "Over", "View": "Weergave", "UnselectAll": "Alles Deselecteren", - "Titles": "Titels", "Tasks": "Taken", "System": "Systeem", "Style": "Stijl", @@ -55,40 +43,30 @@ "Settings": "Instellingen", "SelectAll": "Alles Selecteren", "Security": "Beveiliging", - "SearchForMissing": "Ontbrekende Zoeken", "SearchAll": "Alles Zoeken", "Search": "Zoeken", "Scheduled": "Gepland", "SaveChanges": "Wijzigingen Opslaan", "Restrictions": "Restricties", "RestoreBackup": "Veiligheidskopie Herstellen", - "RemoveSelected": "Selectie Verwijderen", "Refresh": "Vernieuw", "Queue": "Wachtrij", - "QualityProfile": "Kwaliteitsprofiel", "QualityDefinitions": "Kwaliteitsdefinities", "Proxy": "Proxy", - "PreviewRename": "Voorbeeldweergave Naamswijziging", "Options": "Opties", "NoChanges": "Geen Wijzigingen", "NoChange": "Geen Wijziging", - "ImportListStatusCheckAllClientMessage": "Alle lijsten zijn onbeschikbaar wegens fouten", "Movies": "Films", - "MovieIndex": "Film Overzicht", "Movie": "Film", "MoreInfo": "Meer Info", "MonoNotNetCoreCheckMessage": "Gelieve te opwaarderen naar de .NET Core versie van Prowlarr", - "Missing": "Ontbrekend", "MinAvailability": "Min Beschikbaarheid", - "MediaManagement": "Mediabeheer", "ManualImport": "Manuele Import", "Logging": "Logbeheer", "LogFiles": "Logbestanden", - "ListExclusions": "Uitzonderingenlijst", "Languages": "Talen", "Language": "Taal", "ShowAdvanced": "Toon Gevorderd", - "RSSSync": "RSS Sync.", "UpdateCheckUINotWritableMessage": "Kan de update niet installeren omdat de UI map '{0}' niet schrijfbaar is voor de gebruiker '{1}'.", "UpdateCheckStartupTranslocationMessage": "Kan de update niet installeren omdat de map '{0}' zich in een 'App Translocation' map bevindt.", "UpdateCheckStartupNotWritableMessage": "Kan de update niet installeren omdat de map '{0}' niet schrijfbaar is voor de gebruiker '{1}'.", @@ -99,31 +77,21 @@ "Updates": "Updates", "Tags": "Tags", "SetTags": "Tags Toepassen", - "RootFolderCheckMultipleMessage": "Meerdere hoofdmappen ontbreken: {0}", "UI": "Gebruikersinterface", - "RemovedMovieCheckMultipleMessage": "De films {0} zijn verwijderd van TMDb", "ReleaseBranchCheckOfficialBranchMessage": "Branch {0} is geen geldige Prowlarr release branch, u zult geen updates ontvangen", "ProxyCheckResolveIpMessage": "Achterhalen van het IP-adres voor de geconfigureerde proxy host {0} is mislukt", "ProxyCheckFailedToTestMessage": "Testen van proxy is mislukt: {0}", "ProxyCheckBadRequestMessage": "Testen van proxy is mislukt. Statuscode: {0}", "MonoTlsCheckMessage": "Tijdelijke Prowlarr Mono 4.x TLS oplossing nog steeds ingeschakeld, overweeg de MONO_TLS_PROVIDER=legacy omgevingsvariabele te verwijderen", - "UpdateSelected": "Selectie Bijwerken", "UISettingsSummary": "Datum, kleurenblindheid en taal instellingen", "TagsSettingsSummary": "Bekijk alle tags en hun gebruik. Ongebruikte tags kunnen worden verwijderd", - "SizeOnDisk": "Grootte op Schijf", "Size": "Grootte", - "Renamed": "Hernoemd", "ReleaseStatus": "Uitgave Status", - "Ratings": "Waardering", "Protocol": "Protocol", - "ProfilesSettingsSummary": "Kwaliteits- en vertragingsprofielen", "OutputPath": "Uitvoer Pad", - "MonitoredOnly": "Bewaakt", "MediaManagementSettingsSummary": "Naamgeving en bestandsbeheer instellingen", - "ListsSettingsSummary": "Lijsten en uitzonderingen", "LastWriteTime": "Laatste Modificatietijd", "Indexer": "Indexeerder", - "Imported": "Geïmporteerd", "Grabbed": "Opgehaalde", "GeneralSettingsSummary": "Poort, SSL, gebruikersnaam/wachtwoord, proxy, statistieken en updates", "Filename": "Bestandsnaam", @@ -132,15 +100,12 @@ "DownloadClientsSettingsSummary": "Clientconfiguratie downloaden voor integratie in Prowlarr UI-zoekopdracht", "DownloadClient": "Downloader", "Details": "Details", - "CutoffUnmet": "Onbereikte Drempel", "ConnectSettingsSummary": "Meldingen en aangepaste scripts", - "Certification": "Certificatie", "Added": "Toegevoegd", "Actions": "Acties", "Seeders": "Seeders", "Peers": "Peers", "Warn": "Waarschuwing", - "Unavailable": "Onbeschikbaar", "Type": "Type", "Title": "Titel", "Time": "Tijd", @@ -154,21 +119,16 @@ "Save": "Opslaan", "Restart": "Herstart", "Reload": "Herlaad", - "RejectionCount": "Afwijzingsniveau", "PageSize": "Pagina Grootte", - "OrganizeModalNamingPattern": "Naamgeving Sjabloon:", "OrganizeModalAllPathsRelative": "Alle paden zijn relatief t.o.v.:", - "Organize": "Organiseer", "Ok": "Ok", "OAuthPopupMessage": "Pop-ups worden geblokkeerd door uw browser", "Name": "Naam", - "Monitored": "Bewaakt", "Message": "Bericht", "Level": "Niveau", "KeyboardShortcuts": "Sneltoetsen", "Info": "Info", "HealthNoIssues": "Geen problemen gevonden met uw configuratie", - "Extension": "Extensie", "Error": "Fout", "ConnectionLostMessage": "Prowlarr heeft zijn verbinding met de backend verloren en zal moeten worden herladen om functionaliteit te herstellen.", "ConnectionLostAutomaticMessage": "Prowlarr zal automatisch proberen te verbinden, of u kunt hieronder op herladen klikken.", @@ -178,39 +138,29 @@ "Close": "Sluit", "Cancel": "Annuleer", "Apply": "Toepassen", - "AllMoviesHiddenDueToFilter": "Alle films zijn verborgen wegens de toegepaste filter.", "Age": "Leeftijd", - "AddList": "Lijst Toevoegen", "Posters": "Affiches", "UnsavedChanges": "Onopgeslagen Wijzigingen", - "ShowTitle": "Toon Titel", "ShowSizeOnDisk": "Toon Grootte op Schijf", "ShowSearchHelpText": "Toon zoeken knop bij zweven", "ShowSearch": "Toon Zoeken", - "ShowPath": "Toon Pad", "ShowDateAdded": "Toon Datum Toegevoegd", - "SettingsWeekColumnHeader": "Week Kolom Koptekst", "SettingsUiLanguage": "Gebruikersinterface Taal", "SettingsTimeFormat": "Tijdsformaat", "SettingsShowRelativeDatesHelpText": "Toon relatieve (Vandaag/Gisteren/enz.) of absolute datums", "SettingsShowRelativeDates": "Toon Relatieve Datums", "SettingsShortDateFormat": "Korte Datumnotatie", - "SettingsRemotePathMappingRemotePath": "Extern Pad", "SettingsRemotePathMappingLocalPath": "Lokaal Pad", "SettingsLongDateFormat": "Lange Datumnotatie", "SettingsEnableColorImpairedModeHelpText": "Aangepaste stijl voor gebruikers die kleurenblind zijn om gemakkelijker kleurgecodeerde informatie te onderscheiden", "SettingsEnableColorImpairedMode": "Activeer Kleurenblindheid-modus", - "SearchOnAdd": "Zoeken bij Toevoegen", "RecentFolders": "Recente Mappen", "PendingChangesStayReview": "Blijf en bekijk de wijzigingen", "PendingChangesMessage": "U heeft onopgeslagen wijzigingen, bent u zeker dat u deze pagina wilt sluiten?", "PendingChangesDiscardChanges": "Wijzigingen verwerpen en verdergaan", - "Overview": "Overzicht", "MonoVersionCheckUpgradeRecommendedMessage": "De huidige geïnstalleerde Mono versie {0} wordt ondersteund, maar het is aangeraden om te opwaarderen naar versie {1}.", - "MonoVersionCheckNotSupportedMessage": "De huidige geïnstalleerde Mono versie {0} wordt niet langer ondersteund. Gelieve te opwaarderen naar versie {1}.", "InteractiveImport": "Interactieve Import", "ExistingMovies": "Bestaande Film(s)", - "EditRemotePathMapping": "Bewerk Externe Pad Verwijzing", "DetailedProgressBar": "Gedetailleerde voortgangsbalk", "Interval": "Tussentijd", "Fixed": "Opgelost", @@ -218,70 +168,47 @@ "AuthenticationMethodHelpText": "Gebruikersnaam en wachtwoord nodig voor toegang tot Prowlarr", "Authentication": "Authenticatie", "AppDataDirectory": "AppData map", - "AgeWhenGrabbed": "Leeftijd (op moment van ophalen)", "AnalyticsEnabledHelpText": "Stuur anonieme gebruiks- en foutinformatie naar de servers van Prowlarr. Dit omvat informatie over uw browser, welke Prowlarr WebUI pagina's u gebruikt, foutrapportage en OS en runtime versie. We zullen deze informatie gebruiken om prioriteiten te stellen voor functies en het verhelpen van fouten.", - "AnalyseVideoFiles": "Analyseer videobestanden", "AllowHardcodedSubs": "Sta Ingebrande Ondertiteling Toe", "YesCancel": "Ja, Annuleren", - "AddMoviesMonitored": "Film(s) Bewaakt Toevoegen", "CleanLibraryLevel": "Bibliotheek Opschonen Niveau", "DeleteTag": "Verwijder Tag", - "DeleteRestriction": "Verwijder Restrictie", "DeleteNotification": "Verwijder Notificatie", "DeleteIndexer": "Verwijder Indexeerder", - "DeleteFile": "Verwijder Bestand", "DeleteDownloadClient": "Verwijder Downloader", - "DeleteCustomFormat": "Verwijder Eigen Formaat", "Enable": "Activeer", - "EditMovie": "Bewerk Film", "DownloadPropers": "Download PROPERS", "DownloadClientSettings": "Downloader Instellingen", "Docker": "Docker", - "DestinationPath": "Doelmap", "DelayProfile": "Vertragingsprofiel", "DBMigration": "DB Migratie", - "CutoffFormatScoreHelpText": "Wanneer deze eigen formaat score is behaald, zal Prowlarr niet langer films downloaden", "CreateGroup": "Groep aanmaken", - "CreateEmptyMovieFolders": "Lege film mappen aanmaken", "ConnectSettings": "Connecties Instellingen", - "ColonReplacementFormatHelpText": "Wijzig hoe Prowlarr omgaat met dubbele punt vervanging", "CloneProfile": "Dupliceer Profiel", "CloneIndexer": "Dupliceer Indexeerder", "ClientPriority": "Client Prioriteit", - "ClickToChangeLanguage": "Klik om taal te wijzigen", "ChangeHasNotBeenSavedYet": "Wijziging is nog niet opgeslagen", - "CertificationCountryHelpText": "Selecteer Land voor Film Certificatie", "CertificateValidationHelpText": "Wijzig hoe strikt HTTPS certificaat validatie is", "CertificateValidation": "Certificaat Validatie", "BypassProxyForLocalAddresses": "Omzeil Proxy voor Lokale Adressen", "Branch": "Branch", - "BlacklistHelpText": "Voorkomt dat Prowlarr deze film nogmaals automatisch ophaalt", "BindAddressHelpText": "Geldig IPv4 adres of '*' voor alle interfaces", "DeleteBackup": "Verwijder Veiligheidskopie", "BackupIntervalHelpText": "Tussentijd voor automatische back-up", "Backups": "Veiligheidskopieën", "BackupRetentionHelpText": "Automatische veiligheidskopieën ouder dan de retentie periode zullen worden opgeruimd", "BackupFolderHelpText": "Relatieve paden zullen t.o.v. de Prowlarr AppData map bekeken worden", - "AvailabilityDelay": "Beschikbaarheidsvertraging", "AutoRedownloadFailedHelpText": "Automatisch zoeken en probeer een andere release te downloaden", - "AsAllDayHelpText": "Gebeurtenissen zullen als hele-dag gebeurtenissen verschijnen in uw kalender", "AreYouSureYouWantToResetYourAPIKey": "Bent u zeker dat u uw API-sleutel wilt resetten?", - "AreYouSureYouWantToDeleteThisImportListExclusion": "Bent u zeker dat u dit van de uitzonderingenlijst wilt verwijderen?", "ApplyTags": "Tags Toepassen", "ApiKey": "API-sleutel", - "ImportMovies": "Importeer Films", "Importing": "Importeren", - "ImportExtraFiles": "Importeer Extra Bestanden", "IllRestartLater": "Ik zal later herstarten", - "GrabRelease": "Uitgave Ophalen", "IgnoreDeletedMovies": "Negeer Verwijderde Films", "IgnoredAddresses": "Genegeerde Adressen", "Hostname": "Hostnaam", - "Group": "Groep", "GeneralSettings": "Algemene Instellingen", - "Folders": "Mappen", "FileNames": "Bestandsnamen", - "Exluded": "Uitgesloten", "EnableSSL": "Activeer SSL", "EnableInteractiveSearch": "Activeer Interactief Zoeken", "EnableHelpText": "Schakel het maken van metadata bestanden in voor dit metadata type", @@ -292,64 +219,45 @@ "EnableAutomaticSearch": "Activeer Automatisch Zoeken", "EnableAutomaticAdd": "Activeer Automatisch Toevoegen", "EnableAutoHelpText": "Indien ingeschakeld, zullen films automatisch aan Prowlarr worden toegevoegd van deze lijst", - "DownloadFailedCheckDownloadClientForMoreDetails": "Download mislukt: controleer de downloader voor meer details", "CopyUsingHardlinksHelpText": "Gebruik hardlinks bij het kopiëren van torrent bestanden die nog actief zijn", - "PreferIndexerFlags": "Verkies Indexeerder Flags", "PortNumber": "Poort Nummer", "Port": "Poort", "Password": "Wachtwoord", "PackageVersion": "Pakket Versie", - "OnRenameHelpText": "Bij Hernoemen", "OnHealthIssueHelpText": "Bij Gezondheidsprobleem", - "NotMonitored": "Niet Bewaakt", "NoLeaveIt": "Nee, Ongemoeid Laten", "New": "Nieuw", - "MustNotContain": "Mag Niet Bevatten", "MovieYear": "Film Jaar", - "MovieInfoLanguageHelpTextWarning": "Browser Herladen Vereist", "MovieFolderFormat": "Film Map Formaat", - "MovieAvailableButMissing": "Film Beschikbaar, maar Ontbrekend", "MonoVersion": "Mono Versie", "Mode": "Modus", "MinimumLimits": "Minimum Limieten", - "MinimumAge": "Minumum Leeftijd", "MediaManagementSettings": "Mediabeheer Instellingen", "Mechanism": "Mechanisme", "MaximumLimits": "Maximum Limiet", "Logs": "Logbestanden", "LogLevel": "Log Niveau", - "ListUpdateInterval": "Lijst Bijwerken Tussentijd", "Links": "Koppelingen", "EnableMediaInfoHelpText": "Video informatie extraheren zoals resolutie, speelduur en codec informatie van bestanden. Dit maakt het noodzakelijk dat Prowlarr delen van een bestand moet inlezen dewelke hoge schijf- of netwerkactiviteit kan veroorzaken tijdens het scannen.", "BindAddress": "Aanhaak Adres", - "MinimumAgeHelpText": "Enkel Usenet: Minimale leeftijd in minuten voor NZB bestanden alvorens ze worden opgehaald. Gebruik dit om nieuwe uitgaves de tijd te geven om tot bij uw Usenet provider toe te komen.", "IndexerSettings": "Indexeerder Instellingen", "IndexerFlags": "Indexeerder Flags", "EnableSslHelpText": " Vereist herstart als administrator om in werking te treden", "PriorityHelpText": "Geef prioriteit aan meerdere downloaders. Round-Robin wordt gebruikt voor downloaders met dezelfde prioriteit.", - "RecycleBinCleanupDaysHelpText": "Zet op 0 om automatisch opschonen uit te schakelen", "RemoveCompletedDownloadsHelpText": "Verwijder geïmporteerde downloads uit de downloader geschiedenis", - "ReplaceIllegalCharactersHelpText": "Vervang illegale karakters. Indien niet aangevinkt, zal Prowlarr ze in de plaats daarvan verwijderen", "RssSyncIntervalHelpTextWarning": "Dit zal van toepassing zijn op alle indexeerders, gelieve de door hen opgelegde regels te volgen", "SendAnonymousUsageData": "Zend Anonieme Gebruiksdata", - "ShowCutoffUnmetIconHelpText": "Toon icoon voor bestanden waarbij de drempel niet behaald werd", "SkipFreeSpaceCheckWhenImportingHelpText": "Gebruik dit wanneer Prowlarr geen vrije schijfruimte kan detecteren voor de hoofdmap van je films", - "StandardMovieFormat": "Standaard Film Formaat", "TorrentDelayHelpText": "Wachttijd in minuten alvorens een torrent op te halen", "UnableToLoadIndexers": "Indexeerders kunnen niet worden geladen", "UnableToLoadNotifications": "Notificaties kunnen niet worden geladen", "UpdateAutomaticallyHelpText": "Download en installeer updates automatisch. Je zal nog steeds kunnen installeren vanuit Systeem: Updates", "UrlBaseHelpText": "Voor reverse proxy ondersteuning, leeg is standaard", - "IncludeUnknownMovieItemsHelpText": "Toon items zonder een film in de wachtrij, dit kan verwijderde films, TV series of iets anders in Prowlarr zijn categorie omvatten", "IncludeHealthWarningsHelpText": "Voeg Gezondheidswaarschuwingen Toe", - "ListSyncLevelHelpText": "Films in de bibliotheek zullen onbewaakt of verwijderd worden als ze niet in je lijst voorkomen", "LaunchBrowserHelpText": " Open een web browser en navigeer naar de Prowlarr startpagina bij het starten van de app.", "MIA": "MIA", - "MinimumFreeSpaceWhenImportingHelpText": "Voorkom importeren indien de resulterende schijfruimte minder is dan deze hoeveelheid", "MovieTitleHelpText": "De titel van de uit te sluiten film (kan van alles zijn)", - "ImportListSyncIntervalHelpText": "Hoe vaak Prowlarr je lijsten synchroniseert.", "NotificationTriggers": "Melding Reactiestarters", - "OnUpgradeHelpText": "Word op de hoogte gebracht wanneer films worden bijgewerkt naar een betere kwaliteit", "OpenBrowserOnStart": "Open de browser bij het starten", "PageSizeHelpText": "Aantal items om te tonen op iedere pagina", "NoLimitForAnyRuntime": "Geen limiet voor eender welke speelduur", @@ -358,38 +266,27 @@ "PreferredSize": "Gewenste Grootte", "ProxyPasswordHelpText": "Je moet alleen een gebruikersnaam en wachtwoord ingeven als dit vereist is, laat ze anders leeg.", "ProxyUsernameHelpText": "Je moet alleen een gebruikersnaam en wachtwoord ingeven als dit vereist is, laat ze anders leeg.", - "QualityCutoffHasNotBeenMet": "Kwaliteitsdrempel werd niet behaald", "QualitySettings": "Kwaliteitsinstellingen", "ReadTheWikiForMoreInformation": "Lees de Wiki voor meer informatie", - "Reason": "Reden", "RecyclingBin": "Prullenbak", - "Redownload": "Opnieuw downloaden", "RefreshMovie": "Film vernieuwen", "ProxyType": "Proxy Type", "ProxyBypassFilterHelpText": "Gebruik ',' als scheidingsteken en '*' als wildcard voor subdomeinen", - "ProwlarrTags": "Prowlarr Tags", "ReleaseRejected": "Uitgave Afgekeurd", "RemovedFromTaskQueue": "Verwijderd uit taken wachtrij", "RemoveFilter": "Verwijder filter", - "RemoveFromDownloadClient": "Verwijder uit downloader", "RenameMovies": "Hernoem Films", - "Reorder": "Herordenen", "RequiredHelpText": "Deze {0} conditie moet overeenstemmen om het eigen formaat te kunnen toepassen. Anders is een enkele {1} overeenstemming voldoende.", - "RescanMovieFolderAfterRefresh": "De film map herscannen na vernieuwen", "Reset": "Reset", "RestartNow": "Herstart Nu", "RestartProwlarr": "Herstart Prowlarr", "RestartRequiredHelpTextWarning": "Herstarten vereist om in werking te treden", "Result": "Resultaat", "Retention": "Retentie", - "RSSSyncInterval": "RSS Sync. Tussentijd", "ScriptPath": "Script Pad", "ResetAPIKey": "Reset API-sleutel", - "SetPermissionsLinuxHelpTextWarning": "Als je onzeker bent over deze instellingen en hun functie, pas ze dan niet aan.", "ShowAsAllDayEvents": "Weergeven als evenementen die de hele dag duren", - "ShowMovieInformation": "Toon film informatie", "ShowQualityProfileHelpText": "Toon kwaliteitsprofiel onder poster", - "SkipFreeSpaceCheck": "Vrije schijfruimte controle overslaan", "SourceRelativePath": "Relatief Bron Pad", "SSLCertPassword": "SSL Certificaat Wachtwoord", "SSLCertPath": "SSL Certificaat Pad", @@ -398,17 +295,12 @@ "SuggestTranslationChange": "Stel vertaling voor", "TagsHelpText": "Is van toepassing op films met minstens één overeenkomende tag", "TestAllClients": "Test Alle Downloaders", - "TimeFormat": "Tijdsformaat", "TmdbIdHelpText": "De TMDb Id van de uit te sluiten film", "Torrents": "Torrents", "UISettings": "Gebruikersinterface Instellingen", - "UnableToLoadDelayProfiles": "Vertragingsprofielen kunnen niet worden geladen", "UnableToLoadDownloadClients": "Downloaders kunnen niet worden geladen", - "UnableToLoadLists": "Lijsten kunnen niet worden geladen", "UnableToLoadQualityDefinitions": "Kwaliteitsdefinities kunnen niet worden geladen", - "UnableToLoadRemotePathMappings": "Externe pad verwijzingen kunnen niet worden geladen", "UnableToLoadTags": "Tags kunnen niet worden geladen", - "UnmonitoredHelpText": "Voeg onbewaakte films toe aan de iCal informatiestrrom", "UpdateMechanismHelpText": "Gebruik het ingebouwde updatemechanisme of een extern script", "UpdateScriptPathHelpText": "Pad naar een aangepast script dat een uitgepakt updatepakket accepteert en de rest van het updateproces afhandelt", "Uptime": "Bedrijfstijd", @@ -417,73 +309,52 @@ "UseProxy": "Gebruik Proxy", "Username": "Gebruikersnaam", "Version": "Versie", - "WhitelistedHardcodedSubsHelpText": "Deze ondertiteling tags zullen niet als ingebrand worden beschouwd", "SettingsRuntimeFormat": "Speelduur Formaat", - "WaitingToImport": "Wachten tot Importeren", "TagCannotBeDeletedWhileInUse": "Kan niet verwijderd worden terwijl in gebruik", "SSLCertPathHelpText": "Pad naar pfx bestand", "SSLCertPasswordHelpText": "Wachtwoord voor pfx bestand", - "ShowRatings": "Toon Waarderingen", "ShownClickToHide": "Getoond, klik om te verbergen", - "ShowCertification": "Toon Certificatie", "RSSSyncIntervalHelpTextWarning": "Dit zal van toepassing zijn op alle indexeerders, gelieve de door hen opgelegde regels te volgen", "RSSIsNotSupportedWithThisIndexer": "RSS wordt niet ondersteund door deze indexeerder", "RemovingTag": "Tag verwijderen", - "Queued": "Afwachtend", "Pending": "In afwachting", - "NegateHelpText": "Indien aangevinkt, zal het eigen formaat niet worden toegepast indien deze {0} conditie overeenstemt.", "MovieIsUnmonitored": "Film wordt niet bewaakt", - "MovieIsDownloadingInterp": "Film is aan het downloaden - {0}% {1}", "MovieAlreadyExcluded": "Film werd al Uitgesloten", "Manual": "Manueel", "LogLevelTraceHelpTextWarning": "Trace log niveau moet enkel tijdelijk worden gebruikt", - "IncludeRecommendationsHelpText": "Voeg Prowlarr aanbevolen films toe aan ontdekken weergave", "ImportFailedInterp": "Importeren mislukt: {0}", "HiddenClickToShow": "Verborgen, klik om te tonen", - "GoToInterp": "Ga naar {0}", "ExistingTag": "Bestaande tag", "EnableInteractiveSearchHelpTextWarning": "Zoeken wordt niet ondersteund door deze indexeerder", "EnableInteractiveSearchHelpText": "Zal worden gebruikt wanneer interactief zoeken wordt gebruikt", "EnableAutomaticSearchHelpTextWarning": "Zal worden gebruikt wanneer interactief zoeken wordt gebruikt", "EnableAutomaticSearchHelpText": "Zal worden gebruikt wanneer automatische zoekopdrachten worden uitgevoerd via de gebruikersinterface of door Prowlarr", "Downloading": "Downloaden", - "DownloadFailed": "Download mislukt", "DownloadClientUnavailable": "Downloader is onbeschikbaar", "DeleteTagMessageText": "Bent u zeker dat u de tag '{0}' wilt verwijderen?", - "DeleteRestrictionHelpText": "Bent u zeker dat u deze restrictie wilt verwijderen?", "DeleteNotificationMessageText": "Bent u zeker dat u de notificatie '{0}' wilt verwijderen?", "DeleteIndexerMessageText": "Bent u zeker dat u de indexeerder '{0}' wilt verwijderen?", "DeleteDownloadClientMessageText": "Bent u zeker dat u de downloader '{0}' wilt verwijderen?", "DeleteBackupMessageText": "Bent u zeker dat u de veiligheidskopie '{0}' wilt verwijderen?", - "Cutoff": "Drempel", "CheckDownloadClientForDetails": "controleer downloader voor meer details", "CancelPendingTask": "Bent u zeker dat u deze taak in afwachting wilt annuleren?", "BranchUpdateMechanism": "Gebruikte branch door extern update mechanisme", "BranchUpdate": "Te gebruiken branch om Prowlarr bij te werken", "BeforeUpdate": "Voor de update", "AddingTag": "Tag toevoegen", - "VisitGithubCustomFormatsAphrodite": "Bezoek GitHub voor meer details: ", "UnableToLoadUISettings": "Kon gebruikersinterface instellingen niet inladen", - "UnableToLoadRootFolders": "Kon hoofdmappen niet inladen", "UnableToLoadNamingSettings": "Kon Naamgevingsinstellingen niet inladen", - "UnableToLoadMediaManagementSettings": "Kon Mediabeheer instellingen niet inladen", "UnableToLoadIndexerOptions": "Kon indexeerder opties niet inladen", "UnableToLoadGeneralSettings": "Kon Algemene instellingen niet inladen", - "UnableToAddANewRemotePathMappingPleaseTryAgain": "Kon geen nieuw externe pad verwijzing toevoegen, gelieve opnieuw te proberen.", "UnableToAddANewNotificationPleaseTryAgain": "Kon geen nieuwe notificatie toevoegen, gelieve opnieuw te proberen.", - "UnableToAddANewListExclusionPleaseTryAgain": "Kon geen nieuw item toevoegen aan de uitzonderingenlijst, gelieve opnieuw te proberen.", "UnableToAddANewIndexerPleaseTryAgain": "Kon geen nieuwe indexeerder toevoegen, gelieve opnieuw te proberen.", "UnableToAddANewDownloadClientPleaseTryAgain": "Kon geen nieuwe downloader toevoegen, gelieve opnieuw te proberen.", - "UnableToAddANewConditionPleaseTryAgain": "Kon geen nieuwe conditie toevoegen, gelieve opnieuw te proberen.", "RegularExpressionsCanBeTested": "Reguliere expressies kunnen worden getest ", - "ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "Prowlarr ondersteunt elke RSS filmlijst, tevens ook de ander hieronder weergegeven lijsten.", "ProwlarrSupportsAnyIndexer": "Prowlarr ondersteunt veel indexeerders naast elke indexeerder die de Newznab/Torznab-standaard gebruikt met 'Generic Newznab' (voor usenet) of 'Generic Torznab' (voor torrents). Zoek en selecteer uw indexeerder hieronder.", "ProwlarrSupportsAnyDownloadClient": "Prowlarr ondersteund elke downloader die gebruik maakt van de Newznab standaard, tevens ook de ander hieronder weergegeven downloaders.", "NoTagsHaveBeenAddedYet": "Er zijn nog geen tags toegevoegd", - "HaveNotAddedMovies": "U heeft nog geen films toegevoegd, wilt u eerst enkele of al uw films importeren?", "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Voor meer informatie over de individuele lijsten, klik op de info knoppen.", "ForMoreInformationOnTheIndividualDownloadClients": "Voor meer informatie over de individuele downloaders, klik op de info knoppen.", - "FileChmodHelpTexts1": "Octaal, wordt toegepast op mediabestanden bij het importeren/hernoemen door Prowlarr", "ExtraFileExtensionsHelpTexts1": "Komma gescheiden lijst met extra bestanden om te importeren (.nfo zal als .nfo-orig worden geïmporteerd)", "ApplyTagsHelpTexts4": "Vervangen: Vervang de tags met de ingevoerde tags (voer geen tags in om alle tags te wissen)", "ApplyTagsHelpTexts3": "Verwijderen: Verwijder de ingevoerde tags", @@ -494,30 +365,22 @@ "TagIsNotUsedAndCanBeDeleted": "Tag is niet in gebruik en kan verwijderd worden", "StartTypingOrSelectAPathBelow": "Begin met typen of selecteer een pad hier beneden", "Restore": "Herstellen", - "OnDeleteHelpText": "Bij Verwijderen", "NoUpdatesAreAvailable": "Geen updates beschikbaar", "NoLogFiles": "Geen logbestanden", "NoBackupsAreAvailable": "Geen veiligheidskopieën beschikbaar", - "MissingNotMonitored": "Ontbrekend, niet Bewaakt", "MinutesSixty": "60 Minuten: {0}", "MinutesNinety": "90 Minuten: {0}", "MinutesHundredTwenty": "120 Minuten: {0}", "MaintenanceRelease": "Onderhoudsuitgave", - "LoadingMovieExtraFilesFailed": "Laden van film extra bestanden is mislukt", "LinkHere": "hier", "FilterPlaceHolder": "Zoek indexeerder", - "Excluded": "Uitgezonderd", "Exception": "Uitzondering", "ErrorLoadingContents": "Fout bij laden van inhoud", - "DownloadedAndMonitored": "Gedownload en Bewaakt", "UILanguageHelpTextWarning": "Browser Herladen Vereist", "UILanguageHelpText": "Taal die Prowlarr zal gebruiken voor de gebruikersinterface", "UILanguage": "Gebruikersinterface Taal", - "MovieInfoLanguage": "Film Informatie Taal", "ExportCustomFormat": "Exporteer Eigen Formaat", - "DownloadPropersAndRepacksHelpText2": "Gebruik 'Geen Voorkeur' om te sorteren volgens voorkeur woord score boven PROPERS/REPACKS", "DownloadPropersAndRepacks": "PROPERS en REPACKS", - "CustomFormatUnknownCondition": "Onbekende Eigen Formaat conditie '{0}'", "CopyToClipboard": "Kopieer naar Klembord", "Priority": "Prioriteit", "InteractiveSearch": "Interactief Zoeken", @@ -528,9 +391,7 @@ "AutomaticSearch": "Automatisch Zoeken", "AddIndexer": "Voeg Indexeerder Toe", "FocusSearchBox": "Focus Zoekvak", - "EditRestriction": "Bewerk Restrictie", "CloseCurrentModal": "Sluit Huidig Bericht", - "Blacklisted": "Op de zwarte lijst", "AddMovie": "Voeg Film Toe", "AcceptConfirmationModal": "Accepteer Bevestigingsbericht", "Yesterday": "Gisteren", diff --git a/src/NzbDrone.Core/Localization/Core/pl.json b/src/NzbDrone.Core/Localization/Core/pl.json index 85d4dc82e..fb9dd37f8 100644 --- a/src/NzbDrone.Core/Localization/Core/pl.json +++ b/src/NzbDrone.Core/Localization/Core/pl.json @@ -1,15 +1,12 @@ { "Clear": "Wyczyść", - "Certification": "Certyfikacja", "Calendar": "Kalendarz", "BackupNow": "Zrób kopię zapasową teraz", "Backup": "Kopia zapasowa", "AppDataLocationHealthCheckMessage": "Aktualizacja nie będzie możliwa w celu uniknięcia usunięcia danych aplikacji", "Analytics": "Analityka", "All": "Wszystkie", - "AddNewTmdbIdMessage": "Możesz również użyć ID TMDB, np. tmdb:71663", "AddNew": "Dodaj nowe", - "AddExclusion": "Dodaj wyjątek", "Added": "Dodane", "Actions": "Aktywności", "About": "O" diff --git a/src/NzbDrone.Core/Localization/Core/pt.json b/src/NzbDrone.Core/Localization/Core/pt.json index 9f071f334..dee490dcb 100644 --- a/src/NzbDrone.Core/Localization/Core/pt.json +++ b/src/NzbDrone.Core/Localization/Core/pt.json @@ -1,21 +1,17 @@ { "Peers": "Elementos", "AppDataLocationHealthCheckMessage": "Não será possível atualizar para evitar a exclusão de AppData", - "Week": "Semana", "Warn": "Avisar", "View": "Ver", - "UpdateSelected": "Atualização Selecionada", "Updates": "Atualizações", "UpdateCheckUINotWritableMessage": "Não é possível instalar a atualização porque a pasta da IU \"{0}\" não tem permissões de escrita para o utilizador \"{1}\".", "UpdateCheckStartupNotWritableMessage": "Não é possível instalar a atualização porque a pasta de arranque \"{0}\" não tem permissões de escrita para o utilizador \"{1}\".", "UpdateCheckStartupTranslocationMessage": "Não é possível instalar a atualização porque a pasta de arranque \"{0}\" está em uma pasta de transposição de aplicações.", "UnselectAll": "Desmarcar todos", "UnsavedChanges": "Mudanças não guardadas", - "Unmonitored": "Não Monitorado", "UISettingsSummary": "Opções de calendário, data e modo de daltonismo", "UI": "IU", "Type": "Tipo", - "Titles": "Títulos", "Title": "Título", "Time": "Hora", "TestAll": "Testar todos", @@ -33,19 +29,15 @@ "Sort": "Ordenar", "Size": "Tamanho", "Shutdown": "Encerrar", - "ShowStudio": "Mostrar Estúdio", "ShowSearchHelpText": "Mostrar botão de pesquisa ao passar o cursor", "ShowSearch": "Mostrar pesquisa", - "ShowPath": "Mostrar Caminho", "ShowDateAdded": "Mostrar Data Adicionado", "ShowAdvanced": "Mostrar avançado", - "SettingsWeekColumnHeader": "Cabeçalho de Coluna Semanal", "SettingsUiLanguage": "Idioma da UI", "SettingsTimeFormat": "Formato de hora", "SettingsShowRelativeDatesHelpText": "Mostrar datas relativas (Hoje, Ontem, etc.) ou absolutas", "SettingsShowRelativeDates": "Mostrar datas relativas", "SettingsShortDateFormat": "Formato curto de data", - "SettingsRemotePathMappingRemotePath": "Caminho Remoto", "SettingsRemotePathMappingLocalPath": "Caminho Local", "SettingsLongDateFormat": "Formato longo de data", "SettingsEnableColorImpairedMode": "Ativar modo de daltonismo", @@ -55,31 +47,22 @@ "SelectAll": "Selecionar todos", "Seeders": "Semeadores", "Security": "Segurança", - "SearchOnAdd": "Buscar ao Adicionar", "SearchForMissing": "Buscar Ausentes", - "SearchAll": "Buscar Todos", "Search": "Pesquisar", "Scheduled": "Agendado", "SaveChanges": "Guardar mudanças", "Save": "Guardar", - "RSSSync": "Sincronia RSS", "RootFolderCheckSingleMessage": "Pasta raiz não encontrada: {0}", - "RootFolder": "Pasta Raiz", "Restrictions": "Restrições", "RestoreBackup": "Restaurar cópia de segurança", "Restart": "Reiniciar", - "Renamed": "Renomeado", "RemoveRootFolder": "Remover pasta raiz", - "RemovedMovieCheckMultipleMessage": "Os filmes {0} foram removidos do TMDb", "Reload": "Recarregar", "ReleaseStatus": "Estado da versão", "ReleaseBranchCheckPreviousVersionMessage": "A ramificação {0} é para versões anteriores do Prowlarr, utilize a ramificação \"Nightly\" para futuras atualizações", "ReleaseBranchCheckOfficialBranchMessage": "A ramificação {0} não é uma ramificação de versões válida do Prowlarr, você não receberá atualizações", - "RejectionCount": "Contagem de Rejeição", "Refresh": "Atualizar", - "Ratings": "Avaliações", "Queue": "Fila", - "QualityProfiles": "Perfis de Qualidades", "QualityDefinitions": "Definições de qualidade", "PtpOldSettingsCheckMessage": "As definições dos seguintes indexadores do PassThePopcorn são obsoletas e precisam ser atualizadas: {0}", "ProxyCheckResolveIpMessage": "Não é possível resolver o Endereço IP para o Anfitrião de proxy {0} definido", @@ -87,44 +70,32 @@ "ProxyCheckBadRequestMessage": "Falha ao testar o proxy. Código de estado: {0}", "Proxy": "Proxy", "Protocol": "Protocolo", - "ProfilesSettingsSummary": "Qualidade, Idioma e Perfis de Espera", "PreviewRename": "Pré-visualizar Renomear", - "Posters": "Posters", "PhysicalRelease": "Versão Física", "PendingChangesStayReview": "Ficar e rever mudanças", "PendingChangesMessage": "Há mudanças não guardadas, tem a certeza que quer sair dessa página?", "PendingChangesDiscardChanges": "Descartar mudanças e sair", "PageSize": "Tamanho da página", - "Overview": "Resumo", "OrganizeModalSuccess": "Sucesso! Meu trabalho está feito, sem arquivos para renomear.", - "OrganizeModalDisabled": "O renomeamento esta desativado, nada para renomear", "OrganizeAndRename": "Organizar & Renomear", "Options": "Opções", "Ok": "Ok", "OAuthPopupMessage": "Os pop-ups estão sendo bloqueados por seu browser", "NoChanges": "Sem mudanças", "NoChange": "Sem mudança", - "NetImportStatusCheckAllClientMessage": "Todas listas estão indisponíveis devido a falhas", "Name": "Nome", "Movies": "Filmes", - "MovieIndex": "Índice de Filmes", "Movie": "Filme", - "MountCheckMessage": "O ponto de montagem que leva a um filme esta montado como apenas leitura: ", "MoreInfo": "Mais informações", "MonoVersionCheckUpgradeRecommendedMessage": "A versão Mono {0} atualmente instalada é suportada, mas recomenda-se atualizar para {1}.", - "MonoVersionCheckNotSupportedMessage": "Instalado atualmente o Mono versão {0} o qual não é mais suportado. Por favor atualize para o Mono versão {1}.", "MonoTlsCheckMessage": "Uma solução para o Prowlarr Mono 4.x tls ainda está ativa, considere remover a opção de ambiente MONO_TLS_PROVIDER=legacy", "MonoNotNetCoreCheckMessage": "Atualiza para a versão .NET Core do Prowlarr", - "MonitoredOnly": "Apenas Monitorado", "Monitor": "Monitorar", - "MinimumAvailability": "Disponibilidade Mínima", "MetadataSettingsSummary": "Criar arquivos de metadados quando os filmes são importados ou atualizados", "Message": "Mensagem", - "MediaManagement": "Gerenciamento de Mídia", "MassMovieSearch": "Pesquisa de Filmes em Massa", "Logging": "Registo em log", "LogFiles": "Ficheiros de log", - "ListsSettingsSummary": "Listas de Importações, listas de exclusões", "ListExclusions": "Lista de Exclusões", "Level": "Nível", "LastWriteTime": "Hora da última escrita", @@ -134,31 +105,23 @@ "Info": "Informações", "IndexerStatusCheckSingleClientMessage": "Indexadores indisponíveis devido a falhas: {0}", "IndexerStatusCheckAllClientMessage": "Todos os indexadores estão indisponíveis devido a falhas", - "IndexerSearchCheckNoInteractiveMessage": "Sem indexadores disponíveis com Pesquisa Interativa ativada, o Prowlarr não proverá nenhum resultado de pesquisa interativa", "IndexerSearchCheckNoAvailableIndexersMessage": "Todos indexadores capazes de pesquisar estão indisponíveis devido a recente erros de indexadores", "Indexers": "Indexadores", - "IndexerRssHealthCheckNoAvailableIndexers": "Todos indexadores com rss estão temporariamente indisponíveis devido a erros recentes de indexadores", "Indexer": "Indexador", - "ImportTipsMessage": "Algumas dicas para garantir que a importação funcione perfeitamente:", "ImportMechanismHealthCheckMessage": "Ativar Manipulação de Download Completado", - "ImportFirstTip": "Garanta que seus arquivos incluam a qualidade no nome. ex.", "Imported": "Importado", - "Ignored": "Ignorado", "Host": "Anfitrião", "History": "Histórico", "HideAdvanced": "Ocultar avançado", "HealthNoIssues": "Não há problemas com suas definições", "Health": "Estado de funcionamento", - "GrabSelected": "Capturar Selecionado", "Grabbed": "Capturado", "GeneralSettingsSummary": "Porta, SSL, utilizador/palavra-passe, proxy, análises e atualizações", "General": "Geral", - "Formats": "Formatos", "Folder": "Pasta", "Filter": "Filtrar", "Files": "Ficheiros", "Filename": "Nome do ficheiro", - "FailedDownloadHandling": "Manuseio de Download Falhado", "Failed": "Falhado", "ExistingMovies": "Filme(s) existente(s)", "EventType": "Tipo de evento", @@ -172,15 +135,11 @@ "DownloadClientCheckUnableToCommunicateMessage": "Não é possível ligar-se a {0}.", "DownloadClientCheckNoneAvailableMessage": "Nenhum cliente de transferências disponível", "DownloadClient": "Cliente de transferências", - "DotNetVersionCheckNotRecommendedMessage": "O Framework .Net {0} instalado atualmente é suportado, mas nós recomendamos atualizar para ao menos {1}.", "Discover": "Descobrir", "Details": "Detalhes", - "DetailedProgressBar": "Barra de Progresso Detalhada", "Delete": "Eliminar", - "Day": "Dia", "Dates": "Datas", "Date": "Data", - "CustomFormatsSettingsSummary": "Formatos Customizados e Configurações", "CustomFormats": "Formatos Customizados", "CustomFilters": "Filtros personalizados", "ConnectSettingsSummary": "Notificações, ligações para servidores/leitores de multimédia e scripts personalizados", @@ -193,96 +152,66 @@ "Columns": "Colunas", "Close": "Fechar", "Clear": "Limpar", - "Certification": "Certificação", "Cancel": "Cancelar", - "Blacklist": "Lista Negra", "BackupNow": "Criar cópia de segurança", "Backup": "Cópia de segurança", "Apply": "Aplicar", "Analytics": "Análises", - "AllMoviesHiddenDueToFilter": "Todos os filmes estão ocultos devido ao filtro aplicado.", "All": "Todos", "Age": "Tempo de vida", - "AddNewTmdbIdMessage": "Você também pode procurar usando o ID de um filme no TMDb. P. ex. tmdb:71663", "AddNewMessage": "É facil adicionar um novo filme, apenas comece a escrever o nome do filme que quer adicionar", - "AddMovies": "Adicionar Filmes", "AddExclusion": "Adicionar Exclusão", "Added": "Adicionado", "Actions": "Ações", "About": "Informações", - "AutoUnmonitorPreviouslyDownloadedMoviesHelpText": "Filmes deletados no disco deixam automaticamente de ser monitorados no Prowlarr", "Automatic": "Automático", "AuthenticationMethodHelpText": "Solicitar nome de utilizador e palavra-passe para acessar ao Prowlarr", "Authentication": "Autenticação", "AreYouSureYouWantToResetYourAPIKey": "Tem a certeza que quer repor a Chave da API?", - "AreYouSureYouWantToDeleteThisImportListExclusion": "Tem certeza que quer deletar esta exclusão de lista de importação?", "ApplyTags": "Aplicar etiquetas", "AppDataDirectory": "Pasta AppData", "ApiKey": "Chave da API", "AnalyticsEnabledHelpText": "Envia informações anônimas de uso e de erros aos servidores do Prowlarr. Isso inclui informações sobre seu browser, páginas utilizadas na WebUI do Prowlarr, relatórios de erros, bem como as versões do sistema operativo e da aplicação. Utilizaremos essas informações para priorizar funcionalidades e correções de bugs.", - "AlreadyInYourLibrary": "Já está em sua biblioteca", "AllowHardcodedSubs": "Permitir Legendas Embutidas", - "AddMoviesMonitored": "Adicionar Filmes Monitorados", "QualitySettings": "Definições de qualidade", - "PublishedDate": "Data de Publicação", "ProxyType": "Tipo de proxy", - "PreferIndexerFlagsHelpText": "Priorizar versões com marcas especiais", "PortNumber": "Número da porta", "Port": "Porta", "Password": "Palavra-passe", "PageSizeHelpText": "Número de itens por página", "PackageVersion": "Versão do pacote", "OpenBrowserOnStart": "Abrir browser ao iniciar", - "OnRenameHelpText": "Ao Renomear", "OnHealthIssueHelpText": "Ao ter problemas no estado de funcionamento", - "OnDownloadHelpText": "Notificar quando os filmes forem importados com sucesso", "NotificationTriggers": "Acionadores de notificação", "NoMinimumForAnyRuntime": "Sem mínimo para tempo de execução", "NoLimitForAnyRuntime": "Sem limite de tempo de execução", "NoLeaveIt": "Não, deixe-o", "New": "Novo", "NetCore": ".NET", - "MustNotContain": "Não Deve Conter", "MovieYearHelpText": "Ano do filme a excluir", - "MovieTitleHelpText": "Título do filme para excluir (pode ser qualquer palavra)", "MovieInfoLanguageHelpTextWarning": "Será necessário reiniciar o navegador", - "MovieFolderFormat": "Formato da Pasta de Filme", "MovieAvailableButMissing": "Filme Disponível, mas Ausente", "MonoVersion": "Versão do Mono", "Mode": "Modo", "MinimumLimits": "Limites mínimos", - "MinimumFreeSpace": "Espaço Livre Mínimo", "MinimumAge": "Tempo de Vida Mínimo", - "MetadataSettings": "Ajustes de Metadados", "MediaInfo": "Informação Multimídia", "Mechanism": "Mecanismo", - "MaximumSize": "Tamanho Máximo", "MaximumLimits": "Limites máximos", "Logs": "Logs", "LogLevel": "Nível de log", - "ListUpdateInterval": "Intervalo de Atualização das Listas", "Links": "Links", "Interval": "Intervalo", "IndexerFlags": "Sinalizadores do indexador", - "IncludeUnknownMovieItemsHelpText": "Mostrar items sem um filme na fila, isso pode incluir filmes removidos, filmes ou qualquer outra coisa na categoria Prowlarr", "IncludeHealthWarningsHelpText": "Incluir avisos de estado de funcionamento", - "IncludeCustomFormatWhenRenaming": "Incluir Formato Personalizado ao Renomear", "Importing": "Importando", - "ImportExtraFiles": "Importar Arquivos Extras", "IllRestartLater": "Reiniciarei mais tarde", - "IgnoreDeletedMovies": "Ignorar Filmes Deletados", "IgnoredAddresses": "Endereços ignorados", - "ICalHttpUrlHelpText": "Copie este endereço para sua aplicação ou clique para registrar-se caso seu navegador suporte webcal", "Hostname": "Nome do anfitrião", - "Group": "Grupo", "GrabID": "Capturar ID", - "Global": "Global", "GeneralSettings": "Definições gerais", - "Folders": "Pastas", "Fixed": "Corrigido", - "FileNames": "Nomes de Arquivos", "FileChmodMode": "Modo CHMOD de arquivo", - "Ended": "Finalizado", "EnableSslHelpText": " Requer reinício da aplicação como administrador para aplicar alterações", "EnableSSL": "Ativar SSL", "EnableMediaInfoHelpText": "Extraia informações de vídeo como resolução, tempo de execução e informações de codec dos ficheiros. Isso requer que o Prowlarr leia partes do ficheiro, o que pode causar alta atividade do disco ou da rede durante as análises.", @@ -296,49 +225,35 @@ "EnableAutomaticAdd": "Ativar adição automática", "EnableAutoHelpText": "Se ativado, os filmes desta lista serão automaticamente adicionados ao Prowlarr", "Enable": "Ativar", - "EditMovie": "Editar Filme", "DownloadWarningCheckDownloadClientForMoreDetails": "Alerta de download: verifique mais detalhes no gerenciador de downloads", - "DownloadFailedCheckDownloadClientForMoreDetails": "Falha no download: verifique mais detalhes no gerenciador de downloads", "DownloadClientSettings": "Definições do cliente de transferências", "Docker": "Docker", - "DestinationPath": "Caminho de Destino", "DeleteTag": "Eliminar etiqueta", - "DeleteRestriction": "Deletar Restrição", "DeleteNotification": "Eliminar notificação", "DeleteIndexer": "Eliminar indexador", - "DeleteFile": "Apagar arquivo", "DeleteEmptyFolders": "Deletar pastas vazias", "DeleteDownloadClient": "Eliminar cliente de transferências", - "DeleteCustomFormat": "Deletar Formato Personalizado", "DeleteBackup": "Eliminar cópia de segurança", "DelayProfile": "Perfil de atraso", "DBMigration": "Migração da base de dados", - "CutoffFormatScoreHelpText": "Quando esta pontuação do formato personalizado for alcançada, o Prowlarr não irá mais baixar filmes", "CreateGroup": "Criar grupo", - "CreateEmptyMovieFolders": "Criar pastas vazias para filmes", "CopyUsingHardlinksHelpText": "Usar Hardlinks ao tentar copiar arquivos a partir de torrents que ainda estão em modo seed", "ConnectSettings": "Definições de ligação", - "ColonReplacementFormatHelpText": "Mude a forma como o Prowlarr lida com a substituição de dois-pontos", "CloneProfile": "Clonar perfil", "CloneIndexer": "Clonar indexador", - "ClickToChangeQuality": "Clique para mudar a qualidade", "CleanLibraryLevel": "Limpar Nível da Biblioteca", "ChangeHasNotBeenSavedYet": "A mudança ainda não foi guardada", - "CertificationCountryHelpText": "Selecionar País para Certificação de Filmes", "CertificateValidationHelpText": "Mudar nível de restrição da validação da certificação HTTPS", "CertificateValidation": "Validação de certificado", "BypassProxyForLocalAddresses": "Ignorar proxy para endereços locais", "Branch": "Ramificação", - "BlacklistHelpText": "Evite que o Prowlarr tente automaticamente capturar esta versão do filme novamente", "BindAddressHelpText": "Endereço IP4 válido ou \"*\" para todas as interfaces", "BindAddress": "Endereço de vínculo", "Backups": "Cópias de segurança", "BackupFolderHelpText": "Caminhos relativos estarão na pasta AppData do Prowlarr", "BackupIntervalHelpText": "Intervalo entre cópias de segurança automáticas", "BackupRetentionHelpText": "Cópias de segurança automáticas anteriores ao período de retenção serão eliminadas automaticamente", - "CustomFormatJSON": "JSON Personalizado", "ClientPriority": "Prioridade do cliente", - "CheckDownloadClientForDetails": "verifique o gerenciador de downloads para mais detalhes", "CancelPendingTask": "Tem a certeza que quer cancelar esta tarefa pendente?", "BranchUpdateMechanism": "Ramificação utilizada pelo mecanismo externo de atualização", "BranchUpdate": "Ramificação utilizada para atualizar o Prowlarr", @@ -348,16 +263,12 @@ "ApplyTagsHelpTexts2": "Adicionar: agregar as etiquetas à lista existente de etiquetas", "ApplyTagsHelpTexts1": "Como aplicar etiquetas aos indexadores selecionados", "AddingTag": "A adicionar etiqueta", - "DelayingDownloadUntilInterp": "Suspendendo download até {0} às {1}", "VisitGithubCustomFormatsAphrodite": "Acesse o Github para mais detalhes: ", - "UnableToAddANewCustomFormatPleaseTryAgain": "Não foi possível adicionar um novo formato personalizado, tente novamente.", "NegateHelpText": "Se marcado, o formato personalizado não se aplicará se esta condição {0} for atendida.", - "ExportCustomFormat": "Exportar Formato Personalizado", "CustomFormatUnknownCondition": "Condição de Formato Personalizado '{0}' desconhecida", "AutomaticSearch": "Pesquisa automática", "UnableToLoadIndexers": "Não foi possível carregar os indexadores", "UnableToAddANewIndexerPleaseTryAgain": "Não foi possível adicionar um novo indexador, tenta novamente.", - "RSSSyncIntervalHelpTextWarning": "Isto se aplicará a todos os indexadores, siga as regras estabelecidas por eles", "RSSIsNotSupportedWithThisIndexer": "RSS não é suportado por esse indexador", "ProwlarrSupportsAnyIndexer": "O Prowlarr suporta qualquer indexador que usa o padrão Newznab, bem como os outros indexadores listados abaixo.", "IndexerPriorityHelpText": "Prioridade do indexador de 1 (mais alta) a 50 (mais baixa). Padrão: 25.", @@ -366,7 +277,6 @@ "EditIndexer": "Editar indexador", "DeleteIndexerMessageText": "Tem a certeza que quer eliminar o indexador \"{0}\"?", "AddIndexer": "Adicionar indexador", - "ShowCutoffUnmetIconHelpText": "Mostrar ícone para arquivos quando o ponto de corte não tiver sido alcançado", "SetPermissions": "Definir Permissões", "ScriptPath": "Caminho do script", "Retention": "Retenção", @@ -376,74 +286,52 @@ "RestartNow": "Reiniciar agora", "ResetAPIKey": "Repor chave da API", "Reset": "Repor", - "ReplaceIllegalCharacters": "Substituir Caracteres Ilegais", "RenameMovies": "Renomear Filmes", "RemovingTag": "Eliminando etiqueta", - "RemoveFromDownloadClient": "Remover do Gerenciador de Downloads", "RemoveFilter": "Remover filtro", "RefreshMovie": "Atualizar filme", - "Redownload": "Baixar novamente", "RecyclingBin": "Lixeira", - "Real": "Real", "ReadTheWikiForMoreInformation": "Leia a Wiki para obter mais informações", - "Prowlarr": "Prowlarr", "Priority": "Prioridade", "Pending": "Pendente", - "OnDeleteHelpText": "Ao Apagar", "NoUpdatesAreAvailable": "Não há atualizações disponíveis", "NoTagsHaveBeenAddedYet": "Você ainda não adicionou etiquetas", "NoLogFiles": "Sem ficheiros de log", "NoBackupsAreAvailable": "Não há cópias de segurança disponíveis", - "MovieIsUnmonitored": "O filme não é monitorado", "MinutesSixty": "60 minutos: {0}", "MinutesNinety": "90 minutos: {0}", "MinutesHundredTwenty": "120 minutos: {0}", "MIA": "Desaparecidos", - "MarkAsFailed": "Marcar como falhado", "Manual": "Manual", - "LoadingMovieExtraFilesFailed": "Falha no carregamento dos arquivos extras do filme", "LinkHere": "aqui", "InteractiveSearch": "Pesquisa interativa", - "ImportListSyncIntervalHelpText": "Frequência com que o Prowlarr sincroniza suas listas.", "ImportListStatusCheckAllClientMessage": "Todas as listas estão indisponíveis devido a erros", - "ImportFailed": "Falha na importação: {0}", "HiddenClickToShow": "Oculto, clique para mostrar", - "GrabReleaseMessageText": "O Prowlarr não foi capaz de determinar a que filme pertence esta versão. O Prowlarr pode ser incapaz de automaticamente importar esta versão. Deseja capturar '{0}'?", "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Para mais informações sobre cada lista de importação, clique nos botões de informação.", "ForMoreInformationOnTheIndividualDownloadClients": "Para obter mais informações sobre cada cliente de transferências, clique nos botões de informação.", "FilterPlaceHolder": "Indexadores de pesquisa", - "FileChmodHelpTexts1": "Octal, aplicado aos arquivos multimídia ao serem importados/renomeados pelo Prowlarr", "ExtraFileExtensionsHelpTexts2": "Exemplos: '.sub, .nfo' ou 'sub,nfo'", "ExistingTag": "Etiqueta existente", - "MovieExcludedFromAutomaticAdd": "Filme Ignorado da Inclusão Automática", "ExcludeMovie": "Ignorar Filme", "Exception": "Exceção", "ErrorLoadingContents": "Erro ao carregar conteúdo", "EnableInteractiveSearchHelpText": "Será utilizado ao realizar uma pesquisa interativa", "EnableAutomaticSearchHelpTextWarning": "Será utilizado ao realizar uma pesquisa interativa", "EnableAutomaticSearchHelpText": "Será utilizado ao realizar pesquisas automáticas através da IU ou pelo Prowlarr", - "DownloadPropersAndRepacksHelpTextWarning": "Use palavras preferidas para atualizações automáticas a propers/repacks", "PreferredSize": "Tamanho preferido", - "DownloadPropersAndRepacksHelpText1": "Atualizar automaticamente ou não para Propers/Repacks", "Downloading": "Transferindo", - "DownloadFailed": "Falha no download", "DownloadedAndMonitored": "Baixado e Monitorado", "DownloadClientUnavailable": "O cliente de transferências está indisponível", "Disabled": "Desativado", "DeleteTagMessageText": "Tem a certeza que quer eliminar a etiqueta \"{0}\"?", - "DeleteRestrictionHelpText": "Tem certeza que quer deletar esta restrição?", "DeleteNotificationMessageText": "Tem a certeza que quer eliminar a notificação \"{0}\"?", "DeleteDownloadClientMessageText": "Tem a certeza que quer eliminar o cliente de transferências \"{0}\"?", "DeleteBackupMessageText": "Tem a certeza que quer eliminar a cópia de segurança \"{0}\"?", - "IncludeRecommendationsHelpText": "Incluir filmes recomendados pelo Prowlarr na visão de descobrimento", "WhitelistedSubtitleTags": "Tags de Legendas Permitidas", - "WeekColumnHeader": "Cabeçalho da Coluna de Semanas", "UrlBaseHelpText": "Para suporte a proxy inverso, vazio por padrão", - "UpgradeAllowedHelpText": "Se desabilitado, as qualidades não serão atualizadas", "UpdateScriptPathHelpText": "Caminho para um script personalizado que toma um pacote de atualização extraído e lida com o restante do processo da atualização", "UpdateMechanismHelpText": "Utilizar o atualizador do Prowlarr ou um script", "UpdateAutomaticallyHelpText": "Transferir e instalar automaticamente as atualizações. Ainda é possível instalar a partir de Sistema: Atualizações", - "TMDBId": "ID TMDb", "ThisConditionMatchesUsingRegularExpressions": "Esta condição utiliza expressões regulares. Note que os caracteres {0} têm significados especiais e precisam de escape com um {1}", "TestAllClients": "Testar todos os clientes", "TagsHelpText": "Aplica-se a indexadores com pelo menos uma etiqueta correspondente", @@ -453,41 +341,26 @@ "SSLCertPath": "Caminho do certificado SSL", "SSLCertPasswordHelpText": "Palavra-passe do ficheiro PFX", "SSLCertPassword": "Palavra-passe do certificado SSL", - "SourcePath": "Caminho de Origem", "SkipFreeSpaceCheckWhenImportingHelpText": "Usar quando o Prowlarr não puder determinar o espaço livre em sua pasta raiz de filmes", - "ShowYear": "Mostrar Ano", "ShowTitleHelpText": "Mostrar título do filme abaixo do poster", - "ShowQualityProfileHelpText": "Mostrar qualidade do filme abaixo do poster", "ShownClickToHide": "Visível, clique para ocultar", - "ShowMovieInformation": "Mostrar Informações do Filme", "ShowGenres": "Mostrar Categorias", - "ShowAsAllDayEvents": "Mostar como Eventos de Dia Inteiro", "SettingsRuntimeFormat": "Formato de Tempo de Execução", - "SetPermissionsLinuxHelpText": "Deve-se executar CHMOD ao importar/renomear arquivos?", "SendAnonymousUsageData": "Enviar dados anônimos de uso", - "RSSSyncInterval": "Intervalo de Sincronização de RSS", "RetentionHelpText": "Somente Usenet: ajustar para zero para retenção ilimitada", "RestartRequiredHelpTextWarning": "Requer reinício para aplicar alterações", - "RescanAfterRefreshHelpTextWarning": "O Prowlarr não irá automaticamente detectar mudanças nos arquivos quando a opção selecionada não for \"Sempre\"", "ReplaceIllegalCharactersHelpText": "Substituir caracteres ilegais. Se desmarcado, o Prowlarr irá removê-los", - "RemoveHelpTextWarning": "Remover irá apagar o download e o(s) arquivo(s) do gerenciador de downloads.", "RemoveCompletedDownloadsHelpText": "Remover downloads importados do histórico do gerenciador de downloads", - "ProwlarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "O Radar suporta condições personalizadas em relação às propriedades das versões abaixo.", "ProwlarrSupportsAnyDownloadClient": "O Prowlarr suporta qualquer dos clientes de transferências listados abaixo.", "ProxyUsernameHelpText": "Apenas insira o utilizador e a palavra-passe caso seja requerido. Caso contrário, deixe em branco.", "ProxyPasswordHelpText": "Apenas insira o utilizador e a palavra-passe caso seja requerido. Caso contrário, deixe em branco.", "ProxyBypassFilterHelpText": "Utilizar \",\" como separador e \"*.\" como caráter universal para subdomínios", - "MovieInfoLanguage": "Idioma das Informações dos Filmes", "MaintenanceRelease": "Versão de manutenção", - "UsenetDelay": "Espera para Usenet", "TorrentDelayHelpText": "Espera em minutos para aguardar antes de capturar um torrent", "PriorityHelpText": "Priorizar múltiplos clientes de transferências. Utilizaremos round robin para clientes com a mesma prioridade.", "RemovedFromTaskQueue": "Eliminado da fila de tarefas", - "RegularExpressionsCanBeTested": "Expressões regulares podem ser testadas ", "RecycleBinCleanupDaysHelpTextWarning": "Arquivos na lixeira serão excluídos automaticamente após o número de dias selecionado", - "MovieIsMonitored": "Filme é monitorado", "MovieInfoLanguageHelpText": "Idioma usado pelo Prowlarr na UI para as Informações dos Filmes", - "MissingNotMonitored": "Ausente, não Monitorado", "LogLevelTraceHelpTextWarning": "O registo de rasteio somente deve ser ativado temporariamente", "LaunchBrowserHelpText": " Abrir o browser e a home page do Prowlarr ao iniciar a aplicação.", "TagCannotBeDeletedWhileInUse": "Não é possível eliminar enquanto estiver em uso", @@ -495,33 +368,25 @@ "StartupDirectory": "Diretório de arranque", "SSLPort": "Porta SSL", "YesCancel": "Sim, cancelar", - "WaitingToImport": "Aguardando para Importar", "Version": "Versão", "Username": "Nome de utilizador", "UseProxy": "Usar proxy", "Usenet": "Usenet", "URLBase": "URL base", "Uptime": "Tempo de atividade", - "Ungroup": "Desagrupar", "UnableToLoadUISettings": "Não foi possível carregar as definições da IU", "UnableToLoadTags": "Não foi possível carregar as etiquetas", - "UnableToLoadRestrictions": "Não foi possível carregar as Restrições", "UnableToLoadQualityProfiles": "Não foi possível carregar os Perfis de Qualidade", "UnableToLoadQualityDefinitions": "Não foi possível carregar as definições de qualidade", "UnableToLoadNotifications": "Não foi possível carregar as notificações", - "UnableToLoadMovies": "Não foi possível carregar os filmes", "UnableToLoadMediaManagementSettings": "Não foi possível carregar os ajustes de Gerenciamento Multimídia", - "UnableToLoadListOptions": "Não foi possível carregar as opções de lista", "UnableToLoadLanguages": "Não foi possível carregar os idiomas", "UnableToLoadHistory": "Não foi possível carregar o histórico", "UnableToLoadGeneralSettings": "Não foi possível carregar as definições gerais", "UnableToLoadDownloadClients": "Não foi possível carregar os clientes de transferências", - "UnableToLoadBlacklist": "Não foi possível carregar a blacklist", "UnableToAddANewDownloadClientPleaseTryAgain": "Não foi possível adicionar um novo cliente de transferências, tenta novamente.", "UnableToLoadBackups": "Não foi possível carregar as cópias de segurança", - "UnableToAddANewQualityProfilePleaseTryAgain": "Não foi possível adicionar um novo perfil de qualidade, tente novamente.", "UnableToAddANewNotificationPleaseTryAgain": "Não foi possível adicionar uma nova notificação, tenta novamente.", - "UnableToAddANewListPleaseTryAgain": "Não foi possível adicionar uma nova lista, tente novamente.", "UISettings": "Definições da IU", "UILanguageHelpTextWarning": "É preciso reiniciar o browser", "UILanguageHelpText": "Idioma que o Prowlarr usará para a IU", @@ -536,18 +401,12 @@ "MovieIndexScrollBottom": "Índice do filme: deslocar para baixo", "MovieDetailsPreviousMovie": "Detalhes do filme: filme anterior", "MovieDetailsNextMovie": "Detalhes do filme: próximo filme", - "StartSearchForMissingMovie": "Iniciar busca por filme", "StartImport": "Iniciar Importação", - "RequiredRestrictionPlaceHolder": "A versão deve conter pelo menos um destes termos (maiúsculas ou minúsculas)", "ProcessingFolders": "Processando Pastas", - "ImportRootPath": "Indique para o Prowlarr a pasta que contém todos os seus filmes, não um filme específico. p.ex. {0} e não {1}", "ImportErrors": "Importar Erros", - "EditRestriction": "Editar Restrição", "CancelProcessing": "Cancelar Processamento", - "AddMovie": "Adicionar Filme", "SettingsConsoleLogLevel": "Nível de registo do console", "SearchIndexers": "Pesquisar indexadores", - "NewznabVipCheckExpiredClientMessage": "Os benefícios VIP do indexador expiraram: {0}", "IndexersSelectedInterp": "{0} indexador(es) selecionado(s)", "IndexerRss": "RSS do indexador", "IndexerQuery": "Consulta do indexador", diff --git a/src/NzbDrone.Core/Localization/Core/ro.json b/src/NzbDrone.Core/Localization/Core/ro.json index 0632da932..ab074ffbf 100644 --- a/src/NzbDrone.Core/Localization/Core/ro.json +++ b/src/NzbDrone.Core/Localization/Core/ro.json @@ -4,44 +4,32 @@ "DownloadClientCheckUnableToCommunicateMessage": "Nu pot comunica cu {0}.", "DownloadClientCheckNoneAvailableMessage": "Niciun client de descărcare disponibil", "DownloadClient": "Client de descărcare", - "DotNetVersionCheckNotRecommendedMessage": "Versiunea {0} de .Net Framework instalată este acceptată, dar recomandăm instalarea cel puțin a versiunii {1}.", "Discover": "Descoperă", "Details": "Detalii", "Delete": "Șterge", - "Day": "Zi", "Dates": "Date", "Date": "Dată", - "CustomFormats": "Formate personalizate", "CustomFilters": "Filtre personalizate", "ConnectSettingsSummary": "Notificări, conexiuni la servere și aplicații media, scripturi personale", "Connections": "Conexiuni", "Connect": "Conectează", - "Collection": "Colecție", "Clear": "Șterge", - "Certification": "Certificare", "Calendar": "Calendar", "BackupNow": "Fă o copie de siguranță", "Backup": "Copie de siguranță", "AppDataLocationHealthCheckMessage": "Pentru a preveni ștergerea AppData, update-ul nu este posibil", "Analytics": "Statistici", "All": "Toate", - "AddNewTmdbIdMessage": "Poți căuta și folosind id-ul TMDB al unui film. Ex. tmdb:71663", "AddNew": "Adaugă", - "AddExclusion": "Adaugă Excluziune", "Added": "Adăugat", "Actions": "Acțiuni", "About": "Despre", "IndexerStatusCheckAllClientMessage": "Niciun indexator nu este disponibil datorită eșuărilor", - "IndexerSearchCheckNoInteractiveMessage": "Niciun indexator cu Căutare interactivă nu este activ, Prowlarr nu va afișa niciun rezultat de căutare interactivă", "IndexerSearchCheckNoAutomaticMessage": "Niciun indexator cu Căutare automată nu este activ, Prowlarr nu va afișa niciun rezultat de căutare automată", "Indexers": "Indexatori", - "IndexerRssHealthCheckNoAvailableIndexers": "Toți indexatorii ce suportă rss sunt indisponibili temporar datorită erorilor", "Indexer": "Indexator", - "ImportTipsMessage": "Câteva sfaturi pentru a ne asigura că importul este cu succes:", "ImportMechanismHealthCheckMessage": "Activează Procesarea Descărcărilor finalizate", - "ImportFirstTip": "Asigură-te că fișierele au calitatea în nume. Ex.", "Import": "Importă", - "iCalLink": "Legătură iCal", "Host": "Gazdă", "History": "Istorie", "HideAdvanced": "Ascunde Avansat", @@ -49,49 +37,37 @@ "Grabbed": "Prins", "GeneralSettingsSummary": "Port, SSL, utilizator/parolă, proxy, statistici și actualizări", "General": "General", - "Formats": "Formate", "Folder": "Dosar", "Filter": "Filtru", "Files": "Fișiere", "Filename": "Numele Fișierului", - "FailedDownloadHandling": "Procesarea descărcării a eșuat", "Failed": "Eșuat", "EventType": "Tip de eveniment", "Events": "Evenimente", "Edit": "Editează", "DownloadClientStatusCheckSingleClientMessage": "Clienții de descărcare sunt indisponibili datorită erorii: {0}", "DownloadClientStatusCheckAllClientMessage": "Toți clienții de descărcare sunt indisponibili datorită erorilor", - "Profiles": "Profile", "PhysicalRelease": "Lansare fizică", "Peers": "Parteneri", "PageSize": "Mărimea Paginii", - "OrganizeModalSuccess": "Succes! Mi-am terminat treaba, niciun fișier de redenumit.", "OrganizeModalDisabled": "Redenumirea este dezactivată, nimic de redenumit", - "OrganizeAndRename": "Organizează și Redenumește", "Options": "Opțiuni", "Ok": "Ok", "OAuthPopupMessage": "Browser-ul tău blochează pop-upurile", "NoChanges": "Nicio Modificare", "NoChange": "Nicio Modificare", - "ImportListStatusCheckAllClientMessage": "Toate listele sunt indisponibile datorită erorilor", "Name": "Nume", "Movies": "Filme", - "MovieIndex": "Index Filme", "Movie": "Film", - "MountCheckMessage": "Calea ce conține filme este montată în mod de read-only: ", "MoreInfo": "Mai multă informație", "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls este încă activ, ia în calcul să configurezi MONO_TLS_PROVIDER=legacy în opțiunile de mediu", "MonoNotNetCoreCheckMessage": "Actualizează versiunea de .NET Core a Prowlarr", - "Monitored": "Monitorizat", "Missing": "Lipsește", - "MinAvailability": "Disponibilitate minimă", "Metadata": "Metadata", "Message": "Mesaj", - "MediaManagement": "Administrare media", "MassMovieSearch": "Caută filme în masa", "Logging": "Logare", "LogFiles": "Fișiere de loguri", - "ListsSettingsSummary": "Importă Liste, excluderi din listă", "ListExclusions": "Excluderi din listă", "Level": "Nivel", "LastWriteTime": "Data ultimei scrieri", @@ -101,7 +77,6 @@ "Info": "Info", "IndexerStatusCheckSingleClientMessage": "Indexator indisponibil datorită erorilor: {0}", "HealthNoIssues": "Nicio problemă în configurare", - "Extension": "Extensie", "Error": "Eroare", "ConnectionLostMessage": "Prowlarr a pierdut conexiunea cu backend-ul și trebuie reîncărcat pentru a restabili funcționalitatea.", "ConnectionLostAutomaticMessage": "Prowlarr va încerca să se reconecteze automat sau poți apăsa reîncarcă mai jos.", @@ -111,9 +86,7 @@ "Close": "Închide", "Cancel": "Anulează", "Apply": "Aplică", - "AllMoviesHiddenDueToFilter": "Toate filmele sunt ascunse datorită filtrelor aplicate.", "Age": "Vechime", - "AddList": "Adaugă listă", "QualityProfile": "Profil de Calitate", "QualityDefinitions": "Definiții de calitate", "PtpOldSettingsCheckMessage": "Următorul indexer PassThePopcorn are setări depreciate și ar trebui actualizate: {0}", @@ -122,20 +95,16 @@ "ProxyCheckBadRequestMessage": "Testul proxy a eșuat. StatusCode: {0}", "Proxy": "Proxy", "Protocol": "Protocol", - "Year": "An", "Warn": "Atenționare", "View": "Vizualizare", - "UpdateSelected": "Actualizează selecția", "Updates": "Actualizări", "UpdateCheckUINotWritableMessage": "Nu pot instala actualizarea pentru că dosarul UI '{0}' nu poate fi scris de către utilizatorul '{1}'.", "UpdateCheckStartupTranslocationMessage": "Nu pot instala actualizarea pentru că folderul de pornire '{0}' este într-un folder de App Translocation.", "UpdateCheckStartupNotWritableMessage": "Nu pot instala actualizarea pentru că dosarul '{0}' nu poate fi scris de către utilizatorul '{1}'.", "UnselectAll": "Deselectează tot", - "UnmappedFolders": "Foldere nemapate", "UISettingsSummary": "Calendar, dată și setări pentru probleme de vedere", "UI": "Interfață Grafica", "Type": "Tip", - "Titles": "Titluri", "Title": "Titlu", "Time": "Timp", "TestAll": "Testează Tot", @@ -159,26 +128,20 @@ "SelectAll": "SelecteazăTot", "Seeders": "Partajatori", "Security": "Securitate", - "SearchForMissing": "Caută ce lipsește", "SearchAll": "Caută în toate", "Search": "Caută", "Scheduled": "Programat", "SaveChanges": "Salvează modificările", "Save": "Salvează", - "RSSSync": "Sincronizare RSS", "RootFolderCheckSingleMessage": "Folder rădăcină lipsă: {0}", - "RootFolder": "Folder Rădăcină", "Restrictions": "Restricții", "RestoreBackup": "Restaurează salvarea", "Restart": "Repornește", - "Renamed": "Redenumit", "RemoveRootFolder": "Elimină folder rădăcină", - "RemovedMovieCheckMultipleMessage": "Filmele {0} au fost șterse de pe TMBd", "Reload": "Reîncarcă", "ReleaseStatus": "Statusul apariției", "ReleaseBranchCheckPreviousVersionMessage": "Branch {0} este pentru o versiune precedentă a Prowlarr, configurează branchul 'Aphrodite' pentru a primi updateuri", "ReleaseBranchCheckOfficialBranchMessage": "Branchul {0} nu este un branch Prowlarr valid, nu vei primi actualizări", - "RejectionCount": "Numărul Respingerilor", "Refresh": "Reîmprospătează", "Queue": "Coadă" } diff --git a/src/NzbDrone.Core/Localization/Core/ru.json b/src/NzbDrone.Core/Localization/Core/ru.json index f84637fd7..f161e41c6 100644 --- a/src/NzbDrone.Core/Localization/Core/ru.json +++ b/src/NzbDrone.Core/Localization/Core/ru.json @@ -2,20 +2,15 @@ "Close": "Закрыть", "CloneProfile": "Клонировать профиль", "CloneIndexer": "Клонировать индексер", - "CloneCustomFormat": "Клонировать пользовательский формат", "ClientPriority": "Приоритет клиента", - "YouCanAlsoSearch": "Вы так же можете искать используя TMDb id или IMDb id фильма. На пример tmdb:71663", "Activity": "Активность", - "Blacklisted": "В черном списке", "Backups": "Резервные копии", "BackupRetentionHelpText": "Автоматические резервные копии старше указанного периода будут автоматически удалены", "BackupNow": "Сделать резервную копию", "BackupIntervalHelpText": "Периодичность автоматического резервного копирования", "Backup": "Резервная копия", - "AutoRedownloadFailedHelpText": "Автоматически искать и пытаться скачать разные релизы", "AutomaticSearch": "Автоматический поиск", "Authentication": "Аутентификация", - "AsAllDayHelpText": "События появятся как события на весь день в Вашем календаре", "AreYouSureYouWantToResetYourAPIKey": "Вы уверены, что хотите сбросить Ваш API ключ?", "ApplyTagsHelpTexts3": "Убрать: Убрать введенные тэги", "ApplyTags": "Применить тэги", @@ -23,19 +18,13 @@ "AppDataLocationHealthCheckMessage": "Обновление будет не возможно, во избежание удаления данных программы во время обновления", "ApiKey": "API ключ", "Analytics": "Аналитика", - "AlreadyInYourLibrary": "Уже в вашей библиотеке", "AllMoviesHiddenDueToFilter": "Все фильмы спрятаны в соответствии с фильтром.", - "AddRemotePathMapping": "Добавить удаленный путь", "AddNewMessage": "Добавить новый фильм очень просто! Начни печатать название фильма, который хочешь добавить", - "AddMoviesMonitored": "Добавить отслеживаемые фильмы", "AddMovie": "Добавить фильм", - "AddList": "Добавить список", "AddIndexer": "Добавить индексер", - "AddExclusion": "Добавить исключение", "Added": "Добавлено", "Actions": "Действия", "About": "Подробности", - "DeleteCustomFormat": "Удалить пользовательский формат", "DeleteBackupMessageText": "Вы уверены, что хотите удалить резервную копию '{0}'?", "DeleteBackup": "Удалить резервную копию", "Delete": "Удалить" diff --git a/src/NzbDrone.Core/Localization/Core/sv.json b/src/NzbDrone.Core/Localization/Core/sv.json index 06bf49e4a..3bbad8583 100644 --- a/src/NzbDrone.Core/Localization/Core/sv.json +++ b/src/NzbDrone.Core/Localization/Core/sv.json @@ -1,28 +1,22 @@ { - "AddMovies": "Lägg till film(er)", "Activity": "Aktivitet", "About": "Om", "Languages": "Språk", "Language": "Språk", "IndexerStatusCheckSingleClientMessage": "Indexerare otillgängliga på grund av fel: {0}", "IndexerStatusCheckAllClientMessage": "Samtliga indexerare otillgängliga på grund av fel", - "IndexerSearchCheckNoAvailableIndexersMessage": "På grund av nyligen inträffade indexerarfel är alla sök-kapabla indexerare tillfälligt otillgängliga", "IndexerSearchCheckNoAutomaticMessage": "Inga indexerare tillgängliga med Automatisk Sök aktiverat, Prowlarr kommer inte tillhandahålla automatiska sökresultat", "Indexers": "Indexerare", - "ImportTipsMessage": "Några tips för att försäkra oss om att importen går smärtfritt:", "ImportMechanismHealthCheckMessage": "Aktivera Avklarad nedladdningshantering", - "ImportFirstTip": "Var noga med att dina filer inkluderar kvalitet i filnamnet. T.ex.", "iCalLink": "iCal-länk", "Host": "Värd", "History": "Historia", "HideAdvanced": "Dölj avancerat", "Health": "Hälsa", "General": "Generell", - "Formats": "Format", "Folder": "Mapp", "Filter": "Filter", "Files": "Filer", - "FailedDownloadHandling": "Misslyckad nedladdningshantering", "Events": "Händelser", "Edit": "Redigera", "DownloadClientStatusCheckSingleClientMessage": "Otillgängliga nedladdningsklienter på grund av misslyckade anslutningsförsök: {0}", @@ -30,34 +24,27 @@ "DownloadClients": "Nedladdningsklienter", "DownloadClientCheckUnableToCommunicateMessage": "Kommunikation med {0} ej möjlig.", "DownloadClientCheckNoneAvailableMessage": "Ingen nedladdningsklient tillgänglig", - "DotNetVersionCheckNotRecommendedMessage": "Nuvarande installationen av .Net Framework {0} har stöd men vi rekommenderar att uppgradera till minst {1}.", "Discover": "Upptäck", "Delete": "Radera", - "Day": "Dag", "Dates": "Datum", "Date": "Datum", "CustomFilters": "Anpassade Filter", "Connections": "Anslutningar", "Connect": "Anslut", "Clear": "Rensa", - "Cast": "Rollista", "Blacklist": "Svartlista", "BackupNow": "Säkerhets- kopiera", "Backup": "Säkerhetskopiering", "AppDataLocationHealthCheckMessage": "Uppdatering ej möjlig för att AppData inte skall raderas", "Analytics": "Analys", "All": "Samtliga", - "AddNewTmdbIdMessage": "Du kan även söka genom filmens TMDB-Id, t.ex. tmdb:71663", "MoreInfo": "Mer info", "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls workaround är aktiverad, överväg att ta bort \"MONO_TLS_PROVIDER=legacy environment\"-alternativet", "MonoNotNetCoreCheckMessage": "Var vänlig uppgradera till .NET Core-versionen av Prowlarr", - "Missing": "Saknas", "MinAvailability": "Minsta tillgänglighet", - "MediaManagement": "Mediahantering", "ManualImport": "Manuell import", "Logging": "Loggning", "LogFiles": "Loggfiler", - "Year": "År", "Wanted": "Önskade", "View": "Vy", "Updates": "Uppdateringar", @@ -65,10 +52,8 @@ "UpdateCheckStartupTranslocationMessage": "Ej möjligt att installera uppdatering då uppstartsmappen '{0}' är i en \"App translocation\"-mapp.", "UpdateCheckStartupNotWritableMessage": "Ej möjligt att installera uppdatering då uppstartsmappen '{0}' inte är skrivbar för användaren '{1}'.", "UnselectAll": "Avmarkera samtliga", - "UnmappedFolders": "Omappade kataloger", "UISettingsSummary": "Alternativ för kalender, datum och färgblindhet", "UI": "Användargränssnitt", - "Timeleft": "Tid kvar", "Tasks": "Uppgifter", "TagsSettingsSummary": "Se samtliga taggar och hur de används. Oanvända taggar kan tas bort", "Tags": "Taggar", @@ -82,23 +67,18 @@ "SetTags": "Ange taggar", "SelectAll": "Välj samtliga", "Security": "Säkerhet", - "SearchForMissing": "Sök efter saknade", "SearchAll": "Sök samtliga", "Search": "Sök", "Scheduled": "Schemalagt", "SaveChanges": "Spara ändringar", - "RSSSync": "RSS-synk", "RootFolderCheckSingleMessage": "Rotmapp saknas: {0}", - "RootFolder": "Rotmapp", "Restrictions": "Restriktioner", "RestoreBackup": "Återställ säkerhetskopia", - "Renamed": "Omdöpt", "RemovedMovieCheckMultipleMessage": "Filmerna {0} är borttagna från TMDb", "ReleaseBranchCheckOfficialBranchMessage": "Gren {0} är inte en giltig gren av Prowlarr, du kommer ej erhålla uppdateringar", "ReleaseBranchCheckPreviousVersionMessage": "Gren {0} är ämnad en tidigare version av Prowlarr, välj gren 'Aphrodite' för ytterligare uppdateringar", "Refresh": "Uppdatera", "Queue": "Kö", - "QualitySettingsSummary": "Namn och storleksdefinitioner på kvaliteterna", "QualityProfile": "Kvalitetsprofil", "QualityDefinitions": "Kvalitetsdefinitioner", "PtpOldSettingsCheckMessage": "Följande PassThePopcorn-indexerare har inaktuella inställningar och bör uppdateras: {0}", @@ -107,15 +87,11 @@ "ProxyCheckBadRequestMessage": "Test av proxy misslyckades. Statuskod: {0}", "Proxy": "Proxy", "Protocol": "Protokoll", - "ProfilesSettingsSummary": "Profiler för kvalitet, språk och fördröjning", "PreviewRename": "Förhandsvisa namnbyte", - "Path": "Sökväg", "MonitoredOnly": "Endast Bevakade", - "MediaManagementSettingsSummary": "Namngivning- och filhanteringsinställningar", "ListsSettingsSummary": "Importera listor, listuteslutningar", "LastWriteTime": "Senast skriven tid", "Indexer": "Indexerare", - "Imported": "Importerad", "Grabbed": "Hämtad", "GeneralSettingsSummary": "Port, SSL, användarnamn/lösenord, proxy, analys och uppdateringar", "Filename": "Filnamn", @@ -123,23 +99,17 @@ "EventType": "Händelsetyp", "DownloadClientsSettingsSummary": "Nedladdningsklienter, nedladdningshantering och fjärrsökvägar", "DownloadClient": "Nedladdningsklient", - "ReleaseGroup": "Releasegrupp", "ReleaseStatus": "Releasestatus", "Details": "Detaljer", - "CutoffUnmet": "Avgränsande ej tillgodosedd", "ConnectSettingsSummary": "Aviseringar, anslutningar till media-servrar/klienter och anpassade script", - "Certification": "Certifikation", "Added": "Tillagd", "Actions": "Åtgärder", "Options": "Alternativ", "NoChanges": "Inga ändringar", "NoChange": "Ingen förändring", - "ImportListStatusCheckAllClientMessage": "Samtliga listor otillgängliga på grund av fel", "Movies": "Filmer", - "MovieIndex": "Filmindex", "Movie": "Film", "Warn": "Varna", - "Unavailable": "Otillgänglig", "Type": "Typ", "Title": "Titel", "Time": "Tid", @@ -153,22 +123,17 @@ "Save": "Spara", "Restart": "Starta om", "Reload": "Ladda om", - "RejectionCount": "Antal avslag", "Peers": "Peers", "PageSize": "Sidstorlek", - "OrganizeModalNamingPattern": "Namnmönster:", "OrganizeModalAllPathsRelative": "Samtliga sögvägar är relativa till:", "OAuthPopupMessage": "Popups blockeras av din webbläsare", - "Organize": "Organisera", "Ok": "Ok", "Name": "Namn", - "Monitored": "Bevakad", "Message": "Meddelande", "Level": "Nivå", "KeyboardShortcuts": "Tangentbordsgenvägar", "Info": "Info", "HealthNoIssues": "Inga problem hittades med din konfiguration", - "Extension": "Filändelse", "Error": "Fel", "ConnectionLostMessage": "Prowlarr har tappat anslutningen till sin backend och behöver laddas om för att återställa funktionalitet.", "ConnectionLostAutomaticMessage": "Prowlarr kommer försöka ansluta automatiskt, du kan även klicka på ladda om nedan.", @@ -178,8 +143,6 @@ "Close": "Avsluta", "Cancel": "Avbryt", "Apply": "TIllämpa", - "AllMoviesHiddenDueToFilter": "Samtliga filmer är dolda på grund av tillämpade filter.", "Age": "Ålder", - "AddList": "Lägg till lista", "SystemTimeCheckMessage": "Systemklockan går fel med mer än en dag. Schemalagda uppgifter kan få problem att köras innan tiden är korrigerad" } diff --git a/src/NzbDrone.Core/Localization/Core/tr.json b/src/NzbDrone.Core/Localization/Core/tr.json index 6e61a25a0..1d82db118 100644 --- a/src/NzbDrone.Core/Localization/Core/tr.json +++ b/src/NzbDrone.Core/Localization/Core/tr.json @@ -1,5 +1,4 @@ { - "Discover": "Keşfet", "Details": "Detaylar", "Delete": "Sil", "Dates": "Tarih", @@ -7,36 +6,28 @@ "Connections": "Bağlantılar", "Connect": "Bağlan", "Clear": "Temizle", - "Calendar": "Takvim", "AddMovies": "Filimler ekle", "Sort": "Çeşitle", "SetTags": "Etiketleri Ayarla", "Scheduled": "Tarifeli", - "RootFolderCheckSingleMessage": "Eksik kök klasör: {0}", "RootFolder": "Kök Klasör", "ProxyCheckResolveIpMessage": "{0} Yapılandırılmış Proxy Ana Bilgisayarının IP Adresi çözülemedi", "ProxyCheckFailedToTestMessage": "Proxy ile test edilemedi: {0}", "ProxyCheckBadRequestMessage": "Proxy ile test edilemedi. DurumKodu: {0}", "Proxy": "Proxy", - "ImportListStatusCheckSingleClientMessage": "Hatalar nedeniyle kullanılamayan listeler: {0}", "MonitoredOnly": "Sadece İzlenenler", - "Metadata": "Meta veri", "Logging": "Logging", "LogFiles": "Log dosyaları", - "ImportTipsMessage": "İçe aktarmanın sorunsuz geçmesini sağlamak için bazı ipuçları:", "ImportFirstTip": "Dosyalarınızın dosya adlarında kaliteyi dahil etmeyi emin olun. Örneğin.", "Host": "Ana bilgisayar", "GeneralSettingsSummary": "Port, SSL, kullanıcı adı/şifre, proxy, analitikler ve güncellemeler", "Folder": "Klasör", "Files": "Dosyalar", "Filename": "Dosya adı", - "CustomFormatsSettingsSummary": "Özel Biçimler ve Ayarlar", "Crew": "Oyuncular", "AppDataLocationHealthCheckMessage": "Güncellemede AppData'nın silinmesini önlemek için güncelleme mümkün olmayacak", - "AddNewMessage": "Yeni bir film eklemek kolaydır, eklemek istediğiniz filmin adını yazmaya başlayın", "Actions": "Etkiler", "About": "Hakkında", - "Week": "Hafta", "View": "Görünüm", "Updates": "Güncellemeler", "UpdateCheckUINotWritableMessage": "'{0}' UI klasörü '{1}' kullanıcısı tarafından yazılamadığından güncelleme yüklenemiyor.", @@ -45,7 +36,6 @@ "UnselectAll": "Tüm Seçimleri Kaldır", "UISettingsSummary": "Takvim, tarih ve renk engelli seçenekler", "UI": "UI", - "Timeleft": "Kalan zaman", "Tasks": "Görevler", "TagsSettingsSummary": "Tüm etiketleri ve nasıl kullanıldıklarını göster. Kullanılmayan etiketler kaldırılabilinir", "Tags": "Etiketler", @@ -57,54 +47,41 @@ "Settings": "Ayarlar", "SelectAll": "Hepsini seç", "Security": "Güvenlik", - "SearchForMissing": "Kayıpları Ara", "SearchAll": "Tümünü ara", "Search": "Ara", "SaveChanges": "Değişiklikleri Kaydet", - "RSSSync": "RSS Senkronizasyonu", "Restrictions": "Kısıtlamalar", - "Renamed": "Yeniden adlandırıldı", "RemovedMovieCheckSingleMessage": "{0} filmi TMDb'den çıkarıldı", - "ReleaseTitle": "Yayin Başlığı", "ReleaseStatus": "Yayın Durumu", "ReleaseBranchCheckPreviousVersionMessage": "Dal {0}, Prowlarr'ın önceki bir versiyon için, dalı daha fazla güncelleme için 'Aphrodite' olarak ayarlayın", "ReleaseBranchCheckOfficialBranchMessage": "Dal {0} geçerli bir Prowlarr sürüm dalı değil, güncelleme almayacaksınız", "Refresh": "Yenile", "Queue": "Sıra", - "QualityProfiles": "Kalite Profileri", "QualityDefinitions": "Kalite Tanımları", "Protocol": "Protokol", - "ProfilesSettingsSummary": "Kalite, Dil ve Gecikme profilleri", "Options": "Seçenekler", "NoChanges": "Değişiklikler yok", "NoChange": "Değişiklik yok", "Movies": "Filmler", - "MovieEditor": "Film Editörü", "MoreInfo": "Daha fazla bilgi", "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls geçici çözümü hala etkin, MONO_TLS_PROVIDER=legacy seçeneğini kaldırmayı düşünün", "MonoNotNetCoreCheckMessage": "Lütfen Prowlarr'ın .NET Core sürümüne güncelle", - "Missing": "Eksik", "MediaInfoDllCheckMessage": "Medya Bilgi Kütüphanesi yüklenemedi {0}", - "Lists": "Listeler", "LastWriteTime": "Son Yazma Zamanı", "Languages": "Diller", "Language": "Dil", - "ImportSecondTip": "Prowlarr'ı belirli bir filmi değil, tüm filmlerinizi içeren klasöre yönlendirin. Örneğin.", "iCalLink": "iCal Bağlantısı", "History": "Tarih", "HideAdvanced": "Gelişmiş'i Gizle", "Health": "Sağlık", "General": "Genel", - "Formats": "Biçimler", "Filter": "Filtre", "Failed": "Başarısız oldu", "Edit": "Düzenle", "DownloadClientCheckUnableToCommunicateMessage": "{0} ile iletişim kurulamıyor.", - "DotNetVersionCheckNotRecommendedMessage": "Şu anda yüklü .Net Framework {0} desteklenmektedir, fakat en az {1} sürümüne güncelleştirmeyi öneririz.", "DelayProfiles": "Gecikme Profilleri", "CustomFilters": "Özel Filtreler", "ConnectSettingsSummary": "Bildirimler, medya sunucularına/oynatıcılara bağlantılar ve özel komut kodları", - "ChooseAnotherFolder": "Başka bir dosya seç", "Analytics": "Analitik", "All": "Herşey", "Added": "Eklendi", diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index 2e836e821..621e87128 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -270,7 +270,6 @@ "NoChanges": "无修改", "NoChange": "无修改", "NoBackupsAreAvailable": "无备份可用", - "NewznabVipCheckExpiredClientMessage": "搜刮器VIP权益已过期:{0}", "New": "新的", "NetCore": ".NET", "Name": "名称", From 3455f3c92ae8b7ba17d69360ff3a9c9cf1d5c225 Mon Sep 17 00:00:00 2001 From: Servarr <32001786+ServarrAdmin@users.noreply.github.com> Date: Tue, 5 Oct 2021 09:34:23 -0400 Subject: [PATCH 0086/2320] Translations from Weblate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 81.4% (359 of 441 strings) Translated using Weblate (Arabic) Currently translated at 81.6% (360 of 441 strings) Translated using Weblate (Russian) Currently translated at 81.4% (359 of 441 strings) Translated using Weblate (Icelandic) Currently translated at 81.4% (359 of 441 strings) Translated using Weblate (Danish) Currently translated at 81.4% (359 of 441 strings) Translated using Weblate (Slovak) Currently translated at 10.6% (47 of 441 strings) Translated using Weblate (German) Currently translated at 95.4% (421 of 441 strings) Translated using Weblate (Korean) Currently translated at 60.3% (266 of 441 strings) Translated using Weblate (Japanese) Currently translated at 81.4% (359 of 441 strings) Translated using Weblate (Catalan) Currently translated at 2.4% (11 of 441 strings) Translated using Weblate (Bulgarian) Currently translated at 75.7% (334 of 441 strings) Translated using Weblate (Thai) Currently translated at 81.4% (359 of 441 strings) Translated using Weblate (Romanian) Currently translated at 81.8% (361 of 441 strings) Translated using Weblate (Italian) Currently translated at 85.7% (378 of 441 strings) Translated using Weblate (Hindi) Currently translated at 81.4% (359 of 441 strings) Translated using Weblate (Spanish) Currently translated at 83.2% (367 of 441 strings) Translated using Weblate (Hebrew) Currently translated at 81.4% (359 of 441 strings) Translated using Weblate (Portuguese) Currently translated at 84.1% (371 of 441 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 1.1% (5 of 441 strings) Translated using Weblate (Swedish) Currently translated at 81.8% (361 of 441 strings) Translated using Weblate (Czech) Currently translated at 81.4% (359 of 441 strings) Translated using Weblate (Greek) Currently translated at 81.1% (358 of 441 strings) Translated using Weblate (Norwegian Bokmål) Currently translated at 12.4% (55 of 441 strings) Translated using Weblate (Turkish) Currently translated at 81.6% (360 of 441 strings) Translated using Weblate (Vietnamese) Currently translated at 81.4% (359 of 441 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 90.9% (401 of 441 strings) Translated using Weblate (Polish) Currently translated at 81.4% (359 of 441 strings) Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Anonymous <noreply@weblate.org> Co-authored-by: Weblate <noreply@weblate.org> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ar/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/bg/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ca/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/cs/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/da/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/el/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/he/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/is/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/it/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ja/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ko/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nb_NO/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pl/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ro/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ru/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sk/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sv/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/th/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/vi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_Hans/ Translation: Servarr/Prowlarr Co-authored-by: Weblate <noreply@weblate.org> --- src/NzbDrone.Core/Localization/Core/ar.json | 357 ++++++++++++++++- src/NzbDrone.Core/Localization/Core/bg.json | 292 +++++++++++++- src/NzbDrone.Core/Localization/Core/ca.json | 8 +- src/NzbDrone.Core/Localization/Core/cs.json | 362 +++++++++++++++++- src/NzbDrone.Core/Localization/Core/da.json | 312 ++++++++++++++- src/NzbDrone.Core/Localization/Core/de.json | 72 +--- src/NzbDrone.Core/Localization/Core/el.json | 323 +++++++++++++++- src/NzbDrone.Core/Localization/Core/es.json | 96 ++--- src/NzbDrone.Core/Localization/Core/fi.json | 362 +++++++++++++++++- src/NzbDrone.Core/Localization/Core/fr.json | 56 --- src/NzbDrone.Core/Localization/Core/he.json | 362 +++++++++++++++++- src/NzbDrone.Core/Localization/Core/hi.json | 362 +++++++++++++++++- src/NzbDrone.Core/Localization/Core/hu.json | 60 --- src/NzbDrone.Core/Localization/Core/is.json | 362 +++++++++++++++++- src/NzbDrone.Core/Localization/Core/it.json | 88 ++--- src/NzbDrone.Core/Localization/Core/ja.json | 362 +++++++++++++++++- src/NzbDrone.Core/Localization/Core/ko.json | 189 ++++++++- .../Localization/Core/nb_NO.json | 16 +- src/NzbDrone.Core/Localization/Core/nl.json | 50 --- src/NzbDrone.Core/Localization/Core/pl.json | 354 ++++++++++++++++- src/NzbDrone.Core/Localization/Core/pt.json | 70 +--- src/NzbDrone.Core/Localization/Core/ro.json | 257 ++++++++++++- src/NzbDrone.Core/Localization/Core/ru.json | 340 +++++++++++++++- src/NzbDrone.Core/Localization/Core/sk.json | 16 +- src/NzbDrone.Core/Localization/Core/sv.json | 258 ++++++++++++- src/NzbDrone.Core/Localization/Core/th.json | 362 +++++++++++++++++- src/NzbDrone.Core/Localization/Core/tr.json | 299 ++++++++++++++- src/NzbDrone.Core/Localization/Core/vi.json | 362 +++++++++++++++++- .../Localization/Core/zh_CN.json | 127 +++++- .../Localization/Core/zh_Hans.json | 3 +- 30 files changed, 6030 insertions(+), 509 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/ar.json b/src/NzbDrone.Core/Localization/Core/ar.json index 48cc7f6e1..c25cb384a 100644 --- a/src/NzbDrone.Core/Localization/Core/ar.json +++ b/src/NzbDrone.Core/Localization/Core/ar.json @@ -3,5 +3,360 @@ "AddDownloadClient": "إضافة وكيل التحميل", "About": "نبدة عن", "AcceptConfirmationModal": "نموذج قبول التأكيد", - "Actions": "أجراءات" + "Actions": "أجراءات", + "MinutesHundredTwenty": "120 دقيقة: {0}", + "MonoVersion": "نسخة أحادية", + "MoreInfo": "مزيد من المعلومات", + "BranchUpdateMechanism": "يستخدم الفرع بواسطة آلية التحديث الخارجية", + "CloneIndexer": "مفهرس استنساخ", + "Added": "مضاف", + "AddIndexer": "أضف مفهرس", + "AddingTag": "مضيفا العلامة", + "AllIndexersHiddenDueToFilter": "جميع الأفلام مخفية بسبب الفلتر المطبق.", + "ApplicationStatusCheckAllClientMessage": "جميع القوائم غير متاحة بسبب الإخفاقات", + "ApplicationStatusCheckSingleClientMessage": "القوائم غير متاحة بسبب الإخفاقات: {0}", + "AreYouSureYouWantToResetYourAPIKey": "هل أنت متأكد أنك تريد إعادة تعيين مفتاح API الخاص بك؟", + "Authentication": "المصادقة", + "BackupIntervalHelpText": "الفاصل الزمني بين النسخ الاحتياطية التلقائية", + "Languages": "اللغات", + "BackupNow": "اعمل نسخة احتياطية الان", + "BackupRetentionHelpText": "سيتم تنظيف النسخ الاحتياطية التلقائية الأقدم من فترة الاحتفاظ تلقائيًا", + "Backups": "النسخ الاحتياطية", + "BindAddressHelpText": "عنوان IP4 صالح أو \"*\" لجميع الواجهات", + "BypassProxyForLocalAddresses": "تجاوز الوكيل للعناوين المحلية", + "Cancel": "إلغاء", + "CertificateValidation": "التحقق من صحة الشهادة", + "Custom": "مخصص", + "CustomFilters": "مرشحات مخصصة", + "Date": "تاريخ", + "DeleteApplicationMessageText": "هل تريد بالتأكيد حذف الإشعار \"{0}\"؟", + "DeleteDownloadClient": "حذف Download Client", + "DeleteDownloadClientMessageText": "هل أنت متأكد أنك تريد حذف برنامج التنزيل \"{0}\"؟", + "DeleteIndexer": "حذف المفهرس", + "DeleteIndexerMessageText": "هل أنت متأكد أنك تريد حذف المفهرس \"{0}\"؟", + "EnableMediaInfoHelpText": "استخراج معلومات الفيديو مثل الدقة ووقت التشغيل ومعلومات الترميز من الملفات. يتطلب هذا من Radarr قراءة أجزاء من الملف والتي قد تسبب نشاطًا كبيرًا على القرص أو الشبكة أثناء عمليات الفحص.", + "Filename": "اسم الملف", + "HomePage": "الصفحة الرئيسية", + "IndexerProxyStatusCheckSingleClientMessage": "المفهرسات غير متاحة بسبب الإخفاقات: {0}", + "Language": "لغة", + "MinutesNinety": "90 دقيقة: {0}", + "Usenet": "يوزنت", + "MinutesSixty": "60 دقيقة: {0}", + "MonoVersionCheckUpgradeRecommendedMessage": "يتم دعم الإصدار Mono المثبت حاليًا {0} ولكن يوصى بالترقية إلى {1}.", + "MovieDetailsNextMovie": "تفاصيل الفيلم: الفيلم القادم", + "MovieIndexScrollTop": "فهرس الفيلم: قم بالتمرير لأعلى", + "New": "جديد", + "NoLinks": "لا روابط", + "PackageVersion": "إصدار الحزمة", + "PageSizeHelpText": "عدد العناصر التي سيتم عرضها في كل صفحة", + "Peers": "الأقران", + "PendingChangesMessage": "لديك تغييرات لم يتم حفظها ، هل أنت متأكد أنك تريد مغادرة هذه الصفحة؟", + "PendingChangesStayReview": "البقاء ومراجعة التغييرات", + "PortNumber": "رقم المنفذ", + "Presets": "الإعدادات المسبقة", + "Priority": "أفضلية", + "Age": "عمر", + "PriorityHelpText": "تحديد أولويات عملاء التنزيل المتعددين. يتم استخدام Round-Robin للعملاء الذين لديهم نفس الأولوية.", + "PrioritySettings": "أفضلية", + "Protocol": "بروتوكول", + "Analytics": "تحليلات", + "ProxyBypassFilterHelpText": "استخدم \"،\" كفاصل ، و \"*.\" كحرف بدل للنطاقات الفرعية", + "ProxyCheckBadRequestMessage": "فشل اختبار الوكيل. رمز الحالة: {0}", + "ProxyCheckFailedToTestMessage": "فشل اختبار الوكيل: {0}", + "ProxyPasswordHelpText": "ما عليك سوى إدخال اسم مستخدم وكلمة مرور إذا كان أحدهما مطلوبًا. اتركها فارغة وإلا.", + "ProxyUsernameHelpText": "ما عليك سوى إدخال اسم مستخدم وكلمة مرور إذا كان أحدهما مطلوبًا. اتركها فارغة وإلا.", + "PtpOldSettingsCheckMessage": "مفهرسات PassThePopcorn التالية بها إعدادات مهملة ويجب تحديثها: {0}", + "QualitySettings": "إعدادات الجودة", + "Queue": "طابور", + "ReadTheWikiForMoreInformation": "اقرأ Wiki لمزيد من المعلومات", + "Reddit": "رديت", + "Security": "الأمان", + "Seeders": "بزار", + "SelectAll": "اختر الكل", + "SendAnonymousUsageData": "إرسال بيانات الاستخدام المجهولة", + "Style": "أسلوب", + "SystemTimeCheckMessage": "توقف وقت النظام بأكثر من يوم واحد. قد لا تعمل المهام المجدولة بشكل صحيح حتى يتم تصحيح الوقت", + "TableOptionsColumnsMessage": "اختر الأعمدة المرئية والترتيب الذي تظهر به", + "TagCannotBeDeletedWhileInUse": "لا يمكن حذفه أثناء الاستخدام", + "Tasks": "مهام", + "UnableToAddANewAppProfilePleaseTryAgain": "غير قادر على إضافة ملف تعريف جودة جديد ، يرجى المحاولة مرة أخرى.", + "UnableToAddANewDownloadClientPleaseTryAgain": "غير قادر على إضافة عميل تنزيل جديد ، يرجى المحاولة مرة أخرى.", + "UnableToAddANewIndexerPleaseTryAgain": "غير قادر على إضافة مفهرس جديد ، يرجى المحاولة مرة أخرى.", + "UnableToLoadBackups": "تعذر تحميل النسخ الاحتياطية", + "UnableToLoadIndexers": "تعذر تحميل المفهرسات", + "UnableToLoadQualityDefinitions": "تعذر تحميل تعريفات الجودة", + "UnsavedChanges": "التغييرات غير المحفوظة", + "UpdateCheckUINotWritableMessage": "لا يمكن تثبيت التحديث لأن مجلد واجهة المستخدم '{0}' غير قابل للكتابة بواسطة المستخدم '{1}'", + "UpdateScriptPathHelpText": "المسار إلى برنامج نصي مخصص يأخذ حزمة تحديث مستخرجة ويتعامل مع ما تبقى من عملية التحديث", + "Username": "اسم المستخدم", + "Warn": "حذر", + "Yesterday": "في الامس", + "EnableColorImpairedMode": "تفعيل وضع ضعف الألوان", + "EnableColorImpairedModeHelpText": "تم تغيير النمط للسماح للمستخدمين الذين يعانون من ضعف الألوان بتمييز المعلومات المشفرة بالألوان بشكل أفضل", + "EnableCompletedDownloadHandlingHelpText": "استيراد التنزيلات المكتملة تلقائيًا من عميل التنزيل", + "EnabledHelpText": "قم بتمكين هذه القائمة للاستخدام في Radarr", + "EnableHelpText": "تفعيل إنشاء ملف البيانات الوصفية لنوع البيانات الوصفية هذا", + "EnableInteractiveSearch": "تمكين البحث التفاعلي", + "Source": "مصدر", + "SSLCertPassword": "كلمة مرور شهادة SSL", + "UpdateCheckStartupNotWritableMessage": "لا يمكن تثبيت التحديث لأن مجلد بدء التشغيل \"{0}\" غير قابل للكتابة بواسطة المستخدم \"{1}\".", + "UpdateMechanismHelpText": "استخدم المحدث أو البرنامج النصي المدمج في Radarr", + "AppDataDirectory": "دليل AppData", + "ConnectionLostAutomaticMessage": "سيحاول Radarr الاتصال تلقائيًا ، أو يمكنك النقر فوق إعادة التحميل أدناه.", + "ConnectSettings": "ربط الإعدادات", + "CouldNotConnectSignalR": "تعذر الاتصال بـ SignalR ، لن يتم تحديث واجهة المستخدم", + "Dates": "تواريخ", + "DBMigration": "ترحيل DB", + "DelayProfile": "ملف التأخير", + "Delete": "حذف", + "Details": "تفاصيل", + "Donations": "التبرعات", + "DownloadClient": "تحميل العميل", + "EnableAutoHelpText": "في حالة التمكين ، ستتم إضافة الأفلام تلقائيًا إلى Radarr من هذه القائمة", + "IndexerStatusCheckAllClientMessage": "جميع المفهرسات غير متوفرة بسبب الفشل", + "IndexerStatusCheckSingleClientMessage": "المفهرسات غير متاحة بسبب الإخفاقات: {0}", + "Info": "معلومات", + "Interval": "فترة", + "Manual": "كتيب", + "MaximumLimits": "الحدود القصوى", + "NoLimitForAnyRuntime": "لا يوجد حد لأي وقت تشغيل", + "General": "جنرال لواء", + "GeneralSettings": "الاعدادات العامة", + "Grabbed": "اقتطف", + "AppDataLocationHealthCheckMessage": "لن يكون التحديث ممكنًا لمنع حذف AppData عند التحديث", + "ApplyTagsHelpTexts1": "كيفية تطبيق العلامات على الأفلام المختارة", + "ApplyTagsHelpTexts2": "إضافة: أضف العلامات إلى قائمة العلامات الموجودة", + "ApplyTagsHelpTexts3": "إزالة: قم بإزالة العلامات التي تم إدخالها", + "AutomaticSearch": "البحث التلقائي", + "Backup": "دعم", + "BackupFolderHelpText": "ستكون المسارات النسبية ضمن دليل AppData الخاص بـ Radarr", + "BeforeUpdate": "قبل التحديث", + "BindAddress": "عنوان ملزم", + "CertificateValidationHelpText": "تغيير مدى صرامة التحقق من صحة شهادة HTTPS", + "CloneProfile": "الملف الشخصي استنساخ", + "Close": "قريب", + "CloseCurrentModal": "إغلاق Modal الحالي", + "Columns": "الأعمدة", + "Component": "مكون", + "DeleteBackup": "حذف النسخة الاحتياطية", + "DeleteBackupMessageText": "هل تريد بالتأكيد حذف النسخة الاحتياطية \"{0}\"؟", + "DownloadClientSettings": "تنزيل إعدادات العميل", + "EnableInteractiveSearchHelpText": "سيتم استخدامها عند استخدام البحث التفاعلي", + "EnableRss": "تمكين RSS", + "EnableSSL": "تمكين SSL", + "EnableSslHelpText": " يتطلب إعادة التشغيل قيد التشغيل كمسؤول ليصبح ساري المفعول", + "Error": "خطأ", + "ErrorLoadingContents": "خطأ في تحميل المحتويات", + "Events": "الأحداث", + "EventType": "نوع الحدث", + "Exception": "استثناء", + "Files": "الملفات", + "Filter": "منقي", + "FocusSearchBox": "التركيز على مربع البحث", + "Folder": "مجلد", + "Health": "الصحة", + "HealthNoIssues": "لا مشاكل مع التكوين الخاص بك", + "HiddenClickToShow": "مخفي ، انقر للعرض", + "Host": "مضيف", + "IllRestartLater": "سأعيد التشغيل لاحقًا", + "IncludeHealthWarningsHelpText": "قم بتضمين التحذيرات الصحية", + "Indexer": "مفهرس", + "IndexerFlags": "أعلام المفهرس", + "IndexerLongTermStatusCheckAllClientMessage": "جميع المفهرسات غير متوفرة بسبب الفشل لأكثر من 6 ساعات", + "IndexerLongTermStatusCheckSingleClientMessage": "المفهرسات غير متاحة بسبب الإخفاقات لأكثر من 6 ساعات: {0}", + "IndexerPriorityHelpText": "أولوية المفهرس من 1 (الأعلى) إلى 50 (الأدنى). الافتراضي: 25.", + "IndexerProxyStatusCheckAllClientMessage": "جميع المفهرسات غير متوفرة بسبب الفشل", + "NoChange": "لا تغيير", + "NoLogFiles": "لا توجد ملفات سجل", + "NoMinimumForAnyRuntime": "لا يوجد حد أدنى لأي وقت تشغيل", + "NoTagsHaveBeenAddedYet": "لم يتم إضافة أي علامات حتى الان", + "NotificationTriggers": "مشغلات الإخطار", + "NoUpdatesAreAvailable": "لا توجد تحديثات متوفرة", + "OAuthPopupMessage": "يتم حظر النوافذ المنبثقة بواسطة متصفحك", + "OnHealthIssueHelpText": "في قضية الصحة", + "OpenBrowserOnStart": "افتح المتصفح عند البدء", + "OpenThisModal": "افتح هذا النموذج", + "SSLCertPathHelpText": "مسار ملف pfx", + "ReleaseBranchCheckOfficialBranchMessage": "الفرع {0} ليس فرع إصدار Radarr صالح ، لن تتلقى تحديثات", + "RemovedFromTaskQueue": "تمت إزالته من قائمة انتظار المهام", + "RemoveFilter": "قم بإزالة الفلتر", + "RemovingTag": "إزالة العلامة", + "Reset": "إعادة تعيين", + "ResetAPIKey": "إعادة تعيين مفتاح API", + "RSSIsNotSupportedWithThisIndexer": "لا يتم دعم RSS مع هذا المفهرس", + "Save": "حفظ", + "ScriptPath": "مسار البرنامج النصي", + "SettingsEnableColorImpairedMode": "تفعيل وضع ضعف الألوان", + "SettingsEnableColorImpairedModeHelpText": "تم تغيير النمط للسماح للمستخدمين الذين يعانون من ضعف الألوان بتمييز المعلومات المشفرة بالألوان بشكل أفضل", + "Time": "زمن", + "Title": "عنوان", + "Today": "اليوم", + "ChangeHasNotBeenSavedYet": "لم يتم حفظ التغيير بعد", + "Clear": "واضح", + "ClientPriority": "أولوية العميل", + "Tomorrow": "غدا", + "DownloadClientCheckUnableToCommunicateMessage": "تعذر الاتصال بـ {0}.", + "Torrent": "السيول", + "Torrents": "السيول", + "ExistingMovies": "فيلم (أفلام) موجود", + "ExistingTag": "علامة موجودة", + "Failed": "فشل", + "FeatureRequests": "طلبات مخصصة", + "GeneralSettingsSummary": "المنفذ ، SSL ، اسم المستخدم / كلمة المرور ، الوكيل ، التحليلات والتحديثات", + "Grabs": "إختطاف", + "Type": "اكتب", + "UI": "واجهة المستخدم", + "HideAdvanced": "إخفاء الإعدادات المتقدمة", + "History": "التاريخ", + "Hostname": "اسم المضيف", + "IgnoredAddresses": "العناوين التي تم تجاهلها", + "Importing": "استيراد", + "UILanguage": "لغة واجهة المستخدم", + "UILanguageHelpText": "اللغة التي سيستخدمها Radarr لواجهة المستخدم", + "UILanguageHelpTextWarning": "يلزم إعادة تحميل المتصفح", + "KeyboardShortcuts": "اختصارات لوحة المفاتيح", + "LogFiles": "ملفات الدخول", + "LogLevelTraceHelpTextWarning": "يجب تمكين تسجيل التتبع مؤقتًا فقط", + "MonoTlsCheckMessage": "لا يزال الحل البديل لـ Radarr Mono 4.x tls ممكّنًا ، فجرّب إزالة MONO_TLS_PROVIDER = خيار البيئة القديمة", + "Movies": "أفلام", + "Name": "اسم", + "NetCore": ".شبكة", + "Password": "كلمه السر", + "PreferredSize": "الحجم المفضل", + "Proxy": "الوكيل", + "ProxyCheckResolveIpMessage": "فشل حل عنوان IP لمضيف الخادم الوكيل المكون {0}", + "ProxyType": "نوع الوكيل", + "QualityDefinitions": "تعريفات الجودة", + "ReleaseStatus": "حالة الإصدار", + "Search": "بحث", + "SettingsShortDateFormat": "تنسيق التاريخ القصير", + "SettingsShowRelativeDates": "إظهار التواريخ النسبية", + "SettingsShowRelativeDatesHelpText": "عرض نسبي (اليوم / أمس / إلخ) أو التواريخ المطلقة", + "StartTypingOrSelectAPathBelow": "ابدأ الكتابة أو حدد المسار أدناه", + "StartupDirectory": "دليل بدء التشغيل", + "SuggestTranslationChange": "اقترح تغيير الترجمة", + "TableOptions": "خيارات الجدول", + "TagsSettingsSummary": "اطلع على جميع العلامات وكيفية استخدامها. يمكن إزالة العلامات غير المستخدمة", + "UnableToAddANewIndexerProxyPleaseTryAgain": "غير قادر على إضافة مفهرس جديد ، يرجى المحاولة مرة أخرى.", + "UnableToAddANewNotificationPleaseTryAgain": "تعذر إضافة إشعار جديد ، يرجى المحاولة مرة أخرى.", + "UnableToLoadGeneralSettings": "تعذر تحميل الإعدادات العامة", + "UnableToLoadHistory": "تعذر تحميل التاريخ", + "UnableToLoadNotifications": "تعذر تحميل الإخطارات", + "UnselectAll": "إلغاء تحديد الكل", + "URLBase": "قاعدة URL", + "UrlBaseHelpText": "لدعم الوكيل العكسي ، الافتراضي فارغ", + "UseProxy": "استخدام بروكسي", + "View": "رأي", + "Wiki": "ويكي", + "YesCancel": "نعم إلغاء", + "DeleteIndexerProxyMessageText": "هل أنت متأكد أنك تريد حذف العلامة \"{0}\"؟", + "DeleteNotification": "حذف الإعلام", + "DownloadClients": "تحميل العملاء", + "DownloadClientStatusCheckAllClientMessage": "جميع عملاء التنزيل غير متاحين بسبب الفشل", + "DownloadClientStatusCheckSingleClientMessage": "برامج التنزيل غير متاحة بسبب الإخفاقات: {0}", + "DownloadClientUnavailable": "عميل التنزيل غير متوفر", + "Downloading": "جارى التحميل", + "Edit": "تعديل", + "EditIndexer": "تحرير المفهرس", + "Enable": "ممكن", + "EnableAutomaticAdd": "تمكين إضافة تلقائية", + "EnableAutomaticSearch": "تمكين البحث التلقائي", + "EnableAutomaticSearchHelpTextWarning": "سيتم استخدامها عند استخدام البحث التفاعلي", + "Enabled": "ممكن", + "EnableInteractiveSearchHelpTextWarning": "البحث غير معتمد مع هذا المفهرس", + "IndexerPriority": "أولوية المفهرس", + "Port": "ميناء", + "SettingsTimeFormat": "تنسيق الوقت", + "ShowAdvanced": "عرض متقدمة", + "ShownClickToHide": "يظهر ، انقر للإخفاء", + "ShowSearch": "إظهار البحث", + "ShowSearchHelpText": "إظهار زر البحث عند التمرير", + "Shutdown": "اغلق", + "Size": "بحجم", + "Sort": "فرز", + "SSLCertPasswordHelpText": "كلمة المرور لملف pfx", + "SSLCertPath": "مسار شهادة SSL", + "SSLPort": "منفذ SSL", + "UpdateAutomaticallyHelpText": "تنزيل التحديثات وتثبيتها تلقائيًا. ستظل قادرًا على التثبيت من النظام: التحديثات", + "All": "الكل", + "AnalyticsEnabledHelpText": "إرسال معلومات الاستخدام والخطأ المجهولة إلى خوادم Radarr. يتضمن ذلك معلومات حول متصفحك ، وصفحات Radarr WebUI التي تستخدمها ، والإبلاغ عن الأخطاء بالإضافة إلى إصدار نظام التشغيل ووقت التشغيل. سنستخدم هذه المعلومات لتحديد أولويات الميزات وإصلاحات الأخطاء.", + "ApplyTags": "تطبيق العلامات", + "Branch": "فرع شجرة", + "BranchUpdate": "فرع لاستخدامه لتحديث Radarr", + "CancelPendingTask": "هل أنت متأكد أنك تريد إلغاء هذه المهمة المعلقة؟", + "DeleteNotificationMessageText": "هل تريد بالتأكيد حذف الإشعار \"{0}\"؟", + "DeleteTag": "حذف العلامة", + "Logging": "تسجيل", + "LogLevel": "تسجيل مستوى", + "PageSize": "مقاس الصفحه", + "SettingsLongDateFormat": "تنسيق التاريخ الطويل", + "ConnectionLost": "انقطع الاتصال", + "Connections": "روابط", + "MovieDetailsPreviousMovie": "تفاصيل الفيلم: الفيلم السابق", + "MovieIndexScrollBottom": "فهرس الفيلم: التمرير لأسفل", + "NoBackupsAreAvailable": "لا توجد نسخ احتياطية متاحة", + "NoChanges": "لا تغيرات", + "NoLeaveIt": "لا ، اتركها", + "Pending": "قيد الانتظار", + "PendingChangesDiscardChanges": "تجاهل التغييرات واترك", + "RSS": "RSS", + "System": "النظام", + "TagIsNotUsedAndCanBeDeleted": "العلامة غير مستخدمة ويمكن حذفها", + "Tags": "العلامات", + "TagsHelpText": "ينطبق على الأفلام التي تحتوي على علامة مطابقة واحدة على الأقل", + "UISettings": "إعدادات واجهة المستخدم", + "UnableToLoadDownloadClients": "تعذر تحميل عملاء التنزيل", + "UnableToLoadTags": "تعذر تحميل العلامات", + "UnableToLoadUISettings": "تعذر تحميل إعدادات واجهة المستخدم", + "UpdateCheckStartupTranslocationMessage": "لا يمكن تثبيت التحديث لأن مجلد بدء التشغيل \"{0}\" موجود في مجلد App Translocation.", + "Updates": "التحديثات", + "Version": "الإصدار", + "ApiKey": "مفتاح API", + "Apply": "تطبيق", + "DeleteTagMessageText": "هل أنت متأكد أنك تريد حذف العلامة \"{0}\"؟", + "Disabled": "معاق", + "Discord": "الخلاف", + "Docker": "عامل ميناء", + "Fixed": "ثابت", + "ForMoreInformationOnTheIndividualDownloadClients": "لمزيد من المعلومات حول عملاء التنزيل الفرديين ، انقر فوق أزرار المعلومات.", + "Indexers": "مفهرسات", + "InteractiveSearch": "بحث تفاعلي", + "LastWriteTime": "وقت الكتابة الأخير", + "LaunchBrowserHelpText": " افتح مستعرض ويب وانتقل إلى صفحة Radarr الرئيسية عند بدء التطبيق.", + "Level": "مستوى", + "Logs": "السجلات", + "Mechanism": "آلية", + "Message": "رسالة", + "MIA": "MIA", + "MinimumLimits": "الحد الأدنى", + "RefreshMovie": "تحديث الفيلم", + "EnableAutomaticSearchHelpText": "سيتم استخدامه عند إجراء عمليات البحث التلقائي عبر واجهة المستخدم أو بواسطة Radarr", + "Status": "الحالة", + "Uptime": "مدة التشغيل", + "ApplyTagsHelpTexts4": "استبدال: استبدل العلامات بالعلامات التي تم إدخالها (لا تدخل أي علامات لمسح جميع العلامات)", + "AuthenticationMethodHelpText": "طلب اسم المستخدم وكلمة المرور للوصول إلى Radarr", + "Automatic": "تلقائي", + "DownloadClientCheckNoneAvailableMessage": "لا يوجد عميل تنزيل متاح", + "Mode": "الوضع", + "Options": "خيارات", + "Ok": "موافق", + "Refresh": "تحديث", + "Reload": "إعادة تحميل", + "Restart": "إعادة تشغيل", + "RestartNow": "اعد البدء الان", + "RestartRequiredHelpTextWarning": "يتطلب إعادة التشغيل ليصبح ساري المفعول", + "Restore": "استعادة", + "RestoreBackup": "استرجاع النسخة الاحتياطية", + "Restrictions": "قيود", + "Result": "نتيجة", + "Retention": "احتفاظ", + "SaveChanges": "حفظ التغييرات", + "SaveSettings": "احفظ التغييرات", + "Scheduled": "المقرر", + "SetTags": "تعيين العلامات", + "Settings": "الإعدادات", + "Test": "اختبار", + "TestAll": "اختبار الكل", + "TestAllClients": "اختبر كل العملاء", + "UnableToAddANewApplicationPleaseTryAgain": "تعذر إضافة إشعار جديد ، يرجى المحاولة مرة أخرى." } diff --git a/src/NzbDrone.Core/Localization/Core/bg.json b/src/NzbDrone.Core/Localization/Core/bg.json index 99af5a167..0298586d7 100644 --- a/src/NzbDrone.Core/Localization/Core/bg.json +++ b/src/NzbDrone.Core/Localization/Core/bg.json @@ -27,7 +27,7 @@ "BackupFolderHelpText": "Относителните пътища ще бъдат в директорията AppData на Prowlarr", "BackupIntervalHelpText": "Интервал между автоматичните архиви", "BackupNow": "Архивиране сега", - "ChangeHasNotBeenSavedYet": "", + "ChangeHasNotBeenSavedYet": "Промяната все още не е запазена", "Backups": "Архиви", "BeforeUpdate": "Преди актуализация", "CancelPendingTask": "Наистина ли искате да отмените тази чакаща задача?", @@ -69,5 +69,293 @@ "DeleteIndexerMessageText": "Наистина ли искате да изтриете индексатора '{0}'?", "DeleteTag": "Изтриване на маркера", "DeleteTagMessageText": "Наистина ли искате да изтриете маркера '{0}'?", - "DownloadClientCheckNoneAvailableMessage": "Няма наличен клиент за изтегляне" + "DownloadClientCheckNoneAvailableMessage": "Няма наличен клиент за изтегляне", + "IndexerProxyStatusCheckAllClientMessage": "Всички списъци са недостъпни поради неуспехи", + "LastWriteTime": "Време за последно писане", + "Columns": "Колони", + "EnableRss": "Активиране на RSS", + "Downloading": "Изтегляне", + "IndexerProxyStatusCheckSingleClientMessage": "Списъци, недостъпни поради неуспехи: {0}", + "Languages": "Езици", + "LogLevel": "Log Level", + "MovieIndexScrollTop": "Индекс на филма: Превъртете отгоре", + "Movies": "Филми", + "Queue": "Опашка", + "ReadTheWikiForMoreInformation": "Прочетете Wiki за повече информация", + "Reddit": "Reddit", + "Refresh": "Обнови", + "RefreshMovie": "Опресняване на филма", + "Reload": "Презаредете", + "RemovedFromTaskQueue": "Премахнато от опашката на задачите", + "RemoveFilter": "Отстранете филтъра", + "RestoreBackup": "Възстанови архива", + "Restrictions": "Ограничения", + "Result": "Резултат", + "Save": "Запазете", + "SaveChanges": "Запазите промените", + "SelectAll": "Избери всичко", + "SendAnonymousUsageData": "Изпращане на анонимни данни за използване", + "SetTags": "Задаване на маркери", + "SettingsEnableColorImpairedMode": "Активирайте режима с увредени цветове", + "Logs": "Дневници", + "LogFiles": "Лог файлове", + "MoreInfo": "Повече информация", + "SSLPort": "SSL порт", + "Status": "Състояние", + "System": "Система", + "SystemTimeCheckMessage": "Системното време е изключено с повече от 1 ден. Планираните задачи може да не се изпълняват правилно, докато времето не бъде коригирано", + "TestAll": "Тествайте всички", + "Title": "Заглавие", + "Today": "Днес", + "Tomorrow": "Утре", + "Torrents": "Торенти", + "Type": "Тип", + "UILanguageHelpText": "Език, който Radarr ще използва за потребителски интерфейс", + "UnableToAddANewIndexerPleaseTryAgain": "Не може да се добави нов индексатор, моля, опитайте отново.", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Не може да се добави нов индексатор, моля, опитайте отново.", + "UnableToAddANewNotificationPleaseTryAgain": "Не може да се добави ново известие, моля, опитайте отново.", + "UnableToLoadQualityDefinitions": "Определенията за качество не могат да се заредят", + "UpdateAutomaticallyHelpText": "Автоматично изтегляне и инсталиране на актуализации. Все още ще можете да инсталирате от System: Updates", + "UpdateCheckStartupTranslocationMessage": "Не може да се инсталира актуализация, защото стартовата папка „{0}“ е в папка за преместване на приложения.", + "ReleaseStatus": "Състояние на освобождаване", + "UpdateScriptPathHelpText": "Път към персонализиран скрипт, който взема извлечен пакет за актуализация и обработва останалата част от процеса на актуализация", + "UseProxy": "Използвай прокси", + "Username": "Потребителско име", + "Version": "Версия", + "Usenet": "Usenet", + "YesCancel": "Да, Отказ", + "Yesterday": "Вчера", + "Security": "Сигурност", + "StartupDirectory": "Стартова директория", + "Disabled": "хора с увреждания", + "EditIndexer": "Редактиране на Indexer", + "EnableAutomaticSearchHelpTextWarning": "Ще се използва, когато се използва интерактивно търсене", + "Enabled": "Активирано", + "General": "Общ", + "Grabbed": "Грабната", + "Grabs": "Грабнете", + "Health": "Здраве", + "HealthNoIssues": "Няма проблеми с вашата конфигурация", + "HomePage": "Начална страница", + "Hostname": "Име на хост", + "IgnoredAddresses": "Игнорирани адреси", + "IllRestartLater": "Ще рестартирам по-късно", + "IndexerPriority": "Индексатор Приоритет", + "Info": "Информация", + "InteractiveSearch": "Интерактивно търсене", + "Interval": "Интервал", + "KeyboardShortcuts": "Комбинация от клавиши", + "Language": "Език", + "LogLevelTraceHelpTextWarning": "Регистрацията на проследяване трябва да бъде разрешена само временно", + "Manual": "Ръчно", + "MaximumLimits": "Максимални граници", + "Mechanism": "Механизъм", + "Message": "Съобщение", + "MIA": "МВР", + "MinutesHundredTwenty": "120 минути: {0}", + "NoChange": "Няма промяна", + "NoChanges": "Без промени", + "NoLeaveIt": "Не, оставете го", + "NoLogFiles": "Няма регистрационни файлове", + "NoMinimumForAnyRuntime": "Няма минимум за всяко време на изпълнение", + "RestartRequiredHelpTextWarning": "Изисква рестартиране, за да влезе в сила", + "SettingsShortDateFormat": "Формат на кратка дата", + "SSLCertPath": "SSL Cert Path", + "URLBase": "URL база", + "CloneIndexer": "Clone Indexer", + "CloneProfile": "Профил на клониране", + "EnableInteractiveSearch": "Активирайте интерактивно търсене", + "TagIsNotUsedAndCanBeDeleted": "Етикетът не се използва и може да бъде изтрит", + "Time": "Време", + "Torrent": "Торенти", + "UILanguageHelpTextWarning": "Необходимо е презареждане на браузъра", + "UISettings": "Настройки на потребителския интерфейс", + "UnableToAddANewApplicationPleaseTryAgain": "Не може да се добави ново известие, моля, опитайте отново.", + "UnableToAddANewAppProfilePleaseTryAgain": "Не може да се добави нов качествен профил, моля, опитайте отново.", + "UnableToLoadBackups": "Архивите не могат да се заредят", + "AllIndexersHiddenDueToFilter": "Всички филми са скрити поради приложен филтър.", + "Level": "Ниво", + "MinimumLimits": "Минимални лимити", + "ApplicationStatusCheckAllClientMessage": "Всички списъци са недостъпни поради неуспехи", + "ApplicationStatusCheckSingleClientMessage": "Списъци, недостъпни поради неуспехи: {0}", + "Close": "Близо", + "CloseCurrentModal": "Затворете текущия режим", + "DeleteApplicationMessageText": "Наистина ли искате да изтриете известието '{0}'?", + "DeleteIndexerProxyMessageText": "Наистина ли искате да изтриете маркера '{0}'?", + "Discord": "Раздор", + "Docker": "Докер", + "DownloadClients": "Изтеглете клиенти", + "EnableInteractiveSearchHelpText": "Ще се използва, когато се използва интерактивно търсене", + "NoBackupsAreAvailable": "Няма налични резервни копия", + "RemovingTag": "Премахване на етикет", + "Reset": "Нулиране", + "Retention": "Задържане", + "RSS": "RSS", + "Warn": "Предупреждавайте", + "NoTagsHaveBeenAddedYet": "Все още не са добавени етикети", + "NotificationTriggers": "Задействания за уведомяване", + "NoUpdatesAreAvailable": "Няма налични актуализации", + "OAuthPopupMessage": "Изскачащите прозорци се блокират от вашия браузър", + "Ok": "Добре", + "OnHealthIssueHelpText": "По здравен въпрос", + "OpenBrowserOnStart": "Отворете браузъра при стартиране", + "OpenThisModal": "Отворете този модал", + "Options": "Настроики", + "PackageVersion": "Версия на пакета", + "PageSize": "Размер на страницата", + "PendingChangesStayReview": "Останете и прегледайте промените", + "PreferredSize": "Предпочитан размер", + "Presets": "Предварителни настройки", + "Priority": "Приоритет", + "PrioritySettings": "Приоритет", + "PtpOldSettingsCheckMessage": "Следните индексатори PassThePopcorn са оттеглени и трябва да бъдат актуализирани: {0}", + "SettingsLongDateFormat": "Формат с дълга дата", + "SettingsShowRelativeDates": "Показване на относителни дати", + "UnableToLoadDownloadClients": "Клиентите за изтегляне не могат да се заредят", + "DelayProfile": "Профил за забавяне", + "Logging": "Регистрация", + "Exception": "Изключение", + "MinutesNinety": "90 минути: {0}", + "MinutesSixty": "60 минути: {0}", + "MovieDetailsNextMovie": "Подробности за филма: Следващ филм", + "MovieDetailsPreviousMovie": "Подробности за филма: Предишен филм", + "MovieIndexScrollBottom": "Индекс на филма: Превъртане отдолу", + "Name": "Име", + "New": "Ново", + "NoLinks": "Няма връзки", + "PendingChangesMessage": "Имате незапазени промени. Наистина ли искате да напуснете тази страница?", + "Port": "Порт", + "PortNumber": "Номер на пристанище", + "Proxy": "Прокси", + "ProxyBypassFilterHelpText": "Използвайте „,“ като разделител и „*“. като заместващ знак за поддомейни", + "ProxyCheckBadRequestMessage": "Неуспешно тестване на прокси. Код на състоянието: {0}", + "ProxyCheckFailedToTestMessage": "Неуспешно тестване на прокси: {0}", + "ProxyCheckResolveIpMessage": "Неуспешно разрешаване на IP адреса за конфигурирания прокси хост {0}", + "ProxyPasswordHelpText": "Трябва само да въведете потребителско име и парола, ако е необходимо. В противен случай ги оставете празни.", + "ProxyType": "Тип прокси", + "ExistingMovies": "Съществуващи филми", + "ExistingTag": "Съществуващ маркер", + "ProxyUsernameHelpText": "Трябва само да въведете потребителско име и парола, ако е необходимо. В противен случай ги оставете празни.", + "QualityDefinitions": "Определения за качество", + "QualitySettings": "Настройки за качество", + "Importing": "Импортиране", + "ReleaseBranchCheckOfficialBranchMessage": "Клон {0} не е валиден клон за издаване на Radarr, няма да получавате актуализации", + "IncludeHealthWarningsHelpText": "Включете здравни предупреждения", + "SaveSettings": "Запазване на настройките", + "Scheduled": "Планиран", + "ScriptPath": "Път на скрипта", + "Search": "Търсене", + "Seeders": "Сеялки", + "Settings": "Настройки", + "SettingsEnableColorImpairedModeHelpText": "Променен стил, за да позволи на потребителите с увредени цветове да разграничат по-добре информацията, кодирана в цвят", + "SettingsShowRelativeDatesHelpText": "Показване на относителни (днес / вчера / и т.н.) или абсолютни дати", + "SettingsTimeFormat": "Времеви формат", + "ShowAdvanced": "Показване на напреднали", + "ShownClickToHide": "Показано, щракнете, за да се скриете", + "ShowSearch": "Показване на търсене", + "ShowSearchHelpText": "Показване на бутона за търсене при нанасяне на курсора на мишката", + "Shutdown": "Изключвам", + "Size": "Размер", + "Sort": "Вид", + "Source": "Източник", + "SSLCertPassword": "SSL сертификатна парола", + "SSLCertPasswordHelpText": "Парола за pfx файл", + "StartTypingOrSelectAPathBelow": "Започнете да пишете или изберете път отдолу", + "Style": "Стил", + "SuggestTranslationChange": "Предложете промяна на превода", + "TableOptions": "Опции на таблицата", + "TableOptionsColumnsMessage": "Изберете кои колони да се виждат и в кой ред да се показват", + "TagCannotBeDeletedWhileInUse": "Не може да се изтрие, докато се използва", + "Tags": "Етикети", + "TagsHelpText": "Прилага се за филми с поне един съвпадащ маркер", + "Tasks": "Задачи", + "Test": "Тест", + "UI": "Потребителски интерфейс", + "UILanguage": "Език на потребителския интерфейс", + "UpdateCheckStartupNotWritableMessage": "Не може да се инсталира актуализация, тъй като стартовата папка „{0}“ не може да се записва от потребителя „{1}“.", + "UpdateCheckUINotWritableMessage": "Не може да се инсталира актуализация, защото папката „{0}“ на потребителския интерфейс не може да се записва от потребителя „{1}“.", + "Enable": "Активиране", + "EnableColorImpairedMode": "Активирайте режима с увредени цветове", + "EnableColorImpairedModeHelpText": "Променен стил, за да позволи на потребителите с увредени цветове да разграничат по-добре информацията, кодирана в цвят", + "EventType": "Тип на събитието", + "Failed": "Се провали", + "FeatureRequests": "Заявки за функции", + "Filename": "Име на файл", + "Files": "Файлове", + "Filter": "Филтър", + "Fixed": "Фиксирана", + "FocusSearchBox": "Фокусно поле за търсене", + "HiddenClickToShow": "Скрито, кликнете за показване", + "HideAdvanced": "Скрий Разширено", + "Indexer": "Индексатор", + "IndexerFlags": "Индексиращи знамена", + "IndexerLongTermStatusCheckAllClientMessage": "Всички индексатори са недостъпни поради грешки за повече от 6 часа", + "SSLCertPathHelpText": "Път към pfx файл", + "UrlBaseHelpText": "За обратна поддръжка на прокси по подразбиране е празно", + "View": "Изглед", + "ApplyTagsHelpTexts1": "Как да приложите тагове към избраните филми", + "BranchUpdate": "Клон, който да се използва за актуализиране на Radarr", + "Indexers": "Индексатори", + "IndexerStatusCheckAllClientMessage": "Всички индексатори са недостъпни поради грешки", + "Mode": "Режим", + "MonoTlsCheckMessage": "Работното решение на Radarr Mono 4.x tls все още е активирано, помислете за премахване на MONO_TLS_PROVIDER = опция за наследствена среда", + "MonoVersion": "Моно версия", + "MonoVersionCheckUpgradeRecommendedMessage": "Понастоящем инсталираната моно версия {0} се поддържа, но се препоръчва надстройка до {1}.", + "NoLimitForAnyRuntime": "Няма ограничение за всяко време на изпълнение", + "TagsSettingsSummary": "Вижте всички тагове и как се използват. Неизползваните маркери могат да бъдат премахнати", + "TestAllClients": "Тествайте всички клиенти", + "UnableToAddANewDownloadClientPleaseTryAgain": "Не може да се добави нов клиент за изтегляне, моля, опитайте отново.", + "UnableToLoadTags": "Не може да се заредят маркери", + "UnableToLoadUISettings": "Настройките на потребителския интерфейс не могат да се заредят", + "UnsavedChanges": "Незапазени промени", + "UnselectAll": "Деселектирайте всички", + "UpdateMechanismHelpText": "Използвайте вградения в Radarr актуализатор или скрипт", + "Updates": "Актуализации", + "Uptime": "Време за работа", + "DownloadClientSettings": "Изтеглете настройките на клиента", + "DownloadClientStatusCheckAllClientMessage": "Всички клиенти за изтегляне са недостъпни поради неуспехи", + "DownloadClientStatusCheckSingleClientMessage": "Клиентите за изтегляне са недостъпни поради грешки: {0}", + "DownloadClientUnavailable": "Клиентът за изтегляне не е наличен", + "Edit": "редактиране", + "EnableAutoHelpText": "Ако е активирано, Филмите ще бъдат автоматично добавени към Radarr от този списък", + "EnableAutomaticAdd": "Активирайте автоматичното добавяне", + "EnableAutomaticSearch": "Активирайте автоматичното търсене", + "EnableAutomaticSearchHelpText": "Ще се използва, когато се извършват автоматични търсения чрез потребителския интерфейс или от Radarr", + "EnableCompletedDownloadHandlingHelpText": "Автоматично импортирайте завършени изтегляния от клиент за изтегляне", + "EnabledHelpText": "Активирайте този списък за използване в Radarr", + "EnableHelpText": "Активирайте създаването на файл с метаданни за този тип метаданни", + "EnableInteractiveSearchHelpTextWarning": "Търсенето не се поддържа с този индексатор", + "EnableMediaInfoHelpText": "Извличайте видео информация като резолюция, време на работа и информация за кодеци от файлове. Това изисква от Radarr да чете части от файла, които могат да причинят висока активност на диска или мрежата по време на сканиране.", + "EnableSSL": "Активирайте SSL", + "EnableSslHelpText": " Изисква рестартиране, изпълнено като администратор, за да влезе в сила", + "Error": "Грешка", + "ErrorLoadingContents": "Грешка при зареждането на съдържанието", + "Events": "Събития", + "Folder": "Папка", + "ForMoreInformationOnTheIndividualDownloadClients": "За повече информация относно отделните клиенти за изтегляне щракнете върху информационните бутони.", + "GeneralSettings": "Основни настройки", + "GeneralSettingsSummary": "Порт, SSL, потребителско име / парола, прокси, анализи и актуализации", + "History": "История", + "Host": "Водещ", + "IndexerLongTermStatusCheckSingleClientMessage": "Индексатори не са налични поради неуспехи за повече от 6 часа: {0}", + "IndexerPriorityHelpText": "Приоритет на индексатора от 1 (най-висок) до 50 (най-нисък). По подразбиране: 25.", + "IndexerStatusCheckSingleClientMessage": "Индексатори не са налични поради грешки: {0}", + "LaunchBrowserHelpText": " Отворете уеб браузър и отворете началната страница на Radarr при стартиране на приложението.", + "ResetAPIKey": "Нулиране на API ключ", + "Restart": "Рестартирам", + "RestartNow": "Рестартирай сега", + "Restore": "Възстанови", + "RSSIsNotSupportedWithThisIndexer": "RSS не се поддържа с този индексатор", + "Wiki": "Wiki", + "PageSizeHelpText": "Брой елементи за показване на всяка страница", + "Password": "Парола", + "Peers": "Връстници", + "Pending": "В очакване", + "PendingChangesDiscardChanges": "Изхвърлете промените и оставете", + "PriorityHelpText": "Приоритизирайте множество клиенти за изтегляне. Round-Robin се използва за клиенти със същия приоритет.", + "Protocol": "Протокол", + "UnableToLoadGeneralSettings": "Не може да се заредят общи настройки", + "UnableToLoadHistory": "Историята не може да се зареди", + "UnableToLoadIndexers": "Индексаторите не могат да се заредят", + "UnableToLoadNotifications": "Известията не могат да се заредят" } diff --git a/src/NzbDrone.Core/Localization/Core/ca.json b/src/NzbDrone.Core/Localization/Core/ca.json index 10b68eef4..ec9f77a0e 100644 --- a/src/NzbDrone.Core/Localization/Core/ca.json +++ b/src/NzbDrone.Core/Localization/Core/ca.json @@ -3,5 +3,11 @@ "Add": "Afegeix", "Actions": "Accions", "AcceptConfirmationModal": "Accepta el mètode de confirmació", - "About": "Quant a" + "About": "Quant a", + "Movies": "Pel·lícula", + "New": "Nou", + "Reload": "Recarregar", + "Queue": "Cua", + "Refresh": "Actualització", + "Password": "Contrassenya" } diff --git a/src/NzbDrone.Core/Localization/Core/cs.json b/src/NzbDrone.Core/Localization/Core/cs.json index 0967ef424..3467a6296 100644 --- a/src/NzbDrone.Core/Localization/Core/cs.json +++ b/src/NzbDrone.Core/Localization/Core/cs.json @@ -1 +1,361 @@ -{} +{ + "Add": "Přidat", + "CertificateValidation": "Ověření certifikátu", + "DeleteBackupMessageText": "Opravdu chcete smazat zálohu „{0}“?", + "YesCancel": "Ano, zrušit", + "About": "O", + "Component": "Součástka", + "Info": "Info", + "Languages": "Jazyky", + "LogFiles": "Záznam souborů", + "PrioritySettings": "Přednost", + "Logs": "Protokoly", + "ProxyBypassFilterHelpText": "Použijte ',' jako oddělovač a '*.' jako zástupný znak pro subdomény", + "QualityDefinitions": "Definice kvality", + "SaveSettings": "Uložit nastavení", + "Scheduled": "Naplánováno", + "ScriptPath": "Cesta skriptu", + "SetTags": "Nastavit značky", + "Settings": "Nastavení", + "StartTypingOrSelectAPathBelow": "Začněte psát nebo vyberte cestu níže", + "UnableToLoadIndexers": "Nelze načíst indexery", + "Usenet": "Usenet", + "AddDownloadClient": "Přidat staženého klienta", + "Backups": "Zálohy", + "CancelPendingTask": "Opravdu chcete zrušit tento nevyřízený úkol?", + "MovieIndexScrollBottom": "Rejstřík filmů: Posun dolů", + "ProxyType": "Typ serveru proxy", + "Reddit": "Reddit", + "DownloadClientUnavailable": "Stahovací klient není k dispozici", + "ErrorLoadingContents": "Chyba při načítání obsahu", + "IndexerLongTermStatusCheckAllClientMessage": "Všechny indexery nejsou k dispozici z důvodu selhání po dobu delší než 6 hodin", + "MonoVersion": "Mono verze", + "RemovedFromTaskQueue": "Odebráno z fronty úkolů", + "ResetAPIKey": "Resetovat klíč API", + "SSLCertPassword": "Heslo SSL Cert", + "SSLPort": "Port SSL", + "TableOptions": "Možnosti tabulky", + "UnableToAddANewNotificationPleaseTryAgain": "Nelze přidat nové oznámení, zkuste to znovu.", + "UnableToLoadHistory": "Nelze načíst historii", + "View": "Pohled", + "Warn": "Varovat", + "Wiki": "Wiki", + "Connections": "Připojení", + "DeleteDownloadClientMessageText": "Opravdu chcete odstranit klienta pro stahování „{0}“?", + "Details": "Detaily", + "Disabled": "Zakázáno", + "Docker": "Přístavní dělník", + "Donations": "Dary", + "DownloadClientSettings": "Stáhněte si nastavení klienta", + "DownloadClientStatusCheckAllClientMessage": "Všichni klienti pro stahování nejsou kvůli chybám k dispozici", + "DownloadClientStatusCheckSingleClientMessage": "Stahování klientů není k dispozici z důvodu selhání: {0}", + "Downloading": "Stahování", + "Folder": "Složka", + "Grabs": "Urvat", + "HealthNoIssues": "Žádné problémy s vaší konfigurací", + "HiddenClickToShow": "Skryté, kliknutím zobrazíte", + "HideAdvanced": "Skrýt pokročilé", + "Host": "Hostitel", + "Hostname": "Název hostitele", + "IncludeHealthWarningsHelpText": "Zahrnout zdravotní varování", + "Indexer": "Indexer", + "IndexerFlags": "Příznaky indexeru", + "IndexerPriority": "Priorita indexování", + "IndexerPriorityHelpText": "Priorita indexování od 1 (nejvyšší) do 50 (nejnižší). Výchozí: 25.", + "Indexers": "Indexery", + "IndexerStatusCheckAllClientMessage": "Všechny indexery nejsou k dispozici z důvodu selhání", + "LastWriteTime": "Čas posledního zápisu", + "Level": "Úroveň", + "LogLevel": "Úroveň protokolu", + "Manual": "Manuál", + "MaximumLimits": "Maximální limity", + "Message": "Zpráva", + "MIA": "MIA", + "Mode": "Režim", + "NoTagsHaveBeenAddedYet": "Zatím nebyly přidány žádné značky", + "NoMinimumForAnyRuntime": "Žádné minimum za běhu", + "Ok": "OK", + "SendAnonymousUsageData": "Odesílejte anonymní údaje o používání", + "UnselectAll": "Odznačit vše", + "UpdateCheckStartupNotWritableMessage": "Aktualizaci nelze nainstalovat, protože spouštěcí složku „{0}“ nelze zapisovat uživatelem „{1}“.", + "Version": "Verze", + "AnalyticsEnabledHelpText": "Odesílejte anonymní informace o použití a chybách na servery Radarru. To zahrnuje informace o vašem prohlížeči, které stránky Radarr WebUI používáte, hlášení chyb a také verzi operačního systému a běhového prostředí. Tyto informace použijeme k upřednostnění funkcí a oprav chyb.", + "ApiKey": "Klíč API", + "AppDataDirectory": "Adresář AppData", + "AppDataLocationHealthCheckMessage": "Aktualizace nebude možné zabránit smazání AppData při aktualizaci", + "ApplicationStatusCheckAllClientMessage": "Všechny seznamy nejsou k dispozici z důvodu selhání", + "ApplicationStatusCheckSingleClientMessage": "Seznamy nejsou k dispozici z důvodu selhání: {0}", + "Apply": "Aplikovat", + "ApplyTagsHelpTexts2": "Přidat: Přidejte značky do existujícího seznamu značek", + "ApplyTagsHelpTexts1": "Jak použít značky na vybrané filmy", + "Branch": "Větev", + "BranchUpdate": "Pobočka, která se má použít k aktualizaci Radarr", + "EditIndexer": "Upravit indexátor", + "EnableColorImpairedModeHelpText": "Upravený styl umožňující uživatelům s barevným postižením lépe rozlišovat barevně kódované informace", + "EnableCompletedDownloadHandlingHelpText": "Automaticky importovat dokončená stahování z klienta pro stahování", + "EnabledHelpText": "Povolte tento seznam pro použití v Radarru", + "EnableHelpText": "Povolit vytváření souborů metadat pro tento typ metadat", + "ForMoreInformationOnTheIndividualDownloadClients": "Další informace o jednotlivých klientech pro stahování získáte kliknutím na informační tlačítka.", + "General": "Všeobecné", + "ApplyTagsHelpTexts3": "Odebrat: Odebere zadané značky", + "CloseCurrentModal": "Zavřít aktuální modální", + "Columns": "Sloupce", + "ConnectionLost": "Spojení ztraceno", + "ConnectSettings": "Připojit nastavení", + "Custom": "Zvyk", + "EnableAutomaticAdd": "Povolit automatické přidání", + "Error": "Chyba", + "Failed": "Selhalo", + "FeatureRequests": "Žádosti o funkce", + "Filename": "Název souboru", + "Files": "Soubory", + "Filter": "Filtr", + "Fixed": "Pevný", + "FocusSearchBox": "Zaostřovací vyhledávací pole", + "GeneralSettingsSummary": "Port, SSL, uživatelské jméno / heslo, proxy, analytika a aktualizace", + "History": "Dějiny", + "HomePage": "Domovská stránka", + "SettingsEnableColorImpairedModeHelpText": "Upravený styl umožňující uživatelům s barevným postižením lépe rozlišovat barevně kódované informace", + "SettingsLongDateFormat": "Long Date Format", + "SettingsShortDateFormat": "Formát krátkého data", + "Shutdown": "Vypnout", + "TagsHelpText": "Platí pro filmy s alespoň jednou shodnou značkou", + "Tasks": "Úkoly", + "Test": "Test", + "UnableToLoadTags": "Značky nelze načíst", + "IndexerProxyStatusCheckAllClientMessage": "Všechny indexery nejsou k dispozici z důvodu selhání", + "ApplyTags": "Použít značky", + "MoreInfo": "Více informací", + "System": "Systém", + "EnableAutomaticSearchHelpTextWarning": "Bude použito při použití interaktivního vyhledávání", + "EnableColorImpairedMode": "Aktivujte režim se sníženou barevností", + "Enabled": "Povoleno", + "IgnoredAddresses": "Ignorované adresy", + "AcceptConfirmationModal": "Přijměte potvrzení Modal", + "Actions": "Akce", + "Added": "Přidané", + "AddIndexer": "Přidat indexátor", + "LaunchBrowserHelpText": " Otevřete webový prohlížeč a při spuštění aplikace přejděte na domovskou stránku Radarr.", + "Logging": "Protokolování", + "Mechanism": "Mechanismus", + "MinutesNinety": "90 minut: {0}", + "MinutesSixty": "60 minut: {0}", + "MonoTlsCheckMessage": "Řešení Radarr Mono 4.x tls je stále povoleno, zvažte odebrání MONO_TLS_PROVIDER = možnost staršího prostředí", + "MonoVersionCheckUpgradeRecommendedMessage": "Aktuálně nainstalovaná mono verze {0} je podporována, ale doporučuje se upgradovat na {1}.", + "MovieDetailsNextMovie": "Detaily filmu: Další film", + "MovieDetailsPreviousMovie": "Detaily filmu: Předchozí film", + "Movies": "Filmy", + "NoLimitForAnyRuntime": "Žádné omezení za běhu", + "NoLinks": "Žádné odkazy", + "PreferredSize": "Preferovaná velikost", + "Presets": "Předvolby", + "Priority": "Přednost", + "PriorityHelpText": "Upřednostněte více klientů pro stahování. Round-Robin se používá pro klienty se stejnou prioritou.", + "Grabbed": "Popadl", + "Health": "Zdraví", + "LogLevelTraceHelpTextWarning": "Trasování protokolování by mělo být povoleno pouze dočasně", + "ProxyCheckBadRequestMessage": "Nepodařilo se otestovat proxy. StatusCode: {0}", + "ProxyCheckFailedToTestMessage": "Nepodařilo se otestovat proxy: {0}", + "ProxyCheckResolveIpMessage": "Nepodařilo se vyřešit adresu IP konfigurovaného hostitele proxy {0}", + "ProxyPasswordHelpText": "Musíte pouze zadat uživatelské jméno a heslo, pokud je požadováno. Jinak je nechte prázdné.", + "ProxyUsernameHelpText": "Musíte pouze zadat uživatelské jméno a heslo, pokud je požadováno. Jinak je nechte prázdné.", + "PtpOldSettingsCheckMessage": "Následující indexovače PassThePopcorn mají zastaralá nastavení a měla by být aktualizována: {0}", + "QualitySettings": "Nastavení kvality", + "Queue": "Fronta", + "ReadTheWikiForMoreInformation": "Další informace najdete na Wiki", + "Refresh": "Obnovit", + "RefreshMovie": "Obnovit film", + "MovieIndexScrollTop": "Rejstřík filmů: Posun nahoru", + "ReleaseBranchCheckOfficialBranchMessage": "Pobočka {0} není platná větev vydání Radarr, nebudete dostávat aktualizace", + "ReleaseStatus": "Stav vydání", + "Proxy": "Proxy", + "Reload": "Znovu načíst", + "SaveChanges": "Uložit změny", + "Search": "Vyhledávání", + "Security": "Bezpečnostní", + "Seeders": "Secí stroje", + "SelectAll": "Vybrat vše", + "SettingsEnableColorImpairedMode": "Aktivujte režim se sníženou barevností", + "Sort": "Třídit", + "Source": "Zdroj", + "StartupDirectory": "Spouštěcí adresář", + "Status": "Postavení", + "Style": "Styl", + "SuggestTranslationChange": "Navrhnout změnu překladu", + "TableOptionsColumnsMessage": "Vyberte, které sloupce jsou viditelné a v jakém pořadí se zobrazují", + "TagCannotBeDeletedWhileInUse": "Během používání nelze smazat", + "TagIsNotUsedAndCanBeDeleted": "Značka se nepoužívá a lze ji smazat", + "Tags": "Značky", + "UILanguageHelpTextWarning": "Vyžaduje se opětovné načtení prohlížeče", + "UnableToAddANewApplicationPleaseTryAgain": "Nelze přidat nové oznámení, zkuste to znovu.", + "UnableToAddANewAppProfilePleaseTryAgain": "Nelze přidat nový kvalitní profil, zkuste to znovu.", + "UnableToAddANewDownloadClientPleaseTryAgain": "Nelze přidat nového klienta pro stahování, zkuste to znovu.", + "UnableToAddANewIndexerPleaseTryAgain": "Nelze přidat nový indexer, zkuste to znovu.", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Nelze přidat nový indexer, zkuste to znovu.", + "UnableToLoadNotifications": "Nelze načíst oznámení", + "UnableToLoadQualityDefinitions": "Nelze načíst definice kvality", + "UpdateCheckStartupTranslocationMessage": "Aktualizaci nelze nainstalovat, protože spouštěcí složka „{0}“ je ve složce Translocation aplikace.", + "UpdateCheckUINotWritableMessage": "Aktualizaci nelze nainstalovat, protože uživatelská složka „{0}“ není zapisovatelná uživatelem „{1}“.", + "UpdateMechanismHelpText": "Použijte vestavěný aktualizátor Radarr nebo skript", + "UpdateScriptPathHelpText": "Cesta k vlastnímu skriptu, který přebírá extrahovaný balíček aktualizace a zpracovává zbytek procesu aktualizace", + "Uptime": "Provozuschopnost", + "URLBase": "URL Base", + "UrlBaseHelpText": "Pro podporu reverzního proxy je výchozí hodnota prázdná", + "UseProxy": "Použij proxy", + "Username": "Uživatelské jméno", + "Yesterday": "Včera", + "AutomaticSearch": "Automatické vyhledávání", + "BackupFolderHelpText": "Relativní cesty budou v adresáři AppData společnosti Radarr", + "BackupIntervalHelpText": "Interval mezi automatickými zálohami", + "BackupNow": "Zálohovat hned", + "BackupRetentionHelpText": "Automatické zálohy starší než doba uchování budou automaticky vyčištěny", + "BeforeUpdate": "Před aktualizací", + "BindAddress": "Vazba adresy", + "BindAddressHelpText": "Platná adresa IP4 nebo '*' pro všechna rozhraní", + "BranchUpdateMechanism": "Pobočka používaná mechanismem externí aktualizace", + "BypassProxyForLocalAddresses": "Obejít proxy pro místní adresy", + "DeleteIndexerProxyMessageText": "Opravdu chcete smazat značku „{0}“?", + "DeleteTag": "Smazat značku", + "IndexerProxyStatusCheckSingleClientMessage": "Indexery nedostupné z důvodu selhání: {0}", + "Name": "název", + "New": "Nový", + "Protocol": "Protokol", + "RemoveFilter": "Vyjměte filtr", + "RemovingTag": "Odebírání značky", + "Reset": "Resetovat", + "Restart": "Restartujte", + "RestartNow": "Restartovat nyní", + "RestoreBackup": "Obnovit zálohu", + "Restrictions": "Omezení", + "RSSIsNotSupportedWithThisIndexer": "RSS není u tohoto indexeru podporováno", + "Save": "Uložit", + "SSLCertPasswordHelpText": "Heslo pro soubor pfx", + "SSLCertPath": "Cesta certifikátu SSL", + "SSLCertPathHelpText": "Cesta k souboru pfx", + "UnableToLoadBackups": "Nelze načíst zálohy", + "UnableToLoadDownloadClients": "Nelze načíst klienty pro stahování", + "UnableToLoadGeneralSettings": "Nelze načíst obecná nastavení", + "DeleteIndexer": "Odstranit indexer", + "DeleteIndexerMessageText": "Opravdu chcete odstranit indexer „{0}“?", + "DeleteNotification": "Smazat oznámení", + "EnableAutomaticSearch": "Povolit automatické vyhledávání", + "EnableInteractiveSearchHelpText": "Bude použito při použití interaktivního vyhledávání", + "GeneralSettings": "Obecné nastavení", + "InteractiveSearch": "Interaktivní vyhledávání", + "Interval": "Interval", + "KeyboardShortcuts": "Klávesové zkratky", + "Language": "Jazyk", + "MinimumLimits": "Minimální limity", + "MinutesHundredTwenty": "120 minut: {0}", + "NoLogFiles": "Žádné soubory protokolu", + "NoBackupsAreAvailable": "Nejsou k dispozici žádné zálohy", + "NoChanges": "Žádné změny", + "NoLeaveIt": "Ne, nech to", + "PageSize": "Velikost stránky", + "PendingChangesMessage": "Máte neuložené změny. Opravdu chcete tuto stránku opustit?", + "PendingChangesStayReview": "Zůstaňte a zkontrolujte změny", + "Port": "Přístav", + "RestartRequiredHelpTextWarning": "Vyžaduje restart, aby se projevilo", + "Restore": "Obnovit", + "SettingsShowRelativeDates": "Zobrazit relativní data", + "SettingsShowRelativeDatesHelpText": "Zobrazit relativní (dnes / včera / atd.) Nebo absolutní data", + "SystemTimeCheckMessage": "Systémový čas je vypnutý o více než 1 den. Naplánované úlohy nemusí fungovat správně, dokud nebude čas opraven", + "AddingTag": "Přidávání značky", + "Age": "Stáří", + "All": "Všechno", + "AllIndexersHiddenDueToFilter": "Všechny filmy jsou skryty kvůli použitému filtru.", + "Analytics": "Analytics", + "EnableRss": "Povolit RSS", + "NoChange": "Žádná změna", + "ApplyTagsHelpTexts4": "Nahradit: Nahradit tagy zadanými tagy (pro vymazání všech tagů zadejte žádné tagy)", + "AreYouSureYouWantToResetYourAPIKey": "Opravdu chcete resetovat klíč API?", + "Authentication": "Ověření", + "AuthenticationMethodHelpText": "Vyžadovat uživatelské jméno a heslo pro přístup k Radarr", + "Automatic": "Automatický", + "Backup": "Záloha", + "Cancel": "zrušení", + "CertificateValidationHelpText": "Změňte, jak přísné je ověření certifikace HTTPS", + "ChangeHasNotBeenSavedYet": "Změna ještě nebyla uložena", + "Clear": "Průhledná", + "ClientPriority": "Priorita klienta", + "CloneIndexer": "Klonovat indexátor", + "CloneProfile": "Klonovat profil", + "Close": "Zavřít", + "ConnectionLostAutomaticMessage": "Radarr se pokusí připojit automaticky, nebo můžete kliknout na znovu načíst níže.", + "CouldNotConnectSignalR": "Nelze se připojit k SignalR, uživatelské rozhraní se neaktualizuje", + "CustomFilters": "Vlastní filtry", + "Date": "datum", + "Dates": "Termíny", + "DBMigration": "Migrace databáze", + "DelayProfile": "Zpožděný profil", + "Delete": "Vymazat", + "DeleteApplicationMessageText": "Opravdu chcete smazat oznámení „{0}“?", + "DeleteBackup": "Odstranit zálohu", + "DeleteDownloadClient": "Odstranit staženého klienta", + "DeleteNotificationMessageText": "Opravdu chcete smazat oznámení „{0}“?", + "DeleteTagMessageText": "Opravdu chcete smazat značku „{0}“?", + "Discord": "Svár", + "DownloadClient": "Stáhnout klienta", + "DownloadClientCheckNoneAvailableMessage": "Není k dispozici žádný klient pro stahování", + "DownloadClientCheckUnableToCommunicateMessage": "S uživatelem {0} nelze komunikovat.", + "DownloadClients": "Stáhnout klienty", + "Edit": "Upravit", + "Enable": "Umožnit", + "EnableAutoHelpText": "Pokud je tato možnost povolena, filmy budou automaticky přidány do Radarru z tohoto seznamu", + "EnableAutomaticSearchHelpText": "Použije se, když se automatické vyhledávání provádí pomocí uživatelského rozhraní nebo Radarr", + "EnableInteractiveSearch": "Povolit interaktivní vyhledávání", + "EnableInteractiveSearchHelpTextWarning": "Vyhledávání není u tohoto indexeru podporováno", + "EnableMediaInfoHelpText": "Extrahujte ze souborů informace o videu, jako je rozlišení, runtime a informace o kodeku. To vyžaduje, aby Radarr četl části souboru, což může během skenování způsobit vysokou aktivitu disku nebo sítě.", + "EnableSSL": "Povolit SSL", + "EnableSslHelpText": " Vyžaduje restartování spuštěné jako správce, aby se projevilo", + "Events": "Události", + "EventType": "Typ události", + "Exception": "Výjimka", + "ExistingMovies": "Stávající filmy", + "ExistingTag": "Stávající značka", + "IllRestartLater": "Restartuji později", + "Importing": "Import", + "IndexerLongTermStatusCheckSingleClientMessage": "Indexery nedostupné z důvodu selhání po dobu delší než 6 hodin: {0}", + "IndexerStatusCheckSingleClientMessage": "Indexery nedostupné z důvodu selhání: {0}", + "SettingsTimeFormat": "Časový formát", + "ShowAdvanced": "Zobrazit pokročilé", + "ShownClickToHide": "Zobrazeno, kliknutím se skryjete", + "ShowSearch": "Zobrazit vyhledávání", + "ShowSearchHelpText": "Zobrazit vyhledávací tlačítko při najetí myší", + "Size": "Velikost", + "Updates": "Aktualizace", + "NotificationTriggers": "Spouštěče oznámení", + "NoUpdatesAreAvailable": "Nejsou k dispozici žádné aktualizace", + "OAuthPopupMessage": "Vyskakovací okna jsou blokována vaším prohlížečem", + "OnHealthIssueHelpText": "K otázce zdraví", + "OpenBrowserOnStart": "Při spuštění otevřete prohlížeč", + "OpenThisModal": "Otevřete tento modální", + "Options": "Možnosti", + "PackageVersion": "Verze balíčku", + "PageSizeHelpText": "Počet položek, které se mají zobrazit na každé stránce", + "Password": "Heslo", + "Peers": "Vrstevníci", + "Pending": "čekající", + "PendingChangesDiscardChanges": "Zahodit změny a odejít", + "PortNumber": "Číslo portu", + "Result": "Výsledek", + "Retention": "Zadržení", + "RSS": "RSS", + "TagsSettingsSummary": "Podívejte se na všechny značky a na to, jak se používají. Nepoužité značky lze odstranit", + "TestAll": "Vyzkoušet vše", + "TestAllClients": "Vyzkoušejte všechny klienty", + "Time": "Čas", + "Title": "Titul", + "Today": "Dnes", + "Tomorrow": "Zítra", + "Torrent": "Torrenty", + "Torrents": "Torrenty", + "Type": "Typ", + "UI": "UI", + "UILanguage": "Jazyk uživatelského rozhraní", + "UILanguageHelpText": "Jazyk, který Radarr použije pro uživatelské rozhraní", + "UISettings": "Nastavení uživatelského rozhraní", + "UnableToLoadUISettings": "Nelze načíst nastavení uživatelského rozhraní", + "UnsavedChanges": "Neuložené změny", + "UpdateAutomaticallyHelpText": "Automaticky stahovat a instalovat aktualizace. Stále budete moci instalovat ze systému: Aktualizace" +} diff --git a/src/NzbDrone.Core/Localization/Core/da.json b/src/NzbDrone.Core/Localization/Core/da.json index bafe069f4..c62ab1fa7 100644 --- a/src/NzbDrone.Core/Localization/Core/da.json +++ b/src/NzbDrone.Core/Localization/Core/da.json @@ -6,11 +6,7 @@ "Info": "Information", "IndexerStatusCheckSingleClientMessage": "Indexere utilgængelige på grund af fejl: {0}", "IndexerStatusCheckAllClientMessage": "Alle indexere er utilgængelige på grund af fejl", - "IndexerSearchCheckNoAutomaticMessage": "Ingen indexere tilgængelige med Automatisk Søg aktiveret, Prowlarr vil ikke give nogle automatiske søge resultater", "Indexers": "Indexere", - "ImportTipsMessage": "Nogle tips for at sikre importeringen går glat:", - "ImportFirstTip": "Vær sikker på at dine filer inkluderer kvalitet i deres filnavn. f.eks.", - "Ignored": "Ignoreret", "History": "Historie", "HideAdvanced": "Gemt Avancerede", "HealthNoIssues": "Ingen problemer med din konfiguration", @@ -33,7 +29,6 @@ "DownloadClientCheckUnableToCommunicateMessage": "Ude af stand til at kommunikere med {0}.", "DownloadClientCheckNoneAvailableMessage": "Ingen download klient tilgængelig", "DownloadClient": "Download Klient", - "Discover": "Opdag", "Details": "Detaljer", "Delete": "Slet", "Dates": "Datoer", @@ -57,11 +52,314 @@ "Analytics": "Analyser", "All": "Alt", "Age": "Alder", - "AddNew": "Tilføj Ny", "Added": "Tilføjet", "Actions": "Handlinger", "About": "Om", "Disabled": "deaktiveret", "Add": "Tilføj", - "AddDownloadClient": "Tilføj downloadklient" + "AddDownloadClient": "Tilføj downloadklient", + "DBMigration": "DB Migration", + "DelayProfile": "Udskyd Profiler", + "MIA": "MIA", + "MovieDetailsNextMovie": "Filmoplysninger: Næste film", + "MovieDetailsPreviousMovie": "Filmdetaljer: Forrige film", + "ResetAPIKey": "Nulstil API-nøgle", + "SettingsTimeFormat": "Tidsformat", + "SystemTimeCheckMessage": "Systemtiden er slukket mere end 1 dag. Planlagte opgaver kører muligvis ikke korrekt, før tiden er rettet", + "UnsavedChanges": "Ugemte ændringer", + "Updates": "Opdateringer", + "MoreInfo": "Mere info", + "Queue": "Kø", + "Sort": "Sortere", + "UILanguageHelpTextWarning": "Browser genindlæsning påkrævet", + "UnableToLoadHistory": "Kunne ikke indlæse historikken", + "UseProxy": "Brug proxy", + "Settings": "Indstillinger", + "Grabs": "Tag fat", + "Level": "Niveau", + "NoChange": "Ingen ændring", + "ProxyType": "Proxy-type", + "Proxy": "Proxy", + "TagIsNotUsedAndCanBeDeleted": "Tag bruges ikke og kan slettes", + "Tags": "Mærker", + "Tasks": "Opgaver", + "UILanguage": "UI-sprog", + "Custom": "Brugerdefinerede", + "PrioritySettings": "Prioritet", + "TagsSettingsSummary": "Se alle tags og hvordan de bruges. Ubrugte tags kan fjernes", + "Test": "Prøve", + "TestAll": "Test alle", + "TestAllClients": "Test alle klienter", + "Type": "Type", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Kunne ikke tilføje en ny indekser. Prøv igen.", + "UnableToAddANewNotificationPleaseTryAgain": "Kan ikke tilføje en ny underretning, prøv igen.", + "Usenet": "Usenet", + "Username": "Brugernavn", + "Version": "Version", + "Wiki": "Wiki", + "HiddenClickToShow": "Skjult, klik for at vise", + "Result": "Resultat", + "SetTags": "Indstil tags", + "YesCancel": "Ja, Annuller", + "AcceptConfirmationModal": "Accepter bekræftelsesmodal", + "AddIndexer": "Tilføj indexer", + "AnalyticsEnabledHelpText": "Send anonym brugs- og fejlinformation til Radarrs servere. Dette inkluderer information i din browser, hvilke Radarr WebUI-sider du bruger, fejlrapportering samt OS og runtime-version. Vi bruger disse oplysninger til at prioritere funktioner og fejlrettelser.", + "ApplyTagsHelpTexts4": "Erstat: Udskift tags med de indtastede tags (indtast ingen tags for at rydde alle tags)", + "Backups": "Sikkerhedskopier", + "BypassProxyForLocalAddresses": "Bypass-proxy til lokale adresser", + "CancelPendingTask": "Er du sikker på, at du vil annullere denne afventende opgave?", + "CertificateValidation": "Validering af certifikat", + "CloneIndexer": "Klonindekser", + "CloseCurrentModal": "Luk Nuværende Modal", + "CouldNotConnectSignalR": "Kunne ikke oprette forbindelse til SignalR, UI opdateres ikke", + "DeleteApplicationMessageText": "Er du sikker på, at du vil slette underretningen '{0}'?", + "DeleteDownloadClientMessageText": "Er du sikker på, at du vil slette downloadklienten '{0}'?", + "DeleteIndexer": "Slet Indexer", + "DeleteIndexerMessageText": "Er du sikker på, at du vil slette indeksøren '{0}'?", + "DeleteIndexerProxyMessageText": "Er du sikker på, at du vil slette tagget '{0}'?", + "DeleteNotification": "Slet underretning", + "DeleteNotificationMessageText": "Er du sikker på, at du vil slette underretningen '{0}'?", + "DeleteTag": "Slet tag", + "DeleteTagMessageText": "Er du sikker på, at du vil slette tagget '{0}'?", + "Discord": "Uenighed", + "Docker": "Docker", + "Donations": "Donationer", + "DownloadClientSettings": "Download klientindstillinger", + "DownloadClientUnavailable": "Downloadklienten er ikke tilgængelig", + "Downloading": "Downloader", + "EditIndexer": "Rediger indekser", + "Enable": "Aktiver", + "EnableAutoHelpText": "Hvis det er aktiveret, føjes film automatisk til Radarr fra denne liste", + "EnableAutomaticAdd": "Aktivér automatisk tilføjelse", + "EnableAutomaticSearch": "Aktivér automatisk søgning", + "EnableAutomaticSearchHelpText": "Bruges, når der foretages automatiske søgninger via brugergrænsefladen eller af Radarr", + "EnableAutomaticSearchHelpTextWarning": "Bruges, når der bruges interaktiv søgning", + "EnableColorImpairedMode": "Aktivér farve-nedsat tilstand", + "EnableColorImpairedModeHelpText": "Ændret stil for at give farvehæmmede brugere bedre at skelne mellem farvekodede oplysninger", + "EnableCompletedDownloadHandlingHelpText": "Importer automatisk afsluttede downloads fra downloadklienten", + "Enabled": "Aktiveret", + "EnableHelpText": "Aktivér oprettelse af metadatafiler for denne metadatatype", + "EnableInteractiveSearch": "Aktivér interaktiv søgning", + "EnableMediaInfoHelpText": "Uddrag videoinformation såsom opløsning, runtime og codec-oplysninger fra filer. Dette kræver, at Radarr læser dele af filen, som kan forårsage høj disk- eller netværksaktivitet under scanninger.", + "EnableRss": "Aktivér RSS", + "EnableSslHelpText": " Kræver genstart, der kører som administrator for at træde i kraft", + "ErrorLoadingContents": "Fejl ved indlæsning af indhold", + "Exception": "Undtagelse", + "ExistingMovies": "Eksisterende film", + "ExistingTag": "Eksisterende mærke", + "FeatureRequests": "Funktionsanmodninger", + "Filter": "Filter", + "Fixed": "Fast", + "FocusSearchBox": "Fokus søgefelt", + "ForMoreInformationOnTheIndividualDownloadClients": "Klik på informationsknapperne for at få flere oplysninger om de enkelte downloadklienter.", + "GeneralSettings": "Generelle indstillinger", + "HomePage": "Hjemmeside", + "Host": "Vært", + "Hostname": "Værtsnavn", + "IgnoredAddresses": "Ignorerede adresser", + "IllRestartLater": "Jeg genstarter senere", + "Importing": "Importerer", + "IncludeHealthWarningsHelpText": "Inkluder sundhedsadvarsler", + "Indexer": "Indekser", + "IndexerLongTermStatusCheckAllClientMessage": "Alle indeksatorer er ikke tilgængelige på grund af fejl i mere end 6 timer", + "IndexerLongTermStatusCheckSingleClientMessage": "Indeksatorer er ikke tilgængelige på grund af fejl i mere end 6 timer: {0}", + "IndexerPriority": "Indekseringsprioritet", + "IndexerPriorityHelpText": "Indekseringsprioritet fra 1 (højest) til 50 (lavest). Standard: 25.", + "IndexerProxyStatusCheckAllClientMessage": "Alle indexere er utilgængelige på grund af fejl", + "IndexerProxyStatusCheckSingleClientMessage": "Indexere utilgængelige på grund af fejl: {0}", + "LaunchBrowserHelpText": " Åbn en webbrowser, og naviger til Radarr-hjemmesiden ved start af appen.", + "Logging": "Logning", + "LogLevel": "Logniveau", + "LogLevelTraceHelpTextWarning": "Sporlogning bør kun aktiveres midlertidigt", + "Logs": "Logfiler", + "Manual": "brugervejledning", + "MaximumLimits": "Maksimale grænser", + "Mechanism": "Mekanisme", + "Message": "Besked", + "MinimumLimits": "Minimumsgrænser", + "MinutesHundredTwenty": "120 minutter: {0}", + "MinutesNinety": "90 minutter: {0}", + "MinutesSixty": "60 minutter: {0}", + "Mode": "Mode", + "MonoTlsCheckMessage": "Radarr Mono 4.x tls-løsning er stadig aktiveret, overvej at fjerne MONO_TLS_PROVIDER = ældre miljømulighed", + "MonoVersion": "Mono-version", + "MonoVersionCheckUpgradeRecommendedMessage": "Aktuelt installeret Mono-version {0} understøttes, men det anbefales at opgradere til {1}.", + "MovieIndexScrollBottom": "Filmindeks: Rul ned", + "MovieIndexScrollTop": "Filmindeks: Scroll Top", + "Name": "Navn", + "New": "Ny", + "NoBackupsAreAvailable": "Ingen sikkerhedskopier er tilgængelige", + "NoChanges": "Ingen ændringer", + "NoLeaveIt": "Nej, lad det være", + "NoLimitForAnyRuntime": "Ingen grænse for nogen runtime", + "NoLinks": "Ingen links", + "NoLogFiles": "Ingen logfiler", + "NoMinimumForAnyRuntime": "Intet minimum for enhver driftstid", + "NoTagsHaveBeenAddedYet": "Der er ikke tilføjet nogen tags endnu", + "NotificationTriggers": "Meddelelsesudløsere", + "OnHealthIssueHelpText": "Om sundhedsspørgsmål", + "OpenThisModal": "Åbn denne modal", + "PackageVersion": "Pakkeversion", + "PageSize": "Sidestørrelse", + "Pending": "Verserende", + "PendingChangesDiscardChanges": "Kassér ændringer og gå ud", + "PendingChangesMessage": "Du har ikke gemte ændringer. Er du sikker på, at du vil forlade denne side?", + "PendingChangesStayReview": "Bliv og gennemgå ændringer", + "Port": "Havn", + "PortNumber": "Portnummer", + "PreferredSize": "Foretrukken størrelse", + "Priority": "Prioritet", + "Protocol": "Protokol", + "ProxyBypassFilterHelpText": "Brug ',' som en separator og '*.' som et jokertegn for underdomæner", + "ProxyCheckBadRequestMessage": "Kunne ikke teste proxy. Statuskode: {0}", + "ProxyCheckFailedToTestMessage": "Kunne ikke teste proxy: {0}", + "ProxyCheckResolveIpMessage": "Mislykkedes at løse IP-adressen til den konfigurerede proxyhost {0}", + "ProxyPasswordHelpText": "Du skal kun indtaste et brugernavn og en adgangskode, hvis der kræves et. Lad dem være tomme ellers.", + "ProxyUsernameHelpText": "Du skal kun indtaste et brugernavn og en adgangskode, hvis der kræves et. Lad dem være tomme ellers.", + "PtpOldSettingsCheckMessage": "Følgende PassThePopcorn-indeksatorer har forældede indstillinger og skal opdateres: {0}", + "QualityDefinitions": "Kvalitetsdefinitioner", + "QualitySettings": "Kvalitetsindstillinger", + "ReadTheWikiForMoreInformation": "Læs Wiki for mere information", + "Reddit": "Reddit", + "Refresh": "Opdater", + "RefreshMovie": "Opdater film", + "ReleaseBranchCheckOfficialBranchMessage": "Filial {0} er ikke en gyldig Radarr-frigivelsesfilial, du modtager ikke opdateringer", + "Reload": "Genindlæs", + "RemovedFromTaskQueue": "Fjernet fra opgavekøen", + "RemoveFilter": "Fjern filteret", + "RemovingTag": "Fjerner tag", + "Reset": "Nulstil", + "Restart": "Genstart", + "RestartNow": "Genstart nu", + "RestartRequiredHelpTextWarning": "Kræver genstart for at træde i kraft", + "Retention": "Tilbageholdelse", + "SaveChanges": "Gem ændringer", + "SaveSettings": "Gem indstillinger", + "Security": "Sikkerhed", + "Seeders": "Såmaskiner", + "SelectAll": "Vælg alle", + "SendAnonymousUsageData": "Send anonyme brugsdata", + "SettingsEnableColorImpairedMode": "Aktivér farve-nedsat tilstand", + "SettingsLongDateFormat": "Lang datoformat", + "SettingsShortDateFormat": "Kort datoformat", + "SettingsShowRelativeDates": "Vis relative datoer", + "SettingsShowRelativeDatesHelpText": "Vis relative (i dag / i går / osv.) Eller absolutte datoer", + "ShowAdvanced": "Vis avanceret", + "ShowSearch": "Vis søgning", + "ShowSearchHelpText": "Vis søgeknappen, når du holder markøren", + "Shutdown": "Lukke ned", + "Size": "Størrelse", + "Source": "Kilde", + "SSLCertPassword": "SSL-certificeret adgangskode", + "SSLCertPasswordHelpText": "Adgangskode til pfx-fil", + "SSLCertPathHelpText": "Sti til pfx-fil", + "StartTypingOrSelectAPathBelow": "Start med at skrive, eller vælg en sti nedenfor", + "Style": "Stil", + "SuggestTranslationChange": "Foreslå ændring af oversættelsen", + "System": "System", + "TableOptions": "Tabelindstillinger", + "TableOptionsColumnsMessage": "Vælg hvilke kolonner der er synlige og hvilken rækkefølge de vises i", + "TagCannotBeDeletedWhileInUse": "Kan ikke slettes under brug", + "TagsHelpText": "Gælder film med mindst et matchende tag", + "Time": "Tid", + "Title": "Titel", + "Today": "I dag", + "Tomorrow": "I morgen", + "Torrent": "Torrenter", + "Torrents": "Torrenter", + "UI": "UI", + "UILanguageHelpText": "Sprog, som Radarr vil bruge til UI", + "UnableToAddANewApplicationPleaseTryAgain": "Kan ikke tilføje en ny underretning, prøv igen.", + "UnableToAddANewAppProfilePleaseTryAgain": "Kan ikke tilføje en ny kvalitetsprofil, prøv igen.", + "UnableToAddANewDownloadClientPleaseTryAgain": "Kunne ikke tilføje en ny downloadklient. Prøv igen.", + "UnableToAddANewIndexerPleaseTryAgain": "Kunne ikke tilføje en ny indekser. Prøv igen.", + "UnableToLoadBackups": "Kunne ikke indlæse sikkerhedskopier", + "UnableToLoadGeneralSettings": "Kan ikke indlæse generelle indstillinger", + "UnableToLoadIndexers": "Kan ikke indlæse indeksatorer", + "UnableToLoadNotifications": "Kunne ikke indlæse meddelelser", + "UnableToLoadTags": "Kan ikke indlæse tags", + "UnableToLoadUISettings": "UI-indstillingerne kunne ikke indlæses", + "UnselectAll": "Fravælg alle", + "UpdateAutomaticallyHelpText": "Download og installer opdateringer automatisk. Du kan stadig installere fra System: Updates", + "UpdateCheckStartupNotWritableMessage": "Kan ikke installere opdatering, fordi startmappen '{0}' ikke kan skrives af brugeren '{1}'.", + "UpdateCheckUINotWritableMessage": "Kan ikke installere opdatering, fordi brugergrænsefladen \"{0}\" ikke kan skrives af brugeren \"{1}\".", + "UpdateScriptPathHelpText": "Sti til et brugerdefineret script, der tager en udpakket opdateringspakke og håndterer resten af opdateringsprocessen", + "Uptime": "Oppetid", + "URLBase": "URL-base", + "UrlBaseHelpText": "For reverse proxy-support er standard tom", + "Yesterday": "I går", + "AllIndexersHiddenDueToFilter": "Alle film er gemt på grund af aktivt filter.", + "IndexerFlags": "Indexer Flag", + "Interval": "Interval", + "PageSizeHelpText": "Antal elementer, der skal vises på hver side", + "Password": "Adgangskode", + "PriorityHelpText": "Prioriter flere downloadklienter. Round-Robin bruges til klienter med samme prioritet.", + "ReleaseStatus": "Frigør status", + "Restore": "Gendan", + "RestoreBackup": "Gendan sikkerhedskopi", + "Restrictions": "Begrænsninger", + "RSS": "RSS", + "RSSIsNotSupportedWithThisIndexer": "RSS understøttes ikke med denne indekseringsenhed", + "Save": "Gemme", + "Scheduled": "Planlagt", + "ScriptPath": "Script sti", + "Search": "Søg", + "ShownClickToHide": "Vist, klik for at skjule", + "SSLCertPath": "SSL-certificeret sti", + "SSLPort": "SSL-port", + "StartupDirectory": "Startmappe", + "Status": "Status", + "UnableToLoadDownloadClients": "Kunne ikke indlæse downloadklienter", + "UnableToLoadQualityDefinitions": "Kunne ikke indlæse kvalitetsdefinitioner", + "UpdateCheckStartupTranslocationMessage": "Kan ikke installere opdatering, fordi startmappen '{0}' er i en App Translocation-mappe.", + "UpdateMechanismHelpText": "Brug Radarrs indbyggede opdatering eller et script", + "View": "Udsigt", + "Warn": "Advare", + "Movies": "Film", + "AddingTag": "Tilføjer tag", + "ApplicationStatusCheckAllClientMessage": "Alle lister er utilgængelige på grund af fejl", + "ApplicationStatusCheckSingleClientMessage": "Lister utilgængelige på grund af fejl: {0}", + "ApplyTags": "Anvend tags", + "ApplyTagsHelpTexts1": "Sådan anvendes tags på de valgte film", + "ApplyTagsHelpTexts2": "Tilføj: Føj tags til den eksisterende liste over tags", + "ApplyTagsHelpTexts3": "Fjern: Fjern de indtastede tags", + "AreYouSureYouWantToResetYourAPIKey": "Er du sikker på, at du vil nulstille din API-nøgle?", + "Authentication": "Godkendelse", + "AuthenticationMethodHelpText": "Kræv brugernavn og adgangskode for at få adgang til Radarr", + "Automatic": "Automatisk", + "AutomaticSearch": "Automatisk søgning", + "BackupFolderHelpText": "Relative stier vil være under Radarrs AppData-bibliotek", + "BackupIntervalHelpText": "Interval mellem automatiske sikkerhedskopier", + "BackupRetentionHelpText": "Automatiske sikkerhedskopier, der er ældre end opbevaringsperioden, renses automatisk", + "BeforeUpdate": "Før opdatering", + "BindAddress": "Bind adresse", + "BindAddressHelpText": "Gyldig IP4-adresse eller '*' for alle grænseflader", + "Branch": "Afdeling", + "BranchUpdate": "Filial, der skal bruges til at opdatere Radarr", + "BranchUpdateMechanism": "Gren brugt af ekstern opdateringsmekanisme", + "ClientPriority": "Kundens prioritet", + "CloneProfile": "Klonprofil", + "EnableInteractiveSearchHelpText": "Bruges, når der bruges interaktiv søgning", + "EnableInteractiveSearchHelpTextWarning": "Søgning understøttes ikke med denne indekser", + "UISettings": "UI-indstillinger", + "NoUpdatesAreAvailable": "Ingen opdateringer er tilgængelige", + "OAuthPopupMessage": "Pop-ups blokeres af din browser", + "Ok": "Okay", + "OpenBrowserOnStart": "Åbn browser ved start", + "Peers": "Kammerater", + "Presets": "Forudindstillinger", + "SettingsEnableColorImpairedModeHelpText": "Ændret stil for at give farvehæmmede brugere bedre at skelne mellem farvekodede oplysninger", + "Options": "Muligheder", + "EnableSSL": "Aktivér SSL", + "InteractiveSearch": "Interaktiv søgning", + "LogFiles": "Logfiler", + "ApiKey": "API-nøgle", + "AppDataDirectory": "AppData-bibliotek", + "CertificateValidationHelpText": "Skift, hvor streng HTTPS-certificering er", + "ChangeHasNotBeenSavedYet": "Ændring er endnu ikke gemt", + "EnabledHelpText": "Aktivér denne liste til brug i Radarr", + "ConnectSettings": "Forbind indstillinger", + "DeleteBackup": "Slet sikkerhedskopi", + "DeleteBackupMessageText": "Er du sikker på, at du vil slette sikkerhedskopien '{0}'?", + "DeleteDownloadClient": "Slet Download Client" } diff --git a/src/NzbDrone.Core/Localization/Core/de.json b/src/NzbDrone.Core/Localization/Core/de.json index c2186580c..76f5d5dcb 100644 --- a/src/NzbDrone.Core/Localization/Core/de.json +++ b/src/NzbDrone.Core/Localization/Core/de.json @@ -1,12 +1,10 @@ { "About": "Über", - "AddNew": "Hinzufügen", "All": "Alle", "Analytics": "Statistiken", "AppDataLocationHealthCheckMessage": "Ein Update ist nicht möglich, um das Löschen von AppData beim Update zu verhindern", "Backup": "Backups", "BackupNow": "Jetzt sichern", - "ChooseAnotherFolder": "Wähle einen anderen Ordner", "Clear": "Leeren", "Connect": "Verbindungen", "Connections": "Verbindungen", @@ -14,7 +12,6 @@ "Date": "Datum", "Dates": "Termine", "Delete": "Löschen", - "DotNetVersionCheckOldUnsupportedMessage": "Derzeit installiert .Net Framework {0} ist alt und wird nicht unterstützt. Bitte aktualisieren Sie das .Net Framework auf mindestens {1}.", "DownloadClientCheckNoneAvailableMessage": "Es ist kein Downloader verfügbar", "DownloadClientCheckUnableToCommunicateMessage": "Kommunikation mit {0} nicht möglich.", "DownloadClientStatusCheckAllClientMessage": "Alle Downloader sind aufgrund von Fehlern nicht verfügbar", @@ -30,20 +27,15 @@ "HideAdvanced": "Erweiterte Ansicht", "History": "Verlauf", "Host": "Host", - "ImportMechanismHealthCheckMessage": "Aktiviere die Verarbeitung der abgeschlossenen Downloads", - "IndexerRssHealthCheckNoIndexers": "Da keine Indexer mit aktivierter RSS-Synchronisierung verfügbar sind, erfasst Prowlarr nicht automatisch neue Releases auf", "IndexerStatusCheckAllClientMessage": "Alle Indexer sind aufgrund von Fehlern nicht verfügbar", "IndexerStatusCheckSingleClientMessage": "Indexer aufgrund von Fehlern nicht verfügbar: {0}", "Indexers": "Indexer", "Languages": "Sprachen", "LogFiles": "Protokolle", "Logging": "Protokollierung", - "Metadata": "Metadaten", - "Monitor": "Beobachten", "MonoNotNetCoreCheckMessage": "Bitte aktualisieren Sie auf die .NET Core-Version von Prowlarr", "MonoTlsCheckMessage": "Der Workaround für Prowlarr Mono 4.x TLS ist weiterhin aktiviert. Entferne möglicherweise die Option MONO_TLS_PROVIDER=legacy", "MoreInfo": "Mehr Infos", - "MovieIndex": "Filmindex", "Movies": "Filme", "NoChange": "Keine Änderung", "NoChanges": "Keine Änderungen", @@ -58,14 +50,11 @@ "Refresh": "Aktualisieren", "ReleaseBranchCheckOfficialBranchMessage": "Zweig {0} ist kein gültiger Prowlarr-Release-Zweig. Sie erhalten keine Updates", "ReleaseBranchCheckPreviousVersionMessage": "Zweig {0} ist für eine frühere Version von Prowlarr. Setzen Sie den Zweig für weitere Aktualisierungen auf 'nightly'", - "RemovedMovieCheckSingleMessage": "Film {0} wurde aus TMDb entfernt", "RestoreBackup": "Backup einspielen", "Restrictions": "Beschränkungen", - "RootFolders": "Stammordner", "SaveChanges": "Änderungen speichern", "Scheduled": "Geplant", "Search": "Suche", - "SearchSelected": "Ausgw. suchen", "Security": "Sicherheit", "SelectAll": "Alle wählen", "SetTags": "Tags setzen", @@ -85,14 +74,11 @@ "Updates": "Updates", "View": "Ansicht", "Language": "Sprache", - "UpdateSelected": "Ausgw. aktualisieren", "UISettingsSummary": "Einstellungen für Kalender, Datumsformat und Farbbeeinträchtigung", "TagsSettingsSummary": "Alle Tags und deren Benutzung anzeigen. Unbenutzte Tags können entfernt werden", "Size": "Größe", "ReleaseStatus": "Releasestatus", "Protocol": "Protokoll", - "OutputPath": "Ausgabe-Pfad", - "MassMovieSearch": "Massen Filmsuche", "LastWriteTime": "Zuletzt beschrieben", "Indexer": "Indexer", "DownloadClientsSettingsSummary": "Downloader, Downloadverarbeitung und Remote-Pfadzuordnungen", @@ -122,7 +108,6 @@ "Reload": "Neuladen", "Peers": "Peers", "PageSize": "Einträge pro Seite", - "OrganizeModalAllPathsRelative": "Alle Pfade sind relativ zu:", "Ok": "OK", "OAuthPopupMessage": "Dein Browser blockiert Pop-ups", "Name": "Name", @@ -143,32 +128,23 @@ "Age": "Alter", "SystemTimeCheckMessage": "Die Systemzeit ist um einen Tag versetzt. Bis die Zeit korrigiert wurde, könnten die geplanten Aufgaben nicht korrekt ausgeführt werden", "UnsavedChanges": "Ungespeicherte Änderungen", - "ShowSizeOnDisk": "Belegter Speicherplatz anzeigen", "ShowSearchHelpText": "Suchbutton anzeigen beim draufzeigen", "ShowSearch": "Suche anzeigen", - "ShowDateAdded": "Datum \"Hinzugefügt\" anzeigen", - "SettingsUiLanguage": "Sprache (Language)", "SettingsTimeFormat": "Zeitformat", "SettingsShowRelativeDatesHelpText": "Relatives (z.B.: Heute, gestern, etc) oder absolutes Datum anzeigen", "SettingsShowRelativeDates": "Relatives Datum anzeigen", "SettingsShortDateFormat": "Kurzes Datumsformat", - "SettingsRemotePathMappingLocalPath": "Lokaler Pfad", "SettingsLongDateFormat": "Langes Datumsformat", "SettingsEnableColorImpairedMode": "Farbbeeinträchtigter Modus aktivieren", "SettingsEnableColorImpairedModeHelpText": "Alternativer Stil, um farbbeeinträchtigten Benutzern eine bessere Unterscheidung farbcodierter Informationen zu ermöglichen", - "RecentFolders": "Letzte Ordner", - "PosterOptions": "Poster Optionen", "PendingChangesStayReview": "Auf der Seite bleiben", "PendingChangesMessage": "Es gibt noch ungespeicherte Änderungen, bist du sicher, dass du die Seite verlassen möchtest?", "PendingChangesDiscardChanges": "Änderungen verwerfen und schließen", "MonoVersionCheckUpgradeRecommendedMessage": "Die momentane installierte Mono Version {0} wird unterstützt aber es wird empfohlen auf {1} zu updaten.", - "InteractiveImport": "Interaktiver Import", "ExistingMovies": "Vorhandene Filme", - "AddRemotePathMapping": "Entfernte Pfadzuordnung hinzufügen", "UpdateAutomaticallyHelpText": "Updates automatisch herunteraden und installieren. Es kann weiterhin unter \"System -> Updates\" ein manuelles Update angestoßen werden", "UrlBaseHelpText": "Für Reverse-Proxy-Unterstützung. Die Standardeinstellung leer", "EnableAutoHelpText": "Wenn aktiviert werden Filme dieser Liste automatisch hinzugefügt", - "AlreadyInYourLibrary": "Bereits in deiner Bibliothek", "AppDataDirectory": "AppData Ordner", "ApplyTags": "Tags setzen", "Authentication": "Authentifizierung", @@ -183,18 +159,14 @@ "CertificateValidation": "Zertifikat Validierung", "CertificateValidationHelpText": "Ändere wie streng die Validierung der HTTPS-Zertifizierung ist", "ChangeHasNotBeenSavedYet": "Änderung wurde noch nicht gespeichert", - "ClickToChangeQuality": "Qualität ändern...", "ClientPriority": "Priorität", "CloneProfile": "Profil kopieren", - "CreateEmptyMovieFolders": "Leere Filmordner erstellen", - "CutoffFormatScoreHelpText": "Sobald dieser eigener Format Score erreicht wird, werden keine neuen Releases erfasst", "DeleteBackup": "Backup löschen", "DeleteDownloadClient": "Downloader löschen", "DeleteIndexer": "Indexer löschen", "DeleteTag": "Tag löschen", "Docker": "Docker", "DownloadClientSettings": "Downloader Einstellungen", - "EditMovie": "Film bearbeiten", "Enable": "Aktivieren", "EnableAutomaticAdd": "Automatisch hinzufügen", "EnableAutomaticSearch": "Automatisch suchen", @@ -205,10 +177,8 @@ "EnableInteractiveSearch": "Interaktive Suche", "EnableSSL": "SSL", "EnableSslHelpText": " Erfordert einen Neustart als Administrator", - "FileDateHelpText": "Aktualisiere das Erstelldatum beim Import oder Re-Scan", "Fixed": "Behoben", "GeneralSettings": "Allgemeine Einstellungen", - "GrabRelease": "Release erfassen", "Hostname": "Hostname", "IgnoredAddresses": "Ignorierte Adressen", "IllRestartLater": "Später neustarten", @@ -216,7 +186,6 @@ "IncludeHealthWarningsHelpText": "Zustandswarnung", "IndexerFlags": "Indexer Flags", "Interval": "Intervall", - "ListSyncLevelHelpText": "Filme in der Bibliothek werden gelöscht oder nicht weiter beobachtet wenn sie nicht in der Liste sind", "LogLevel": "Log Level", "Logs": "Logs", "Mechanism": "Verfahren", @@ -224,9 +193,6 @@ "MinimumLimits": "Mindest Grenzen", "Mode": "Modus", "MonoVersion": "Mono Version", - "MovieID": "Film ID", - "MovieYear": "Erscheinungsjahr", - "NamingSettings": "Bennenungs Einstellungen", "NetCore": ".NET Core", "New": "Neu", "NoLeaveIt": "Nein, nicht ändern", @@ -244,13 +210,9 @@ "ProxyType": "Proxy Typ", "ProxyUsernameHelpText": "Nur wenn ein Benutzername und Passwort erforderlich ist, muss es eingegeben werden. Ansonsten leer lassen.", "QualitySettings": "Qualitäts Einstellungen", - "Reason": "Grund", - "RecyclingBinCleanup": "Papierkorb aufräumen", "RefreshMovie": "Film aktualisieren", "RemovedFromTaskQueue": "Aus der Aufgabenwarteschlage entfernt", "RemoveFilter": "Filter entfernen", - "RenameMoviesHelpText": "Wenn das umbennen deaktiviert ist, wird der vorhandene Dateiname benutzt", - "RescanAfterRefreshHelpText": "Nach dem aktualisieren des Films, den Filmordner neu scannen", "Reset": "Zurücksetzen", "ResetAPIKey": "API-Schlüssel zurücksetzen", "RestartNow": "Jetzt neustarten", @@ -258,9 +220,6 @@ "Result": "Ergebnis", "Retention": "Aufbewahrung ( Retention )", "ScriptPath": "Script Pfad", - "ShowAsAllDayEvents": "Als Ganztags Events anzeigen", - "ShowMonitoredHelpText": "Beobachtungsstatus unter dem Plakat anzeigen", - "SkipFreeSpaceCheck": "Pürfung des freien Speichers überspringen", "SourceRelativePath": "Relativer Quellpfad", "SSLCertPassword": "SSL Zertifikat Passwort", "SSLPort": "SSL Port", @@ -273,7 +232,6 @@ "UpdateScriptPathHelpText": "Pfad zu einem benutzerdefinierten Skript, das ein extrahiertes Update-Paket übernimmt und den Rest des Update-Prozesses abwickelt", "Uptime": "Laufzeit", "URLBase": "URL Base", - "TorrentDelayHelpText": "Verzögerung in Minuten bevor ein Torrent-Release erfasst wird", "Torrents": "Torrents", "UISettings": "Benutzeroberflächen Einstellungen", "UnableToLoadDownloadClients": "Downloader konnten nicht geladen werden", @@ -288,12 +246,10 @@ "YesCancel": "Ja, abbrechen", "EnableColorImpairedModeHelpText": "Alternativer Style, um farbbeeinträchtigten Benutzern eine bessere Unterscheidung farbcodierter Informationen zu ermöglichen", "EnableMediaInfoHelpText": "Videoinformationen wie Auflösung, Laufzeit und Codec aus Datien erkennen. Dazu ist es erforderlich, dass Prowlarr Teile der Datei liest, was zu hoher Festplatten- oder Netzwerkaktivität während der Scans führen kann.", - "HelpText": "Intervall in Minuten. Zum deaktivieren auf 0 setzen ( Dies wird das automatische Release erfassen deaktivieren )", "NoMinimumForAnyRuntime": "Kein Minimum für Laufzeiten", "AnalyticsEnabledHelpText": "Sende anonyme Nutzungs- und Fehlerinformationen an die Server von Prowlarr. Dazu gehören Informationen über Browser, welche Seiten der Prowlarr-Weboberfläche aufgerufen wurden, Fehlerberichte sowie Betriebssystem- und Laufzeitversion. Wir werden diese Informationen verwenden, um Funktionen und Fehlerbehebungen zu priorisieren.", "RestartRequiredHelpTextWarning": "Erfordert einen Neustart", "ApiKey": "API-Schlüssel", - "ImportExtraFilesHelpText": "Importiere zutreffende Extra Dateien (Untertitel, nfo, etc.) nach dem Importieren einer Filmdatei", "AreYouSureYouWantToResetYourAPIKey": "Bist du sicher, dass du den API-Schlüssel zurücksetzen willst?", "PriorityHelpText": "Priorisiere mehrere Downloader. Rundlauf-Verfahren wird für Downloader mit der gleichen Priorität verwendet.", "AuthenticationMethodHelpText": "Für den Zugriff auf Prowlarr sind Benutzername und Passwort erforderlich", @@ -305,24 +261,18 @@ "BackupFolderHelpText": "Relative Pfade befinden sich unter Prowlarrs AppData Ordner", "DelayProfile": "Verzögerungs Profil", "MaximumLimits": "Maximale Grenzen", - "DeleteEmptyFoldersHelpText": "Lösche leere Filmeordner während des Scans oder wenn Filmdateien gelöscht werden", "DeleteNotification": "Benachrichtigung löschen", "CloneIndexer": "Indexer kopieren", "ConnectSettings": "Eintellungen für Verbindungen", - "WaitingToProcess": "Wartet auf Verarbeitung", "TagCannotBeDeletedWhileInUse": "Kann während der Benutzung nicht gelöscht werden", "SSLCertPathHelpText": "Pfad zur PFX Datei", "SSLCertPasswordHelpText": "Passwort für die PFX Datei", "ShownClickToHide": "Angezeigt, zum verstecken klicken", - "SearchOnAddHelpText": "Suche nach den Filmen auf der Liste nach dem hinzufügen", "RSSIsNotSupportedWithThisIndexer": "RSS wird von diesem Indexer nicht unterstützt", "RemovingTag": "Tag entfernen", "Pending": "Ausstehend", - "MovieIsUnmonitored": "Film wird nicht beobachtet", - "MovieAlreadyExcluded": "Film ist schon ausgeschlossen", "Manual": "Manuell", "LogLevelTraceHelpTextWarning": "Trace logging sollte nur kurzzeitig aktiviert werden", - "ImportFailedInterp": "Import fehlgeschlagen: {0}", "HiddenClickToShow": "Versteckt, klicken zum anzeigen", "ExistingTag": "Vorhandener Tag", "EnableInteractiveSearchHelpTextWarning": "Der Indexer unterstützt keine Suchen", @@ -336,15 +286,12 @@ "DeleteIndexerMessageText": "Indexer '{0}' wirklich löschen?", "DeleteDownloadClientMessageText": "Downloader '{0}' wirklich löschen?", "DeleteBackupMessageText": "Backup '{0}' wirkich löschen?", - "CheckDownloadClientForDetails": "prüfe den Downloader für mehr Details", "CancelPendingTask": "Diese laufende Aufgabe wirklich abbrechen?", "BranchUpdateMechanism": "Branch für den externen Updateablauf", "BranchUpdate": "Verwendeter Branch zur Aktualisierung von Prowlarr", "BeforeUpdate": "Vor dem Update", "AddingTag": "Tag hinzufügen", "UnableToLoadUISettings": "Oberflächen Einstellungen konnten nicht geladen werden", - "UnableToLoadMediaManagementSettings": "Media Verwaltungseinstellungen konnten nicht geladen werden", - "UnableToLoadLanguages": "Sprachen konnten nicht geladen werden", "UnableToLoadHistory": "Verlauf konnte nicht geladen werden", "UnableToLoadGeneralSettings": "Allgemeine Einstellungen konnten nicht geladen werden", "UnableToLoadBackups": "Backups konnten nicht geladen werden", @@ -354,7 +301,6 @@ "TagIsNotUsedAndCanBeDeleted": "Tag wird nicht benutzt und kann gelöscht werden", "StartTypingOrSelectAPathBelow": "Eingeben oder unten auswählen", "Restore": "Wiederherstellen", - "ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "RSS Film Listen sowie unten aufgelistete werden untertützt.", "ProwlarrSupportsAnyIndexer": "Prowlarr unterstützt alle Indexer, welcher den Newznab/Torznab Standard implementiert (verwende 'Generic Newznab' (für Usenet) oder 'Generic Torznab' (für Torrents)) und darüber hinaus viele weitere Indexer. Wählen Sie im Folgenden Ihren Indexer aus der Liste.", "ProwlarrSupportsAnyDownloadClient": "Jeder Downloader der den Newznab-Standard verwendet oder unten aufgelistet ist wird untertützt.", "NoUpdatesAreAvailable": "Es sind keine Updates verfügbar", @@ -365,14 +311,10 @@ "MinutesNinety": "90 Minuten: {0}", "MinutesHundredTwenty": "120 Minuten: {0}", "MaintenanceRelease": "Wartungsupdate", - "LinkHere": "hier", - "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Für mehr Infomationen klicke auf die Info-Knöpfe.", "ForMoreInformationOnTheIndividualDownloadClients": "Für mehr Infomationen klicke auf die Info-Knöpfe.", "FilterPlaceHolder": "Filme suchen", - "ExtraFileExtensionsHelpTexts2": "Vorschläge: sub, nfo, srt, jpg", "Exception": "Ausnahme", "ErrorLoadingContents": "Fehler beim laden der Inhalte", - "CantFindMovie": "Warum kann der Film nicht gefunden werden?", "ApplyTagsHelpTexts4": "Ersetzen: Nur eingegebene Tags übernehmen und vorhandene entfernen( keine Tags eingeben um alle zu entfernen )", "ApplyTagsHelpTexts3": "Entfernen: Eingegebene Tags entfernen", "ApplyTagsHelpTexts2": "Hinzufügen: Füge neu Tags zu den existierenden Tags hinzu", @@ -380,9 +322,6 @@ "UILanguageHelpTextWarning": "Webseite muss neu geladen werden", "UILanguageHelpText": "Sprache für die gesamte Oberfläche", "UILanguage": "Oberflächen Sprache ( UI Language )", - "ExportCustomFormat": "Eigenes Format exportieren", - "DownloadPropersAndRepacksHelpText2": "Benutze 'Nicht bevorzugen' um den bevorzugte Wörter Score über Proper oder Repacks zu sortieren", - "CopyToClipboard": "In die Zwischenablage kopieren", "Priority": "Priorität", "InteractiveSearch": "Interaktive Suche", "IndexerPriorityHelpText": "Indexer Priorität von 1 (höchste) bis 50 (niedrigste). Standart: 25.", @@ -400,9 +339,6 @@ "FocusSearchBox": "Suchbox fokussieren", "CloseCurrentModal": "Momentanes Modal schließen", "AcceptConfirmationModal": "Bestätigung akzeptieren Modal", - "RequiredRestrictionPlaceHolder": "Ein Release muss mindestens einen dieser Begriffe enthalten (Groß- und Kleinschreibung wird nicht berücksichtigt)", - "ImportIncludeQuality": "Stelle sicher, dass die Qualität im Dateinamen vorkommt ( z.B.: {0} )", - "StartProcessing": "Verarbeitung starten", "AddRestriction": "Beschränkung hinzufügen", "Yesterday": "Gestern", "Tomorrow": "Morgen", @@ -485,5 +421,11 @@ "Stats": "Statistiken", "NoSearchResultsFound": "Keine Suchergebnisse gefunden. Versuchen Sie unten eine erneute Suche durchzuführen.", "Query": "Abfrage", - "Torrent": "Torrent" + "Torrent": "Torrent", + "NoLinks": "Keine Links", + "Grabs": "Erfasse", + "IndexerProxyStatusCheckAllClientMessage": "Alle Indexer sind aufgrund von Fehlern nicht verfügbar", + "IndexerProxyStatusCheckSingleClientMessage": "Listen aufgrund von Fehlern nicht verfügbar: {0}", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Der neue Indexer konnte nicht hinzugefügt werden, bitte erneut probieren.", + "DeleteIndexerProxyMessageText": "Tag '{0}' wirklich löschen?" } diff --git a/src/NzbDrone.Core/Localization/Core/el.json b/src/NzbDrone.Core/Localization/Core/el.json index 5a970d5ff..dd7ee2a33 100644 --- a/src/NzbDrone.Core/Localization/Core/el.json +++ b/src/NzbDrone.Core/Localization/Core/el.json @@ -10,12 +10,10 @@ "Connections": "Συνδέσεις", "Connect": "Σύνδεση", "Clear": "Καθαρισμός", - "Calendar": "Ημερολόγιο", "BackupNow": "Δημιουργία Αντιγράφου Ασφαλείας", "Backup": "Αντίγραφο Ασφαλείας", "Analytics": "Αναλύσεις", "All": "Όλα", - "AddExclusion": "Προσθήκη Εξαίρεσης", "Added": "Προστέθηκε", "Actions": "Ενέργειες", "About": "Σχετικά", @@ -35,7 +33,6 @@ "DownloadClientStatusCheckSingleClientMessage": "Προγράμματα λήψης που είναι μη διαθέσιμα λόγων αποτυχιών: {0}", "DownloadClientStatusCheckAllClientMessage": "Όλα τα προγράμματα λήψης είναι μη διαθέσιμα λόγων αποτυχιών", "DownloadClientsSettingsSummary": "Προγράμματα λήψης, διαχείριση λήψεων και αντιστοίχηση remote path", - "CustomFormatsSettingsSummary": "Custom Formats και Ρυθμίσεις", "CustomFilters": "Custom Φιλτρα", "ConnectSettingsSummary": "Ειδοποιήσεις, συνδέσεις σε media servers/players και custom scripts", "AppDataLocationHealthCheckMessage": "Η αναβάθμιση δεν είναι πιθανό να αποτρέψει την διαγραφή των AppData κατά την αναβάθμιση", @@ -45,5 +42,323 @@ "Close": "Κλείσιμο", "Cancel": "Ακύρωση", "Apply": "Εφαρμογή", - "Age": "Ηλικία" + "Age": "Ηλικία", + "ExistingTag": "Υφιστάμενη ετικέτα", + "FocusSearchBox": "Πλαίσιο αναζήτησης εστίασης", + "Indexer": "Ευρετήριο", + "PendingChangesDiscardChanges": "Απορρίψτε τις αλλαγές και φύγετε", + "ShowSearchHelpText": "Εμφάνιση κουμπιού αναζήτησης στο δείκτη", + "UpdateCheckStartupNotWritableMessage": "Δεν είναι δυνατή η εγκατάσταση της ενημέρωσης επειδή ο φάκελος εκκίνησης \"{0}\" δεν είναι εγγράψιμος από τον χρήστη \"{1}\".", + "BranchUpdateMechanism": "Υποκατάστημα που χρησιμοποιείται από εξωτερικό μηχανισμό ενημέρωσης", + "Mode": "Τρόπος", + "SettingsEnableColorImpairedMode": "Ενεργοποίηση λειτουργίας με προβλήματα χρώματος", + "Add": "Προσθήκη", + "ApiKey": "Κλειδί API", + "Discord": "Διχόνοια", + "Donations": "Δωρεές", + "ForMoreInformationOnTheIndividualDownloadClients": "Για περισσότερες πληροφορίες σχετικά με τους μεμονωμένους πελάτες λήψης, κάντε κλικ στα κουμπιά πληροφοριών.", + "IgnoredAddresses": "Διευθύνσεις που αγνοήθηκαν", + "IllRestartLater": "Θα επανεκκινήσω αργότερα", + "Protocol": "Πρωτόκολλο", + "Reddit": "Reddit", + "Restrictions": "Περιορισμοί", + "Result": "Αποτέλεσμα", + "Retention": "Κράτηση", + "RSS": "RSS", + "RSSIsNotSupportedWithThisIndexer": "Το RSS δεν υποστηρίζεται με αυτό το ευρετήριο", + "Save": "Σώσει", + "SaveChanges": "Αποθήκευσε τις αλλαγές", + "SettingsEnableColorImpairedModeHelpText": "Τροποποιημένο στυλ για να επιτρέπεται στους χρήστες με προβλήματα χρώματος να διακρίνουν καλύτερα τις πληροφορίες με χρωματική κωδικοποίηση", + "SSLPort": "Θύρα SSL", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Δεν είναι δυνατή η προσθήκη νέου ευρετηρίου, δοκιμάστε ξανά.", + "Wiki": "Wiki", + "AddIndexer": "Προσθήκη ευρετηρίου", + "AddingTag": "Προσθήκη ετικέτας", + "ApplyTagsHelpTexts2": "Προσθήκη: Προσθέστε τις ετικέτες στην υπάρχουσα λίστα ετικετών", + "ApplyTagsHelpTexts3": "Αφαίρεση: Καταργήστε τις καταχωρημένες ετικέτες", + "AreYouSureYouWantToResetYourAPIKey": "Είστε βέβαιοι ότι θέλετε να επαναφέρετε το κλειδί API σας;", + "DeleteIndexer": "Διαγραφή ευρετηρίου", + "NoChange": "Καμία αλλαγή", + "Port": "Λιμάνι", + "PortNumber": "Αριθμός θύρας", + "PreferredSize": "Προτιμώμενο μέγεθος", + "IndexerStatusCheckAllClientMessage": "Όλοι οι δείκτες δεν είναι διαθέσιμοι λόγω αστοχιών", + "IndexerStatusCheckSingleClientMessage": "Τα ευρετήρια δεν είναι διαθέσιμα λόγω αστοχιών: {0}", + "KeyboardShortcuts": "Συντομεύσεις πληκτρολογίου", + "Language": "Γλώσσα", + "MonoTlsCheckMessage": "Η λύση Radarr Mono 4.x tls είναι ακόμα ενεργοποιημένη, εξετάστε το ενδεχόμενο να καταργήσετε το MONO_TLS_PROVIDER = επιλογή περιβάλλοντος παλαιού τύπου", + "PriorityHelpText": "Προτεραιότητα πολλαπλών πελατών λήψης. Το Round-Robin χρησιμοποιείται για πελάτες με την ίδια προτεραιότητα.", + "PrioritySettings": "Προτεραιότητα", + "Reset": "Επαναφορά", + "CouldNotConnectSignalR": "Δεν ήταν δυνατή η σύνδεση στο SignalR, η διεπαφή χρήστη δεν θα ενημερωθεί", + "StartupDirectory": "Κατάλογος εκκίνησης", + "Logs": "Κούτσουρα", + "Updates": "Ενημερώσεις", + "TagCannotBeDeletedWhileInUse": "Δεν είναι δυνατή η διαγραφή κατά τη χρήση", + "AcceptConfirmationModal": "Αποδοχή Modal επιβεβαίωσης", + "AddDownloadClient": "Προσθήκη προγράμματος-πελάτη λήψης", + "AllIndexersHiddenDueToFilter": "Όλες οι ταινίες έχουν κρυφτεί λόγω εφαρμογής φίλτρου", + "Authentication": "Αυθεντικοποίηση", + "ConnectionLost": "Η σύνδεση χάθηκε", + "ConnectSettings": "Σύνδεση ρυθμίσεων", + "Disabled": "άτομα με ειδικές ανάγκες", + "Manual": "Εγχειρίδιο", + "MaximumLimits": "Μέγιστα όρια", + "MinutesSixty": "60 λεπτά: {0}", + "MovieDetailsNextMovie": "Λεπτομέρειες ταινίας: Επόμενη ταινία", + "QualityDefinitions": "Ορισμοί ποιότητας", + "QualitySettings": "Ρυθμίσεις ποιότητας", + "SetTags": "Ορισμός ετικετών", + "ShowSearch": "Εμφάνιση αναζήτησης", + "Status": "Κατάσταση", + "Tags": "Ετικέτες", + "UI": "Διεπαφή χρήστη", + "UILanguage": "Γλώσσα διεπαφής χρήστη", + "UILanguageHelpText": "Γλώσσα που θα χρησιμοποιήσει ο Radarr για τη διεπαφή χρήστη", + "UISettings": "Ρυθμίσεις διεπαφής χρήστη", + "Yesterday": "Εχθές", + "FeatureRequests": "Αιτήματα χαρακτηριστικών", + "Grabbed": "Αρπαξε", + "HiddenClickToShow": "Κρυφό, κάντε κλικ για εμφάνιση", + "IndexerPriority": "Προτεραιότητα ευρετηρίου", + "Indexers": "Ευρετήρια", + "Info": "Πληροφορίες", + "Languages": "Γλώσσες", + "LastWriteTime": "Τελευταία ώρα εγγραφής", + "Level": "Επίπεδο", + "LogLevel": "Επίπεδο καταγραφής", + "MIA": "ΜΙΑ", + "Proxy": "Πληρεξούσιο", + "ProxyBypassFilterHelpText": "Χρησιμοποιήστε το \",\" ως διαχωριστικό και \"*.\" ως μπαλαντέρ για υποτομείς", + "UnableToAddANewAppProfilePleaseTryAgain": "Δεν είναι δυνατή η προσθήκη ενός νέου προφίλ ποιότητας. Δοκιμάστε ξανά.", + "UnableToLoadHistory": "Δεν είναι δυνατή η φόρτωση του ιστορικού", + "UpdateCheckUINotWritableMessage": "Δεν είναι δυνατή η εγκατάσταση της ενημέρωσης επειδή ο φάκελος διεπαφής χρήστη \"{0}\" δεν είναι εγγράψιμος από τον χρήστη \"{1}\".", + "ApplyTagsHelpTexts4": "Αντικατάσταση: Αντικαταστήστε τις ετικέτες με τις εισαγόμενες ετικέτες (μην εισάγετε ετικέτες για να διαγράψετε όλες τις ετικέτες)", + "AuthenticationMethodHelpText": "Απαιτήστε όνομα χρήστη και κωδικό πρόσβασης για πρόσβαση στο Radarr", + "Automatic": "Αυτόματο", + "BeforeUpdate": "Πριν από την ενημέρωση", + "BindAddressHelpText": "Έγκυρη διεύθυνση IP4 ή «*» για όλες τις διεπαφές", + "Branch": "Κλαδί", + "ChangeHasNotBeenSavedYet": "Η αλλαγή δεν έχει αποθηκευτεί ακόμα", + "CloneProfile": "Προφίλ κλώνου", + "CloseCurrentModal": "Κλείσιμο τρέχοντος modal", + "DBMigration": "Μετεγκατάσταση DB", + "DelayProfile": "Προφίλ χρονοκαθυστέρησης", + "DeleteApplicationMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε την ειδοποίηση \"{0}\";", + "DeleteBackupMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε το αντίγραφο ασφαλείας \"{0}\";", + "DeleteIndexerMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε το ευρετήριο \"{0}\";", + "DeleteIndexerProxyMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε τη λίστα \"{0}\";", + "DeleteNotificationMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε την ειδοποίηση \"{0}\";", + "DeleteTagMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε την ετικέτα \"{0}\";", + "DownloadClientUnavailable": "Ο πελάτης λήψης δεν είναι διαθέσιμος", + "EnableAutoHelpText": "Εάν ενεργοποιηθεί, οι Ταινίες θα προστεθούν αυτόματα στο Radarr από αυτήν τη λίστα", + "EnableAutomaticAdd": "Ενεργοποίηση αυτόματης προσθήκης", + "EnableAutomaticSearch": "Ενεργοποίηση αυτόματης αναζήτησης", + "EnableAutomaticSearchHelpText": "Θα χρησιμοποιηθεί όταν πραγματοποιούνται αυτόματες αναζητήσεις μέσω του περιβάλλοντος χρήστη ή του Radarr", + "EnableColorImpairedModeHelpText": "Τροποποιημένο στυλ για να επιτρέπεται στους χρήστες με προβλήματα χρώματος να διακρίνουν καλύτερα τις πληροφορίες με χρωματική κωδικοποίηση", + "EnableMediaInfoHelpText": "Εξαγωγή πληροφοριών βίντεο, όπως ανάλυση, χρόνος εκτέλεσης και πληροφορίες κωδικοποιητή από αρχεία. Αυτό απαιτεί από τον Radarr να διαβάσει τμήματα του αρχείου που ενδέχεται να προκαλέσουν υψηλή δραστηριότητα δίσκου ή δικτύου κατά τη διάρκεια των σαρώσεων.", + "EnableSslHelpText": " Απαιτείται επανεκκίνηση ως διαχειριστής για να τεθεί σε ισχύ", + "Error": "Λάθος", + "ErrorLoadingContents": "Σφάλμα κατά τη φόρτωση περιεχομένων", + "ExistingMovies": "Υφιστάμενες ταινίες", + "GeneralSettings": "Γενικές Ρυθμίσεις", + "Grabs": "Αρπάζω", + "HealthNoIssues": "Δεν υπάρχουν προβλήματα με τη διαμόρφωσή σας", + "HomePage": "Αρχική σελίδα", + "Host": "Πλήθος", + "Hostname": "Όνομα κεντρικού υπολογιστή", + "IndexerLongTermStatusCheckSingleClientMessage": "Τα ευρετήρια δεν είναι διαθέσιμα λόγω αστοχιών για περισσότερο από 6 ώρες: {0}", + "IndexerPriorityHelpText": "Προτεραιότητα ευρετηρίου από 1 (Υψηλότερη) έως 50 (Χαμηλότερη). Προεπιλογή: 25.", + "IndexerProxyStatusCheckAllClientMessage": "Όλες οι λίστες δεν είναι διαθέσιμες λόγω αστοχιών", + "IndexerProxyStatusCheckSingleClientMessage": "Τα ευρετήρια δεν είναι διαθέσιμα λόγω αστοχιών: {0}", + "LaunchBrowserHelpText": " Ανοίξτε ένα πρόγραμμα περιήγησης ιστού και μεταβείτε στην αρχική σελίδα του Radarr κατά την έναρξη της εφαρμογής.", + "LogFiles": "Αρχεία καταγραφής", + "Logging": "Ξύλευση", + "LogLevelTraceHelpTextWarning": "Η καταγραφή ιχνών πρέπει να ενεργοποιηθεί προσωρινά", + "Mechanism": "Μηχανισμός", + "Message": "Μήνυμα", + "MinimumLimits": "Ελάχιστα όρια", + "MinutesHundredTwenty": "120 λεπτά: {0}", + "MinutesNinety": "90 λεπτά: {0}", + "MonoVersion": "Μονο έκδοση", + "MonoVersionCheckUpgradeRecommendedMessage": "Η τρέχουσα εγκατεστημένη έκδοση Mono {0} υποστηρίζεται, αλλά συνιστάται η αναβάθμιση σε {1}.", + "MovieDetailsPreviousMovie": "Λεπτομέρειες ταινίας: Προηγούμενη ταινία", + "MovieIndexScrollBottom": "Ευρετήριο ταινιών: Κύλιση κάτω", + "MovieIndexScrollTop": "Ευρετήριο ταινιών: Κύλιση στην κορυφή", + "Movies": "Κινηματογράφος", + "Name": "Ονομα", + "New": "Νέος", + "NoBackupsAreAvailable": "Δεν υπάρχουν διαθέσιμα αντίγραφα ασφαλείας", + "NoLeaveIt": "Όχι, άσε το", + "NoLimitForAnyRuntime": "Δεν υπάρχει όριο για οποιοδήποτε χρόνο εκτέλεσης", + "NoLinks": "Χωρίς συνδέσμους", + "NoLogFiles": "Δεν υπάρχουν αρχεία καταγραφής", + "NoMinimumForAnyRuntime": "Χωρίς ελάχιστο για κάθε χρόνο εκτέλεσης", + "NoTagsHaveBeenAddedYet": "Δεν έχουν προστεθεί ετικέτες ακόμη", + "NotificationTriggers": "Ενεργοποιήσεις ειδοποίησης", + "PageSizeHelpText": "Αριθμός στοιχείων προς εμφάνιση σε κάθε σελίδα", + "Password": "Κωδικός πρόσβασης", + "Peers": "Ομότιμοι", + "Pending": "εκκρεμής", + "PendingChangesMessage": "Έχετε μη αποθηκευμένες αλλαγές, είστε βέβαιοι ότι θέλετε να αποχωρήσετε από αυτήν τη σελίδα;", + "PendingChangesStayReview": "Παραμείνετε και ελέγξτε τις αλλαγές", + "Presets": "Προεπιλογές", + "Priority": "Προτεραιότητα", + "ProxyCheckFailedToTestMessage": "Αποτυχία δοκιμής διακομιστή μεσολάβησης: {0}", + "ProxyCheckResolveIpMessage": "Αποτυχία επίλυσης της διεύθυνσης IP για τον Διαμορφωμένο διακομιστή μεσολάβησης {0}", + "PtpOldSettingsCheckMessage": "Οι ακόλουθοι ευρετηριαστές PassThePopcorn έχουν καταργήσει τις ρυθμίσεις και πρέπει να ενημερωθούν: {0}", + "Queue": "Ουρά", + "ReadTheWikiForMoreInformation": "Διαβάστε το Wiki για περισσότερες πληροφορίες", + "Refresh": "Φρεσκάρω", + "RefreshMovie": "Ανανέωση ταινίας", + "ReleaseBranchCheckOfficialBranchMessage": "Το υποκατάστημα {0} δεν είναι έγκυρο υποκατάστημα κυκλοφορίας Radarr, δεν θα λαμβάνετε ενημερώσεις", + "Reload": "Φορτώνω πάλι", + "RemovedFromTaskQueue": "Καταργήθηκε από την ουρά εργασιών", + "RemoveFilter": "Αφαιρέστε το φίλτρο", + "RemovingTag": "Κατάργηση ετικέτας", + "ResetAPIKey": "Επαναφορά κλειδιού API", + "Restart": "Επανεκκίνηση", + "RestartNow": "Επανεκκίνηση τώρα", + "RestartRequiredHelpTextWarning": "Απαιτείται επανεκκίνηση για να τεθεί σε ισχύ", + "Restore": "Επαναφέρω", + "SaveSettings": "Αποθήκευση ρυθμίσεων", + "Seeders": "Σπόροι", + "SelectAll": "Επιλογή όλων", + "SendAnonymousUsageData": "Αποστολή ανώνυμων δεδομένων χρήσης", + "Settings": "Ρυθμίσεις", + "SettingsLongDateFormat": "Μορφή μεγάλης ημερομηνίας", + "SettingsShortDateFormat": "Μορφή σύντομης ημερομηνίας", + "SettingsTimeFormat": "Μορφή ώρας", + "ShowAdvanced": "Εμφάνιση για προχωρημένους", + "ShownClickToHide": "Εμφανίζεται, κάντε κλικ για απόκρυψη", + "Shutdown": "ΤΕΡΜΑΤΙΣΜΟΣ ΛΕΙΤΟΥΡΓΙΑΣ", + "SSLCertPasswordHelpText": "Κωδικός πρόσβασης για το αρχείο pfx", + "SSLCertPath": "Διαδρομή πιστοποίησης SSL", + "StartTypingOrSelectAPathBelow": "Ξεκινήστε να πληκτρολογείτε ή επιλέξτε μια διαδρομή παρακάτω", + "Style": "Στυλ", + "SystemTimeCheckMessage": "Ο χρόνος συστήματος είναι απενεργοποιημένος για περισσότερο από 1 ημέρα. Οι προγραμματισμένες εργασίες ενδέχεται να μην εκτελούνται σωστά έως ότου διορθωθεί η ώρα", + "TableOptions": "Επιλογές πίνακα", + "TableOptionsColumnsMessage": "Επιλέξτε ποιες στήλες είναι ορατές και με ποια σειρά εμφανίζονται", + "TagIsNotUsedAndCanBeDeleted": "Η ετικέτα δεν χρησιμοποιείται και μπορεί να διαγραφεί", + "TagsHelpText": "Ισχύει για ταινίες με τουλάχιστον μία αντίστοιχη ετικέτα", + "TagsSettingsSummary": "Δείτε όλες τις ετικέτες και πώς χρησιμοποιούνται. Οι αχρησιμοποίητες ετικέτες μπορούν να αφαιρεθούν", + "Test": "Δοκιμή", + "TestAll": "Δοκιμάστε όλα", + "TestAllClients": "Δοκιμάστε όλους τους πελάτες", + "Title": "Τίτλος", + "Today": "Σήμερα", + "Tomorrow": "Αύριο", + "Torrent": "Torrents", + "Torrents": "Torrents", + "Type": "Τύπος", + "UILanguageHelpTextWarning": "Απαιτείται επαναφόρτωση προγράμματος περιήγησης", + "UnableToAddANewApplicationPleaseTryAgain": "Δεν είναι δυνατή η προσθήκη νέας ειδοποίησης, δοκιμάστε ξανά.", + "UnableToAddANewDownloadClientPleaseTryAgain": "Δεν είναι δυνατή η προσθήκη νέου προγράμματος-πελάτη λήψης. Δοκιμάστε ξανά.", + "UnableToAddANewIndexerPleaseTryAgain": "Δεν είναι δυνατή η προσθήκη νέου ευρετηρίου, δοκιμάστε ξανά.", + "UnableToLoadGeneralSettings": "Δεν είναι δυνατή η φόρτωση των γενικών ρυθμίσεων", + "UnableToLoadNotifications": "Δεν είναι δυνατή η φόρτωση ειδοποιήσεων", + "UnableToLoadQualityDefinitions": "Δεν είναι δυνατή η φόρτωση των ορισμών ποιότητας", + "UnableToLoadUISettings": "Δεν είναι δυνατή η φόρτωση των ρυθμίσεων διεπαφής χρήστη", + "UnsavedChanges": "Μη αποθηκευμένες αλλαγές", + "UpdateCheckStartupTranslocationMessage": "Δεν είναι δυνατή η εγκατάσταση της ενημέρωσης επειδή ο φάκελος εκκίνησης \"{0}\" βρίσκεται σε ένα φάκελο \"Μετατόπιση εφαρμογών\".", + "UpdateScriptPathHelpText": "Διαδρομή σε ένα προσαρμοσμένο σενάριο που λαμβάνει ένα εξαγόμενο πακέτο ενημέρωσης και χειρίζεται το υπόλοιπο της διαδικασίας ενημέρωσης", + "URLBase": "Βάση διεύθυνσης URL", + "UrlBaseHelpText": "Για αντίστροφη υποστήριξη διακομιστή μεσολάβησης, η προεπιλογή είναι άδεια", + "Usenet": "Usenet", + "UseProxy": "Χρησιμοποιήστε διακομιστή μεσολάβησης", + "Username": "Όνομα χρήστη", + "Version": "Εκδοχή", + "View": "Θέα", + "Warn": "Προειδοποιώ", + "YesCancel": "Ναι, Ακύρωση", + "Exception": "Εξαίρεση", + "Importing": "Εισαγωγή", + "IncludeHealthWarningsHelpText": "Συμπεριλάβετε προειδοποιήσεις για την υγεία", + "Security": "Ασφάλεια", + "Tasks": "Καθήκοντα", + "UnableToLoadBackups": "Δεν είναι δυνατή η φόρτωση αντιγράφων ασφαλείας", + "UnableToLoadDownloadClients": "Δεν είναι δυνατή η φόρτωση πελατών λήψης", + "UnableToLoadIndexers": "Δεν είναι δυνατή η φόρτωση του ευρετηρίου", + "UpdateMechanismHelpText": "Χρησιμοποιήστε το ενσωματωμένο πρόγραμμα ενημέρωσης του Radarr ή ένα σενάριο", + "AnalyticsEnabledHelpText": "Στείλτε ανώνυμες πληροφορίες χρήσης και σφάλματος στους διακομιστές του Radarr. Αυτό περιλαμβάνει πληροφορίες στο πρόγραμμα περιήγησής σας, ποιες σελίδες Radarr WebUI χρησιμοποιείτε, αναφορά σφαλμάτων καθώς και έκδοση λειτουργικού συστήματος και χρόνου εκτέλεσης. Θα χρησιμοποιήσουμε αυτές τις πληροφορίες για να δώσουμε προτεραιότητα σε λειτουργίες και διορθώσεις σφαλμάτων.", + "AppDataDirectory": "Κατάλογος AppData", + "BindAddress": "Δεσμευμένη διεύθυνση", + "EnableRss": "Ενεργοποίηση RSS", + "EnableInteractiveSearchHelpTextWarning": "Η αναζήτηση δεν υποστηρίζεται με αυτό το ευρετήριο", + "IndexerFlags": "Σημαίες ευρετηρίου", + "IndexerLongTermStatusCheckAllClientMessage": "Όλοι οι δείκτες δεν είναι διαθέσιμοι λόγω αστοχιών για περισσότερο από 6 ώρες", + "InteractiveSearch": "Διαδραστική αναζήτηση", + "Interval": "Διάστημα", + "ProxyCheckBadRequestMessage": "Αποτυχία δοκιμής διακομιστή μεσολάβησης. StatusCode: {0}", + "ProxyPasswordHelpText": "Πρέπει να εισαγάγετε ένα όνομα χρήστη και έναν κωδικό πρόσβασης μόνο εάν απαιτείται. Αφήστε τα κενά διαφορετικά.", + "ProxyType": "Τύπος διακομιστή μεσολάβησης", + "ProxyUsernameHelpText": "Πρέπει να εισαγάγετε ένα όνομα χρήστη και έναν κωδικό πρόσβασης μόνο εάν απαιτείται. Αφήστε τα κενά διαφορετικά.", + "RestoreBackup": "Επαναφορά αντιγράφων ασφαλείας", + "Scheduled": "Προγραμματισμένος", + "ScriptPath": "Διαδρομή σεναρίου", + "Search": "Αναζήτηση", + "SettingsShowRelativeDates": "Εμφάνιση σχετικών ημερομηνιών", + "SettingsShowRelativeDatesHelpText": "Εμφάνιση σχετικών (Σήμερα / Χθες / κ.λπ.) ή απόλυτες ημερομηνίες", + "SSLCertPathHelpText": "Διαδρομή στο αρχείο pfx", + "ApplicationStatusCheckAllClientMessage": "Όλες οι λίστες δεν είναι διαθέσιμες λόγω αστοχιών", + "ApplicationStatusCheckSingleClientMessage": "Μη διαθέσιμες λίστες λόγω αποτυχιών: {0}", + "ApplyTags": "Εφαρμογή ετικετών", + "ApplyTagsHelpTexts1": "Πώς να εφαρμόσετε ετικέτες στις επιλεγμένες ταινίες", + "BackupFolderHelpText": "Οι σχετικές διαδρομές θα βρίσκονται στον κατάλογο AppData του Radarr", + "AutomaticSearch": "Αυτόματη αναζήτηση", + "BackupIntervalHelpText": "Διάστημα μεταξύ των αυτόματων αντιγράφων ασφαλείας", + "BackupRetentionHelpText": "Τα αυτόματα αντίγραφα ασφαλείας που είναι παλαιότερα από την περίοδο διατήρησης θα καθαρίζονται αυτόματα", + "Backups": "Δημιουργία αντιγράφων ασφαλείας", + "BranchUpdate": "Υποκατάστημα για χρήση για την ενημέρωση του Radarr", + "CancelPendingTask": "Είστε βέβαιοι ότι θέλετε να ακυρώσετε αυτήν την εργασία σε εκκρεμότητα;", + "CertificateValidation": "Επικύρωση πιστοποιητικού", + "CertificateValidationHelpText": "Αλλάξτε πόσο αυστηρή είναι η επικύρωση πιστοποίησης HTTPS", + "ClientPriority": "Προτεραιότητα πελάτη", + "CloneIndexer": "Δείκτης κλώνου", + "DeleteBackup": "Διαγραφή αντιγράφων ασφαλείας", + "DeleteDownloadClient": "Διαγραφή προγράμματος-πελάτη λήψης", + "DeleteDownloadClientMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε τον πελάτη λήψης \"{0}\";", + "DeleteNotification": "Διαγραφή ειδοποίησης", + "Docker": "Λιμενεργάτης", + "DownloadClientSettings": "Λήψη ρυθμίσεων πελάτη", + "Downloading": "Λήψη", + "EnableInteractiveSearch": "Ενεργοποίηση διαδραστικής αναζήτησης", + "SuggestTranslationChange": "Προτείνετε αλλαγή μετάφρασης", + "System": "Σύστημα", + "Time": "χρόνος", + "NoUpdatesAreAvailable": "Δεν υπάρχουν διαθέσιμες ενημερώσεις", + "OAuthPopupMessage": "Τα αναδυόμενα παράθυρα αποκλείονται από το πρόγραμμα περιήγησής σας", + "Ok": "Εντάξει", + "OnHealthIssueHelpText": "Σχετικά με το θέμα της υγείας", + "OpenBrowserOnStart": "Ανοίξτε το πρόγραμμα περιήγησης κατά την έναρξη", + "OpenThisModal": "Ανοίξτε αυτό το Modal", + "Options": "Επιλογές", + "PackageVersion": "Έκδοση πακέτου", + "PageSize": "Μέγεθος σελίδας", + "ReleaseStatus": "Κατάσταση κυκλοφορίας", + "Size": "Μέγεθος", + "Sort": "Είδος", + "Source": "Πηγή", + "SSLCertPassword": "Κωδικός πρόσβασης SSL Cert", + "UnableToLoadTags": "Δεν είναι δυνατή η φόρτωση ετικετών", + "UnselectAll": "Αποεπιλογή όλων", + "UpdateAutomaticallyHelpText": "Αυτόματη λήψη και εγκατάσταση ενημερώσεων. Θα εξακολουθείτε να μπορείτε να κάνετε εγκατάσταση από το System: Updates", + "UnableToAddANewNotificationPleaseTryAgain": "Δεν είναι δυνατή η προσθήκη νέας ειδοποίησης, δοκιμάστε ξανά.", + "Uptime": "Ώρα", + "NoChanges": "Χωρίς αλλαγές", + "MoreInfo": "Περισσότερες πληροφορίες", + "Custom": "Εθιμο", + "Fixed": "Σταθερός", + "EnableSSL": "Ενεργοποίηση SSL", + "BypassProxyForLocalAddresses": "Παράκαμψη διακομιστή μεσολάβησης για τοπικές διευθύνσεις", + "DeleteTag": "Διαγραφή ετικέτας", + "EditIndexer": "Επεξεργασία ευρετηρίου", + "Enable": "επιτρέπω", + "EnableAutomaticSearchHelpTextWarning": "Θα χρησιμοποιηθεί όταν χρησιμοποιείται διαδραστική αναζήτηση", + "EnableColorImpairedMode": "Ενεργοποίηση λειτουργίας με προβλήματα χρώματος", + "EnableCompletedDownloadHandlingHelpText": "Αυτόματη εισαγωγή ολοκληρωμένων λήψεων από τον πελάτη λήψης", + "Enabled": "Ενεργοποιήθηκε", + "EnabledHelpText": "Ενεργοποιήστε αυτήν τη λίστα για χρήση στο Radarr", + "EnableHelpText": "Ενεργοποίηση δημιουργίας αρχείων μεταδεδομένων για αυτόν τον τύπο μεταδεδομένων", + "EnableInteractiveSearchHelpText": "Θα χρησιμοποιηθεί όταν χρησιμοποιείται διαδραστική αναζήτηση" } diff --git a/src/NzbDrone.Core/Localization/Core/es.json b/src/NzbDrone.Core/Localization/Core/es.json index 2ee39f81b..b2d1edae3 100644 --- a/src/NzbDrone.Core/Localization/Core/es.json +++ b/src/NzbDrone.Core/Localization/Core/es.json @@ -1,7 +1,5 @@ { "Indexers": "Indexers", - "ImportMechanismHealthCheckMessage": "Activar Manipulación de Descargas Completadas", - "iCalLink": "iCal Link", "Host": "Host", "History": "Historia", "HideAdvanced": "Ocultar Avanzado", @@ -17,7 +15,6 @@ "DownloadClients": "Gestores de Descargas", "DownloadClientCheckUnableToCommunicateMessage": "Incapaz de comunicarse con {0}.", "DownloadClientCheckNoneAvailableMessage": "Ningún gestor de descargas disponible", - "Discover": "Descubrir", "Delete": "Borrar", "Dates": "Fechas", "Date": "Fecha", @@ -25,13 +22,11 @@ "Connections": "Conexiones", "Connect": "Conectar", "Clear": "Borrar", - "Blacklist": "Bloqueadas", "BackupNow": "Hacer copia de seguridad", "Backup": "Backup", "AppDataLocationHealthCheckMessage": "No será posible actualizar para prevenir que AppData se borre durante la actualización", "Analytics": "Analíticas", "All": "Todas", - "AddNew": "Añadir Nueva", "About": "Acerca", "View": "Vista", "Updates": "Actualizaciones", @@ -51,14 +46,11 @@ "SetTags": "Poner Etiquetas", "SelectAll": "Seleccionar Todas", "Security": "Seguridad", - "SearchAll": "Buscar Todas", "Search": "Buscar", "Scheduled": "Programado", "SaveChanges": "Guardar Cambios", - "RootFolderCheckMultipleMessage": "Varias carpetas de origen no existen: {0}", "Restrictions": "Restricciones", "RestoreBackup": "Recuperar Backup", - "RemovedMovieCheckMultipleMessage": "Las películas {0} ya no están en TMDb", "ReleaseBranchCheckPreviousVersionMessage": "La versión {0} es de una versión anterior de Prowlarr, ajusta la versión a 'Nightly' para recibir actualizaciones", "ReleaseBranchCheckOfficialBranchMessage": "Las versión {0} no es una versión válida de Prowlarr, no recibirás actualizaciones", "Refresh": "Actualizar", @@ -75,8 +67,6 @@ "Movies": "Películas", "MonoNotNetCoreCheckMessage": "Por favor actualiza a la versión .NET Core de Prowlarr", "MoreInfo": "Más Información", - "MinimumAvailability": "Disponibilidad Mínima", - "MediaInfoDllCheckMessage": "La Librería MediaInfo no se ha cargado {0}", "Logging": "Registro de eventos", "LogFiles": "Archivos de Registro", "Languages": "Idiomas", @@ -89,9 +79,7 @@ "Size": "Tamaño", "ReleaseStatus": "Estado del Estreno", "Protocol": "Protocolo", - "OutputPath": "Ruta de Output", "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls todavía está habilitado, considera la posibilidad de eliminar la opción MONO_TLS_PROVIDER=legacy", - "MassMovieSearch": "Búsqueda en masa de películas", "LastWriteTime": "Última Fecha de Escritura", "IndexerStatusCheckSingleClientMessage": "Indexers no disponibles debido a errores: {0}", "Indexer": "Indexer", @@ -120,7 +108,6 @@ "Reload": "Recargar", "Peers": "Peers", "PageSize": "Tamaño de Página", - "OrganizeModalAllPathsRelative": "Todas las rutas son relativas a:", "Ok": "Ok", "OAuthPopupMessage": "Pop-ups bloqueados por su navegador", "Name": "Nombre", @@ -141,46 +128,34 @@ "Age": "Edad", "SystemTimeCheckMessage": "El reloj del sistema está retrasado más de un día. Las tareas de mantenimiento no se ejecutarán correctamente hasta que se haya corregido", "ExistingMovies": "Película(s) Existente", - "DetailedProgressBar": "Barra de Progreso Detallada", "UnsavedChanges": "Cambios no guardados", - "ShowSizeOnDisk": "Mostrar Tamaño en Disco", "ShowSearchHelpText": "Mostrar botón de búsqueda al pasar el cursor por encima", "ShowSearch": "Mostrar Búsqueda", - "ShowDateAdded": "Mostrar Fecha de Añadido", - "SettingsUiLanguage": "Idioma de UI", "SettingsTimeFormat": "Formato de Hora", "SettingsShowRelativeDatesHelpText": "Mostrar fechas relativas (Hoy/Ayer/etc) o absolutas", "SettingsShowRelativeDates": "Mostrar Fechas Relativas", "SettingsShortDateFormat": "Formato Corto de Fecha", - "SettingsRemotePathMappingLocalPath": "Ruta Local", "SettingsLongDateFormat": "Formato Largo de Fecha", - "SearchMovie": "Buscar Película", - "Posters": "Posters", "PendingChangesStayReview": "Permanecer y revisar cambios", "PendingChangesMessage": "Hay cambios sin salvar, estás seguro de que quieres salir de esta página?", "PendingChangesDiscardChanges": "Descartar cambios y salir", "MonoVersionCheckUpgradeRecommendedMessage": "Le versión de Mono {0} instalada actualmente es compatible pero se recomienda actualizar a {1}.", "SettingsEnableColorImpairedModeHelpText": "Estilo modificado para permitir que usuarios con problemas de color distingan mejor la información codificada por colores", "SettingsEnableColorImpairedMode": "Activar Modo De Color Degradado", - "Grab": "Capturar", "GeneralSettings": "Ajustes Generales", "Fixed": "Arreglado", - "Exluded": "Excluida", "EnableSslHelpText": " Requiere reiniciar la aplicación como administrador para que surta efecto", "EnableMediaInfoHelpText": "Extraiga información de video como resolución, tiempo de ejecución e información de códec de los archivos. Esto requiere que Prowlarr lea partes del archivo y puede causar una alta actividad en el disco o en la red durante los escaneos.", "Enable": "Habilitar", - "DownloadWarningCheckDownloadClientForMoreDetails": "Advertencia de descarga: consulte el gestor de descargas para obtener más detalles", "DownloadClientSettings": "Ajustes de Gestor de Descargas", "Docker": "Docker", "DeleteTag": "Borrar Etiqueta", "DeleteNotification": "Borrar Notificación", "DeleteIndexer": "Borrar Indexer", - "DeleteEmptyFolders": "Borrar carpetas vacías", "DeleteDownloadClient": "Borrar Gestor de Descargas", "DeleteBackup": "Borrar Backup", "DelayProfile": "Perfil de Retraso", "DBMigration": "Migración de DB", - "CreateEmptyMovieFolders": "Crear carpetas de películas vacías", "CloneProfile": "Clonar Perfil", "CloneIndexer": "Clonar Indexer", "ClientPriority": "Prioridad de Cliente", @@ -194,7 +169,6 @@ "BackupRetentionHelpText": "Backups automáticos anteriores al período de retención serán borrados automáticamente", "BackupIntervalHelpText": "Intervalo entre backups automáticos", "BackupFolderHelpText": "Las rutas relativas estarán en el directorio AppData de Prowlarr", - "AutoRedownloadFailedHelpText": "Buscar e intentar descargar automáticamente una versión diferente", "Automatic": "Automático", "AuthenticationMethodHelpText": "Requerir nombre de usuario y contraseña para acceder Prowlarr", "Authentication": "Autenticación", @@ -203,8 +177,6 @@ "ApplyTags": "Aplicar Etiquetas", "AppDataDirectory": "Directorio de AppData", "AnalyticsEnabledHelpText": "Envíe información anónima de uso y error a los servidores de Prowlarr. Esto incluye información sobre su navegador, qué páginas de Prowlarr WebUI utiliza, informes de errores, así como el sistema operativo y la versión en tiempo de ejecución. Usaremos esta información para priorizar funciones y correcciones de errores.", - "AllowHardcodedSubs": "Permitir Hardcoded Subs", - "AddListExclusion": "Añadir Exclusión De Lista", "YesCancel": "Si, Cancela", "Version": "Versión", "Username": "Nombre de usuario", @@ -223,7 +195,6 @@ "UnableToLoadDownloadClients": "No se puden cargar los gestores de descargas", "UISettings": "Ajustes del UI", "Torrents": "Torrents", - "TMDBId": "TMDb Id", "TestAllClients": "Comprobar Todos los Gestores", "TagsHelpText": "Se aplica a películas con al menos una etiqueta coincidente", "SuggestTranslationChange": "Sugerir un cambio en la traducción", @@ -231,9 +202,6 @@ "SSLPort": "Puerto SSL", "SSLCertPath": "Ruta del Certificado SSL", "SSLCertPassword": "Contraseña del Certificado SSL", - "SkipFreeSpaceCheckWhenImportingHelpText": "Usar cuando Prowlarr no pueda detectar el espacio disponible en la carpeta de películas", - "ShowQualityProfileHelpText": "Mostrar el perfil de calidad debajo del poster", - "ShowCutoffUnmetIconHelpText": "Mostrar el icono para los ficheros cuando no se ha alcanzado el corte", "SetPermissionsLinuxHelpText": "Debe chmod ser ejecutado una vez los archivos hayan sido importados/renombrados?", "SendAnonymousUsageData": "Enviar Datos de Uso Anónimamente", "ScriptPath": "Ruta del Script", @@ -244,15 +212,9 @@ "RestartNow": "Reiniciar Ahora", "ResetAPIKey": "Reajustar API", "Reset": "Reajustar", - "RequiredHelpText": "Esta condición {0} ha de igualar al formato propio para aplicarse. Si no, una sóla {1} es suficiente.", - "RenameMoviesHelpText": "Prowlarr usará el nombre del archivo si el renombrado está deshabilitado", - "RemoveFromDownloadClient": "Eliminar del Gestor de Descargas", "RemoveFilter": "Eliminar filtro", "RemovedFromTaskQueue": "Eliminar de la cola de tareas", - "ReleaseDates": "Fechas de Estreno", "RefreshMovie": "Actualizar película", - "RecyclingBin": "Papelera de Reciclaje", - "Reason": "Razón", "ReadTheWikiForMoreInformation": "Lee la Wiki para más información", "QualitySettings": "Ajustes de Calidad", "ProxyUsernameHelpText": "Tienes que introducir tu nombre de usuario y contraseña sólo si son requeridos. Si no, déjalos vacios.", @@ -272,19 +234,14 @@ "NoLeaveIt": "No, Déjalo", "New": "Nueva", "NetCore": ".NET Core", - "MovieYearHelpText": "Año de la película a excluir", - "MovieInfoLanguageHelpTextWarning": "Recargar el Navegador", - "MovieAvailableButMissing": "Película Disponible pero Ausente", "MonoVersion": "Version de Mono", "Mode": "Modo", "MinimumLimits": "Límites Mínimos", - "MinimumAge": "Edad Mínima", "MIA": "MIA", "Mechanism": "Mecanismo", "MaximumLimits": "Límites Máximos", "Logs": "Registros", "LogLevel": "Nivel de Registro", - "ListSettings": "Ajustes de Lista", "LaunchBrowserHelpText": " Abrir un navegador web e ir a la página de inicio de Prowlarr al arrancar la app.", "Interval": "Intervalo", "IndexerFlags": "Marcas de Indexer", @@ -303,25 +260,19 @@ "EnableAutomaticSearch": "Habilitar Búsqueda Automática", "EnableAutomaticAdd": "Habilitar Añadido Automático", "EnableAutoHelpText": "Si se habilita, las Películas en esta lista se añadirán automáticamente a Prowlarr", - "CopyUsingHardlinksHelpText": "Usar Hardlinks al intentar copiar ficheros de los torrents que siguen seedeando", "ConnectSettings": "Conectar Ajustes", "BindAddress": "Dirección de Ligado", "OpenBrowserOnStart": "Abrir navegador al arrancar", "OnHealthIssueHelpText": "En Problema de Salud", - "MovieIsOnImportExclusionList": "La película está en la Lista de Exclusión", "TagCannotBeDeletedWhileInUse": "No se puede eliminar estando en uso", "SSLCertPathHelpText": "Ruta al archivo pfx", "SSLCertPasswordHelpText": "Contraseña para el archivo pfx", "ShownClickToHide": "Mostrado, clic para ocultar", - "RSSSyncIntervalHelpTextWarning": "Se aplicará a todos los indexers, por favor sigue las reglas de los mismos", "RSSIsNotSupportedWithThisIndexer": "RSS no son soportadas por este indexer", "RemovingTag": "Eliminando etiqueta", "Pending": "Pendiente", - "MovieIsUnmonitored": "La película no está monitoreada", - "MovieAlreadyExcluded": "Película ya Excluida", "Manual": "Manual", "LogLevelTraceHelpTextWarning": "El registro de seguimiento se ha de habilitar solo temporalmente", - "ImportFailedInterp": "la importación ha fallado: {0}", "HiddenClickToShow": "Oculto, clic para mostrar", "ExistingTag": "Etiqueta existente", "EnableInteractiveSearchHelpTextWarning": "Buscar no está soportado por este indexer", @@ -335,16 +286,12 @@ "DeleteBackupMessageText": "Seguro que quieres eliminar la copia de seguridad '{0}'?", "DeleteDownloadClientMessageText": "Seguro que quieres eliminar el gestor de descargas '{0}'?", "DeleteIndexerMessageText": "Seguro que quieres eliminar el indexer '{0}'?", - "CheckDownloadClientForDetails": "comprobar el gestor de descargas para más detalles", "CancelPendingTask": "Seguro que quieres cancelar esta tarea pendiente?", "BranchUpdateMechanism": "Rama usada por el mecanismo de actualización externo", "BranchUpdate": "Qué rama usar para actualizar Prowlarr", "BeforeUpdate": "Antes de actualizar", "AddingTag": "Añadiendo etiqueta", - "VisitGithubCustomFormatsAphrodite": "Visita Github para más detalles: ", "UnableToLoadUISettings": "No se han podido cargar los ajustes de UI", - "UnableToLoadNamingSettings": "No se han podido cargar los ajustes de renombrado", - "UnableToLoadLanguages": "No se han podido cargar los idiomas", "UnableToLoadHistory": "No se ha podido cargar la historia", "UnableToLoadGeneralSettings": "No se han podido cargar los ajustes Generales", "UnableToLoadBackups": "No se han podido cargar las copias de seguridad", @@ -364,14 +311,10 @@ "MinutesNinety": "90 Minutos: {0}", "MinutesHundredTwenty": "120 Minutos: {0}", "MaintenanceRelease": "Lanzamiento de mantenimiento", - "LinkHere": "aquí", - "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Para más información individual sobre las listas de importación, haz clic en los botones de información.", "ForMoreInformationOnTheIndividualDownloadClients": "Para más información individual de los gestores de descarga, haz clic en lls botones de información.", "FilterPlaceHolder": "Buscar películas", - "ExtraFileExtensionsHelpTexts2": "Ejemplos : '.sub, .nfo' o 'sub,nfo'", "Exception": "Excepción", "ErrorLoadingContents": "Error al cargar los contenidos", - "CantFindMovie": "Por qué no puedo encontrar mi película?", "ApplyTagsHelpTexts4": "Reemplazar: Reemplazar las etiquetas con las etiquetas introducidas (no introducir etiquetas para eliminar todas las etiquetas)", "ApplyTagsHelpTexts3": "Eliminar: Eliminar las etiquetas introducidas", "ApplyTagsHelpTexts2": "Añadir: Añadir a las etiquetas la lista existente de etiquetas", @@ -379,9 +322,6 @@ "UILanguageHelpTextWarning": "Recargar el Navegador", "UILanguageHelpText": "Lenguaje que Prowlarr usara para el UI", "UILanguage": "Lenguaje de UI", - "ExportCustomFormat": "Exportar Formato Personalizado", - "DownloadPropersAndRepacks": "Propers y Repacks", - "CopyToClipboard": "Copiar al portapapeles", "Priority": "Prioridad", "InteractiveSearch": "Búsqueda Interactiva", "IndexerPriorityHelpText": "Prioridad del Indexer de 1 (La más alta) a 50 (La más baja). Por defecto: 25.", @@ -399,11 +339,39 @@ "MovieDetailsNextMovie": "Detalles de la película: Siguiente Película", "CloseCurrentModal": "Cerrar Modal Actual", "AcceptConfirmationModal": "Aceptar el Modal de Confirmación", - "SearchFailedPleaseTryAgainLater": "La búsqueda ha fallado, por favor inténtalo de nuevo más tarde.", - "NoMatchFound": "No se han encontrado coincidencias!", - "Existing": "Existente", "AddRestriction": "Añadir Restricción", "IndexerLongTermStatusCheckSingleClientMessage": "Indexers no disponible por errores durando más de 6 horas: {0}", "IndexerLongTermStatusCheckAllClientMessage": "Ningún indexer está disponible por errores durando más de 6 horas", - "PrioritySettings": "Prioridad" + "PrioritySettings": "Prioridad", + "Reddit": "Reddit", + "UnableToAddANewAppProfilePleaseTryAgain": "No se ha podido añadir un nuevo perfil de calidad, prueba otra vez.", + "DeleteIndexerProxyMessageText": "Seguro que quieres eliminar la etiqueta '{0}'?", + "Discord": "Discordia", + "Add": "Añadir", + "Custom": "Personalizado", + "Donations": "Donaciones", + "SearchIndexers": "Buscar películas", + "Enabled": "Habilitado", + "Grabs": "Capturar", + "Presets": "Preajustes", + "RSS": "RSS", + "Today": "Hoy", + "Tomorrow": "mañana", + "Torrent": "Torrents", + "UnableToAddANewIndexerProxyPleaseTryAgain": "No se ha podido añadir un nuevo indexer, prueba otra vez.", + "Wiki": "Wiki", + "Yesterday": "Ayer", + "ApplicationStatusCheckAllClientMessage": "Las listas no están disponibles debido a errores", + "ApplicationStatusCheckSingleClientMessage": "Listas no disponibles debido a errores: {0}", + "AllIndexersHiddenDueToFilter": "Todas las películas están ocultas debido al filtro aplicado.", + "DeleteApplicationMessageText": "Seguro que quieres elminiar la notificación '{0}'?", + "IndexerProxyStatusCheckAllClientMessage": "Los indexers no están disponibles debido a errores", + "IndexerProxyStatusCheckSingleClientMessage": "Indexers no disponibles debido a errores: {0}", + "NoLinks": "Sin enlaces", + "AddDownloadClient": "Añadir Gestor de Descargas", + "CouldNotConnectSignalR": "No se pudo conectar a SignalR, la interfaz de usuario no se actualiza", + "EnableRss": "Habilitar RSS", + "FeatureRequests": "Peticiones de características", + "HomePage": "Página de inicio", + "UnableToAddANewApplicationPleaseTryAgain": "No se ha podido añadir una nueva notificación, prueba otra vez." } diff --git a/src/NzbDrone.Core/Localization/Core/fi.json b/src/NzbDrone.Core/Localization/Core/fi.json index 0967ef424..d32c061d1 100644 --- a/src/NzbDrone.Core/Localization/Core/fi.json +++ b/src/NzbDrone.Core/Localization/Core/fi.json @@ -1 +1,361 @@ -{} +{ + "IndexerProxyStatusCheckSingleClientMessage": "Hakemistot eivät ole käytettävissä vikojen takia: {0}", + "Logging": "Kirjaaminen", + "LogLevel": "Lokitaso", + "MovieIndexScrollTop": "Elokuvahakemisto: Vieritä alkuun", + "Apply": "Käytä", + "ClientPriority": "Asiakkaan prioriteetti", + "EnabledHelpText": "Ota tämä luettelo käyttöön Radarrissa", + "IndexerPriorityHelpText": "Hakemistoprioriteetti 1 (korkein) 50 (matalin). Oletus: 25.", + "Manual": "Manuaalinen", + "Add": "Lisätä", + "Reload": "Lataa uudelleen", + "Indexers": "Hakemistot", + "MovieIndexScrollBottom": "Elokuvahakemisto: Vieritä alareunaa", + "Movies": "Elokuvat", + "PtpOldSettingsCheckMessage": "Seuraavilla PassThePopcorn-indeksoijilla on vanhentuneet asetukset, ja ne tulisi päivittää: {0}", + "QualityDefinitions": "Laadun määritelmät", + "SSLCertPassword": "SSL-varmenteen salasana", + "Style": "Tyyli", + "Tags": "Tunnisteet", + "Today": "Tänään", + "About": "Noin", + "AcceptConfirmationModal": "Hyväksy vahvistusmoodi", + "Actions": "Toiminnot", + "ApplicationStatusCheckAllClientMessage": "Kaikki luettelot eivät ole käytettävissä vikojen takia", + "ApplicationStatusCheckSingleClientMessage": "Luettelot eivät ole käytettävissä vikojen takia: {0}", + "Date": "Päivämäärä", + "Dates": "Päivämäärät", + "SettingsTimeFormat": "Aikamuoto", + "Message": "Viesti", + "Seeders": "Kylvökoneet", + "TestAll": "Testaa kaikki", + "AddDownloadClient": "Lisää latausasiakas", + "CustomFilters": "Mukautetut suodattimet", + "DeleteIndexer": "Poista indeksointilaite", + "DeleteTag": "Poista tunniste", + "DownloadClientCheckNoneAvailableMessage": "Latausasiakasta ei ole käytettävissä", + "EnableRss": "Ota RSS käyttöön", + "Filter": "Suodattaa", + "Fixed": "Kiinteä", + "FocusSearchBox": "Kohdista hakukenttä", + "ForMoreInformationOnTheIndividualDownloadClients": "Saat lisätietoja yksittäisistä latausohjelmista napsauttamalla tietopainikkeita.", + "HideAdvanced": "Piilota Lisäasetukset", + "History": "Historia", + "MIA": "MIA", + "MonoVersion": "Mono-versio", + "MonoVersionCheckUpgradeRecommendedMessage": "Tällä hetkellä asennettua mono-versiota {0} tuetaan, mutta päivittämistä versioon {1} suositellaan.", + "New": "Uusi", + "PageSizeHelpText": "Kullakin sivulla näytettävien kohteiden määrä", + "Proxy": "Välityspalvelin", + "ProxyBypassFilterHelpText": "Käytä erottimena ',' ja '*.' jokerimerkkinä aliverkkotunnuksille", + "Reddit": "Reddit", + "Refresh": "virkistää", + "RefreshMovie": "Päivitä elokuva", + "ReleaseBranchCheckOfficialBranchMessage": "Branch {0} ei ole kelvollinen Radarr-julkaisuhakemisto, et saa päivityksiä", + "RestartRequiredHelpTextWarning": "Edellyttää uudelleenkäynnistystä voimaantulemiseksi", + "Result": "Tulos", + "Settings": "asetukset", + "SettingsLongDateFormat": "Pitkä päivämäärämuoto", + "SettingsShortDateFormat": "Lyhyt päivämäärämuoto", + "UnselectAll": "Poista kaikkien valinta", + "UpdateCheckStartupTranslocationMessage": "Päivitystä ei voi asentaa, koska käynnistyskansio {0} on App Translocation -kansiossa.", + "UpdateCheckUINotWritableMessage": "Päivitystä ei voi asentaa, koska käyttäjä {1} ei voi kirjoittaa käyttöliittymäkansiota {0}.", + "UpdateMechanismHelpText": "Käytä Radarrin sisäänrakennettua päivitysohjelmaa tai komentosarjaa", + "ApplyTagsHelpTexts3": "Poista: Poista syötetyt tunnisteet", + "Enable": "ota käyttöön", + "UI": "UI", + "UrlBaseHelpText": "Käänteisen välityspalvelimen tuen oletus on tyhjä", + "Usenet": "Usenet", + "BackupNow": "Varmuuskopioi nyt", + "NoBackupsAreAvailable": "Varmuuskopioita ei ole saatavilla", + "UpdateCheckStartupNotWritableMessage": "Päivitystä ei voi asentaa, koska Käynnistyskansiota {0} ei voi kirjoittaa käyttäjä {1}.", + "Updates": "Päivitykset", + "UpdateScriptPathHelpText": "Polku mukautettuun komentosarjaan, joka vie puretun päivityspaketin ja käsittelee loput päivitysprosessista", + "Uptime": "Käyttöaste", + "URLBase": "URL-pohja", + "UseProxy": "Käytä välityspalvelinta", + "Username": "Käyttäjätunnus", + "YesCancel": "Kyllä, Peruuta", + "NoTagsHaveBeenAddedYet": "Tunnisteita ei ole vielä lisätty", + "ApplyTags": "Käytä tunnisteita", + "Authentication": "Todennus", + "AuthenticationMethodHelpText": "Vaadi käyttäjätunnus ja salasana käyttääksesi Radarria", + "BindAddressHelpText": "Voimassa oleva IP4-osoite tai '*' kaikille liitännöille", + "Close": "kiinni", + "DeleteNotification": "Poista ilmoitus", + "Docker": "Satamatyöläinen", + "DownloadClient": "Lataa asiakasohjelma", + "EnableMediaInfoHelpText": "Pura tiedostoista videotiedot, kuten tarkkuus, ajonaika ja koodekkitiedot. Tämä edellyttää, että Radarr lukee tiedoston osat, jotka voivat aiheuttaa paljon levyn tai verkon toimintaa tarkistusten aikana.", + "Language": "Kieli", + "Search": "Hae", + "Details": "Yksityiskohdat", + "InteractiveSearch": "Interaktiivinen haku", + "Interval": "Intervalli", + "KeyboardShortcuts": "Pikanäppäimet", + "Languages": "Kieli (kielet", + "LastWriteTime": "Viimeinen kirjoitusaika", + "LogFiles": "Lokitiedostot", + "LogLevelTraceHelpTextWarning": "Jäljityksen kirjaaminen tulisi ottaa käyttöön vain väliaikaisesti", + "Logs": "Lokit", + "MaximumLimits": "Enimmäisrajat", + "Mechanism": "Mekanismi", + "MonoTlsCheckMessage": "Radarr Mono 4.x -tls -kiertotapa on edelleen käytössä, harkitse MONO_TLS_PROVIDER = vanhan ympäristön vaihtoehdon poistamista", + "MovieDetailsNextMovie": "Elokuvan tiedot: Seuraava elokuva", + "MovieDetailsPreviousMovie": "Elokuvan tiedot: Edellinen elokuva", + "Name": "Nimi", + "NoLinks": "Ei linkkejä", + "Peers": "Peers", + "Pending": "Odottaa", + "PreferredSize": "Haluttu koko", + "Presets": "Esiasetukset", + "Priority": "Prioriteetti", + "PriorityHelpText": "Priorisoi useita latausasiakkaita. Round-Robinia käytetään asiakkaille, joilla on sama prioriteetti.", + "PrioritySettings": "Prioriteetti", + "Protocol": "Pöytäkirja", + "ProxyCheckBadRequestMessage": "Välityspalvelimen testaaminen epäonnistui. StatusCode: {0}", + "ProxyCheckFailedToTestMessage": "Välityspalvelimen testaaminen epäonnistui: {0}", + "ProxyCheckResolveIpMessage": "Määritetyn välityspalvelimen {0} IP-osoitteen selvittäminen epäonnistui", + "ProxyPasswordHelpText": "Käyttäjänimi ja salasana on annettava vain, jos niitä tarvitaan. Jätä ne muuten tyhjiksi.", + "ProxyType": "Välityspalvelimen tyyppi", + "ProxyUsernameHelpText": "Käyttäjänimi ja salasana on annettava vain, jos niitä tarvitaan. Jätä ne muuten tyhjiksi.", + "QualitySettings": "Laatuasetukset", + "Queue": "Jonottaa", + "ReadTheWikiForMoreInformation": "Lue lisätietoja Wikistä", + "ReleaseStatus": "Vapauta tila", + "RemovedFromTaskQueue": "Poistettu tehtäväjonosta", + "RemoveFilter": "Poista suodatin", + "RemovingTag": "Poistetaan tagia", + "Reset": "Nollaa", + "ResetAPIKey": "Nollaa API-avain", + "Restart": "Uudelleenkäynnistää", + "RestartNow": "Käynnistä uudelleen nyt", + "Restore": "Palauttaa", + "RSS": "RSS", + "RSSIsNotSupportedWithThisIndexer": "RSS-tiedostoa ei tueta tässä hakemistossa", + "ScriptPath": "Komentosarjan polku", + "Security": "Turvallisuus", + "SuggestTranslationChange": "Ehdota käännösmuutosta", + "System": "Järjestelmä", + "SystemTimeCheckMessage": "Järjestelmäaika on pois päältä yli päivällä. Ajoitetut tehtävät eivät välttämättä toimi oikein ennen kuin aika on korjattu", + "TagCannotBeDeletedWhileInUse": "Ei voida poistaa käytön aikana", + "TagIsNotUsedAndCanBeDeleted": "Tunnistetta ei käytetä ja se voidaan poistaa", + "TagsSettingsSummary": "Katso kaikki tunnisteet ja niiden käyttö. Käyttämättömät tunnisteet voidaan poistaa", + "Tasks": "Tehtävät", + "Test": "Testata", + "TestAllClients": "Testaa kaikki asiakkaat", + "Time": "Aika", + "Title": "Otsikko", + "Tomorrow": "Huomenna", + "Torrent": "Torrentit", + "Torrents": "Torrentit", + "Type": "Tyyppi", + "UILanguage": "Käyttöliittymän kieli", + "UnableToAddANewApplicationPleaseTryAgain": "Uutta ilmoitusta ei voi lisätä, yritä uudelleen.", + "UnableToAddANewIndexerPleaseTryAgain": "Uutta hakemistoa ei voi lisätä, yritä uudelleen.", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Uutta hakemistoa ei voi lisätä, yritä uudelleen.", + "UnableToLoadBackups": "Varmuuskopioita ei voi ladata", + "UnableToLoadDownloadClients": "Latausohjelmia ei voi ladata", + "UnableToLoadGeneralSettings": "Yleisiä asetuksia ei voi ladata", + "UpdateAutomaticallyHelpText": "Lataa ja asenna päivitykset automaattisesti. Voit silti asentaa System: Updates -sovelluksesta", + "Added": "Lisätty", + "AddIndexer": "Lisää indeksoija", + "AddingTag": "Lisätään tagi", + "Age": "Ikä", + "All": "Kaikki", + "AllIndexersHiddenDueToFilter": "Kaikki elokuvat on piilotettu käytetyn suodattimen takia.", + "Analytics": "Analytics", + "AnalyticsEnabledHelpText": "Lähetä nimettömiä käyttö- ja virhetietoja Radarrin palvelimille. Tämä sisältää tietoja selaimestasi, mitä Radarr WebUI -sivuja käytät, virheraportoinnista sekä käyttöjärjestelmästä ja ajonaikaisesta versiosta. Käytämme näitä tietoja priorisoimaan ominaisuuksia ja virhekorjauksia.", + "ApiKey": "API-avain", + "AppDataDirectory": "AppData-hakemisto", + "DBMigration": "DB-siirto", + "Delete": "Poistaa", + "DeleteIndexerProxyMessageText": "Haluatko varmasti poistaa tagin {0}?", + "DeleteNotificationMessageText": "Haluatko varmasti poistaa ilmoituksen {0}?", + "Disabled": "Liikuntarajoitteinen", + "DownloadClientCheckUnableToCommunicateMessage": "Ei voida kommunikoida käyttäjän {0} kanssa.", + "DownloadClients": "Lataa asiakkaita", + "DownloadClientSettings": "Lataa asiakasasetukset", + "DownloadClientStatusCheckAllClientMessage": "Kaikki latausasiakkaat eivät ole käytettävissä vikojen takia", + "MinutesHundredTwenty": "120 minuuttia: {0}", + "MinutesNinety": "90 minuuttia: {0}", + "MinutesSixty": "60 minuuttia: {0}", + "Mode": "Tila", + "MoreInfo": "Lisätietoja", + "SelectAll": "Valitse kaikki", + "SendAnonymousUsageData": "Lähetä nimettömiä käyttötietoja", + "SetTags": "Aseta tunnisteet", + "SettingsEnableColorImpairedMode": "Ota käyttöön Värin heikentynyt tila", + "ShowAdvanced": "Näytä Lisäasetukset", + "ShowSearchHelpText": "Näytä hakupainike hiirellä", + "Shutdown": "Sammuttaa", + "Size": "Koko", + "Sort": "Järjestellä", + "UnableToAddANewDownloadClientPleaseTryAgain": "Uutta latausasiakasta ei voi lisätä, yritä uudelleen.", + "AppDataLocationHealthCheckMessage": "Päivittäminen ei ole mahdollista estää AppDatan poistamista päivityksestä", + "UnableToLoadHistory": "Historiaa ei voi ladata", + "UnableToLoadIndexers": "Hakemistoja ei voi ladata", + "UnableToLoadNotifications": "Ilmoituksia ei voi ladata", + "UnableToLoadQualityDefinitions": "Laatumääritelmiä ei voi ladata", + "UnableToLoadTags": "Tunnisteita ei voi ladata", + "UnableToLoadUISettings": "Käyttöliittymän asetuksia ei voi ladata", + "UnsavedChanges": "Tallentamattomat muutokset", + "Yesterday": "Eilen", + "ConnectionLost": "Yhteys kadotettu", + "ConnectionLostAutomaticMessage": "Radarr yrittää muodostaa yhteyden automaattisesti, tai voit napsauttaa Lataa alla.", + "DeleteDownloadClientMessageText": "Haluatko varmasti poistaa latausasiakasohjelman {0}?", + "DeleteTagMessageText": "Haluatko varmasti poistaa tagin {0}?", + "Discord": "Erimielisyydet", + "Donations": "Lahjoitukset", + "DownloadClientUnavailable": "Latausohjelma ei ole käytettävissä", + "Downloading": "Ladataan", + "Edit": "Muokata", + "EnableAutomaticSearchHelpText": "Käytetään, kun automaattiset haut suoritetaan käyttöliittymän tai Radarrin kautta", + "EnableAutomaticSearchHelpTextWarning": "Käytetään, kun käytetään interaktiivista hakua", + "EnableColorImpairedModeHelpText": "Muutettu tyyli, jotta värivammaiset käyttäjät voivat erottaa paremmin värikoodatut tiedot", + "Enabled": "Käytössä", + "EnableInteractiveSearchHelpTextWarning": "Hakemistoa ei tueta tällä hakemistolla", + "EventType": "Tapahtumatyyppi", + "Exception": "Poikkeus", + "FeatureRequests": "Ominaisuuspyynnöt", + "Grabbed": "Tarttui", + "IgnoredAddresses": "Ohitetut osoitteet", + "IllRestartLater": "Aloitan myöhemmin uudelleen", + "Info": "Tiedot", + "LaunchBrowserHelpText": " Avaa verkkoselain ja siirry Radarrin kotisivulle sovelluksen alkaessa.", + "MinimumLimits": "Vähimmäisrajat", + "NoChanges": "Ei muutoksia", + "NoLeaveIt": "Ei, jätä se", + "PendingChangesMessage": "Sinulla on tallentamattomia muutoksia. Haluatko varmasti poistua tältä sivulta?", + "PendingChangesStayReview": "Pysy ja tarkista muutokset", + "Save": "Tallentaa", + "SaveChanges": "Tallenna muutokset", + "SaveSettings": "Tallenna asetukset", + "Scheduled": "Suunniteltu", + "SettingsEnableColorImpairedModeHelpText": "Muutettu tyyli, jotta värivammaiset käyttäjät voivat erottaa paremmin värikoodatut tiedot", + "SettingsShowRelativeDates": "Näytä suhteelliset päivämäärät", + "SettingsShowRelativeDatesHelpText": "Näytä suhteelliset (tänään / eilen / jne.) Tai absoluuttiset päivämäärät", + "ShownClickToHide": "Näkyy, piilota napsauttamalla", + "ShowSearch": "Näytä haku", + "Source": "Lähde", + "SSLPort": "SSL-portti", + "StartTypingOrSelectAPathBelow": "Aloita kirjoittaminen tai valitse alla oleva polku", + "StartupDirectory": "Käynnistyshakemisto", + "TableOptions": "Taulukon asetukset", + "TableOptionsColumnsMessage": "Valitse mitkä sarakkeet ovat näkyvissä ja missä järjestyksessä ne näkyvät", + "TagsHelpText": "Koskee elokuvia, joissa on vähintään yksi vastaava tunniste", + "UnableToAddANewAppProfilePleaseTryAgain": "Uutta laatuprofiilia ei voi lisätä, yritä uudelleen.", + "UnableToAddANewNotificationPleaseTryAgain": "Uutta ilmoitusta ei voi lisätä, yritä uudelleen.", + "Version": "Versio", + "View": "Näytä", + "Warn": "Varoittaa", + "Wiki": "Wiki", + "ApplyTagsHelpTexts1": "Kuinka lisätä tunnisteita valittuihin elokuviin", + "ApplyTagsHelpTexts2": "Lisää: Lisää tunnisteet olemassa olevaan tunnisteiden luetteloon", + "ApplyTagsHelpTexts4": "Korvaa: Korvaa tunnisteet syötetyillä tunnisteilla (tyhjennä kaikki tunnisteet kirjoittamalla mitään tunnisteita)", + "Importing": "Tuonti", + "Port": "Satama", + "AreYouSureYouWantToResetYourAPIKey": "Haluatko varmasti nollata API-avaimesi?", + "Automatic": "Automaattinen", + "AutomaticSearch": "Automaattinen haku", + "Backup": "Varmuuskopioida", + "BackupFolderHelpText": "Suhteelliset polut ovat Radarrin AppData-hakemistossa", + "BackupIntervalHelpText": "Automaattisten varmuuskopioiden väli", + "BackupRetentionHelpText": "Säilytysjaksoa vanhemmat automaattiset varmuuskopiot puhdistetaan automaattisesti", + "Backups": "Varmuuskopiot", + "BeforeUpdate": "Ennen päivitystä", + "BindAddress": "Sitova osoite", + "Branch": "Haara", + "BranchUpdate": "Haara, jota käytetään Radarrin päivittämiseen", + "BranchUpdateMechanism": "Ulkoisen päivitysmekanismin käyttämä haara", + "BypassProxyForLocalAddresses": "Ohita välityspalvelin paikallisille osoitteille", + "Cancel": "Peruuttaa", + "CancelPendingTask": "Haluatko varmasti peruuttaa tämän odottavan tehtävän?", + "CertificateValidation": "Varmenteen vahvistus", + "CertificateValidationHelpText": "Muuta, kuinka tiukka HTTPS-sertifikaatin vahvistus on", + "ChangeHasNotBeenSavedYet": "Muutosta ei ole vielä tallennettu", + "Clear": "Asia selvä", + "CloneIndexer": "Kloonihakemisto", + "CloneProfile": "Klooniprofiili", + "CloseCurrentModal": "Sulje nykyinen modaali", + "Columns": "Sarakkeet", + "Component": "Komponentti", + "Connections": "Liitännät", + "ConnectSettings": "Yhdistä asetukset", + "CouldNotConnectSignalR": "Yhdistäminen SignalR-verkkoon epäonnistui, käyttöliittymää ei päivitetä", + "Custom": "Mukautettu", + "DelayProfile": "Viivytä profiili", + "DeleteApplicationMessageText": "Haluatko varmasti poistaa ilmoituksen {0}?", + "DeleteBackup": "Poista varmuuskopio", + "DeleteBackupMessageText": "Haluatko varmasti poistaa varmuuskopion {0}?", + "DeleteDownloadClient": "Poista Download Client", + "DeleteIndexerMessageText": "Haluatko varmasti poistaa indeksoijan {0}?", + "DownloadClientStatusCheckSingleClientMessage": "Latausasiakkaat eivät ole käytettävissä vikojen takia: {0}", + "EditIndexer": "Muokkaa hakemistoa", + "EnableAutoHelpText": "Jos tämä on käytössä, Elokuvat lisätään automaattisesti Radarriin tästä luettelosta", + "EnableAutomaticAdd": "Ota automaattinen lisäys käyttöön", + "EnableAutomaticSearch": "Ota automaattinen haku käyttöön", + "EnableColorImpairedMode": "Ota käyttöön Värin heikentynyt tila", + "EnableCompletedDownloadHandlingHelpText": "Tuo valmiit lataukset automaattisesti latausohjelmasta", + "EnableHelpText": "Ota käyttöön metatietotiedoston luominen tälle metatietotyypille", + "EnableInteractiveSearch": "Ota interaktiivinen haku käyttöön", + "EnableInteractiveSearchHelpText": "Käytetään, kun käytetään interaktiivista hakua", + "EnableSSL": "Ota SSL käyttöön", + "EnableSslHelpText": " Edellyttää uudelleenkäynnistyksen järjestelmänvalvojana voimaantuloa varten", + "Error": "Virhe", + "ErrorLoadingContents": "Virhe sisällön lataamisessa", + "Events": "Tapahtumat", + "ExistingMovies": "Olemassa olevat elokuvat", + "ExistingTag": "Olemassa oleva tunniste", + "Failed": "Epäonnistui", + "Filename": "Tiedoston nimi", + "Files": "Tiedostot", + "Folder": "Kansio", + "General": "Kenraali", + "GeneralSettings": "Yleiset asetukset", + "GeneralSettingsSummary": "Portti, SSL, käyttäjänimi / salasana, välityspalvelin, analytiikka ja päivitykset", + "Grabs": "Napata", + "Health": "Terveys", + "Level": "Taso", + "HealthNoIssues": "Ei ongelmia kokoonpanossasi", + "HiddenClickToShow": "Piilotettu, napsauta näyttääksesi", + "HomePage": "Kotisivu", + "Host": "Isäntä", + "Hostname": "Isäntänimi", + "IncludeHealthWarningsHelpText": "Sisällytä terveysvaroitukset", + "Indexer": "Hakemisto", + "IndexerFlags": "Hakemistoliput", + "IndexerLongTermStatusCheckAllClientMessage": "Kaikki indeksoijat eivät ole käytettävissä yli 6 tunnin vikojen takia", + "IndexerLongTermStatusCheckSingleClientMessage": "Indeksoijat eivät ole käytettävissä yli 6 tunnin vikojen takia: {0}", + "IndexerPriority": "Hakemistoprioriteetti", + "IndexerProxyStatusCheckAllClientMessage": "Kaikki luettelot eivät ole käytettävissä vikojen takia", + "IndexerStatusCheckAllClientMessage": "Kaikki indeksoijat eivät ole käytettävissä vikojen takia", + "IndexerStatusCheckSingleClientMessage": "Hakemistot eivät ole käytettävissä vikojen takia: {0}", + "NoChange": "Ei muutosta", + "NoLimitForAnyRuntime": "Ei rajoituksia ajonajalle", + "NoLogFiles": "Ei lokitiedostoja", + "NoMinimumForAnyRuntime": "Ei vähimmäismäärää millään ajon aikana", + "SSLCertPasswordHelpText": "Salasana pfx-tiedostolle", + "SSLCertPath": "SSL-varmenteen polku", + "SSLCertPathHelpText": "Polku pfx-tiedostoon", + "Status": "Tila", + "NotificationTriggers": "Ilmoituksen laukaisimet", + "NoUpdatesAreAvailable": "Päivityksiä ei ole saatavilla", + "OAuthPopupMessage": "Selaimesi estää ponnahdusikkunat", + "Ok": "Ok", + "OnHealthIssueHelpText": "Terveyskysymyksestä", + "OpenBrowserOnStart": "Avaa selain käynnistyksen yhteydessä", + "OpenThisModal": "Avaa tämä tila", + "Options": "Vaihtoehdot", + "PackageVersion": "Pakettiversio", + "PageSize": "Sivun koko", + "Password": "Salasana", + "PendingChangesDiscardChanges": "Hylkää muutokset ja lähde", + "PortNumber": "Porttinumero", + "RestoreBackup": "Palauta varmuuskopio", + "Restrictions": "Rajoitukset", + "Retention": "Säilytys", + "UILanguageHelpText": "Kieli, jota Radarr käyttää käyttöliittymään", + "UILanguageHelpTextWarning": "Selaimen uudelleenlataus vaaditaan", + "UISettings": "Käyttöliittymän asetukset" +} diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index 8fcf02b53..42ca9f44c 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -1,7 +1,6 @@ { "IndexerStatusCheckAllClientMessage": "Tous les indexeurs sont indisponibles en raison d'échecs", "Indexers": "Indexeurs", - "Import": "Importer", "Host": "Hôte", "History": "Historique", "HideAdvanced": "Masquer avancé", @@ -22,13 +21,11 @@ "Connections": "Connexions", "Connect": "Notifications", "Clear": "Effacer", - "Blacklist": "Liste noire", "BackupNow": "Sauvegarder maintenant", "Backup": "Sauvegarde", "AppDataLocationHealthCheckMessage": "La mise à jour ne sera pas possible d'empêcher la suppression AppData sur mise à jour", "Analytics": "Analytique", "All": "Tout", - "AddExclusion": "Ajouter une exclusion", "About": "À propos", "IndexerStatusCheckSingleClientMessage": "Indexeurs indisponibles en raison d'échecs : {0}", "DownloadClientStatusCheckSingleClientMessage": "Clients de Téléchargement indisponibles en raison d'échecs : {0}", @@ -48,14 +45,11 @@ "Settings": "Paramètres", "SelectAll": "Tout sélectionner", "Security": "Sécurité", - "SearchAll": "Rechercher tout", "Search": "Rechercher", "Scheduled": "Programmé", "SaveChanges": "Sauvegarder les modifications", - "RootFolderCheckSingleMessage": "Dossier racine manquant : {0}", "Restrictions": "Restrictions", "RestoreBackup": "Restaurer la sauvegarde", - "RemovedMovieCheckSingleMessage": "Le film {0} a été supprimé de TMDb", "ReleaseBranchCheckPreviousVersionMessage": "La branche {0} est pour une version précédente de Prowlarr, définissez la branche sur 'Nightly' pour d'autres mises à jour", "ReleaseBranchCheckOfficialBranchMessage": "La branche {0} n'est pas une branche de version Prowlarr valide, vous ne recevrez pas de mises à jour", "Refresh": "Rafraîchir", @@ -67,26 +61,20 @@ "ProxyCheckBadRequestMessage": "Échec du test du proxy. StatusCode : {0}", "Proxy": "Proxy", "Protocol": "Protocole", - "PreviewRename": "Aperçu Renommage", "Options": "Options", "NoChanges": "Aucun changement", "NoChange": "Pas de changement", "Movies": "Films", - "Movie": "Film", "MoreInfo": "Plus d'informations", "MonoTlsCheckMessage": "Solution de contournement Prowlarr Mono 4.x tls toujours activée, pensez à supprimer l'option d'environnement MONO_TLS_PROVIDER = legacy", - "ImportFirstTip": "Assurez-vous que vos fichiers incluent la qualité dans leurs noms de fichiers. par exemple.", "Grabbed": "Attrapé", "DownloadClientsSettingsSummary": "Clients de Téléchargement configuration pour l'intégration dans la recherche de l'interface utilisateur Prowlarr", "DownloadClientCheckUnableToCommunicateMessage": "Impossible de communiquer avec {0}.", "DownloadClient": "Client de Téléchargement", "MonoNotNetCoreCheckMessage": "Veuillez mettre à niveau vers la version .NET Core de Prowlarr", - "MinimumAvailability": "Disponibilité minimale", "MediaManagementSettingsSummary": "Paramètres de dénomination et de gestion des fichiers", - "ManualImport": "Importation manuelle", "Logging": "Enregistrement", "LogFiles": "Fichiers Log", - "ImportSecondTip": "Pointer Prowlarr vers le dossier contenant tous vos films, pas un en particulier. par exemple.", "View": "Vue", "Updates": "Mises à jour", "UI": "UI", @@ -131,7 +119,6 @@ "Reload": "Recharger", "Peers": "Pairs", "PageSize": "Pagination", - "OrganizeModalAllPathsRelative": "Tous les chemins sont relatifs à :", "Ok": "OK", "OAuthPopupMessage": "Les pop-ups sont bloquées par votre navigateur", "Name": "Nom", @@ -143,26 +130,20 @@ "SystemTimeCheckMessage": "L'heure du système est décalée de plus d'un jour. Les tâches planifiées peuvent ne pas s'exécuter correctement tant que l'heure ne sera pas corrigée", "SettingsShowRelativeDates": "Afficher les dates relatives", "UnsavedChanges": "Changement non sauvegardés", - "ShowSizeOnDisk": "Afficher la taille sur le disque", "ShowSearchHelpText": "Afficher le bouton de recherche au survol de la souris", "ShowSearch": "Afficher la recherche", - "SettingsWeekColumnHeader": "En-tête de la colonne : Semaine", "SettingsTimeFormat": "Format de l'heure", "SettingsShowRelativeDatesHelpText": "Afficher les dates relatives (Aujourd'hui/ Hier/ etc) ou absolues", "SettingsShortDateFormat": "Format de date court", - "SettingsRemotePathMappingLocalPath": "Chemin local", "SettingsLongDateFormat": "Format de date long", "SettingsEnableColorImpairedModeHelpText": "Style altéré pour aider les personnes daltoniennes à distinguer les informations en couleurs", "SettingsEnableColorImpairedMode": "Activer le mode daltonien", - "RecentFolders": "Dossiers récents", "PosterOptions": "Options des posters", "PendingChangesStayReview": "Rester et vérifier les changements", "PendingChangesMessage": "Vous avez effectué des changements non sauvegardés, souhaitez vous quitter cette page ?", "PendingChangesDiscardChanges": "Abandonner les changements et quitter", "MonoVersionCheckUpgradeRecommendedMessage": "La version installée de Mono {0} est supportée mais mettre à jour en version {1} est recommandé.", - "InteractiveImport": "Importation interactive", "ExistingMovies": "Films existants", - "DetailedProgressBar": "Barre de progression détaillée", "CloneProfile": "Cloner le profil", "CloneIndexer": "Cloner l'indexeur", "ClientPriority": "Priorité du client", @@ -184,14 +165,11 @@ "AppDataDirectory": "Dossier AppData", "ApiKey": "Clé API", "AnalyticsEnabledHelpText": "Envoyer des informations anonymes sur l'utilisation et les erreurs vers les serveurs de Prowlarr. Cela inclut des informations sur votre navigateur, quelle page Prowlarr WebUI vous utilisez, les rapports d'erreur ainsi que le système d'exploitation et sa version. Nous utiliserons ces informations pour prioriser les nouvelles fonctionnalités et les corrections de bugs.", - "AllowHardcodedSubs": "Autoriser les sous-titres incrustés", "IgnoreDeletedMovies": "Ignorer les films effacés", "IgnoredAddresses": "Adresses ignorées", "Hostname": "Nom d'hôte", - "GrabID": "ID du grab", "GeneralSettings": "Réglages Généraux", "Fixed": "Corrigé", - "FileChmodMode": "Mode chmod du fichier", "EnableSslHelpText": " Nécessite un redémarrage en tant qu'administrateur pour être effectif", "EnableSSL": "Activer le SSL", "EnableMediaInfoHelpText": "Extraire les informations de la vidéo (résolution, temps et codec par exemple) depuis les fichiers. Cela nécessite que Prowlarr lise des parties du fichier ce qui peut entraîner une forte utilisation du disque dur ou du réseau pendant les scans.", @@ -205,23 +183,18 @@ "EnableAutomaticAdd": "Activer l'ajout automatique", "EnableAutoHelpText": "En cas d'activation, les films seront automatiquement ajoutés à Prowlarr depuis cette liste", "Enable": "Activer", - "DownloadWarningCheckDownloadClientForMoreDetails": "Avertissement téléchargement : voir le client de téléchargement pour plus de détails", "DownloadClientSettings": "Réglages Clients de téléchargement", "Docker": "Docker", "DeleteTag": "Supprimer le tag", "DeleteNotification": "Supprimer la notification", "DeleteIndexer": "Supprimer l'indexeur", - "DeleteEmptyFolders": "Supprimer les dossiers vides", "DeleteDownloadClient": "Supprimer le client de téléchargement", "DeleteBackup": "Supprimer la sauvegarde", "DBMigration": "Migration de la base de données", - "CreateGroup": "Créer un groupe", "CopyUsingHardlinksHelpText": "Utiliser des liens fixes quand on essaye de copier des fichiers appartenant à des torrents en cours de partage", "ConnectSettings": "Paramètres de connexion", "BackupFolderHelpText": "Les chemins correspondants seront sous le répertoire AppData de Prowlarr", - "ImportExtraFiles": "Importer les fichiers extra", "IllRestartLater": "Je redémarrerai plus tard", - "ClickToChangeMovie": "Cliquer pour changer le film", "CancelPendingTask": "Êtes-vous sur de vouloir annuler cette tâche en attente ?", "BranchUpdateMechanism": "Branche utilisée par le mécanisme de mise à jour extérieur", "BranchUpdate": "Branche à utiliser pour mettre Prowlarr à jour", @@ -244,25 +217,19 @@ "FilterPlaceHolder": "Rechercher des indexeurs", "Exception": "Exception", "EditIndexer": "Modifier l'indexeur", - "DownloadedAndMonitored": "Téléchargé et Surveillé", "Disabled": "Désactivé", "DeleteNotificationMessageText": "Êtes-vous sûr de vouloir supprimer la notification '{0}' ?", "AutomaticSearch": "Recherche automatique", "AddIndexer": "Ajouter un indexeur", - "LinkHere": "ici", "Interval": "Intervalle", "InteractiveSearch": "Recherche interactive", "IndexerPriorityHelpText": "Priorité de l'indexeur de 1 (la plus élevée) à 50 (la plus basse). Par défaut: 25.", "IndexerPriority": "Priorité de l'indexeur", - "ImportMovies": "Importer Films", "Importing": "Importation", - "HaveNotAddedMovies": "Vous n'avez pas encore ajouté de films, voulez-vous d'abord importer certains ou tous vos films ?", "ExcludeMovie": "Exclure Film", - "CustomFormatUnknownCondition": "Condition de format personnalisé inconnue '{0}'", "UnableToLoadRestrictions": "Impossible de charger les restrictions", "UnableToLoadQualityDefinitions": "Impossible de charger les définitions de qualité", "UnableToLoadNotifications": "Impossible de charger les notifications", - "UnableToLoadMediaManagementSettings": "Impossible de charger les paramètres de gestion des médias", "WaitingToImport": "En attente d'importation", "Version": "Version", "Username": "Nom d'utilisateur", @@ -271,16 +238,13 @@ "UrlBaseHelpText": "Pour la prise en charge du proxy inverse, la valeur par défaut est vide", "URLBase": "Base URL", "YesCancel": "Oui, annuler", - "MovieInfoLanguageHelpTextWarning": "Rechargement du navigateur requis", "MovieFiles": "Fichiers vidéo", - "MoreDetails": "Plus de détails", "MonoVersion": "Mono Version", "Mode": "Mode", "MinutesSixty": "60 Minutes : {0}", "MinutesNinety": "90 Minutes : {0}", "MinutesHundredTwenty": "120 Minutes : {0}", "MinimumLimits": "Limites minimales", - "MediaManagementSettings": "Paramètres de gestion des médias", "Mechanism": "Mécanisme", "MaximumLimits": "Limites maximales", "Manual": "Manuel", @@ -288,14 +252,11 @@ "Logs": "Journaux", "LogLevelTraceHelpTextWarning": "La journalisation des traces ne doit être activée que temporairement", "LogLevel": "Niveau du journal", - "LoadingMovieCreditsFailed": "Échec du chargement des crédits du film", "HiddenClickToShow": "Caché, cliquez pour afficher", "IncludeHealthWarningsHelpText": "Inclure avertissements santé", "FocusSearchBox": "Zone de recherche de focus", "ProxyBypassFilterHelpText": "Utiliser ',' comme séparateur et '*.' comme caractère générique pour les sous-domaines", - "IncludeCustomFormatWhenRenamingHelpText": "Inclus dans {Custom Formats} renommer le format", "ExtraFileExtensionsHelpTexts1": "Liste séparée par des virgules des fichiers supplémentaires à importer (.nfo sera importé en tant que .nfo-orig)", - "WeekColumnHeader": "En-tête de colonne de la semaine", "Uptime": "Durée de fonctionnent", "UpdateScriptPathHelpText": "Chemin vers un script personnalisé qui prend un package de mise à jour extraite et gère le reste du processus de mise à jour", "UpdateMechanismHelpText": "Utiliser le programme de mise à jour intégré dans Prowlarr ou un script", @@ -306,17 +267,14 @@ "UnableToLoadHistory": "Impossible de charger l'historique", "UnableToLoadGeneralSettings": "Impossible de charger les paramètres généraux", "UnableToLoadDownloadClients": "Impossible de charger les clients de téléchargement", - "UnableToLoadBlacklist": "Impossible de charger la liste noire", "UnableToLoadBackups": "Impossible de charger les sauvegardes", "UnableToAddANewNotificationPleaseTryAgain": "Impossible d'ajouter une nouvelle notification, veuillez réessayer.", "UnableToAddANewIndexerPleaseTryAgain": "Impossible d'ajouter un nouvel indexeur, veuillez réessayer.", "UnableToAddANewDownloadClientPleaseTryAgain": "Impossible d'ajouter un nouveau client de téléchargement, veuillez réessayer.", - "TorrentDelay": "Torrent Délai", "PriorityHelpText": "Donnez la priorité à plusieurs clients de téléchargement. Le Round-Robin est utilisé pour les clients ayant la même priorité.", "TagIsNotUsedAndCanBeDeleted": "La balise n'est pas utilisée et peut être supprimée", "TagsHelpText": "S'applique aux films avec au moins une balise correspondante", "StartTypingOrSelectAPathBelow": "Commencer à taper ou sélectionner un chemin ci-dessous", - "PreferIndexerFlags": "Préférer les indicateurs d'indexation", "NoTagsHaveBeenAddedYet": "Aucune identification n'a été ajoutée pour l'instant", "IndexerFlags": "Indicateurs d'indexeur", "DeleteTagMessageText": "Voulez-vous vraiment supprimer la balise '{0}' ?", @@ -326,7 +284,6 @@ "UILanguageHelpText": "Langue que Prowlarr utilisera pour l'interface utilisateur", "UILanguage": "UI Langue", "Torrents": "Torrents", - "TestAllLists": "Tester toutes les listes", "TestAllClients": "Tester tous les clients", "TagCannotBeDeletedWhileInUse": "Ne peut pas être supprimé pendant l'utilisation", "SuggestTranslationChange": "Suggérer un changement de traduction", @@ -336,12 +293,9 @@ "SSLCertPath": "Chemin du certificat SSL", "SSLCertPasswordHelpText": "Mot de passe pour le fichier pfx", "SSLCertPassword": "Mot de passe du certificat SSL", - "SkipFreeSpaceCheckWhenImportingHelpText": "À utiliser lorsque Prowlarr ne parvient pas à détecter l'espace libre dans le dossier racine de votre film", "ShowTitleHelpText": "Afficher le titre du film sous l'affiche", "ShownClickToHide": "Montré, cliquez pour masquer", - "ShowGenres": "Afficher les genres", "ShouldMonitorHelpText": "Si activé, les films ajoutés par cette liste sont ajoutés et surveillés", - "SetPermissions": "Définir les autorisations", "SendAnonymousUsageData": "Envoyer des données d'utilisation anonymes", "ScriptPath": "Chemin du script", "SaveSettings": "Enregistrer les paramètres", @@ -354,18 +308,13 @@ "RestartNow": "Redémarrer maintenant", "ResetAPIKey": "Réinitialiser la clé API", "Reset": "Réinitialiser", - "RequiredPlaceHolder": "Ajouter une nouvelle restriction", "RenameMoviesHelpText": "Prowlarr utilisera le nom de fichier existant si le changement de nom est désactivé", "RemovingTag": "Suppression du tag", - "MarkAsFailedMessageText": "Voulez-vous vraiment marquer '{0}' comme échoué ?", "ExistingTag": "Tag existant", - "DownloadPropersAndRepacks": "Propres et Repacks", "RemoveFromDownloadClient": "Supprimer du client de téléchargement", "RemoveFilter": "Supprimer le filtre", "RemovedFromTaskQueue": "Supprimé de la file d'attente des tâches", - "ReleaseDates": "Date de sortie", "RefreshMovie": "Actualiser film", - "RecyclingBin": "Corbeille", "Reason": "Raison", "ReadTheWikiForMoreInformation": "Consultez le Wiki pour plus d'informations", "ProwlarrSupportsAnyIndexer": "Prowlarr prend en charge de nombreux indexeurs en plus de tout indexeur qui utilise la norme Newznab/Torznab en utilisant « Generic Newznab » (pour usenet) ou « Generic Torznab » (pour les torrents). Recherchez et sélectionnez votre indexeur ci-dessous.", @@ -383,7 +332,6 @@ "PageSizeHelpText": "Nombre d'éléments à afficher sur chaque page", "PackageVersion": "Version du package", "OpenBrowserOnStart": "Ouvrir le navigateur au démarrage", - "OnDeleteHelpText": "Lors de la suppression", "NoUpdatesAreAvailable": "Aucune mise à jour n'est disponible", "NotificationTriggers": "Déclencheurs de notification", "NoLimitForAnyRuntime": "Aucune limite pour aucune durée", @@ -393,21 +341,17 @@ "NoBackupsAreAvailable": "Aucune sauvegarde n'est disponible", "New": "Nouveau", "NetCore": ".NET Core", - "MustContain": "Doit contenir", "MovieIndexScrollTop": "Index des films : faire défiler vers le haut", "MovieIndexScrollBottom": "Index des Films : faire défiler vers le bas", "MovieDetailsPreviousMovie": "Détails du film : Film Précédent", "MovieDetailsNextMovie": "Détails du film : Prochain Film", - "MovieFolderFormat": "Format de dossier de film", "MIA": "MIA", "LaunchBrowserHelpText": " Ouvrer un navigateur Web et accéder à la page d'accueil de Prowlarr au démarrage de l'application.", "CloseCurrentModal": "Fermer le modal actuel", "AddingTag": "Ajouter un tag", "OnHealthIssueHelpText": "Sur un problème de santé", "AcceptConfirmationModal": "Accepter la modalité de confirmation", - "SearchFailedPleaseTryAgainLater": "La recherche a échoué, veuillez réessayer plus tard.", "OpenThisModal": "Ouvrer ce modal", - "ImportErrors": "Erreurs d'importation", "CancelProcessing": "Annuler le traitement", "IndexerLongTermStatusCheckSingleClientMessage": "Indexeurs indisponibles en raison de pannes pendant plus de 6 heures : {0}", "IndexerLongTermStatusCheckAllClientMessage": "Tous les indexeurs sont indisponibles en raison d'échecs de plus de 6 heures", diff --git a/src/NzbDrone.Core/Localization/Core/he.json b/src/NzbDrone.Core/Localization/Core/he.json index 0967ef424..26e2f5ec9 100644 --- a/src/NzbDrone.Core/Localization/Core/he.json +++ b/src/NzbDrone.Core/Localization/Core/he.json @@ -1 +1,361 @@ -{} +{ + "Indexers": "אינדקסים", + "New": "חָדָשׁ", + "Columns": "עמודות", + "ConnectionLost": "החיבור אבד", + "CouldNotConnectSignalR": "לא ניתן להתחבר ל- SignalR, ממשק המשתמש לא יתעדכן", + "Dates": "תאריכים", + "EnableAutomaticSearchHelpText": "ישמש כאשר חיפושים אוטומטיים מבוצעים דרך ממשק המשתמש או על ידי Radarr", + "EnableAutomaticSearchHelpTextWarning": "ישמש כאשר נעשה שימוש בחיפוש אינטראקטיבי", + "EnableColorImpairedMode": "אפשר מצב של פגיעה בצבע", + "EnableHelpText": "אפשר יצירת קובץ מטא-נתונים עבור סוג מטא-נתונים זה", + "EnableRss": "אפשר RSS", + "EnableSSL": "אפשר SSL", + "MinutesSixty": "60 דקות: {0}", + "Age": "גיל", + "All": "את כל", + "AllIndexersHiddenDueToFilter": "כל הסרטים מוסתרים בגלל המסנן שהוחל.", + "Interval": "הַפסָקָה", + "KeyboardShortcuts": "קיצורי דרך במקלדת", + "MaximumLimits": "מגבלות מקסימליות", + "Mechanism": "מַנגָנוֹן", + "Message": "הוֹדָעָה", + "MIA": "MIA", + "Name": "שֵׁם", + "NoLinks": "אין קישורים", + "Pending": "ממתין ל", + "PendingChangesDiscardChanges": "מחק שינויים ועזוב", + "PriorityHelpText": "העדיפו עדיפות למספר לקוחות הורדה. Round-Robin משמש ללקוחות עם אותה עדיפות.", + "PrioritySettings": "עדיפות", + "ProxyBypassFilterHelpText": "השתמש ב- ',' כמפריד וב- '*.' כתו כללי לתת-דומיינים", + "ProxyCheckBadRequestMessage": "נכשל בדיקת ה- proxy. קוד קוד: {0}", + "QualityDefinitions": "הגדרות איכות", + "ReleaseStatus": "שחרור סטטוס", + "Reload": "לִטעוֹן מִחָדָשׁ", + "RemovedFromTaskQueue": "הוסר מתור המשימות", + "RemoveFilter": "הסר את המסנן", + "RemovingTag": "הסרת התג", + "Settings": "הגדרות", + "SettingsEnableColorImpairedMode": "אפשר מצב של פגיעה בצבע", + "SettingsEnableColorImpairedModeHelpText": "סגנון שונה כדי לאפשר למשתמשים לקויי צבע להבחין טוב יותר במידע המקודד בצבע", + "SettingsLongDateFormat": "פורמט תאריך ארוך", + "SettingsShortDateFormat": "פורמט תאריך קצר", + "UnableToLoadDownloadClients": "לא ניתן לטעון לקוחות הורדות", + "UnableToAddANewNotificationPleaseTryAgain": "לא ניתן להוסיף התראה חדשה, נסה שוב.", + "UnableToLoadGeneralSettings": "לא ניתן לטעון את ההגדרות הכלליות", + "UnableToLoadIndexers": "לא ניתן לטעון אינדקסים", + "About": "על אודות", + "AcceptConfirmationModal": "קבל את מודל האישור", + "Added": "נוסף", + "Component": "רְכִיב", + "Info": "מידע", + "IndexerLongTermStatusCheckAllClientMessage": "כל האינדקסים אינם זמינים עקב כשלים במשך יותר מ -6 שעות", + "IndexerLongTermStatusCheckSingleClientMessage": "אינדקסים לא זמינים עקב כשלים במשך יותר משש שעות: {0}", + "Manual": "מדריך ל", + "PageSize": "גודל עמוד", + "PageSizeHelpText": "מספר הפריטים להצגה בכל עמוד", + "Password": "סיסמה", + "Reset": "אִתחוּל", + "DeleteIndexerProxyMessageText": "האם אתה בטוח שברצונך למחוק את התג '{0}'?", + "Donations": "תרומות", + "DownloadClient": "הורד לקוח", + "DownloadClientCheckNoneAvailableMessage": "אין לקוח להורדה זמין", + "DownloadClientCheckUnableToCommunicateMessage": "לא ניתן לתקשר עם {0}.", + "PendingChangesMessage": "יש לך שינויים שלא נשמרו, האם אתה בטוח שברצונך לעזוב דף זה?", + "PendingChangesStayReview": "הישאר וסקר שינויים", + "Port": "נמל", + "PortNumber": "מספר יציאה", + "PreferredSize": "גודל מועדף", + "Presets": "הגדרות קבועות מראש", + "Proxy": "פרוקסי", + "ProxyType": "סוג proxy", + "RSSIsNotSupportedWithThisIndexer": "RSS אינו נתמך עם אינדקס זה", + "SettingsShowRelativeDatesHelpText": "הצג תאריכים קרובים (היום / אתמול / וכו ') או תאריכים מוחלטים", + "TableOptions": "אפשרויות טבלה", + "Tasks": "משימות", + "Torrents": "טורנטים", + "Type": "סוּג", + "UI": "ממשק משתמש", + "UILanguage": "שפת ממשק משתמש", + "UILanguageHelpText": "שפה בה Radarr ישתמש עבור ממשק המשתמש", + "UILanguageHelpTextWarning": "חובה לטעון דפדפן", + "UISettings": "הגדרות ממשק המשתמש", + "UnableToAddANewAppProfilePleaseTryAgain": "לא ניתן להוסיף פרופיל איכות חדש, נסה שוב.", + "UnableToLoadBackups": "לא ניתן לטעון גיבויים", + "UnableToLoadQualityDefinitions": "לא ניתן לטעון הגדרות איכות", + "UnableToLoadTags": "לא ניתן לטעון תגים", + "UnableToLoadUISettings": "לא ניתן לטעון הגדרות ממשק משתמש", + "UnsavedChanges": "שינויים שלא נשמרו", + "UnselectAll": "בטל את הבחירה בכול", + "BranchUpdate": "ענף לשימוש עדכון Radarr", + "BranchUpdateMechanism": "ענף המשמש את מנגנון העדכון החיצוני", + "BypassProxyForLocalAddresses": "עקיפת פרוקסי לכתובות מקומיות", + "Cancel": "לְבַטֵל", + "Custom": "המותאם אישית", + "CustomFilters": "מסננים מותאמים אישית", + "Date": "תַאֲרִיך", + "DownloadClientStatusCheckAllClientMessage": "כל לקוחות ההורדה אינם זמינים עקב כשלים", + "DownloadClientStatusCheckSingleClientMessage": "הורדת לקוחות לא זמינה עקב כשלים: {0}", + "DownloadClientUnavailable": "לקוח ההורדות אינו זמין", + "Downloading": "מוריד", + "Fixed": "תוקן", + "FocusSearchBox": "תיבת חיפוש פוקוס", + "Folder": "תיקיה", + "General": "כללי", + "Mode": "מצב", + "Protocol": "נוהל", + "StartTypingOrSelectAPathBelow": "התחל להקליד או בחר נתיב למטה", + "Style": "סִגְנוֹן", + "Wiki": "וויקי", + "Backups": "גיבויים", + "BeforeUpdate": "לפני העדכון", + "Enabled": "מופעל", + "Language": "שפה", + "Languages": "שפות", + "LastWriteTime": "זמן כתיבה אחרון", + "LaunchBrowserHelpText": " פתח דפדפן אינטרנט ונווט אל דף הבית של Radarr בהתחלת האפליקציה.", + "Level": "רָמָה", + "LogFiles": "קבצי יומן", + "Logging": "רישום", + "LogLevel": "רמת יומן", + "LogLevelTraceHelpTextWarning": "יש להפעיל רישום מעקב באופן זמני בלבד", + "Logs": "יומנים", + "MinimumLimits": "מגבלות מינימום", + "MinutesHundredTwenty": "120 דקות: {0}", + "MinutesNinety": "90 דקות: {0}", + "NoChange": "ללא שינוי", + "Analytics": "ניתוח", + "AnalyticsEnabledHelpText": "שלח פרטי שימוש ושגיאה אנונימיים לשרתי Radarr. זה כולל מידע בדפדפן שלך, אילו דפי Radarr WebUI אתה משתמש, דיווח על שגיאות וכן מערכת הפעלה וגרסת זמן ריצה. אנו נשתמש במידע זה כדי לתעדף תכונות ותיקוני באגים.", + "Security": "בִּטָחוֹן", + "Ok": "בסדר", + "ShownClickToHide": "מוצג, לחץ כדי להסתיר", + "Usenet": "Usenet", + "URLBase": "בסיס URL", + "Retention": "הַחזָקָה", + "RSS": "RSS", + "Save": "להציל", + "SaveChanges": "שמור שינויים", + "SaveSettings": "שמור הגדרות", + "Seeders": "זריעים", + "SelectAll": "בחר הכל", + "SendAnonymousUsageData": "שלח נתוני שימוש אנונימיים", + "SetTags": "הגדר תגים", + "SettingsShowRelativeDates": "הצג תאריכים יחסית", + "SuggestTranslationChange": "הצע שינוי בתרגום", + "System": "מערכת", + "SystemTimeCheckMessage": "זמן המערכת אינו פעיל יותר מיום אחד. משימות מתוזמנות עשויות שלא לפעול כראוי עד לתיקון הזמן", + "TableOptionsColumnsMessage": "בחר אילו עמודות גלויות ובאיזה סדר הן יופיעו", + "TagCannotBeDeletedWhileInUse": "לא ניתן למחוק בזמן השימוש", + "TagIsNotUsedAndCanBeDeleted": "לא משתמשים בתג וניתן למחוק אותו", + "SSLCertPassword": "סיסמת אישורי SSL", + "SSLCertPasswordHelpText": "סיסמה לקובץ pfx", + "SSLCertPath": "נתיב אישורי SSL", + "SSLCertPathHelpText": "נתיב לקובץ pfx", + "SSLPort": "יציאת SSL", + "StartupDirectory": "ספריית ההפעלה", + "Status": "סטָטוּס", + "Tags": "תגים", + "TagsSettingsSummary": "ראה את כל התגים ואופן השימוש בהם. ניתן להסיר תגים שאינם בשימוש", + "Test": "מִבְחָן", + "TestAll": "בדוק הכל", + "TestAllClients": "בדוק את כל הלקוחות", + "Time": "זְמַן", + "Title": "כותרת", + "UnableToLoadHistory": "לא ניתן לטעון את ההיסטוריה", + "UpdateCheckStartupNotWritableMessage": "לא ניתן להתקין את העדכון מכיוון שתיקיית ההפעלה '{0}' אינה ניתנת לכתיבה על ידי המשתמש '{1}'.", + "AddDownloadClient": "הוסף לקוח הורדות", + "Filename": "שם קובץ", + "Files": "קבצים", + "Filter": "לְסַנֵן", + "ForMoreInformationOnTheIndividualDownloadClients": "למידע נוסף על לקוחות הורדה בודדים, לחץ על כפתורי המידע.", + "GeneralSettings": "הגדרות כלליות", + "GeneralSettingsSummary": "יציאה, SSL, שם משתמש / סיסמה, פרוקסי, ניתוחים ועדכונים", + "Grabbed": "תפס", + "Grabs": "לִתְפּוֹס", + "Health": "בְּרִיאוּת", + "HealthNoIssues": "אין בעיות בתצורה שלך", + "HiddenClickToShow": "מוסתר, לחץ להצגה", + "HideAdvanced": "הסתר מתקדם", + "History": "הִיסטוֹרִיָה", + "HomePage": "דף הבית", + "Host": "מנחה", + "Hostname": "שם מארח", + "IndexerPriority": "עדיפות אינדקס", + "IndexerPriorityHelpText": "עדיפות אינדקס מ -1 (הגבוה ביותר) ל -50 (הנמוך ביותר). ברירת מחדל: 25.", + "IndexerProxyStatusCheckAllClientMessage": "כל הרשימות אינן זמינות בגלל כשלים", + "IndexerProxyStatusCheckSingleClientMessage": "אינדקסים לא זמינים בגלל כשלים: {0}", + "IndexerStatusCheckAllClientMessage": "כל האינדקסים אינם זמינים עקב כשלים", + "IndexerStatusCheckSingleClientMessage": "אינדקסים לא זמינים בגלל כשלים: {0}", + "NoBackupsAreAvailable": "אין גיבויים", + "NoLimitForAnyRuntime": "אין הגבלה לכל זמן ריצה", + "PackageVersion": "גרסת חבילה", + "Peers": "עמיתים", + "ProxyCheckFailedToTestMessage": "נכשל בדיקת ה- proxy: {0}", + "ProxyCheckResolveIpMessage": "פתרון כתובת ה- IP עבור מארח ה- Proxy המוגדר {0} נכשל", + "ProxyPasswordHelpText": "עליך להזין שם משתמש וסיסמה רק אם נדרשים שם. השאר אותם ריקים אחרת.", + "ProxyUsernameHelpText": "עליך להזין שם משתמש וסיסמה רק אם נדרשים שם. השאר אותם ריקים אחרת.", + "PtpOldSettingsCheckMessage": "האינדקסים הבאים של PassThePopcorn ביטלו את ההגדרות ויש לעדכן אותם: {0}", + "Reddit": "רדיט", + "ReleaseBranchCheckOfficialBranchMessage": "סניף {0} אינו סניף חוקי לשחרור Radarr, לא תקבל עדכונים", + "ScriptPath": "נתיב סקריפט", + "Search": "לחפש", + "UpdateMechanismHelpText": "השתמש במעדכן המובנה של Radarr או בסקריפט", + "UnableToLoadNotifications": "לא ניתן לטעון התראות", + "Add": "לְהוֹסִיף", + "Branch": "ענף", + "CancelPendingTask": "האם אתה בטוח שברצונך לבטל משימה זו בהמתנה?", + "CertificateValidationHelpText": "שנה את מידת אימות ההסמכה של HTTPS", + "ChangeHasNotBeenSavedYet": "השינוי עדיין לא נשמר", + "ConnectionLostAutomaticMessage": "Radarr ינסה להתחבר אוטומטית, או שתלחץ על טען מחדש למטה.", + "Connections": "חיבורים", + "ConnectSettings": "חבר הגדרות", + "QualitySettings": "הגדרות איכות", + "Queue": "תוֹר", + "ReadTheWikiForMoreInformation": "קרא את הוויקי למידע נוסף", + "ResetAPIKey": "אפס את מפתח ה- API", + "Restart": "אתחול", + "RestartNow": "אתחל עכשיו", + "Restore": "לשחזר", + "RestoreBackup": "שחזור גיבוי", + "Restrictions": "מגבלות", + "Result": "תוֹצָאָה", + "TagsHelpText": "חל על סרטים עם תג אחד לפחות תואם", + "Today": "היום", + "Tomorrow": "מָחָר", + "Torrent": "טורנטים", + "UnableToAddANewIndexerProxyPleaseTryAgain": "לא ניתן להוסיף אינדקס חדש, נסה שוב.", + "UpdateCheckStartupTranslocationMessage": "לא ניתן להתקין את העדכון מכיוון שתיקיית ההפעלה '{0}' נמצאת בתיקיית טרנסלוקציה של אפליקציות.", + "UpdateCheckUINotWritableMessage": "לא ניתן להתקין את העדכון מכיוון שתיקיית ממשק המשתמש '{0}' אינה ניתנת לכתיבה על ידי המשתמש '{1}'.", + "Updates": "עדכונים", + "UpdateScriptPathHelpText": "נתיב לסקריפט מותאם אישית שלוקח חבילת עדכון שחולצה ומטפל בשארית תהליך העדכון", + "Uptime": "זמן עבודה", + "UrlBaseHelpText": "לתמיכת proxy הפוכה, ברירת המחדל ריקה", + "UseProxy": "תשתמש בפרוקסי", + "Username": "שם משתמש", + "Version": "גִרְסָה", + "View": "נוף", + "Warn": "לְהַזהִיר", + "YesCancel": "כן, בטל", + "Yesterday": "אתמול", + "Actions": "פעולות", + "AddIndexer": "הוסף אינדקס", + "AddingTag": "מוסיף תג", + "DownloadClients": "הורד לקוחות", + "DownloadClientSettings": "הורד את הגדרות הלקוח", + "Edit": "לַעֲרוֹך", + "EditIndexer": "ערוך אינדקס", + "Enable": "לְאַפשֵׁר", + "EnableAutoHelpText": "אם מופעלת, סרטים יתווספו אוטומטית לרדאר מרשימה זו", + "EnableAutomaticAdd": "אפשר הוספה אוטומטית", + "MonoTlsCheckMessage": "הפיתרון לעקיפת הבעיה של Radarr Mono 4.x עדיין מופעל, שקול להסיר MONO_TLS_PROVIDER = אפשרות סביבה מדור קודם", + "MonoVersion": "גרסת מונו", + "MonoVersionCheckUpgradeRecommendedMessage": "גרסת מונו המותקנת כעת {0} נתמכת, אך מומלץ לשדרג ל- {1}.", + "MoreInfo": "עוד מידע", + "MovieDetailsNextMovie": "פרטי הסרט: הסרט הבא", + "MovieIndexScrollBottom": "אינדקס סרטים: גלילה תחתונה", + "MovieIndexScrollTop": "אינדקס הסרטים: גלול למעלה", + "Movies": "סרטים", + "Priority": "עדיפות", + "SettingsTimeFormat": "פורמט זמן", + "ShowAdvanced": "הצג מתקדם", + "Shutdown": "לכבות", + "Size": "גודל", + "Sort": "סוג", + "Source": "מָקוֹר", + "BackupFolderHelpText": "נתיבים יחסית יהיו תחת ספריית AppData של Radarr", + "BackupIntervalHelpText": "מרווח בין גיבויים אוטומטיים", + "BackupRetentionHelpText": "גיבויים אוטומטיים ישנים יותר מתקופת השמירה ינוקו אוטומטית", + "EnableInteractiveSearch": "אפשר חיפוש אינטראקטיבי", + "EnableInteractiveSearchHelpText": "ישמש כאשר נעשה שימוש בחיפוש אינטראקטיבי", + "EnableInteractiveSearchHelpTextWarning": "אינדקס זה אינו נתמך בחיפוש", + "IgnoredAddresses": "כתובות שהתעלמו מהן", + "RestartRequiredHelpTextWarning": "נדרש הפעלה מחדש כדי להיכנס לתוקף", + "UnableToAddANewApplicationPleaseTryAgain": "לא ניתן להוסיף התראה חדשה, נסה שוב.", + "DeleteApplicationMessageText": "האם אתה בטוח שברצונך למחוק את ההודעה '{0}'?", + "DeleteBackup": "מחק את הגיבוי", + "DeleteBackupMessageText": "האם אתה בטוח שברצונך למחוק את הגיבוי '{0}'?", + "DeleteDownloadClient": "מחק את לקוח ההורדות", + "DeleteDownloadClientMessageText": "האם אתה בטוח שברצונך למחוק את לקוח ההורדות '{0}'?", + "DeleteIndexer": "מחק את אינדקס", + "Docker": "דוקר", + "InteractiveSearch": "חיפוש אינטראקטיבי", + "IllRestartLater": "אתחיל מאוחר יותר", + "Importing": "מייבא", + "IncludeHealthWarningsHelpText": "כלול אזהרות בריאות", + "Indexer": "מַפתְחָן", + "IndexerFlags": "אינדקס דגלים", + "MovieDetailsPreviousMovie": "פרטי הסרט: הסרט הקודם", + "NoChanges": "אין שינויים", + "NoLeaveIt": "לא, עזוב את זה", + "NoLogFiles": "אין קבצי יומן", + "NoMinimumForAnyRuntime": "אין מינימום לכל זמן ריצה", + "Scheduled": "מתוזמן", + "ApplyTagsHelpTexts1": "כיצד להחיל תגים על הסרטים שנבחרו", + "ApiKey": "מפתח API", + "AppDataDirectory": "ספריית AppData", + "AppDataLocationHealthCheckMessage": "לא ניתן יהיה לעדכן את מחיקת AppData בעדכון", + "ApplicationStatusCheckAllClientMessage": "כל הרשימות אינן זמינות בגלל כשלים", + "ApplicationStatusCheckSingleClientMessage": "רשימות לא זמינות בגלל כשלים: {0}", + "Apply": "להגיש מועמדות", + "ApplyTags": "החל תגים", + "ApplyTagsHelpTexts2": "הוסף: הוסף את התגים לרשימת התגים הקיימת", + "ApplyTagsHelpTexts3": "הסר: הסר את התגים שהוזנו", + "ApplyTagsHelpTexts4": "החלף: החלף את התגים בתגיות שהוזנו (אין להזין תגים כדי למחוק את כל התגים)", + "AreYouSureYouWantToResetYourAPIKey": "האם אתה בטוח שברצונך לאפס את מפתח ה- API שלך?", + "Authentication": "אימות", + "AuthenticationMethodHelpText": "דרוש שם משתמש וסיסמה כדי לגשת ל Radarr", + "Automatic": "אוֹטוֹמָטִי", + "AutomaticSearch": "חיפוש אוטומטי", + "Backup": "גיבוי", + "BackupNow": "גיבוי עכשיו", + "BindAddress": "כתובת איגוד", + "BindAddressHelpText": "כתובת IP4 תקפה או '*' לכל הממשקים", + "CertificateValidation": "אימות תעודה", + "Clear": "ברור", + "ClientPriority": "עדיפות לקוח", + "CloneIndexer": "אינדקס שיבוט", + "CloneProfile": "פרופיל שיבוט", + "Close": "סגור", + "CloseCurrentModal": "סגור את המודול הנוכחי", + "DBMigration": "הגירת DB", + "DelayProfile": "עיכוב פרופיל", + "Delete": "לִמְחוֹק", + "DeleteIndexerMessageText": "האם אתה בטוח שברצונך למחוק את האינדקס '{0}'?", + "DeleteNotification": "מחק הודעה", + "DeleteNotificationMessageText": "האם אתה בטוח שברצונך למחוק את ההודעה '{0}'?", + "DeleteTag": "מחק את התג", + "DeleteTagMessageText": "האם אתה בטוח שברצונך למחוק את התג '{0}'?", + "Details": "פרטים", + "Disabled": "נָכֶה", + "Discord": "מַחֲלוֹקֶת", + "EnableAutomaticSearch": "אפשר חיפוש אוטומטי", + "EnableColorImpairedModeHelpText": "סגנון שונה כדי לאפשר למשתמשים לקויי צבע להבחין טוב יותר במידע המקודד בצבע", + "EnableCompletedDownloadHandlingHelpText": "ייבא אוטומטית הורדות שהושלמו מלקוח ההורדות", + "EnabledHelpText": "אפשר רשימה זו לשימוש ברדאר", + "EnableMediaInfoHelpText": "חלץ מידע וידאו כגון רזולוציה, זמן ריצה ומידע קודק מקבצים. זה מחייב את Radarr לקרוא חלקים מהקובץ שעלולים לגרום לדיסק גבוה או לפעילות רשת במהלך הסריקות.", + "EnableSslHelpText": " דרוש הפעלה מחדש כמנהל כדי להיכנס לתוקף", + "Error": "שְׁגִיאָה", + "ErrorLoadingContents": "שגיאה בטעינת התוכן", + "Events": "אירועים", + "EventType": "סוג אירוע", + "Exception": "יוצא מן הכלל", + "ExistingMovies": "סרטים קיימים", + "ExistingTag": "תג קיים", + "Failed": "נִכשָׁל", + "FeatureRequests": "בקשות תכונה", + "UpdateAutomaticallyHelpText": "הורד והתקין עדכונים באופן אוטומטי. עדיין תוכל להתקין ממערכת: עדכונים", + "NoTagsHaveBeenAddedYet": "עדיין לא נוספו תגים", + "NotificationTriggers": "מפעילים התראות", + "NoUpdatesAreAvailable": "אין עדכונים זמינים", + "OAuthPopupMessage": "חלונות קופצים נחסמים על ידי הדפדפן שלך", + "OnHealthIssueHelpText": "בנושא הבריאות", + "OpenBrowserOnStart": "פתח את הדפדפן בהתחלה", + "OpenThisModal": "פתח את המודאל הזה", + "Options": "אפשרויות", + "Refresh": "לְרַעֲנֵן", + "RefreshMovie": "רענן סרט", + "ShowSearch": "הצג חיפוש", + "ShowSearchHelpText": "הצג את לחצן החיפוש ברחף", + "UnableToAddANewDownloadClientPleaseTryAgain": "לא ניתן להוסיף לקוח הורדות חדש, נסה שוב.", + "UnableToAddANewIndexerPleaseTryAgain": "לא ניתן להוסיף אינדקס חדש, נסה שוב." +} diff --git a/src/NzbDrone.Core/Localization/Core/hi.json b/src/NzbDrone.Core/Localization/Core/hi.json index 0967ef424..81b5f1421 100644 --- a/src/NzbDrone.Core/Localization/Core/hi.json +++ b/src/NzbDrone.Core/Localization/Core/hi.json @@ -1 +1,361 @@ -{} +{ + "LogLevel": "छांटने का स्तर", + "Message": "संदेश", + "Movies": "चलचित्र", + "Name": "नाम", + "Add": "जोड़ना", + "Date": "दिनांक", + "Tomorrow": "आने वाला कल", + "Apply": "लागू", + "AuthenticationMethodHelpText": "Radarr का उपयोग करने के लिए उपयोगकर्ता नाम और पासवर्ड की आवश्यकता है", + "Automatic": "स्वचालित", + "Backup": "बैकअप", + "Indexers": "indexers", + "Level": "स्तर", + "LogFiles": "फाइल्स लॉग करें # लॉग फाइलें", + "Logging": "लॉगिंग", + "LogLevelTraceHelpTextWarning": "ट्रेस लॉगिंग को केवल अस्थायी रूप से सक्षम किया जाना चाहिए", + "Logs": "लॉग्स", + "Manual": "गाइड", + "MaximumLimits": "अधिकतम सीमा", + "Mechanism": "तंत्र", + "MIA": "एमआईए", + "MinutesSixty": "60 मिनट: {0}", + "Mode": "मोड", + "Proxy": "प्रतिनिधि", + "ProxyBypassFilterHelpText": "एक विभाजक के रूप में ',' और '*' का प्रयोग करें। उपडोमेन के लिए एक वाइल्डकार्ड के रूप में", + "Queue": "कतार", + "SettingsEnableColorImpairedModeHelpText": "रंग बिगड़ा हुआ उपयोगकर्ताओं को बेहतर रंग कोडित जानकारी को अलग करने की अनुमति देने के लिए बदल शैली", + "ShowSearchHelpText": "होवर पर खोज बटन दिखाएं", + "Sort": "तरह", + "SSLCertPasswordHelpText": "Pfx फ़ाइल के लिए पासवर्ड", + "SSLCertPassword": "एसएसएल सर्टिफिकेट पासवर्ड", + "SSLCertPath": "एसएसएल सर्टिफिकेट पाथ", + "SSLCertPathHelpText": "Pfx फ़ाइल का पथ", + "SSLPort": "एसएसएल पोर्ट", + "StartTypingOrSelectAPathBelow": "टाइप करना शुरू करें या नीचे एक पथ चुनें", + "Style": "अंदाज", + "System": "प्रणाली", + "Tags": "टैग", + "Test": "परीक्षा", + "Port": "बंदरगाह", + "PortNumber": "पोर्ट संख्या", + "RSSIsNotSupportedWithThisIndexer": "RSS इस अनुक्रमणिका के साथ समर्थित नहीं है", + "SendAnonymousUsageData": "अनाम उपयोग डेटा भेजें", + "SetTags": "टैग सेट करें", + "About": "के बारे में", + "AcceptConfirmationModal": "पुष्टि मोडल स्वीकार करें", + "Actions": "कार्रवाई", + "Added": "जोड़ा", + "AddIndexer": "सूचकांक जोड़ें", + "AddingTag": "टैग जोड़ना", + "Age": "उम्र", + "All": "सब", + "ApiKey": "एपीआई कुंजी", + "AppDataDirectory": "AppData निर्देशिका", + "ApplyTags": "टैग लागू करें", + "Authentication": "प्रमाणीकरण", + "ClientPriority": "ग्राहक प्राथमिकता", + "Connections": "सम्बन्ध", + "DownloadClientStatusCheckSingleClientMessage": "विफलताओं के कारण अनुपलब्ध ग्राहक डाउनलोड करें: {0}", + "MovieDetailsNextMovie": "मूवी विवरण: अगली फिल्म", + "NoChanges": "कोई बदलाव नहीं", + "Yesterday": "बिता कल", + "DeleteIndexerProxyMessageText": "क्या आप वाकई '{0}' टैग हटाना चाहते हैं?", + "DeleteNotification": "अधिसूचना हटाएं", + "DeleteTag": "टैग हटाएं", + "Details": "विवरण", + "EditIndexer": "अनुक्रमणिका संपादित करें", + "Enable": "सक्षम", + "EnableAutomaticAdd": "स्वचालित जोड़ें सक्षम करें", + "EnableColorImpairedMode": "रंग-बिगड़ा मोड सक्षम करें", + "EnableAutomaticSearchHelpTextWarning": "इंटरैक्टिव खोज का उपयोग करने पर उपयोग किया जाएगा", + "Filter": "फ़िल्टर", + "Fixed": "फिक्स्ड", + "Peers": "साथियों", + "Save": "सहेजें", + "SaveChanges": "परिवर्तनों को सुरक्षित करें", + "SaveSettings": "समायोजन बचाओ", + "Scheduled": "अनुसूचित", + "Security": "सुरक्षा", + "Seeders": "बीज", + "SelectAll": "सभी का चयन करे", + "Settings": "समायोजन", + "SettingsLongDateFormat": "लंबी तिथि प्रारूप", + "SettingsShortDateFormat": "लघु तिथि प्रारूप", + "SettingsShowRelativeDates": "रिलेटिव डेट्स दिखाएं", + "SettingsShowRelativeDatesHelpText": "रिश्तेदार (आज / कल / आदि) या पूर्ण तिथियां दिखाएं", + "Shutdown": "बंद करना", + "TagCannotBeDeletedWhileInUse": "उपयोग करते समय हटाया नहीं जा सकता", + "TagIsNotUsedAndCanBeDeleted": "टैग का उपयोग नहीं किया जाता है और इसे हटाया जा सकता है", + "Type": "प्रकार", + "UISettings": "यूआई सेटिंग्स", + "AddDownloadClient": "डाउनलोड क्लाइंट जोड़ें", + "BackupIntervalHelpText": "स्वचालित बैकअप के बीच अंतराल", + "Backups": "बैकअप", + "DelayProfile": "देरी प्रोफ़ाइल", + "Delete": "हटाएं", + "EnableInteractiveSearchHelpTextWarning": "खोज इस अनुक्रमणिका के साथ समर्थित नहीं है", + "Indexer": "इंडेक्सर", + "ShowAdvanced": "शो पहले होगा", + "ShowSearch": "खोज दिखाएँ", + "UI": "यूआई", + "UILanguage": "यूआई भाषा", + "UILanguageHelpText": "वह भाषा जिसे रेडर यूआई के लिए उपयोग करेगा", + "UILanguageHelpTextWarning": "ब्राउज़र रीलोड आवश्यक है", + "ChangeHasNotBeenSavedYet": "परिवर्तन अभी तक सहेजा नहीं गया है", + "TableOptions": "तालिका विकल्प", + "Size": "आकार", + "ApplicationStatusCheckAllClientMessage": "सभी सूचियाँ विफल होने के कारण अनुपलब्ध हैं", + "BackupRetentionHelpText": "अवधारण अवधि से अधिक पुराने स्वचालित बैकअप स्वचालित रूप से साफ हो जाएंगे", + "Columns": "कॉलम", + "Component": "अंग", + "DownloadClientSettings": "क्लाइंट सेटिंग्स डाउनलोड करें", + "EventType": "घटना प्रकार", + "Exception": "अपवाद", + "IndexerStatusCheckAllClientMessage": "विफलताओं के कारण सभी अनुक्रमणिका अनुपलब्ध हैं", + "IndexerStatusCheckSingleClientMessage": "अनुक्रमणिका विफलताओं के कारण अनुपलब्ध: {0}", + "Info": "जानकारी", + "Language": "भाषा: हिन्दी", + "Languages": "बोली", + "PrioritySettings": "वरीयता", + "UnableToAddANewDownloadClientPleaseTryAgain": "नया डाउनलोड क्लाइंट जोड़ने में असमर्थ, कृपया पुनः प्रयास करें।", + "UnableToAddANewIndexerPleaseTryAgain": "नया अनुक्रमणिका जोड़ने में असमर्थ, कृपया पुनः प्रयास करें।", + "UnableToAddANewIndexerProxyPleaseTryAgain": "नया अनुक्रमणिका जोड़ने में असमर्थ, कृपया पुनः प्रयास करें।", + "UnableToLoadBackups": "बैकअप लोड करने में असमर्थ", + "NoTagsHaveBeenAddedYet": "अभी तक कोई टैग नहीं जोड़े गए हैं", + "Reddit": "reddit", + "UpdateMechanismHelpText": "रेडर के बिल्ट इन अपडेटर या स्क्रिप्ट का उपयोग करें", + "Updates": "अपडेट", + "MoreInfo": "और जानकारी", + "New": "नया", + "CustomFilters": "कस्टम फ़िल्टर", + "Dates": "खजूर", + "DBMigration": "DB प्रवासन", + "DeleteApplicationMessageText": "क्या आप वाकई '{0}' की सूचना हटाना चाहते हैं?", + "DeleteBackup": "बैकअप हटाएं", + "DeleteBackupMessageText": "क्या आप वाकई '{0}' बैकअप हटाना चाहते हैं?", + "DeleteDownloadClient": "डाउनलोड क्लाइंट हटाएं", + "DeleteDownloadClientMessageText": "क्या आप वाकई डाउनलोड क्लाइंट '{0}' को हटाना चाहते हैं?", + "DeleteIndexer": "अनुक्रमणिका हटाएं", + "DeleteIndexerMessageText": "क्या आप वाकई '{0}' इंडेक्स को हटाना चाहते हैं?", + "GeneralSettingsSummary": "पोर्ट, एसएसएल, उपयोगकर्ता नाम / पासवर्ड, प्रॉक्सी, एनालिटिक्स और अपडेट", + "UrlBaseHelpText": "रिवर्स प्रॉक्सी समर्थन के लिए, डिफ़ॉल्ट खाली है", + "MonoTlsCheckMessage": "रेडार मोनो 4.x tls वर्कअराउंड अभी भी सक्षम है, MONO_TLS_PROVIDER = विरासत पर्यावरण विकल्प को हटाने पर विचार करें", + "MonoVersion": "मोनो संस्करण", + "MonoVersionCheckUpgradeRecommendedMessage": "वर्तमान में स्थापित मोनो संस्करण {0} समर्थित है लेकिन {1} में अपग्रेड करने की सिफारिश की गई है।", + "MovieDetailsPreviousMovie": "मूवी का विवरण: पिछला मूवी", + "MovieIndexScrollBottom": "मूवी इंडेक्स: नीचे स्क्रॉल करें", + "MovieIndexScrollTop": "मूवी इंडेक्स: टॉप स्क्रॉल करें", + "NoLinks": "कोई लिंक नहीं", + "BindAddress": "बाँध का पता", + "Branch": "डाली", + "ProxyCheckBadRequestMessage": "प्रॉक्सी का परीक्षण करने में विफल। स्थिति कोड: {0}", + "ProxyCheckFailedToTestMessage": "प्रॉक्सी का परीक्षण करने में विफल: {0}", + "ProxyCheckResolveIpMessage": "कॉन्फ़िगर प्रॉक्सी होस्ट {0} के लिए आईपी एड्रेस को हल करने में विफल", + "ProxyPasswordHelpText": "यदि आवश्यक हो तो आपको केवल एक उपयोगकर्ता नाम और पासवर्ड दर्ज करना होगा। उन्हें खाली छोड़ दें अन्यथा।", + "ProxyType": "प्रॉक्सी प्रकार", + "ProxyUsernameHelpText": "यदि आवश्यक हो तो आपको केवल एक उपयोगकर्ता नाम और पासवर्ड दर्ज करना होगा। उन्हें खाली छोड़ दें अन्यथा।", + "PtpOldSettingsCheckMessage": "निम्न PassThePopcorn इंडेक्सर्स को हटाए गए सेटिंग्स हैं और उन्हें अपडेट किया जाना चाहिए: {0}", + "QualityDefinitions": "गुणवत्ता परिभाषाएँ", + "QualitySettings": "गुणवत्ता सेटिंग्स", + "ReadTheWikiForMoreInformation": "अधिक जानकारी के लिए विकी पढ़ें", + "Refresh": "ताज़ा करना", + "RefreshMovie": "फिल्म को रिफ्रेश करें", + "ReleaseBranchCheckOfficialBranchMessage": "शाखा {0} वैध रेडीआर रिलीज शाखा नहीं है, आपको अपडेट नहीं मिलेगा", + "ReleaseStatus": "रिलीज की स्थिति", + "Reload": "पुनः लोड करें", + "RemovedFromTaskQueue": "कार्य कतार से हटा दिया गया", + "RemoveFilter": "फ़िल्टर निकालें", + "RemovingTag": "टैग हटाना", + "Reset": "रीसेट", + "ResetAPIKey": "एपीआई कुंजी को रीसेट करें", + "Restart": "पुनर्प्रारंभ करें", + "Source": "स्रोत", + "StartupDirectory": "स्टार्टअप निर्देशिका", + "SuggestTranslationChange": "अनुवाद परिवर्तन का सुझाव दें", + "SystemTimeCheckMessage": "सिस्टम का समय 1 दिन से अधिक बंद है। जब तक समय सही नहीं होगा तब तक शेड्यूल किए गए कार्य सही तरीके से नहीं चल सकते हैं", + "TableOptionsColumnsMessage": "चुनें कि कौन से कॉलम दिखाई दे रहे हैं और वे किस क्रम में दिखाई देते हैं", + "TagsSettingsSummary": "सभी टैग देखें और उनका उपयोग कैसे किया जाता है। अप्रयुक्त टैग को हटाया जा सकता है", + "TestAll": "सभी का परीक्षण करें", + "TestAllClients": "सभी ग्राहकों का परीक्षण करें", + "Title": "शीर्षक", + "Today": "आज", + "Torrent": "टोरेंट", + "Torrents": "टोरेंट", + "UnableToAddANewApplicationPleaseTryAgain": "नई अधिसूचना जोड़ने में असमर्थ, कृपया पुनः प्रयास करें।", + "UnableToAddANewAppProfilePleaseTryAgain": "नई गुणवत्ता प्रोफ़ाइल जोड़ने में असमर्थ, कृपया पुनः प्रयास करें।", + "UnableToLoadTags": "टैग लोड करने में असमर्थ", + "UnableToLoadUISettings": "UI सेटिंग्स लोड करने में असमर्थ", + "UnsavedChanges": "बिना बदलाव किए", + "UnselectAll": "सभी का चयन रद्द", + "UpdateAutomaticallyHelpText": "अपडेट को स्वचालित रूप से डाउनलोड और इंस्टॉल करें। आप अभी भी सिस्टम से अपडेट कर पाएंगे: अपडेट", + "UpdateCheckUINotWritableMessage": "अद्यतन स्थापित नहीं कर सकता क्योंकि UI फ़ोल्डर '{0}' उपयोगकर्ता '{1}' द्वारा लिखने योग्य नहीं है।", + "Uptime": "अपटाइम", + "URLBase": "URL बेस", + "YesCancel": "हाँ, रद्द करें", + "AllIndexersHiddenDueToFilter": "सभी फिल्में लागू फिल्टर के कारण छिपी हुई हैं।", + "Analytics": "एनालिटिक्स", + "AnalyticsEnabledHelpText": "बेनामी उपयोग और त्रुटि जानकारी को Radarr के सर्वर पर भेजें। इसमें आपके ब्राउज़र की जानकारी शामिल है, जो आपके द्वारा उपयोग किए जाने वाले रेडर वेबयूआई पृष्ठों, त्रुटि रिपोर्टिंग के साथ-साथ ओएस और रनटाइम संस्करण भी है। हम इस जानकारी का उपयोग सुविधाओं और बग फिक्स को प्राथमिकता देने के लिए करेंगे।", + "MinimumLimits": "न्यूनतम सीमा", + "MinutesHundredTwenty": "120 मिनट: {0}", + "MinutesNinety": "90 मिनट: {0}", + "TagsHelpText": "कम से कम एक मिलान टैग के साथ फिल्मों पर लागू होता है", + "DeleteTagMessageText": "क्या आप वाकई '{0}' टैग हटाना चाहते हैं?", + "Disabled": "विकलांग", + "Discord": "कलह", + "Docker": "डाक में काम करनेवाला मज़दूर", + "Donations": "दान", + "DownloadClient": "क्लाइंट डाउनलोड करें", + "DownloadClientCheckNoneAvailableMessage": "कोई डाउनलोड क्लाइंट उपलब्ध नहीं है", + "DownloadClientCheckUnableToCommunicateMessage": "{0} के साथ संवाद करने में असमर्थ।", + "DownloadClients": "ग्राहक डाउनलोड करें", + "Downloading": "डाउनलोड", + "Pending": "विचाराधीन", + "PendingChangesDiscardChanges": "परिवर्तन छोड़ें और छोड़ें", + "PendingChangesMessage": "आपने परिवर्तन रद्द कर दिए हैं, क्या आप वाकई इस पृष्ठ को छोड़ना चाहते हैं?", + "RestartRequiredHelpTextWarning": "प्रभावी करने के लिए पुनरारंभ की आवश्यकता है", + "Restore": "पुनर्स्थापित", + "RestoreBackup": "बैकअप बहाल", + "Restrictions": "प्रतिबंध", + "Result": "परिणाम", + "Retention": "अवधारण", + "RSS": "आरएसएस", + "ScriptPath": "पटकथा पथ", + "Search": "खोज", + "SettingsTimeFormat": "समय प्रारूप", + "ShownClickToHide": "दिखाया, छिपाने के लिए क्लिक करें", + "Tasks": "कार्य", + "UnableToLoadHistory": "इतिहास लोड करने में असमर्थ", + "UnableToLoadIndexers": "अनुक्रमणिका लोड करने में असमर्थ", + "AppDataLocationHealthCheckMessage": "अद्यतन पर अद्यतन AppData को रोकने के लिए अद्यतन करना संभव नहीं होगा", + "Usenet": "यूज़नेट", + "UseProxy": "प्रॉक्सी का उपयोग करें", + "Username": "उपयोगकर्ता नाम", + "Version": "संस्करण", + "View": "राय", + "Warn": "चेतावनी देना", + "Wiki": "विकि", + "ConnectionLost": "संपर्क टूट गया", + "ConnectionLostAutomaticMessage": "Radarr अपने आप कनेक्ट होने का प्रयास करेगा, या आप नीचे पुनः लोड कर सकते हैं।", + "ConnectSettings": "कनेक्ट सेटिंग्स", + "CouldNotConnectSignalR": "सिग्नलआर से कनेक्ट नहीं हो सका, UI अपडेट नहीं होगा", + "Custom": "रिवाज", + "DeleteNotificationMessageText": "क्या आप वाकई '{0}' की सूचना हटाना चाहते हैं?", + "IgnoredAddresses": "उपेक्षित पते", + "IllRestartLater": "मैं बाद में पुनः आरंभ करूँगा", + "Importing": "आयात कर रहा है", + "NotificationTriggers": "अधिसूचना ट्रिगर", + "PageSize": "पृष्ठ आकार", + "Time": "समय", + "UpdateScriptPathHelpText": "एक कस्टम स्क्रिप्ट का पथ जो एक निकाला गया अद्यतन पैकेज लेता है और शेष अद्यतन प्रक्रिया को संभालता है", + "ApplicationStatusCheckSingleClientMessage": "विफलताओं के कारण अनुपलब्ध सूची: {0}", + "ApplyTagsHelpTexts1": "चयनित फिल्मों के लिए टैग कैसे लागू करें", + "ApplyTagsHelpTexts2": "जोड़ें: टैग की मौजूदा सूची में टैग जोड़ें", + "ApplyTagsHelpTexts3": "निकालें: दर्ज किए गए टैग निकालें", + "ApplyTagsHelpTexts4": "प्रतिस्थापित करें: दर्ज किए गए टैगों के साथ टैग बदलें (सभी टैग्स को खाली करने के लिए कोई टैग दर्ज न करें)", + "AreYouSureYouWantToResetYourAPIKey": "क्या आप वाकई अपनी API कुंजी को रीसेट करना चाहते हैं?", + "AutomaticSearch": "स्वचालित खोज", + "BackupFolderHelpText": "रिलेटिव पाथ रेडर के ऐपडाटा डायरेक्टरी के तहत होगा", + "BackupNow": "अब समर्थन देना", + "BeforeUpdate": "अपडेट करने से पहले", + "BindAddressHelpText": "सभी इंटरफेस के लिए वैध IP4 पता या '*'", + "BranchUpdate": "रेडर को अपडेट करने के लिए उपयोग करने के लिए शाखा", + "BranchUpdateMechanism": "बाहरी अद्यतन तंत्र द्वारा उपयोग की जाने वाली शाखा", + "BypassProxyForLocalAddresses": "स्थानीय पते के लिए बायपास प्रॉक्सी", + "Cancel": "रद्द करना", + "CancelPendingTask": "क्या आप वाकई इस लंबित कार्य को रद्द करना चाहते हैं?", + "CertificateValidation": "प्रमाणपत्र सत्यापन", + "CertificateValidationHelpText": "बदलें कि HTTPS प्रमाणन सत्यापन कितना सख्त है", + "Clear": "स्पष्ट", + "CloneIndexer": "क्लोन इंडेक्सर", + "CloneProfile": "क्लोन प्रोफ़ाइल", + "Close": "बंद करे", + "CloseCurrentModal": "वर्तमान मोडल को बंद करें", + "DownloadClientStatusCheckAllClientMessage": "सभी डाउनलोड क्लाइंट विफलताओं के कारण अनुपलब्ध हैं", + "DownloadClientUnavailable": "डाउनलोड क्लाइंट अनुपलब्ध है", + "Edit": "संपादित करें", + "EnableAutoHelpText": "यदि सक्षम किया गया है, तो फिल्में इस सूची से स्वचालित रूप से Radarr में जुड़ जाएंगी", + "EnableAutomaticSearch": "स्वचालित खोज सक्षम करें", + "EnableAutomaticSearchHelpText": "यूआई के माध्यम से या रेडर द्वारा स्वचालित खोज किए जाने पर उपयोग किया जाएगा", + "EnableColorImpairedModeHelpText": "रंग बिगड़ा हुआ उपयोगकर्ताओं को बेहतर रंग कोडित जानकारी को अलग करने की अनुमति देने के लिए बदल शैली", + "EnableCompletedDownloadHandlingHelpText": "डाउनलोड क्लाइंट से स्वचालित रूप से पूर्ण डाउनलोड आयात करें", + "Enabled": "सक्रिय", + "EnabledHelpText": "इस सूची को Radarr में उपयोग के लिए सक्षम करें", + "EnableHelpText": "इस मेटाडेटा प्रकार के लिए मेटाडेटा फ़ाइल निर्माण सक्षम करें", + "EnableInteractiveSearch": "इंटरएक्टिव खोज सक्षम करें", + "EnableInteractiveSearchHelpText": "इंटरैक्टिव खोज का उपयोग करने पर उपयोग किया जाएगा", + "EnableMediaInfoHelpText": "वीडियो जानकारी जैसे रिज़ॉल्यूशन, रनटाइम और कोडेक जानकारी फ़ाइलों से निकालें। इसके लिए रेडर को फ़ाइल के कुछ हिस्सों को पढ़ना पड़ता है, जिससे स्कैन के दौरान हाई डिस्क या नेटवर्क गतिविधि हो सकती है।", + "EnableRss": "आरएसएस को सक्षम करें", + "EnableSSL": "SSL सक्षम करें", + "EnableSslHelpText": " प्रभावी होने के लिए प्रशासक के रूप में पुनः आरंभ करने की आवश्यकता है", + "Error": "त्रुटि", + "ErrorLoadingContents": "सामग्री लोड करने में त्रुटि", + "Events": "आयोजन", + "ExistingMovies": "मौजूदा मूवी", + "ExistingTag": "मौजूदा टैग", + "Failed": "अनुत्तीर्ण होना", + "FeatureRequests": "सुविधा का अनुरोध", + "Filename": "फ़ाइल का नाम", + "Files": "फ़ाइलें", + "FocusSearchBox": "फोकस बॉक्स खोजें", + "Folder": "फ़ोल्डर", + "ForMoreInformationOnTheIndividualDownloadClients": "व्यक्तिगत डाउनलोड क्लाइंट के बारे में अधिक जानकारी के लिए, जानकारी बटन पर क्लिक करें।", + "General": "आम", + "GeneralSettings": "सामान्य सेटिंग्स", + "Grabbed": "पकड़ा", + "Grabs": "लपकना", + "Health": "स्वास्थ्य", + "HealthNoIssues": "आपके कॉन्फ़िगरेशन के साथ कोई समस्या नहीं है", + "HiddenClickToShow": "छिपा हुआ, दिखाने के लिए क्लिक करें", + "HideAdvanced": "उन्नत छिपाएँ", + "History": "इतिहास", + "HomePage": "मुख पृष्ठ", + "Host": "मेज़बान", + "Hostname": "होस्ट का नाम", + "IncludeHealthWarningsHelpText": "स्वास्थ्य चेतावनी शामिल करें", + "IndexerFlags": "इंडेक्स फ्लैग", + "IndexerLongTermStatusCheckAllClientMessage": "6 घंटे से अधिक समय तक विफलताओं के कारण सभी सूचकांक अनुपलब्ध हैं", + "IndexerLongTermStatusCheckSingleClientMessage": "6 घंटे से अधिक समय तक विफलताओं के कारण सूचकांक उपलब्ध नहीं: {0}", + "IndexerPriority": "सूचकांक प्राथमिकता", + "IndexerPriorityHelpText": "इंडेक्सर प्राथमिकता 1 (उच्चतम) से 50 (सबसे कम)। डिफ़ॉल्ट: 25", + "IndexerProxyStatusCheckAllClientMessage": "सभी सूचियाँ विफल होने के कारण अनुपलब्ध हैं", + "IndexerProxyStatusCheckSingleClientMessage": "अनुक्रमणिका विफलताओं के कारण अनुपलब्ध: {0}", + "InteractiveSearch": "इंटरएक्टिव खोज", + "Interval": "मध्यान्तर", + "KeyboardShortcuts": "कुंजीपटल अल्प मार्ग", + "LastWriteTime": "अंतिम समय लिखें", + "LaunchBrowserHelpText": " एक वेब ब्राउज़र खोलें और ऐप स्टार्ट पर रेडर होमपेज पर नेविगेट करें।", + "NoBackupsAreAvailable": "कोई बैकअप उपलब्ध नहीं हैं", + "NoChange": "कोई परिवर्तन नहीं होता है", + "NoLeaveIt": "नहीं, इसे छोड़ो", + "NoLimitForAnyRuntime": "किसी भी रनटाइम के लिए कोई सीमा नहीं", + "NoLogFiles": "कोई लॉग फ़ाइल नहीं", + "NoMinimumForAnyRuntime": "किसी रनटाइम के लिए कोई न्यूनतम नहीं", + "Ok": "ठीक", + "PackageVersion": "पैकेज संस्करण", + "PageSizeHelpText": "प्रत्येक पृष्ठ पर दिखाने के लिए मदों की संख्या", + "Password": "कुंजिका", + "PendingChangesStayReview": "रहें और परिवर्तनों की समीक्षा करें", + "PreferredSize": "पसंदीदा आकार", + "Presets": "प्रीसेट", + "Priority": "वरीयता", + "PriorityHelpText": "एकाधिक डाउनलोड ग्राहकों को प्राथमिकता दें। राउंड-रॉबिन का उपयोग उसी प्राथमिकता वाले ग्राहकों के लिए किया जाता है।", + "Protocol": "मसविदा बनाना", + "RestartNow": "अब पुनःचालू करें", + "SettingsEnableColorImpairedMode": "रंग-बिगड़ा मोड सक्षम करें", + "UnableToAddANewNotificationPleaseTryAgain": "नई अधिसूचना जोड़ने में असमर्थ, कृपया पुनः प्रयास करें।", + "UnableToLoadDownloadClients": "डाउनलोड क्लाइंट लोड करने में असमर्थ", + "UnableToLoadGeneralSettings": "सामान्य सेटिंग्स लोड करने में असमर्थ", + "UnableToLoadNotifications": "सूचनाएं लोड करने में असमर्थ", + "UnableToLoadQualityDefinitions": "गुणवत्ता परिभाषाएँ लोड करने में असमर्थ", + "UpdateCheckStartupNotWritableMessage": "अपडेट स्थापित नहीं किया जा सकता क्योंकि स्टार्टअप फ़ोल्डर '{0}' उपयोगकर्ता '{1}' द्वारा लिखने योग्य नहीं है।", + "UpdateCheckStartupTranslocationMessage": "अपडेट स्थापित नहीं किया जा सकता क्योंकि स्टार्टअप फ़ोल्डर '{0}' ऐप ट्रांसलेशन फ़ोल्डर में है।", + "NoUpdatesAreAvailable": "कोई अद्यतन उपलब्ध नहीं हैं", + "OAuthPopupMessage": "आपके ब्राउज़र द्वारा पॉप-अप्स को ब्लॉक किया जा रहा है", + "OnHealthIssueHelpText": "स्वास्थ्य के मुद्दे पर", + "OpenBrowserOnStart": "प्रारंभ पर ब्राउज़र खोलें", + "OpenThisModal": "इस मोडल को खोलें", + "Options": "विकल्प", + "Status": "स्थिति" +} diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index 1b1a08e23..22184e227 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -1,9 +1,7 @@ { "About": "Névjegy", "Analytics": "Analitika", - "AllowHardcodedSubsHelpText": "Az észlelt beégetett feliratok automatikusan le lesznek töltve", "AddNewMovie": "Új film hozzáadása", - "AddMovies": "Film hozzáadása", "AddIndexer": "Indexer hozzáadása", "AddingTag": "Címke hozzáadása", "Error": "Hiba", @@ -16,11 +14,9 @@ "EnableAutomaticAdd": "Engedélyezd az automatikus hozzáadást", "EnableAutoHelpText": "Ha engedélyezve van, a Filmek automatikusan hozzáadódnak a Prowlarr-hoz ebből a listából", "Enable": "Aktiválás", - "EditMovie": "Film Szerkesztése", "EditIndexer": "Indexer Szerkesztése", "Edit": "Szerkesztés", "Downloading": "Letöltés Alatt", - "DownloadedButNotMonitored": "Letöltve, de nincs Figyelve", "DownloadClientUnavailable": "Letöltőkliens nem elérhető", "DownloadClientStatusCheckSingleClientMessage": "Letöltőkliens hiba miatt nem elérhető: {0}", "DownloadClientStatusCheckAllClientMessage": "Az összes letöltőkliens elérhetetlen, hiba miatt", @@ -34,12 +30,10 @@ "Disabled": "Letiltott", "Details": "Részletek", "DeleteTagMessageText": "Biztosan törlöd a(z) „{0}” címkét?", - "DeleteRestriction": "Megkötés Törlése", "DeleteNotificationMessageText": "Biztosan törlöd a(z) „{0}” értesítést?", "DeleteNotification": "Értesítés Törlése", "DeleteIndexerMessageText": "Biztosan törlöd a(z) „{0}” indexert?", "DeleteIndexer": "Indexer Törlése", - "DeleteEmptyFolders": "Üres Mappa Törlése", "DeleteDownloadClientMessageText": "Biztosan törlöd a(z) „{0}” letöltő klienst?", "DeleteDownloadClient": "Letöltőkliens Törlése", "DeleteBackupMessageText": "Biztosan törlöd a(z) „{0}” biztonsági mentést?", @@ -49,10 +43,8 @@ "DBMigration": "DB Migráció", "Dates": "Dátumok", "Date": "Dátum", - "CustomFormatUnknownConditionOption": "Ismeretlen „{0}” opció a(z) „{1}” feltételhez", "CustomFormats": "Egyéni Formátumok", "CustomFilters": "Egyéni Szűrők", - "CreateEmptyMovieFolders": "Készíts egy üres mappát", "CopyToClipboard": "Másold a Vágólapra", "ConnectSettingsSummary": "Értesítések és egyéni szkriptek", "ConnectSettings": "Kapcsolódási Beállítások", @@ -70,7 +62,6 @@ "ClientPriority": "Kliens Prioritás", "Clear": "Törölni", "ChangeHasNotBeenSavedYet": "A változások még nem lettek elmentve", - "Certification": "Tanúsítvány", "CertificateValidationHelpText": "Módosítsa a HTTPS tanúsítás szigorúságát", "CertificateValidation": "Tanúsítvány érvényesítése", "CancelPendingTask": "Biztosan törlöd ezt a függőben lévő feladatot?", @@ -79,7 +70,6 @@ "BranchUpdateMechanism": "A külső frissítési mechanizmus által használt ágazat", "BranchUpdate": "Ágazattípus a Prowlarr frissítéseihez", "Branch": "Ágazat", - "Blacklist": "Feketelista", "BindAddressHelpText": "Érvényes IP4-cím, vagy „*” minden interfészhez", "BindAddress": "Kapcsolási Cím", "BeforeUpdate": "Alkalmazásfrissítés előtt", @@ -89,7 +79,6 @@ "BackupIntervalHelpText": "Időeltérés a biztonsági mentések között", "BackupFolderHelpText": "Az elérési útvonalak a Prowlarr AppData könyvtárában lesznek", "Backup": "Biztonsági Mentés", - "AutoRedownloadFailedHelpText": "Másik kiadás automatikus keresése és letöltése", "AutomaticSearch": "Automatikus Keresés", "Automatic": "Automatikus", "ApplyTagsHelpTexts4": "Csere: Cserélje ki a címkéket a beírt címkékre (az összes címke törléséhez ne adjon meg címkéket)", @@ -115,11 +104,8 @@ "HiddenClickToShow": "Rejtett, kattints a megjelenítéshez", "HealthNoIssues": "Nincs hiba a konfigurációval", "Health": "Állapot", - "GrabReleaseMessageText": "Prowlarr nem tudta meghatározni, hogy melyik filmhez készült ez a kiadás. Lehet, hogy a Prowlarr nem tudja automatikusan importálni ezt a kiadást. Meg szeretnéd ragadni a (z) „{0}”-t?", "GeneralSettingsSummary": "Port, SSL, felhasználónév / jelszó, proxy, elemzések, és frissítések", - "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Az egyes importálási listákkal kapcsolatos további információkért kattints az info gombokra.", "ForMoreInformationOnTheIndividualDownloadClients": "Ha többet szeretnél megtudni a különböző letöltési kliensekről, kattints az információs gombokra.", - "Folders": "Mappák", "Folder": "Mappa", "FocusSearchBox": "Fókusz Keresőmező", "Fixed": "Kijavítva", @@ -127,9 +113,7 @@ "Filter": "Szűrő", "Files": "Fájl", "Filename": "Fájlnév", - "FileChmodHelpTexts1": "Octal, médiafájlokra alkalmazva, amikor a Prowlarr importálja / átnevezi őket", "Failed": "Sikertelen", - "ExportCustomFormat": "Egyéni Formátum Exportálása", "ExistingTag": "Meglévő Címke", "ExistingMovies": "Létező Film(ek)", "Exception": "Kivétel", @@ -151,7 +135,6 @@ "Status": "Állapot", "StartupDirectory": "Indítási könyvtár", "StartTypingOrSelectAPathBelow": "Kezdd el gépelni, vagy válassz az alábbi útvonalak közül", - "StandardMovieFormat": "Normál filmformátum", "SSLPort": "SSL Port", "SSLCertPathHelpText": "A PFX fájl elérési útvonala", "SSLCertPath": "Az SSL tanúsítvány elérési útvonala", @@ -159,24 +142,18 @@ "SSLCertPassword": "SSL Tanúsítvány jelszava", "Source": "Forrás", "Sort": "Rendezés", - "SizeOnDisk": "Méret a lemezen", "Size": "Méret", "Shutdown": "Leállítás", - "ShowTitle": "Cím megjelenítése", "ShowSearchHelpText": "A kereső gomb megjelenítése az egérrel", - "SettingsWeekColumnHeaderHelpText": "Minden oszlop felett jelenjen meg, hogy melyik hét az aktuális", "MonoVersion": "Mono Verzió", "MonoTlsCheckMessage": "A Prowlarr Mono 4.x tls megoldás továbbra is engedélyezett, fontolja meg a MONO_TLS_PROVIDER =legacy opció eltávolítását", - "ShowQualityProfile": "Minőségi profil megjelenítése", "ShownClickToHide": "Kattints, hogy elrejtsd", - "ShowMonitored": "Monitorozottak mutatása", "ShowCertification": "Tanúsítvány megjelenítése", "ShowAdvanced": "Haladó nézet", "SettingsTimeFormat": "Időformátum", "SettingsShowRelativeDatesHelpText": "Relatív (Ma / Tegnap / stb.) vagy valós dátumok megjelenítése", "SettingsShowRelativeDates": "Relatív dátumok megjelenítése", "SettingsShortDateFormat": "Rövid dátumformátum", - "SettingsRemotePathMappingLocalPathHelpText": "Elérési út, amelyet a Prowlarr használhat a távoli elérési út, helyi eléréséhez", "SettingsLongDateFormat": "Hosszú dátumformátum", "SettingsEnableColorImpairedModeHelpText": "Megváltoztatott stílus, hogy a színtévesztő felhasználók jobban megkülönböztessék a színkódolt információkat", "SettingsEnableColorImpairedMode": "Színtévesztő mód bekapcsolása", @@ -185,7 +162,6 @@ "SelectAll": "Összes kijelölése", "Seeders": "Seederek", "Security": "Biztonság", - "SearchMovie": "Film keresés", "SearchFailedPleaseTryAgainLater": "Keresés sikertelen, próbáld újra később.", "Search": "Keresés", "ScriptPath": "Script útvonal", @@ -193,9 +169,7 @@ "SaveSettings": "Beállítások mentése", "SaveChanges": "Változtatások mentése", "Save": "Mentés", - "RSSSync": "RSS Szinkronizálás", "RSSIsNotSupportedWithThisIndexer": "Az RSS nem támogatott ezzel az indexerrel", - "RootFolder": "Gyökérmappa", "Retention": "Visszatartás", "Result": "Eredmények", "Restrictions": "Korlátozások", @@ -207,24 +181,18 @@ "Restart": "Újraindítás", "ResetAPIKey": "API Kulcs visszaállítása", "Reset": "Visszaállítás", - "RequiredRestrictionPlaceHolder": "A kiadásnak tartalmaznia kell legalább egy ilyen kifejezést (a kis- és nagybetűket nem veszi figyelembe)", "ReplaceIllegalCharacters": "Az illegális karakterek cseréje", - "RenameFiles": "Fájl(ok) átnevezése", "RemovingTag": "Címke eltávolítása", - "RemoveFromQueue": "Eltávolítás a sorból", "RemoveFilter": "Szűrő törlése", "RemovedFromTaskQueue": "Eltávolítva a feladatsorról", "Reload": "Újratöltés", "ReleaseStatus": "Kiadás státusza", - "Released": "Megjelent", "ReleaseBranchCheckPreviousVersionMessage": "Az ágazat {0} a Prowlarr előző verziójához tartozik, a további frissítések érdekében állítsd az ágat 'nightly'-ra", "ReleaseBranchCheckOfficialBranchMessage": "A(z) {0} nem érvényes Prowlarr frissítési ágazat, ezért nem kap frissítéseket", "RefreshMovie": "Film frissítése", "Refresh": "Frissítés", - "RecycleBinHelpText": "A filmfájlok végleges törlés helyett ide kerülnek törléskor", "Reason": "Ok", "ReadTheWikiForMoreInformation": "Olvasd el a Wiki-t további információkért", - "ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "A Prowlarr támogatja az RSS filmlistákat, valamint az alábbiakban felsoroltakat.", "ProwlarrSupportsAnyIndexer": "A Prowlarr számos indexert támogat, minden olyan indexelő mellett, amely a Newznab / Torznab szabványt használja, valamint a 'Generic Newznab' (usenethez) vagy a 'Generic Torznab' (torrentekhez) használatával. Keresés és az alább felsorolt indexelők kiválasztása.", "ProwlarrSupportsAnyDownloadClient": "A Prowlarr minden olyan letöltési klienst támogat, amely a Newznab szabványt használja, valamint az alább felsorolt letöltési klienseket.", "Queue": "Várakozási sor", @@ -240,13 +208,10 @@ "ProxyBypassFilterHelpText": "Használja elválasztóként a ',' és a '*' karaktereket, az aldomainek helyettesítőjeként", "Proxy": "Proxy", "Protocol": "Protokoll", - "Profiles": "Profil(ok)", "PriorityHelpText": "Priorizálj több letöltési klienst. A Round-Robint azonos prioritású letöltőkliensek használják.", "Priority": "Prioritás", - "OnGrabHelpText": "Megfogva", "MonoVersionCheckUpgradeRecommendedMessage": "A jelenleg telepített Mono {0} verzió támogatott, de ajánlott frissíteni a(z) {1} verzióra.", "PreferredSize": "Preferált méret", - "PosterOptions": "Poszter beállítások", "PortNumber": "Port száma", "Port": "Port", "PendingChangesStayReview": "Maradj, és tekintsd át a változásokat", @@ -258,7 +223,6 @@ "PageSizeHelpText": "Az egyes oldalakon megjelenítendő elemek száma", "PageSize": "Oldal mérete", "PackageVersion": "Csomagverzió", - "OrganizeModalSuccess": "Siker! Befejeztem a munkám, nincsenek átnevezésre váró fájlok.", "Organize": "Rendezés", "Options": "Opciók", "OpenThisModal": "Nyissa meg ezt a modált", @@ -278,31 +242,23 @@ "New": "Új", "NetCore": ".NET", "Name": "Név", - "MovieYear": "Kiadási év", "Movies": "Filmek", - "MovieIsMonitored": "A film monitorozva van", "MovieInfoLanguageHelpText": "A Prowlarr által a filminformációkhoz használt nyelv", "MovieIndexScrollTop": "Film Index: Görgess fel", "MovieIndexScrollBottom": "Film Index: Görgess le", - "MovieFiles": "Filmfájl(ok)", "MovieDetailsPreviousMovie": "A film részletei: Előző film", "MovieDetailsNextMovie": "A film részletei: Következő film", - "MoveFiles": "Fájl(ok) mozgatása", "MoreInfo": "Több Információ", "MonoNotNetCoreCheckMessage": "Kérjük, frissítsd a Prowlarr .NET Core verzióját", - "Monitored": "Monitorozva", "Mode": "Mód", "MinutesSixty": "60 Perc: {0}", "MinutesNinety": "90 Perc: {0}", "MinutesHundredTwenty": "120 Perc: {0}", "MinimumLimits": "Minimális Határ", - "MinimumAgeHelpText": "Usenet: Az NZB-k minimális életkora percekben, mielőtt megragadnák őket. Használja ezt arra, hogy időt biztosítson az új kiadásoknak az usenet-szolgáltatóhoz történő továbbterjesztésre.", "MIA": "MIA", "Message": "Üzenet", - "MediaInfoDllCheckMessage": "A MediaInfo könyvtár betöltése nem sikerült {0}", "Mechanism": "Mechanizmus", "MaximumLimits": "Maximális Limit", - "ManualImport": "Manuális Importálás", "Manual": "Manuális", "MaintenanceRelease": "Karbantartási kiadás", "Logs": "Logok", @@ -310,9 +266,7 @@ "LogLevel": "Log Szint", "Logging": "Loggolás", "LogFiles": "Log Fájlok", - "LoadingMovieExtraFilesFailed": "A film extra fájljainak betöltése nem sikerült", "ListSettings": "Lista Beállítások", - "LinkHere": "ide", "Level": "Szint", "LaunchBrowserHelpText": " Nyisson meg egy böngészőt, és az alkalmazás indításakor lépjen a Prowlarr kezdőlapjára.", "LastWriteTime": "Utolsó írási idő", @@ -328,12 +282,10 @@ "Grabbed": "Megfogva", "GeneralSettings": "Általános Beállítások", "General": "Általános", - "UnableToLoadLanguages": "Nem sikerült betölteni a nyelveket", "UnableToLoadIndexers": "Nem lehet betölteni az indexereket", "UnableToLoadHistory": "Nem sikerült betölteni az előzményeket", "UnableToLoadGeneralSettings": "Nem sikerült betölteni az általános beállításokat", "UnableToLoadDownloadClients": "Nem sikerült betölteni a letöltőkliens(eke)t", - "UnableToLoadBlacklist": "Nem sikerült betölteni a feketelistát", "UnableToLoadBackups": "Biztonsági mentés(ek) betöltése sikertelen", "UnableToAddANewNotificationPleaseTryAgain": "Nem lehet új értesítést hozzáadni, próbálkozz újra.", "UnableToAddANewIndexerPleaseTryAgain": "Nem lehet új indexert hozzáadni, próbálkozz újra.", @@ -346,7 +298,6 @@ "UI": "Felület", "Type": "Típus", "Torrents": "Torrentek", - "TMDBId": "TMDb azonosító", "Title": "Cím", "Time": "Idő", "TestAllClients": "Összes kliens tesztelése", @@ -361,27 +312,19 @@ "TableOptionsColumnsMessage": "Válasszd ki, mely oszlopok legyenek láthatóak, és milyen sorrendben jelenjenek meg", "SystemTimeCheckMessage": "A rendszeridő több mint 1 napja nem frissült. Előfordulhat, hogy az ütemezett feladatok az idő kijavításáig nem futnak megfelelően", "IndexerStatusCheckAllClientMessage": "Az összes indexer elérhetetlen hiba miatt", - "IndexerSearchCheckNoAvailableIndexersMessage": "Az összes keresésre képes indexer átmenetileg nem elérhető, a legutóbbi indexelő hibák miatt", "Indexers": "Indexerek", "IndexerPriorityHelpText": "Indexelő prioritás 1-től (legmagasabb) 50-ig (legalacsonyabb). Alapértelmezés: 25.", "IndexerPriority": "Indexer Prioritása", "IndexerFlags": "Indexer Zászló", "Indexer": "Indexelő", - "IncludeProwlarrRecommendations": "Tartalmazza a Prowlarr Ajánlásait", "IncludeHealthWarningsHelpText": "Tartalmazza a Állapot Figyelmeztetéseket", - "ImportTipsMessage": "Néhány tipp az importálás zökkenőmentes lebonyolításához:", "ImportListSyncIntervalHelpText": "A Prowlarr milyen gyakran szinkronizáljon a listáival.", "Importing": "Importálás Folyamatban", - "ImportFailed": "Importálás sikertelen: {0}", "ImportErrors": "Importálási Hiba", - "Import": "Importálás", "IllRestartLater": "Később Újraindítom", "IgnoredAddresses": "Ignorált Címek", - "ICalFeed": "iCal-Feed", "YesCancel": "Igen, Mégsem", - "Week": "Hét", "Warn": "Figyelmeztet", - "VisitGithubCustomFormatsAphrodite": "Látogasd meg a GitHub-ot további információkért: ", "View": "Nézet", "Version": "Verzió", "Username": "Felhasználónév", @@ -399,13 +342,10 @@ "UpdateAutomaticallyHelpText": "A frissítések automatikus letöltése és telepítése. A Rendszer: Frissítések alkalmazásból továbbra is telepíteni tudja", "UnselectAll": "Minden kijelölés megszüntetése", "UnsavedChanges": "Nem mentett változások", - "UnmappedFolders": "Feltérképezetlen mappák", "UnableToLoadUISettings": "Nem sikerült betölteni a felhasználói felület beállításait", "UnableToLoadTags": "Nem sikerült betölteni a címkéket", - "UnableToLoadQualityProfiles": "Nem lehet betölteni a minőségi profilokat", "UnableToLoadQualityDefinitions": "Nem lehet betölteni a minőségi meghatározásokat", "UnableToLoadNotifications": "Nem sikerült betölteni az Értesítéseket", - "UnableToLoadMediaManagementSettings": "Nem sikerült betölteni a Média Kezelés beállításait", "ThisConditionMatchesUsingRegularExpressions": "Ez a feltétel megfelel a Reguláris kifejezések használatának. Ne feledje, hogy a karakterek {0} különleges jelentéssel bírnak, és el kell kerülniük egy {1} karakterrel", "TableOptions": "Táblázat beállításai", "ShowSearch": "Keresés(ek) megjelenítése", diff --git a/src/NzbDrone.Core/Localization/Core/is.json b/src/NzbDrone.Core/Localization/Core/is.json index 0967ef424..f4ac2cb0c 100644 --- a/src/NzbDrone.Core/Localization/Core/is.json +++ b/src/NzbDrone.Core/Localization/Core/is.json @@ -1 +1,361 @@ -{} +{ + "Add": "Bæta við", + "AreYouSureYouWantToResetYourAPIKey": "Ertu viss um að þú viljir endurstilla API lykilinn þinn?", + "BindAddress": "Bind heimilisfang", + "BranchUpdate": "Útibú til að nota til að uppfæra Radarr", + "Logs": "Logs", + "Usenet": "Usenet", + "Logging": "Skógarhögg", + "MovieIndexScrollBottom": "Kvikmyndavísitala: Flettu neðst", + "Result": "Niðurstaða", + "SSLCertPathHelpText": "Leið að pfx skrá", + "SSLPort": "SSL höfn", + "Backup": "Afritun", + "UI": "HÍ", + "About": "Um það bil", + "Added": "Bætt við", + "DeleteIndexerProxyMessageText": "Ertu viss um að þú viljir eyða merkinu '{0}'?", + "EnableColorImpairedModeHelpText": "Breyttur stíll til að leyfa litaskertum notendum að greina betur litakóðuð upplýsingar", + "Enabled": "Virkt", + "EnableInteractiveSearchHelpText": "Verður notað þegar gagnvirk leit er notuð", + "EnableRss": "Virkja RSS", + "ErrorLoadingContents": "Villa við að hlaða innihald", + "Events": "Viðburðir", + "EventType": "Viðburðargerð", + "Exception": "Undantekning", + "FocusSearchBox": "Fókus leitarreitur", + "Grabbed": "Greip", + "IndexerProxyStatusCheckAllClientMessage": "Allir listar eru ekki tiltækir vegna bilana", + "IndexerProxyStatusCheckSingleClientMessage": "Listar ekki tiltækir vegna bilana: {0}", + "SSLCertPassword": "SSL vottorð lykilorð", + "SSLCertPasswordHelpText": "Lykilorð fyrir PFX skrá", + "SSLCertPath": "SSL vottunarleið", + "AddDownloadClient": "Bæta við Download Client", + "BackupNow": "Taktu öryggisafrit núna", + "DeleteDownloadClient": "Eyða niðurhals viðskiptavinur", + "General": "Almennt", + "IgnoredAddresses": "Heimilisföng hunsuð", + "Interval": "Tímabil", + "Search": "Leitaðu", + "UILanguage": "Tungumál HÍ", + "CertificateValidation": "Staðfesting skírteina", + "Clear": "Hreinsa", + "DownloadClientSettings": "Sæktu niður stillingar viðskiptavinar", + "Health": "Heilsa", + "NoBackupsAreAvailable": "Engin afrit eru í boði", + "NoChange": "Engin breyting", + "NoChanges": "Engar breytingar", + "NoLeaveIt": "Nei, skilið það eftir", + "SaveChanges": "Vista breytingar", + "Details": "Upplýsingar", + "PortNumber": "Portnúmer", + "Uptime": "Spenntur", + "SystemTimeCheckMessage": "Slökkt er á tíma kerfisins meira en 1 dag. Skipulögð verkefni ganga kannski ekki rétt fyrr en tíminn er leiðréttur", + "TableOptions": "Borðvalkostir", + "TableOptionsColumnsMessage": "Veldu hvaða dálkar eru sýnilegir og í hvaða röð þeir birtast", + "TagCannotBeDeletedWhileInUse": "Ekki er hægt að eyða meðan hún er í notkun", + "TagIsNotUsedAndCanBeDeleted": "Merkið er ekki notað og hægt er að eyða því", + "Tags": "Merkimiðar", + "Tasks": "Verkefni", + "Test": "Próf", + "TestAllClients": "Prófaðu alla viðskiptavini", + "Time": "Tími", + "Today": "Í dag", + "Tomorrow": "Á morgun", + "Torrent": "Flæði", + "Torrents": "Flæði", + "Type": "Tegund", + "UnableToAddANewApplicationPleaseTryAgain": "Ekki er hægt að bæta við nýrri tilkynningu. Reyndu aftur.", + "UnableToLoadBackups": "Ekki er hægt að hlaða afrit", + "UnableToLoadDownloadClients": "Ekki er hægt að hlaða niður viðskiptavinum", + "UnableToLoadGeneralSettings": "Ekki er hægt að hlaða almennar stillingar", + "UnableToLoadHistory": "Ekki er hægt að hlaða sögu", + "UnableToLoadIndexers": "Ekki er hægt að hlaða Indexers", + "UnableToLoadNotifications": "Ekki er hægt að hlaða tilkynningar", + "UrlBaseHelpText": "Fyrir öfugan umboðsmannastuðning er sjálfgefið autt", + "UseProxy": "Notaðu Proxy", + "Username": "Notendanafn", + "Version": "Útgáfa", + "LaunchBrowserHelpText": " Opnaðu vafra og farðu á Radarr heimasíðuna þegar forritið byrjar.", + "Level": "Stig", + "MaximumLimits": "Hámarksmörk", + "Mechanism": "Mekanismi", + "Message": "Skilaboð", + "AcceptConfirmationModal": "Samþykkja staðfestingarform", + "Actions": "Aðgerðir", + "CloneIndexer": "Clone Indexer", + "Proxy": "Umboðsmaður", + "SuggestTranslationChange": "Legg til þýðingabreytingu", + "DeleteTag": "Eyða tagi", + "DeleteTagMessageText": "Ertu viss um að þú viljir eyða merkinu '{0}'?", + "Donations": "Framlög", + "DownloadClient": "Sæktu viðskiptavin", + "DownloadClientCheckNoneAvailableMessage": "Enginn niðurhalsþjónn er í boði", + "Edit": "Breyta", + "EnableCompletedDownloadHandlingHelpText": "Flytja sjálfkrafa niður niðurhal frá niðurhalsþjóni", + "EnabledHelpText": "Virkaðu þennan lista til notkunar í Radarr", + "EnableHelpText": "Virkja stofnun lýsigagna fyrir þessa gerð lýsigagna", + "EnableInteractiveSearch": "Virkja gagnvirka leit", + "EnableSSL": "Virkja SSL", + "EnableSslHelpText": " Krefst endurræsingar sem stjórnandi til að taka gildi", + "Error": "Villa", + "ExistingMovies": "Núverandi kvikmynd (ir)", + "ExistingTag": "Núverandi merki", + "Failed": "Mistókst", + "FeatureRequests": "Aðgerðarbeiðnir", + "Filename": "Skráarnafn", + "Files": "Skrár", + "LogLevel": "Log Level", + "LogLevelTraceHelpTextWarning": "Aðeins ætti að virkja rakningaskráningu tímabundið", + "Manual": "Handbók", + "MIA": "MIA", + "MinimumLimits": "Lágmark", + "MinutesHundredTwenty": "120 mínútur: {0}", + "New": "Nýtt", + "NoMinimumForAnyRuntime": "Ekkert lágmark fyrir neina keyrslutíma", + "NotificationTriggers": "Tilkynningakveikjur", + "PackageVersion": "Pakki Útgáfa", + "PageSize": "Stærð blaðsíðu", + "PageSizeHelpText": "Fjöldi atriða til að sýna á hverri síðu", + "ProxyCheckResolveIpMessage": "Mistókst að leysa IP-tölu fyrir stillta proxy-gestgjafa {0}", + "ProxyPasswordHelpText": "Þú þarft aðeins að slá inn notendanafn og lykilorð ef þess er krafist. Láttu þá vera auða annars.", + "ProxyType": "Umboðsmaður", + "QualityDefinitions": "Gæðaskilgreiningar", + "QualitySettings": "Gæðastillingar", + "Queue": "Biðröð", + "ReadTheWikiForMoreInformation": "Lestu Wiki fyrir frekari upplýsingar", + "Refresh": "Hressa", + "RefreshMovie": "Hressa kvikmynd", + "ReleaseBranchCheckOfficialBranchMessage": "Útibú {0} er ekki gild útibú frá Radarr, þú færð ekki uppfærslur", + "Reload": "Endurhlaða", + "ResetAPIKey": "Endurstilla API lykil", + "Restart": "Endurræsa", + "RestartNow": "Endurræstu núna", + "SendAnonymousUsageData": "Sendu nafnlaus notkunargögn", + "SetTags": "Settu merki", + "Settings": "Stillingar", + "SettingsEnableColorImpairedMode": "Virkja litaskerta ham", + "UILanguageHelpText": "Tungumál sem Radarr mun nota fyrir HÍ", + "UILanguageHelpTextWarning": "Endurhlaða vafra krafist", + "UISettings": "Stillingar HÍ", + "UnableToLoadQualityDefinitions": "Ekki er hægt að hlaða gæðaskilgreiningar", + "UnableToLoadTags": "Ekki er hægt að hlaða merkin", + "UnableToLoadUISettings": "Ekki er hægt að hlaða stillingar HÍ", + "UnselectAll": "Afmarkaðu allt", + "UpdateAutomaticallyHelpText": "Sjálfkrafa hlaða niður og setja upp uppfærslur. Þú munt samt geta sett upp úr System: Updates", + "UpdateCheckStartupNotWritableMessage": "Ekki er hægt að setja uppfærslu þar sem ræsimappan '{0}' er ekki skrifanleg af notandanum '{1}'.", + "UpdateCheckStartupTranslocationMessage": "Ekki er hægt að setja uppfærslu vegna þess að ræsimappan '{0}' er í forritunarmöppu forrits.", + "UpdateCheckUINotWritableMessage": "Ekki er hægt að setja uppfærslu vegna þess að notendamöppan '{0}' er ekki skrifuð af notandanum '{1}'.", + "UpdateMechanismHelpText": "Notaðu innbyggða uppfærslu Radarr eða handrit", + "Updates": "Uppfærslur", + "UpdateScriptPathHelpText": "Leið að sérsniðnu handriti sem tekur útdreginn uppfærslupakka og annast afganginn af uppfærsluferlinu", + "URLBase": "Vefslóðagrunnur", + "View": "Útsýni", + "Warn": "Vara við", + "Wiki": "Wiki", + "YesCancel": "Já, hætta við", + "Yesterday": "Í gær", + "Connections": "Tengingar", + "Custom": "Sérsniðin", + "EnableColorImpairedMode": "Virkja litaskerta ham", + "HideAdvanced": "Fela lengra komna", + "HomePage": "Heimasíða", + "PriorityHelpText": "Forgangsraðaðu mörgum niðurhal viðskiptavinum. Round-Robin er notað fyrir viðskiptavini með sömu forgang.", + "Reddit": "Reddit", + "SelectAll": "Velja allt", + "SettingsTimeFormat": "Tímasnið", + "TestAll": "Prófaðu allt", + "Title": "Titill", + "UnsavedChanges": "Óvistaðar breytingar", + "CertificateValidationHelpText": "Breyttu hversu ströng HTTPS vottun er", + "ChangeHasNotBeenSavedYet": "Breyting hefur ekki verið vistuð ennþá", + "ClientPriority": "Forgangur viðskiptavinar", + "CloneProfile": "Klónasnið", + "CloseCurrentModal": "Lokaðu núverandi modal", + "Columns": "Súlur", + "Component": "Hluti", + "ConnectionLost": "Tenging rofin", + "ConnectionLostAutomaticMessage": "Radarr mun reyna að tengjast sjálfkrafa eða þú getur smellt á endurhlaða hér að neðan.", + "Folder": "Mappa", + "ForMoreInformationOnTheIndividualDownloadClients": "Fyrir frekari upplýsingar um einstaka niðurhal viðskiptavini, smelltu á upplýsingatakkana.", + "GeneralSettings": "Almennar stillingar", + "Grabs": "Grípa", + "GeneralSettingsSummary": "Gátt, SSL, notandanafn / lykilorð, umboð, greining og uppfærslur", + "History": "Saga", + "NoUpdatesAreAvailable": "Engar uppfærslur eru í boði", + "OpenBrowserOnStart": "Opnaðu vafra við byrjun", + "TagsHelpText": "Gildir fyrir kvikmyndir með að minnsta kosti einu samsvarandi merki", + "TagsSettingsSummary": "Sjáðu öll merkin og hvernig þau eru notuð. Hægt er að fjarlægja ónotuð merki", + "AddIndexer": "Bættu við Indexer", + "Date": "Dagsetning", + "AddingTag": "Bætir við merki", + "Age": "Aldur", + "All": "Allt", + "AllIndexersHiddenDueToFilter": "Allar kvikmyndir eru faldar vegna beittrar síu.", + "Analytics": "Greiningar", + "AnalyticsEnabledHelpText": "Sendu nafnlausar upplýsingar um notkun og villur á netþjóna Radarr. Þetta felur í sér upplýsingar í vafranum þínum, hvaða Radarr WebUI síður þú notar, villuskýrslur sem og stýrikerfi og keyrsluútgáfu. Við munum nota þessar upplýsingar til að forgangsraða eiginleikum og villuleiðréttingum.", + "ApiKey": "API lykill", + "AppDataDirectory": "AppData skrá", + "AppDataLocationHealthCheckMessage": "Uppfærsla verður ekki möguleg til að koma í veg fyrir að AppData sé eytt við uppfærslu", + "ApplicationStatusCheckAllClientMessage": "Allir listar eru ekki tiltækir vegna bilana", + "ApplicationStatusCheckSingleClientMessage": "Listar ekki tiltækir vegna bilana: {0}", + "Apply": "Sækja um", + "ApplyTags": "Notaðu merki", + "ApplyTagsHelpTexts1": "Hvernig á að setja merki á völdu kvikmyndirnar", + "ApplyTagsHelpTexts2": "Bæta við: Bættu merkjum við núverandi lista yfir merki", + "ApplyTagsHelpTexts3": "Fjarlægja: Fjarlægðu innsláttarmerkin", + "ApplyTagsHelpTexts4": "Skipta um: Skiptu um merkin með innsláttu merkjunum (sláðu inn engin merki til að hreinsa öll merki)", + "Authentication": "Auðkenning", + "AuthenticationMethodHelpText": "Krefjast notandanafns og lykilorðs til að fá aðgang að Radarr", + "Automatic": "Sjálfskiptur", + "AutomaticSearch": "Sjálfvirk leit", + "BackupIntervalHelpText": "Bil milli sjálfvirkra afrita", + "BackupRetentionHelpText": "Sjálfvirk afrit sem eru eldri en varðveislutímabilið verða hreinsuð upp sjálfkrafa", + "NoTagsHaveBeenAddedYet": "Engum merkjum hefur verið bætt við ennþá", + "OAuthPopupMessage": "Lokað er fyrir sprettiglugga af vafranum þínum", + "Backups": "Afrit", + "BeforeUpdate": "Fyrir uppfærslu", + "BindAddressHelpText": "Gilt IP4 heimilisfang eða '*' fyrir öll tengi", + "Branch": "Útibú", + "CancelPendingTask": "Ertu viss um að þú viljir hætta við þetta verkefni í bið?", + "ConnectSettings": "Tengdu stillingar", + "CouldNotConnectSignalR": "Gat ekki tengst SignalR, HÍ mun ekki uppfæra", + "CustomFilters": "Sérsniðin síur", + "Dates": "Dagsetningar", + "DBMigration": "DB fólksflutningar", + "DelayProfile": "Seinka prófíl", + "Delete": "Eyða", + "DeleteApplicationMessageText": "Ertu viss um að þú viljir eyða tilkynningunni „{0}“?", + "DeleteBackup": "Eyða afritun", + "DeleteBackupMessageText": "Ertu viss um að þú viljir eyða öryggisafritinu '{0}'?", + "DeleteDownloadClientMessageText": "Ertu viss um að þú viljir eyða niðurhalsviðskiptavininum '{0}'?", + "DeleteIndexer": "Eyða Indexer", + "DeleteIndexerMessageText": "Ertu viss um að þú viljir eyða vísitölunni '{0}'?", + "DeleteNotification": "Eyða tilkynningu", + "DeleteNotificationMessageText": "Ertu viss um að þú viljir eyða tilkynningunni „{0}“?", + "Disabled": "Öryrkjar", + "Discord": "Ósætti", + "Docker": "Docker", + "DownloadClientCheckUnableToCommunicateMessage": "Ekki er hægt að eiga samskipti við {0}.", + "DownloadClients": "Sækja viðskiptavini", + "DownloadClientStatusCheckAllClientMessage": "Allir viðskiptavinir sem hlaða niður eru ekki tiltækir vegna bilana", + "DownloadClientStatusCheckSingleClientMessage": "Sæktu viðskiptavini sem eru ekki tiltækir vegna bilana: {0}", + "DownloadClientUnavailable": "Niðurhalsþjónn er ekki tiltækur", + "Downloading": "Sækir", + "EditIndexer": "Breyttu Indexer", + "Enable": "Virkja", + "EnableAutoHelpText": "Ef það er virkt verður kvikmyndum sjálfkrafa bætt við Radarr af þessum lista", + "EnableAutomaticAdd": "Virkja sjálfvirka viðbót", + "EnableAutomaticSearch": "Virkja sjálfvirka leit", + "EnableAutomaticSearchHelpText": "Verður notað þegar sjálfvirkar leitir eru framkvæmdar í HÍ eða af Radarr", + "EnableAutomaticSearchHelpTextWarning": "Verður notað þegar gagnvirk leit er notuð", + "EnableInteractiveSearchHelpTextWarning": "Leit er ekki studd með þessum flokkara", + "EnableMediaInfoHelpText": "Dragðu út myndbandsupplýsingar eins og upplausn, keyrslutíma og merkjamál upplýsingar úr skrám. Þetta krefst þess að Radarr lesi hluta af skránni sem geta valdið mikilli virkni á diski eða neti meðan á skönnunum stendur.", + "Filter": "Sía", + "Fixed": "Fastur", + "HealthNoIssues": "Engin vandamál með stillingar þínar", + "HiddenClickToShow": "Falinn, smelltu til að sýna", + "Host": "Gestgjafi", + "Hostname": "Gestgjafanafn", + "IllRestartLater": "Ég byrja aftur seinna", + "Importing": "Innflutningur", + "IncludeHealthWarningsHelpText": "Láttu heilsuviðvaranir fylgja með", + "Indexer": "Indexer", + "Info": "Upplýsingar", + "IndexerFlags": "Indexer fánar", + "IndexerLongTermStatusCheckAllClientMessage": "Allir verðtryggingaraðilar eru ekki tiltækir vegna bilana í meira en 6 klukkustundir", + "IndexerLongTermStatusCheckSingleClientMessage": "Vísitölufólk er ekki tiltækt vegna bilana í meira en 6 klukkustundir: {0}", + "IndexerPriorityHelpText": "Forgangur flokkara frá 1 (Hæstur) til 50 (Lægstur). Sjálfgefið: 25.", + "Indexers": "Vísitölufólk", + "IndexerStatusCheckAllClientMessage": "Allir verðtryggingaraðilar eru ekki tiltækir vegna bilana", + "IndexerStatusCheckSingleClientMessage": "Vísitölufólk er ekki tiltækt vegna bilana: {0}", + "NoLimitForAnyRuntime": "Engin takmörk fyrir neina keyrslutíma", + "NoLogFiles": "Engar logskrár", + "Ok": "Allt í lagi", + "OnHealthIssueHelpText": "Um heilbrigðismál", + "OpenThisModal": "Opnaðu þetta módel", + "Options": "Valkostir", + "Password": "Lykilorð", + "Peers": "Jafningjar", + "Pending": "Í bið", + "PendingChangesDiscardChanges": "Fargaðu breytingum og farðu", + "PendingChangesMessage": "Þú ert með óvistaðar breytingar, ertu viss um að þú viljir yfirgefa þessa síðu?", + "PendingChangesStayReview": "Vertu og skoðaðu breytingar", + "PreferredSize": "Æskileg stærð", + "ShowAdvanced": "Sýna lengra komna", + "UnableToAddANewAppProfilePleaseTryAgain": "Ekki er hægt að bæta við nýjum gæðaprófíl, reyndu aftur.", + "UnableToAddANewDownloadClientPleaseTryAgain": "Ekki er hægt að bæta við nýjum niðurhalsþjóni, reyndu aftur.", + "UnableToAddANewIndexerPleaseTryAgain": "Ekki er hægt að bæta við nýjum flokkara, reyndu aftur.", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Ekki er hægt að bæta við nýjum flokkara, reyndu aftur.", + "UnableToAddANewNotificationPleaseTryAgain": "Ekki er hægt að bæta við nýrri tilkynningu. Reyndu aftur.", + "BackupFolderHelpText": "Hlutfallslegir slóðir verða undir AppData skránni hjá Radarr", + "BranchUpdateMechanism": "Útibú notað af ytri uppfærslu", + "BypassProxyForLocalAddresses": "Hliðarbraut umboðsmanns fyrir heimilisfang", + "Cancel": "Hætta við", + "Close": "Lokaðu", + "IndexerPriority": "Forgangur indexers", + "InteractiveSearch": "Gagnvirk leit", + "KeyboardShortcuts": "Flýtilyklar", + "Language": "Tungumál", + "LogFiles": "Log skrár", + "Languages": "Tungumál", + "LastWriteTime": "Síðasti skrifatími", + "MinutesNinety": "90 mínútur: {0}", + "MinutesSixty": "60 mínútur: {0}", + "Mode": "Mode", + "MonoTlsCheckMessage": "Radarr Mono 4.x tls lausn enn virk, íhugaðu að fjarlægja MONO_TLS_PROVIDER = arfur umhverfis valkostur", + "MonoVersion": "Mónóútgáfa", + "MonoVersionCheckUpgradeRecommendedMessage": "Núverandi uppsett Mono útgáfa {0} er studd en mælt er með uppfærslu í {1}.", + "MoreInfo": "Meiri upplýsingar", + "MovieDetailsNextMovie": "Upplýsingar um kvikmynd: Næsta kvikmynd", + "MovieDetailsPreviousMovie": "Upplýsingar um kvikmynd: Fyrri kvikmynd", + "MovieIndexScrollTop": "Kvikmyndavísitala: Scroll Top", + "Movies": "Kvikmyndir", + "Name": "Nafn", + "NoLinks": "Engir krækjur", + "Port": "Höfn", + "Presets": "Forstillingar", + "Priority": "Forgangsröð", + "PrioritySettings": "Forgangsröð", + "Protocol": "Bókun", + "ProxyBypassFilterHelpText": "Notaðu ',' sem aðskilnað og '*.' sem jókort fyrir undirlén", + "ProxyCheckBadRequestMessage": "Mistókst að prófa umboðsmann. Stöðukóði: {0}", + "ProxyCheckFailedToTestMessage": "Mistókst að prófa umboðsmann: {0}", + "ProxyUsernameHelpText": "Þú þarft aðeins að slá inn notendanafn og lykilorð ef þess er krafist. Láttu þá vera auða annars.", + "PtpOldSettingsCheckMessage": "Eftirfarandi PassThePopcorn vísitölur hafa úrelt stillingar og ætti að uppfæra þær: {0}", + "ReleaseStatus": "Sleppa stöðu", + "RemovedFromTaskQueue": "Fjarlægð úr verkröð", + "RemoveFilter": "Fjarlægðu síuna", + "RemovingTag": "Fjarlægir merkið", + "Reset": "Endurstilla", + "RestartRequiredHelpTextWarning": "Krefst endurræsingar til að taka gildi", + "Restore": "Endurheimta", + "RestoreBackup": "Endurheimtu öryggisafrit", + "Restrictions": "Takmarkanir", + "Retention": "Varðveisla", + "RSS": "RSS", + "RSSIsNotSupportedWithThisIndexer": "RSS er ekki studd með þessum flokkara", + "Save": "Vista", + "SaveSettings": "Vista stillingar", + "Scheduled": "Tímaáætlun", + "ScriptPath": "Handritaleið", + "Security": "Öryggi", + "Seeders": "Plöntur", + "SettingsEnableColorImpairedModeHelpText": "Breyttur stíll til að leyfa litaskertum notendum að greina betur litakóðuð upplýsingar", + "SettingsLongDateFormat": "Langt stefnumót", + "SettingsShortDateFormat": "Stutt dagsetningarsnið", + "SettingsShowRelativeDates": "Sýna hlutfallslegar dagsetningar", + "SettingsShowRelativeDatesHelpText": "Sýndu ættingja (í dag / í gær / etc) eða algerar dagsetningar", + "ShownClickToHide": "Sýnt, smelltu til að fela", + "ShowSearch": "Sýna leit", + "ShowSearchHelpText": "Sýna leitarhnappinn á sveima", + "Shutdown": "Lokun", + "Size": "Stærð", + "Sort": "Raða", + "Source": "Heimild", + "StartTypingOrSelectAPathBelow": "Byrjaðu að slá eða veldu leið hér að neðan", + "StartupDirectory": "Ræsiskrá", + "Status": "Staða", + "Style": "Stíll", + "System": "Kerfi" +} diff --git a/src/NzbDrone.Core/Localization/Core/it.json b/src/NzbDrone.Core/Localization/Core/it.json index 7eed8ac91..6d09cea78 100644 --- a/src/NzbDrone.Core/Localization/Core/it.json +++ b/src/NzbDrone.Core/Localization/Core/it.json @@ -6,23 +6,18 @@ "SetTags": "Imposta Tag", "SelectAll": "Seleziona Tutto", "Scheduled": "In Programma", - "RootFolder": "Cartella Radice", "ReleaseBranchCheckPreviousVersionMessage": "Il Branch {0} corrisponde ad una versione precedente di Prowlarr, imposta il branch su \"Nightly\" per ricevere gli aggiornamenti futuri", "ReleaseBranchCheckOfficialBranchMessage": "Il Branch {0} non è un branch valido per le release di Prowlarr, non riceverai aggiornamenti", "QualityDefinitions": "Definizioni delle Qualità", "PtpOldSettingsCheckMessage": "Il seguente indexer PassThePopcorn ha delle impostazioni obsolete e deve essere aggiornato: {0}", "ProxyCheckResolveIpMessage": "Impossibile risolvere l'indirizzo IP per il Proxy {0}", - "OutputPath": "Percorso di Destinazione", "NoChanges": "Nessuna Modifica", "NoChange": "Nessuna Modifica", - "Monitor": "Segui", - "ListExclusions": "Esclusioni dalle Liste", "LastWriteTime": "Orario di Ultima Scrittura", "Indexer": "Indicizzatore", "HideAdvanced": "Nascondi Avanzate", "Health": "Salute", "Grabbed": "Recuperato", - "DigitalRelease": "Release Digitale", "Clear": "Cancella", "AppDataLocationHealthCheckMessage": "Non è possibile effettuare l'aggiornamento per evitare di cancellare AppData", "Analytics": "Statistiche", @@ -47,7 +42,6 @@ "SaveChanges": "Salva Modifiche", "Restrictions": "Restrizioni", "RestoreBackup": "Ripristina Backup", - "RemovedMovieCheckSingleMessage": "Il Film {0} è stato rimosso da TMDb", "ReleaseStatus": "Stato Release", "Refresh": "Aggiorna", "Queue": "Coda", @@ -60,18 +54,13 @@ "MoreInfo": "Maggiori Info", "MonoTlsCheckMessage": "Il workaround per Prowlarr Mono 4.x tls è ancora disabilitato, potresti considerare di rimuovere l'opzione ambiente MONO_TLS_PROVIDER=legacy", "MonoNotNetCoreCheckMessage": "Per favore aggiorna alla versione .NET Core di Prowlarr", - "MetadataSettingsSummary": "Crea file metadata quando i film vengono importati o aggiornati", - "ManualImport": "Import Manuale", "Logging": "Logging", "LogFiles": "File di Log", "Languages": "Lingue", "Language": "Lingua", "IndexerStatusCheckSingleClientMessage": "Indexer non disponibili a causa di errori: {0}", "IndexerStatusCheckAllClientMessage": "Tutti gli indexer non sono disponibili a causa di errori", - "IndexerSearchCheckNoAutomaticMessage": "Non è disponibile nessun indexer con abilitata la Ricerca Automatica, Prowlarr non fornirà nessun risultato tramite la ricerca automatica", "Indexers": "Indexer", - "ImportSecondTip": "Indirizza Prowlarr alla cartella che contiene tutti i tuoi film, non a cartelle specifiche. Ad esempio:", - "Imported": "Importato", "Host": "Host", "History": "Storia", "GeneralSettingsSummary": "Porta, SSL, Nome utente/password, proxy, statistiche e aggiornamenti", @@ -99,19 +88,15 @@ "Connect": "Collega", "Connections": "Collegamenti", "ConnectSettingsSummary": "Notifiche, collegamenti a media server/player e script personalizzati", - "Cast": "Cast", "BackupNow": "Effettua ora il Backup", "Backup": "Backup", "All": "Tutti", "Actions": "Azioni", - "Activity": "Attività", "Age": "Età", - "AddListExclusion": "Aggiungi Lista Esclusioni", "Close": "Chiudi", "CloneProfile": "Clona il Profilo", "CloneIndexer": "Clona Indexer", "ClientPriority": "Priorità del Client", - "CheckForFinishedDownloadsInterval": "Intervallo per il controllo dei download finiti", "ChangeHasNotBeenSavedYet": "Il cambiamento non è stato ancora salvato", "CertificateValidationHelpText": "Cambiare il \"grado di severità\" della convalida del certificato HTTPS", "CertificateValidation": "Convalida del certificato", @@ -124,7 +109,6 @@ "BackupRetentionHelpText": "I backup automatici più vecchi del periodo di conservazione verranno eliminati automaticamente", "BackupIntervalHelpText": "Intervallo tra i backup automatici", "BackupFolderHelpText": "I percorsi relativi saranno sotto la directory AppData di Prowlarr", - "AutoRedownloadFailedHelpText": "Ricerca automatica e tentativo di scaricare un'altra versione", "Automatic": "Automatico", "AuthenticationMethodHelpText": "Utilizza nome utente e password per accedere a Prowlarr", "Authentication": "Autenticazione", @@ -134,7 +118,6 @@ "AppDataDirectory": "Cartella AppData", "ApiKey": "Chiave API", "AnalyticsEnabledHelpText": "Inviare informazioni anonime sull'utilizzo e sugli errori ai server di Prowlarr. Ciò include informazioni sul tuo browser, come le pagine di Prowlarr che utilizzi, la segnalazione di errori e la versione del sistema operativo e del runtime. Utilizzeremo queste informazioni per dare priorità alle funzioni e alle correzioni di bug.", - "AllowHardcodedSubsHelpText": "Se verranno rilevati sottotitoli impressi il film verrà comunque scaricato", "Warn": "Attenzione", "Type": "Tipo", "Title": "Titolo", @@ -152,7 +135,6 @@ "Reload": "Ricarica", "Peers": "Peers", "PageSize": "Dimensione Pagina", - "OrganizeModalAllPathsRelative": "Tutti i percorsi sono relativi a:", "Ok": "Ok", "OAuthPopupMessage": "I Pop-ups sono bloccati dal tuo browser", "Name": "Nome", @@ -165,26 +147,21 @@ "Error": "Errore", "EnableAutoHelpText": "Se abilitato, i film saranno aggiunti automaticamente a Prowlarr da questa lista", "Enable": "Abilita", - "Edition": "Edizione", "DownloadClientSettings": "Impostazioni del client di download", "Docker": "Docker", "DeleteTag": "Cancella Tag", "DeleteNotification": "Cancellare la notifica", "DeleteIndexer": "Cancella Indexer", - "DeleteEmptyFolders": "Cancellare le cartelle vuote", "DeleteDownloadClient": "Cancellare il client di download", "DeleteBackup": "Cancellare il backup", "DelayProfile": "Profili di Ritardo", "DBMigration": "Migrazione del DataBase", - "CustomFormatScore": "Punteggio del formato personalizzato", - "CopyUsingHardlinksHelpTextWarning": "Occasionalmente, i blocchi dei file possono impedire la ridenominazione dei file in fase di seeding. È possibile disattivare temporaneamente il seeding e utilizzare la funzione di rinomina di Prowlarr per evitare il problema.", "ConnectSettings": "Impostazioni di connessione", "ConnectionLostMessage": "Prowlarr ha perso la connessione al backend e dovrà essere ricaricato per ripristinare la funzionalità.", "ConnectionLostAutomaticMessage": "Prowlarr cercherà di connettersi automaticamente, oppure potete cliccare su ricarica qui sotto.", "ConnectionLost": "Connessione persa", "Component": "Componente", "Columns": "Colonne", - "CouldNotFindResults": "Non ho trovato risultati per '{0}'", "DeleteBackupMessageText": "Sei sicuro di voler cancellare il backup '{0}'?", "CancelPendingTask": "Sei sicuro di voler cancellare questa operazione in sospeso?", "BranchUpdateMechanism": "Branch utilizzato dal sistema di aggiornamento esterno", @@ -192,23 +169,19 @@ "ApplyTagsHelpTexts2": "Aggiungi: Aggiungere i tag la lista esistente di tag", "ApplyTagsHelpTexts1": "Come applicare i tag ai film selezionati", "AddingTag": "Aggiungi tag", - "Proper": "Proper", "Password": "Password", "OnHealthIssueHelpText": "Quando c'è un problema", "NotificationTriggers": "Selettori di notifica", "NetCore": ".NET", "Logs": "Logs", "Hostname": "Hostname", - "FileChmodHelpTexts2": "La stessa modalità viene applicata alle cartelle di film/sub con il bit di esecuzione aggiunto, ad esempio, 0644 diventa 0755", "MIA": "MIA", "IndexerFlags": "Etichetta indexer", - "ExtraFileExtensionsHelpTexts1": "Liste di file Extra da importare separate da virgola (.nfo saranno importate come .nfo-orig)", "EnableSSL": "Abilita SSL", "EnableColorImpairedModeHelpText": "Stile alterato per permettere agli utenti daltonici di distinguere meglio le informazioni con colori codificati", "SettingsLongDateFormat": "Formato Data Lungo", "SettingsEnableColorImpairedMode": "Abilità la modalità colori alternati", "SendAnonymousUsageData": "Invia dati sull'uso anonimamente", - "SearchMovie": "Trova Film", "ScriptPath": "Percorso dello script", "RSSIsNotSupportedWithThisIndexer": "RSS non è supportato con questo indexer", "Retention": "Memorizzazione", @@ -219,16 +192,10 @@ "RestartNow": "Riavvia adesso", "ResetAPIKey": "Resetta la Chiave API", "Reset": "Resetta", - "RequiredPlaceHolder": "Aggiunge una nuova restrizione", - "Reorder": "Riordina", "RemovingTag": "Sto eliminando il tag", - "RemoveFromBlacklist": "Rimuovi della blacklist", "RemoveFilter": "Rimuovi filtro", "RemovedFromTaskQueue": "Rimuovi dalla coda di lavoro", - "ReleaseRejected": "Release rifiutata", "RefreshMovie": "Aggiorna il Film", - "RecyclingBin": "Cestino", - "RecentFolders": "Cartelle recenti", "ReadTheWikiForMoreInformation": "Leggi le Wiki per maggiori informazioni", "ProwlarrSupportsAnyIndexer": "Prowlarr supporta qualunque indexer che usi gli standard Newznab, cosi come gli altri Indexer sotto.", "ProwlarrSupportsAnyDownloadClient": "Prowlarr supporta qualunque client di download che usi gli standard Newznab, cosi come gli altri client sotto.", @@ -239,7 +206,6 @@ "ProxyBypassFilterHelpText": "Usa ',' come separatore, e '*.' come jolly per i sottodomini", "PriorityHelpText": "Dai priorità ai client di download multipli. Round-Robin è usato per i client con la stessa priorità.", "PreferredSize": "Dimensione preferita", - "PosterOptions": "Opzioni dei poster", "PortNumber": "Numero di porta", "Port": "Porta", "PendingChangesStayReview": "Rimani e rivedi modifiche", @@ -257,36 +223,26 @@ "NoLeaveIt": "No, lascialo", "NoBackupsAreAvailable": "Nessun Backup disponibile", "New": "Nuovo", - "MustContain": "Deve contenere", - "MoviesSelectedInterp": "{0} Film selezionato(i)", - "MovieIsDownloadingInterp": "Film in download - {0}% {1}", "MovieInfoLanguage": "Lingua delle info del film", - "MovieExcludedFromAutomaticAdd": "Film escluso dall'aggiunta automatica", "MonoVersion": "Versione Mono", "Mode": "Modo", "MinutesSixty": "60 Minuti: {0}", "MinutesNinety": "90 Minuti: {0}", "MinutesHundredTwenty": "120 Minuti: {0}", "MinimumLimits": "Limiti minimi", - "MinFormatScoreHelpText": "Punteggio minimo del formato personalizzato abilitato al download", "Mechanism": "Meccanismo", "MaximumLimits": "Limiti massimi", "Manual": "Manuale", "MaintenanceRelease": "Release di Manutenzione", "LogLevelTraceHelpTextWarning": "Il Trace Log dovrebbe essere abilitato solo temporaneamente", "LogLevel": "Livello di Log", - "LoadingMovieCreditsFailed": "Caricamento dei crediti del film fallito", - "LinkHere": "qui", "LaunchBrowserHelpText": " Apri un browser e vai all'homepage di Prowlarr all'avvio dell'app.", "Interval": "Intervallo", - "IncludeUnknownMovieItemsHelpText": "Mostra le voci senza un film nella coda. Ciò potrebbe include film spostati o altro nelle categorie di Prowlarr", "IncludeHealthWarningsHelpText": "Includi gli avvisi di salute", "Importing": "Importazione", - "ImportExtraFiles": "Importa file Extra", "IllRestartLater": "Riavvierò più tardi", "IgnoredAddresses": "Indirizzi ignorati", "HiddenClickToShow": "Nascosto, premi per mostrare", - "GrabReleaseMessageText": "Prowlarr non è stato in grado di determinare a quale film si riferisce questa release. Prowlarr potrebbe non essere in grado di importarla automaticamente. Vuoi catturare '{0}'?", "GeneralSettings": "Impostazioni Generali", "ForMoreInformationOnTheIndividualDownloadClients": "Per maggiori informazioni sui singoli client di download clicca sul pulsante info.", "Fixed": "Fissato", @@ -309,7 +265,6 @@ "EnableAutomaticSearch": "Attiva la ricerca automatica", "EnableAutomaticAdd": "Attiva l'aggiunta automatica", "Downloading": "Scaricando", - "DownloadedAndMonitored": "Scaricato e Monitorato", "DownloadClientUnavailable": "Il client di download non è disponibile", "DeleteTagMessageText": "Sei sicuro di voler eliminare il tag '{0}'?", "DeleteNotificationMessageText": "Sei sicuro di voler eliminare la notifica '{0}'?", @@ -321,7 +276,6 @@ "Usenet": "Usenet", "Uptime": "Tempo di attività", "YesCancel": "Si, annulla", - "WaitingToProcess": "In attesa di processo", "Version": "Versione", "Username": "Nome utente", "UseProxy": "Usa Proxy", @@ -333,11 +287,8 @@ "UnsavedChanges": "Modifiche non salvate", "UnableToLoadUISettings": "Non riesco a caricare le impostazioni della UI", "UnableToLoadTags": "Non riesco a caricare i tag", - "UnableToLoadQualityProfiles": "Non riesco a caricare i profili della qualità", "UnableToLoadQualityDefinitions": "Non riesco a caricare le definizioni della qualità", "UnableToLoadNotifications": "Non riesco a caricare le notifiche", - "UnableToLoadMediaManagementSettings": "Non riesco a caricare le impostazioni di Gestione dei Media", - "UnableToLoadLanguages": "Non riesco a caricare le lingue", "UnableToLoadIndexers": "Non riesco a caricare l'indexer", "UnableToLoadHistory": "Non riesco a caricare la storia", "UnableToLoadGeneralSettings": "Non riesco a caricare le impostazioni generali", @@ -351,8 +302,6 @@ "UILanguageHelpText": "Lingua che Prowlarr userà per la UI", "UILanguage": "Lingua della UI", "Torrents": "Torrent", - "TMDBId": "ID di TMDb", - "TestAllIndexers": "Testa tutti gli indexer", "TestAllClients": "Testa tutti i client", "TagsHelpText": "Si applica ai film con almeno un tag corrispondente", "TagIsNotUsedAndCanBeDeleted": "Il tag non è usato e può essere eliminato", @@ -365,22 +314,14 @@ "SSLCertPath": "Percorso Cert SSL", "SSLCertPasswordHelpText": "Password del file pfx", "SSLCertPassword": "Password Cert SSL", - "SkipFreeSpaceCheckWhenImportingHelpText": "Usa quando Prowlarr non è in grado di determinare lo spazio libero della cartella di root dei film", - "ShowTitleHelpText": "Mostra il titolo del film sotto il poster", "ShowSearchHelpText": "Mostra pulsante ricerca al passaggio", "ShowSearch": "Mostra ricerca", - "ShowPath": "Mostra percorso", "ShownClickToHide": "Visibile, clicca per nascondere", - "ShowMonitored": "Mostra i monitorati", - "ShowCertification": "Mostra certificato", - "SettingsWeekColumnHeader": "Intestazione colonna settimana", "SettingsTimeFormat": "Formato orario", "SettingsShowRelativeDatesHelpText": "Mostra date relative (Oggi/Ieri/ecc) o assolute", "SettingsShowRelativeDates": "Mostra date relative", "SettingsShortDateFormat": "Formato Data Corto", - "SettingsRemotePathMappingLocalPathHelpText": "Percorso che Prowlarr dovrebbe usare per accedere localmente al percorso remoto", "SettingsEnableColorImpairedModeHelpText": "Stile alterato per permettere agli utenti daltonici di distinguere meglio le informazioni con colori codificati", - "DownloadPropersAndRepacksHelpText1": "Aggiornare o meno automaticamente a Proper/Repack", "Priority": "Priorità", "InteractiveSearch": "Ricerca interattiva", "IndexerPriorityHelpText": "Priorità dell'indexer da 1 (più alto) a 50 (più basso). Default: 25.", @@ -398,9 +339,6 @@ "FocusSearchBox": "Attiva casella di ricerca", "CloseCurrentModal": "Chiudi la modalità corrente", "AcceptConfirmationModal": "Accetta modalità di conferma", - "SearchFailedPleaseTryAgainLater": "Ricerca fallita, provare più tardi.", - "NoMatchFound": "Nessuna corrispondenza trovata!", - "Existing": "Esistente", "AddRestriction": "Aggiungi Limitazioni", "IndexerLongTermStatusCheckSingleClientMessage": "Alcuni indexer non disponibili da più di 6 ore a causa di errori: {0}", "IndexerLongTermStatusCheckAllClientMessage": "Nessun indexer è disponibile da più di 6 ore a causa di errori", @@ -422,5 +360,29 @@ "HomePage": "Home Page", "Id": "Id", "IndexerHealthCheckNoIndexers": "Nessun indexer abilitato Prowlarr non ritornerà risultati di ricerca", - "EnableRss": "Abilita RSS" + "EnableRss": "Abilita RSS", + "NoLinks": "Nessun collegamento", + "RSS": "RSS", + "Wiki": "Wiki", + "AllIndexersHiddenDueToFilter": "Tutti i film sono nascosti a causa del filtro applicato.", + "DeleteApplicationMessageText": "Sei sicuro di voler eliminare la notifica '{0}'?", + "DeleteIndexerProxyMessageText": "Sei sicuro di voler eliminare la lista '{0}'?", + "Presets": "Preset", + "SearchIndexers": "Cerca Films", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Non riesco ad aggiungere un nuovo indexer, riprova.", + "Yesterday": "Ieri", + "ApplicationStatusCheckSingleClientMessage": "Liste non disponibili a causa di errori: {0}", + "Today": "Oggi", + "Tomorrow": "Domani", + "ApplicationStatusCheckAllClientMessage": "Tutte le liste non sono disponibili a causa di errori", + "CouldNotConnectSignalR": "Non ho potuto connettermi a SignalR, la UI non si aggiornerà", + "Custom": "Personalizzato", + "FeatureRequests": "Richieste di funzionalità", + "Grabs": "Preleva", + "IndexerProxyStatusCheckAllClientMessage": "Tutti gli indexer non sono disponibili a causa di errori", + "IndexerProxyStatusCheckSingleClientMessage": "Indexer non disponibili a causa di errori: {0}", + "Reddit": "Reddit", + "Torrent": "Torrent", + "UnableToAddANewApplicationPleaseTryAgain": "Non riesco ad aggiungere una nuova notifica, riprova.", + "UnableToAddANewAppProfilePleaseTryAgain": "Non riesco ad aggiungere un nuovo profilo di qualità, riprova." } diff --git a/src/NzbDrone.Core/Localization/Core/ja.json b/src/NzbDrone.Core/Localization/Core/ja.json index 0967ef424..7815f7528 100644 --- a/src/NzbDrone.Core/Localization/Core/ja.json +++ b/src/NzbDrone.Core/Localization/Core/ja.json @@ -1 +1,361 @@ -{} +{ + "MovieDetailsNextMovie": "映画の詳細:次の映画", + "OpenThisModal": "このモーダルを開く", + "InteractiveSearch": "インタラクティブ検索", + "Interval": "間隔", + "ApplyTagsHelpTexts1": "選択した映画にタグを適用する方法", + "Add": "追加", + "AutomaticSearch": "自動検索", + "CloneProfile": "クローンプロファイル", + "Close": "閉じる", + "EditIndexer": "インデクサーの編集", + "ExistingMovies": "既存の映画", + "ExistingTag": "既存のタグ", + "Failed": "失敗しました", + "Indexer": "インデクサー", + "IndexerFlags": "インデクサフラグ", + "MovieDetailsPreviousMovie": "映画の詳細:前の映画", + "NoChanges": "変更なし", + "NoLeaveIt": "いいえ、そのままにしておきます", + "NoLimitForAnyRuntime": "ランタイムに制限はありません", + "NoUpdatesAreAvailable": "利用可能なアップデートはありません", + "OAuthPopupMessage": "ポップアップがブラウザによってブロックされています", + "Ok": "OK", + "RemovingTag": "タグの削除", + "Reset": "リセット", + "SettingsTimeFormat": "時間形式", + "ShowAdvanced": "高度な表示", + "Time": "時間", + "View": "見る", + "Language": "言語", + "KeyboardShortcuts": "キーボードショートカット", + "LogLevel": "ログレベル", + "NotificationTriggers": "通知トリガー", + "OnHealthIssueHelpText": "健康問題について", + "Priority": "優先", + "Restart": "再起動", + "RSSIsNotSupportedWithThisIndexer": "RSSはこのインデクサーではサポートされていません", + "ShowSearch": "検索を表示", + "SSLPort": "SSLポート", + "StartupDirectory": "スタートアップディレクトリ", + "TagsHelpText": "一致するタグが少なくとも1つある映画に適用されます", + "TagsSettingsSummary": "すべてのタグとその使用方法を確認してください。未使用のタグは削除できます", + "Tasks": "タスク", + "Test": "テスト", + "Title": "題名", + "UISettings": "UI設定", + "UnableToAddANewApplicationPleaseTryAgain": "新しい通知を追加できません。もう一度やり直してください。", + "UnableToLoadNotifications": "通知を読み込めません", + "UpdateCheckStartupNotWritableMessage": "スタートアップフォルダ「{0}」はユーザー「{1}」によって書き込み可能ではないため、更新をインストールできません。", + "UpdateMechanismHelpText": "Radarrの組み込みアップデーターまたはスクリプトを使用する", + "Wiki": "ウィキ", + "Yesterday": "昨日", + "ApplyTagsHelpTexts3": "削除:入力したタグを削除します", + "ApplyTagsHelpTexts4": "置換:タグを入力したタグに置き換えます(すべてのタグをクリアするには、タグを入力しないでください)", + "AreYouSureYouWantToResetYourAPIKey": "APIキーをリセットしてもよろしいですか?", + "Type": "タイプ", + "General": "一般", + "IgnoredAddresses": "無視されたアドレス", + "DeleteIndexerProxyMessageText": "タグ「{0}」を削除してもよろしいですか?", + "Edit": "編集", + "DownloadClientSettings": "クライアント設定のダウンロード", + "DownloadClientStatusCheckAllClientMessage": "障害のため、すべてのダウンロードクライアントを利用できません", + "EnableAutoHelpText": "有効にすると、映画はこのリストからRadarrに自動的に追加されます", + "EnableAutomaticAdd": "自動追加を有効にする", + "EnableAutomaticSearch": "自動検索を有効にする", + "EnableAutomaticSearchHelpText": "UIまたはRadarによって自動検索が実行されるときに使用されます", + "EnableCompletedDownloadHandlingHelpText": "完了したダウンロードをダウンロードクライアントから自動的にインポートします", + "Enabled": "有効", + "EnableInteractiveSearchHelpTextWarning": "このインデクサーでは検索はサポートされていません", + "EnableSslHelpText": " 有効にするには、管理者として実行を再開する必要があります", + "FeatureRequests": "機能リクエスト", + "Filename": "ファイル名", + "Files": "ファイル", + "Filter": "フィルタ", + "IndexerLongTermStatusCheckAllClientMessage": "6時間以上の障害のため、すべてのインデクサーが使用できなくなります", + "IndexerProxyStatusCheckAllClientMessage": "障害のため、すべてのインデクサーを使用できません", + "IndexerProxyStatusCheckSingleClientMessage": "失敗のため利用できないリスト:{0}", + "Indexers": "インデクサー", + "Languages": "言語", + "LastWriteTime": "最終書き込み時間", + "Level": "レベル", + "LogFiles": "ログファイル", + "Logging": "ロギング", + "Logs": "ログ", + "Manual": "マニュアル", + "MaximumLimits": "最大制限", + "Message": "メッセージ", + "MIA": "MIA", + "MinimumLimits": "最小制限", + "MinutesHundredTwenty": "120分:{0}", + "Pending": "保留中", + "PtpOldSettingsCheckMessage": "次のPassThePopcornインデクサーは非推奨の設定であり、更新する必要があります:{0}", + "QualityDefinitions": "品質の定義", + "QualitySettings": "品質設定", + "Refresh": "更新", + "ReleaseStatus": "リリースステータス", + "Reload": "リロード", + "RemovedFromTaskQueue": "タスクキューから削除されました", + "RemoveFilter": "フィルタを取り外します", + "RestartRequiredHelpTextWarning": "有効にするには再起動が必要です", + "SaveSettings": "設定を保存する", + "Security": "セキュリティ", + "Seeders": "シーダー", + "SendAnonymousUsageData": "匿名の使用状況データを送信する", + "SetTags": "タグを設定する", + "Settings": "設定", + "SettingsEnableColorImpairedMode": "色障害モードを有効にする", + "SettingsShortDateFormat": "短い日付形式", + "SettingsShowRelativeDates": "相対的な日付を表示する", + "Shutdown": "シャットダウン", + "Source": "ソース", + "SSLCertPasswordHelpText": "pfxファイルのパスワード", + "SSLCertPathHelpText": "pfxファイルへのパス", + "StartTypingOrSelectAPathBelow": "入力を開始するか、以下のパスを選択してください", + "Status": "状態", + "SuggestTranslationChange": "翻訳の変更を提案する", + "System": "システム", + "TableOptions": "テーブルオプション", + "TableOptionsColumnsMessage": "表示する列と表示する順序を選択します", + "TagCannotBeDeletedWhileInUse": "使用中は削除できません", + "TagIsNotUsedAndCanBeDeleted": "タグは使用されておらず、削除できます", + "TestAll": "すべてテスト", + "UnableToLoadDownloadClients": "ダウンロードクライアントを読み込めません", + "UnableToLoadGeneralSettings": "一般設定を読み込めません", + "UnableToLoadIndexers": "インデクサーを読み込めません", + "UpdateAutomaticallyHelpText": "アップデートを自動的にダウンロードしてインストールします。 System:Updatesから引き続きインストールできます。", + "Updates": "更新", + "Uptime": "稼働時間", + "Username": "ユーザー名", + "AddDownloadClient": "ダウンロードクライアントの追加", + "BackupFolderHelpText": "相対パスはRadarrのAppDataディレクトリの下にあります", + "DownloadClient": "クライアントのダウンロード", + "DownloadClientStatusCheckSingleClientMessage": "失敗のためにダウンロードできないクライアント:{0}", + "Restore": "戻す", + "DeleteIndexer": "インデクサーを削除する", + "EnableRss": "RSSを有効にする", + "EnableInteractiveSearch": "インタラクティブ検索を有効にする", + "OpenBrowserOnStart": "起動時にブラウザを開く", + "MinutesSixty": "60分:{0}", + "Mode": "モード", + "MonoVersion": "モノバージョン", + "MoreInfo": "より詳しい情報", + "Downloading": "ダウンロード", + "Usenet": "Usenet", + "ApplyTagsHelpTexts2": "追加:既存のタグリストにタグを追加します", + "Authentication": "認証", + "AuthenticationMethodHelpText": "Radarrにアクセスするにはユーザー名とパスワードが必要です", + "Automatic": "自動", + "BackupIntervalHelpText": "自動バックアップの間隔", + "BackupNow": "今すぐバックアップ", + "CertificateValidationHelpText": "HTTPS認証検証の厳密さを変更する", + "ChangeHasNotBeenSavedYet": "変更はまだ保存されていません", + "Clear": "晴れ", + "ClientPriority": "クライアントの優先順位", + "CloneIndexer": "クローンインデクサー", + "CloseCurrentModal": "現在のモーダルを閉じる", + "Columns": "列", + "Component": "成分", + "ConnectionLost": "接続切断", + "ConnectionLostAutomaticMessage": "Radarrは自動的に接続を試みます。または、下の[再読み込み]をクリックしてください。", + "Connections": "接続", + "ConnectSettings": "接続設定", + "Options": "オプション", + "IndexerStatusCheckAllClientMessage": "障害のため、すべてのインデクサーを使用できません", + "Reddit": "Reddit", + "Today": "今日", + "Tomorrow": "明日", + "Torrent": "トレント", + "UI": "UI", + "CouldNotConnectSignalR": "SignalRに接続できませんでした。UIは更新されません", + "Custom": "カスタム", + "DBMigration": "DB移行", + "DelayProfile": "遅延プロファイル", + "Delete": "削除", + "DeleteApplicationMessageText": "通知「{0}」を削除してもよろしいですか?", + "DeleteBackup": "バックアップを削除する", + "DeleteBackupMessageText": "バックアップ「{0}」を削除してもよろしいですか?", + "DeleteDownloadClient": "ダウンロードクライアントを削除する", + "DeleteDownloadClientMessageText": "ダウンロードクライアント「{0}」を削除してもよろしいですか?", + "Docker": "Docker", + "Donations": "寄付", + "DownloadClientCheckNoneAvailableMessage": "ダウンロードクライアントは利用できません", + "DownloadClientCheckUnableToCommunicateMessage": "{0}と通信できません。", + "DownloadClients": "クライアントのダウンロード", + "DownloadClientUnavailable": "ダウンロードクライアントは利用できません", + "Enable": "有効にする", + "EnableAutomaticSearchHelpTextWarning": "インタラクティブ検索を使用する場合に使用されます", + "EnableColorImpairedMode": "色障害モードを有効にする", + "Backup": "バックアップ", + "UpdateScriptPathHelpText": "抽出された更新パッケージを取得し、更新プロセスの残りを処理するカスタムスクリプトへのパス", + "LogLevelTraceHelpTextWarning": "トレースログは一時的にのみ有効にする必要があります", + "Mechanism": "機構", + "MinutesNinety": "90分:{0}", + "MovieIndexScrollBottom": "映画インデックス:下にスクロール", + "MovieIndexScrollTop": "映画インデックス:スクロールトップ", + "Movies": "映画", + "Name": "名前", + "New": "新着", + "NoLinks": "リンクなし", + "PackageVersion": "パッケージバージョン", + "PageSize": "ページサイズ", + "Password": "パスワード", + "PendingChangesStayReview": "滞在して変更を確認する", + "Port": "港", + "PortNumber": "ポート番号", + "PreferredSize": "推奨サイズ", + "Presets": "プリセット", + "PriorityHelpText": "複数のダウンロードクライアントに優先順位を付けます。ラウンドロビンは、同じ優先度のクライアントに使用されます。", + "PrioritySettings": "優先", + "Protocol": "プロトコル", + "Proxy": "プロキシ", + "ProxyBypassFilterHelpText": "'、'を区切り文字として使用し、 '*。'を使用します。サブドメインのワイルドカードとして", + "ProxyCheckBadRequestMessage": "プロキシのテストに失敗しました。 StatusCode:{0}", + "ProxyCheckFailedToTestMessage": "プロキシのテストに失敗しました:{0}", + "ProxyCheckResolveIpMessage": "構成済みプロキシホスト{0}のIPアドレスの解決に失敗しました", + "ProxyPasswordHelpText": "ユーザー名とパスワードが必要な場合にのみ入力する必要があります。それ以外の場合は空白のままにします。", + "ProxyType": "プロキシタイプ", + "RefreshMovie": "映画を更新する", + "ReleaseBranchCheckOfficialBranchMessage": "ブランチ{0}は有効なRadarrリリースブランチではありません。更新を受け取りません。", + "ResetAPIKey": "APIキーをリセット", + "RestartNow": "今すぐ再起動", + "Restrictions": "制限", + "Result": "結果", + "Retention": "保持", + "RSS": "RSS", + "Save": "保存する", + "SaveChanges": "変更内容を保存", + "Scheduled": "予定", + "ScriptPath": "スクリプトパス", + "Search": "探す", + "SelectAll": "すべて選択", + "SettingsLongDateFormat": "長い日付形式", + "SettingsShowRelativeDatesHelpText": "相対(今日/昨日など)または絶対日付を表示する", + "ShownClickToHide": "表示、クリックして非表示", + "ShowSearchHelpText": "ホバー時に検索ボタンを表示する", + "Size": "サイズ", + "Sort": "ソート", + "SSLCertPath": "SSL証明書パス", + "SystemTimeCheckMessage": "システム時刻が1日以上ずれています。スケジュールされたタスクは、時間が修正されるまで正しく実行されない場合があります", + "Tags": "タグ", + "TestAllClients": "すべてのクライアントをテストする", + "Torrents": "トレント", + "UILanguage": "UI言語", + "UILanguageHelpText": "RadarrがUIに使用する言語", + "UILanguageHelpTextWarning": "ブラウザのリロードが必要", + "UnableToAddANewAppProfilePleaseTryAgain": "新しい品質プロファイルを追加できません。再試行してください。", + "UnableToAddANewDownloadClientPleaseTryAgain": "新しいダウンロードクライアントを追加できません。もう一度やり直してください。", + "UnableToAddANewIndexerPleaseTryAgain": "新しいインデクサーを追加できません。もう一度やり直してください。", + "UnableToAddANewNotificationPleaseTryAgain": "新しい通知を追加できません。もう一度やり直してください。", + "UnableToLoadBackups": "バックアップを読み込めません", + "UnableToLoadHistory": "履歴を読み込めません", + "UnableToLoadQualityDefinitions": "品質定義を読み込めません", + "UnableToLoadTags": "タグを読み込めません", + "UnableToLoadUISettings": "UI設定を読み込めません", + "UnsavedChanges": "保存されていない変更", + "UnselectAll": "すべて選択解除", + "BackupRetentionHelpText": "保存期間より古い自動バックアップは自動的にクリーンアップされます", + "Backups": "バックアップ", + "CertificateValidation": "証明書の検証", + "UpdateCheckStartupTranslocationMessage": "スタートアップフォルダー '{0}'がAppTranslocationフォルダーにあるため、更新をインストールできません。", + "UpdateCheckUINotWritableMessage": "UIフォルダー「{0}」はユーザー「{1}」によって書き込み可能ではないため、更新をインストールできません。", + "URLBase": "URLベース", + "UrlBaseHelpText": "リバースプロキシサポートの場合、デフォルトは空です", + "UseProxy": "プロキシを使う", + "Version": "バージョン", + "Warn": "警告", + "YesCancel": "はい、キャンセル", + "CustomFilters": "カスタムフィルター", + "Date": "日付", + "Dates": "日付", + "SSLCertPassword": "SSL証明書のパスワード", + "About": "約", + "AcceptConfirmationModal": "確認モーダルを受け入れる", + "Actions": "行動", + "Added": "追加", + "AddIndexer": "インデクサーを追加", + "AddingTag": "タグの追加", + "Age": "年齢", + "All": "すべて", + "AllIndexersHiddenDueToFilter": "フィルタが適用されているため、すべてのムービーが非表示になっています。", + "Analytics": "分析", + "AnalyticsEnabledHelpText": "匿名の使用状況とエラー情報をRadarrのサーバーに送信します。これには、使用するRadarr WebUIページ、エラーレポート、OSおよびランタイムバージョンなどのブラウザに関する情報が含まれます。この情報を使用して、機能とバグ修正に優先順位を付けます。", + "ApiKey": "APIキー", + "AppDataDirectory": "AppDataディレクトリ", + "AppDataLocationHealthCheckMessage": "更新時にAppDataが削除されないように更新することはできません", + "ApplicationStatusCheckAllClientMessage": "障害のため、すべてのリストを利用できません", + "ApplicationStatusCheckSingleClientMessage": "失敗のため利用できないリスト:{0}", + "Apply": "適用する", + "ApplyTags": "タグを適用する", + "GeneralSettings": "一般設定", + "Grabbed": "掴んだ", + "Health": "健康", + "HealthNoIssues": "構成に問題はありません", + "HideAdvanced": "高度な非表示", + "EnabledHelpText": "Radarrで使用するためにこのリストを有効にします", + "EnableHelpText": "このメタデータタイプのメタデータファイルの作成を有効にする", + "EnableInteractiveSearchHelpText": "インタラクティブ検索を使用する場合に使用されます", + "MonoVersionCheckUpgradeRecommendedMessage": "現在インストールされているMonoバージョン{0}がサポートされていますが、{1}にアップグレードすることをお勧めします。", + "EnableMediaInfoHelpText": "ファイルから解像度、ランタイム、コーデック情報などのビデオ情報を抽出します。これには、Radarrがファイルの一部を読み取る必要があり、スキャン中にディスクまたはネットワークのアクティビティが高くなる可能性があります。", + "Error": "エラー", + "ErrorLoadingContents": "コンテンツの読み込み中にエラーが発生しました", + "Events": "イベント", + "EventType": "イベントタイプ", + "Exception": "例外", + "Fixed": "修繕", + "LaunchBrowserHelpText": " Webブラウザーを開き、アプリの起動時にRadarrホームページに移動します。", + "PageSizeHelpText": "各ページに表示するアイテムの数", + "Peers": "ピア", + "PendingChangesDiscardChanges": "変更を破棄してそのままにします", + "PendingChangesMessage": "保存されていない変更があります。このページを離れてもよろしいですか?", + "Style": "スタイル", + "UnableToAddANewIndexerProxyPleaseTryAgain": "新しいインデクサーを追加できません。もう一度やり直してください。", + "IncludeHealthWarningsHelpText": "健康上の警告を含める", + "NoBackupsAreAvailable": "バックアップは利用できません", + "NoChange": "変化なし", + "Queue": "キュー", + "RestoreBackup": "バックアップを復元", + "BeforeUpdate": "更新前", + "BindAddress": "バインドアドレス", + "BindAddressHelpText": "すべてのインターフェースに有効なIP4アドレスまたは「*」", + "Branch": "ブランチ", + "BranchUpdate": "Radarrの更新に使用するブランチ", + "BranchUpdateMechanism": "外部更新メカニズムで使用されるブランチ", + "BypassProxyForLocalAddresses": "ローカルアドレスのプロキシをバイパスする", + "Cancel": "キャンセル", + "CancelPendingTask": "この保留中のタスクをキャンセルしてもよろしいですか?", + "DeleteIndexerMessageText": "インデクサー「{0}」を削除してもよろしいですか?", + "DeleteNotification": "通知を削除", + "DeleteNotificationMessageText": "通知「{0}」を削除してもよろしいですか?", + "DeleteTag": "タグを削除", + "DeleteTagMessageText": "タグ「{0}」を削除してもよろしいですか?", + "Details": "詳細", + "Disabled": "無効", + "Discord": "不和", + "IndexerPriority": "インデクサの優先順位", + "IndexerPriorityHelpText": "インデクサーの優先度は1(最高)から50(最低)です。デフォルト:25。", + "MonoTlsCheckMessage": "Radarr Mono 4.x tlsの回避策は引き続き有効です。MONO_TLS_PROVIDER=レガシー環境オプションを削除することを検討してください", + "EnableColorImpairedModeHelpText": "色が損なわれたユーザーが色分けされた情報をよりよく区別できるようにスタイルを変更", + "EnableSSL": "SSLを有効にする", + "FocusSearchBox": "フォーカス検索ボックス", + "Folder": "フォルダ", + "ForMoreInformationOnTheIndividualDownloadClients": "個々のダウンロードクライアントの詳細については、情報ボタンをクリックしてください。", + "GeneralSettingsSummary": "ポート、SSL、ユーザー名/パスワード、プロキシ、分析、更新", + "Grabs": "つかむ", + "HiddenClickToShow": "非表示、クリックして表示", + "History": "歴史", + "HomePage": "ホームページ", + "Host": "ホスト", + "Hostname": "ホスト名", + "IllRestartLater": "後で再起動します", + "Importing": "インポート", + "IndexerLongTermStatusCheckSingleClientMessage": "6時間以上の障害のため、インデクサーを使用できません:{0}", + "IndexerStatusCheckSingleClientMessage": "失敗のためインデクサーを利用できません:{0}", + "Info": "情報", + "NoLogFiles": "ログファイルがありません", + "NoMinimumForAnyRuntime": "ランタイムの最小値はありません", + "NoTagsHaveBeenAddedYet": "タグはまだ追加されていません", + "ProxyUsernameHelpText": "ユーザー名とパスワードが必要な場合にのみ入力する必要があります。それ以外の場合は空白のままにします。", + "ReadTheWikiForMoreInformation": "詳細については、Wikiをお読みください", + "SettingsEnableColorImpairedModeHelpText": "色が損なわれたユーザーが色分けされた情報をよりよく区別できるようにスタイルを変更" +} diff --git a/src/NzbDrone.Core/Localization/Core/ko.json b/src/NzbDrone.Core/Localization/Core/ko.json index 8ab7b76e1..295fd9497 100644 --- a/src/NzbDrone.Core/Localization/Core/ko.json +++ b/src/NzbDrone.Core/Localization/Core/ko.json @@ -77,5 +77,192 @@ "DeleteNotification": "알림 삭제", "DeleteNotificationMessageText": "알림 '{0}'을(를) 삭제하시겠습니까?", "DownloadClientCheckUnableToCommunicateMessage": "{0}와(과) 통신할 수 없습니다.", - "DownloadClientStatusCheckSingleClientMessage": "실패로 인해 다운 불러올 수 없는 클라이언트 : {0}" + "DownloadClientStatusCheckSingleClientMessage": "실패로 인해 다운 불러올 수 없는 클라이언트 : {0}", + "MoreInfo": "더 많은 정보", + "Edit": "편집하다", + "Indexer": "인덱서", + "MinutesSixty": "60 분 : {0}", + "MinutesNinety": "60 분 : {0}", + "Name": "이름", + "New": "새로운", + "ProxyUsernameHelpText": "필요한 경우 사용자 이름과 암호 만 입력하면됩니다. 그렇지 않으면 공백으로 두십시오.", + "QualityDefinitions": "품질 정의", + "RestartRequiredHelpTextWarning": "적용하려면 다시 시작해야합니다.", + "SaveChanges": "변경 사항을 저장하다", + "Settings": "설정", + "SettingsLongDateFormat": "긴 날짜 형식", + "SSLCertPassword": "SSL 인증서 비밀번호", + "TagIsNotUsedAndCanBeDeleted": "태그는 사용되지 않으며 삭제할 수 있습니다.", + "Tags": "태그", + "UISettings": "UI 설정", + "UnableToAddANewApplicationPleaseTryAgain": "새 알림을 추가 할 수 없습니다. 다시 시도하십시오.", + "UnableToAddANewAppProfilePleaseTryAgain": "새 품질 프로필을 추가 할 수 없습니다. 다시 시도하십시오.", + "UnableToAddANewDownloadClientPleaseTryAgain": "새 다운로드 클라이언트를 추가 할 수 없습니다. 다시 시도하십시오.", + "UnableToAddANewIndexerPleaseTryAgain": "새 인덱서를 추가 할 수 없습니다. 다시 시도하십시오.", + "UnableToLoadBackups": "백업을로드 할 수 없습니다.", + "UpdateAutomaticallyHelpText": "업데이트를 자동으로 다운로드하고 설치합니다. 시스템 : 업데이트에서 계속 설치할 수 있습니다.", + "RemoveFilter": "필터 제거", + "Size": "크기", + "AllIndexersHiddenDueToFilter": "적용된 필터로 인해 모든 영화가 숨겨집니다.", + "Reset": "초기화", + "Enable": "활성화", + "Enabled": "활성화", + "EnableInteractiveSearchHelpText": "대화 형 검색을 사용할 때 사용됩니다.", + "EnableRss": "RSS 활성화", + "Fixed": "결정된", + "HiddenClickToShow": "숨김, 클릭하여 표시", + "Host": "주최자", + "Port": "포트", + "Protocol": "실험 계획안", + "Proxy": "대리", + "ProxyBypassFilterHelpText": "','를 구분 기호로 사용하고 '*'를 사용하십시오. 하위 도메인에 대한 와일드 카드로", + "ProxyPasswordHelpText": "필요한 경우 사용자 이름과 암호 만 입력하면됩니다. 그렇지 않으면 공백으로 두십시오.", + "ProxyType": "프록시 유형", + "ReadTheWikiForMoreInformation": "자세한 내용은 Wiki를 참조하십시오.", + "Tomorrow": "내일", + "UI": "UI", + "UnableToLoadIndexers": "인덱서를로드 할 수 없습니다.", + "Updates": "업데이트", + "Uptime": "가동 시간", + "YesCancel": "예, 취소합니다", + "Folder": "폴더", + "ConnectionLostMessage": "Radarr는 백엔드와의 연결이 끊어졌으며 기능을 복원하려면 다시 로딩해야 합니다.", + "EnableAutomaticAdd": "자동 추가 활성화", + "EnableAutomaticSearch": "자동 검색 활성화", + "EnableAutomaticSearchHelpText": "UI 또는 Radarr를 통해 자동 검색을 수행 할 때 사용됩니다.", + "ErrorLoadingContents": "콘텐츠로드 오류", + "Grabs": "붙잡다", + "Torrent": "급류", + "Torrents": "급류", + "Type": "유형", + "ApplyTagsHelpTexts2": "추가 : 기존 태그 목록에 태그를 추가합니다.", + "DeleteApplicationMessageText": "알림 '{0}'을(를) 삭제하시겠습니까?", + "ApplyTagsHelpTexts1": "선택한 동영상에 태그를 적용하는 방법", + "AuthenticationMethodHelpText": "Radarr에 액세스하려면 사용자 이름 및 암호 필요", + "BackupFolderHelpText": "상대 경로는 Radarr의 AppData 디렉토리에 있습니다.", + "Branch": "분기", + "BranchUpdate": "Radarr 업데이트에 사용할 분기", + "DeleteIndexerProxyMessageText": "'{0}' 태그를 삭제하시겠습니까?", + "EnableCompletedDownloadHandlingHelpText": "다운로드 클라이언트에서 완료된 다운로드를 자동으로 가져 오기", + "EnableHelpText": "이 메타 데이터 유형에 대한 메타 데이터 파일 생성 활성화", + "EnableInteractiveSearch": "대화 형 검색 활성화", + "EnableInteractiveSearchHelpTextWarning": "이 인덱서에서는 검색이 지원되지 않습니다.", + "EnableSSL": "SSL 활성화", + "EnableSslHelpText": " 적용하려면 관리자로 실행을 다시 시작해야합니다.", + "History": "역사", + "Indexers": "인덱서", + "Refresh": "새롭게 하다", + "Mode": "방법", + "TagCannotBeDeletedWhileInUse": "사용 중에는 삭제할 수 없습니다.", + "NoLimitForAnyRuntime": "런타임 제한 없음", + "NoMinimumForAnyRuntime": "런타임에 대한 최소값 없음", + "NoUpdatesAreAvailable": "사용 가능한 업데이트가 없습니다.", + "OnHealthIssueHelpText": "건강 문제", + "OpenBrowserOnStart": "시작시 브라우저 열기", + "QualitySettings": "품질 설정", + "Reload": "새로 고침", + "RemovedFromTaskQueue": "작업 대기열에서 제거됨", + "ResetAPIKey": "API 키 재설정", + "Restart": "재시작", + "RestartNow": "지금 다시 시작", + "Restore": "복원", + "Result": "결과", + "Retention": "보유", + "RSSIsNotSupportedWithThisIndexer": "이 인덱서에서는 RSS가 지원되지 않습니다.", + "Scheduled": "예정", + "ScriptPath": "스크립트 경로", + "Search": "검색", + "Security": "보안", + "SendAnonymousUsageData": "익명 사용 데이터 보내기", + "Source": "출처", + "SSLCertPasswordHelpText": "pfx 파일의 비밀번호", + "SSLCertPath": "SSL 인증서 경로", + "SSLCertPathHelpText": "pfx 파일 경로", + "StartTypingOrSelectAPathBelow": "입력을 시작하거나 아래 경로를 선택하세요.", + "Status": "상태", + "Style": "스타일", + "Tasks": "과제", + "TestAllClients": "모든 클라이언트 테스트", + "Title": "표제", + "Today": "오늘", + "UILanguageHelpTextWarning": "브라우저 새로 고침 필요", + "UnableToLoadDownloadClients": "다운로드 클라이언트를로드 할 수 없습니다.", + "UnableToLoadHistory": "기록을로드 할 수 없습니다.", + "UnableToLoadQualityDefinitions": "품질 정의를로드 할 수 없습니다.", + "UnableToLoadTags": "태그를로드 할 수 없습니다.", + "UnableToLoadUISettings": "UI 설정을로드 할 수 없습니다.", + "ConnectionLostAutomaticMessage": "Radarr가 자동으로 연결을 시도하거나 아래에서 새로고침을 클릭할 수 있습니다.", + "RemovingTag": "태그 제거", + "IndexerPriority": "인덱서 우선 순위", + "Language": "언어", + "Languages": "언어", + "LaunchBrowserHelpText": " 웹 브라우저를 열고 앱 시작시 Radarr 홈페이지로 이동합니다.", + "SSLPort": "SSL 포트", + "StartupDirectory": "시작 디렉토리", + "LogFiles": "로그 파일", + "Logging": "벌채 반출", + "MonoVersion": "모노 버전", + "NoLogFiles": "로그 파일 없음", + "NotificationTriggers": "알림 트리거", + "PackageVersion": "패키지 버전", + "PageSizeHelpText": "각 페이지에 표시 할 항목 수", + "PortNumber": "포트 번호", + "Queue": "열", + "RestoreBackup": "백업 복원", + "SettingsEnableColorImpairedMode": "색 장애 모드 활성화", + "SettingsEnableColorImpairedModeHelpText": "색상 장애가있는 사용자가 색상 코드 정보를 더 잘 구별 할 수 있도록 스타일 변경", + "ShowSearchHelpText": "마우스 오버시 검색 버튼 표시", + "UnableToAddANewIndexerProxyPleaseTryAgain": "새 인덱서를 추가 할 수 없습니다. 다시 시도하십시오.", + "UnableToAddANewNotificationPleaseTryAgain": "새 알림을 추가 할 수 없습니다. 다시 시도하십시오.", + "UnableToLoadGeneralSettings": "일반 설정을로드 할 수 없습니다.", + "UnableToLoadNotifications": "알림을로드 할 수 없습니다.", + "UpdateMechanismHelpText": "Radarr의 내장 업데이트 프로그램 또는 스크립트 사용", + "UpdateScriptPathHelpText": "추출 된 업데이트 패키지를 사용하고 나머지 업데이트 프로세스를 처리하는 사용자 지정 스크립트에 대한 경로", + "URLBase": "URL베이스", + "Usenet": "유즈넷", + "UseProxy": "프록시 사용", + "Username": "사용자 이름", + "Version": "버전", + "EnableAutomaticSearchHelpTextWarning": "대화 형 검색을 사용할 때 사용됩니다.", + "EnableColorImpairedMode": "색 장애 모드 활성화", + "EnableColorImpairedModeHelpText": "색상 장애가있는 사용자가 색상 코드 정보를 더 잘 구별 할 수 있도록 스타일 변경", + "Exception": "예외", + "ExistingTag": "기존 태그", + "Files": "파일", + "IgnoredAddresses": "무시 된 주소", + "IllRestartLater": "나중에 다시 시작하겠습니다", + "Importing": "가져 오기", + "IncludeHealthWarningsHelpText": "건강 경고 포함", + "LogLevel": "로그 수준", + "LogLevelTraceHelpTextWarning": "추적 로깅은 일시적으로 만 활성화해야합니다.", + "MaximumLimits": "최대 한도", + "Mechanism": "기구", + "MIA": "MIA", + "MinimumLimits": "최소 한도", + "MinutesHundredTwenty": "120 분 : {0}", + "PageSize": "페이지 크기", + "Password": "암호", + "TestAll": "모두 테스트", + "Options": "옵션", + "SettingsTimeFormat": "시간 형식", + "AnalyticsEnabledHelpText": "익명의 사용 및 오류 정보를 Radarr의 서버에 보냅니다. 여기에는 브라우저에 대한 정보, 사용하는 Radarr WebUI 페이지, 오류보고, OS 및 런타임 버전이 포함됩니다. 이 정보를 사용하여 기능 및 버그 수정의 우선 순위를 지정합니다.", + "Filename": "파일 이름", + "ForMoreInformationOnTheIndividualDownloadClients": "개별 다운로드 클라이언트에 대한 자세한 내용을 보려면 정보 버튼을 클릭하십시오.", + "GeneralSettings": "일반 설정", + "Hostname": "호스트 이름", + "IndexerPriorityHelpText": "인덱서 우선 순위는 1 (가장 높음)에서 50 (가장 낮음)까지입니다. 기본값 : 25.", + "Interval": "간격", + "Logs": "로그", + "Message": "메시지", + "NoBackupsAreAvailable": "사용 가능한 백업이 없습니다.", + "NoChange": "변경 사항 없음", + "NoChanges": "변경 사항 없음", + "NoLeaveIt": "아니, 놔둬", + "SettingsShortDateFormat": "짧은 날짜 형식", + "SettingsShowRelativeDates": "상대 날짜 표시", + "SettingsShowRelativeDatesHelpText": "상대 (오늘 / 어제 / 기타) 또는 절대 날짜 표시", + "ShownClickToHide": "표시됨, 숨기려면 클릭", + "ShowSearch": "검색 표시", + "UILanguage": "UI 언어", + "UILanguageHelpText": "Radarr가 UI에 사용할 언어" } diff --git a/src/NzbDrone.Core/Localization/Core/nb_NO.json b/src/NzbDrone.Core/Localization/Core/nb_NO.json index f79e611da..5f720b635 100644 --- a/src/NzbDrone.Core/Localization/Core/nb_NO.json +++ b/src/NzbDrone.Core/Localization/Core/nb_NO.json @@ -39,5 +39,19 @@ "BranchUpdateMechanism": "Gren brukt av ekstern oppdateringsmekanisme", "BypassProxyForLocalAddresses": "Omgå proxy for lokale adresser", "CancelPendingTask": "Er du sikker på at du vil avbryte denne ventende oppgaven?", - "CertificateValidationHelpText": "Endre hvor streng HTTPS -sertifisering validering er" + "CertificateValidationHelpText": "Endre hvor streng HTTPS -sertifisering validering er", + "ApplyTagsHelpTexts1": "Slik bruker du tagger på de valgte filmene", + "DeleteBackupMessageText": "Er du sikker på at du vil slette formattaggen {0}?", + "AllIndexersHiddenDueToFilter": "Alle filmer er skjult på grunn av påført filter.", + "AnalyticsEnabledHelpText": "Send anonym bruk og feilinformasjon til Radarrs servere. Dette inkluderer informasjon om nettleseren din, hvilke Radarr WebUI -sider du bruker, feilrapportering samt OS og kjøretidsversjon. Vi vil bruke denne informasjonen til å prioritere funksjoner og feilrettinger.", + "ApplyTagsHelpTexts2": "Legg til: Legg til taggene i den eksisterende listen med tagger", + "AuthenticationMethodHelpText": "Krev brukernavn og passord for å få tilgang til Radarr", + "BackupFolderHelpText": "Relative stier vil være under Radarr's AppData -katalog", + "BranchUpdate": "Gren som skal brukes til å oppdatere Radarr", + "DeleteApplicationMessageText": "Er du sikker på at du vil slette formattaggen {0}?", + "DeleteDownloadClientMessageText": "Er du sikker på at du vil slette formattaggen {0}?", + "DeleteIndexerMessageText": "Er du sikker på at du vil slette formattaggen {0}?", + "DeleteIndexerProxyMessageText": "Er du sikker på at du vil slette formattaggen {0}?", + "DeleteNotificationMessageText": "Er du sikker på at du vil slette formattaggen {0}?", + "DeleteTagMessageText": "Er du sikker på at du vil slette formattaggen {0}?" } diff --git a/src/NzbDrone.Core/Localization/Core/nl.json b/src/NzbDrone.Core/Localization/Core/nl.json index 9074fb5c4..d7aed77f1 100644 --- a/src/NzbDrone.Core/Localization/Core/nl.json +++ b/src/NzbDrone.Core/Localization/Core/nl.json @@ -1,6 +1,5 @@ { "Indexers": "Indexeerders", - "ImportSecondTip": "Wijs Prowlarr naar de map die al je films bevat, niet naar een map met slechts één specifieke film. Bijv.", "ImportFirstTip": "Zorg ervoor dat je bestanden de kwaliteit in hun bestandsnaam bevatten. Bijv.", "Host": "Host", "History": "Geschiedenis", @@ -17,7 +16,6 @@ "DownloadClients": "Downloaders", "DownloadClientCheckUnableToCommunicateMessage": "Niet in staat om te communiceren met {0}.", "DownloadClientCheckNoneAvailableMessage": "Er is geen downloader beschikbaar", - "Discover": "Ontdekken", "Delete": "Verwijderen", "Dates": "Datum en tijd", "Date": "Datum", @@ -25,13 +23,11 @@ "Connections": "Connecties", "Connect": "Meldingen", "Clear": "Wissen", - "Blacklist": "Zwarte lijst", "BackupNow": "Veiligheidskopie Maken", "Analytics": "Statistieken", "Backup": "Veiligheidskopie", "AppDataLocationHealthCheckMessage": "Bijwerken zal niet mogelijk zijn om het verwijderen van AppData te voorkomen", "All": "Alles", - "AddExclusion": "Uitzondering(en) Toevoegen", "About": "Over", "View": "Weergave", "UnselectAll": "Alles Deselecteren", @@ -43,7 +39,6 @@ "Settings": "Instellingen", "SelectAll": "Alles Selecteren", "Security": "Beveiliging", - "SearchAll": "Alles Zoeken", "Search": "Zoeken", "Scheduled": "Gepland", "SaveChanges": "Wijzigingen Opslaan", @@ -57,10 +52,8 @@ "NoChanges": "Geen Wijzigingen", "NoChange": "Geen Wijziging", "Movies": "Films", - "Movie": "Film", "MoreInfo": "Meer Info", "MonoNotNetCoreCheckMessage": "Gelieve te opwaarderen naar de .NET Core versie van Prowlarr", - "MinAvailability": "Min Beschikbaarheid", "ManualImport": "Manuele Import", "Logging": "Logbeheer", "LogFiles": "Logbestanden", @@ -88,7 +81,6 @@ "Size": "Grootte", "ReleaseStatus": "Uitgave Status", "Protocol": "Protocol", - "OutputPath": "Uitvoer Pad", "MediaManagementSettingsSummary": "Naamgeving en bestandsbeheer instellingen", "LastWriteTime": "Laatste Modificatietijd", "Indexer": "Indexeerder", @@ -120,7 +112,6 @@ "Restart": "Herstart", "Reload": "Herlaad", "PageSize": "Pagina Grootte", - "OrganizeModalAllPathsRelative": "Alle paden zijn relatief t.o.v.:", "Ok": "Ok", "OAuthPopupMessage": "Pop-ups worden geblokkeerd door uw browser", "Name": "Naam", @@ -139,29 +130,22 @@ "Cancel": "Annuleer", "Apply": "Toepassen", "Age": "Leeftijd", - "Posters": "Affiches", "UnsavedChanges": "Onopgeslagen Wijzigingen", - "ShowSizeOnDisk": "Toon Grootte op Schijf", "ShowSearchHelpText": "Toon zoeken knop bij zweven", "ShowSearch": "Toon Zoeken", - "ShowDateAdded": "Toon Datum Toegevoegd", "SettingsUiLanguage": "Gebruikersinterface Taal", "SettingsTimeFormat": "Tijdsformaat", "SettingsShowRelativeDatesHelpText": "Toon relatieve (Vandaag/Gisteren/enz.) of absolute datums", "SettingsShowRelativeDates": "Toon Relatieve Datums", "SettingsShortDateFormat": "Korte Datumnotatie", - "SettingsRemotePathMappingLocalPath": "Lokaal Pad", "SettingsLongDateFormat": "Lange Datumnotatie", "SettingsEnableColorImpairedModeHelpText": "Aangepaste stijl voor gebruikers die kleurenblind zijn om gemakkelijker kleurgecodeerde informatie te onderscheiden", "SettingsEnableColorImpairedMode": "Activeer Kleurenblindheid-modus", - "RecentFolders": "Recente Mappen", "PendingChangesStayReview": "Blijf en bekijk de wijzigingen", "PendingChangesMessage": "U heeft onopgeslagen wijzigingen, bent u zeker dat u deze pagina wilt sluiten?", "PendingChangesDiscardChanges": "Wijzigingen verwerpen en verdergaan", "MonoVersionCheckUpgradeRecommendedMessage": "De huidige geïnstalleerde Mono versie {0} wordt ondersteund, maar het is aangeraden om te opwaarderen naar versie {1}.", - "InteractiveImport": "Interactieve Import", "ExistingMovies": "Bestaande Film(s)", - "DetailedProgressBar": "Gedetailleerde voortgangsbalk", "Interval": "Tussentijd", "Fixed": "Opgelost", "Automatic": "Automatisch", @@ -169,20 +153,16 @@ "Authentication": "Authenticatie", "AppDataDirectory": "AppData map", "AnalyticsEnabledHelpText": "Stuur anonieme gebruiks- en foutinformatie naar de servers van Prowlarr. Dit omvat informatie over uw browser, welke Prowlarr WebUI pagina's u gebruikt, foutrapportage en OS en runtime versie. We zullen deze informatie gebruiken om prioriteiten te stellen voor functies en het verhelpen van fouten.", - "AllowHardcodedSubs": "Sta Ingebrande Ondertiteling Toe", "YesCancel": "Ja, Annuleren", - "CleanLibraryLevel": "Bibliotheek Opschonen Niveau", "DeleteTag": "Verwijder Tag", "DeleteNotification": "Verwijder Notificatie", "DeleteIndexer": "Verwijder Indexeerder", "DeleteDownloadClient": "Verwijder Downloader", "Enable": "Activeer", - "DownloadPropers": "Download PROPERS", "DownloadClientSettings": "Downloader Instellingen", "Docker": "Docker", "DelayProfile": "Vertragingsprofiel", "DBMigration": "DB Migratie", - "CreateGroup": "Groep aanmaken", "ConnectSettings": "Connecties Instellingen", "CloneProfile": "Dupliceer Profiel", "CloneIndexer": "Dupliceer Indexeerder", @@ -198,17 +178,14 @@ "Backups": "Veiligheidskopieën", "BackupRetentionHelpText": "Automatische veiligheidskopieën ouder dan de retentie periode zullen worden opgeruimd", "BackupFolderHelpText": "Relatieve paden zullen t.o.v. de Prowlarr AppData map bekeken worden", - "AutoRedownloadFailedHelpText": "Automatisch zoeken en probeer een andere release te downloaden", "AreYouSureYouWantToResetYourAPIKey": "Bent u zeker dat u uw API-sleutel wilt resetten?", "ApplyTags": "Tags Toepassen", "ApiKey": "API-sleutel", "Importing": "Importeren", "IllRestartLater": "Ik zal later herstarten", - "IgnoreDeletedMovies": "Negeer Verwijderde Films", "IgnoredAddresses": "Genegeerde Adressen", "Hostname": "Hostnaam", "GeneralSettings": "Algemene Instellingen", - "FileNames": "Bestandsnamen", "EnableSSL": "Activeer SSL", "EnableInteractiveSearch": "Activeer Interactief Zoeken", "EnableHelpText": "Schakel het maken van metadata bestanden in voor dit metadata type", @@ -219,7 +196,6 @@ "EnableAutomaticSearch": "Activeer Automatisch Zoeken", "EnableAutomaticAdd": "Activeer Automatisch Toevoegen", "EnableAutoHelpText": "Indien ingeschakeld, zullen films automatisch aan Prowlarr worden toegevoegd van deze lijst", - "CopyUsingHardlinksHelpText": "Gebruik hardlinks bij het kopiëren van torrent bestanden die nog actief zijn", "PortNumber": "Poort Nummer", "Port": "Poort", "Password": "Wachtwoord", @@ -227,27 +203,21 @@ "OnHealthIssueHelpText": "Bij Gezondheidsprobleem", "NoLeaveIt": "Nee, Ongemoeid Laten", "New": "Nieuw", - "MovieYear": "Film Jaar", "MovieFolderFormat": "Film Map Formaat", "MonoVersion": "Mono Versie", "Mode": "Modus", "MinimumLimits": "Minimum Limieten", - "MediaManagementSettings": "Mediabeheer Instellingen", "Mechanism": "Mechanisme", "MaximumLimits": "Maximum Limiet", "Logs": "Logbestanden", "LogLevel": "Log Niveau", - "Links": "Koppelingen", "EnableMediaInfoHelpText": "Video informatie extraheren zoals resolutie, speelduur en codec informatie van bestanden. Dit maakt het noodzakelijk dat Prowlarr delen van een bestand moet inlezen dewelke hoge schijf- of netwerkactiviteit kan veroorzaken tijdens het scannen.", "BindAddress": "Aanhaak Adres", - "IndexerSettings": "Indexeerder Instellingen", "IndexerFlags": "Indexeerder Flags", "EnableSslHelpText": " Vereist herstart als administrator om in werking te treden", "PriorityHelpText": "Geef prioriteit aan meerdere downloaders. Round-Robin wordt gebruikt voor downloaders met dezelfde prioriteit.", - "RemoveCompletedDownloadsHelpText": "Verwijder geïmporteerde downloads uit de downloader geschiedenis", "RssSyncIntervalHelpTextWarning": "Dit zal van toepassing zijn op alle indexeerders, gelieve de door hen opgelegde regels te volgen", "SendAnonymousUsageData": "Zend Anonieme Gebruiksdata", - "SkipFreeSpaceCheckWhenImportingHelpText": "Gebruik dit wanneer Prowlarr geen vrije schijfruimte kan detecteren voor de hoofdmap van je films", "TorrentDelayHelpText": "Wachttijd in minuten alvorens een torrent op te halen", "UnableToLoadIndexers": "Indexeerders kunnen niet worden geladen", "UnableToLoadNotifications": "Notificaties kunnen niet worden geladen", @@ -256,7 +226,6 @@ "IncludeHealthWarningsHelpText": "Voeg Gezondheidswaarschuwingen Toe", "LaunchBrowserHelpText": " Open een web browser en navigeer naar de Prowlarr startpagina bij het starten van de app.", "MIA": "MIA", - "MovieTitleHelpText": "De titel van de uit te sluiten film (kan van alles zijn)", "NotificationTriggers": "Melding Reactiestarters", "OpenBrowserOnStart": "Open de browser bij het starten", "PageSizeHelpText": "Aantal items om te tonen op iedere pagina", @@ -268,14 +237,11 @@ "ProxyUsernameHelpText": "Je moet alleen een gebruikersnaam en wachtwoord ingeven als dit vereist is, laat ze anders leeg.", "QualitySettings": "Kwaliteitsinstellingen", "ReadTheWikiForMoreInformation": "Lees de Wiki voor meer informatie", - "RecyclingBin": "Prullenbak", "RefreshMovie": "Film vernieuwen", "ProxyType": "Proxy Type", "ProxyBypassFilterHelpText": "Gebruik ',' als scheidingsteken en '*' als wildcard voor subdomeinen", - "ReleaseRejected": "Uitgave Afgekeurd", "RemovedFromTaskQueue": "Verwijderd uit taken wachtrij", "RemoveFilter": "Verwijder filter", - "RenameMovies": "Hernoem Films", "RequiredHelpText": "Deze {0} conditie moet overeenstemmen om het eigen formaat te kunnen toepassen. Anders is een enkele {1} overeenstemming voldoende.", "Reset": "Reset", "RestartNow": "Herstart Nu", @@ -285,9 +251,7 @@ "Retention": "Retentie", "ScriptPath": "Script Pad", "ResetAPIKey": "Reset API-sleutel", - "ShowAsAllDayEvents": "Weergeven als evenementen die de hele dag duren", "ShowQualityProfileHelpText": "Toon kwaliteitsprofiel onder poster", - "SourceRelativePath": "Relatief Bron Pad", "SSLCertPassword": "SSL Certificaat Wachtwoord", "SSLCertPath": "SSL Certificaat Pad", "SSLPort": "SSL Poort", @@ -295,7 +259,6 @@ "SuggestTranslationChange": "Stel vertaling voor", "TagsHelpText": "Is van toepassing op films met minstens één overeenkomende tag", "TestAllClients": "Test Alle Downloaders", - "TmdbIdHelpText": "De TMDb Id van de uit te sluiten film", "Torrents": "Torrents", "UISettings": "Gebruikersinterface Instellingen", "UnableToLoadDownloadClients": "Downloaders kunnen niet worden geladen", @@ -309,20 +272,16 @@ "UseProxy": "Gebruik Proxy", "Username": "Gebruikersnaam", "Version": "Versie", - "SettingsRuntimeFormat": "Speelduur Formaat", "TagCannotBeDeletedWhileInUse": "Kan niet verwijderd worden terwijl in gebruik", "SSLCertPathHelpText": "Pad naar pfx bestand", "SSLCertPasswordHelpText": "Wachtwoord voor pfx bestand", "ShownClickToHide": "Getoond, klik om te verbergen", - "RSSSyncIntervalHelpTextWarning": "Dit zal van toepassing zijn op alle indexeerders, gelieve de door hen opgelegde regels te volgen", "RSSIsNotSupportedWithThisIndexer": "RSS wordt niet ondersteund door deze indexeerder", "RemovingTag": "Tag verwijderen", "Pending": "In afwachting", - "MovieIsUnmonitored": "Film wordt niet bewaakt", "MovieAlreadyExcluded": "Film werd al Uitgesloten", "Manual": "Manueel", "LogLevelTraceHelpTextWarning": "Trace log niveau moet enkel tijdelijk worden gebruikt", - "ImportFailedInterp": "Importeren mislukt: {0}", "HiddenClickToShow": "Verborgen, klik om te tonen", "ExistingTag": "Bestaande tag", "EnableInteractiveSearchHelpTextWarning": "Zoeken wordt niet ondersteund door deze indexeerder", @@ -336,26 +295,21 @@ "DeleteIndexerMessageText": "Bent u zeker dat u de indexeerder '{0}' wilt verwijderen?", "DeleteDownloadClientMessageText": "Bent u zeker dat u de downloader '{0}' wilt verwijderen?", "DeleteBackupMessageText": "Bent u zeker dat u de veiligheidskopie '{0}' wilt verwijderen?", - "CheckDownloadClientForDetails": "controleer downloader voor meer details", "CancelPendingTask": "Bent u zeker dat u deze taak in afwachting wilt annuleren?", "BranchUpdateMechanism": "Gebruikte branch door extern update mechanisme", "BranchUpdate": "Te gebruiken branch om Prowlarr bij te werken", "BeforeUpdate": "Voor de update", "AddingTag": "Tag toevoegen", "UnableToLoadUISettings": "Kon gebruikersinterface instellingen niet inladen", - "UnableToLoadNamingSettings": "Kon Naamgevingsinstellingen niet inladen", "UnableToLoadIndexerOptions": "Kon indexeerder opties niet inladen", "UnableToLoadGeneralSettings": "Kon Algemene instellingen niet inladen", "UnableToAddANewNotificationPleaseTryAgain": "Kon geen nieuwe notificatie toevoegen, gelieve opnieuw te proberen.", "UnableToAddANewIndexerPleaseTryAgain": "Kon geen nieuwe indexeerder toevoegen, gelieve opnieuw te proberen.", "UnableToAddANewDownloadClientPleaseTryAgain": "Kon geen nieuwe downloader toevoegen, gelieve opnieuw te proberen.", - "RegularExpressionsCanBeTested": "Reguliere expressies kunnen worden getest ", "ProwlarrSupportsAnyIndexer": "Prowlarr ondersteunt veel indexeerders naast elke indexeerder die de Newznab/Torznab-standaard gebruikt met 'Generic Newznab' (voor usenet) of 'Generic Torznab' (voor torrents). Zoek en selecteer uw indexeerder hieronder.", "ProwlarrSupportsAnyDownloadClient": "Prowlarr ondersteund elke downloader die gebruik maakt van de Newznab standaard, tevens ook de ander hieronder weergegeven downloaders.", "NoTagsHaveBeenAddedYet": "Er zijn nog geen tags toegevoegd", - "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Voor meer informatie over de individuele lijsten, klik op de info knoppen.", "ForMoreInformationOnTheIndividualDownloadClients": "Voor meer informatie over de individuele downloaders, klik op de info knoppen.", - "ExtraFileExtensionsHelpTexts1": "Komma gescheiden lijst met extra bestanden om te importeren (.nfo zal als .nfo-orig worden geïmporteerd)", "ApplyTagsHelpTexts4": "Vervangen: Vervang de tags met de ingevoerde tags (voer geen tags in om alle tags te wissen)", "ApplyTagsHelpTexts3": "Verwijderen: Verwijder de ingevoerde tags", "ApplyTagsHelpTexts2": "Toevoegen: Voeg de tags toe aan de lijst met bestaande tags", @@ -372,16 +326,13 @@ "MinutesNinety": "90 Minuten: {0}", "MinutesHundredTwenty": "120 Minuten: {0}", "MaintenanceRelease": "Onderhoudsuitgave", - "LinkHere": "hier", "FilterPlaceHolder": "Zoek indexeerder", "Exception": "Uitzondering", "ErrorLoadingContents": "Fout bij laden van inhoud", "UILanguageHelpTextWarning": "Browser Herladen Vereist", "UILanguageHelpText": "Taal die Prowlarr zal gebruiken voor de gebruikersinterface", "UILanguage": "Gebruikersinterface Taal", - "ExportCustomFormat": "Exporteer Eigen Formaat", "DownloadPropersAndRepacks": "PROPERS en REPACKS", - "CopyToClipboard": "Kopieer naar Klembord", "Priority": "Prioriteit", "InteractiveSearch": "Interactief Zoeken", "IndexerPriorityHelpText": "Indexeerder Prioriteit van 1 (Hoogste) tot 50 (Laagste). Standaard: 25.", @@ -392,7 +343,6 @@ "AddIndexer": "Voeg Indexeerder Toe", "FocusSearchBox": "Focus Zoekvak", "CloseCurrentModal": "Sluit Huidig Bericht", - "AddMovie": "Voeg Film Toe", "AcceptConfirmationModal": "Accepteer Bevestigingsbericht", "Yesterday": "Gisteren", "Tomorrow": "Morgen", diff --git a/src/NzbDrone.Core/Localization/Core/pl.json b/src/NzbDrone.Core/Localization/Core/pl.json index fb9dd37f8..ab8d68c8a 100644 --- a/src/NzbDrone.Core/Localization/Core/pl.json +++ b/src/NzbDrone.Core/Localization/Core/pl.json @@ -1,13 +1,361 @@ { "Clear": "Wyczyść", - "Calendar": "Kalendarz", "BackupNow": "Zrób kopię zapasową teraz", "Backup": "Kopia zapasowa", "AppDataLocationHealthCheckMessage": "Aktualizacja nie będzie możliwa w celu uniknięcia usunięcia danych aplikacji", "Analytics": "Analityka", "All": "Wszystkie", - "AddNew": "Dodaj nowe", "Added": "Dodane", "Actions": "Aktywności", - "About": "O" + "About": "O", + "Logging": "Logowanie", + "MinutesNinety": "90 minut: {0}", + "EnableSslHelpText": " Wymaga ponownego uruchomienia jako administrator, aby odniosło skutek", + "ReadTheWikiForMoreInformation": "Przeczytaj Wiki, aby uzyskać więcej informacji", + "Reload": "Przeładować", + "SSLCertPassword": "Hasło certyfikatu SSL", + "SSLCertPasswordHelpText": "Hasło do pliku pfx", + "TableOptionsColumnsMessage": "Wybierz, które kolumny są widoczne i w jakiej kolejności się pojawiają", + "BeforeUpdate": "Przed aktualizacją", + "BindAddress": "Adres powiązania", + "BranchUpdate": "Oddział do użycia do aktualizacji Radarr", + "Cancel": "Anuluj", + "ApplyTagsHelpTexts3": "Usuń: usuń wprowadzone tagi", + "Automatic": "Automatyczny", + "ApplyTags": "Zastosuj tagi", + "ApplyTagsHelpTexts4": "Zastąp: Zastąp tagi wprowadzonymi tagami (nie wprowadzaj tagów, aby usunąć wszystkie tagi)", + "BackupIntervalHelpText": "Odstęp czasu między automatycznymi kopiami zapasowymi", + "Close": "Blisko", + "CloseCurrentModal": "Zamknij bieżący tryb", + "Delete": "Usunąć", + "Discord": "Niezgoda", + "Edit": "Edytować", + "EnableAutoHelpText": "Jeśli włączone, filmy będą automatycznie dodawane do Radarr z tej listy", + "EnableAutomaticSearchHelpText": "Będzie używany, gdy automatyczne wyszukiwania są wykonywane przez interfejs użytkownika lub przez Radarr", + "EnableHelpText": "Włącz tworzenie pliku metadanych dla tego typu metadanych", + "KeyboardShortcuts": "Skróty klawiszowe", + "UnableToAddANewAppProfilePleaseTryAgain": "Nie można dodać nowego profilu jakości, spróbuj ponownie.", + "URLBase": "Baza adresów URL", + "CustomFilters": "Filtry niestandardowe", + "DeleteIndexerMessageText": "Czy na pewno chcesz usunąć indeksator „{0}”?", + "EnableInteractiveSearchHelpTextWarning": "Wyszukiwanie nie jest obsługiwane przez ten indeksator", + "EnableRss": "Włącz RSS", + "LaunchBrowserHelpText": " Otwórz przeglądarkę internetową i przejdź do strony głównej Radarr po uruchomieniu aplikacji.", + "Password": "Hasło", + "Peers": "Rówieśnicy", + "Pending": "W oczekiwaniu", + "PrioritySettings": "Priorytet", + "Protocol": "Protokół", + "Options": "Opcje", + "ProxyType": "Typ proxy", + "ShownClickToHide": "Pokazane, kliknij, aby ukryć", + "QualityDefinitions": "Definicje jakości", + "Refresh": "Odświeżać", + "ReleaseStatus": "Stan wydania", + "RemovingTag": "Usuwanie tagu", + "SelectAll": "Zaznacz wszystko", + "Shutdown": "Zamknąć", + "Style": "Styl", + "System": "System", + "TableOptions": "Opcje tabeli", + "TagCannotBeDeletedWhileInUse": "Nie można usunąć, gdy jest używany", + "UnselectAll": "Odznacz wszystko", + "Usenet": "Usenet", + "AllIndexersHiddenDueToFilter": "Wszystkie filmy są ukryte ze względu na zastosowany filtr.", + "ApiKey": "Klucz API", + "UI": "UI", + "AcceptConfirmationModal": "Zaakceptuj tryb potwierdzenia", + "AddIndexer": "Dodaj indeksator", + "AddingTag": "Dodawanie tagu", + "Age": "Wiek", + "CertificateValidationHelpText": "Zmień ścisłą walidację certyfikatu HTTPS", + "ChangeHasNotBeenSavedYet": "Zmiana nie została jeszcze zapisana", + "DownloadClient": "Pobierz klienta", + "Exception": "Wyjątek", + "ExistingMovies": "Istniejące filmy", + "ExistingTag": "Istniejący tag", + "Filename": "Nazwa pliku", + "Languages": "Języki", + "NoChange": "Bez zmiany", + "NoMinimumForAnyRuntime": "Brak minimum dla dowolnego środowiska uruchomieniowego", + "Add": "Dodaj", + "AppDataDirectory": "Katalog AppData", + "AreYouSureYouWantToResetYourAPIKey": "Czy na pewno chcesz zresetować swój klucz API?", + "AutomaticSearch": "Automatyczne wyszukiwanie", + "Branch": "Gałąź", + "Connections": "Znajomości", + "ConnectSettings": "Ustawienia połączenia", + "CouldNotConnectSignalR": "Nie można połączyć się z SignalR, interfejs użytkownika nie zostanie zaktualizowany", + "EnableInteractiveSearchHelpText": "Będzie używany, gdy używane jest wyszukiwanie interaktywne", + "HomePage": "Strona główna", + "IndexerProxyStatusCheckSingleClientMessage": "Listy niedostępne z powodu błędów: {0}", + "LastWriteTime": "Czas ostatniego zapisu", + "Level": "Poziom", + "LogFiles": "Pliki dziennika", + "MaximumLimits": "Maksymalne limity", + "Mechanism": "Mechanizm", + "MovieDetailsPreviousMovie": "Szczegóły filmu: poprzedni film", + "NoChanges": "Bez zmian", + "NoUpdatesAreAvailable": "Brak dostępnych aktualizacji", + "OAuthPopupMessage": "Twoja przeglądarka blokuje wyskakujące okienka", + "Ok": "Dobrze", + "OnHealthIssueHelpText": "W kwestii zdrowia", + "PageSize": "Rozmiar strony", + "PageSizeHelpText": "Liczba elementów do pokazania na każdej stronie", + "PendingChangesStayReview": "Zostań i przejrzyj zmiany", + "RSSIsNotSupportedWithThisIndexer": "RSS nie jest obsługiwany przez ten indeksator", + "Settings": "Ustawienia", + "ShowAdvanced": "Pokaż zaawansowane", + "Test": "Test", + "UILanguage": "Język interfejsu użytkownika", + "UnableToLoadNotifications": "Nie można załadować powiadomień", + "UpdateCheckUINotWritableMessage": "Nie można zainstalować aktualizacji, ponieważ użytkownik „{1}” nie ma prawa zapisu w folderze interfejsu użytkownika „{0}”.", + "UseProxy": "Użyj proxy", + "DeleteIndexerProxyMessageText": "Czy na pewno chcesz usunąć tag „{0}”?", + "DeleteNotificationMessageText": "Czy na pewno chcesz usunąć powiadomienie „{0}”?", + "EnableSSL": "Włącz SSL", + "Error": "Błąd", + "ErrorLoadingContents": "Błąd podczas ładowania treści", + "Events": "Wydarzenia", + "SettingsLongDateFormat": "Format długiej daty", + "AnalyticsEnabledHelpText": "Wysyłaj anonimowe informacje o użytkowaniu i błędach do serwerów Radarr. Obejmuje to informacje o Twojej przeglądarce, z których stron Radarr WebUI używasz, raportowanie błędów, a także wersję systemu operacyjnego i środowiska wykonawczego. Wykorzystamy te informacje, aby nadać priorytet funkcjom i poprawkom błędów.", + "ApplicationStatusCheckAllClientMessage": "Wszystkie listy są niedostępne z powodu błędów", + "ApplicationStatusCheckSingleClientMessage": "Listy niedostępne z powodu błędów: {0}", + "Apply": "Zastosować", + "ApplyTagsHelpTexts1": "Jak zastosować tagi do wybranych filmów", + "ApplyTagsHelpTexts2": "Dodaj: dodaj tagi do istniejącej listy tagów", + "Authentication": "Poświadczenie", + "AuthenticationMethodHelpText": "Wymagaj nazwy użytkownika i hasła, aby uzyskać dostęp do Radarr", + "BackupFolderHelpText": "Względne ścieżki będą znajdować się w katalogu AppData Radarr", + "BackupRetentionHelpText": "Automatyczne kopie zapasowe starsze niż okres przechowywania zostaną automatycznie wyczyszczone", + "BindAddressHelpText": "Prawidłowy adres IP4 lub „*” dla wszystkich interfejsów", + "BranchUpdateMechanism": "Gałąź używana przez zewnętrzny mechanizm aktualizacji", + "BypassProxyForLocalAddresses": "Pomijaj serwer proxy dla adresów lokalnych", + "CancelPendingTask": "Czy na pewno chcesz anulować to oczekujące zadanie?", + "CertificateValidation": "Walidacja certyfikatu", + "ClientPriority": "Priorytet klienta", + "CloneIndexer": "Clone Indexer", + "CloneProfile": "Klonuj profil", + "Component": "Składnik", + "ConnectionLost": "Utracono połączenie", + "ConnectionLostAutomaticMessage": "Radarr spróbuje połączyć się automatycznie lub możesz kliknąć przycisk przeładuj poniżej.", + "Custom": "Zwyczaj", + "Date": "Data", + "Dates": "Daktyle", + "DBMigration": "Migracja bazy danych", + "DelayProfile": "Profil opóźnienia", + "DeleteApplicationMessageText": "Czy na pewno chcesz usunąć powiadomienie „{0}”?", + "DeleteBackup": "Usuń kopię zapasową", + "DeleteBackupMessageText": "Czy na pewno chcesz usunąć kopię zapasową „{0}”?", + "DeleteDownloadClient": "Usuń klienta pobierania", + "DeleteDownloadClientMessageText": "Czy na pewno chcesz usunąć klienta pobierania „{0}”?", + "DeleteIndexer": "Usuń indeksator", + "DeleteNotification": "Usuń powiadomienie", + "Disabled": "Wyłączone", + "Docker": "Doker", + "DownloadClientCheckNoneAvailableMessage": "Żaden klient pobierania nie jest dostępny", + "DownloadClientCheckUnableToCommunicateMessage": "Nie można skomunikować się z {0}.", + "DownloadClientStatusCheckSingleClientMessage": "Klienci pobierania niedostępni z powodu błędów: {0}", + "DownloadClientUnavailable": "Klient pobierania jest niedostępny", + "Downloading": "Ściąganie", + "EditIndexer": "Edytuj indeksator", + "Enable": "Włączyć", + "EnableAutomaticAdd": "Włącz automatyczne dodawanie", + "EnableAutomaticSearch": "Włącz automatyczne wyszukiwanie", + "EnableAutomaticSearchHelpTextWarning": "Będzie używany, gdy używane jest wyszukiwanie interaktywne", + "EnableColorImpairedMode": "Włącz tryb z zaburzeniami kolorów", + "EnableColorImpairedModeHelpText": "Zmieniony styl, aby umożliwić użytkownikom z zaburzeniami kolorów lepsze rozróżnianie informacji oznaczonych kolorami", + "EnableCompletedDownloadHandlingHelpText": "Automatycznie importuj ukończone pliki do pobrania z klienta pobierania", + "Enabled": "Włączone", + "EnabledHelpText": "Włącz tę listę do użytku w Radarr", + "DownloadClientStatusCheckAllClientMessage": "Wszyscy klienci pobierania są niedostępni z powodu błędów", + "EnableInteractiveSearch": "Włącz wyszukiwanie interaktywne", + "EnableMediaInfoHelpText": "Wyodrębnij z plików informacje wideo, takie jak rozdzielczość, czas działania i kodeki. Wymaga to odczytu przez Radarr części pliku, które mogą powodować dużą aktywność dysku lub sieci podczas skanowania.", + "EventType": "Typ wydarzenia", + "Failed": "Niepowodzenie", + "FeatureRequests": "Żądania funkcji", + "Files": "Akta", + "Filter": "Filtr", + "Fixed": "Naprawiony", + "FocusSearchBox": "Zaznacz pole wyszukiwania", + "Folder": "Teczka", + "ForMoreInformationOnTheIndividualDownloadClients": "Aby uzyskać więcej informacji na temat poszczególnych klientów pobierania, kliknij przyciski informacyjne.", + "General": "Generał", + "GeneralSettings": "Ustawienia główne", + "GeneralSettingsSummary": "Port, SSL, nazwa użytkownika / hasło, proxy, analizy i aktualizacje", + "Grabbed": "Złapał", + "HealthNoIssues": "Żadnych problemów z konfiguracją", + "HiddenClickToShow": "Ukryty, kliknij, aby pokazać", + "HideAdvanced": "Ukryj zaawansowane", + "History": "Historia", + "Hostname": "Nazwa hosta", + "IgnoredAddresses": "Ignorowane adresy", + "IllRestartLater": "Zrestartuję później", + "IndexerLongTermStatusCheckAllClientMessage": "Wszystkie indeksatory są niedostępne z powodu awarii przez ponad 6 godzin", + "IndexerLongTermStatusCheckSingleClientMessage": "Indeksatory niedostępne z powodu błędów przez ponad 6 godzin: {0}", + "QualitySettings": "Ustawienia jakości", + "IndexerPriority": "Priorytet indeksatora", + "IndexerPriorityHelpText": "Priorytet indeksatora od 1 (najwyższy) do 50 (najniższy). Domyślnie: 25.", + "IndexerProxyStatusCheckAllClientMessage": "Wszystkie listy są niedostępne z powodu błędów", + "ShowSearchHelpText": "Pokaż przycisk wyszukiwania po najechaniu kursorem", + "IndexerStatusCheckSingleClientMessage": "Indeksatory niedostępne z powodu błędów: {0}", + "Info": "Informacje", + "Interval": "Interwał", + "Language": "Język", + "LogLevel": "Poziom dziennika", + "LogLevelTraceHelpTextWarning": "Rejestrowanie śledzenia powinno być włączone tylko tymczasowo", + "Logs": "Dzienniki", + "Manual": "podręcznik", + "MovieDetailsNextMovie": "Szczegóły filmu: następny film", + "MovieIndexScrollBottom": "Indeks filmów: przewiń w dół", + "MovieIndexScrollTop": "Indeks filmów: przewiń do góry", + "Name": "Nazwa", + "New": "Nowy", + "NoBackupsAreAvailable": "Brak dostępnych kopii zapasowych", + "UnableToLoadQualityDefinitions": "Nie można załadować definicji jakości", + "Uptime": "Dostępność", + "UnableToLoadUISettings": "Nie można załadować ustawień interfejsu użytkownika", + "NoLeaveIt": "Nie, zostaw to", + "NoLimitForAnyRuntime": "Brak ograniczeń dla dowolnego czasu wykonywania", + "NoLinks": "Brak linków", + "NoLogFiles": "Brak plików dziennika", + "NoTagsHaveBeenAddedYet": "Żadne tagi nie zostały jeszcze dodane", + "View": "Widok", + "NotificationTriggers": "Wyzwalacze powiadomień", + "OpenBrowserOnStart": "Otwórz przeglądarkę przy starcie", + "OpenThisModal": "Otwórz ten modal", + "PackageVersion": "Wersja pakietu", + "PendingChangesDiscardChanges": "Odrzuć zmiany i wyjdź", + "PendingChangesMessage": "Masz niezapisane zmiany, czy na pewno chcesz opuścić tę stronę?", + "Port": "Port", + "PortNumber": "Numer portu", + "PreferredSize": "Preferowany rozmiar", + "Presets": "Presety", + "Priority": "Priorytet", + "PriorityHelpText": "Nadaj priorytet wielu klientom pobierania. W przypadku klientów o tym samym priorytecie używane jest działanie okrężne.", + "Proxy": "Pełnomocnik", + "ProxyBypassFilterHelpText": "Użyj znaku „,” jako separatora i „*”. jako symbol wieloznaczny dla subdomen", + "ProxyCheckBadRequestMessage": "Nie udało się przetestować serwera proxy. StatusCode: {0}", + "ProxyCheckFailedToTestMessage": "Nie udało się przetestować serwera proxy: {0}", + "ProxyCheckResolveIpMessage": "Nie udało się rozwiązać adresu IP dla skonfigurowanego hosta proxy {0}", + "ProxyPasswordHelpText": "Musisz tylko wprowadzić nazwę użytkownika i hasło, jeśli jest to wymagane. W przeciwnym razie pozostaw je puste.", + "ProxyUsernameHelpText": "Musisz tylko wprowadzić nazwę użytkownika i hasło, jeśli jest to wymagane. W przeciwnym razie pozostaw je puste.", + "PtpOldSettingsCheckMessage": "Następujące indeksatory PassThePopcorn mają przestarzałe ustawienia i należy je zaktualizować: {0}", + "Queue": "Kolejka", + "Reddit": "Reddit", + "RefreshMovie": "Odśwież film", + "ReleaseBranchCheckOfficialBranchMessage": "Gałąź {0} nie jest poprawną gałęzią wydania Radarr, nie będziesz otrzymywać aktualizacji", + "RemovedFromTaskQueue": "Usunięto z kolejki zadań", + "RemoveFilter": "Usuń filtr", + "Reset": "Resetowanie", + "ResetAPIKey": "Zresetuj klucz API", + "Restart": "Uruchom ponownie", + "RestartRequiredHelpTextWarning": "Wymaga ponownego uruchomienia, aby odniosło skutek", + "Restore": "Przywracać", + "RestoreBackup": "Przywracania kopii zapasowej", + "Restrictions": "Ograniczenia", + "Result": "Wynik", + "Retention": "Zatrzymywanie", + "Save": "Zapisać", + "SaveChanges": "Zapisz zmiany", + "SaveSettings": "Zapisz ustawienia", + "Scheduled": "Planowy", + "ScriptPath": "Script Path", + "Search": "Szukaj", + "Security": "Bezpieczeństwo", + "Seeders": "Siewniki", + "SendAnonymousUsageData": "Wysyłaj anonimowe dane dotyczące użytkowania", + "SetTags": "Ustaw tagi", + "SettingsEnableColorImpairedMode": "Włącz tryb z zaburzeniami kolorów", + "SettingsEnableColorImpairedModeHelpText": "Zmieniony styl, aby umożliwić użytkownikom z zaburzeniami kolorów lepsze rozróżnianie informacji oznaczonych kolorami", + "SettingsShortDateFormat": "Format krótkiej daty", + "SettingsShowRelativeDates": "Pokaż daty względne", + "SettingsShowRelativeDatesHelpText": "Pokaż daty względne (dzisiaj / wczoraj / itd.) Lub bezwzględne", + "SettingsTimeFormat": "Format czasu", + "ShowSearch": "Pokaż wyszukiwanie", + "Size": "Rozmiar", + "Sort": "Sortować", + "Source": "Źródło", + "SSLCertPath": "Ścieżka certyfikatu SSL", + "SSLCertPathHelpText": "Ścieżka do pliku pfx", + "SSLPort": "Port SSL", + "StartTypingOrSelectAPathBelow": "Zacznij pisać lub wybierz ścieżkę poniżej", + "StartupDirectory": "Katalog startowy", + "Status": "Status", + "SuggestTranslationChange": "Zaproponuj zmianę tłumaczenia", + "SystemTimeCheckMessage": "Czas systemowy jest wyłączony o więcej niż 1 dzień. Zaplanowane zadania mogą nie działać poprawnie, dopóki czas nie zostanie skorygowany", + "Tags": "Tagi", + "TagsHelpText": "Dotyczy filmów z co najmniej jednym pasującym tagiem", + "TagsSettingsSummary": "Zobacz wszystkie tagi i sposób ich używania. Nieużywane tagi można usunąć", + "TestAll": "Testuj wszystko", + "TestAllClients": "Przetestuj wszystkich klientów", + "Time": "Czas", + "Title": "Tytuł", + "Today": "Dzisiaj", + "Tomorrow": "Jutro", + "Torrent": "Torrenty", + "Torrents": "Torrenty", + "Type": "Rodzaj", + "UILanguageHelpText": "Język, którego Radarr będzie używać w interfejsie użytkownika", + "UILanguageHelpTextWarning": "Wymagane przeładowanie przeglądarki", + "UISettings": "Ustawienia interfejsu użytkownika", + "UnableToAddANewApplicationPleaseTryAgain": "Nie można dodać nowego powiadomienia, spróbuj ponownie.", + "UnableToAddANewDownloadClientPleaseTryAgain": "Nie można dodać nowego klienta pobierania, spróbuj ponownie.", + "UnableToAddANewIndexerPleaseTryAgain": "Nie można dodać nowego indeksatora, spróbuj ponownie.", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Nie można dodać nowego indeksatora, spróbuj ponownie.", + "UnableToAddANewNotificationPleaseTryAgain": "Nie można dodać nowego powiadomienia, spróbuj ponownie.", + "UnableToLoadBackups": "Nie można załadować kopii zapasowych", + "UnableToLoadDownloadClients": "Nie można załadować klientów pobierania", + "UnableToLoadGeneralSettings": "Nie można załadować ustawień ogólnych", + "UnableToLoadHistory": "Nie można załadować historii", + "UnableToLoadIndexers": "Nie można załadować indeksatorów", + "UnableToLoadTags": "Nie można załadować tagów", + "UnsavedChanges": "Niezapisane zmiany", + "UpdateAutomaticallyHelpText": "Automatycznie pobieraj i instaluj aktualizacje. Nadal będziesz mógł zainstalować z System: Updates", + "UpdateCheckStartupNotWritableMessage": "Nie można zainstalować aktualizacji, ponieważ użytkownik „{1}” nie ma prawa zapisu do folderu startowego „{0}”.", + "UpdateCheckStartupTranslocationMessage": "Nie można zainstalować aktualizacji, ponieważ folder startowy „{0}” znajduje się w folderze translokacji aplikacji.", + "UpdateMechanismHelpText": "Użyj wbudowanego aktualizatora Radarr lub skryptu", + "Updates": "Aktualizacje", + "UpdateScriptPathHelpText": "Ścieżka do niestandardowego skryptu, który pobiera wyodrębniony pakiet aktualizacji i obsługuje pozostałą część procesu aktualizacji", + "UrlBaseHelpText": "W przypadku obsługi zwrotnego proxy wartość domyślna jest pusta", + "Username": "Nazwa Użytkownika", + "DeleteTag": "Usuń tag", + "DeleteTagMessageText": "Czy na pewno chcesz usunąć tag „{0}”?", + "Details": "Detale", + "Donations": "Darowizny", + "DownloadClients": "Pobierz klientów", + "DownloadClientSettings": "Pobierz ustawienia klienta", + "Importing": "Importowanie", + "IncludeHealthWarningsHelpText": "Uwzględnij ostrzeżenia zdrowotne", + "Indexer": "Indeksator", + "IndexerFlags": "Flagi indeksujące", + "TagIsNotUsedAndCanBeDeleted": "Znacznik nie jest używany i można go usunąć", + "AddDownloadClient": "Dodaj klienta pobierania", + "Grabs": "Chwycić", + "Health": "Zdrowie", + "InteractiveSearch": "Wyszukiwanie interaktywne", + "Version": "Wersja", + "Warn": "Ostrzec", + "Wiki": "Wiki", + "YesCancel": "Tak, anuluj", + "Yesterday": "Wczoraj", + "Backups": "Kopie zapasowe", + "Message": "Wiadomość", + "MIA": "MIA", + "MinimumLimits": "Minimalne limity", + "MinutesHundredTwenty": "120 minut: {0}", + "MinutesSixty": "60 minut: {0}", + "Mode": "Tryb", + "MonoTlsCheckMessage": "Obejście problemu z Radarr Mono 4.x tls jest nadal włączone, rozważ usunięcie MONO_TLS_PROVIDER = starsza opcja środowiska", + "MonoVersion": "Wersja mono", + "MonoVersionCheckUpgradeRecommendedMessage": "Aktualnie zainstalowana wersja Mono {0} jest obsługiwana, ale zalecana jest aktualizacja do {1}.", + "MoreInfo": "Więcej informacji", + "Movies": "Kino", + "Columns": "Kolumny", + "Host": "Gospodarz", + "Indexers": "Indeksatory", + "IndexerStatusCheckAllClientMessage": "Wszystkie indeksatory są niedostępne z powodu błędów", + "RestartNow": "Zrestartuj teraz", + "RSS": "RSS", + "Tasks": "Zadania" } diff --git a/src/NzbDrone.Core/Localization/Core/pt.json b/src/NzbDrone.Core/Localization/Core/pt.json index dee490dcb..3642ecfc6 100644 --- a/src/NzbDrone.Core/Localization/Core/pt.json +++ b/src/NzbDrone.Core/Localization/Core/pt.json @@ -31,14 +31,11 @@ "Shutdown": "Encerrar", "ShowSearchHelpText": "Mostrar botão de pesquisa ao passar o cursor", "ShowSearch": "Mostrar pesquisa", - "ShowDateAdded": "Mostrar Data Adicionado", "ShowAdvanced": "Mostrar avançado", - "SettingsUiLanguage": "Idioma da UI", "SettingsTimeFormat": "Formato de hora", "SettingsShowRelativeDatesHelpText": "Mostrar datas relativas (Hoje, Ontem, etc.) ou absolutas", "SettingsShowRelativeDates": "Mostrar datas relativas", "SettingsShortDateFormat": "Formato curto de data", - "SettingsRemotePathMappingLocalPath": "Caminho Local", "SettingsLongDateFormat": "Formato longo de data", "SettingsEnableColorImpairedMode": "Ativar modo de daltonismo", "SettingsEnableColorImpairedModeHelpText": "Estilo alterado para permitir que utilizadores com daltonismo possam melhor distinguir informações de cores", @@ -47,16 +44,13 @@ "SelectAll": "Selecionar todos", "Seeders": "Semeadores", "Security": "Segurança", - "SearchForMissing": "Buscar Ausentes", "Search": "Pesquisar", "Scheduled": "Agendado", "SaveChanges": "Guardar mudanças", "Save": "Guardar", - "RootFolderCheckSingleMessage": "Pasta raiz não encontrada: {0}", "Restrictions": "Restrições", "RestoreBackup": "Restaurar cópia de segurança", "Restart": "Reiniciar", - "RemoveRootFolder": "Remover pasta raiz", "Reload": "Recarregar", "ReleaseStatus": "Estado da versão", "ReleaseBranchCheckPreviousVersionMessage": "A ramificação {0} é para versões anteriores do Prowlarr, utilize a ramificação \"Nightly\" para futuras atualizações", @@ -70,14 +64,10 @@ "ProxyCheckBadRequestMessage": "Falha ao testar o proxy. Código de estado: {0}", "Proxy": "Proxy", "Protocol": "Protocolo", - "PreviewRename": "Pré-visualizar Renomear", - "PhysicalRelease": "Versão Física", "PendingChangesStayReview": "Ficar e rever mudanças", "PendingChangesMessage": "Há mudanças não guardadas, tem a certeza que quer sair dessa página?", "PendingChangesDiscardChanges": "Descartar mudanças e sair", "PageSize": "Tamanho da página", - "OrganizeModalSuccess": "Sucesso! Meu trabalho está feito, sem arquivos para renomear.", - "OrganizeAndRename": "Organizar & Renomear", "Options": "Opções", "Ok": "Ok", "OAuthPopupMessage": "Os pop-ups estão sendo bloqueados por seu browser", @@ -85,18 +75,13 @@ "NoChange": "Sem mudança", "Name": "Nome", "Movies": "Filmes", - "Movie": "Filme", "MoreInfo": "Mais informações", "MonoVersionCheckUpgradeRecommendedMessage": "A versão Mono {0} atualmente instalada é suportada, mas recomenda-se atualizar para {1}.", "MonoTlsCheckMessage": "Uma solução para o Prowlarr Mono 4.x tls ainda está ativa, considere remover a opção de ambiente MONO_TLS_PROVIDER=legacy", "MonoNotNetCoreCheckMessage": "Atualiza para a versão .NET Core do Prowlarr", - "Monitor": "Monitorar", - "MetadataSettingsSummary": "Criar arquivos de metadados quando os filmes são importados ou atualizados", "Message": "Mensagem", - "MassMovieSearch": "Pesquisa de Filmes em Massa", "Logging": "Registo em log", "LogFiles": "Ficheiros de log", - "ListExclusions": "Lista de Exclusões", "Level": "Nível", "LastWriteTime": "Hora da última escrita", "Language": "Idioma", @@ -105,11 +90,8 @@ "Info": "Informações", "IndexerStatusCheckSingleClientMessage": "Indexadores indisponíveis devido a falhas: {0}", "IndexerStatusCheckAllClientMessage": "Todos os indexadores estão indisponíveis devido a falhas", - "IndexerSearchCheckNoAvailableIndexersMessage": "Todos indexadores capazes de pesquisar estão indisponíveis devido a recente erros de indexadores", "Indexers": "Indexadores", "Indexer": "Indexador", - "ImportMechanismHealthCheckMessage": "Ativar Manipulação de Download Completado", - "Imported": "Importado", "Host": "Anfitrião", "History": "Histórico", "HideAdvanced": "Ocultar avançado", @@ -135,12 +117,10 @@ "DownloadClientCheckUnableToCommunicateMessage": "Não é possível ligar-se a {0}.", "DownloadClientCheckNoneAvailableMessage": "Nenhum cliente de transferências disponível", "DownloadClient": "Cliente de transferências", - "Discover": "Descobrir", "Details": "Detalhes", "Delete": "Eliminar", "Dates": "Datas", "Date": "Data", - "CustomFormats": "Formatos Customizados", "CustomFilters": "Filtros personalizados", "ConnectSettingsSummary": "Notificações, ligações para servidores/leitores de multimédia e scripts personalizados", "Connections": "Ligações", @@ -159,8 +139,6 @@ "Analytics": "Análises", "All": "Todos", "Age": "Tempo de vida", - "AddNewMessage": "É facil adicionar um novo filme, apenas comece a escrever o nome do filme que quer adicionar", - "AddExclusion": "Adicionar Exclusão", "Added": "Adicionado", "Actions": "Ações", "About": "Informações", @@ -172,7 +150,6 @@ "AppDataDirectory": "Pasta AppData", "ApiKey": "Chave da API", "AnalyticsEnabledHelpText": "Envia informações anônimas de uso e de erros aos servidores do Prowlarr. Isso inclui informações sobre seu browser, páginas utilizadas na WebUI do Prowlarr, relatórios de erros, bem como as versões do sistema operativo e da aplicação. Utilizaremos essas informações para priorizar funcionalidades e correções de bugs.", - "AllowHardcodedSubs": "Permitir Legendas Embutidas", "QualitySettings": "Definições de qualidade", "ProxyType": "Tipo de proxy", "PortNumber": "Número da porta", @@ -188,19 +165,13 @@ "NoLeaveIt": "Não, deixe-o", "New": "Novo", "NetCore": ".NET", - "MovieYearHelpText": "Ano do filme a excluir", - "MovieInfoLanguageHelpTextWarning": "Será necessário reiniciar o navegador", - "MovieAvailableButMissing": "Filme Disponível, mas Ausente", "MonoVersion": "Versão do Mono", "Mode": "Modo", "MinimumLimits": "Limites mínimos", - "MinimumAge": "Tempo de Vida Mínimo", - "MediaInfo": "Informação Multimídia", "Mechanism": "Mecanismo", "MaximumLimits": "Limites máximos", "Logs": "Logs", "LogLevel": "Nível de log", - "Links": "Links", "Interval": "Intervalo", "IndexerFlags": "Sinalizadores do indexador", "IncludeHealthWarningsHelpText": "Incluir avisos de estado de funcionamento", @@ -208,10 +179,8 @@ "IllRestartLater": "Reiniciarei mais tarde", "IgnoredAddresses": "Endereços ignorados", "Hostname": "Nome do anfitrião", - "GrabID": "Capturar ID", "GeneralSettings": "Definições gerais", "Fixed": "Corrigido", - "FileChmodMode": "Modo CHMOD de arquivo", "EnableSslHelpText": " Requer reinício da aplicação como administrador para aplicar alterações", "EnableSSL": "Ativar SSL", "EnableMediaInfoHelpText": "Extraia informações de vídeo como resolução, tempo de execução e informações de codec dos ficheiros. Isso requer que o Prowlarr leia partes do ficheiro, o que pode causar alta atividade do disco ou da rede durante as análises.", @@ -225,23 +194,18 @@ "EnableAutomaticAdd": "Ativar adição automática", "EnableAutoHelpText": "Se ativado, os filmes desta lista serão automaticamente adicionados ao Prowlarr", "Enable": "Ativar", - "DownloadWarningCheckDownloadClientForMoreDetails": "Alerta de download: verifique mais detalhes no gerenciador de downloads", "DownloadClientSettings": "Definições do cliente de transferências", "Docker": "Docker", "DeleteTag": "Eliminar etiqueta", "DeleteNotification": "Eliminar notificação", "DeleteIndexer": "Eliminar indexador", - "DeleteEmptyFolders": "Deletar pastas vazias", "DeleteDownloadClient": "Eliminar cliente de transferências", "DeleteBackup": "Eliminar cópia de segurança", "DelayProfile": "Perfil de atraso", "DBMigration": "Migração da base de dados", - "CreateGroup": "Criar grupo", - "CopyUsingHardlinksHelpText": "Usar Hardlinks ao tentar copiar arquivos a partir de torrents que ainda estão em modo seed", "ConnectSettings": "Definições de ligação", "CloneProfile": "Clonar perfil", "CloneIndexer": "Clonar indexador", - "CleanLibraryLevel": "Limpar Nível da Biblioteca", "ChangeHasNotBeenSavedYet": "A mudança ainda não foi guardada", "CertificateValidationHelpText": "Mudar nível de restrição da validação da certificação HTTPS", "CertificateValidation": "Validação de certificado", @@ -263,9 +227,6 @@ "ApplyTagsHelpTexts2": "Adicionar: agregar as etiquetas à lista existente de etiquetas", "ApplyTagsHelpTexts1": "Como aplicar etiquetas aos indexadores selecionados", "AddingTag": "A adicionar etiqueta", - "VisitGithubCustomFormatsAphrodite": "Acesse o Github para mais detalhes: ", - "NegateHelpText": "Se marcado, o formato personalizado não se aplicará se esta condição {0} for atendida.", - "CustomFormatUnknownCondition": "Condição de Formato Personalizado '{0}' desconhecida", "AutomaticSearch": "Pesquisa automática", "UnableToLoadIndexers": "Não foi possível carregar os indexadores", "UnableToAddANewIndexerPleaseTryAgain": "Não foi possível adicionar um novo indexador, tenta novamente.", @@ -277,7 +238,6 @@ "EditIndexer": "Editar indexador", "DeleteIndexerMessageText": "Tem a certeza que quer eliminar o indexador \"{0}\"?", "AddIndexer": "Adicionar indexador", - "SetPermissions": "Definir Permissões", "ScriptPath": "Caminho do script", "Retention": "Retenção", "Result": "Resultado", @@ -286,11 +246,9 @@ "RestartNow": "Reiniciar agora", "ResetAPIKey": "Repor chave da API", "Reset": "Repor", - "RenameMovies": "Renomear Filmes", "RemovingTag": "Eliminando etiqueta", "RemoveFilter": "Remover filtro", "RefreshMovie": "Atualizar filme", - "RecyclingBin": "Lixeira", "ReadTheWikiForMoreInformation": "Leia a Wiki para obter mais informações", "Priority": "Prioridade", "Pending": "Pendente", @@ -303,16 +261,11 @@ "MinutesHundredTwenty": "120 minutos: {0}", "MIA": "Desaparecidos", "Manual": "Manual", - "LinkHere": "aqui", "InteractiveSearch": "Pesquisa interativa", - "ImportListStatusCheckAllClientMessage": "Todas as listas estão indisponíveis devido a erros", "HiddenClickToShow": "Oculto, clique para mostrar", - "ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Para mais informações sobre cada lista de importação, clique nos botões de informação.", "ForMoreInformationOnTheIndividualDownloadClients": "Para obter mais informações sobre cada cliente de transferências, clique nos botões de informação.", "FilterPlaceHolder": "Indexadores de pesquisa", - "ExtraFileExtensionsHelpTexts2": "Exemplos: '.sub, .nfo' ou 'sub,nfo'", "ExistingTag": "Etiqueta existente", - "ExcludeMovie": "Ignorar Filme", "Exception": "Exceção", "ErrorLoadingContents": "Erro ao carregar conteúdo", "EnableInteractiveSearchHelpText": "Será utilizado ao realizar uma pesquisa interativa", @@ -320,19 +273,16 @@ "EnableAutomaticSearchHelpText": "Será utilizado ao realizar pesquisas automáticas através da IU ou pelo Prowlarr", "PreferredSize": "Tamanho preferido", "Downloading": "Transferindo", - "DownloadedAndMonitored": "Baixado e Monitorado", "DownloadClientUnavailable": "O cliente de transferências está indisponível", "Disabled": "Desativado", "DeleteTagMessageText": "Tem a certeza que quer eliminar a etiqueta \"{0}\"?", "DeleteNotificationMessageText": "Tem a certeza que quer eliminar a notificação \"{0}\"?", "DeleteDownloadClientMessageText": "Tem a certeza que quer eliminar o cliente de transferências \"{0}\"?", "DeleteBackupMessageText": "Tem a certeza que quer eliminar a cópia de segurança \"{0}\"?", - "WhitelistedSubtitleTags": "Tags de Legendas Permitidas", "UrlBaseHelpText": "Para suporte a proxy inverso, vazio por padrão", "UpdateScriptPathHelpText": "Caminho para um script personalizado que toma um pacote de atualização extraído e lida com o restante do processo da atualização", "UpdateMechanismHelpText": "Utilizar o atualizador do Prowlarr ou um script", "UpdateAutomaticallyHelpText": "Transferir e instalar automaticamente as atualizações. Ainda é possível instalar a partir de Sistema: Atualizações", - "ThisConditionMatchesUsingRegularExpressions": "Esta condição utiliza expressões regulares. Note que os caracteres {0} têm significados especiais e precisam de escape com um {1}", "TestAllClients": "Testar todos os clientes", "TagsHelpText": "Aplica-se a indexadores com pelo menos uma etiqueta correspondente", "TagIsNotUsedAndCanBeDeleted": "A etiqueta não é utilizada e pode ser eliminada", @@ -341,26 +291,16 @@ "SSLCertPath": "Caminho do certificado SSL", "SSLCertPasswordHelpText": "Palavra-passe do ficheiro PFX", "SSLCertPassword": "Palavra-passe do certificado SSL", - "SkipFreeSpaceCheckWhenImportingHelpText": "Usar quando o Prowlarr não puder determinar o espaço livre em sua pasta raiz de filmes", - "ShowTitleHelpText": "Mostrar título do filme abaixo do poster", "ShownClickToHide": "Visível, clique para ocultar", - "ShowGenres": "Mostrar Categorias", - "SettingsRuntimeFormat": "Formato de Tempo de Execução", "SendAnonymousUsageData": "Enviar dados anônimos de uso", - "RetentionHelpText": "Somente Usenet: ajustar para zero para retenção ilimitada", "RestartRequiredHelpTextWarning": "Requer reinício para aplicar alterações", - "ReplaceIllegalCharactersHelpText": "Substituir caracteres ilegais. Se desmarcado, o Prowlarr irá removê-los", - "RemoveCompletedDownloadsHelpText": "Remover downloads importados do histórico do gerenciador de downloads", "ProwlarrSupportsAnyDownloadClient": "O Prowlarr suporta qualquer dos clientes de transferências listados abaixo.", "ProxyUsernameHelpText": "Apenas insira o utilizador e a palavra-passe caso seja requerido. Caso contrário, deixe em branco.", "ProxyPasswordHelpText": "Apenas insira o utilizador e a palavra-passe caso seja requerido. Caso contrário, deixe em branco.", "ProxyBypassFilterHelpText": "Utilizar \",\" como separador e \"*.\" como caráter universal para subdomínios", "MaintenanceRelease": "Versão de manutenção", - "TorrentDelayHelpText": "Espera em minutos para aguardar antes de capturar um torrent", "PriorityHelpText": "Priorizar múltiplos clientes de transferências. Utilizaremos round robin para clientes com a mesma prioridade.", "RemovedFromTaskQueue": "Eliminado da fila de tarefas", - "RecycleBinCleanupDaysHelpTextWarning": "Arquivos na lixeira serão excluídos automaticamente após o número de dias selecionado", - "MovieInfoLanguageHelpText": "Idioma usado pelo Prowlarr na UI para as Informações dos Filmes", "LogLevelTraceHelpTextWarning": "O registo de rasteio somente deve ser ativado temporariamente", "LaunchBrowserHelpText": " Abrir o browser e a home page do Prowlarr ao iniciar a aplicação.", "TagCannotBeDeletedWhileInUse": "Não é possível eliminar enquanto estiver em uso", @@ -376,11 +316,8 @@ "Uptime": "Tempo de atividade", "UnableToLoadUISettings": "Não foi possível carregar as definições da IU", "UnableToLoadTags": "Não foi possível carregar as etiquetas", - "UnableToLoadQualityProfiles": "Não foi possível carregar os Perfis de Qualidade", "UnableToLoadQualityDefinitions": "Não foi possível carregar as definições de qualidade", "UnableToLoadNotifications": "Não foi possível carregar as notificações", - "UnableToLoadMediaManagementSettings": "Não foi possível carregar os ajustes de Gerenciamento Multimídia", - "UnableToLoadLanguages": "Não foi possível carregar os idiomas", "UnableToLoadHistory": "Não foi possível carregar o histórico", "UnableToLoadGeneralSettings": "Não foi possível carregar as definições gerais", "UnableToLoadDownloadClients": "Não foi possível carregar os clientes de transferências", @@ -401,9 +338,6 @@ "MovieIndexScrollBottom": "Índice do filme: deslocar para baixo", "MovieDetailsPreviousMovie": "Detalhes do filme: filme anterior", "MovieDetailsNextMovie": "Detalhes do filme: próximo filme", - "StartImport": "Iniciar Importação", - "ProcessingFolders": "Processando Pastas", - "ImportErrors": "Importar Erros", "CancelProcessing": "Cancelar Processamento", "SettingsConsoleLogLevel": "Nível de registo do console", "SearchIndexers": "Pesquisar indexadores", @@ -495,5 +429,7 @@ "AddIndexerProxy": "Adicionar Proxy de Indexador", "IndexerProxyStatusCheckSingleClientMessage": "Proxys indisponíveis devido a falhas: {0}", "IndexerProxies": "Proxys de Indexadores", - "IndexerProxyStatusCheckAllClientMessage": "Todos os proxys estão indisponíveis devido a falhas" + "IndexerProxyStatusCheckAllClientMessage": "Todos os proxys estão indisponíveis devido a falhas", + "NoLinks": "Sem ligações", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Não foi possível adicionar um novo indexador, tenta novamente." } diff --git a/src/NzbDrone.Core/Localization/Core/ro.json b/src/NzbDrone.Core/Localization/Core/ro.json index ab074ffbf..4d67e97c7 100644 --- a/src/NzbDrone.Core/Localization/Core/ro.json +++ b/src/NzbDrone.Core/Localization/Core/ro.json @@ -4,7 +4,6 @@ "DownloadClientCheckUnableToCommunicateMessage": "Nu pot comunica cu {0}.", "DownloadClientCheckNoneAvailableMessage": "Niciun client de descărcare disponibil", "DownloadClient": "Client de descărcare", - "Discover": "Descoperă", "Details": "Detalii", "Delete": "Șterge", "Dates": "Date", @@ -14,22 +13,17 @@ "Connections": "Conexiuni", "Connect": "Conectează", "Clear": "Șterge", - "Calendar": "Calendar", "BackupNow": "Fă o copie de siguranță", "Backup": "Copie de siguranță", "AppDataLocationHealthCheckMessage": "Pentru a preveni ștergerea AppData, update-ul nu este posibil", "Analytics": "Statistici", "All": "Toate", - "AddNew": "Adaugă", "Added": "Adăugat", "Actions": "Acțiuni", "About": "Despre", "IndexerStatusCheckAllClientMessage": "Niciun indexator nu este disponibil datorită eșuărilor", - "IndexerSearchCheckNoAutomaticMessage": "Niciun indexator cu Căutare automată nu este activ, Prowlarr nu va afișa niciun rezultat de căutare automată", "Indexers": "Indexatori", "Indexer": "Indexator", - "ImportMechanismHealthCheckMessage": "Activează Procesarea Descărcărilor finalizate", - "Import": "Importă", "Host": "Gazdă", "History": "Istorie", "HideAdvanced": "Ascunde Avansat", @@ -47,10 +41,8 @@ "Edit": "Editează", "DownloadClientStatusCheckSingleClientMessage": "Clienții de descărcare sunt indisponibili datorită erorii: {0}", "DownloadClientStatusCheckAllClientMessage": "Toți clienții de descărcare sunt indisponibili datorită erorilor", - "PhysicalRelease": "Lansare fizică", "Peers": "Parteneri", "PageSize": "Mărimea Paginii", - "OrganizeModalDisabled": "Redenumirea este dezactivată, nimic de redenumit", "Options": "Opțiuni", "Ok": "Ok", "OAuthPopupMessage": "Browser-ul tău blochează pop-upurile", @@ -58,17 +50,12 @@ "NoChange": "Nicio Modificare", "Name": "Nume", "Movies": "Filme", - "Movie": "Film", "MoreInfo": "Mai multă informație", "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls este încă activ, ia în calcul să configurezi MONO_TLS_PROVIDER=legacy în opțiunile de mediu", "MonoNotNetCoreCheckMessage": "Actualizează versiunea de .NET Core a Prowlarr", - "Missing": "Lipsește", - "Metadata": "Metadata", "Message": "Mesaj", - "MassMovieSearch": "Caută filme în masa", "Logging": "Logare", "LogFiles": "Fișiere de loguri", - "ListExclusions": "Excluderi din listă", "Level": "Nivel", "LastWriteTime": "Data ultimei scrieri", "Languages": "Limbi", @@ -87,7 +74,6 @@ "Cancel": "Anulează", "Apply": "Aplică", "Age": "Vechime", - "QualityProfile": "Profil de Calitate", "QualityDefinitions": "Definiții de calitate", "PtpOldSettingsCheckMessage": "Următorul indexer PassThePopcorn are setări depreciate și ar trebui actualizate: {0}", "ProxyCheckResolveIpMessage": "Nu am putut găsi adresa IP pentru Hostul Proxy Configurat {0}", @@ -128,20 +114,255 @@ "SelectAll": "SelecteazăTot", "Seeders": "Partajatori", "Security": "Securitate", - "SearchAll": "Caută în toate", "Search": "Caută", "Scheduled": "Programat", "SaveChanges": "Salvează modificările", "Save": "Salvează", - "RootFolderCheckSingleMessage": "Folder rădăcină lipsă: {0}", "Restrictions": "Restricții", "RestoreBackup": "Restaurează salvarea", "Restart": "Repornește", - "RemoveRootFolder": "Elimină folder rădăcină", "Reload": "Reîncarcă", "ReleaseStatus": "Statusul apariției", "ReleaseBranchCheckPreviousVersionMessage": "Branch {0} este pentru o versiune precedentă a Prowlarr, configurează branchul 'Aphrodite' pentru a primi updateuri", "ReleaseBranchCheckOfficialBranchMessage": "Branchul {0} nu este un branch Prowlarr valid, nu vei primi actualizări", "Refresh": "Reîmprospătează", - "Queue": "Coadă" + "Queue": "Coadă", + "New": "Nou", + "MonoVersion": "Versiune mono", + "MonoVersionCheckUpgradeRecommendedMessage": "Versiunea mono instalată în prezent {0} este acceptată, dar se recomandă actualizarea la {1}.", + "OpenThisModal": "Deschideți acest mod", + "SettingsEnableColorImpairedMode": "Activați modul afectat de culoare", + "SettingsEnableColorImpairedModeHelpText": "Stil modificat pentru a permite utilizatorilor cu deficiențe de culoare să distingă mai bine informațiile codificate prin culoare", + "SettingsLongDateFormat": "Format de dată lungă", + "SettingsShortDateFormat": "Format scurt de dată", + "SettingsTimeFormat": "Format de timp", + "NoLimitForAnyRuntime": "Fără limită pentru orice timp de rulare", + "RSSIsNotSupportedWithThisIndexer": "RSS nu este acceptat cu acest indexer", + "ShowSearchHelpText": "Afișați butonul de căutare pe hover", + "UILanguageHelpText": "Limba pe care Radarr o va folosi pentru interfața de utilizare", + "UILanguageHelpTextWarning": "Reîncărcare browser necesară", + "Wiki": "Wiki", + "YesCancel": "Da, Anulați", + "EnableColorImpairedModeHelpText": "Stil modificat pentru a permite utilizatorilor cu deficiențe de culoare să distingă mai bine informațiile codificate prin culoare", + "EnableCompletedDownloadHandlingHelpText": "Importați automat descărcările finalizate de la clientul de descărcare", + "DeleteIndexer": "Ștergeți Indexer", + "DeleteIndexerMessageText": "Sigur doriți să ștergeți indexatorul „{0}”?", + "DeleteNotification": "Ștergeți notificarea", + "DeleteNotificationMessageText": "Sigur doriți să ștergeți notificarea „{0}”?", + "DeleteTag": "Ștergeți eticheta", + "AddingTag": "Se adaugă etichetă", + "LaunchBrowserHelpText": " Deschideți un browser web și navigați la pagina de pornire Radarr la pornirea aplicației.", + "AppDataDirectory": "Directorul AppData", + "ApplicationStatusCheckAllClientMessage": "Toate listele sunt indisponibile datorită erorilor", + "AreYouSureYouWantToResetYourAPIKey": "Sigur doriți să vă resetați cheia API?", + "Authentication": "Autentificare", + "AuthenticationMethodHelpText": "Solicitați numele de utilizator și parola pentru a accesa Radarr", + "AutomaticSearch": "Căutare automată", + "BackupFolderHelpText": "Căile relative vor fi în directorul AppData al lui Radarr", + "BackupIntervalHelpText": "Interval între copiile de rezervă automate", + "Backups": "Copii de rezervă", + "BeforeUpdate": "Înainte de actualizare", + "BindAddressHelpText": "Adresă IP4 validă sau „*” pentru toate interfețele", + "Branch": "Ramură", + "BranchUpdate": "Sucursală de utilizat pentru actualizarea Radarr", + "BranchUpdateMechanism": "Ramură utilizată de mecanismul extern de actualizare", + "BypassProxyForLocalAddresses": "Bypass Proxy pentru adrese locale", + "CancelPendingTask": "Sigur doriți să anulați această sarcină în așteptare?", + "CertificateValidation": "Validarea certificatului", + "CertificateValidationHelpText": "Modificați cât de strictă este validarea certificării HTTPS", + "ClientPriority": "Prioritatea clientului", + "CloneIndexer": "Clonă Indexer", + "CloseCurrentModal": "Închideți modul curent", + "EnableAutoHelpText": "Dacă este activată, Filme vor fi adăugate automat la Radarr din această listă", + "EnableAutomaticSearch": "Activați Căutarea automată", + "EnableAutomaticSearchHelpText": "Va fi utilizat atunci când căutările automate sunt efectuate prin interfața de utilizare sau de către Radarr", + "EnableInteractiveSearchHelpText": "Va fi utilizat atunci când este utilizată căutarea interactivă", + "ForMoreInformationOnTheIndividualDownloadClients": "Pentru mai multe informații despre clienții individuali de descărcare, faceți clic pe butoanele de informații.", + "IllRestartLater": "Voi reporni mai târziu", + "IndexerProxyStatusCheckAllClientMessage": "Niciun indexator nu este disponibil datorită eșuărilor", + "IndexerProxyStatusCheckSingleClientMessage": "Liste indisponibile datorită erorilor: {0}", + "NoMinimumForAnyRuntime": "Niciun minim pentru orice timp de rulare", + "Add": "Adăuga", + "Custom": "Personalizat", + "DeleteBackup": "Ștergeți Backup", + "MovieIndexScrollBottom": "Index film: Derulați partea de jos", + "NoLinks": "Fără legături", + "NoUpdatesAreAvailable": "Nu sunt disponibile actualizări", + "Fixed": "Fix", + "OnHealthIssueHelpText": "Cu privire la problema sănătății", + "PackageVersion": "Versiunea pachetului", + "Password": "Parola", + "Pending": "In asteptarea", + "PendingChangesDiscardChanges": "Aruncați modificările și plecați", + "PreferredSize": "Dimensiune preferată", + "Priority": "Prioritate", + "PriorityHelpText": "Prioritizați mai mulți clienți de descărcare. Round-Robin este utilizat pentru clienții cu aceeași prioritate.", + "PrioritySettings": "Prioritate", + "QualitySettings": "Setări de calitate", + "Reddit": "Reddit", + "Result": "Rezultat", + "RSS": "RSS", + "SettingsShowRelativeDatesHelpText": "Afișați datele relative (Azi / Ieri / etc) sau absolute", + "TestAllClients": "Testați toți clienții", + "Today": "Astăzi", + "UnableToAddANewNotificationPleaseTryAgain": "Imposibil de adăugat o nouă notificare, încercați din nou.", + "UnableToLoadBackups": "Imposibil de încărcat copiile de rezervă", + "UnableToLoadDownloadClients": "Nu se pot încărca clienții de descărcare", + "URLBase": "Baza URL", + "UrlBaseHelpText": "Pentru suport proxy invers, implicit este gol", + "Usenet": "Usenet", + "EditIndexer": "Editați Indexer", + "Enable": "Permite", + "EnableRss": "Activați RSS", + "ErrorLoadingContents": "Eroare la încărcarea conținutului", + "ExistingMovies": "Filme existente", + "FocusSearchBox": "Caseta de căutare Focus", + "IndexerFlags": "Steaguri indexatoare", + "Presets": "Presetări", + "RemovedFromTaskQueue": "Eliminat din coada de activități", + "RemoveFilter": "Scoateți filtrul", + "RemovingTag": "Se elimină eticheta", + "SaveSettings": "Salvează setările", + "Torrents": "Torente", + "UnableToAddANewApplicationPleaseTryAgain": "Imposibil de adăugat o nouă notificare, încercați din nou.", + "UnableToAddANewDownloadClientPleaseTryAgain": "Imposibil de adăugat un nou client de descărcare, încercați din nou.", + "DownloadClientSettings": "Descărcați setările clientului", + "EnableMediaInfoHelpText": "Extrageți informații video, cum ar fi rezoluția, runtime și informații despre codec din fișiere. Acest lucru necesită ca Radarr să citească părți ale fișierului care pot provoca activitate ridicată pe disc sau rețea în timpul scanărilor.", + "EnableInteractiveSearchHelpTextWarning": "Căutarea nu este acceptată cu acest indexer", + "EnableAutomaticSearchHelpTextWarning": "Va fi utilizat atunci când este utilizată căutarea interactivă", + "Enabled": "Activat", + "IncludeHealthWarningsHelpText": "Includeți avertismente de sănătate", + "IndexerPriorityHelpText": "Prioritatea indexerului de la 1 (cea mai mare) la 50 (cea mai mică). Implicit: 25.", + "InteractiveSearch": "Căutare interactivă", + "LogLevel": "Nivel jurnal", + "LogLevelTraceHelpTextWarning": "Înregistrarea urmăririi trebuie activată doar temporar", + "Logs": "Jurnale", + "MaximumLimits": "Limite maxime", + "Mechanism": "Mecanism", + "MIA": "MIA", + "MinimumLimits": "Limite minime", + "MinutesHundredTwenty": "120 de minute: {0}", + "ProxyBypassFilterHelpText": "Folosiți „,” ca separator și „*.” ca un wildcard pentru subdomenii", + "ProxyType": "Tip proxy", + "ProxyPasswordHelpText": "Trebuie să introduceți un nume de utilizator și o parolă numai dacă este necesară. Lasă-le necompletate altfel.", + "ProxyUsernameHelpText": "Trebuie să introduceți un nume de utilizator și o parolă numai dacă este necesară. Lasă-le necompletate altfel.", + "ReadTheWikiForMoreInformation": "Citiți Wiki pentru mai multe informații", + "RefreshMovie": "Reîmprospătați filmul", + "RestartRequiredHelpTextWarning": "Necesită repornire pentru a intra în vigoare", + "Restore": "Restabili", + "Retention": "Retenţie", + "ScriptPath": "Calea Scriptului", + "UnableToLoadIndexers": "Imposibil de încărcat indexatori", + "UnableToLoadNotifications": "Nu se pot încărca notificările", + "UnableToLoadTags": "Nu se pot încărca etichete", + "UnableToLoadUISettings": "Nu se pot încărca setările UI", + "UpdateMechanismHelpText": "Utilizați actualizatorul încorporat al lui Radarr sau un script", + "AnalyticsEnabledHelpText": "Trimiteți informații anonime privind utilizarea și erorile către serverele Radarr. Aceasta include informații despre browserul dvs., ce pagini WebUI Radarr utilizați, raportarea erorilor, precum și sistemul de operare și versiunea de execuție. Vom folosi aceste informații pentru a acorda prioritate caracteristicilor și remedierilor de erori.", + "ApiKey": "Cheie API", + "BackupRetentionHelpText": "Copiile de rezervă automate mai vechi de perioada de păstrare vor fi curățate automat", + "BindAddress": "Adresa de legare", + "ChangeHasNotBeenSavedYet": "Modificarea nu a fost încă salvată", + "CloneProfile": "Profil de clonare", + "NoLeaveIt": "Nu, lasă-l", + "DBMigration": "Migrarea DB", + "UnableToLoadQualityDefinitions": "Nu se pot încărca definițiile de calitate", + "DelayProfile": "Profile de întârziere", + "DeleteBackupMessageText": "Sigur doriți să ștergeți copia de rezervă „{0}”?", + "DeleteTagMessageText": "Sigur doriți să ștergeți eticheta „{0}”?", + "EnableHelpText": "Activați crearea fișierului de metadate pentru acest tip de metadate", + "EnableInteractiveSearch": "Activați căutarea interactivă", + "EnableSSL": "Activați SSL", + "EnableSslHelpText": " Necesită repornirea în funcție de administrator pentru a intra în vigoare", + "ExistingTag": "Etichetă existentă", + "FeatureRequests": "Cereri de caracteristici", + "HiddenClickToShow": "Ascuns, faceți clic pentru a afișa", + "HomePage": "Pagina principala", + "Hostname": "Numele gazdei", + "IgnoredAddresses": "Adrese ignorate", + "Importing": "Importând", + "IndexerLongTermStatusCheckAllClientMessage": "Toți indexatorii nu sunt disponibili din cauza unor eșecuri de mai mult de 6 ore", + "IndexerLongTermStatusCheckSingleClientMessage": "Indexatori indisponibili din cauza unor eșecuri de mai mult de 6 ore: {0}", + "IndexerPriority": "Prioritatea indexerului", + "MinutesNinety": "90 de minute: {0}", + "MinutesSixty": "60 de minute: {0}", + "Mode": "Mod", + "MovieDetailsNextMovie": "Detalii film: Următorul film", + "MovieDetailsPreviousMovie": "Detalii film: Filmul anterior", + "MovieIndexScrollTop": "Index film: Derulați sus", + "NoBackupsAreAvailable": "Nu sunt disponibile copii de rezervă", + "NoLogFiles": "Nu există fișiere jurnal", + "NoTagsHaveBeenAddedYet": "Nu s-au adăugat încă etichete", + "NotificationTriggers": "Declanșatoare de notificări", + "OpenBrowserOnStart": "Deschideți browserul la pornire", + "PageSizeHelpText": "Numărul de articole de afișat pe fiecare pagină", + "PendingChangesMessage": "Aveți modificări nesalvate, sunteți sigur că doriți să părăsiți această pagină?", + "PendingChangesStayReview": "Rămâneți și examinați modificările", + "ResetAPIKey": "Resetați cheia API", + "RestartNow": "Reporniți acum", + "SettingsShowRelativeDates": "Afișați datele relative", + "ShownClickToHide": "Afișat, faceți clic pentru a ascunde", + "ShowSearch": "Afișați Căutare", + "TagCannotBeDeletedWhileInUse": "Nu poate fi șters în timpul utilizării", + "TagIsNotUsedAndCanBeDeleted": "Eticheta nu este utilizată și poate fi ștearsă", + "TagsHelpText": "Se aplică filmelor cu cel puțin o etichetă potrivită", + "Tomorrow": "Mâine", + "Torrent": "Torente", + "UILanguage": "Limbajul UI", + "UISettings": "Setări UI", + "UnableToAddANewAppProfilePleaseTryAgain": "Imposibil de adăugat un nou profil de calitate, încercați din nou.", + "UnableToAddANewIndexerPleaseTryAgain": "Imposibil de adăugat un nou indexer, încercați din nou.", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Imposibil de adăugat un nou indexer, încercați din nou.", + "UpdateScriptPathHelpText": "Calea către un script personalizat care preia un pachet de actualizare extras și se ocupă de restul procesului de actualizare", + "Uptime": "Timp de funcționare", + "UseProxy": "Utilizarea proxy", + "Username": "Nume de utilizator", + "Version": "Versiune", + "Yesterday": "Ieri", + "AcceptConfirmationModal": "Acceptați Modul de confirmare", + "DeleteIndexerProxyMessageText": "Sigur doriți să ștergeți eticheta „{0}”?", + "Disabled": "Dezactivat", + "Discord": "Discordie", + "Docker": "Docher", + "Donations": "Donații", + "Downloading": "Descărcarea", + "EnableColorImpairedMode": "Activați modul afectat de culoare", + "EnabledHelpText": "Activați această listă pentru utilizare în Radarr", + "Interval": "Interval", + "Manual": "Manual", + "UnableToLoadGeneralSettings": "Nu se pot încărca setările generale", + "UnableToLoadHistory": "Istoricul nu poate fi încărcat", + "UnsavedChanges": "Modificări nesalvate", + "UpdateAutomaticallyHelpText": "Descărcați și instalați automat actualizări. Veți putea în continuare să instalați din System: Updates", + "AddDownloadClient": "Adăugați client de descărcare", + "AddIndexer": "Adăugați Indexer", + "AllIndexersHiddenDueToFilter": "Toate filmele sunt ascunse datorită filtrelor aplicate.", + "DeleteDownloadClient": "Ștergeți clientul de descărcare", + "DeleteDownloadClientMessageText": "Sigur doriți să ștergeți clientul de descărcare „{0}”?", + "ConnectSettings": "Setări conectare", + "CouldNotConnectSignalR": "Nu s-a putut conecta la SignalR, UI nu se va actualiza", + "EnableAutomaticAdd": "Activați adăugarea automată", + "GeneralSettings": "setari generale", + "Grabs": "Apuca", + "Port": "Port", + "PortNumber": "Numarul portului", + "Reset": "Resetați", + "SendAnonymousUsageData": "Trimiteți date de utilizare anonime", + "SSLCertPassword": "Parola SSL Cert", + "SSLCertPasswordHelpText": "Parola pentru fișierul pfx", + "SSLCertPath": "Calea SSL Cert", + "SSLCertPathHelpText": "Calea către fișierul pfx", + "SSLPort": "Port SSL", + "StartTypingOrSelectAPathBelow": "Începeți să tastați sau selectați o cale de mai jos", + "StartupDirectory": "Director de pornire", + "SuggestTranslationChange": "Sugerează modificarea traducerii", + "ApplicationStatusCheckSingleClientMessage": "Liste indisponibile datorită erorilor: {0}", + "ApplyTags": "Aplicați etichete", + "ApplyTagsHelpTexts1": "Cum se aplică etichete filmelor selectate", + "ApplyTagsHelpTexts2": "Adăugare: adăugați etichetele la lista de etichete existentă", + "ApplyTagsHelpTexts3": "Eliminați: eliminați etichetele introduse", + "ApplyTagsHelpTexts4": "Înlocuire: înlocuiți etichetele cu etichetele introduse (nu introduceți etichete pentru a șterge toate etichetele)", + "Automatic": "Automat", + "DeleteApplicationMessageText": "Sigur doriți să ștergeți notificarea „{0}”?", + "DownloadClientUnavailable": "Clientul de descărcare nu este disponibil", + "Exception": "Excepție" } diff --git a/src/NzbDrone.Core/Localization/Core/ru.json b/src/NzbDrone.Core/Localization/Core/ru.json index f161e41c6..9b3de53b1 100644 --- a/src/NzbDrone.Core/Localization/Core/ru.json +++ b/src/NzbDrone.Core/Localization/Core/ru.json @@ -3,7 +3,6 @@ "CloneProfile": "Клонировать профиль", "CloneIndexer": "Клонировать индексер", "ClientPriority": "Приоритет клиента", - "Activity": "Активность", "Backups": "Резервные копии", "BackupRetentionHelpText": "Автоматические резервные копии старше указанного периода будут автоматически удалены", "BackupNow": "Сделать резервную копию", @@ -18,14 +17,345 @@ "AppDataLocationHealthCheckMessage": "Обновление будет не возможно, во избежание удаления данных программы во время обновления", "ApiKey": "API ключ", "Analytics": "Аналитика", - "AllMoviesHiddenDueToFilter": "Все фильмы спрятаны в соответствии с фильтром.", - "AddNewMessage": "Добавить новый фильм очень просто! Начни печатать название фильма, который хочешь добавить", - "AddMovie": "Добавить фильм", "AddIndexer": "Добавить индексер", "Added": "Добавлено", "Actions": "Действия", "About": "Подробности", "DeleteBackupMessageText": "Вы уверены, что хотите удалить резервную копию '{0}'?", "DeleteBackup": "Удалить резервную копию", - "Delete": "Удалить" + "Delete": "Удалить", + "MinutesHundredTwenty": "120 минут: {0}", + "MinutesNinety": "90 минут: {0}", + "MinutesSixty": "60 минут: {0}", + "MonoTlsCheckMessage": "Radarr Mono 4.x tls включён, удалите настройку MONO_TLS_PROVIDER=legacy", + "NoLinks": "Нет ссылок", + "Refresh": "Обновить", + "RefreshMovie": "Обновить фильм", + "RSS": "RSS", + "SendAnonymousUsageData": "Отправить анонимные данные об использовании", + "UnableToLoadHistory": "Не удалось загрузить историю", + "MonoVersionCheckUpgradeRecommendedMessage": "Установленная Mono версия {0} поддерживается, но рекомендуем обновить до версии {1}.", + "MoreInfo": "Ещё инфо", + "MovieDetailsNextMovie": "Подробности фильма: следующий фильм", + "MovieIndexScrollTop": "Индекс фильма: промотать вверх", + "Size": "Размер", + "OpenBrowserOnStart": "Открывать браузер при запуске", + "OpenThisModal": "Открыть это модальное окно", + "Options": "Опции", + "PackageVersion": "Версия пакета", + "PageSize": "Размер страницы", + "PageSizeHelpText": "Количество показываемое на каждой страницы", + "Password": "Пароль", + "Peers": "Пиры", + "Pending": "В ожидании", + "PendingChangesDiscardChanges": "Не применять изменения и выйти", + "PendingChangesStayReview": "Оставайтесь и просмотрите изменения", + "Port": "Порт", + "PortNumber": "Номер порта", + "PreferredSize": "Предпочитаемый размер", + "QualityDefinitions": "Определения качества", + "LogFiles": "Файлы журнала", + "Details": "Подробности", + "DownloadClients": "Клиенты для скачивания", + "Filename": "Имя файла", + "Files": "Файлы", + "Filter": "Фильтр", + "Importing": "Импортирование", + "IndexerStatusCheckAllClientMessage": "Все индексаторы недоступны из-за ошибок", + "LogLevel": "Уровень журнала", + "LogLevelTraceHelpTextWarning": "Отслеживание журнала желательно включать только на короткое время", + "Logs": "Журналы", + "Manual": "Ручной", + "MaximumLimits": "Максимальные ограничения", + "Mechanism": "Механизм", + "NoBackupsAreAvailable": "Нет резервных копий", + "DeleteDownloadClientMessageText": "Вы уверены, что хотите удалить программу для скачивания '{0}'?", + "Edit": "Редактирование", + "Enable": "Включить", + "Indexer": "Индексатор", + "SettingsShortDateFormat": "Короткий формат даты", + "SettingsShowRelativeDates": "Показать относительные даты", + "SettingsShowRelativeDatesHelpText": "Показывать относительные (сегодня / вчера / и т. д.) или абсолютные даты", + "DeleteIndexer": "Удалить индексер", + "Docker": "Docker", + "FocusSearchBox": "Поле поиска в фокусе", + "Reset": "Сбросить", + "Add": "Добавить", + "EnableSSL": "Включить SSL", + "IndexerFlags": "Флаги индексатора", + "Priority": "Приоритет", + "Updates": "Обновления", + "Usenet": "Usenet", + "AcceptConfirmationModal": "Окно подтверждения", + "Today": "Сегодня", + "DeleteIndexerProxyMessageText": "Вы уверены, что хотите удалить тэг '{0}'?", + "ExistingMovies": "Существующие фильм(ы)", + "ExistingTag": "Существующий тэг", + "Failed": "Неудачно", + "IndexerProxyStatusCheckSingleClientMessage": "Индексаторы недоступны из-за ошибок: {0}", + "Indexers": "Индексаторы", + "InteractiveSearch": "Интерактивный поиск", + "Interval": "Интервал", + "KeyboardShortcuts": "Горячие клавиши", + "Language": "Язык", + "Languages": "Языки", + "LastWriteTime": "Последнее время записи", + "LaunchBrowserHelpText": " Открывать браузер и переходить на страницу Radarr при запуске программы.", + "Level": "Уровень", + "MinimumLimits": "Минимальные ограничения", + "Ok": "Ok", + "AddDownloadClient": "Добавить программу для скачивания", + "UpdateMechanismHelpText": "Используйте встроенную в Radarr функцию обновления или скрипт", + "IndexerStatusCheckSingleClientMessage": "Индексаторы недоступны из-за ошибок: {0}", + "NoMinimumForAnyRuntime": "Нет минимума для любого времени", + "NoTagsHaveBeenAddedYet": "Теги еще не добавлены", + "UnableToLoadTags": "Невозможно загрузить теги", + "AnalyticsEnabledHelpText": "Отправлять в Radarr информацию о использовании и ошибках. Анонимная статистика включает в себя информацию о браузере, какие страницы загружены, сообщения об ошибках, а так же операционной системе. Мы используем эту информацию для выявления ошибок, а так же для разработки нового функционала.", + "ApplyTagsHelpTexts4": "Заменить: Изменить существующие тэги на введенные тэги (оставьте пустым чтобы очистить все тэги)", + "AuthenticationMethodHelpText": "Необходим логин и пароль для доступа в Radarr", + "BackupFolderHelpText": "Относительные пути будут в каталоге AppData Radarr", + "BeforeUpdate": "До обновления", + "BindAddress": "Привязать адрес", + "BindAddressHelpText": "Действительный IP4-адрес или '*' для всех интерфейсов", + "Branch": "Ветка", + "BranchUpdate": "Ветвь для обновления Radarr", + "BranchUpdateMechanism": "Ветвь, используемая внешним механизмом обновления", + "BypassProxyForLocalAddresses": "Обход прокси для локальных адресов", + "Cancel": "Отменить", + "CancelPendingTask": "Вы уверены, что хотите убрать данную задачу из очереди?", + "CertificateValidation": "Проверка сертификата", + "CertificateValidationHelpText": "Изменить строгое подтверждение сертификации НТТР", + "ChangeHasNotBeenSavedYet": "Изменения ещё не вступили в силу", + "Clear": "Очистить", + "CloseCurrentModal": "Закрыть текущее окно", + "Columns": "Столбцы", + "Component": "Компонент", + "ConnectionLost": "Соединение прервано", + "Connections": "Соединения", + "ConnectSettings": "Настройки соединения", + "CouldNotConnectSignalR": "Не возможно подключиться к SignalR, интерфейс не будет обновляться", + "Custom": "Настраиваемый", + "CustomFilters": "Настраиваемые фильтры", + "Date": "Дата", + "Dates": "Даты", + "DBMigration": "Перенос БД", + "DelayProfile": "Профиль приостановки", + "DeleteIndexerMessageText": "Вы уверены что хотите удалить индексер '{0}'?", + "DeleteNotification": "Удалить уведомление", + "DeleteNotificationMessageText": "Вы уверены, что хотите удалить уведомление '{0}'?", + "DeleteTag": "Удалить тэг", + "DeleteTagMessageText": "Вы уверены, что хотите удалить тэг '{0}'?", + "Disabled": "Выключено", + "Discord": "Discord", + "Donations": "Пожертвования", + "DownloadClient": "Загрузчик", + "DownloadClientCheckNoneAvailableMessage": "Ни один загрузчик не доступен", + "DownloadClientCheckUnableToCommunicateMessage": "Невозможно связаться с {0}.", + "DownloadClientSettings": "Настройки клиента скачиваний", + "DownloadClientStatusCheckAllClientMessage": "Все клиенты для скачивания недоступны из-за ошибок", + "DownloadClientStatusCheckSingleClientMessage": "Клиенты для скачивания недоступны из-за ошибок: {0}", + "DownloadClientUnavailable": "Программа для скачивания недоступна", + "Downloading": "Скачивается", + "EnableAutoHelpText": "Если включено, то Radarr автоматически добавит фильмы из списка", + "EnableAutomaticAdd": "Включить автоматическое добавление", + "EnableAutomaticSearch": "Включить автоматический поиск", + "EnableAutomaticSearchHelpText": "Будет использовано для автоматических поисков через интерфейс или Radarr", + "EnableAutomaticSearchHelpTextWarning": "Будет использовано при автоматических поисках", + "EnableColorImpairedModeHelpText": "Стиль изменён чтобы слабовидящие лучше различали цвета", + "EnableCompletedDownloadHandlingHelpText": "Автоматически импортировать завершенные скачивания", + "Enabled": "Включено", + "EnabledHelpText": "Использовать этот лист в Radarr", + "EnableHelpText": "Создавать файл метаданных для это типа метаданных", + "EnableInteractiveSearch": "Включить интерактивный поиск", + "EnableRss": "Включить RSS", + "Fixed": "Исправлено", + "Folder": "Папка", + "ForMoreInformationOnTheIndividualDownloadClients": "Для дополнительной информации пл программам скачивания нажмите эту кнопку.", + "General": "Основное", + "GeneralSettings": "Основные настройки", + "GeneralSettingsSummary": "Порт, SSL, логин/пароль, прокси, аналитика и обновления", + "Grabbed": "Захвачено", + "Grabs": "Захватить", + "Health": "Здоровье", + "HealthNoIssues": "С вашей конфигурацией нет проблем", + "HiddenClickToShow": "Скрыто, нажмите чтобы показать", + "HideAdvanced": "Скрыть расширенные", + "History": "История", + "HomePage": "Домашняя страница", + "Host": "Хост", + "Hostname": "Имя хоста", + "IgnoredAddresses": "Проигнорированные адреса", + "IllRestartLater": "Перезапущу позднее", + "IncludeHealthWarningsHelpText": "Включая предупреждения о здоровье", + "IndexerLongTermStatusCheckAllClientMessage": "Все индексаторы недоступны из-за ошибок за последние 6 часов", + "IndexerLongTermStatusCheckSingleClientMessage": "Все индексаторы недоступны из-за ошибок за последние 6 часов: {0}", + "IndexerPriority": "Приоритет индексаторов", + "IndexerPriorityHelpText": "Приоритет индексаторов от 1 (наивысший) до 50 (низший). По-умолчанию: 25.", + "IndexerProxyStatusCheckAllClientMessage": "Все индексаторы недоступны из-за ошибок", + "Info": "Информация", + "Logging": "Журналирование", + "Message": "Сообщение", + "MIA": "MIA", + "Mode": "Режим", + "MonoVersion": "Моно версия", + "MovieDetailsPreviousMovie": "Подробности фильма: предыдущий фильм", + "MovieIndexScrollBottom": "Индекс фильма: промотать в низ", + "Movies": "Фильмы", + "Name": "Имя", + "New": "Новый", + "NoChanges": "Нет изменений", + "NoLeaveIt": "Нет, оставить", + "NoLimitForAnyRuntime": "Нет ограничений для любого времени", + "NoLogFiles": "Нет файлов журнала", + "NoUpdatesAreAvailable": "Нет обновлений", + "OAuthPopupMessage": "Ваш браузер блокирует всплывающие окна", + "OnHealthIssueHelpText": "По вопросам здоровья", + "PendingChangesMessage": "У вас есть несохраненные изменения. Вы уверены, что хотите покинуть эту страницу?", + "Presets": "Предустановки", + "PriorityHelpText": "Установите приоритет нескольких клиентов загрузки. Круговой алгоритм используется для клиентов с таким же приоритетом.", + "PrioritySettings": "Приоритет", + "Protocol": "Протокол", + "Proxy": "Прокси", + "ProxyBypassFilterHelpText": "Используйте ',' в качестве разделителя и '*.' как подстановочный знак для поддоменов", + "ProxyCheckBadRequestMessage": "Не удалось проверить прокси. Код: {0}", + "ProxyCheckFailedToTestMessage": "Не удалось проверить прокси: {0}", + "ProxyCheckResolveIpMessage": "Не удалось преобразовать IP-адрес для настроенного прокси-хоста {0}", + "ProxyPasswordHelpText": "Нужно ввести имя пользователя и пароль только если они необходимы. В противном случае оставьте их пустыми.", + "ProxyType": "Тип прокси", + "ProxyUsernameHelpText": "Нужно ввести имя пользователя и пароль только если они необходимы. В противном случае оставьте их пустыми.", + "PtpOldSettingsCheckMessage": "Следующие индексаторы PassThePopcorn устарели и должны быть обновлены: {0}", + "QualitySettings": "Настройки качества", + "Queue": "Очередь", + "ReadTheWikiForMoreInformation": "Прочтите Wiki для получения дополнительной информации", + "ReleaseBranchCheckOfficialBranchMessage": "Ветка {0} не является допустимой веткой выпуска Radarr, вы не будете получать обновления", + "ReleaseStatus": "Статус релиза", + "Reload": "Перезагрузить", + "RemovedFromTaskQueue": "Удалено из очереди задач", + "RemoveFilter": "Удалить фильтр", + "RemovingTag": "Удаление тега", + "ResetAPIKey": "Сбросить API ключ", + "Restart": "Перезапустить", + "RestartNow": "Перезапустить сейчас", + "RestartRequiredHelpTextWarning": "Для вступления в силу требуется перезапуск", + "Restore": "Восстановить", + "RestoreBackup": "Восстановить из резервной копии", + "Restrictions": "Ограничения", + "Result": "Результат", + "Retention": "Удержание", + "RSSIsNotSupportedWithThisIndexer": "RSS не поддерживается этим индексатором", + "Save": "Сохранить", + "SaveChanges": "Сохранить изменения", + "SaveSettings": "Сохранить настройки", + "Scheduled": "Запланировано", + "ScriptPath": "Путь к скрипту", + "Search": "Поиск", + "Security": "Безопасность", + "Seeders": "Сиды", + "SelectAll": "Выбрать все", + "SetTags": "Установить теги", + "Settings": "Настройки", + "SettingsEnableColorImpairedMode": "Версия для слабовидящих", + "SettingsEnableColorImpairedModeHelpText": "Стиль изменён чтобы слабовидящие лучше различали цвета", + "SettingsLongDateFormat": "Длинный формат даты", + "SettingsTimeFormat": "Формат времени", + "ShowAdvanced": "Показать расширенные", + "ShownClickToHide": "Показано, нажмите чтобы скрыть", + "ShowSearch": "Показать поиск", + "ShowSearchHelpText": "Показать копку поиска по наведению", + "Shutdown": "Выключить", + "Sort": "Сортировка", + "Source": "Источник", + "SSLCertPassword": "Пароль SSL сертификата", + "SSLCertPasswordHelpText": "Пароль pfx файла", + "SSLCertPath": "Путь SSL сертификата", + "SSLCertPathHelpText": "Путь к pfx файлу", + "StartTypingOrSelectAPathBelow": "Начните вводить или выберите путь ниже", + "StartupDirectory": "Каталог автозагрузки", + "Status": "Статус", + "Style": "Стиль", + "SuggestTranslationChange": "Предложить изменение перевода", + "SystemTimeCheckMessage": "Расхождение системного времени более чем на 1 день. Запланированные задачи могут работать некорректно, пока не будет исправлено время", + "TableOptionsColumnsMessage": "Выберите, какие столбцы отображаются и в каком порядке", + "TagIsNotUsedAndCanBeDeleted": "Тег не используется и может быть удален", + "TagsHelpText": "Применимо к фильмам с хотя бы одним подходящим тегом", + "TagsSettingsSummary": "Посмотрите все теги и способы их использования. Неиспользуемые теги можно удалить", + "Tasks": "Задачи", + "Test": "Тест", + "TestAll": "Тестировать все", + "TestAllClients": "Тестировать всех клиентов", + "Time": "Время", + "Title": "Название", + "Tomorrow": "Завтра", + "Torrent": "Торренты", + "Torrents": "Торренты", + "Type": "Тип", + "UI": "Пользовательский интерфейс", + "UILanguage": "Язык пользовательского интерфейса", + "UILanguageHelpTextWarning": "Требуется перезагрузка браузера", + "UISettings": "Настройки пользовательского интерфейса", + "UnableToAddANewApplicationPleaseTryAgain": "Невозможно добавить новое уведомление, попробуйте еще раз.", + "UnableToAddANewAppProfilePleaseTryAgain": "Не удалось добавить новый профиль качества. Повторите попытку.", + "UnableToAddANewDownloadClientPleaseTryAgain": "Не удалось добавить новый клиент загрузки, попробуйте еще раз.", + "UnableToAddANewIndexerPleaseTryAgain": "Не удалось добавить новый индексатор, повторите попытку.", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Не удалось добавить новый индексатор, повторите попытку.", + "UnableToAddANewNotificationPleaseTryAgain": "Невозможно добавить новое уведомление, попробуйте еще раз.", + "UnableToLoadBackups": "Невозможно загрузить резервные копии", + "UnableToLoadDownloadClients": "Невозможно загрузить загрузчики", + "UnableToLoadGeneralSettings": "Невозможно загрузить общие настройки", + "UnableToLoadIndexers": "Не удалось загрузить индексаторы", + "UnableToLoadNotifications": "Невозможно загрузить уведомления", + "UnableToLoadQualityDefinitions": "Не удалось загрузить определения качества", + "UnableToLoadUISettings": "Не удалось загрузить настройки пользовательского интерфейса", + "UnsavedChanges": "Несохраненные изменения", + "UnselectAll": "Снять все выделения", + "UpdateAutomaticallyHelpText": "Автоматически загружать и устанавливать обновления. Вы так же можете установить в Система: Обновления", + "UpdateCheckStartupNotWritableMessage": "Невозможно установить обновление так как загрузочная папка '{0}' недоступна для записи для пользователя '{1}'.", + "UpdateCheckStartupTranslocationMessage": "Не удается установить обновление, поскольку папка автозагрузки \"{0}\" находится в папке перемещения приложений.", + "UpdateCheckUINotWritableMessage": "Невозможно установить обновление так как UI папка '{0}' недоступна для записи для пользователя '{1}'.", + "UpdateScriptPathHelpText": "Путь к пользовательскому скрипту, который обрабатывает остатки после процесса обновления", + "Uptime": "Время работы", + "URLBase": "Базовый URL", + "UrlBaseHelpText": "Для поддержки обратного прокси, по умолчанию пусто", + "UseProxy": "Использовать прокси", + "Username": "Пользователь", + "Version": "Версия", + "View": "Просмотр", + "AddingTag": "Добавить ярлык", + "SSLPort": "SSL порт", + "UILanguageHelpText": "Язык, который Radarr будет использовать для пользовательского интерфейса", + "EnableInteractiveSearchHelpTextWarning": "Поиск не поддерживается с этим индексатором", + "EnableMediaInfoHelpText": "Извлекать из файлов видео разрешение, длительность и информацию о кодеках. Это может привести к высокой активности диска и сети во время сканирования.", + "EnableSslHelpText": " Требуется перезапуск от администратора", + "ErrorLoadingContents": "Ошибка при загрузке содержимого", + "Events": "События", + "EventType": "Тип события", + "Exception": "Исключение", + "FeatureRequests": "Будущие запросы", + "Warn": "Предупреждать", + "Wiki": "Wiki", + "YesCancel": "Да, отменить", + "Yesterday": "Вчера", + "NotificationTriggers": "Триггеры уведомления", + "ApplicationStatusCheckAllClientMessage": "Все листы недоступны из-за ошибок", + "Automatic": "Автоматически", + "ConnectionLostAutomaticMessage": "Radarr попытается соединиться автоматически или нажмите кнопку внизу.", + "DeleteApplicationMessageText": "Вы уверены, что хотите удалить уведомление '{0}'?", + "DeleteDownloadClient": "Удалить программу для скачивания", + "EnableColorImpairedMode": "Версия для слабовидящих", + "EnableInteractiveSearchHelpText": "Будет использовано при автоматических поисках", + "Error": "Ошибка", + "NoChange": "Нет изменений", + "Age": "Возраст", + "All": "Все", + "AllIndexersHiddenDueToFilter": "Все фильмы спрятаны в соответствии с фильтром.", + "AppDataDirectory": "AppData директория", + "Reddit": "Reddit", + "System": "Система", + "TableOptions": "Опции таблицы", + "TagCannotBeDeletedWhileInUse": "Невозможно удалить во время использования", + "Tags": "Тэги", + "ApplicationStatusCheckSingleClientMessage": "Листы недоступны из-за ошибок: {0}", + "ApplyTagsHelpTexts1": "Как добавить ярлыки к выбранным фильмам", + "ApplyTagsHelpTexts2": "Добавить: добавить ярлыки к существующему списку", + "EditIndexer": "Редактировать индексатор" } diff --git a/src/NzbDrone.Core/Localization/Core/sk.json b/src/NzbDrone.Core/Localization/Core/sk.json index 64d835697..3769e165e 100644 --- a/src/NzbDrone.Core/Localization/Core/sk.json +++ b/src/NzbDrone.Core/Localization/Core/sk.json @@ -31,5 +31,19 @@ "AutomaticSearch": "Automatické vyhľadávanie", "BackupIntervalHelpText": "Interval medzi automatickými zálohami", "BackupRetentionHelpText": "Automatické zálohy staršie než doba uchovania budú automaticky vyčistené", - "BranchUpdateMechanism": "Vetva používaná externým mechanizmom aktualizácie" + "BranchUpdateMechanism": "Vetva používaná externým mechanizmom aktualizácie", + "DeleteApplicationMessageText": "Naozaj chcete zmazať značku formátu {0} ?", + "DeleteBackupMessageText": "Naozaj chcete zmazať značku formátu {0} ?", + "DeleteIndexerMessageText": "Naozaj chcete zmazať značku formátu {0} ?", + "DeleteIndexerProxyMessageText": "Naozaj chcete zmazať značku formátu {0} ?", + "DeleteNotificationMessageText": "Naozaj chcete zmazať značku formátu {0} ?", + "DeleteTagMessageText": "Naozaj chcete zmazať značku formátu {0} ?", + "AllIndexersHiddenDueToFilter": "Všetky filmy sú skryté kvôli použitému filtru.", + "AnalyticsEnabledHelpText": "Odosielajte anonymné informácie o používaní a chybách na servery Readarru. To zahŕňa informácie o vašom prehliadači, ktoré stránky Radarr WebUI používate, hlásenia chýb a taktiež verziu operačného systému a spúšťacieho prostredia. Tieto informácie použijeme k uprednostňovaniu funkcií a oprav chýb.", + "ApplyTagsHelpTexts1": "Ako použiť značky na vybrané filmy", + "ApplyTagsHelpTexts2": "Pridať: Pridajte značky do existujúceho zoznamu značiek", + "AuthenticationMethodHelpText": "Vyžadovať používateľské meno a heslo pre prístup k Radarru", + "BackupFolderHelpText": "Relatívne cesty budú v priečinku AppData Radarru", + "BranchUpdate": "Vetva, ktorá sa má použiť k aktualizácií Radarru", + "DeleteDownloadClientMessageText": "Naozaj chcete zmazať značku formátu {0} ?" } diff --git a/src/NzbDrone.Core/Localization/Core/sv.json b/src/NzbDrone.Core/Localization/Core/sv.json index 3bbad8583..3e0dca5f5 100644 --- a/src/NzbDrone.Core/Localization/Core/sv.json +++ b/src/NzbDrone.Core/Localization/Core/sv.json @@ -1,14 +1,10 @@ { - "Activity": "Aktivitet", "About": "Om", "Languages": "Språk", "Language": "Språk", "IndexerStatusCheckSingleClientMessage": "Indexerare otillgängliga på grund av fel: {0}", "IndexerStatusCheckAllClientMessage": "Samtliga indexerare otillgängliga på grund av fel", - "IndexerSearchCheckNoAutomaticMessage": "Inga indexerare tillgängliga med Automatisk Sök aktiverat, Prowlarr kommer inte tillhandahålla automatiska sökresultat", "Indexers": "Indexerare", - "ImportMechanismHealthCheckMessage": "Aktivera Avklarad nedladdningshantering", - "iCalLink": "iCal-länk", "Host": "Värd", "History": "Historia", "HideAdvanced": "Dölj avancerat", @@ -24,7 +20,6 @@ "DownloadClients": "Nedladdningsklienter", "DownloadClientCheckUnableToCommunicateMessage": "Kommunikation med {0} ej möjlig.", "DownloadClientCheckNoneAvailableMessage": "Ingen nedladdningsklient tillgänglig", - "Discover": "Upptäck", "Delete": "Radera", "Dates": "Datum", "Date": "Datum", @@ -32,7 +27,6 @@ "Connections": "Anslutningar", "Connect": "Anslut", "Clear": "Rensa", - "Blacklist": "Svartlista", "BackupNow": "Säkerhets- kopiera", "Backup": "Säkerhetskopiering", "AppDataLocationHealthCheckMessage": "Uppdatering ej möjlig för att AppData inte skall raderas", @@ -41,11 +35,8 @@ "MoreInfo": "Mer info", "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls workaround är aktiverad, överväg att ta bort \"MONO_TLS_PROVIDER=legacy environment\"-alternativet", "MonoNotNetCoreCheckMessage": "Var vänlig uppgradera till .NET Core-versionen av Prowlarr", - "MinAvailability": "Minsta tillgänglighet", - "ManualImport": "Manuell import", "Logging": "Loggning", "LogFiles": "Loggfiler", - "Wanted": "Önskade", "View": "Vy", "Updates": "Uppdateringar", "UpdateCheckUINotWritableMessage": "Ej möjligt att installera uppdatering då användargränssnittsmappen '{0}' inte är skrivbar för användaren '{1}'.", @@ -67,19 +58,15 @@ "SetTags": "Ange taggar", "SelectAll": "Välj samtliga", "Security": "Säkerhet", - "SearchAll": "Sök samtliga", "Search": "Sök", "Scheduled": "Schemalagt", "SaveChanges": "Spara ändringar", - "RootFolderCheckSingleMessage": "Rotmapp saknas: {0}", "Restrictions": "Restriktioner", "RestoreBackup": "Återställ säkerhetskopia", - "RemovedMovieCheckMultipleMessage": "Filmerna {0} är borttagna från TMDb", "ReleaseBranchCheckOfficialBranchMessage": "Gren {0} är inte en giltig gren av Prowlarr, du kommer ej erhålla uppdateringar", "ReleaseBranchCheckPreviousVersionMessage": "Gren {0} är ämnad en tidigare version av Prowlarr, välj gren 'Aphrodite' för ytterligare uppdateringar", "Refresh": "Uppdatera", "Queue": "Kö", - "QualityProfile": "Kvalitetsprofil", "QualityDefinitions": "Kvalitetsdefinitioner", "PtpOldSettingsCheckMessage": "Följande PassThePopcorn-indexerare har inaktuella inställningar och bör uppdateras: {0}", "ProxyCheckResolveIpMessage": "Misslyckades att slå upp IP-adressen till konfigurerad proxyvärd {0}", @@ -87,9 +74,6 @@ "ProxyCheckBadRequestMessage": "Test av proxy misslyckades. Statuskod: {0}", "Proxy": "Proxy", "Protocol": "Protokoll", - "PreviewRename": "Förhandsvisa namnbyte", - "MonitoredOnly": "Endast Bevakade", - "ListsSettingsSummary": "Importera listor, listuteslutningar", "LastWriteTime": "Senast skriven tid", "Indexer": "Indexerare", "Grabbed": "Hämtad", @@ -108,7 +92,6 @@ "NoChanges": "Inga ändringar", "NoChange": "Ingen förändring", "Movies": "Filmer", - "Movie": "Film", "Warn": "Varna", "Type": "Typ", "Title": "Titel", @@ -125,7 +108,6 @@ "Reload": "Ladda om", "Peers": "Peers", "PageSize": "Sidstorlek", - "OrganizeModalAllPathsRelative": "Samtliga sögvägar är relativa till:", "OAuthPopupMessage": "Popups blockeras av din webbläsare", "Ok": "Ok", "Name": "Namn", @@ -144,5 +126,243 @@ "Cancel": "Avbryt", "Apply": "TIllämpa", "Age": "Ålder", - "SystemTimeCheckMessage": "Systemklockan går fel med mer än en dag. Schemalagda uppgifter kan få problem att köras innan tiden är korrigerad" + "SystemTimeCheckMessage": "Systemklockan går fel med mer än en dag. Schemalagda uppgifter kan få problem att köras innan tiden är korrigerad", + "HomePage": "Hemsida", + "IndexerPriority": "Indexerprioritet", + "Pending": "I väntan på", + "Reddit": "Reddit", + "IndexerProxyStatusCheckAllClientMessage": "Samtliga indexerare otillgängliga på grund av fel", + "MovieDetailsNextMovie": "Filmdetaljer: Nästa film", + "NoLinks": "Inga länkar", + "NoTagsHaveBeenAddedYet": "Inga taggar har lagts till ännu", + "NotificationTriggers": "Meddelandeutlösare", + "Presets": "Förinställningar", + "PrioritySettings": "Prioritet", + "RefreshMovie": "Uppdatera filmen", + "RemoveFilter": "Ta bort filter", + "ResetAPIKey": "Återställa API-nyckel", + "RSS": "RSS", + "SettingsEnableColorImpairedMode": "Aktivera färgskadat läge", + "ClientPriority": "Klient prioritet", + "SettingsTimeFormat": "Tidsformat", + "UnableToAddANewAppProfilePleaseTryAgain": "Det gick inte att lägga till en ny kvalitetsprofil. Försök igen.", + "UnableToAddANewDownloadClientPleaseTryAgain": "Inte möjligt att lägga till en ny nedladdningsklient, var god försök igen.", + "UnableToAddANewIndexerPleaseTryAgain": "Inte möjligt att lägga till en ny indexerare, var god försök igen.", + "UnableToAddANewNotificationPleaseTryAgain": "Det gick inte att lägga till ett nytt meddelande, försök igen.", + "UpdateScriptPathHelpText": "Sökväg till ett anpassat skript som tar ett extraherat uppdateringspaket och hanterar resten av uppdateringsprocessen", + "Usenet": "Usenet", + "UseProxy": "Använd proxy", + "Username": "Användarnamn", + "Version": "Version", + "Wiki": "Wiki", + "YesCancel": "Ja, avbryt", + "Yesterday": "Igår", + "ShowSearchHelpText": "Visa sökknappen på svävaren", + "ConnectSettings": "Anslutnings inställningar", + "Downloading": "Laddar ned", + "EditIndexer": "Redigera indexerare", + "EnableAutomaticSearchHelpText": "Används när automatiska sökningar utförs via användargränssnittet eller av Radarr", + "EnableColorImpairedMode": "Aktivera färgskadat läge", + "EnableMediaInfoHelpText": "Extrahera videoinformation som upplösning, runtime och codec-information från filer. Detta kräver att Radarr läser delar av filen som kan orsaka hög disk- eller nätverksaktivitet under skanningar.", + "Password": "Lösenord", + "Port": "Port", + "Add": "Lägg till", + "ApplyTags": "Tillämpa taggar", + "ApplyTagsHelpTexts1": "Så här applicerar du taggar på de valda filmerna", + "RestartRequiredHelpTextWarning": "Kräver omstart för att träda i kraft", + "Restore": "Återställ", + "Result": "Resultat", + "Retention": "Bibehållande", + "ApplyTagsHelpTexts2": "Lägg till: Lägg till taggarna i den befintliga listan med taggar", + "CertificateValidation": "Validering av certifikat", + "CloneIndexer": "Klona indexerare", + "RSSIsNotSupportedWithThisIndexer": "RSS stöds inte av denna indexerare", + "SaveSettings": "Spara inställningar", + "ScriptPath": "Skriptsökväg", + "CouldNotConnectSignalR": "Kunde inte ansluta till SignalR, UI uppdateras inte", + "DeleteTag": "Radera tagg", + "Hostname": "Värdnamn", + "MinutesSixty": "60 minuter: {0}", + "Mode": "Läge", + "NoMinimumForAnyRuntime": "Inget minimum för någon körtid", + "Docker": "Docker", + "Enable": "Aktivera", + "ProxyPasswordHelpText": "Du behöver bara ange ett användarnamn och lösenord om det krävs. Lämna dem tomma annars.", + "Automatic": "Automatiskt", + "BindAddress": "Bindningsadress", + "Branch": "Gren", + "CloseCurrentModal": "Stäng nuvarande modal", + "DBMigration": "DB Migration", + "DelayProfile": "Fördröjande profil", + "DeleteApplicationMessageText": "Är du säker på att du vill radera aviseringen '{0}'?", + "DeleteIndexer": "Radera indexerare", + "Discord": "Discord", + "Donations": "Donationer", + "DownloadClientSettings": "Inställningar för Nedladdningsklient", + "EnableCompletedDownloadHandlingHelpText": "Importera automatiskt färdiga nedladdningar från nedladdningsklienten", + "EnabledHelpText": "Aktivera den här listan för användning i Radarr", + "EnableRss": "Aktivera RSS", + "MinimumLimits": "Minsta gränser", + "MinutesNinety": "90 minuter: {0}", + "MovieDetailsPreviousMovie": "Filmdetaljer: Föregående film", + "MovieIndexScrollBottom": "Filmindex: Skrolla ner", + "PendingChangesDiscardChanges": "Kassera ändringar och lämna", + "ProxyType": "Proxy-typ", + "RestartNow": "Starta om nu", + "StartupDirectory": "Startkatalog", + "TestAllClients": "Testa samtliga klienter", + "Today": "Idag", + "UILanguageHelpText": "Språk som Radarr kommer att använda för användargränssnitt", + "UISettings": "UI-inställningar", + "UnableToLoadNotifications": "Det gick inte att läsa in aviseringar", + "UnableToLoadTags": "Det gick inte att ladda taggar", + "AcceptConfirmationModal": "Acceptera bekräftelsemodal", + "AreYouSureYouWantToResetYourAPIKey": "Är du säker på att du vill nollställa din API-nyckel?", + "Authentication": "Autentisera", + "LogLevelTraceHelpTextWarning": "Spårloggning bör endast aktiveras tillfälligt", + "DeleteIndexerProxyMessageText": "Är du säker på att du vill radera taggen '{0}'?", + "DeleteNotification": "Radera avisering", + "DownloadClientUnavailable": "Nedladdningsklient är otillgänglig", + "Fixed": "Fast", + "FocusSearchBox": "Fokus sökruta", + "IncludeHealthWarningsHelpText": "Inkludera hälsovarningar", + "IndexerFlags": "Indexerflaggor", + "AddDownloadClient": "Lägg till nedladdningsklient", + "AddIndexer": "Lägg till indexerare", + "AddingTag": "Lägg till tagg", + "Enabled": "Aktiverad", + "Exception": "Undantag", + "IndexerProxyStatusCheckSingleClientMessage": "Indexerare otillgängliga på grund av fel: {0}", + "UILanguageHelpTextWarning": "Omladdning av webbläsaren krävs", + "UnableToLoadHistory": "Det gick inte att läsa in historiken", + "Uptime": "Drifttid", + "URLBase": "URL-bas", + "UnableToLoadUISettings": "Det går inte att ladda UI-inställningarna", + "UnsavedChanges": "Osparade ändringar", + "UpdateAutomaticallyHelpText": "Automatiskt ladda ned och installera uppdateringar. Du kommer fortfarande att kunna installera från System: Uppdateringar", + "UrlBaseHelpText": "För omvänd proxy-stöd är standard tom", + "AnalyticsEnabledHelpText": "Skicka anonym användning och felinformation till Radarrs servrar. Detta inkluderar information i din webbläsare, vilka Radarr WebUI-sidor du använder, felrapportering samt operativsystem och runtime-version. Vi kommer att använda denna information för att prioritera funktioner och buggfixar.", + "AppDataDirectory": "AppData-katalog", + "ApplicationStatusCheckSingleClientMessage": "Listor otillgängliga på grund av fel: {0}", + "ApplyTagsHelpTexts3": "Ta bort: Ta bort de angivna taggarna", + "ApplyTagsHelpTexts4": "Ersätt: Ersätt taggarna med de angivna taggarna (ange inga taggar för att rensa alla taggar)", + "BindAddressHelpText": "Giltig IP4-adress eller '*' för alla gränssnitt", + "BranchUpdate": "Gren att använda för att uppdatera Radarr", + "BranchUpdateMechanism": "Gren som används av extern uppdateringsmekanism", + "BypassProxyForLocalAddresses": "Bypass Proxy för lokala adresser", + "CancelPendingTask": "Är du säker på att du vill avbryta den väntande uppgiften?", + "CertificateValidationHelpText": "Ändra hur strikt valideringen av HTTPS certifikat är", + "ChangeHasNotBeenSavedYet": "Ändringen har inte sparats än", + "CloneProfile": "Klona profil", + "Custom": "Beställnings", + "DeleteBackup": "Radera säkerhetskopia", + "DeleteBackupMessageText": "Är du säker på att du vill radera säkerhetskopian '{0}'?", + "DeleteDownloadClient": "Radera nedladdningsklient", + "DeleteDownloadClientMessageText": "Är du säker på att du vill ta bort nedladdningsklienten '{0}'?", + "DeleteNotificationMessageText": "Är du säker på att du vill radera aviseringen '{0}'?", + "DeleteTagMessageText": "Är du säker på att du vill radera taggen '{0}'?", + "Disabled": "Inaktiverad", + "EnableAutoHelpText": "Om det är aktiverat läggs filmer automatiskt till Radarr från den här listan", + "EnableAutomaticAdd": "Aktivera automatisk tillägg", + "EnableAutomaticSearch": "Aktivera automatisk sökning", + "EnableAutomaticSearchHelpTextWarning": "Används när interaktiv sökning används", + "EnableColorImpairedModeHelpText": "Ändrad stil för att göra det möjligt för användare med färgstörning att bättre skilja färgkodad information", + "EnableHelpText": "Aktivera metadatafilskapande för denna metadatatyp", + "EnableInteractiveSearch": "Aktivera interaktiv sökning", + "EnableInteractiveSearchHelpText": "Används när interaktiv sökning används", + "EnableInteractiveSearchHelpTextWarning": "Sökning stöds ej av denna indexerare", + "EnableSSL": "Aktivera SSL", + "EnableSslHelpText": " Kräver omstart som administratör för att träda i kraft", + "ErrorLoadingContents": "Fel vid inläsning av innehåll", + "ExistingMovies": "Befintliga film(er)", + "ExistingTag": "Befintlig tagg", + "FeatureRequests": "Funktionsbegäranden", + "ForMoreInformationOnTheIndividualDownloadClients": "Klicka på informationsknapparna för mer information om de enskilda nedladdningsklienterna.", + "GeneralSettings": "Allmänna Inställningar", + "Grabs": "Hämta", + "HiddenClickToShow": "Dold, klicka för att visa", + "IgnoredAddresses": "Ignorerade adresser", + "IllRestartLater": "Jag startar om senare", + "Importing": "Importerar", + "IndexerLongTermStatusCheckAllClientMessage": "Alla indexerare är inte tillgängliga på grund av fel i mer än 6 timmar", + "IndexerLongTermStatusCheckSingleClientMessage": "Indexatorer är inte tillgängliga på grund av misslyckanden i mer än sex timmar: {0}", + "IndexerPriorityHelpText": "Indexeringsprioritet från 1 (högst) till 50 (lägst). Standard: 25.", + "InteractiveSearch": "Interaktiv sökning", + "Interval": "Intervall", + "LaunchBrowserHelpText": " Öppna en webbläsare och navigera till Radarr-hemsidan vid appstart.", + "Logs": "Loggar", + "Manual": "Manuell", + "MaximumLimits": "Maximala gränser", + "Mechanism": "Mekanism", + "MIA": "MIA", + "MinutesHundredTwenty": "120 minuter: {0}", + "MonoVersionCheckUpgradeRecommendedMessage": "För närvarande installerad monoversion {0} stöds men uppgradering till {1} rekommenderas.", + "MovieIndexScrollTop": "Filmindex: Skrolla upp", + "NoUpdatesAreAvailable": "Inga uppdateringar är tillgängliga", + "OnHealthIssueHelpText": "På hälsofrågan", + "OpenBrowserOnStart": "Öppna webbläsare vid start", + "OpenThisModal": "Öppna den här modalen", + "PackageVersion": "Paketversion", + "PageSizeHelpText": "Antal objekt som ska visas på varje sida", + "PendingChangesMessage": "Du har osparade ändringar, är du säker på att du vill lämna sidan?", + "PendingChangesStayReview": "Bo och granska ändringar", + "PortNumber": "Portnummer", + "PreferredSize": "Önskad storlek", + "Priority": "Prioritet", + "PriorityHelpText": "Prioritera flera nedladdningsklienter. Round-Robin används för kunder med samma prioritet.", + "ProxyBypassFilterHelpText": "Använd ',' som separator och '*.' som ett jokertecken för underdomäner", + "ProxyUsernameHelpText": "Du behöver bara ange ett användarnamn och lösenord om det krävs. Lämna dem tomma annars.", + "QualitySettings": "Kvalitetsalternativ", + "ReadTheWikiForMoreInformation": "Läs Wiki för mer information", + "RemovedFromTaskQueue": "Borttagen från uppgiftskön", + "RemovingTag": "Ta bort taggen", + "Reset": "Återställa", + "SendAnonymousUsageData": "Skickar anonym användningsinformation", + "SettingsEnableColorImpairedModeHelpText": "Ändrad stil för att göra det möjligt för användare med färgstörning att bättre skilja färgkodad information", + "SettingsLongDateFormat": "Långt datumformat", + "SettingsShortDateFormat": "Kort datumformat", + "SettingsShowRelativeDates": "Visa relativa datum", + "SettingsShowRelativeDatesHelpText": "Visa relativa (Idag / Igår / etc) eller absoluta datum", + "ShownClickToHide": "Visad, klicka för att dölja", + "ShowSearch": "Visa sök", + "SSLCertPassword": "SSL-certifierat lösenord", + "SSLCertPasswordHelpText": "Lösenord för pfx-fil", + "SSLCertPath": "SSL-certifierad sökväg", + "SSLCertPathHelpText": "Sökväg till pfx-fil", + "SSLPort": "SSL-port", + "StartTypingOrSelectAPathBelow": "Börja skriva eller välj en sökväg nedan", + "SuggestTranslationChange": "Föreslå översättningsändring", + "TagCannotBeDeletedWhileInUse": "Kan inte tas bort när den används", + "TagIsNotUsedAndCanBeDeleted": "Taggen används inte och kan raderas", + "TagsHelpText": "Gäller filmer med minst en matchande tagg", + "Tomorrow": "Igår", + "Torrent": "Torrenter", + "UILanguage": "UI-språk", + "UnableToAddANewApplicationPleaseTryAgain": "Det gick inte att lägga till ett nytt meddelande, försök igen.", + "UnableToLoadBackups": "Det gick inte att ladda säkerhetskopior", + "DeleteIndexerMessageText": "Är du säker på att du vill ta bort indexeraren '{0}'?", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Inte möjligt att lägga till en ny indexerare, var god försök igen.", + "UnableToLoadGeneralSettings": "Det går inte att läsa in allmänna inställningar", + "UnableToLoadIndexers": "Det går inte att ladda indexerare", + "New": "Ny", + "NoBackupsAreAvailable": "Inga säkerhetskopior tillgängliga", + "NoLeaveIt": "Nej, lämna det", + "NoLimitForAnyRuntime": "Ingen gräns för någon körtid", + "UnableToLoadQualityDefinitions": "Det går inte att ladda kvalitetsdefinitioner", + "AuthenticationMethodHelpText": "Kräva användarnamn och lösenord för att komma åt Radarr", + "AutomaticSearch": "Automatisk sökning", + "BackupFolderHelpText": "Relativa sökvägar finns under Radarrs AppData-katalog", + "BackupIntervalHelpText": "Intervall mellan automatiska säkerhetskopior", + "BackupRetentionHelpText": "Automatiska säkerhetskopior som är äldre än lagringsperioden rensas automatiskt", + "Backups": "Säkerhetskopior", + "BeforeUpdate": "Innan uppdatering", + "Torrents": "Torrenter", + "AllIndexersHiddenDueToFilter": "Samtliga filmer är dolda på grund av tillämpade filter.", + "ApiKey": "API-nyckel", + "ApplicationStatusCheckAllClientMessage": "Samtliga listor otillgängliga på grund av fel", + "LogLevel": "Loggnivå", + "MonoVersion": "Mono version", + "NoLogFiles": "Inga loggfiler", + "UnableToLoadDownloadClients": "Det gick inte att ladda nedladdningsklienter", + "UpdateMechanismHelpText": "Använd Radarrs inbyggda uppdaterare eller ett skript" } diff --git a/src/NzbDrone.Core/Localization/Core/th.json b/src/NzbDrone.Core/Localization/Core/th.json index 0967ef424..2ecf0e205 100644 --- a/src/NzbDrone.Core/Localization/Core/th.json +++ b/src/NzbDrone.Core/Localization/Core/th.json @@ -1 +1,361 @@ -{} +{ + "All": "ทั้งหมด", + "ApiKey": "คีย์ API", + "Apply": "สมัคร", + "AutomaticSearch": "ค้นหาอัตโนมัติ", + "ExistingTag": "แท็กที่มีอยู่", + "Host": "โฮสต์", + "NotificationTriggers": "ทริกเกอร์การแจ้งเตือน", + "View": "ดู", + "AllIndexersHiddenDueToFilter": "ภาพยนตร์ทั้งหมดถูกซ่อนเนื่องจากใช้ฟิลเตอร์", + "Analytics": "การวิเคราะห์", + "Backup": "การสำรองข้อมูล", + "BackupFolderHelpText": "เส้นทางสัมพัทธ์จะอยู่ภายใต้ไดเรกทอรี AppData ของ Radarr", + "EnableAutoHelpText": "หากเปิดใช้งานภาพยนตร์จะถูกเพิ่มลงใน Radarr โดยอัตโนมัติจากรายการนี้", + "EnableAutomaticAdd": "เปิดใช้งานการเพิ่มอัตโนมัติ", + "Importing": "กำลังนำเข้า", + "IncludeHealthWarningsHelpText": "รวมคำเตือนด้านสุขภาพ", + "Pending": "รอดำเนินการ", + "PortNumber": "หมายเลขพอร์ต", + "Restart": "เริ่มต้นใหม่", + "SSLCertPathHelpText": "พา ธ ไปยังไฟล์ pfx", + "IndexerProxyStatusCheckAllClientMessage": "รายการทั้งหมดไม่พร้อมใช้งานเนื่องจากความล้มเหลว", + "IndexerProxyStatusCheckSingleClientMessage": "ตัวจัดทำดัชนีไม่พร้อมใช้งานเนื่องจากความล้มเหลว: {0}", + "Indexers": "ดัชนี", + "Info": "ข้อมูล", + "InteractiveSearch": "การค้นหาแบบโต้ตอบ", + "LastWriteTime": "เวลาเขียนล่าสุด", + "LaunchBrowserHelpText": " เปิดเว็บเบราว์เซอร์และไปที่หน้าแรกของ Radarr เมื่อเริ่มแอป", + "MinimumLimits": "ขีด จำกัด ขั้นต่ำ", + "MinutesHundredTwenty": "120 นาที: {0}", + "MinutesNinety": "90 นาที: {0}", + "MinutesSixty": "60 นาที: {0}", + "Mode": "โหมด", + "MonoTlsCheckMessage": "วิธีแก้ปัญหา Radarr Mono 4.x tls ยังคงเปิดใช้งานอยู่ให้พิจารณาลบตัวเลือก MONO_TLS_PROVIDER = สภาพแวดล้อมเดิม", + "MonoVersion": "เวอร์ชันโมโน", + "MonoVersionCheckUpgradeRecommendedMessage": "ปัจจุบันรองรับเวอร์ชัน Mono {0} ที่ติดตั้งแล้ว แต่แนะนำให้อัปเกรดเป็น {1}", + "MoreInfo": "ข้อมูลเพิ่มเติม", + "MovieDetailsNextMovie": "รายละเอียดภาพยนตร์: ภาพยนตร์เรื่องต่อไป", + "MovieDetailsPreviousMovie": "รายละเอียดภาพยนตร์: ภาพยนตร์เรื่องก่อนหน้า", + "MovieIndexScrollBottom": "ดัชนีภาพยนตร์: เลื่อนด้านล่าง", + "MovieIndexScrollTop": "ดัชนีภาพยนตร์: เลื่อนด้านบน", + "Movies": "ภาพยนตร์", + "New": "ใหม่", + "NoLinks": "ไม่มีลิงค์", + "OpenThisModal": "เปิด Modal นี้", + "Options": "ตัวเลือก", + "PackageVersion": "เวอร์ชันแพ็คเกจ", + "Peers": "เพื่อนร่วมงาน", + "PendingChangesDiscardChanges": "ยกเลิกการเปลี่ยนแปลงและออก", + "PendingChangesMessage": "คุณยังไม่ได้บันทึกการเปลี่ยนแปลงแน่ใจไหมว่าต้องการออกจากหน้านี้", + "PendingChangesStayReview": "อยู่และตรวจสอบการเปลี่ยนแปลง", + "ProxyCheckFailedToTestMessage": "ไม่สามารถทดสอบพร็อกซี: {0}", + "ProxyPasswordHelpText": "คุณจะต้องป้อนชื่อผู้ใช้และรหัสผ่านหากจำเป็นเท่านั้น เว้นว่างไว้เป็นอย่างอื่น", + "ShowAdvanced": "แสดงขั้นสูง", + "ShownClickToHide": "แสดงคลิกเพื่อซ่อน", + "ShowSearch": "แสดงการค้นหา", + "Source": "ที่มา", + "StartTypingOrSelectAPathBelow": "เริ่มพิมพ์หรือเลือกเส้นทางด้านล่าง", + "SuggestTranslationChange": "แนะนำการเปลี่ยนคำแปล", + "TableOptionsColumnsMessage": "เลือกคอลัมน์ที่สามารถมองเห็นได้และลำดับที่จะปรากฏ", + "TagCannotBeDeletedWhileInUse": "ไม่สามารถลบได้ขณะใช้งาน", + "TagIsNotUsedAndCanBeDeleted": "ไม่ได้ใช้แท็กและสามารถลบได้", + "Tags": "แท็ก", + "TagsHelpText": "ใช้กับภาพยนตร์ที่มีแท็กที่ตรงกันอย่างน้อยหนึ่งแท็ก", + "TagsSettingsSummary": "ดูแท็กทั้งหมดและวิธีการใช้งาน แท็กที่ไม่ได้ใช้สามารถลบออกได้", + "Tasks": "งาน", + "Test": "ทดสอบ", + "TestAll": "ทดสอบทั้งหมด", + "TestAllClients": "ทดสอบลูกค้าทั้งหมด", + "Time": "เวลา", + "Title": "หัวข้อ", + "UILanguageHelpText": "ภาษาที่ Radarr จะใช้สำหรับ UI", + "UILanguageHelpTextWarning": "จำเป็นต้องโหลดเบราว์เซอร์ใหม่", + "UnableToAddANewIndexerPleaseTryAgain": "ไม่สามารถเพิ่มตัวสร้างดัชนีใหม่ได้โปรดลองอีกครั้ง", + "UnableToAddANewIndexerProxyPleaseTryAgain": "ไม่สามารถเพิ่มตัวสร้างดัชนีใหม่ได้โปรดลองอีกครั้ง", + "UnableToLoadDownloadClients": "ไม่สามารถโหลดไคลเอนต์ดาวน์โหลด", + "UpdateCheckUINotWritableMessage": "ไม่สามารถติดตั้งการอัปเดตเนื่องจากโฟลเดอร์ UI \"{0}\" ไม่สามารถเขียนได้โดยผู้ใช้ \"{1}\"", + "Updates": "อัปเดต", + "UpdateScriptPathHelpText": "พา ธ ไปยังสคริปต์แบบกำหนดเองที่ใช้แพ็กเกจโปรแกรมปรับปรุงที่แยกออกมาและจัดการส่วนที่เหลือของกระบวนการอัพเดต", + "AddDownloadClient": "เพิ่มไคลเอนต์ดาวน์โหลด", + "Yesterday": "เมื่อวานนี้", + "Added": "เพิ่มแล้ว", + "About": "เกี่ยวกับ", + "AcceptConfirmationModal": "ยอมรับรูปแบบการยืนยัน", + "Actions": "การดำเนินการ", + "DeleteIndexerProxyMessageText": "แน่ใจไหมว่าต้องการลบรายการ \"{0}\"", + "DeleteTagMessageText": "แน่ใจไหมว่าต้องการลบแท็ก \"{0}\"", + "Disabled": "ปิดการใช้งาน", + "Discord": "ไม่ลงรอยกัน", + "Docker": "นักเทียบท่า", + "Failed": "ล้มเหลว", + "FeatureRequests": "คำขอคุณสมบัติ", + "Filename": "ชื่อไฟล์", + "Files": "ไฟล์", + "Filter": "กรอง", + "Fixed": "แก้ไขแล้ว", + "FocusSearchBox": "ช่องค้นหาโฟกัส", + "Folder": "โฟลเดอร์", + "Message": "ข้อความ", + "NoUpdatesAreAvailable": "ไม่มีการอัปเดต", + "PtpOldSettingsCheckMessage": "ตัวสร้างดัชนี PassThePopcorn ต่อไปนี้ได้เลิกใช้การตั้งค่าและควรได้รับการอัปเดต: {0}", + "QualityDefinitions": "คำจำกัดความคุณภาพ", + "QualitySettings": "การตั้งค่าคุณภาพ", + "Queue": "คิว", + "ReadTheWikiForMoreInformation": "อ่าน Wiki สำหรับข้อมูลเพิ่มเติม", + "Reddit": "Reddit", + "Refresh": "รีเฟรช", + "RefreshMovie": "รีเฟรชภาพยนตร์", + "Reload": "โหลดซ้ำ", + "RemovedFromTaskQueue": "ลบออกจากคิวงาน", + "RemoveFilter": "ลบตัวกรอง", + "RemovingTag": "กำลังลบแท็ก", + "Reset": "รีเซ็ต", + "Save": "บันทึก", + "SaveChanges": "บันทึกการเปลี่ยนแปลง", + "Scheduled": "กำหนดเวลา", + "ScriptPath": "เส้นทางสคริปต์", + "Seeders": "Seeders", + "SelectAll": "เลือกทั้งหมด", + "SystemTimeCheckMessage": "เวลาของระบบปิดมากกว่า 1 วัน งานที่ตั้งเวลาไว้อาจทำงานไม่ถูกต้องจนกว่าจะมีการแก้ไขเวลา", + "UnableToAddANewNotificationPleaseTryAgain": "ไม่สามารถเพิ่มการแจ้งเตือนใหม่โปรดลองอีกครั้ง", + "UnableToLoadBackups": "ไม่สามารถโหลดข้อมูลสำรอง", + "UnableToLoadNotifications": "ไม่สามารถโหลดการแจ้งเตือน", + "UnableToLoadQualityDefinitions": "ไม่สามารถโหลดคำจำกัดความคุณภาพ", + "ApplicationStatusCheckAllClientMessage": "รายการทั้งหมดไม่พร้อมใช้งานเนื่องจากความล้มเหลว", + "ApplicationStatusCheckSingleClientMessage": "รายการไม่พร้อมใช้งานเนื่องจากความล้มเหลว: {0}", + "DeleteIndexer": "ลบ Indexer", + "DeleteNotification": "ลบการแจ้งเตือน", + "IgnoredAddresses": "ที่อยู่ที่ถูกละเว้น", + "Level": "ระดับ", + "PageSizeHelpText": "จำนวนรายการที่จะแสดงในแต่ละหน้า", + "ShowSearchHelpText": "แสดงปุ่มค้นหาเมื่อวางเมาส์เหนือ", + "Shutdown": "ปิดตัวลง", + "Size": "ขนาด", + "AppDataDirectory": "ไดเรกทอรี AppData", + "ApplyTags": "ใช้แท็ก", + "ApplyTagsHelpTexts1": "วิธีใช้แท็กกับภาพยนตร์ที่เลือก", + "ApplyTagsHelpTexts2": "เพิ่ม: เพิ่มแท็กในรายการแท็กที่มีอยู่", + "ApplyTagsHelpTexts3": "ลบ: ลบแท็กที่ป้อน", + "ApplyTagsHelpTexts4": "แทนที่: แทนที่แท็กด้วยแท็กที่ป้อน (ป้อนไม่มีแท็กเพื่อล้างแท็กทั้งหมด)", + "AreYouSureYouWantToResetYourAPIKey": "แน่ใจไหมว่าต้องการรีเซ็ตคีย์ API", + "Authentication": "การรับรองความถูกต้อง", + "AuthenticationMethodHelpText": "ต้องการชื่อผู้ใช้และรหัสผ่านเพื่อเข้าถึงเรดาร์", + "Automatic": "อัตโนมัติ", + "BackupIntervalHelpText": "ช่วงเวลาระหว่างการสำรองข้อมูลอัตโนมัติ", + "BackupRetentionHelpText": "การสำรองข้อมูลอัตโนมัติที่เก่ากว่าระยะเวลาการเก็บรักษาจะถูกล้างโดยอัตโนมัติ", + "Backups": "การสำรองข้อมูล", + "BeforeUpdate": "ก่อนการอัปเดต", + "BindAddress": "ผูกที่อยู่", + "BindAddressHelpText": "ที่อยู่ IP4 ที่ถูกต้องหรือ \"*\" สำหรับอินเทอร์เฟซทั้งหมด", + "BranchUpdate": "สาขาที่จะใช้ในการอัปเดต Radarr", + "BranchUpdateMechanism": "สาขาที่ใช้โดยกลไกการอัพเดตภายนอก", + "BypassProxyForLocalAddresses": "บายพาสพร็อกซีสำหรับที่อยู่ท้องถิ่น", + "CancelPendingTask": "แน่ใจไหมว่าต้องการยกเลิกงานที่รอดำเนินการนี้", + "ChangeHasNotBeenSavedYet": "ยังไม่ได้บันทึกการเปลี่ยนแปลง", + "Clear": "ชัดเจน", + "CloneIndexer": "Clone Indexer", + "CloneProfile": "โปรไฟล์โคลน", + "Close": "ปิด", + "ConnectionLost": "ขาดการเชื่อมต่อ", + "ConnectionLostAutomaticMessage": "Radarr จะพยายามเชื่อมต่อโดยอัตโนมัติหรือคุณสามารถคลิกโหลดซ้ำด้านล่าง", + "Connections": "การเชื่อมต่อ", + "ConnectSettings": "เชื่อมต่อการตั้งค่า", + "CouldNotConnectSignalR": "ไม่สามารถเชื่อมต่อกับ SignalR UI จะไม่อัปเดต", + "Custom": "กำหนดเอง", + "CustomFilters": "ตัวกรองที่กำหนดเอง", + "Date": "วันที่", + "Dates": "วันที่", + "DBMigration": "การย้ายฐานข้อมูล", + "DelayProfile": "โปรไฟล์ล่าช้า", + "Delete": "ลบ", + "DeleteApplicationMessageText": "แน่ใจไหมว่าต้องการลบการแจ้งเตือน \"{0}\"", + "DeleteBackup": "ลบข้อมูลสำรอง", + "DeleteBackupMessageText": "แน่ใจไหมว่าต้องการลบข้อมูลสำรอง \"{0}\"", + "DeleteDownloadClient": "ลบไคลเอนต์ดาวน์โหลด", + "DeleteIndexerMessageText": "แน่ใจไหมว่าต้องการลบตัวสร้างดัชนี \"{0}\"", + "Donations": "การบริจาค", + "DownloadClient": "ดาวน์โหลดไคลเอนต์", + "DownloadClientCheckNoneAvailableMessage": "ไม่มีไคลเอนต์ดาวน์โหลด", + "DownloadClientCheckUnableToCommunicateMessage": "ไม่สามารถสื่อสารกับ {0}", + "DownloadClients": "ดาวน์โหลดไคลเอนต์", + "DownloadClientSettings": "ดาวน์โหลด Client Settings", + "DownloadClientStatusCheckAllClientMessage": "ไคลเอนต์ดาวน์โหลดทั้งหมดไม่สามารถใช้งานได้เนื่องจากความล้มเหลว", + "DownloadClientStatusCheckSingleClientMessage": "ดาวน์โหลดไคลเอ็นต์ไม่ได้เนื่องจากความล้มเหลว: {0}", + "DownloadClientUnavailable": "ไม่สามารถดาวน์โหลดไคลเอนต์ได้", + "Downloading": "กำลังดาวน์โหลด", + "Edit": "แก้ไข", + "EditIndexer": "แก้ไข Indexer", + "Enable": "เปิดใช้งาน", + "EnableAutomaticSearch": "เปิดใช้งานการค้นหาอัตโนมัติ", + "EnableAutomaticSearchHelpText": "จะใช้เมื่อทำการค้นหาอัตโนมัติผ่าน UI หรือโดย Radarr", + "EnableAutomaticSearchHelpTextWarning": "จะใช้เมื่อใช้การค้นหาแบบโต้ตอบ", + "EnableColorImpairedMode": "เปิดใช้งานโหมดไร้สี", + "EnableColorImpairedModeHelpText": "รูปแบบที่เปลี่ยนแปลงเพื่อให้ผู้ใช้ที่มีความบกพร่องทางสีแยกแยะข้อมูลรหัสสีได้ดีขึ้น", + "EnableCompletedDownloadHandlingHelpText": "นำเข้าการดาวน์โหลดที่เสร็จสมบูรณ์โดยอัตโนมัติจากไคลเอนต์ดาวน์โหลด", + "Enabled": "เปิดใช้งาน", + "EnabledHelpText": "เปิดใช้รายการนี้เพื่อใช้ใน Radarr", + "EnableHelpText": "เปิดใช้งานการสร้างไฟล์ข้อมูลเมตาสำหรับประเภทข้อมูลเมตานี้", + "EnableInteractiveSearch": "เปิดใช้งานการค้นหาแบบโต้ตอบ", + "EnableInteractiveSearchHelpText": "จะใช้เมื่อใช้การค้นหาแบบโต้ตอบ", + "EnableInteractiveSearchHelpTextWarning": "ตัวสร้างดัชนีนี้ไม่รองรับการค้นหา", + "ForMoreInformationOnTheIndividualDownloadClients": "สำหรับข้อมูลเพิ่มเติมเกี่ยวกับไคลเอนต์ดาวน์โหลดแต่ละรายการคลิกที่ปุ่มข้อมูล", + "General": "ทั่วไป", + "GeneralSettings": "การตั้งค่าทั่วไป", + "GeneralSettingsSummary": "พอร์ต SSL ชื่อผู้ใช้ / รหัสผ่านพร็อกซีการวิเคราะห์และอัปเดต", + "Grabbed": "คว้า", + "Grabs": "คว้า", + "Health": "สุขภาพ", + "HealthNoIssues": "ไม่มีปัญหากับการกำหนดค่าของคุณ", + "HiddenClickToShow": "ซ่อนอยู่คลิกเพื่อแสดง", + "HideAdvanced": "ซ่อนขั้นสูง", + "History": "ประวัติศาสตร์", + "HomePage": "หน้าแรก", + "Hostname": "ชื่อโฮสต์", + "IllRestartLater": "ฉันจะรีสตาร์ทในภายหลัง", + "Indexer": "Indexer", + "IndexerFlags": "ดัชนีดัชนี", + "IndexerLongTermStatusCheckAllClientMessage": "ตัวจัดทำดัชนีทั้งหมดไม่สามารถใช้งานได้เนื่องจากความล้มเหลวเป็นเวลานานกว่า 6 ชั่วโมง", + "IndexerLongTermStatusCheckSingleClientMessage": "ดัชนีไม่พร้อมใช้งานเนื่องจากความล้มเหลวเป็นเวลานานกว่า 6 ชั่วโมง: {0}", + "IndexerPriority": "ลำดับความสำคัญของ Indexer", + "IndexerPriorityHelpText": "ลำดับความสำคัญของดัชนีจาก 1 (สูงสุด) ถึง 50 (ต่ำสุด) ค่าเริ่มต้น: 25.", + "IndexerStatusCheckAllClientMessage": "ตัวทำดัชนีทั้งหมดไม่พร้อมใช้งานเนื่องจากความล้มเหลว", + "IndexerStatusCheckSingleClientMessage": "ตัวจัดทำดัชนีไม่พร้อมใช้งานเนื่องจากความล้มเหลว: {0}", + "MIA": "MIA", + "NoBackupsAreAvailable": "ไม่มีการสำรองข้อมูล", + "NoChange": "ไม่มีการเปลี่ยนแปลง", + "NoChanges": "ไม่มีการเปลี่ยนแปลง", + "NoLeaveIt": "ไม่ปล่อยไว้", + "NoLimitForAnyRuntime": "ไม่มีขีด จำกัด สำหรับรันไทม์ใด ๆ", + "NoMinimumForAnyRuntime": "ไม่มีขั้นต่ำสำหรับรันไทม์ใด ๆ", + "NoTagsHaveBeenAddedYet": "ยังไม่มีการเพิ่มแท็ก", + "OAuthPopupMessage": "เบราว์เซอร์ของคุณบล็อกป๊อปอัป", + "OnHealthIssueHelpText": "เกี่ยวกับปัญหาสุขภาพ", + "OpenBrowserOnStart": "เปิดเบราว์เซอร์เมื่อเริ่มต้น", + "Port": "ท่าเรือ", + "PreferredSize": "ขนาดที่ต้องการ", + "Presets": "ค่าที่ตั้งไว้ล่วงหน้า", + "Priority": "ลำดับความสำคัญ", + "PriorityHelpText": "จัดลำดับความสำคัญของไคลเอนต์ดาวน์โหลดหลายรายการ Round-Robin ใช้สำหรับลูกค้าที่มีลำดับความสำคัญเดียวกัน", + "PrioritySettings": "ลำดับความสำคัญ", + "Protocol": "มาตรการ", + "Proxy": "พร็อกซี", + "ProxyBypassFilterHelpText": "ใช้ \",\" เป็นตัวคั่นและ \"*.\" เป็นสัญลักษณ์แทนสำหรับโดเมนย่อย", + "ProxyCheckBadRequestMessage": "ไม่สามารถทดสอบพร็อกซี StatusCode: {0}", + "Restore": "คืนค่า", + "RestoreBackup": "คืนค่าการสำรองข้อมูล", + "Restrictions": "ข้อ จำกัด", + "Retention": "การเก็บรักษา", + "RSS": "RSS", + "SendAnonymousUsageData": "ส่งข้อมูลการใช้งานแบบไม่ระบุตัวตน", + "SetTags": "ตั้งแท็ก", + "Settings": "การตั้งค่า", + "SettingsEnableColorImpairedMode": "เปิดใช้งานโหมดไร้สี", + "SettingsEnableColorImpairedModeHelpText": "รูปแบบที่เปลี่ยนแปลงเพื่อให้ผู้ใช้ที่มีความบกพร่องทางสีแยกแยะข้อมูลรหัสสีได้ดีขึ้น", + "SettingsShowRelativeDates": "แสดงวันที่สัมพัทธ์", + "SettingsShowRelativeDatesHelpText": "แสดงญาติ (วันนี้ / เมื่อวาน / ฯลฯ ) หรือวันที่แน่นอน", + "SettingsTimeFormat": "รูปแบบเวลา", + "UpdateMechanismHelpText": "ใช้ตัวอัปเดตหรือสคริปต์ในตัวของ Radarr", + "UnableToLoadGeneralSettings": "ไม่สามารถโหลดการตั้งค่าทั่วไป", + "UnableToLoadHistory": "ไม่สามารถโหลดประวัติ", + "UnableToLoadIndexers": "ไม่สามารถโหลด Indexers", + "UnableToLoadTags": "ไม่สามารถโหลดแท็ก", + "UnableToLoadUISettings": "ไม่สามารถโหลดการตั้งค่า UI", + "UnsavedChanges": "การเปลี่ยนแปลงที่ไม่ได้บันทึก", + "UnselectAll": "ไม่เลือกทั้งหมด", + "UpdateAutomaticallyHelpText": "ดาวน์โหลดและติดตั้งการอัปเดตโดยอัตโนมัติ คุณจะยังติดตั้งได้จาก System: Updates", + "UpdateCheckStartupNotWritableMessage": "ไม่สามารถติดตั้งการอัปเดตเนื่องจากโฟลเดอร์เริ่มต้น \"{0}\" ไม่สามารถเขียนได้โดยผู้ใช้ \"{1}\"", + "UpdateCheckStartupTranslocationMessage": "ไม่สามารถติดตั้งการอัปเดตได้เนื่องจากโฟลเดอร์เริ่มต้น \"{0}\" อยู่ในโฟลเดอร์การแปลแอป", + "Uptime": "เวลาทำงาน", + "URLBase": "ฐาน URL", + "UrlBaseHelpText": "สำหรับการสนับสนุน reverse proxy ค่าเริ่มต้นจะว่างเปล่า", + "UseProxy": "ใช้ Proxy", + "Username": "ชื่อผู้ใช้", + "Version": "เวอร์ชัน", + "Warn": "เตือน", + "Wiki": "วิกิ", + "Password": "รหัสผ่าน", + "ProxyUsernameHelpText": "คุณจะต้องป้อนชื่อผู้ใช้และรหัสผ่านหากจำเป็นเท่านั้น เว้นว่างไว้เป็นอย่างอื่น", + "SettingsLongDateFormat": "รูปแบบวันที่ยาว", + "SettingsShortDateFormat": "รูปแบบวันที่สั้น", + "Add": "เพิ่ม", + "CloseCurrentModal": "ปิด Modal ปัจจุบัน", + "Columns": "คอลัมน์", + "Component": "ส่วนประกอบ", + "BackupNow": "การสำรองข้อมูลในขณะนี้", + "Events": "เหตุการณ์", + "EventType": "ประเภทเหตุการณ์", + "Name": "ชื่อ", + "Result": "ผลลัพธ์", + "Usenet": "Usenet", + "YesCancel": "ใช่ยกเลิก", + "AddIndexer": "เพิ่ม Indexer", + "AddingTag": "กำลังเพิ่มแท็ก", + "Age": "อายุ", + "CertificateValidation": "การตรวจสอบใบรับรอง", + "CertificateValidationHelpText": "เปลี่ยนวิธีการตรวจสอบการรับรอง HTTPS ที่เข้มงวด", + "ClientPriority": "ลำดับความสำคัญของลูกค้า", + "DeleteNotificationMessageText": "แน่ใจไหมว่าต้องการลบการแจ้งเตือน \"{0}\"", + "DeleteTag": "ลบแท็ก", + "EnableSSL": "เปิดใช้งาน SSL", + "ProxyCheckResolveIpMessage": "ไม่สามารถแก้ไขที่อยู่ IP สำหรับโฮสต์พร็อกซีที่กำหนดค่าไว้ {0}", + "ProxyType": "ประเภทพร็อกซี", + "Cancel": "ยกเลิก", + "NoLogFiles": "ไม่มีไฟล์บันทึก", + "Details": "รายละเอียด", + "EnableMediaInfoHelpText": "ดึงข้อมูลวิดีโอเช่นความละเอียดรันไทม์และข้อมูลตัวแปลงสัญญาณออกจากไฟล์ สิ่งนี้ต้องใช้ Radarr เพื่ออ่านบางส่วนของไฟล์ซึ่งอาจทำให้เกิดดิสก์หรือกิจกรรมเครือข่ายสูงระหว่างการสแกน", + "EnableRss": "เปิดใช้ RSS", + "EnableSslHelpText": " ต้องรีสตาร์ทในฐานะผู้ดูแลระบบจึงจะมีผล", + "Error": "ข้อผิดพลาด", + "ErrorLoadingContents": "เกิดข้อผิดพลาดในการโหลดเนื้อหา", + "Exception": "ข้อยกเว้น", + "ExistingMovies": "ภาพยนตร์ที่มีอยู่", + "Interval": "ช่วงเวลา", + "KeyboardShortcuts": "แป้นพิมพ์ลัด", + "Language": "ภาษา", + "Languages": "ภาษา", + "LogFiles": "ล็อกไฟล์", + "Logging": "การบันทึก", + "LogLevel": "ระดับบันทึก", + "LogLevelTraceHelpTextWarning": "ควรเปิดใช้งานการบันทึกการติดตามชั่วคราวเท่านั้น", + "Logs": "บันทึก", + "Manual": "คู่มือ", + "MaximumLimits": "ขีด จำกัด สูงสุด", + "Mechanism": "กลไก", + "Ok": "ตกลง", + "ResetAPIKey": "รีเซ็ตคีย์ API", + "RestartNow": "เริ่มต้นใหม่เดี๋ยวนี้", + "RestartRequiredHelpTextWarning": "ต้องรีสตาร์ทเพื่อให้มีผล", + "RSSIsNotSupportedWithThisIndexer": "RSS ไม่ได้รับการสนับสนุนกับตัวสร้างดัชนีนี้", + "Search": "ค้นหา", + "Security": "ความปลอดภัย", + "SSLCertPassword": "รหัสผ่านใบรับรอง SSL", + "SSLCertPasswordHelpText": "รหัสผ่านสำหรับไฟล์ pfx", + "SSLCertPath": "เส้นทางใบรับรอง SSL", + "SSLPort": "พอร์ต SSL", + "StartupDirectory": "ไดเร็กทอรีเริ่มต้น", + "Status": "สถานะ", + "Style": "สไตล์", + "System": "ระบบ", + "TableOptions": "ตัวเลือกตาราง", + "Today": "วันนี้", + "Tomorrow": "พรุ่งนี้", + "Torrent": "Torrents", + "Torrents": "Torrents", + "Type": "ประเภท", + "UI": "UI", + "UILanguage": "ภาษา UI", + "UISettings": "การตั้งค่า UI", + "UnableToAddANewApplicationPleaseTryAgain": "ไม่สามารถเพิ่มการแจ้งเตือนใหม่โปรดลองอีกครั้ง", + "UnableToAddANewAppProfilePleaseTryAgain": "ไม่สามารถเพิ่มโปรไฟล์คุณภาพใหม่ได้โปรดลองอีกครั้ง", + "UnableToAddANewDownloadClientPleaseTryAgain": "ไม่สามารถเพิ่มไคลเอนต์ดาวน์โหลดใหม่ได้โปรดลองอีกครั้ง", + "AnalyticsEnabledHelpText": "ส่งข้อมูลการใช้งานและข้อผิดพลาดโดยไม่ระบุชื่อไปยังเซิร์ฟเวอร์ของ Radarr ซึ่งรวมถึงข้อมูลบนเบราว์เซอร์ของคุณเพจ Radarr WebUI ที่คุณใช้การรายงานข้อผิดพลาดตลอดจนระบบปฏิบัติการและเวอร์ชันรันไทม์ เราจะใช้ข้อมูลนี้เพื่อจัดลำดับความสำคัญของคุณสมบัติและการแก้ไขข้อบกพร่อง", + "AppDataLocationHealthCheckMessage": "การอัปเดตจะเป็นไปไม่ได้เพื่อป้องกันการลบ AppData ในการอัปเดต", + "DeleteDownloadClientMessageText": "แน่ใจไหมว่าต้องการลบไคลเอนต์ดาวน์โหลด \"{0}\"", + "PageSize": "ขนาดหน้า", + "ReleaseBranchCheckOfficialBranchMessage": "สาขา {0} ไม่ใช่สาขาการเผยแพร่ Radarr ที่ถูกต้องคุณจะไม่ได้รับการอัปเดต", + "ReleaseStatus": "สถานะการเปิดตัว", + "SaveSettings": "บันทึกการตั้งค่า", + "Branch": "สาขา", + "Sort": "จัดเรียง" +} diff --git a/src/NzbDrone.Core/Localization/Core/tr.json b/src/NzbDrone.Core/Localization/Core/tr.json index 1d82db118..0330a7025 100644 --- a/src/NzbDrone.Core/Localization/Core/tr.json +++ b/src/NzbDrone.Core/Localization/Core/tr.json @@ -6,25 +6,20 @@ "Connections": "Bağlantılar", "Connect": "Bağlan", "Clear": "Temizle", - "AddMovies": "Filimler ekle", "Sort": "Çeşitle", "SetTags": "Etiketleri Ayarla", "Scheduled": "Tarifeli", - "RootFolder": "Kök Klasör", "ProxyCheckResolveIpMessage": "{0} Yapılandırılmış Proxy Ana Bilgisayarının IP Adresi çözülemedi", "ProxyCheckFailedToTestMessage": "Proxy ile test edilemedi: {0}", "ProxyCheckBadRequestMessage": "Proxy ile test edilemedi. DurumKodu: {0}", "Proxy": "Proxy", - "MonitoredOnly": "Sadece İzlenenler", "Logging": "Logging", "LogFiles": "Log dosyaları", - "ImportFirstTip": "Dosyalarınızın dosya adlarında kaliteyi dahil etmeyi emin olun. Örneğin.", "Host": "Ana bilgisayar", "GeneralSettingsSummary": "Port, SSL, kullanıcı adı/şifre, proxy, analitikler ve güncellemeler", "Folder": "Klasör", "Files": "Dosyalar", "Filename": "Dosya adı", - "Crew": "Oyuncular", "AppDataLocationHealthCheckMessage": "Güncellemede AppData'nın silinmesini önlemek için güncelleme mümkün olmayacak", "Actions": "Etkiler", "About": "Hakkında", @@ -47,11 +42,9 @@ "Settings": "Ayarlar", "SelectAll": "Hepsini seç", "Security": "Güvenlik", - "SearchAll": "Tümünü ara", "Search": "Ara", "SaveChanges": "Değişiklikleri Kaydet", "Restrictions": "Kısıtlamalar", - "RemovedMovieCheckSingleMessage": "{0} filmi TMDb'den çıkarıldı", "ReleaseStatus": "Yayın Durumu", "ReleaseBranchCheckPreviousVersionMessage": "Dal {0}, Prowlarr'ın önceki bir versiyon için, dalı daha fazla güncelleme için 'Aphrodite' olarak ayarlayın", "ReleaseBranchCheckOfficialBranchMessage": "Dal {0} geçerli bir Prowlarr sürüm dalı değil, güncelleme almayacaksınız", @@ -66,11 +59,9 @@ "MoreInfo": "Daha fazla bilgi", "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls geçici çözümü hala etkin, MONO_TLS_PROVIDER=legacy seçeneğini kaldırmayı düşünün", "MonoNotNetCoreCheckMessage": "Lütfen Prowlarr'ın .NET Core sürümüne güncelle", - "MediaInfoDllCheckMessage": "Medya Bilgi Kütüphanesi yüklenemedi {0}", "LastWriteTime": "Son Yazma Zamanı", "Languages": "Diller", "Language": "Dil", - "iCalLink": "iCal Bağlantısı", "History": "Tarih", "HideAdvanced": "Gelişmiş'i Gizle", "Health": "Sağlık", @@ -79,11 +70,297 @@ "Failed": "Başarısız oldu", "Edit": "Düzenle", "DownloadClientCheckUnableToCommunicateMessage": "{0} ile iletişim kurulamıyor.", - "DelayProfiles": "Gecikme Profilleri", "CustomFilters": "Özel Filtreler", "ConnectSettingsSummary": "Bildirimler, medya sunucularına/oynatıcılara bağlantılar ve özel komut kodları", "Analytics": "Analitik", "All": "Herşey", "Added": "Eklendi", - "Add": "Ekle" + "Add": "Ekle", + "Branch": "Şube", + "TestAllClients": "Tüm İstemcileri Test Et", + "ErrorLoadingContents": "İçerik yüklenirken hata oluştu", + "FeatureRequests": "Özellik talepleri", + "HiddenClickToShow": "Gizli, göstermek için tıklayın", + "LogLevelTraceHelpTextWarning": "İzleme günlük kaydı yalnızca geçici olarak etkinleştirilmelidir", + "Peers": "Akranlar", + "Pending": "Bekliyor", + "Presets": "Ön ayarlar", + "RemoveFilter": "Filtreyi kaldır", + "SettingsEnableColorImpairedMode": "Renk Bozukluğu Modunu Etkinleştir", + "ShowSearchHelpText": "Fareyle üzerine gelindiğinde arama düğmesini göster", + "Shutdown": "Kapat", + "TableOptions": "Masa Seçenekleri", + "UnableToLoadIndexers": "Dizinleyiciler yüklenemiyor", + "UnableToLoadTags": "Etiketler yüklenemiyor", + "UnsavedChanges": "Kaydedilmemiş Değişiklikler", + "ApplyTagsHelpTexts4": "Değiştir: Etiketleri girilen etiketlerle değiştirin (tüm etiketleri temizlemek için hiçbir etiket girmeyin)", + "Backups": "Yedeklemeler", + "BindAddress": "Bağlama Adresi", + "BypassProxyForLocalAddresses": "Yerel Adresler için Proxy'yi Atla", + "DeleteNotificationMessageText": "'{0}' bildirimini silmek istediğinizden emin misiniz?", + "EnableSslHelpText": " Etkili olması için yönetici olarak yeniden çalıştırmayı gerektirir", + "Fixed": "Sabit", + "PendingChangesMessage": "Kaydedilmemiş değişiklikleriniz var, bu sayfadan ayrılmak istediğinizden emin misiniz?", + "PendingChangesStayReview": "Kalın ve değişiklikleri inceleyin", + "Port": "Liman", + "PortNumber": "Port numarası", + "PreferredSize": "Tercih Edilen Boyut", + "RestoreBackup": "Yedeği Geri Yükle", + "RSS": "RSS", + "Save": "Kayıt etmek", + "SaveSettings": "Ayarları kaydet", + "ScriptPath": "Komut Dosyası Yolu", + "Test": "Ölçek", + "TestAll": "Tümünü Test Et", + "UnableToAddANewApplicationPleaseTryAgain": "Yeni bir bildirim eklenemiyor, lütfen tekrar deneyin.", + "YesCancel": "Evet İptal", + "ApplicationStatusCheckAllClientMessage": "Hatalar nedeniyle tüm listeler kullanılamıyor", + "CancelPendingTask": "Bu bekleyen görevi iptal etmek istediğinizden emin misiniz?", + "DeleteTag": "Etiketi Sil", + "BindAddressHelpText": "Tüm arayüzler için geçerli IP4 adresi veya '*'", + "ConnectSettings": "Bağlantı Ayarları", + "DBMigration": "DB Geçişi", + "DelayProfile": "Gecikme Profilleri", + "DeleteApplicationMessageText": "'{0}' bildirimini silmek istediğinizden emin misiniz?", + "DeleteBackup": "Yedeklemeyi Sil", + "DeleteBackupMessageText": "'{0}' yedeğini silmek istediğinizden emin misiniz?", + "DeleteDownloadClient": "İndirme İstemcisini Sil", + "DeleteDownloadClientMessageText": "İndirme istemcisini '{0}' silmek istediğinizden emin misiniz?", + "DownloadClientSettings": "İstemci Ayarlarını İndir", + "EnableAutomaticSearchHelpText": "Kullanıcı arayüzü veya Radarr tarafından otomatik aramalar yapıldığında kullanılacaktır", + "ForMoreInformationOnTheIndividualDownloadClients": "Bireysel indirme istemcileri hakkında daha fazla bilgi için bilgi düğmelerine tıklayın.", + "Hostname": "Hostname", + "OpenThisModal": "Bu Modeli Aç", + "Manual": "Manuel", + "Mechanism": "Mekanizma", + "Message": "İleti", + "MIA": "MIA", + "MonoVersion": "Mono Versiyon", + "MovieDetailsNextMovie": "Film Ayrıntıları: Sonraki Film", + "MovieDetailsPreviousMovie": "Film Detayları: Önceki Film", + "MovieIndexScrollBottom": "Film Dizini: Alta Kaydırma", + "MovieIndexScrollTop": "Film Dizini: Yukarı Kaydırma", + "NoLinks": "Bağlantı Yok", + "PackageVersion": "Paket Sürümü", + "PageSize": "Sayfa boyutu", + "PageSizeHelpText": "Her sayfada gösterilecek öğe sayısı", + "ProxyBypassFilterHelpText": "Ayırıcı olarak \",\" ve \"*\" kullanın. alt alan adları için joker karakter olarak", + "ProxyUsernameHelpText": "Gerekirse yalnızca bir kullanıcı adı ve şifre girmeniz gerekir. Aksi takdirde boş bırakın.", + "Reload": "Tekrar yükle", + "RemovedFromTaskQueue": "Görev kuyruğundan kaldırıldı", + "SendAnonymousUsageData": "Anonim Kullanım Verilerini Gönderin", + "Age": "Yaş", + "AllIndexersHiddenDueToFilter": "Uygulanan filtre nedeniyle tüm filmler gizlendi.", + "AnalyticsEnabledHelpText": "Anonim kullanım ve hata bilgilerini Radarr sunucularına gönderin. Bu, tarayıcınızla ilgili bilgileri, kullandığınız Radarr WebUI sayfalarını, hata raporlamasının yanı sıra işletim sistemi ve çalışma zamanı sürümünü içerir. Bu bilgileri, özellikleri ve hata düzeltmelerini önceliklendirmek için kullanacağız.", + "ApiKey": "API Anahtarı", + "AppDataDirectory": "AppData dizini", + "MonoVersionCheckUpgradeRecommendedMessage": "Şu anda kurulu Mono sürümü {0} desteklenmektedir, ancak {1} sürümüne yükseltilmesi önerilir.", + "NoUpdatesAreAvailable": "Güncelleme yok", + "OAuthPopupMessage": "Pop-up'lar tarayıcınız tarafından engelleniyor", + "Ok": "Tamam", + "OnHealthIssueHelpText": "Sağlık Sorunu Hakkında", + "BranchUpdate": "Radarr'ı güncellemek için kullanılacak dal", + "Close": "Kapat", + "ConnectionLostAutomaticMessage": "Radarr otomatik olarak bağlanmayı deneyecek veya aşağıdan yeniden yükle'yi tıklayabilirsiniz.", + "ApplicationStatusCheckSingleClientMessage": "Hatalar nedeniyle kullanılamayan listeler: {0}", + "ApplyTags": "Etiketleri Uygula", + "RSSIsNotSupportedWithThisIndexer": "RSS, bu indeksleyici ile desteklenmiyor", + "ApplyTagsHelpTexts3": "Kaldır: Girilen etiketleri kaldırın", + "Interval": "Aralık", + "Logs": "Kütükler", + "ApplyTagsHelpTexts1": "Seçilen filmlere etiketler nasıl uygulanır", + "Authentication": "Doğrulama", + "AuthenticationMethodHelpText": "Radarr'a erişmek için Kullanıcı Adı ve Şifre gerektir", + "BackupIntervalHelpText": "Otomatik yedeklemeler arasındaki aralık", + "BackupNow": "Şimdi yedekle", + "BackupRetentionHelpText": "Saklama süresinden daha eski olan otomatik yedeklemeler otomatik olarak temizlenecektir", + "BeforeUpdate": "Güncellemeden önce", + "BranchUpdateMechanism": "Harici güncelleme mekanizması tarafından kullanılan dal", + "CertificateValidation": "Sertifika Doğrulama", + "CertificateValidationHelpText": "HTTPS sertifika doğrulamasının ne kadar katı olduğunu değiştirin", + "ChangeHasNotBeenSavedYet": "Değişiklik henüz kaydedilmedi", + "ClientPriority": "Müşteri Önceliği", + "CloneIndexer": "Klon İndeksleyici", + "CloneProfile": "Klon Profili", + "CloseCurrentModal": "Geçerli Modeli Kapat", + "Columns": "Sütunlar", + "Component": "Bileşen", + "ConnectionLost": "Bağlantı koptu", + "DeleteIndexerProxyMessageText": "'{0}' etiketini silmek istediğinizden emin misiniz?", + "DeleteNotification": "Bildirimi Sil", + "DeleteTagMessageText": "'{0}' etiketini silmek istediğinizden emin misiniz?", + "Disabled": "Devre dışı", + "Discord": "Uyuşmazlık", + "Docker": "Liman işçisi", + "Donations": "Bağışlar", + "DownloadClient": "İstemciyi İndir", + "DownloadClientCheckNoneAvailableMessage": "İndirme istemcisi yok", + "DownloadClients": "İstemcileri İndir", + "EnableAutomaticAdd": "Otomatik Eklemeyi Etkinleştir", + "EnableAutomaticSearch": "Otomatik Aramayı Etkinleştir", + "EnableAutomaticSearchHelpTextWarning": "Etkileşimli arama kullanıldığında kullanılacak", + "EnableColorImpairedMode": "Renk Bozukluğu Modunu Etkinleştir", + "EnableColorImpairedModeHelpText": "Renk bozukluğu olan kullanıcıların renk kodlu bilgileri daha iyi ayırt etmesine olanak tanıyan değiştirilmiş stil", + "EnableCompletedDownloadHandlingHelpText": "Tamamlanan indirmeleri indirme istemcisinden otomatik olarak içe aktarın", + "EnableHelpText": "Bu meta veri türü için meta veri dosyası oluşturmayı etkinleştirin", + "EnableInteractiveSearchHelpText": "Etkileşimli arama kullanıldığında kullanılacak", + "EnableInteractiveSearchHelpTextWarning": "Bu indeksleyici ile arama desteklenmiyor", + "FocusSearchBox": "Arama Kutusuna Odaklan", + "GeneralSettings": "Genel Ayarlar", + "Grabs": "Kapmak", + "HealthNoIssues": "Yapılandırmanızla ilgili sorun yok", + "HomePage": "Ana Sayfa", + "IllRestartLater": "Daha sonra yeniden başlayacağım", + "IncludeHealthWarningsHelpText": "Sağlık Uyarılarını Dahil Et", + "IndexerFlags": "Dizin Oluşturucu Bayrakları", + "IndexerLongTermStatusCheckAllClientMessage": "6 saatten uzun süren arızalar nedeniyle tüm dizinleyiciler kullanılamıyor", + "IndexerLongTermStatusCheckSingleClientMessage": "6 saatten uzun süredir yaşanan arızalar nedeniyle dizinleyiciler kullanılamıyor: {0}", + "IndexerPriority": "Dizin Oluşturucu Önceliği", + "IndexerPriorityHelpText": "1 (En Yüksek) ila 50 (En Düşük) arasında Dizin Oluşturucu Önceliği. Varsayılan: 25.", + "IndexerStatusCheckAllClientMessage": "Hatalar nedeniyle tüm dizinleyiciler kullanılamıyor", + "IndexerStatusCheckSingleClientMessage": "Hatalar nedeniyle dizinleyiciler kullanılamıyor: {0}", + "Info": "Bilgi", + "InteractiveSearch": "Etkileşimli Arama", + "KeyboardShortcuts": "Klavye kısayolları", + "LaunchBrowserHelpText": " Bir web tarayıcısı açın ve uygulama başlangıcında Radarr ana sayfasına gidin.", + "LogLevel": "Günlük Düzeyi", + "MinimumLimits": "Minimum Limitler", + "MinutesHundredTwenty": "120 Dakika: {0}", + "MinutesNinety": "90 Dakika: {0}", + "MinutesSixty": "60 Dakika: {0}", + "Mode": "Mod", + "NoTagsHaveBeenAddedYet": "Henüz etiket eklenmedi", + "NotificationTriggers": "Bildirim Tetikleyicileri", + "OpenBrowserOnStart": "Başlangıçta tarayıcıyı aç", + "Password": "Parola", + "PendingChangesDiscardChanges": "Değişiklikleri atın ve ayrıl", + "Priority": "Öncelik", + "PriorityHelpText": "Birden çok İndirme İstemcisine öncelik verin. Round-Robin, aynı önceliğe sahip müşteriler için kullanılır.", + "PrioritySettings": "Öncelik", + "ProxyType": "Proxy Türü", + "PtpOldSettingsCheckMessage": "Aşağıdaki PassThePopcorn dizinleyicilerinin ayarları kullanımdan kaldırıldı ve güncellenmeleri gerekiyor: {0}", + "QualitySettings": "Kalite Ayarları", + "ReadTheWikiForMoreInformation": "Daha fazla bilgi için Wiki'yi okuyun", + "Reddit": "Reddit", + "RefreshMovie": "Filmi yenile", + "RemovingTag": "Etiket kaldırılıyor", + "Reset": "Sıfırla", + "ResetAPIKey": "API Anahtarını Sıfırla", + "RestartNow": "Şimdi yeniden başlat", + "Result": "Sonuç", + "Retention": "Saklama", + "SettingsEnableColorImpairedModeHelpText": "Renk bozukluğu olan kullanıcıların renk kodlu bilgileri daha iyi ayırt etmesine olanak tanıyan değiştirilmiş stil", + "SettingsLongDateFormat": "Uzun Tarih Formatı", + "SettingsShortDateFormat": "Kısa Tarih Formatı", + "SettingsShowRelativeDates": "Göreli Tarihleri Göster", + "SettingsShowRelativeDatesHelpText": "Göreli (Bugün / Dün / vb.) Veya mutlak tarihleri göster", + "SettingsTimeFormat": "Zaman formatı", + "ShownClickToHide": "Gösterildi, gizlemek için tıklayın", + "Source": "Kaynak", + "SSLCertPassword": "SSL Sertifika Parolası", + "SSLCertPasswordHelpText": "Pfx dosyası için şifre", + "SSLCertPath": "SSL Sertifika Yolu", + "SSLCertPathHelpText": "Pfx dosyasının yolu", + "SSLPort": "SSL Bağlantı Noktası", + "StartTypingOrSelectAPathBelow": "Yazmaya başlayın veya aşağıdan bir yol seçin", + "StartupDirectory": "Başlangıç dizini", + "SuggestTranslationChange": "Çeviri değişikliği önerin", + "SystemTimeCheckMessage": "Sistem saati 1 günden fazla kapalı. Zamanlanan görevler, saat düzeltilene kadar doğru çalışmayabilir", + "TableOptionsColumnsMessage": "Hangi sütunların görünür olduğunu ve hangi sırada görüneceklerini seçin", + "Title": "Başlık", + "Today": "Bugün", + "Tomorrow": "Yarın", + "Torrent": "Torrentler", + "Torrents": "Torrentler", + "Type": "Tür", + "UILanguageHelpText": "Radarr'ın UI için kullanacağı dil", + "UILanguageHelpTextWarning": "Tarayıcının Yeniden Yüklenmesi Gerekiyor", + "UISettings": "UI Ayarları", + "UnableToAddANewAppProfilePleaseTryAgain": "Yeni bir kaliteli profil eklenemiyor, lütfen tekrar deneyin.", + "UnableToAddANewDownloadClientPleaseTryAgain": "Yeni bir indirme istemcisi eklenemiyor, lütfen tekrar deneyin.", + "UnableToAddANewIndexerPleaseTryAgain": "Yeni bir dizinleyici eklenemiyor, lütfen tekrar deneyin.", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Yeni bir dizinleyici eklenemiyor, lütfen tekrar deneyin.", + "UnableToAddANewNotificationPleaseTryAgain": "Yeni bir bildirim eklenemiyor, lütfen tekrar deneyin.", + "UnableToLoadBackups": "Yedeklemeler yüklenemiyor", + "UnableToLoadHistory": "Geçmiş yüklenemiyor", + "UnableToLoadNotifications": "Bildirimler yüklenemiyor", + "UnableToLoadQualityDefinitions": "Kalite Tanımları yüklenemiyor", + "UnableToLoadUISettings": "UI ayarları yüklenemiyor", + "Yesterday": "Dün", + "AcceptConfirmationModal": "Onay Modelini Kabul Et", + "AddIndexer": "Dizin Oluşturucu Ekle", + "AddDownloadClient": "İndirme İstemcisi Ekle", + "AddingTag": "Etiket ekleniyor", + "CouldNotConnectSignalR": "SignalR'ye bağlanılamadı, kullanıcı arayüzü güncellenmeyecek", + "Custom": "Özel", + "DeleteIndexer": "Dizinleyiciyi Sil", + "DeleteIndexerMessageText": "Dizin oluşturucuyu '{0}' silmek istediğinizden emin misiniz?", + "DownloadClientStatusCheckSingleClientMessage": "Hatalar nedeniyle indirilemeyen istemciler: {0}", + "Downloading": "İndiriliyor", + "Enabled": "Etkin", + "IgnoredAddresses": "Yoksayılan Adresler", + "Importing": "İçe aktarılıyor", + "Indexer": "Dizin oluşturucu", + "DownloadClientStatusCheckAllClientMessage": "Hatalar nedeniyle tüm indirme istemcileri kullanılamıyor", + "DownloadClientUnavailable": "İndirme istemcisi kullanılamıyor", + "EditIndexer": "Dizinleyiciyi Düzenle", + "Enable": "etkinleştirme", + "EnableAutoHelpText": "Etkinleştirilirse, Filmler bu listeden Radarr'a otomatik olarak eklenecektir", + "EnabledHelpText": "Bu listeyi Radarr'da kullanmak üzere etkinleştirin", + "EnableInteractiveSearch": "Etkileşimli Aramayı Etkinleştir", + "EnableMediaInfoHelpText": "Dosyalardan çözünürlük, çalışma zamanı ve kodek bilgileri gibi video bilgilerini çıkarın. Bu, Radarr'ın dosyanın taramalar sırasında yüksek disk veya ağ etkinliğine neden olabilecek bölümlerini okumasını gerektirir.", + "EnableRss": "RSS'yi etkinleştir", + "EnableSSL": "SSL'yi etkinleştir", + "NoLeaveIt": "Hayır, Bırak", + "Error": "Hata", + "Events": "Etkinlikler", + "EventType": "Etkinlik tipi", + "Exception": "İstisna", + "ExistingMovies": "Mevcut Filmler", + "ExistingTag": "Mevcut etiket", + "IndexerProxyStatusCheckAllClientMessage": "Hatalar nedeniyle tüm dizinleyiciler kullanılamıyor", + "IndexerProxyStatusCheckSingleClientMessage": "Hatalar nedeniyle dizinleyiciler kullanılamıyor: {0}", + "Indexers": "Dizin oluşturucular", + "MaximumLimits": "Maksimum Sınırlar", + "Name": "İsim", + "New": "Yeni", + "NoBackupsAreAvailable": "Kullanılabilir yedek yok", + "NoLimitForAnyRuntime": "Herhangi bir çalışma zamanı için sınır yok", + "NoLogFiles": "Günlük dosyası yok", + "NoMinimumForAnyRuntime": "Herhangi bir çalışma süresi için minimum değer yok", + "Restart": "Tekrar başlat", + "RestartRequiredHelpTextWarning": "Etkili olması için yeniden başlatma gerektirir", + "Restore": "Onarmak", + "Seeders": "Ekme makineleri", + "TagCannotBeDeletedWhileInUse": "Kullanımdayken silinemez", + "TagIsNotUsedAndCanBeDeleted": "Etiket kullanılmaz ve silinebilir", + "TagsHelpText": "En az bir eşleşen etikete sahip filmler için geçerlidir", + "UILanguage": "UI Dili", + "UpdateScriptPathHelpText": "Çıkarılan bir güncelleme paketini alan ve güncelleme işleminin geri kalanını işleyen özel bir komut dosyasına giden yol", + "Uptime": "Uptime", + "URLBase": "URL Tabanı", + "UrlBaseHelpText": "Ters proxy desteği için varsayılan boştur", + "Usenet": "Usenet", + "UseProxy": "Proxy kullan", + "Username": "Kullanıcı adı", + "Version": "Sürüm", + "Warn": "Uyar", + "Wiki": "Wiki", + "Apply": "Uygulamak", + "BackupFolderHelpText": "Göreli yollar Radarr'ın AppData dizini altında olacaktır", + "Grabbed": "Yakalandı", + "ProxyPasswordHelpText": "Gerekirse yalnızca bir kullanıcı adı ve şifre girmeniz gerekir. Aksi takdirde boş bırakın.", + "UpdateAutomaticallyHelpText": "Güncellemeleri otomatik olarak indirin ve yükleyin. Yine de Sistem'den yükleyebileceksiniz: Güncellemeler", + "UpdateMechanismHelpText": "Radarr'ın yerleşik güncelleyicisini veya bir komut dosyasını kullanın", + "ShowSearch": "Aramayı Göster", + "UnableToLoadDownloadClients": "İndirme istemcileri yüklenemiyor", + "UnableToLoadGeneralSettings": "Genel ayarlar yüklenemiyor", + "ApplyTagsHelpTexts2": "Ekle: Etiketleri mevcut etiket listesine ekleyin", + "AreYouSureYouWantToResetYourAPIKey": "API Anahtarınızı sıfırlamak istediğinizden emin misiniz?", + "Automatic": "Otomatik", + "AutomaticSearch": "Otomatik Arama", + "Backup": "Destek olmak", + "Cancel": "İptal etmek", + "Level": "Seviye", + "Time": "Zaman" } diff --git a/src/NzbDrone.Core/Localization/Core/vi.json b/src/NzbDrone.Core/Localization/Core/vi.json index 0967ef424..bcd81e73d 100644 --- a/src/NzbDrone.Core/Localization/Core/vi.json +++ b/src/NzbDrone.Core/Localization/Core/vi.json @@ -1 +1,361 @@ -{} +{ + "HideAdvanced": "Ẩn nâng cao", + "OpenThisModal": "Mở phương thức này", + "ChangeHasNotBeenSavedYet": "Thay đổi vẫn chưa được lưu", + "Clear": "Thông thoáng", + "CustomFilters": "Bộ lọc tùy chỉnh", + "Date": "Ngày", + "Dates": "ngày", + "DBMigration": "Di chuyển DB", + "NoBackupsAreAvailable": "Không có bản sao lưu nào", + "NoChanges": "Không thay đổi", + "NoLeaveIt": "Không để nó", + "NoLimitForAnyRuntime": "Không có giới hạn cho bất kỳ thời gian chạy nào", + "NoLogFiles": "Không có tệp nhật ký", + "QualitySettings": "Cài đặt chất lượng", + "IndexerProxyStatusCheckSingleClientMessage": "Danh sách không có sẵn do lỗi: {0}", + "Indexers": "Người lập chỉ mục", + "InteractiveSearch": "Tìm kiếm tương tác", + "Message": "Thông điệp", + "MinutesHundredTwenty": "120 phút: {0}", + "MinutesNinety": "90 phút: {0}", + "MinutesSixty": "60 phút: {0}", + "Mode": "Chế độ", + "MonoTlsCheckMessage": "Giải pháp thay thế Radarr Mono 4.x tls vẫn được bật, hãy xem xét loại bỏ MONO_TLS_PROVIDER = tùy chọn môi trường kế thừa", + "Name": "Tên", + "NoLinks": "Không có liên kết", + "NoMinimumForAnyRuntime": "Không có tối thiểu cho bất kỳ thời gian chạy nào", + "NoTagsHaveBeenAddedYet": "Chưa có thẻ nào được thêm vào", + "NotificationTriggers": "Kích hoạt thông báo", + "NoUpdatesAreAvailable": "Không có bản cập nhật nào có sẵn", + "OAuthPopupMessage": "Cửa sổ bật lên đang bị trình duyệt của bạn chặn", + "OnHealthIssueHelpText": "Về vấn đề sức khỏe", + "OpenBrowserOnStart": "Mở trình duyệt khi bắt đầu", + "Options": "Tùy chọn", + "PackageVersion": "Phiên bản gói", + "PageSize": "Kích thước trang", + "PageSizeHelpText": "Số mục hiển thị trên mỗi trang", + "PendingChangesDiscardChanges": "Hủy các thay đổi và rời khỏi", + "PendingChangesMessage": "Bạn có các thay đổi chưa được lưu, bạn có chắc chắn muốn rời khỏi trang này không?", + "PendingChangesStayReview": "Ở lại và xem xét các thay đổi", + "PreferredSize": "Kích thước ưa thích", + "Presets": "Cài đặt trước", + "Priority": "Sự ưu tiên", + "PriorityHelpText": "Ưu tiên nhiều Khách hàng tải xuống. Round-Robin được sử dụng cho các khách hàng có cùng mức độ ưu tiên.", + "PrioritySettings": "Sự ưu tiên", + "Protocol": "Giao thức", + "ProxyBypassFilterHelpText": "Sử dụng ',' làm dấu phân tách và '*.' làm ký tự đại diện cho các miền phụ", + "ProxyCheckFailedToTestMessage": "Không thể kiểm tra proxy: {0}", + "ProxyCheckResolveIpMessage": "Không thể phân giải Địa chỉ IP cho Máy chủ Proxy đã Định cấu hình {0}", + "ProxyPasswordHelpText": "Bạn chỉ cần nhập tên người dùng và mật khẩu nếu được yêu cầu. Nếu không, hãy để trống chúng.", + "ProxyType": "Loại proxy", + "ProxyUsernameHelpText": "Bạn chỉ cần nhập tên người dùng và mật khẩu nếu được yêu cầu. Nếu không, hãy để trống chúng.", + "PtpOldSettingsCheckMessage": "Các trình lập chỉ mục PassThePopcorn sau đây có cài đặt không được dùng nữa và sẽ được cập nhật: {0}", + "QualityDefinitions": "Định nghĩa chất lượng", + "Reddit": "Reddit", + "Refresh": "Làm tươi", + "ReleaseBranchCheckOfficialBranchMessage": "Nhánh {0} không phải là nhánh phát hành Radarr hợp lệ, bạn sẽ không nhận được cập nhật", + "ReleaseStatus": "Tình trạng phát hành", + "Reload": "Nạp lại", + "RemovedFromTaskQueue": "Đã xóa khỏi hàng đợi tác vụ", + "RemoveFilter": "Xóa bộ lọc", + "Search": "Tìm kiếm", + "Security": "Bảo vệ", + "Seeders": "Máy gieo hạt", + "SelectAll": "Chọn tất cả", + "SetTags": "Đặt thẻ", + "SettingsShowRelativeDatesHelpText": "Hiển thị ngày tương đối (Hôm nay / Hôm qua / v.v.) hoặc ngày tuyệt đối", + "SettingsTimeFormat": "Định dạng thời gian", + "ShowAdvanced": "Hiển thị nâng cao", + "SSLCertPath": "Đường dẫn cảnh báo SSL", + "SSLCertPathHelpText": "Đường dẫn đến tệp pfx", + "SSLPort": "Cổng SSL", + "Style": "Phong cách", + "SuggestTranslationChange": "Đề xuất thay đổi bản dịch", + "SystemTimeCheckMessage": "Thời gian hệ thống tắt hơn 1 ngày. Các tác vụ đã lên lịch có thể không chạy chính xác cho đến khi thời gian được sửa", + "TableOptions": "Tùy chọn bảng", + "TableOptionsColumnsMessage": "Chọn cột nào hiển thị và chúng xuất hiện theo thứ tự nào", + "TagCannotBeDeletedWhileInUse": "Không thể bị xóa khi đang sử dụng", + "TagIsNotUsedAndCanBeDeleted": "Thẻ không được sử dụng và có thể bị xóa", + "Tags": "Thẻ", + "TagsHelpText": "Áp dụng cho phim có ít nhất một thẻ phù hợp", + "TagsSettingsSummary": "Xem tất cả các thẻ và cách chúng được sử dụng. Các thẻ không sử dụng có thể bị xóa", + "Tasks": "Nhiệm vụ", + "Test": "Kiểm tra", + "TestAll": "Kiểm tra tất cả", + "TestAllClients": "Kiểm tra tất cả khách hàng", + "Title": "Tiêu đề", + "Today": "Hôm nay", + "Tomorrow": "Ngày mai", + "Torrent": "Torrents", + "UnableToAddANewIndexerPleaseTryAgain": "Không thể thêm trình chỉ mục mới, vui lòng thử lại.", + "UpdateAutomaticallyHelpText": "Tự động tải xuống và cài đặt các bản cập nhật. Bạn vẫn có thể cài đặt từ Hệ thống: Cập nhật", + "UpdateCheckStartupNotWritableMessage": "Không thể cài đặt bản cập nhật vì người dùng '{0}' không thể ghi thư mục khởi động '{1}'.", + "Backups": "Sao lưu", + "BeforeUpdate": "Trước khi cập nhật", + "CertificateValidationHelpText": "Thay đổi cách xác thực chứng chỉ HTTPS nghiêm ngặt", + "MinimumLimits": "Giới hạn tối thiểu", + "About": "Trong khoảng", + "AcceptConfirmationModal": "Phương thức xác nhận chấp nhận", + "Actions": "Hành động", + "Added": "Thêm", + "AddIndexer": "Thêm trình lập chỉ mục", + "AddingTag": "Thêm thẻ", + "Age": "Tuổi tác", + "All": "Tất cả", + "Analytics": "phân tích", + "Automatic": "Tự động", + "DeleteIndexer": "Xóa trình lập chỉ mục", + "DownloadClientSettings": "Tải xuống cài đặt ứng dụng khách", + "DownloadClientStatusCheckAllClientMessage": "Tất cả các ứng dụng khách tải xuống không khả dụng do lỗi", + "DownloadClientStatusCheckSingleClientMessage": "Ứng dụng khách tải xuống không khả dụng do lỗi: {0}", + "DownloadClientUnavailable": "Ứng dụng khách tải xuống không khả dụng", + "Downloading": "Đang tải xuống", + "Edit": "Biên tập", + "EditIndexer": "Chỉnh sửa trình lập chỉ mục", + "EnableColorImpairedModeHelpText": "Đã thay đổi kiểu để cho phép người dùng khiếm thị phân biệt rõ hơn thông tin mã màu", + "Enabled": "Đã bật", + "HiddenClickToShow": "Ẩn, bấm để hiển thị", + "History": "Lịch sử", + "HomePage": "Trang chủ", + "Host": "Tổ chức", + "IllRestartLater": "Tôi sẽ khởi động lại sau", + "Importing": "Nhập khẩu", + "Password": "Mật khẩu", + "Peers": "Ngang hàng", + "Pending": "Đang chờ xử lý", + "Port": "Hải cảng", + "RestoreBackup": "Khôi phục lại bản sao lưu", + "Restrictions": "Những hạn chế", + "Result": "Kết quả", + "Retention": "Giữ lại", + "RSS": "RSS", + "SendAnonymousUsageData": "Gửi dữ liệu sử dụng ẩn danh", + "Settings": "Cài đặt", + "SettingsEnableColorImpairedModeHelpText": "Đã thay đổi kiểu để cho phép người dùng khiếm thị phân biệt rõ hơn thông tin mã màu", + "StartTypingOrSelectAPathBelow": "Bắt đầu nhập hoặc chọn một đường dẫn bên dưới", + "StartupDirectory": "Thư mục khởi động", + "UpdateScriptPathHelpText": "Đường dẫn đến tập lệnh tùy chỉnh có gói cập nhật được trích xuất và xử lý phần còn lại của quá trình cập nhật", + "URLBase": "Cơ sở URL", + "UrlBaseHelpText": "Đối với hỗ trợ proxy ngược, mặc định là trống", + "Usenet": "Usenet", + "View": "Lượt xem", + "Authentication": "Xác thực", + "Backup": "Sao lưu", + "DeleteTagMessageText": "Bạn có chắc chắn muốn xóa thẻ '{0}' không?", + "IndexerLongTermStatusCheckSingleClientMessage": "Trình lập chỉ mục không khả dụng do lỗi trong hơn 6 giờ: {0}", + "IndexerPriority": "Mức độ ưu tiên của người lập chỉ mục", + "KeyboardShortcuts": "Các phím tắt bàn phím", + "Language": "Ngôn ngữ", + "Languages": "Ngôn ngữ", + "LastWriteTime": "Lần viết cuối cùng", + "LaunchBrowserHelpText": " Mở trình duyệt web và điều hướng đến trang chủ Radarr khi khởi động ứng dụng.", + "Level": "Cấp độ", + "LogFiles": "Tệp nhật ký", + "Logging": "Ghi nhật ký", + "LogLevel": "Mức đăng nhập", + "LogLevelTraceHelpTextWarning": "Ghi nhật ký theo dõi chỉ nên được bật tạm thời", + "Logs": "Nhật ký", + "Manual": "Thủ công", + "MaximumLimits": "Giới hạn tối đa", + "Mechanism": "Cơ chế", + "MIA": "MIA", + "New": "Mới", + "ProxyCheckBadRequestMessage": "Không thể kiểm tra proxy. Mã trạng thái: {0}", + "BackupRetentionHelpText": "Các bản sao lưu tự động cũ hơn khoảng thời gian lưu giữ sẽ tự động được dọn dẹp", + "BindAddress": "Địa chỉ ràng buộc", + "BranchUpdate": "Nhánh sử dụng để cập nhật Radarr", + "CloseCurrentModal": "Đóng phương thức hiện tại", + "RSSIsNotSupportedWithThisIndexer": "RSS không được hỗ trợ với trình chỉ mục này", + "SettingsEnableColorImpairedMode": "Bật Chế độ Khuyết màu", + "AnalyticsEnabledHelpText": "Gửi thông tin sử dụng và lỗi ẩn danh đến máy chủ của Radarr. Điều này bao gồm thông tin về trình duyệt của bạn, trang WebUI của Radarr mà bạn sử dụng, báo cáo lỗi cũng như hệ điều hành và phiên bản thời gian chạy. Chúng tôi sẽ sử dụng thông tin này để ưu tiên các tính năng và sửa lỗi.", + "ApiKey": "Mã API", + "AppDataDirectory": "Thư mục AppData", + "AppDataLocationHealthCheckMessage": "Việc cập nhật sẽ không thể ngăn việc xóa AppData khi cập nhật", + "ApplicationStatusCheckAllClientMessage": "Tất cả danh sách không có sẵn do lỗi", + "ApplicationStatusCheckSingleClientMessage": "Danh sách không có sẵn do lỗi: {0}", + "Apply": "Ứng dụng", + "ApplyTags": "Áp dụng thẻ", + "ApplyTagsHelpTexts1": "Cách áp dụng thẻ cho các phim đã chọn", + "AuthenticationMethodHelpText": "Yêu cầu Tên người dùng và Mật khẩu để truy cập Radarr", + "AutomaticSearch": "Tìm kiếm tự động", + "BackupFolderHelpText": "Các đường dẫn tương đối sẽ nằm trong thư mục AppData của Radarr", + "BackupIntervalHelpText": "Khoảng thời gian giữa các bản sao lưu tự động", + "BackupNow": "Sao lưu ngay", + "BindAddressHelpText": "Địa chỉ IP4 hợp lệ hoặc '*' cho tất cả các giao diện", + "Branch": "Chi nhánh", + "BranchUpdateMechanism": "Nhánh được sử dụng bởi cơ chế cập nhật bên ngoài", + "BypassProxyForLocalAddresses": "Bỏ qua proxy cho địa chỉ cục bộ", + "Cancel": "Huỷ bỏ", + "CancelPendingTask": "Bạn có chắc chắn muốn hủy nhiệm vụ đang chờ xử lý này không?", + "ClientPriority": "Ưu tiên khách hàng", + "CloneIndexer": "Trình lập chỉ mục nhân bản", + "CloneProfile": "Hồ sơ nhân bản", + "Close": "Đóng", + "Columns": "Cột", + "Component": "Thành phần", + "ConnectionLost": "Kết nối bị mất", + "ConnectionLostAutomaticMessage": "Radarr sẽ cố gắng kết nối tự động hoặc bạn có thể nhấp vào tải lại bên dưới.", + "Connections": "Kết nối", + "ConnectSettings": "Kết nối Cài đặt", + "CouldNotConnectSignalR": "Không thể kết nối với SignalR, giao diện người dùng sẽ không cập nhật", + "Custom": "Tập quán", + "DelayProfile": "Hồ sơ trì hoãn", + "Delete": "Xóa bỏ", + "DeleteApplicationMessageText": "Bạn có chắc chắn muốn xóa thông báo '{0}' không?", + "DeleteBackup": "Xóa bản sao lưu", + "DeleteBackupMessageText": "Bạn có chắc chắn muốn xóa bản sao lưu '{0}' không?", + "DeleteIndexerMessageText": "Bạn có chắc chắn muốn xóa trình lập chỉ mục '{0}' không?", + "DownloadClientCheckNoneAvailableMessage": "Không có ứng dụng khách tải xuống nào", + "DownloadClientCheckUnableToCommunicateMessage": "Không thể giao tiếp với {0}.", + "EnableCompletedDownloadHandlingHelpText": "Tự động nhập các bản tải xuống đã hoàn thành từ máy khách tải xuống", + "EnabledHelpText": "Bật danh sách này để sử dụng trong Radarr", + "EnableHelpText": "Cho phép tạo tệp siêu dữ liệu cho loại siêu dữ liệu này", + "FeatureRequests": "Yêu cầu tính năng", + "Filename": "Tên tệp", + "Files": "Các tập tin", + "MonoVersion": "Phiên bản Mono", + "NoChange": "Không thay đổi", + "PortNumber": "Số cổng", + "Proxy": "Ủy quyền", + "IndexerProxyStatusCheckAllClientMessage": "Tất cả các trình lập chỉ mục không khả dụng do lỗi", + "IndexerStatusCheckAllClientMessage": "Tất cả các trình lập chỉ mục không khả dụng do lỗi", + "Info": "Thông tin", + "MonoVersionCheckUpgradeRecommendedMessage": "Phiên bản Mono được cài đặt hiện tại {0} được hỗ trợ nhưng nên nâng cấp lên {1}.", + "MoreInfo": "Thêm thông tin", + "MovieDetailsNextMovie": "Chi tiết phim: Phim tiếp theo", + "MovieDetailsPreviousMovie": "Chi tiết phim: Phim trước", + "MovieIndexScrollBottom": "Mục lục phim: Cuộn dưới cùng", + "MovieIndexScrollTop": "Mục lục phim: Cuộn lên đầu", + "Movies": "Phim", + "Ok": "Đồng ý", + "RemovingTag": "Xóa thẻ", + "Reset": "Cài lại", + "ResetAPIKey": "Đặt lại khóa API", + "Restart": "Khởi động lại", + "RestartNow": "Khởi động lại ngay", + "Save": "Tiết kiệm", + "SaveChanges": "Lưu thay đổi", + "SaveSettings": "Lưu các thiết lập", + "Scheduled": "Lên kế hoạch", + "ScriptPath": "Đường dẫn tập lệnh", + "SettingsLongDateFormat": "Định dạng ngày dài", + "SettingsShortDateFormat": "Định dạng ngày ngắn", + "SettingsShowRelativeDates": "Hiển thị Ngày tương đối", + "Torrents": "Torrents", + "Type": "Kiểu", + "UILanguage": "Ngôn ngữ giao diện người dùng", + "UILanguageHelpText": "Ngôn ngữ mà Radarr sẽ sử dụng cho giao diện người dùng", + "UILanguageHelpTextWarning": "Yêu cầu tải lại trình duyệt", + "UnableToAddANewApplicationPleaseTryAgain": "Không thể thêm thông báo mới, vui lòng thử lại.", + "UnableToAddANewAppProfilePleaseTryAgain": "Không thể thêm hồ sơ chất lượng mới, vui lòng thử lại.", + "UnableToAddANewDownloadClientPleaseTryAgain": "Không thể thêm ứng dụng khách tải xuống mới, vui lòng thử lại.", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Không thể thêm trình chỉ mục mới, vui lòng thử lại.", + "UnableToAddANewNotificationPleaseTryAgain": "Không thể thêm thông báo mới, vui lòng thử lại.", + "UnableToLoadBackups": "Không thể tải các bản sao lưu", + "UnableToLoadDownloadClients": "Không thể tải ứng dụng khách tải xuống", + "UnableToLoadGeneralSettings": "Không thể tải Cài đặt chung", + "UnableToLoadHistory": "Không thể tải lịch sử", + "UnableToLoadIndexers": "Không thể tải Trình chỉ mục", + "UnableToLoadNotifications": "Không thể tải thông báo", + "UnableToLoadTags": "Không thể tải thẻ", + "UnableToLoadUISettings": "Không thể tải cài đặt giao diện người dùng", + "UnsavedChanges": "Các thay đổi chưa được lưu", + "UnselectAll": "Bỏ chọn tất cả", + "UpdateCheckStartupTranslocationMessage": "Không thể cài đặt bản cập nhật vì thư mục khởi động '{0}' nằm trong thư mục Chuyển vị ứng dụng.", + "UpdateCheckUINotWritableMessage": "Không thể cài đặt bản cập nhật vì thư mục giao diện người dùng '{0}' không thể ghi bởi người dùng '{1}'.", + "UseProxy": "Sử dụng Proxy", + "Wiki": "Wiki", + "YesCancel": "Có, Hủy bỏ", + "Yesterday": "Hôm qua", + "Add": "Thêm vào", + "AddDownloadClient": "Thêm ứng dụng khách tải xuống", + "ApplyTagsHelpTexts2": "Thêm: Thêm thẻ vào danh sách thẻ hiện có", + "ApplyTagsHelpTexts3": "Xóa: Xóa các thẻ đã nhập", + "ApplyTagsHelpTexts4": "Thay thế: Thay thế các thẻ bằng các thẻ đã nhập (không nhập thẻ nào để xóa tất cả các thẻ)", + "AreYouSureYouWantToResetYourAPIKey": "Bạn có chắc chắn muốn đặt lại Khóa API của mình không?", + "FocusSearchBox": "Hộp Tìm kiếm Tiêu điểm", + "CertificateValidation": "Xác thực chứng chỉ", + "Hostname": "Tên máy chủ", + "IgnoredAddresses": "Địa chỉ bị Bỏ qua", + "IncludeHealthWarningsHelpText": "Bao gồm các cảnh báo về sức khỏe", + "Queue": "Xếp hàng", + "ReadTheWikiForMoreInformation": "Đọc Wiki để biết thêm thông tin", + "Restore": "Khôi phục", + "DeleteIndexerProxyMessageText": "Bạn có chắc chắn muốn xóa thẻ '{0}' không?", + "DeleteNotification": "Xóa thông báo", + "DeleteNotificationMessageText": "Bạn có chắc chắn muốn xóa thông báo '{0}' không?", + "Details": "Chi tiết", + "Disabled": "Tàn tật", + "Discord": "Bất hòa", + "Docker": "Docker", + "Donations": "Quyên góp", + "DownloadClient": "Tải xuống ứng dụng khách", + "DownloadClients": "Tải xuống ứng dụng khách", + "GeneralSettingsSummary": "Cổng, SSL, tên người dùng / mật khẩu, proxy, phân tích và cập nhật", + "Fixed": "đã sửa", + "Folder": "Thư mục", + "ForMoreInformationOnTheIndividualDownloadClients": "Để biết thêm thông tin về các ứng dụng khách tải xuống riêng lẻ, hãy nhấp vào các nút thông tin.", + "Grabbed": "Nắm lấy", + "Grabs": "Vồ lấy", + "Health": "Sức khỏe", + "HealthNoIssues": "Không có vấn đề với cấu hình của bạn", + "RestartRequiredHelpTextWarning": "Yêu cầu khởi động lại để có hiệu lực", + "ShownClickToHide": "Hiển thị, nhấp để ẩn", + "ShowSearch": "Hiển thị Tìm kiếm", + "ShowSearchHelpText": "Hiển thị nút tìm kiếm khi di chuột", + "SSLCertPassword": "Mật khẩu cảnh báo SSL", + "SSLCertPasswordHelpText": "Mật khẩu cho tệp pfx", + "Shutdown": "Tắt", + "Size": "Kích thước", + "Sort": "Sắp xếp", + "Source": "Nguồn", + "Status": "Trạng thái", + "UpdateMechanismHelpText": "Sử dụng trình cập nhật tích hợp của Radarr hoặc một tập lệnh", + "Updates": "Cập nhật", + "Uptime": "Thời gian hoạt động", + "Username": "tên tài khoản", + "Version": "Phiên bản", + "AllIndexersHiddenDueToFilter": "Tất cả phim đều bị ẩn do áp dụng bộ lọc.", + "DeleteTag": "Xóa thẻ", + "UnableToLoadQualityDefinitions": "Không thể tải Định nghĩa chất lượng", + "Enable": "Kích hoạt", + "EnableAutoHelpText": "Nếu được bật, Phim sẽ tự động được thêm vào Radarr từ danh sách này", + "EnableAutomaticAdd": "Bật tính năng Thêm tự động", + "EnableAutomaticSearch": "Bật tìm kiếm tự động", + "EnableAutomaticSearchHelpText": "Sẽ được sử dụng khi tìm kiếm tự động được thực hiện qua giao diện người dùng hoặc bằng Radarr", + "EnableAutomaticSearchHelpTextWarning": "Sẽ được sử dụng khi tìm kiếm tương tác được sử dụng", + "EnableColorImpairedMode": "Bật Chế độ Khuyết màu", + "General": "Chung", + "Warn": "Cảnh báo", + "DeleteDownloadClient": "Xóa ứng dụng khách tải xuống", + "DeleteDownloadClientMessageText": "Bạn có chắc chắn muốn xóa ứng dụng khách tải xuống '{0}' không?", + "EnableInteractiveSearch": "Bật tìm kiếm tương tác", + "EnableInteractiveSearchHelpText": "Sẽ được sử dụng khi tìm kiếm tương tác được sử dụng", + "EnableInteractiveSearchHelpTextWarning": "Trình lập chỉ mục này không hỗ trợ tìm kiếm", + "EnableMediaInfoHelpText": "Trích xuất thông tin video như độ phân giải, thời gian chạy và thông tin codec từ các tệp. Điều này yêu cầu Radarr đọc các phần của tệp có thể gây ra hoạt động mạng hoặc đĩa cao trong quá trình quét.", + "EnableRss": "Bật RSS", + "EnableSSL": "Bật SSL", + "EnableSslHelpText": " Yêu cầu khởi động lại chạy với tư cách quản trị viên để có hiệu lực", + "Error": "lỗi", + "ErrorLoadingContents": "Lỗi khi tải nội dung", + "Events": "Sự kiện", + "EventType": "Loại sự kiện", + "Exception": "ngoại lệ", + "ExistingMovies": "(Các) phim hiện có", + "ExistingTag": "Thẻ hiện có", + "Failed": "Thất bại", + "Filter": "Bộ lọc", + "GeneralSettings": "Cài đặt chung", + "Indexer": "Người lập chỉ mục", + "IndexerFlags": "Cờ chỉ mục", + "IndexerLongTermStatusCheckAllClientMessage": "Tất cả các trình lập chỉ mục không khả dụng do lỗi trong hơn 6 giờ", + "IndexerPriorityHelpText": "Mức độ ưu tiên của người lập chỉ mục từ 1 (Cao nhất) đến 50 (Thấp nhất). Mặc định: 25.", + "IndexerStatusCheckSingleClientMessage": "Trình lập chỉ mục không khả dụng do lỗi: {0}", + "Interval": "Khoảng thời gian", + "RefreshMovie": "Làm mới phim", + "System": "Hệ thống", + "Time": "Thời gian", + "UI": "Giao diện người dùng", + "UISettings": "Cài đặt giao diện người dùng" +} diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index 621e87128..85679accf 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -278,5 +278,130 @@ "MovieIndexScrollBottom": "影片索引:滚动到底部", "MovieDetailsPreviousMovie": "影片详细:前一个", "MovieDetailsNextMovie": "影片详细:下一个", - "BackupIntervalHelpText": "自动备份时间间隔" + "BackupIntervalHelpText": "自动备份时间间隔", + "IndexerProxyStatusCheckAllClientMessage": "所有搜刮器都因错误不可用", + "SettingsShowRelativeDates": "显示相对日期", + "SettingsShowRelativeDatesHelpText": "显示相对日期(今天昨天等)或绝对日期", + "Source": "源代码", + "SSLCertPasswordHelpText": "pfx文件密码", + "TagCannotBeDeletedWhileInUse": "使用中无法删除", + "TagIsNotUsedAndCanBeDeleted": "标签未被使用,可删除", + "UILanguageHelpTextWarning": "浏览器需重新加载", + "UISettings": "UI设置", + "UnableToAddANewApplicationPleaseTryAgain": "无法添加新通知,请稍后重试。", + "UnableToAddANewAppProfilePleaseTryAgain": "无法添加新影片质量配置,请稍后重试。", + "UnableToAddANewDownloadClientPleaseTryAgain": "无法添加下载客户端,请稍后重试。", + "UnableToAddANewIndexerProxyPleaseTryAgain": "无法添加搜刮器,请稍后重试。", + "UnableToAddANewNotificationPleaseTryAgain": "无法添加新通知,请稍后重试。", + "UnableToLoadBackups": "无法加载备份", + "UnableToLoadDownloadClients": "无法加载下载客户端", + "UnableToLoadGeneralSettings": "无法加载通用设置", + "UnableToLoadUISettings": "无法加载UI设置", + "UnsavedChanges": "未保存更改", + "UnselectAll": "全不选", + "UpdateAutomaticallyHelpText": "自动下载并安装更新。你还可以在“系统:更新”中安装", + "UpdateCheckStartupNotWritableMessage": "无法安装更新,因为用户“{1}”对于启动文件夹“{0}”没有写入权限。", + "UpdateCheckStartupTranslocationMessage": "无法安装更新,因为启动文件夹“{0}”在一个应用程序迁移文件夹。Cannot install update because startup folder '{0}' is in an App Translocation folder.", + "Usenet": "Usenet", + "UseProxy": "使用代理", + "Username": "用户名", + "Version": "版本", + "View": "视图", + "Warn": "警告", + "Wiki": "Wiki", + "Yesterday": "昨天", + "Torrent": "Torrents", + "Torrents": "Torrents", + "Type": "类型", + "UnableToLoadNotifications": "无法加载通知连接", + "UnableToLoadQualityDefinitions": "无法加载影片质量定义", + "RefreshMovie": "刷新影片", + "Reload": "重新加载", + "Restore": "恢复", + "NoLinks": "无链接", + "Queue": "队列", + "ReadTheWikiForMoreInformation": "查阅Wiki获得更多信息", + "Reddit": "Reddit", + "ReleaseBranchCheckOfficialBranchMessage": "分支 {0} 不是合法的Radarr发布分支,您不会收到任何更新", + "RemovedFromTaskQueue": "从任务队列中移除", + "RemoveFilter": "移除过滤条件", + "RemovingTag": "移除标签", + "RestartRequiredHelpTextWarning": "重启生效", + "RestoreBackup": "恢复备份", + "Result": "结果", + "Retention": "保留", + "RSS": "RSS", + "RSSIsNotSupportedWithThisIndexer": "该搜刮器不支持RSS", + "Save": "保存", + "SaveChanges": "保存更改", + "SaveSettings": "保存设置", + "Scheduled": "计划中", + "ScriptPath": "脚本路径", + "SearchIndexers": "搜刮器搜索", + "Security": "安全", + "Seeders": "种子", + "SelectAll": "选择全部", + "SendAnonymousUsageData": "发送匿名使用数据", + "Settings": "设置", + "SettingsLongDateFormat": "长时间格式", + "SettingsShortDateFormat": "短日期格式", + "SettingsTimeFormat": "时间格式", + "ShowAdvanced": "显示高级设置", + "ShownClickToHide": "已显示,点击隐藏", + "ShowSearch": "显示搜索按钮", + "ShowSearchHelpText": "在选项中显示搜索框", + "Shutdown": "关机", + "Size": "文件大小", + "Sort": "排序", + "SSLCertPath": "SSL证书路径", + "SSLCertPathHelpText": "pfx文件路径", + "SSLPort": "SSL端口", + "StartTypingOrSelectAPathBelow": "输入路径或者从下面选择", + "StartupDirectory": "启动目录", + "Status": "状态", + "Style": "类型", + "SuggestTranslationChange": "建议翻译改变 Suggest translation change", + "SystemTimeCheckMessage": "系统时间相差超过1天。在纠正时间之前,计划的任务可能无法正确运行", + "TableOptions": "表格选项", + "TableOptionsColumnsMessage": "选择显示哪些列并排序", + "Tags": "标签", + "TagsHelpText": "应用于具有至少一个匹配标签的电影", + "TagsSettingsSummary": "显示全部标签和标签使用情况,可删除未使用的标签", + "Tasks": "任务", + "Test": "测试", + "TestAll": "测试全部", + "TestAllClients": "测试全部客户端", + "Time": "时间", + "Title": "标题", + "Today": "今天", + "Tomorrow": "明天", + "UI": "UI界面", + "UILanguage": "UI界面语言", + "UILanguageHelpText": "Radarr使用的UI界面语言", + "UpdateCheckUINotWritableMessage": "无法安装升级,因为用户“{1}”不可写入界面文件夹“{0}”。", + "UpdateMechanismHelpText": "使用Radarr内置的更新器或者脚本", + "Updates": "更新", + "UpdateScriptPathHelpText": "自定义脚本的路径,该脚本处理获取的更新包并处理更新过程的其余部分", + "Uptime": "运行时间", + "URLBase": "基本URL", + "UrlBaseHelpText": "对于反向代理支持,默认为空", + "ReleaseStatus": "发布状态", + "SetTags": "设定标签", + "UnableToLoadIndexers": "无法加载搜刮器", + "Restrictions": "限制条件", + "Search": "搜索", + "SSLCertPassword": "SSL证书密码", + "UnableToAddANewIndexerPleaseTryAgain": "无法添加搜刮器,请稍后重试。", + "AcceptConfirmationModal": "接受确认模组Accept Confirmation Modal", + "DeleteIndexerProxyMessageText": "您确定要删除列表 '{0}'?", + "IndexerProxyStatusCheckSingleClientMessage": "搜刮器因错误不可用:{0}", + "Refresh": "刷新", + "UnableToLoadHistory": "无法加载历史记录", + "UnableToLoadTags": "无法加载标签", + "YesCancel": "是,取消", + "System": "系统", + "Reset": "重置", + "ResetAPIKey": "重置API Key", + "Restart": "重启", + "RestartNow": "马上重启" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_Hans.json b/src/NzbDrone.Core/Localization/Core/zh_Hans.json index 23a7976d4..9257cfdd8 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_Hans.json +++ b/src/NzbDrone.Core/Localization/Core/zh_Hans.json @@ -2,5 +2,6 @@ "Added": "已添加", "AddDownloadClient": "添加下载客户端", "Add": "添加", - "About": "关于" + "About": "关于", + "Analytics": "分析" } From 0cca9525a1cea9f227bacd16748cccb78244b9af Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 6 Oct 2021 17:07:08 -0500 Subject: [PATCH 0087/2320] Fixed: (Indexers) Download requests not using the configured proxy Fixes #520 --- src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs | 2 +- src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs b/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs index 226be41b1..3275caade 100644 --- a/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs @@ -43,7 +43,7 @@ namespace NzbDrone.Core.Indexers try { - var response = await _httpClient.ExecuteAsync(request); + var response = await _httpClient.ExecuteAsync(request, Definition); torrentData = response.ResponseData; } catch (HttpException ex) diff --git a/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs b/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs index d1ab70ddc..93c559e19 100644 --- a/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs @@ -39,7 +39,7 @@ namespace NzbDrone.Core.Indexers try { - var response = await _httpClient.ExecuteAsync(request); + var response = await _httpClient.ExecuteAsync(request, Definition); nzbData = response.ResponseData; _logger.Debug("Downloaded nzb for release finished ({0} bytes from {1})", nzbData.Length, link.AbsoluteUri); From d18ddcaa509f2800d4db80d74b13c56b9e669c41 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Wed, 6 Oct 2021 22:30:44 +0000 Subject: [PATCH 0088/2320] Update translation files Updated by "Cleanup translation files" hook in Weblate. Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate <noreply@weblate.org> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/de.json | 2 -- src/NzbDrone.Core/Localization/Core/es.json | 2 -- src/NzbDrone.Core/Localization/Core/fr.json | 15 --------------- src/NzbDrone.Core/Localization/Core/hu.json | 13 ------------- src/NzbDrone.Core/Localization/Core/it.json | 2 -- src/NzbDrone.Core/Localization/Core/nl.json | 12 ------------ src/NzbDrone.Core/Localization/Core/pt.json | 1 - 7 files changed, 47 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/de.json b/src/NzbDrone.Core/Localization/Core/de.json index 76f5d5dcb..c0266e450 100644 --- a/src/NzbDrone.Core/Localization/Core/de.json +++ b/src/NzbDrone.Core/Localization/Core/de.json @@ -220,7 +220,6 @@ "Result": "Ergebnis", "Retention": "Aufbewahrung ( Retention )", "ScriptPath": "Script Pfad", - "SourceRelativePath": "Relativer Quellpfad", "SSLCertPassword": "SSL Zertifikat Passwort", "SSLPort": "SSL Port", "SSLCertPath": "Pfad zum SSL Zertifikat", @@ -339,7 +338,6 @@ "FocusSearchBox": "Suchbox fokussieren", "CloseCurrentModal": "Momentanes Modal schließen", "AcceptConfirmationModal": "Bestätigung akzeptieren Modal", - "AddRestriction": "Beschränkung hinzufügen", "Yesterday": "Gestern", "Tomorrow": "Morgen", "Today": "Heute", diff --git a/src/NzbDrone.Core/Localization/Core/es.json b/src/NzbDrone.Core/Localization/Core/es.json index b2d1edae3..10e42093b 100644 --- a/src/NzbDrone.Core/Localization/Core/es.json +++ b/src/NzbDrone.Core/Localization/Core/es.json @@ -202,7 +202,6 @@ "SSLPort": "Puerto SSL", "SSLCertPath": "Ruta del Certificado SSL", "SSLCertPassword": "Contraseña del Certificado SSL", - "SetPermissionsLinuxHelpText": "Debe chmod ser ejecutado una vez los archivos hayan sido importados/renombrados?", "SendAnonymousUsageData": "Enviar Datos de Uso Anónimamente", "ScriptPath": "Ruta del Script", "Retention": "Retención", @@ -339,7 +338,6 @@ "MovieDetailsNextMovie": "Detalles de la película: Siguiente Película", "CloseCurrentModal": "Cerrar Modal Actual", "AcceptConfirmationModal": "Aceptar el Modal de Confirmación", - "AddRestriction": "Añadir Restricción", "IndexerLongTermStatusCheckSingleClientMessage": "Indexers no disponible por errores durando más de 6 horas: {0}", "IndexerLongTermStatusCheckAllClientMessage": "Ningún indexer está disponible por errores durando más de 6 horas", "PrioritySettings": "Prioridad", diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index 42ca9f44c..81694c566 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -72,7 +72,6 @@ "DownloadClientCheckUnableToCommunicateMessage": "Impossible de communiquer avec {0}.", "DownloadClient": "Client de Téléchargement", "MonoNotNetCoreCheckMessage": "Veuillez mettre à niveau vers la version .NET Core de Prowlarr", - "MediaManagementSettingsSummary": "Paramètres de dénomination et de gestion des fichiers", "Logging": "Enregistrement", "LogFiles": "Fichiers Log", "View": "Vue", @@ -138,7 +137,6 @@ "SettingsLongDateFormat": "Format de date long", "SettingsEnableColorImpairedModeHelpText": "Style altéré pour aider les personnes daltoniennes à distinguer les informations en couleurs", "SettingsEnableColorImpairedMode": "Activer le mode daltonien", - "PosterOptions": "Options des posters", "PendingChangesStayReview": "Rester et vérifier les changements", "PendingChangesMessage": "Vous avez effectué des changements non sauvegardés, souhaitez vous quitter cette page ?", "PendingChangesDiscardChanges": "Abandonner les changements et quitter", @@ -165,7 +163,6 @@ "AppDataDirectory": "Dossier AppData", "ApiKey": "Clé API", "AnalyticsEnabledHelpText": "Envoyer des informations anonymes sur l'utilisation et les erreurs vers les serveurs de Prowlarr. Cela inclut des informations sur votre navigateur, quelle page Prowlarr WebUI vous utilisez, les rapports d'erreur ainsi que le système d'exploitation et sa version. Nous utiliserons ces informations pour prioriser les nouvelles fonctionnalités et les corrections de bugs.", - "IgnoreDeletedMovies": "Ignorer les films effacés", "IgnoredAddresses": "Adresses ignorées", "Hostname": "Nom d'hôte", "GeneralSettings": "Réglages Généraux", @@ -191,7 +188,6 @@ "DeleteDownloadClient": "Supprimer le client de téléchargement", "DeleteBackup": "Supprimer la sauvegarde", "DBMigration": "Migration de la base de données", - "CopyUsingHardlinksHelpText": "Utiliser des liens fixes quand on essaye de copier des fichiers appartenant à des torrents en cours de partage", "ConnectSettings": "Paramètres de connexion", "BackupFolderHelpText": "Les chemins correspondants seront sous le répertoire AppData de Prowlarr", "IllRestartLater": "Je redémarrerai plus tard", @@ -226,11 +222,8 @@ "IndexerPriorityHelpText": "Priorité de l'indexeur de 1 (la plus élevée) à 50 (la plus basse). Par défaut: 25.", "IndexerPriority": "Priorité de l'indexeur", "Importing": "Importation", - "ExcludeMovie": "Exclure Film", - "UnableToLoadRestrictions": "Impossible de charger les restrictions", "UnableToLoadQualityDefinitions": "Impossible de charger les définitions de qualité", "UnableToLoadNotifications": "Impossible de charger les notifications", - "WaitingToImport": "En attente d'importation", "Version": "Version", "Username": "Nom d'utilisateur", "UseProxy": "Utiliser un proxy", @@ -238,7 +231,6 @@ "UrlBaseHelpText": "Pour la prise en charge du proxy inverse, la valeur par défaut est vide", "URLBase": "Base URL", "YesCancel": "Oui, annuler", - "MovieFiles": "Fichiers vidéo", "MonoVersion": "Mono Version", "Mode": "Mode", "MinutesSixty": "60 Minutes : {0}", @@ -256,7 +248,6 @@ "IncludeHealthWarningsHelpText": "Inclure avertissements santé", "FocusSearchBox": "Zone de recherche de focus", "ProxyBypassFilterHelpText": "Utiliser ',' comme séparateur et '*.' comme caractère générique pour les sous-domaines", - "ExtraFileExtensionsHelpTexts1": "Liste séparée par des virgules des fichiers supplémentaires à importer (.nfo sera importé en tant que .nfo-orig)", "Uptime": "Durée de fonctionnent", "UpdateScriptPathHelpText": "Chemin vers un script personnalisé qui prend un package de mise à jour extraite et gère le reste du processus de mise à jour", "UpdateMechanismHelpText": "Utiliser le programme de mise à jour intégré dans Prowlarr ou un script", @@ -293,9 +284,7 @@ "SSLCertPath": "Chemin du certificat SSL", "SSLCertPasswordHelpText": "Mot de passe pour le fichier pfx", "SSLCertPassword": "Mot de passe du certificat SSL", - "ShowTitleHelpText": "Afficher le titre du film sous l'affiche", "ShownClickToHide": "Montré, cliquez pour masquer", - "ShouldMonitorHelpText": "Si activé, les films ajoutés par cette liste sont ajoutés et surveillés", "SendAnonymousUsageData": "Envoyer des données d'utilisation anonymes", "ScriptPath": "Chemin du script", "SaveSettings": "Enregistrer les paramètres", @@ -308,14 +297,11 @@ "RestartNow": "Redémarrer maintenant", "ResetAPIKey": "Réinitialiser la clé API", "Reset": "Réinitialiser", - "RenameMoviesHelpText": "Prowlarr utilisera le nom de fichier existant si le changement de nom est désactivé", "RemovingTag": "Suppression du tag", "ExistingTag": "Tag existant", - "RemoveFromDownloadClient": "Supprimer du client de téléchargement", "RemoveFilter": "Supprimer le filtre", "RemovedFromTaskQueue": "Supprimé de la file d'attente des tâches", "RefreshMovie": "Actualiser film", - "Reason": "Raison", "ReadTheWikiForMoreInformation": "Consultez le Wiki pour plus d'informations", "ProwlarrSupportsAnyIndexer": "Prowlarr prend en charge de nombreux indexeurs en plus de tout indexeur qui utilise la norme Newznab/Torznab en utilisant « Generic Newznab » (pour usenet) ou « Generic Torznab » (pour les torrents). Recherchez et sélectionnez votre indexeur ci-dessous.", "ProwlarrSupportsAnyDownloadClient": "Prowlarr prend en charge tout client de téléchargement qui utilise le standard Newznab, ainsi que d'autres clients de téléchargement répertoriés ci-dessous.", @@ -352,7 +338,6 @@ "OnHealthIssueHelpText": "Sur un problème de santé", "AcceptConfirmationModal": "Accepter la modalité de confirmation", "OpenThisModal": "Ouvrer ce modal", - "CancelProcessing": "Annuler le traitement", "IndexerLongTermStatusCheckSingleClientMessage": "Indexeurs indisponibles en raison de pannes pendant plus de 6 heures : {0}", "IndexerLongTermStatusCheckAllClientMessage": "Tous les indexeurs sont indisponibles en raison d'échecs de plus de 6 heures", "Yesterday": "Hier", diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index 22184e227..7ec9c2b49 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -1,7 +1,6 @@ { "About": "Névjegy", "Analytics": "Analitika", - "AddNewMovie": "Új film hozzáadása", "AddIndexer": "Indexer hozzáadása", "AddingTag": "Címke hozzáadása", "Error": "Hiba", @@ -43,9 +42,7 @@ "DBMigration": "DB Migráció", "Dates": "Dátumok", "Date": "Dátum", - "CustomFormats": "Egyéni Formátumok", "CustomFilters": "Egyéni Szűrők", - "CopyToClipboard": "Másold a Vágólapra", "ConnectSettingsSummary": "Értesítések és egyéni szkriptek", "ConnectSettings": "Kapcsolódási Beállítások", "Connections": "Kapcsolatok", @@ -148,7 +145,6 @@ "MonoVersion": "Mono Verzió", "MonoTlsCheckMessage": "A Prowlarr Mono 4.x tls megoldás továbbra is engedélyezett, fontolja meg a MONO_TLS_PROVIDER =legacy opció eltávolítását", "ShownClickToHide": "Kattints, hogy elrejtsd", - "ShowCertification": "Tanúsítvány megjelenítése", "ShowAdvanced": "Haladó nézet", "SettingsTimeFormat": "Időformátum", "SettingsShowRelativeDatesHelpText": "Relatív (Ma / Tegnap / stb.) vagy valós dátumok megjelenítése", @@ -162,7 +158,6 @@ "SelectAll": "Összes kijelölése", "Seeders": "Seederek", "Security": "Biztonság", - "SearchFailedPleaseTryAgainLater": "Keresés sikertelen, próbáld újra később.", "Search": "Keresés", "ScriptPath": "Script útvonal", "Scheduled": "Ütemezve", @@ -181,7 +176,6 @@ "Restart": "Újraindítás", "ResetAPIKey": "API Kulcs visszaállítása", "Reset": "Visszaállítás", - "ReplaceIllegalCharacters": "Az illegális karakterek cseréje", "RemovingTag": "Címke eltávolítása", "RemoveFilter": "Szűrő törlése", "RemovedFromTaskQueue": "Eltávolítva a feladatsorról", @@ -191,7 +185,6 @@ "ReleaseBranchCheckOfficialBranchMessage": "A(z) {0} nem érvényes Prowlarr frissítési ágazat, ezért nem kap frissítéseket", "RefreshMovie": "Film frissítése", "Refresh": "Frissítés", - "Reason": "Ok", "ReadTheWikiForMoreInformation": "Olvasd el a Wiki-t további információkért", "ProwlarrSupportsAnyIndexer": "A Prowlarr számos indexert támogat, minden olyan indexelő mellett, amely a Newznab / Torznab szabványt használja, valamint a 'Generic Newznab' (usenethez) vagy a 'Generic Torznab' (torrentekhez) használatával. Keresés és az alább felsorolt indexelők kiválasztása.", "ProwlarrSupportsAnyDownloadClient": "A Prowlarr minden olyan letöltési klienst támogat, amely a Newznab szabványt használja, valamint az alább felsorolt letöltési klienseket.", @@ -223,7 +216,6 @@ "PageSizeHelpText": "Az egyes oldalakon megjelenítendő elemek száma", "PageSize": "Oldal mérete", "PackageVersion": "Csomagverzió", - "Organize": "Rendezés", "Options": "Opciók", "OpenThisModal": "Nyissa meg ezt a modált", "OpenBrowserOnStart": "Indításkor nyissa meg a böngészőt", @@ -243,7 +235,6 @@ "NetCore": ".NET", "Name": "Név", "Movies": "Filmek", - "MovieInfoLanguageHelpText": "A Prowlarr által a filminformációkhoz használt nyelv", "MovieIndexScrollTop": "Film Index: Görgess fel", "MovieIndexScrollBottom": "Film Index: Görgess le", "MovieDetailsPreviousMovie": "A film részletei: Előző film", @@ -266,7 +257,6 @@ "LogLevel": "Log Szint", "Logging": "Loggolás", "LogFiles": "Log Fájlok", - "ListSettings": "Lista Beállítások", "Level": "Szint", "LaunchBrowserHelpText": " Nyisson meg egy böngészőt, és az alkalmazás indításakor lépjen a Prowlarr kezdőlapjára.", "LastWriteTime": "Utolsó írási idő", @@ -318,9 +308,7 @@ "IndexerFlags": "Indexer Zászló", "Indexer": "Indexelő", "IncludeHealthWarningsHelpText": "Tartalmazza a Állapot Figyelmeztetéseket", - "ImportListSyncIntervalHelpText": "A Prowlarr milyen gyakran szinkronizáljon a listáival.", "Importing": "Importálás Folyamatban", - "ImportErrors": "Importálási Hiba", "IllRestartLater": "Később Újraindítom", "IgnoredAddresses": "Ignorált Címek", "YesCancel": "Igen, Mégsem", @@ -346,7 +334,6 @@ "UnableToLoadTags": "Nem sikerült betölteni a címkéket", "UnableToLoadQualityDefinitions": "Nem lehet betölteni a minőségi meghatározásokat", "UnableToLoadNotifications": "Nem sikerült betölteni az Értesítéseket", - "ThisConditionMatchesUsingRegularExpressions": "Ez a feltétel megfelel a Reguláris kifejezések használatának. Ne feledje, hogy a karakterek {0} különleges jelentéssel bírnak, és el kell kerülniük egy {1} karakterrel", "TableOptions": "Táblázat beállításai", "ShowSearch": "Keresés(ek) megjelenítése", "SetTags": "Címkék beállítása", diff --git a/src/NzbDrone.Core/Localization/Core/it.json b/src/NzbDrone.Core/Localization/Core/it.json index 6d09cea78..b01b3d9f0 100644 --- a/src/NzbDrone.Core/Localization/Core/it.json +++ b/src/NzbDrone.Core/Localization/Core/it.json @@ -223,7 +223,6 @@ "NoLeaveIt": "No, lascialo", "NoBackupsAreAvailable": "Nessun Backup disponibile", "New": "Nuovo", - "MovieInfoLanguage": "Lingua delle info del film", "MonoVersion": "Versione Mono", "Mode": "Modo", "MinutesSixty": "60 Minuti: {0}", @@ -339,7 +338,6 @@ "FocusSearchBox": "Attiva casella di ricerca", "CloseCurrentModal": "Chiudi la modalità corrente", "AcceptConfirmationModal": "Accetta modalità di conferma", - "AddRestriction": "Aggiungi Limitazioni", "IndexerLongTermStatusCheckSingleClientMessage": "Alcuni indexer non disponibili da più di 6 ore a causa di errori: {0}", "IndexerLongTermStatusCheckAllClientMessage": "Nessun indexer è disponibile da più di 6 ore a causa di errori", "PrioritySettings": "Priorità", diff --git a/src/NzbDrone.Core/Localization/Core/nl.json b/src/NzbDrone.Core/Localization/Core/nl.json index d7aed77f1..732c90d33 100644 --- a/src/NzbDrone.Core/Localization/Core/nl.json +++ b/src/NzbDrone.Core/Localization/Core/nl.json @@ -1,6 +1,5 @@ { "Indexers": "Indexeerders", - "ImportFirstTip": "Zorg ervoor dat je bestanden de kwaliteit in hun bestandsnaam bevatten. Bijv.", "Host": "Host", "History": "Geschiedenis", "HideAdvanced": "Verberg Gevorderd", @@ -54,7 +53,6 @@ "Movies": "Films", "MoreInfo": "Meer Info", "MonoNotNetCoreCheckMessage": "Gelieve te opwaarderen naar de .NET Core versie van Prowlarr", - "ManualImport": "Manuele Import", "Logging": "Logbeheer", "LogFiles": "Logbestanden", "Languages": "Talen", @@ -81,7 +79,6 @@ "Size": "Grootte", "ReleaseStatus": "Uitgave Status", "Protocol": "Protocol", - "MediaManagementSettingsSummary": "Naamgeving en bestandsbeheer instellingen", "LastWriteTime": "Laatste Modificatietijd", "Indexer": "Indexeerder", "Grabbed": "Opgehaalde", @@ -133,7 +130,6 @@ "UnsavedChanges": "Onopgeslagen Wijzigingen", "ShowSearchHelpText": "Toon zoeken knop bij zweven", "ShowSearch": "Toon Zoeken", - "SettingsUiLanguage": "Gebruikersinterface Taal", "SettingsTimeFormat": "Tijdsformaat", "SettingsShowRelativeDatesHelpText": "Toon relatieve (Vandaag/Gisteren/enz.) of absolute datums", "SettingsShowRelativeDates": "Toon Relatieve Datums", @@ -203,7 +199,6 @@ "OnHealthIssueHelpText": "Bij Gezondheidsprobleem", "NoLeaveIt": "Nee, Ongemoeid Laten", "New": "Nieuw", - "MovieFolderFormat": "Film Map Formaat", "MonoVersion": "Mono Versie", "Mode": "Modus", "MinimumLimits": "Minimum Limieten", @@ -216,9 +211,7 @@ "IndexerFlags": "Indexeerder Flags", "EnableSslHelpText": " Vereist herstart als administrator om in werking te treden", "PriorityHelpText": "Geef prioriteit aan meerdere downloaders. Round-Robin wordt gebruikt voor downloaders met dezelfde prioriteit.", - "RssSyncIntervalHelpTextWarning": "Dit zal van toepassing zijn op alle indexeerders, gelieve de door hen opgelegde regels te volgen", "SendAnonymousUsageData": "Zend Anonieme Gebruiksdata", - "TorrentDelayHelpText": "Wachttijd in minuten alvorens een torrent op te halen", "UnableToLoadIndexers": "Indexeerders kunnen niet worden geladen", "UnableToLoadNotifications": "Notificaties kunnen niet worden geladen", "UpdateAutomaticallyHelpText": "Download en installeer updates automatisch. Je zal nog steeds kunnen installeren vanuit Systeem: Updates", @@ -242,7 +235,6 @@ "ProxyBypassFilterHelpText": "Gebruik ',' als scheidingsteken en '*' als wildcard voor subdomeinen", "RemovedFromTaskQueue": "Verwijderd uit taken wachtrij", "RemoveFilter": "Verwijder filter", - "RequiredHelpText": "Deze {0} conditie moet overeenstemmen om het eigen formaat te kunnen toepassen. Anders is een enkele {1} overeenstemming voldoende.", "Reset": "Reset", "RestartNow": "Herstart Nu", "RestartProwlarr": "Herstart Prowlarr", @@ -251,7 +243,6 @@ "Retention": "Retentie", "ScriptPath": "Script Pad", "ResetAPIKey": "Reset API-sleutel", - "ShowQualityProfileHelpText": "Toon kwaliteitsprofiel onder poster", "SSLCertPassword": "SSL Certificaat Wachtwoord", "SSLCertPath": "SSL Certificaat Pad", "SSLPort": "SSL Poort", @@ -279,7 +270,6 @@ "RSSIsNotSupportedWithThisIndexer": "RSS wordt niet ondersteund door deze indexeerder", "RemovingTag": "Tag verwijderen", "Pending": "In afwachting", - "MovieAlreadyExcluded": "Film werd al Uitgesloten", "Manual": "Manueel", "LogLevelTraceHelpTextWarning": "Trace log niveau moet enkel tijdelijk worden gebruikt", "HiddenClickToShow": "Verborgen, klik om te tonen", @@ -301,7 +291,6 @@ "BeforeUpdate": "Voor de update", "AddingTag": "Tag toevoegen", "UnableToLoadUISettings": "Kon gebruikersinterface instellingen niet inladen", - "UnableToLoadIndexerOptions": "Kon indexeerder opties niet inladen", "UnableToLoadGeneralSettings": "Kon Algemene instellingen niet inladen", "UnableToAddANewNotificationPleaseTryAgain": "Kon geen nieuwe notificatie toevoegen, gelieve opnieuw te proberen.", "UnableToAddANewIndexerPleaseTryAgain": "Kon geen nieuwe indexeerder toevoegen, gelieve opnieuw te proberen.", @@ -332,7 +321,6 @@ "UILanguageHelpTextWarning": "Browser Herladen Vereist", "UILanguageHelpText": "Taal die Prowlarr zal gebruiken voor de gebruikersinterface", "UILanguage": "Gebruikersinterface Taal", - "DownloadPropersAndRepacks": "PROPERS en REPACKS", "Priority": "Prioriteit", "InteractiveSearch": "Interactief Zoeken", "IndexerPriorityHelpText": "Indexeerder Prioriteit van 1 (Hoogste) tot 50 (Laagste). Standaard: 25.", diff --git a/src/NzbDrone.Core/Localization/Core/pt.json b/src/NzbDrone.Core/Localization/Core/pt.json index 3642ecfc6..8df0e10ea 100644 --- a/src/NzbDrone.Core/Localization/Core/pt.json +++ b/src/NzbDrone.Core/Localization/Core/pt.json @@ -338,7 +338,6 @@ "MovieIndexScrollBottom": "Índice do filme: deslocar para baixo", "MovieDetailsPreviousMovie": "Detalhes do filme: filme anterior", "MovieDetailsNextMovie": "Detalhes do filme: próximo filme", - "CancelProcessing": "Cancelar Processamento", "SettingsConsoleLogLevel": "Nível de registo do console", "SearchIndexers": "Pesquisar indexadores", "IndexersSelectedInterp": "{0} indexador(es) selecionado(s)", From 5dd6cde61a148e7091370f74216248cfbf0ef23b Mon Sep 17 00:00:00 2001 From: dobbleg1000 <j8kap@hotmail.com> Date: Sun, 3 Oct 2021 23:37:06 -0500 Subject: [PATCH 0089/2320] Fixed: (Indexer) Changed BakaBT to default to SFW content Update Bakabt for Adult Content Bool and change link --- src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs index 3a805f04c..dd9001134 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs @@ -170,7 +170,11 @@ namespace NzbDrone.Core.Indexers.Definitions private IEnumerable<IndexerRequest> GetPagedRequests(string term) { var searchString = term; - var searchUrl = Settings.BaseUrl + "browse.php?only=0&hentai=1&incomplete=1&lossless=1&hd=1&multiaudio=1&bonus=1&reorder=1&q="; + var searchUrl = Settings.BaseUrl + " browse.php?only=0&incomplete=1&lossless=1&hd=1&multiaudio=1&bonus=1&reorder=1&q="; + if (Settings.AdultContent) + { + searchUrl = Settings.BaseUrl + "browse.php?only=0&hentai=1&incomplete=1&lossless=1&hd=1&multiaudio=1&bonus=1&reorder=1&q="; + } var match = Regex.Match(term, @".*(?=\s(?:[Ee]\d+|\d+)$)"); if (match.Success) @@ -440,7 +444,10 @@ namespace NzbDrone.Core.Indexers.Definitions [FieldDefinition(5, Label = "Append Season", Type = FieldType.Checkbox, HelpText = "Append Season for Sonarr Compatibility")] public bool AppendSeason { get; set; } - [FieldDefinition(6)] + [FieldDefinition(6, Label = "Adult Content", Type = FieldType.Checkbox, HelpText = "Allow Adult Content (Must be enabled in BakaBT settings)")] + public bool AdultContent { get; set; } + + [FieldDefinition(7)] public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); public NzbDroneValidationResult Validate() From dcfa3ad48e46d6d92a594966cef0210afbb91b42 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 6 Oct 2021 19:08:14 -0500 Subject: [PATCH 0090/2320] Update contributing [skip ci] (#528) * update contributing [skip ci] sonarr pulls / *arr pulls * nuke contributing => wiki [skip ci] * fix wiki link [skip ci] * fixup! fix wiki link [skip ci] (lint) --- CONTRIBUTING.md | 54 ++++++------------------------------------------- 1 file changed, 6 insertions(+), 48 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 730295c6c..4217a04b5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,55 +1,13 @@ -# How to Contribute # +# How to Contribute We're always looking for people to help make Prowlarr even better, there are a number of ways to contribute. -This file is updated on an ad-hoc basis, for the latest details please see the [contributing wiki page](https://wiki.servarr.com/prowlarr/contributing). +This file has been moved to the wiki for the latest details please see the [contributing wiki page](https://wiki.servarr.com/prowlarr/contributing). -## Documentation ## -Setup guides, FAQ, the more information we have on the [wiki](https://wiki.servarr.com/prowlarr) the better. +## Documentation -## Development ## +Setup guides, [FAQ](https://wiki.servarr.com/prowlarr/faq), the more information we have on the [wiki](https://wiki.servarr.com/prowlarr) the better. -### Tools required ### -- Visual Studio 2019 or higher (https://www.visualstudio.com/vs/). The community version is free and works (https://www.visualstudio.com/downloads/). -- HTML/Javascript editor of choice (VS Code/Sublime Text/Webstorm/Atom/etc) -- [Git](https://git-scm.com/downloads) -- [NodeJS](https://nodejs.org/en/download/) (Node 12.X.X or higher) -- [Yarn](https://yarnpkg.com/) -- .NET Core 5.0. +## Development -### Getting started ### - -1. Fork Prowlarr -2. Clone the repository into your development machine. [*info*](https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository-from-github) -3. Install the required Node Packages `yarn install` -4. Start gulp to monitor your dev environment for any changes that need post processing using `yarn start` command. -5. Build the project in Visual Studio, Setting startup project to `Prowlarr.Console` and framework to `net5.0` -6. Debug the project in Visual Studio -7. Open http://localhost:9696 - -### Contributing Code ### -- If you're adding a new, already requested feature, please comment on [Github Issues](https://github.com/Prowlarr/Prowlarr/issues "Github Issues") so work is not duplicated (If you want to add something not already on there, please talk to us first) -- Rebase from Prowlarr's develop branch, don't merge -- Make meaningful commits, or squash them -- Feel free to make a pull request before work is complete, this will let us see where its at and make comments/suggest improvements -- Reach out to us on the discord if you have any questions -- Add tests (unit/integration) -- Commit with *nix line endings for consistency (We checkout Windows and commit *nix) -- One feature/bug fix per pull request to keep things clean and easy to understand -- Use 4 spaces instead of tabs, this is the default for VS 2019 and WebStorm (to my knowledge) - -### Contributing Indexers ### -- If you're contributing an indexer please phrase your commit as something like: `New: (Indexer) {Indexer Name}`, `New: (Indexer) {Usenet|Torrent} {Indexer Name}`, `New: (Indexer) {Torznab|Newznab} {Indexer Name}` -- If you're updating an indexer please phrase your commit as something like: `Fixed: (Indexer) {Indexer Name} {changes}` e.g. `Fixed: (Indexer) Changed BHD to use API` - -### Pull Requesting ### -- Only make pull requests to develop, never master, if you make a PR to master we'll comment on it and close it -- You're probably going to get some comments or questions from us, they will be to ensure consistency and maintainability -- We'll try to respond to pull requests as soon as possible, if its been a day or two, please reach out to us, we may have missed it -- Each PR should come from its own [feature branch](http://martinfowler.com/bliki/FeatureBranch.html) not develop in your fork, it should have a meaningful branch name (what is being added/fixed) - - new-feature (Good) - - fix-bug (Good) - - patch (Bad) - - develop (Bad) - -If you have any questions about any of this, please let us know. +See the [Wiki Page](https://wiki.servarr.com/prowlarr/contributing) From 918071903ba0724ef47992f9c417fece3faaa498 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 6 Oct 2021 19:32:22 -0500 Subject: [PATCH 0091/2320] New: Raw search engine support in caps --- .../Indexers/IndexerCapabilities.cs | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs b/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs index b6a2c04dc..92f66de27 100644 --- a/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs +++ b/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs @@ -52,6 +52,8 @@ namespace NzbDrone.Core.Indexers public int? LimitsMax { get; set; } public int? LimitsDefault { get; set; } + public bool SupportsRawSearch { get; set; } + public List<SearchParam> SearchParams; public bool SearchAvailable => SearchParams.Count > 0; @@ -87,6 +89,7 @@ namespace NzbDrone.Core.Indexers public IndexerCapabilities() { + SupportsRawSearch = false; SearchParams = new List<SearchParam> { SearchParam.Q }; TvSearchParams = new List<TvSearchParam>(); MovieSearchParams = new List<MovieSearchParam>(); @@ -364,22 +367,28 @@ namespace NzbDrone.Core.Indexers new XElement("searching", new XElement("search", new XAttribute("available", SearchAvailable ? "yes" : "no"), - new XAttribute("supportedParams", SupportedSearchParams())), + new XAttribute("supportedParams", SupportedSearchParams()), + SupportsRawSearch ? new XAttribute("searchEngine", "raw") : null), new XElement("tv-search", new XAttribute("available", TvSearchAvailable ? "yes" : "no"), - new XAttribute("supportedParams", SupportedTvSearchParams())), + new XAttribute("supportedParams", SupportedTvSearchParams()), + SupportsRawSearch ? new XAttribute("searchEngine", "raw") : null), new XElement("movie-search", new XAttribute("available", MovieSearchAvailable ? "yes" : "no"), - new XAttribute("supportedParams", SupportedMovieSearchParams())), + new XAttribute("supportedParams", SupportedMovieSearchParams()), + SupportsRawSearch ? new XAttribute("searchEngine", "raw") : null), new XElement("music-search", new XAttribute("available", MusicSearchAvailable ? "yes" : "no"), - new XAttribute("supportedParams", SupportedMusicSearchParams())), + new XAttribute("supportedParams", SupportedMusicSearchParams()), + SupportsRawSearch ? new XAttribute("searchEngine", "raw") : null), new XElement("audio-search", new XAttribute("available", MusicSearchAvailable ? "yes" : "no"), - new XAttribute("supportedParams", SupportedMusicSearchParams())), + new XAttribute("supportedParams", SupportedMusicSearchParams()), + SupportsRawSearch ? new XAttribute("searchEngine", "raw") : null), new XElement("book-search", new XAttribute("available", BookSearchAvailable ? "yes" : "no"), - new XAttribute("supportedParams", SupportedBookSearchParams()))), + new XAttribute("supportedParams", SupportedBookSearchParams()), + SupportsRawSearch ? new XAttribute("searchEngine", "raw") : null)), new XElement("categories", from c in Categories.GetTorznabCategoryTree(true) select new XElement("category", From 234995cbafef4a3e3eba18fc13ecaad4563a2b35 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 6 Oct 2021 19:33:47 -0500 Subject: [PATCH 0092/2320] Rename indexer proxied HTTP methods for clarification --- .../AvistazTests/PrivateHDFixture.cs | 2 +- .../FileListTests/FileListFixture.cs | 2 +- .../IndexerTests/HDBitsTests/HDBitsFixture.cs | 4 ++-- .../NewznabCapabilitiesProviderFixture.cs | 6 +++--- .../NewznabTests/NewznabFixture.cs | 2 +- .../IndexerTests/PTPTests/PTPFixture.cs | 4 ++-- .../IndexerTests/RarbgTests/RarbgFixture.cs | 6 +++--- .../TorznabTests/TorznabFixture.cs | 6 +++--- .../Indexers/Definitions/BakaBT.cs | 2 +- .../Definitions/Cardigann/Cardigann.cs | 2 +- .../Cardigann/CardigannRequestGenerator.cs | 20 +++++++++---------- .../Definitions/Headphones/Headphones.cs | 2 +- .../Newznab/NewznabCapabilitiesProvider.cs | 2 +- .../Indexers/Definitions/SpeedApp.cs | 2 +- src/NzbDrone.Core/Indexers/HttpIndexerBase.cs | 6 +++--- .../Indexers/IndexerHttpClient.cs | 8 ++++---- .../Indexers/TorrentIndexerBase.cs | 2 +- .../Indexers/UsenetIndexerBase.cs | 2 +- 18 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/PrivateHDFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/PrivateHDFixture.cs index 86469cdc8..377fdd968 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/PrivateHDFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/PrivateHDFixture.cs @@ -34,7 +34,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AvistazTests var recentFeed = ReadAllText(@"Files/Indexers/PrivateHD/recentfeed.json"); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader { { "Content-Type", "application/json" } }, new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/FileListTests/FileListFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/FileListTests/FileListFixture.cs index 63570a01e..12f12c095 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/FileListTests/FileListFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/FileListTests/FileListFixture.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests var recentFeed = ReadAllText(@"Files/Indexers/FileList/recentfeed.json"); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/HDBitsTests/HDBitsFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/HDBitsTests/HDBitsFixture.cs index 49feabe43..91e3efcf0 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/HDBitsTests/HDBitsFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/HDBitsTests/HDBitsFixture.cs @@ -45,7 +45,7 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests var responseJson = ReadAllText(fileName); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), responseJson))); var torrents = (await Subject.Fetch(_movieSearchCriteria)).Releases; @@ -74,7 +74,7 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests var responseJson = new { status = 5, message = "Invalid authentication credentials" }.ToJson(); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteAsync(It.IsAny<HttpRequest>(), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.IsAny<HttpRequest>(), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), Encoding.UTF8.GetBytes(responseJson)))); var torrents = (await Subject.Fetch(_movieSearchCriteria)).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs index 03aa7da01..a5a7c7c14 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs @@ -43,7 +43,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests private void GivenCapsResponse(string caps) { Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.Execute(It.IsAny<HttpRequest>(), It.IsAny<IndexerDefinition>())) + .Setup(o => o.ExecuteProxied(It.IsAny<HttpRequest>(), It.IsAny<IndexerDefinition>())) .Returns<HttpRequest, IndexerDefinition>((r, d) => new HttpResponse(r, new HttpHeader(), new CookieCollection(), caps)); } @@ -56,7 +56,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests Subject.GetCapabilities(_settings, _definition); Mocker.GetMock<IIndexerHttpClient>() - .Verify(o => o.Execute(It.IsAny<HttpRequest>(), It.IsAny<IndexerDefinition>()), Times.Once()); + .Verify(o => o.ExecuteProxied(It.IsAny<HttpRequest>(), It.IsAny<IndexerDefinition>()), Times.Once()); } [Test] @@ -85,7 +85,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests public void should_throw_if_failed_to_get() { Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.Execute(It.IsAny<HttpRequest>(), It.IsAny<IndexerDefinition>())) + .Setup(o => o.ExecuteProxied(It.IsAny<HttpRequest>(), It.IsAny<IndexerDefinition>())) .Throws<Exception>(); Assert.Throws<Exception>(() => Subject.GetCapabilities(_settings, _definition)); diff --git a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabFixture.cs index 77120b8d4..75ba1038c 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabFixture.cs @@ -43,7 +43,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests var recentFeed = ReadAllText(@"Files/Indexers/Newznab/newznab_nzb_su.xml"); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 }, Limit = 100, Offset = 0 })).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs index 736386139..b9827e838 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs @@ -37,11 +37,11 @@ namespace NzbDrone.Core.Test.IndexerTests.PTPTests var responseJson = ReadAllText(fileName); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), authStream.ToString()))); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader { ContentType = HttpAccept.Json.Value }, new CookieCollection(), responseJson))); var torrents = (await Subject.Fetch(new MovieSearchCriteria())).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs index 7d6fd31d5..89e3eafb7 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs @@ -38,7 +38,7 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests var recentFeed = ReadAllText(@"Files/Indexers/Rarbg/RecentFeed_v2.json"); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; @@ -65,7 +65,7 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests public async Task should_parse_error_20_as_empty_results() { Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), "{ error_code: 20, error: \"some message\" }"))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; @@ -77,7 +77,7 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests public async Task should_warn_on_unknown_error() { Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), "{ error_code: 25, error: \"some message\" }"))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs index 444ad4433..588a41349 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs @@ -44,7 +44,7 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_hdaccess_net.xml"); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria())).Releases; @@ -73,7 +73,7 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_tpb.xml"); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria())).Releases; @@ -103,7 +103,7 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_animetosho.xml"); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria())).Releases; diff --git a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs index dd9001134..a9e0e601d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs @@ -52,7 +52,7 @@ namespace NzbDrone.Core.Indexers.Definitions .SetCookies(GetCookies() ?? new Dictionary<string, string>()) .Build(); - var response = await _httpClient.ExecuteAsync(request, Definition); + var response = await _httpClient.ExecuteProxiedAsync(request, Definition); var parser = new HtmlParser(); var dom = parser.ParseDocument(response.Content); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs index 3ba142241..f2759f848 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs @@ -177,7 +177,7 @@ namespace NzbDrone.Core.Indexers.Cardigann try { - var response = await _httpClient.ExecuteAsync(request, Definition); + var response = await _httpClient.ExecuteProxiedAsync(request, Definition); downloadBytes = response.ResponseData; } catch (HttpException ex) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 644229ad2..9fe82b64d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -194,7 +194,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.Headers.Add("Referer", SiteLink); - var response = await HttpClient.ExecuteAsync(requestBuilder.Build(), Definition); + var response = await HttpClient.ExecuteProxiedAsync(requestBuilder.Build(), Definition); Cookies = response.GetCookies(); @@ -331,7 +331,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.Headers.Add("Referer", loginUrl); - var simpleCaptchaResult = await HttpClient.ExecuteAsync(requestBuilder.Build(), Definition); + var simpleCaptchaResult = await HttpClient.ExecuteProxiedAsync(requestBuilder.Build(), Definition); var simpleCaptchaJSON = JObject.Parse(simpleCaptchaResult.Content); var captchaSelection = simpleCaptchaJSON["images"][0]["hash"].ToString(); @@ -411,7 +411,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var request = requestBuilder.Build(); request.SetContent(body); - loginResult = await HttpClient.ExecuteAsync(request, Definition); + loginResult = await HttpClient.ExecuteProxiedAsync(request, Definition); } else { @@ -431,7 +431,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.AddFormParameter(pair.Key, pair.Value); } - loginResult = await HttpClient.ExecuteAsync(requestBuilder.Build(), Definition); + loginResult = await HttpClient.ExecuteProxiedAsync(requestBuilder.Build(), Definition); } Cookies = loginResult.GetCookies(); @@ -466,7 +466,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.Headers.Add("Referer", SiteLink); - var response = await HttpClient.ExecuteAsync(requestBuilder.Build(), Definition); + var response = await HttpClient.ExecuteProxiedAsync(requestBuilder.Build(), Definition); Cookies = response.GetCookies(); @@ -490,7 +490,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.Headers.Add("Referer", SiteLink); - var response = await HttpClient.ExecuteAsync(requestBuilder.Build(), Definition); + var response = await HttpClient.ExecuteProxiedAsync(requestBuilder.Build(), Definition); Cookies = response.GetCookies(); @@ -569,7 +569,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var request = requestBuilder.Build(); - landingResult = await HttpClient.ExecuteAsync(request, Definition); + landingResult = await HttpClient.ExecuteProxiedAsync(request, Definition); Cookies = landingResult.GetCookies(); @@ -613,7 +613,7 @@ namespace NzbDrone.Core.Indexers.Cardigann .SetHeader("Referer", loginUrl.AbsoluteUri) .Build(); - var response = await HttpClient.ExecuteAsync(request, Definition); + var response = await HttpClient.ExecuteProxiedAsync(request, Definition); return new Captcha { @@ -703,7 +703,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } } - var response = await HttpClient.ExecuteAsync(httpRequest.Build(), Definition); + var response = await HttpClient.ExecuteProxiedAsync(httpRequest.Build(), Definition); _logger.Debug($"CardigannIndexer ({_definition.Id}): handleRequest() remote server returned {response.StatusCode.ToString()}"); return response; @@ -743,7 +743,7 @@ namespace NzbDrone.Core.Indexers.Cardigann request.AllowAutoRedirect = true; - var response = await HttpClient.ExecuteAsync(request, Definition); + var response = await HttpClient.ExecuteProxiedAsync(request, Definition); var results = response.Content; var searchResultParser = new HtmlParser(); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs b/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs index 7b2980045..264aed562 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs @@ -63,7 +63,7 @@ namespace NzbDrone.Core.Indexers.Headphones try { - var response = await _httpClient.ExecuteAsync(request, Definition); + var response = await _httpClient.ExecuteProxiedAsync(request, Definition); downloadBytes = response.ResponseData; } catch (Exception) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs index fe069c0bc..29911e7db 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs @@ -56,7 +56,7 @@ namespace NzbDrone.Core.Indexers.Newznab try { - response = _httpClient.Execute(request, definition); + response = _httpClient.ExecuteProxied(request, definition); } catch (Exception ex) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs index 686a417a9..43d23d709 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs @@ -141,7 +141,7 @@ namespace NzbDrone.Core.Indexers.Definitions try { - var response = await _httpClient.ExecuteAsync(request, Definition); + var response = await _httpClient.ExecuteProxiedAsync(request, Definition); torrentData = response.ResponseData; } catch (HttpException ex) diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index 5a7c87bad..377acd25e 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -379,7 +379,7 @@ namespace NzbDrone.Core.Indexers request.HttpRequest.SuppressHttpError = true; request.HttpRequest.Encoding = Encoding; - var response = await _httpClient.ExecuteAsync(request.HttpRequest, Definition); + var response = await _httpClient.ExecuteProxiedAsync(request.HttpRequest, Definition); // Check reponse to see if auth is needed, if needed try again if (CheckIfLoginNeeded(response)) @@ -391,7 +391,7 @@ namespace NzbDrone.Core.Indexers request.HttpRequest.Url = originalUrl; ModifyRequest(request); - response = await _httpClient.ExecuteAsync(request.HttpRequest, Definition); + response = await _httpClient.ExecuteProxiedAsync(request.HttpRequest, Definition); } // Throw common http errors here before we try to parse @@ -414,7 +414,7 @@ namespace NzbDrone.Core.Indexers { request.Encoding = Encoding; - var response = await _httpClient.ExecuteAsync(request, Definition); + var response = await _httpClient.ExecuteProxiedAsync(request, Definition); _eventAggregator.PublishEvent(new IndexerAuthEvent(Definition.Id, !response.HasHttpError, response.ElapsedTime)); diff --git a/src/NzbDrone.Core/Indexers/IndexerHttpClient.cs b/src/NzbDrone.Core/Indexers/IndexerHttpClient.cs index 1558b139c..34e8715f4 100644 --- a/src/NzbDrone.Core/Indexers/IndexerHttpClient.cs +++ b/src/NzbDrone.Core/Indexers/IndexerHttpClient.cs @@ -14,8 +14,8 @@ namespace NzbDrone.Core.Indexers { public interface IIndexerHttpClient : IHttpClient { - Task<HttpResponse> ExecuteAsync(HttpRequest request, ProviderDefinition definition); - HttpResponse Execute(HttpRequest request, ProviderDefinition definition); + Task<HttpResponse> ExecuteProxiedAsync(HttpRequest request, ProviderDefinition definition); + HttpResponse ExecuteProxied(HttpRequest request, ProviderDefinition definition); } public class IndexerHttpClient : HttpClient, IIndexerHttpClient @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Indexers _indexerProxyFactory = indexerProxyFactory; } - public async Task<HttpResponse> ExecuteAsync(HttpRequest request, ProviderDefinition definition) + public async Task<HttpResponse> ExecuteProxiedAsync(HttpRequest request, ProviderDefinition definition) { var selectedProxy = GetProxy(definition); @@ -41,7 +41,7 @@ namespace NzbDrone.Core.Indexers return PostResponse(await ExecuteAsync(request), selectedProxy); } - public HttpResponse Execute(HttpRequest request, ProviderDefinition definition) + public HttpResponse ExecuteProxied(HttpRequest request, ProviderDefinition definition) { var selectedProxy = GetProxy(definition); diff --git a/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs b/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs index 3275caade..451d001a7 100644 --- a/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs @@ -43,7 +43,7 @@ namespace NzbDrone.Core.Indexers try { - var response = await _httpClient.ExecuteAsync(request, Definition); + var response = await _httpClient.ExecuteProxiedAsync(request, Definition); torrentData = response.ResponseData; } catch (HttpException ex) diff --git a/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs b/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs index 93c559e19..af3044c33 100644 --- a/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs @@ -39,7 +39,7 @@ namespace NzbDrone.Core.Indexers try { - var response = await _httpClient.ExecuteAsync(request, Definition); + var response = await _httpClient.ExecuteProxiedAsync(request, Definition); nzbData = response.ResponseData; _logger.Debug("Downloaded nzb for release finished ({0} bytes from {1})", nzbData.Length, link.AbsoluteUri); From 9eba50d9db5e8c8ccadf131db0f9f35ff1a1725d Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Fri, 8 Oct 2021 08:49:10 -0500 Subject: [PATCH 0093/2320] New: Log which DB is being migrated (cherry picked from Sonarr commit 07c95f06d3b9b32aaeb923d4c678f10a2bf1141a) --- .../Migration/Framework/NzbDroneMigrationBase.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Datastore/Migration/Framework/NzbDroneMigrationBase.cs b/src/NzbDrone.Core/Datastore/Migration/Framework/NzbDroneMigrationBase.cs index 96cd14011..20971d097 100644 --- a/src/NzbDrone.Core/Datastore/Migration/Framework/NzbDroneMigrationBase.cs +++ b/src/NzbDrone.Core/Datastore/Migration/Framework/NzbDroneMigrationBase.cs @@ -41,15 +41,18 @@ namespace NzbDrone.Core.Datastore.Migration.Framework switch (MigrationContext.Current.MigrationType) { case MigrationType.Main: - _logger.Info("Starting migration to " + Version); + LogMigrationMessage(MigrationType.Main); MainDbUpgrade(); return; case MigrationType.Log: - _logger.Info("Starting migration to " + Version); + LogMigrationMessage(MigrationType.Log); LogDbUpgrade(); return; default: + LogMigrationMessage(MigrationType.Log); LogDbUpgrade(); + + LogMigrationMessage(MigrationType.Main); MainDbUpgrade(); return; } @@ -59,5 +62,10 @@ namespace NzbDrone.Core.Datastore.Migration.Framework { throw new NotImplementedException(); } + + private void LogMigrationMessage(MigrationType type) + { + _logger.Info("Starting migration of {0} DB to {1}", type.ToString(), Version); + } } } From 25bb10d62b518e400710576f3a6e7267f00350c8 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 6 Oct 2021 21:19:29 -0500 Subject: [PATCH 0094/2320] New: (Cardigann) AllowRawSearch Property --- .../Indexers/Definitions/Cardigann/CardigannDefinition.cs | 1 + src/NzbDrone.Core/Indexers/IndexerFactory.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs index 4a69943c6..e930f1488 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs @@ -70,6 +70,7 @@ namespace NzbDrone.Core.Indexers.Cardigann public Dictionary<string, string> Categories { get; set; } public List<CategorymappingBlock> Categorymappings { get; set; } public Dictionary<string, List<string>> Modes { get; set; } + public bool AllowRawSearch { get; set; } } public class CaptchaBlock diff --git a/src/NzbDrone.Core/Indexers/IndexerFactory.cs b/src/NzbDrone.Core/Indexers/IndexerFactory.cs index 9096d22b9..26f20a4e0 100644 --- a/src/NzbDrone.Core/Indexers/IndexerFactory.cs +++ b/src/NzbDrone.Core/Indexers/IndexerFactory.cs @@ -97,6 +97,7 @@ namespace NzbDrone.Core.Indexers definition.Privacy = defFile.Type == "private" ? IndexerPrivacy.Private : IndexerPrivacy.Public; definition.Capabilities = new IndexerCapabilities(); definition.Capabilities.ParseCardigannSearchModes(defFile.Caps.Modes); + definition.Capabilities.SupportsRawSearch = defFile.Caps.AllowRawSearch; MapCardigannCategories(definition, defFile); } From 293b32ea0efbacd33c5b1fdfad036720acdc1499 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 6 Oct 2021 21:55:35 -0500 Subject: [PATCH 0095/2320] New: Improve size and number parsing --- .../ParserTests/ParseUtilFixture.cs | 24 ++++++++ .../Indexers/Definitions/Anidub.cs | 2 +- .../Indexers/Definitions/AnimeTorrents.cs | 2 +- .../Indexers/Definitions/Animedia.cs | 2 +- .../Indexers/Definitions/Anthelion.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/BB.cs | 2 +- .../Indexers/Definitions/BakaBT.cs | 3 +- .../Indexers/Definitions/BinSearch.cs | 2 +- .../Definitions/Cardigann/CardigannParser.cs | 2 +- .../Indexers/Definitions/GazelleGames.cs | 2 +- .../Indexers/Definitions/HDSpace.cs | 2 +- .../Indexers/Definitions/HDTorrents.cs | 2 +- .../Indexers/Definitions/IPTorrents.cs | 2 +- .../Indexers/Definitions/ImmortalSeed.cs | 2 +- .../Indexers/Definitions/MyAnonamouse.cs | 2 +- .../Indexers/Definitions/Nebulance.cs | 2 +- .../Indexers/Definitions/PreToMe.cs | 2 +- .../Indexers/Definitions/RevolutionTT.cs | 2 +- .../Indexers/Definitions/RuTracker.cs | 2 +- .../Indexers/Definitions/SceneTime.cs | 2 +- .../Indexers/Definitions/TVVault.cs | 2 +- .../Indexers/Definitions/TorrentSeeds.cs | 2 +- .../Indexers/Definitions/ZonaQ.cs | 2 +- src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs | 42 ------------- src/NzbDrone.Core/Parser/ParseUtil.cs | 60 +++++++++++++++++-- 25 files changed, 103 insertions(+), 68 deletions(-) create mode 100644 src/NzbDrone.Core.Test/ParserTests/ParseUtilFixture.cs diff --git a/src/NzbDrone.Core.Test/ParserTests/ParseUtilFixture.cs b/src/NzbDrone.Core.Test/ParserTests/ParseUtilFixture.cs new file mode 100644 index 000000000..88ad41303 --- /dev/null +++ b/src/NzbDrone.Core.Test/ParserTests/ParseUtilFixture.cs @@ -0,0 +1,24 @@ +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.ParserTests +{ + [TestFixture] + public class ParseUtilFixture : CoreTest + { + [TestCase("1023.4 KB", 1047961)] + [TestCase("1023.4 MB", 1073112704)] + [TestCase("1,023.4 MB", 1073112704)] + [TestCase("1.023,4 MB", 1073112704)] + [TestCase("1 023,4 MB", 1073112704)] + [TestCase("1.023.4 MB", 1073112704)] + [TestCase("1023.4 GB", 1098867408896)] + [TestCase("1023.4 TB", 1125240226709504)] + public void should_parse_size(string stringSize, long size) + { + ParseUtil.GetBytes(stringSize).Should().Be(size); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs b/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs index 8905fddb4..d656f9ce4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs @@ -405,7 +405,7 @@ namespace NzbDrone.Core.Indexers.Definitions const string SizeSelector = ".list.down > .red"; var sizeStr = tabNode.QuerySelector(SizeSelector).TextContent; - return ReleaseInfo.GetBytes(sizeStr); + return ParseUtil.GetBytes(sizeStr); } private string GetReleaseLink(AngleSharp.Dom.IElement tabNode) diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs index 600205049..0e0b59de6 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs @@ -276,7 +276,7 @@ namespace NzbDrone.Core.Indexers.Definitions } var sizeStr = row.QuerySelector("td:nth-of-type(6)").TextContent; - release.Size = ReleaseInfo.GetBytes(sizeStr); + release.Size = ParseUtil.GetBytes(sizeStr); var connections = row.QuerySelector("td:nth-of-type(8)").TextContent.Trim().Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs b/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs index 855c6dade..cb4980a5d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs @@ -210,7 +210,7 @@ namespace NzbDrone.Core.Indexers.Definitions private long getReleaseSize(AngleSharp.Dom.IElement tr) { var sizeStr = tr.QuerySelector("div.tracker_info_left").TextContent; - return ReleaseInfo.GetBytes(SizeInfoQueryRegex.Match(sizeStr).Groups[1].Value.Trim()); + return ParseUtil.GetBytes(SizeInfoQueryRegex.Match(sizeStr).Groups[1].Value.Trim()); } private DateTime getReleaseDate(AngleSharp.Dom.IElement tr) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs b/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs index 80189259b..b52b49a14 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs @@ -242,7 +242,7 @@ namespace NzbDrone.Core.Indexers.Definitions var files = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(3)").TextContent); var publishDate = DateTimeUtil.FromTimeAgo(row.QuerySelector("td:nth-child(4)").TextContent); - var size = ReleaseInfo.GetBytes(row.QuerySelector("td:nth-child(5)").FirstChild.TextContent); + var size = ParseUtil.GetBytes(row.QuerySelector("td:nth-child(5)").FirstChild.TextContent); var grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(6)").TextContent); var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(7)").TextContent); var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(8)").TextContent); diff --git a/src/NzbDrone.Core/Indexers/Definitions/BB.cs b/src/NzbDrone.Core/Indexers/Definitions/BB.cs index 5934fd4d3..ac722626c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BB.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BB.cs @@ -279,7 +279,7 @@ namespace NzbDrone.Core.Indexers.Definitions release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); var sizeStr = row.Children[4].TextContent; - release.Size = ReleaseInfo.GetBytes(sizeStr); + release.Size = ParseUtil.GetBytes(sizeStr); release.Files = ParseUtil.CoerceInt(row.Children[2].TextContent.Trim()); release.Seeders = ParseUtil.CoerceInt(row.Children[7].TextContent.Trim()); diff --git a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs index a9e0e601d..a24077037 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs @@ -15,6 +15,7 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Validation; @@ -342,7 +343,7 @@ namespace NzbDrone.Core.Indexers.Definitions release.MinimumSeedTime = 172800; // 48 hours var size = row.QuerySelector(".size").TextContent; - release.Size = ReleaseInfo.GetBytes(size); + release.Size = ParseUtil.GetBytes(size); //22 Jul 15 var dateStr = row.QuerySelector(".added").TextContent.Replace("'", string.Empty); diff --git a/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs b/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs index b1eab50c4..dd51ae064 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs @@ -194,7 +194,7 @@ namespace NzbDrone.Core.Indexers.Definitions { Guid = guid, Title = parsedTitle.Groups["title"].Value, - Size = ReleaseInfo.GetBytes(string.Format("{0} {1}", size.Groups["size"].Value, size.Groups["unit"].Value)), + Size = ParseUtil.GetBytes(string.Format("{0} {1}", size.Groups["size"].Value, size.Groups["unit"].Value)), PublishDate = publishDate, Categories = new List<IndexerCategory> { NewznabStandardCategory.Other }, InfoUrl = infoUrl, diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index 57d4e469f..525e67410 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -209,7 +209,7 @@ namespace NzbDrone.Core.Indexers.Cardigann value = release.Categories.ToString(); break; case "size": - release.Size = ReleaseInfo.GetBytes(value); + release.Size = ParseUtil.GetBytes(value); value = release.Size.ToString(); break; case "leechers": diff --git a/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs b/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs index b69cf9595..0a85320d2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs @@ -361,7 +361,7 @@ namespace NzbDrone.Core.Indexers.Definitions var details = _settings.BaseUrl + qDetailsLink.GetAttribute("href"); var grabs = ParseUtil.CoerceInt(qGrabs.TextContent); var leechers = ParseUtil.CoerceInt(qLeechers.TextContent); - var size = ReleaseInfo.GetBytes(sizeString); + var size = ParseUtil.GetBytes(sizeString); var release = new TorrentInfo { diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs b/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs index de83b0fa5..e4742cc0e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs @@ -276,7 +276,7 @@ namespace NzbDrone.Core.Indexers.Definitions //"July 11, 2015, 13:34:09", "Today|Yesterday at 20:04:23" release.PublishDate = DateTimeUtil.FromUnknown(dateStr); var sizeStr = row.Children[5].TextContent; - release.Size = ReleaseInfo.GetBytes(sizeStr); + release.Size = ParseUtil.GetBytes(sizeStr); release.Seeders = ParseUtil.CoerceInt(row.Children[7].TextContent); release.Peers = ParseUtil.CoerceInt(row.Children[8].TextContent) + release.Seeders; var grabs = row.QuerySelector("td:nth-child(10)").TextContent; diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs index 4c860d812..f206e3a3e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs @@ -259,7 +259,7 @@ namespace NzbDrone.Core.Indexers.Definitions var link = new Uri(_settings.BaseUrl + row.Children[4].FirstElementChild.GetAttribute("href")); var description = row.Children[2].QuerySelector("span").TextContent; - var size = ReleaseInfo.GetBytes(row.Children[7].TextContent); + var size = ParseUtil.GetBytes(row.Children[7].TextContent); var dateTag = row.Children[6].FirstElementChild; var dateString = string.Join(" ", dateTag.Attributes.Select(attr => attr.Name)); diff --git a/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs index 31d651112..445a0980a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs @@ -304,7 +304,7 @@ namespace NzbDrone.Core.Indexers.Definitions // Torrents - Category column == Icons var cat = _categories.MapTrackerCatToNewznab(catIcon.GetAttribute("href").Substring(1)); - var size = ReleaseInfo.GetBytes(row.Children[5].TextContent); + var size = ParseUtil.GetBytes(row.Children[5].TextContent); var colIndex = 6; int? files = null; diff --git a/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs b/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs index 77b81d1fc..29224d5a6 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs @@ -280,7 +280,7 @@ namespace NzbDrone.Core.Indexers.Definitions release.PublishDate = DateTime.ParseExact(dateString, "yyyy-MM-dd hh:mm tt", CultureInfo.InvariantCulture); var sizeStr = row.QuerySelector("td:nth-of-type(5)").TextContent.Trim(); - release.Size = ReleaseInfo.GetBytes(sizeStr); + release.Size = ParseUtil.GetBytes(sizeStr); release.Seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(7)").TextContent.Trim()); release.Peers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(8)").TextContent.Trim()) + release.Seeders; diff --git a/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs b/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs index 02d30567b..eb7f716ea 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs @@ -360,7 +360,7 @@ namespace NzbDrone.Core.Indexers.Definitions release.Seeders = item.Seeders; release.Peers = item.Leechers + release.Seeders; var size = item.Size; - release.Size = ReleaseInfo.GetBytes(size); + release.Size = ParseUtil.GetBytes(size); release.DownloadVolumeFactor = item.Free ? 0 : 1; release.UploadVolumeFactor = 1; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs index 7776608fa..71327650c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs @@ -224,7 +224,7 @@ namespace NzbDrone.Core.Indexers.Definitions var link = _settings.BaseUrl + row.QuerySelector("a[href*='action=download']").GetAttribute("href"); var qColSize = row.QuerySelector("td:nth-child(3)"); - var size = ReleaseInfo.GetBytes(qColSize.Children[0].TextContent); + var size = ParseUtil.GetBytes(qColSize.Children[0].TextContent); var files = ParseUtil.CoerceInt(qColSize.Children[1].TextContent.Split(':')[1].Trim()); var qPublishdate = row.QuerySelector("td:nth-child(4) span"); diff --git a/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs b/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs index f0d69065f..4033a23f2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs @@ -342,7 +342,7 @@ namespace NzbDrone.Core.Indexers.Definitions var dateStr = Regex.Replace(row.Children[5].InnerHtml, @"\<br[\s]{0,1}[\/]{0,1}\>", " "); var publishDate = DateTimeUtil.FromTimeAgo(dateStr); var files = ParseUtil.CoerceInt(row.Children[3].TextContent); - var size = ReleaseInfo.GetBytes(row.Children[7].TextContent); + var size = ParseUtil.GetBytes(row.Children[7].TextContent); var grabs = ParseUtil.CoerceInt(row.Children[8].TextContent); var seeders = ParseUtil.CoerceInt(row.Children[9].TextContent); var leechers = ParseUtil.CoerceInt(row.Children[10].TextContent); diff --git a/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs b/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs index 41e66ba09..f3bb2e387 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs @@ -281,7 +281,7 @@ namespace NzbDrone.Core.Indexers.Definitions var dateString = row.QuerySelector("td:nth-child(6) nobr").TextContent.Trim(); var publishDate = DateTime.ParseExact(dateString, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture); - var size = ReleaseInfo.GetBytes(row.QuerySelector("td:nth-child(7)").InnerHtml.Split('<').First().Trim()); + var size = ParseUtil.GetBytes(row.QuerySelector("td:nth-child(7)").InnerHtml.Split('<').First().Trim()); var files = ParseUtil.GetLongFromString(row.QuerySelector("td:nth-child(7) > a").TextContent); var grabs = ParseUtil.GetLongFromString(row.QuerySelector("td:nth-child(8)").TextContent); var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(9)").TextContent); diff --git a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs index 408c7ad83..3717a04f7 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs @@ -1672,7 +1672,7 @@ namespace NzbDrone.Core.Indexers.Definitions private long GetSizeOfRelease(in IElement row) { var qSize = row.QuerySelector("td.tor-size"); - var size = ReleaseInfo.GetBytes(qSize.GetAttribute("data-ts_text")); + var size = ParseUtil.GetBytes(qSize.GetAttribute("data-ts_text")); return size; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs b/src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs index 12649f599..890881000 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs @@ -254,7 +254,7 @@ namespace NzbDrone.Core.Indexers.Definitions DownloadUrl = string.Format("{0}/download.php/{1}/download.torrent", _settings.BaseUrl, torrentId), Guid = details, PublishDate = DateTimeUtil.FromTimeAgo(qDescCol.ChildNodes.Last().TextContent), - Size = ReleaseInfo.GetBytes(sizeStr), + Size = ParseUtil.GetBytes(sizeStr), Seeders = seeders, Peers = ParseUtil.CoerceInt(row.Children[leechersIndex].TextContent.Trim()) + seeders, DownloadVolumeFactor = row.QuerySelector("font > b:contains(Freeleech)") != null ? 0 : 1, diff --git a/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs b/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs index 48958a972..fd796d284 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs @@ -256,7 +256,7 @@ namespace NzbDrone.Core.Indexers.Definitions var files = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(3)").TextContent); var publishDate = DateTimeUtil.FromTimeAgo(row.QuerySelector("td:nth-child(4)").TextContent); - var size = ReleaseInfo.GetBytes(row.QuerySelector("td:nth-child(5)").FirstChild.TextContent); + var size = ParseUtil.GetBytes(row.QuerySelector("td:nth-child(5)").FirstChild.TextContent); var grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(6)").TextContent); var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(7)").TextContent); var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(8)").TextContent); diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs index d27850ec9..c164c8d28 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs @@ -314,7 +314,7 @@ namespace NzbDrone.Core.Indexers.Definitions var qColumns = row.QuerySelectorAll("td"); release.Files = ParseUtil.CoerceInt(qColumns[3].TextContent); release.PublishDate = DateTimeUtil.FromUnknown(qColumns[5].TextContent); - release.Size = ReleaseInfo.GetBytes(qColumns[6].TextContent); + release.Size = ParseUtil.GetBytes(qColumns[6].TextContent); release.Grabs = ParseUtil.CoerceInt(qColumns[7].TextContent.Replace("Times", "")); release.Seeders = ParseUtil.CoerceInt(qColumns[8].TextContent); release.Peers = ParseUtil.CoerceInt(qColumns[9].TextContent) + release.Seeders; diff --git a/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs b/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs index 9ae731a0f..328ca8aef 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs @@ -355,7 +355,7 @@ namespace NzbDrone.Core.Indexers.Definitions var publishDateStr = row.Children[4].InnerHtml.Split('>').Last(); var publishDate = DateTime.ParseExact(publishDateStr, "dd/MM/yyyy", CultureInfo.InvariantCulture); - var size = ReleaseInfo.GetBytes(row.Children[5].TextContent.Replace(".", "").Replace(",", ".")); + var size = ParseUtil.GetBytes(row.Children[5].TextContent.Replace(".", "").Replace(",", ".")); var seeders = ParseUtil.CoerceInt(row.Children[6].TextContent); var leechers = ParseUtil.CoerceInt(row.Children[7].TextContent); var grabs = ParseUtil.CoerceInt(row.Children[8].TextContent); diff --git a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs index 3642dc7e6..c2f023b60 100644 --- a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs +++ b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs @@ -99,47 +99,5 @@ namespace NzbDrone.Core.Parser.Model return ToString(); } } - - public static long GetBytes(string str) - { - var valStr = new string(str.Where(c => char.IsDigit(c) || c == '.').ToArray()); - var unit = new string(str.Where(char.IsLetter).ToArray()); - var val = ParseUtil.CoerceFloat(valStr); - return GetBytes(unit, val); - } - - public static long GetBytes(string unit, float value) - { - unit = unit.Replace("i", "").ToLowerInvariant(); - if (unit.Contains("kb")) - { - return BytesFromKB(value); - } - - if (unit.Contains("mb")) - { - return BytesFromMB(value); - } - - if (unit.Contains("gb")) - { - return BytesFromGB(value); - } - - if (unit.Contains("tb")) - { - return BytesFromTB(value); - } - - return (long)value; - } - - public static long BytesFromTB(float tb) => BytesFromGB(tb * 1024f); - - public static long BytesFromGB(float gb) => BytesFromMB(gb * 1024f); - - public static long BytesFromMB(float mb) => BytesFromKB(mb * 1024f); - - public static long BytesFromKB(float kb) => (long)(kb * 1024f); } } diff --git a/src/NzbDrone.Core/Parser/ParseUtil.cs b/src/NzbDrone.Core/Parser/ParseUtil.cs index cdf651476..c157bf3dc 100644 --- a/src/NzbDrone.Core/Parser/ParseUtil.cs +++ b/src/NzbDrone.Core/Parser/ParseUtil.cs @@ -18,10 +18,20 @@ namespace NzbDrone.Core.Parser public static string NormalizeMultiSpaces(string s) => new Regex(@"\s+").Replace(NormalizeSpace(s), " "); - public static string NormalizeNumber(string s) => - NormalizeSpace(s) - .Replace("-", "0") - .Replace(",", ""); + public static string NormalizeNumber(string s) + { + s = (s.Length == 0) ? "0" : s.Replace(",", "."); + + s = NormalizeSpace(s).Replace("-", "0"); + + if (s.Count(c => c == '.') > 1) + { + var lastOcc = s.LastIndexOf('.'); + s = s.Substring(0, lastOcc).Replace(".", string.Empty) + s.Substring(lastOcc); + } + + return s; + } public static string RemoveInvalidXmlChars(string text) => string.IsNullOrEmpty(text) ? "" : InvalidXmlChars.Replace(text, ""); @@ -98,5 +108,47 @@ namespace NzbDrone.Core.Parser var qs = QueryHelpers.ParseQuery(qsStr); return qs[argument].FirstOrDefault(); } + + public static long GetBytes(string str) + { + var valStr = new string(str.Where(c => char.IsDigit(c) || c == '.' || c == ',').ToArray()); + var unit = new string(str.Where(char.IsLetter).ToArray()); + var val = CoerceFloat(valStr); + return GetBytes(unit, val); + } + + public static long GetBytes(string unit, float value) + { + unit = unit.Replace("i", "").ToLowerInvariant(); + if (unit.Contains("kb")) + { + return BytesFromKB(value); + } + + if (unit.Contains("mb")) + { + return BytesFromMB(value); + } + + if (unit.Contains("gb")) + { + return BytesFromGB(value); + } + + if (unit.Contains("tb")) + { + return BytesFromTB(value); + } + + return (long)value; + } + + public static long BytesFromTB(float tb) => BytesFromGB(tb * 1024f); + + public static long BytesFromGB(float gb) => BytesFromMB(gb * 1024f); + + public static long BytesFromMB(float mb) => BytesFromKB(mb * 1024f); + + public static long BytesFromKB(float kb) => (long)(kb * 1024f); } } From c5caf2237516a470016501b635e3a4c9cc7f36af Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 16 Aug 2021 19:59:36 -0500 Subject: [PATCH 0096/2320] New: Support for Prowlarr Definitions v2 New: Support for Updated yml Definitions Fixes: #298 --- .../IndexerDefinitionUpdateService.cs | 4 +- .../Cardigann/CardigannDefinition.cs | 24 ++- .../Cardigann/CardigannRequestGenerator.cs | 185 ++++++++++++++---- 3 files changed, 173 insertions(+), 40 deletions(-) diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index 8f861e017..d12d9a042 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -24,7 +24,9 @@ namespace NzbDrone.Core.IndexerVersions public class IndexerDefinitionUpdateService : IIndexerDefinitionUpdateService, IExecute<IndexerDefinitionUpdateCommand> { - private const int DEFINITION_VERSION = 1; + /* Update Service will fall back if version # does not exist for an indexer per Ta */ + + private const int DEFINITION_VERSION = 2; private readonly List<string> _defintionBlocklist = new List<string>() { "aither", diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs index e930f1488..c666af501 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs @@ -39,6 +39,7 @@ namespace NzbDrone.Core.Indexers.Cardigann public List<string> Links { get; set; } public List<string> Legacylinks { get; set; } public bool Followredirect { get; set; } = false; + public bool TestLinkTorrent { get; set; } = true; public List<string> Certificates { get; set; } public CapabilitiesBlock Caps { get; set; } public LoginBlock Login { get; set; } @@ -167,11 +168,30 @@ namespace NzbDrone.Core.Indexers.Cardigann } public class DownloadBlock + { + public List<SelectorField> Selectors { get; set; } + public string Method { get; set; } + public BeforeBlock Before { get; set; } + public InfohashBlock Infohash { get; set; } + } + + public class InfohashBlock + { + public SelectorField Hash { get; set; } + public SelectorField Title { get; set; } + public bool UseBeforeResponse { get; set; } + } + + public class SelectorField { public string Selector { get; set; } public string Attribute { get; set; } + public bool UseBeforeResponse { get; set; } public List<FilterBlock> Filters { get; set; } - public string Method { get; set; } - public RequestBlock Before { get; set; } + } + + public class BeforeBlock : RequestBlock + { + public SelectorField Pathselector { get; set; } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 9fe82b64d..283481615 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -721,9 +721,26 @@ namespace NzbDrone.Core.Indexers.Cardigann AddTemplateVariablesFromUri(variables, link, ".DownloadUri"); - if (download.Before != null) + var headers = ParseCustomHeaders(_definition.Search?.Headers, variables); + HttpResponse response = null; + + var request = new HttpRequestBuilder(link.ToString()) + .SetCookies(Cookies ?? new Dictionary<string, string>()) + .SetHeaders(headers ?? new Dictionary<string, string>()) + .Build(); + + request.AllowAutoRedirect = true; + + var beforeBlock = download.Before; + if (beforeBlock != null) { - await HandleRequest(download.Before, variables, link.ToString()); + if (beforeBlock.Pathselector != null) + { + response = await HttpClient.ExecuteProxiedAsync(request, Definition); + beforeBlock.Path = MatchSelector(response, beforeBlock.Pathselector, variables); + } + + response = await HandleRequest(beforeBlock, variables, link.ToString()); } if (download.Method == "post") @@ -731,49 +748,105 @@ namespace NzbDrone.Core.Indexers.Cardigann method = HttpMethod.POST; } - if (download.Selector != null) + if (download.Infohash != null) { - var selector = ApplyGoTemplateText(download.Selector, variables); - var headers = ParseCustomHeaders(_definition.Search?.Headers, variables); - - var request = new HttpRequestBuilder(link.ToString()) - .SetCookies(Cookies ?? new Dictionary<string, string>()) - .SetHeaders(headers ?? new Dictionary<string, string>()) - .Build(); - - request.AllowAutoRedirect = true; - - var response = await HttpClient.ExecuteProxiedAsync(request, Definition); - - var results = response.Content; - var searchResultParser = new HtmlParser(); - var searchResultDocument = searchResultParser.ParseDocument(results); - var downloadElement = searchResultDocument.QuerySelector(selector); - if (downloadElement != null) + try { - _logger.Debug(string.Format("CardigannIndexer ({0}): Download selector {1} matched:{2}", _definition.Id, selector, downloadElement.ToHtmlPretty())); + headers = ParseCustomHeaders(_definition.Search?.Headers, variables); - var href = ""; - if (download.Attribute != null) + if (!download.Infohash.UseBeforeResponse || download.Before == null || response == null) { - href = downloadElement.GetAttribute(download.Attribute); + response = await HttpClient.ExecuteProxiedAsync(request, Definition); + } + + var hash = MatchSelector(response, download.Infohash.Hash, variables); + if (hash == null) + { + throw new Exception($"InfoHash selectors didn't match"); + } + + var title = MatchSelector(response, download.Infohash.Title, variables); + if (title == null) + { + throw new Exception($"InfoHash selectors didn't match"); + } + + var magnet = MagnetLinkBuilder.BuildPublicMagnetLink(hash, title); + var torrentLink = ResolvePath(magnet, link); + + var hashDownloadRequest = new HttpRequestBuilder(torrentLink.AbsoluteUri) + .SetCookies(Cookies ?? new Dictionary<string, string>()) + .Build(); + + hashDownloadRequest.Method = method; + + return hashDownloadRequest; + } + catch (Exception) + { + _logger.Error("CardigannIndexer ({0}): Exception with InfoHash block with hashSelector {1} and titleSelector {2}", + _definition.Id, + download.Infohash.Hash.Selector, + download.Infohash.Title.Selector); + } + } + else if (download.Selectors != null) + { + headers = ParseCustomHeaders(_definition.Search?.Headers, variables); + + foreach (var selector in download.Selectors) + { + var queryselector = ApplyGoTemplateText(selector.Selector, variables); + + try + { + if (!selector.UseBeforeResponse || download.Before == null || response == null) + { + response = await HttpClient.ExecuteProxiedAsync(request, Definition); + } + + var href = MatchSelector(response, selector, variables, debugMatch: true); if (href == null) { - throw new Exception(string.Format("Attribute \"{0}\" is not set for element {1}", download.Attribute, downloadElement.ToHtmlPretty())); + continue; } - } - else - { - href = downloadElement.TextContent; - } - href = ApplyFilters(href, download.Filters, variables); - link = ResolvePath(href, link); - } - else - { - _logger.Error(string.Format("CardigannIndexer ({0}): Download selector {1} didn't match:\n{2}", _definition.Id, download.Selector, results)); - throw new Exception(string.Format("Download selector {0} didn't match", download.Selector)); + var torrentLink = ResolvePath(href, link); + if (torrentLink.Scheme != "magnet" && _definition.TestLinkTorrent) + { + // Test link + var testLinkRequest = new HttpRequestBuilder(torrentLink.ToString()) + .SetCookies(Cookies ?? new Dictionary<string, string>()) + .SetHeaders(headers ?? new Dictionary<string, string>()) + .Build(); + + response = await HttpClient.ExecuteProxiedAsync(testLinkRequest, Definition); + + var content = response.Content; + if (content.Length >= 1 && content[0] != 'd') + { + _logger.Debug("CardigannIndexer ({0}): Download selector {1}'s torrent file is invalid, retrying with next available selector", _definition.Id, queryselector); + + continue; + } + } + + link = torrentLink; + + var selectorDownloadRequest = new HttpRequestBuilder(link.AbsoluteUri) + .SetCookies(Cookies ?? new Dictionary<string, string>()) + .Build(); + + selectorDownloadRequest.Method = method; + + return selectorDownloadRequest; + } + catch (Exception e) + { + _logger.Error("{0} CardigannIndexer ({1}): An exception occurred while trying selector {2}, retrying with next available selector", e, _definition.Id, queryselector); + + throw new Exception(string.Format("An exception occurred while trying selector {0}", queryselector)); + } } } } @@ -787,6 +860,44 @@ namespace NzbDrone.Core.Indexers.Cardigann return downloadRequest; } + protected string MatchSelector(HttpResponse response, SelectorField selector, Dictionary<string, object> variables, bool debugMatch = false) + { + var selectorText = ApplyGoTemplateText(selector.Selector, variables); + var parser = new HtmlParser(); + + var results = response.Content; + var resultDocument = parser.ParseDocument(results); + + var element = resultDocument.QuerySelector(selectorText); + if (element == null) + { + _logger.Debug($"CardigannIndexer ({_definition.Id}): Selector {selectorText} could not match any elements."); + return null; + } + + if (debugMatch) + { + _logger.Debug($"CardigannIndexer ({_definition.Id}): Download selector {selector} matched:{element.ToHtmlPretty()}"); + } + + string val; + if (selector.Attribute != null) + { + val = element.GetAttribute(selector.Attribute); + if (val == null) + { + throw new Exception($"Attribute \"{selector.Attribute}\" is not set for element {element.ToHtmlPretty()}"); + } + } + else + { + val = element.TextContent; + } + + val = ApplyFilters(val, selector.Filters, variables); + return val; + } + public bool CheckIfLoginIsNeeded(HttpResponse response) { if (response.HasHttpRedirect) From 8b8b5ba1c800c978b3ef6f1e3c16b1ee048a276e Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 9 Oct 2021 23:31:14 -0500 Subject: [PATCH 0097/2320] Cleanup cardigann logging --- .../Definitions/Cardigann/CardigannRequestGenerator.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 283481615..b08755ca2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -590,7 +590,7 @@ namespace NzbDrone.Core.Indexers.Cardigann if (captcha != null && automaticlogin) { - _logger.Error(string.Format("CardigannIndexer ({0}): Found captcha during automatic login, aborting", _definition.Id)); + _logger.Error("CardigannIndexer ({0}): Found captcha during automatic login, aborting", _definition.Id); } return captcha; @@ -623,7 +623,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } else { - _logger.Debug(string.Format("CardigannIndexer ({0}): No captcha image found", _definition.Id)); + _logger.Debug("CardigannIndexer ({0}): No captcha image found", _definition.Id); } } else @@ -650,7 +650,8 @@ namespace NzbDrone.Core.Indexers.Cardigann protected async Task<HttpResponse> HandleRequest(RequestBlock request, Dictionary<string, object> variables = null, string referer = null) { var requestLinkStr = ResolvePath(ApplyGoTemplateText(request.Path, variables)).ToString(); - _logger.Debug($"CardigannIndexer ({_definition.Id}): handleRequest() requestLinkStr= {requestLinkStr}"); + + _logger.Debug("CardigannIndexer ({0}): handleRequest() requestLinkStr= {1}", _definition.Id, requestLinkStr); Dictionary<string, string> pairs = null; var queryCollection = new NameValueCollection(); @@ -705,7 +706,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var response = await HttpClient.ExecuteProxiedAsync(httpRequest.Build(), Definition); - _logger.Debug($"CardigannIndexer ({_definition.Id}): handleRequest() remote server returned {response.StatusCode.ToString()}"); + _logger.Debug("CardigannIndexer ({0}): handleRequest() remote server returned {1}", _definition.Id, response.StatusCode); return response; } From 5dfe530cf31a4566c57aab260fa0c42e614d7830 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 10 Oct 2021 14:06:30 -0500 Subject: [PATCH 0098/2320] Fixed: (BB) Detect when re-auth needed --- src/NzbDrone.Core/Indexers/Definitions/BB.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BB.cs b/src/NzbDrone.Core/Indexers/Definitions/BB.cs index ac722626c..4950814a6 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BB.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BB.cs @@ -103,6 +103,11 @@ namespace NzbDrone.Core.Indexers.Definitions protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) { + if (!httpResponse.Content.Contains("logout.php")) + { + return true; + } + return false; } From 76d73aa6a92d0d8689d7aaa7c57a024c16836e6c Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 10 Oct 2021 14:23:42 -0500 Subject: [PATCH 0099/2320] New: (Indexer) SpeedCD --- .../Indexers/Definitions/SpeedCD.cs | 369 ++++++++++++++++++ 1 file changed, 369 insertions(+) create mode 100644 src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs new file mode 100644 index 000000000..520a6ea21 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs @@ -0,0 +1,369 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using AngleSharp.Html.Parser; +using FluentValidation; +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Indexers.Definitions +{ + public class SpeedCD : TorrentIndexerBase<SpeedCDSettings> + { + public override string Name => "SpeedCD"; + public override string[] IndexerUrls => new string[] + { + "https://speed.cd/", + "https://speed.click/", + "https://speeders.me/" + }; + + public override string Description => "Your home now!"; + public override string Language => "en-US"; + public override Encoding Encoding => Encoding.UTF8; + public override DownloadProtocol Protocol => DownloadProtocol.Torrent; + public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + public override IndexerCapabilities Capabilities => SetCapabilities(); + + public SpeedCD(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) + { + } + + public override IIndexerRequestGenerator GetRequestGenerator() + { + return new SpeedCDRequestGenerator() { Settings = Settings, Capabilities = Capabilities, Encoding = Encoding }; + } + + public override IParseIndexerResponse GetParser() + { + return new SpeedCDParser(Settings, Capabilities.Categories); + } + + protected override async Task DoLogin() + { + var requestBuilder = new HttpRequestBuilder(string.Format("{0}/{1}", Settings.BaseUrl.TrimEnd('/'), "checkpoint/API")) + { + LogResponseContent = true, + AllowAutoRedirect = true + }; + + var loginPage = await ExecuteAuth(requestBuilder.Build()); + + var tokenRegex = new Regex(@"name=\\""a\\"" value=\\""([^""]+)\\"""); + var matches = tokenRegex.Match(loginPage.Content); + if (!matches.Success) + { + throw new IndexerAuthException("Error parsing the login form"); + } + + var token = matches.Groups[1].Value; + + Cookies = null; + + var requestBuilder2 = new HttpRequestBuilder(string.Format("{0}/{1}", Settings.BaseUrl.TrimEnd('/'), "checkpoint/")) + { + LogResponseContent = true, + AllowAutoRedirect = true + }; + + var authLoginRequest = requestBuilder2 + .AddFormParameter("pwd", Settings.Password) + .AddFormParameter("a", token) + .SetCookies(loginPage.GetCookies()) + .Build(); + + var response = await ExecuteAuth(authLoginRequest); + + if (CheckIfLoginNeeded(response)) + { + var parser = new HtmlParser(); + var dom = parser.ParseDocument(response.Content); + var errorMessage = dom.QuerySelector("h5")?.TextContent; + if (response.Content.Contains("Wrong Captcha!")) + { + errorMessage = "Captcha required due to a failed login attempt. Login via a browser to whitelist your IP and then reconfigure Prowlarr."; + } + + throw new IndexerAuthException(errorMessage); + } + + var cookies = response.GetCookies(); + UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); + + _logger.Debug("SpeedCD authentication succeeded."); + } + + protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) + { + if (!httpResponse.Content.Contains("/browse.php")) + { + return true; + } + + return false; + } + + private IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities + { + TvSearchParams = new List<TvSearchParam> + { + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId + }, + MovieSearchParams = new List<MovieSearchParam> + { + MovieSearchParam.Q, MovieSearchParam.ImdbId + }, + MusicSearchParams = new List<MusicSearchParam> + { + MusicSearchParam.Q + }, + BookSearchParams = new List<BookSearchParam> + { + BookSearchParam.Q + } + }; + + caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesOther, "Movies/XviD"); + caps.Categories.AddCategoryMapping(42, NewznabStandardCategory.Movies, "Movies/Packs"); + caps.Categories.AddCategoryMapping(32, NewznabStandardCategory.Movies, "Movies/Kids"); + caps.Categories.AddCategoryMapping(43, NewznabStandardCategory.MoviesHD, "Movies/HD"); + caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.Movies, "Movies/DiVERSiTY"); + caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.MoviesBluRay, "Movies/B-Ray"); + caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.Movies3D, "Movies/3D"); + caps.Categories.AddCategoryMapping(40, NewznabStandardCategory.MoviesDVD, "Movies/DVD-R"); + caps.Categories.AddCategoryMapping(56, NewznabStandardCategory.Movies, "Movies/Anime"); + caps.Categories.AddCategoryMapping(50, NewznabStandardCategory.TVSport, "TV/Sports"); + caps.Categories.AddCategoryMapping(52, NewznabStandardCategory.TVHD, "TV/B-Ray"); + caps.Categories.AddCategoryMapping(53, NewznabStandardCategory.TVSD, "TV/DVD-R"); + caps.Categories.AddCategoryMapping(41, NewznabStandardCategory.TV, "TV/Packs"); + caps.Categories.AddCategoryMapping(55, NewznabStandardCategory.TV, "TV/Kids"); + caps.Categories.AddCategoryMapping(57, NewznabStandardCategory.TV, "TV/DiVERSiTY"); + caps.Categories.AddCategoryMapping(49, NewznabStandardCategory.TVHD, "TV/HD"); + caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVSD, "TV/Episodes"); + caps.Categories.AddCategoryMapping(30, NewznabStandardCategory.TVAnime, "TV/Anime"); + caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.PCISO, "Games/PC ISO"); + caps.Categories.AddCategoryMapping(39, NewznabStandardCategory.ConsoleWii, "Games/Wii"); + caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.ConsolePS3, "Games/PS3"); + caps.Categories.AddCategoryMapping(35, NewznabStandardCategory.Console, "Games/Nintendo"); + caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.ConsoleXBox360, "Games/XboX360"); + caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.PCMobileOther, "Mobile"); + caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.PC0day, "Apps/0DAY"); + caps.Categories.AddCategoryMapping(51, NewznabStandardCategory.PCMac, "Mac"); + caps.Categories.AddCategoryMapping(54, NewznabStandardCategory.Books, "Educational"); + caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.Books, "Books-Mags"); + caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.Audio, "Music/Audio"); + caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Music/Flac"); + caps.Categories.AddCategoryMapping(44, NewznabStandardCategory.Audio, "Music/Pack"); + caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.AudioVideo, "Music/Video"); + + return caps; + } + } + + public class SpeedCDRequestGenerator : IIndexerRequestGenerator + { + public SpeedCDSettings Settings { get; set; } + public IndexerCapabilities Capabilities { get; set; } + public Encoding Encoding { get; set; } + + public SpeedCDRequestGenerator() + { + } + + private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null) + { + var searchUrl = string.Format("{0}/browse/", Settings.BaseUrl.TrimEnd('/')); + + var qc = new List<string>(); + + var catList = Capabilities.Categories.MapTorznabCapsToTrackers(categories); + foreach (var cat in catList) + { + qc.Add(cat); + } + + if (imdbId.IsNotNullOrWhiteSpace()) + { + qc.Add("deep"); + qc.Add("q"); + qc.Add(imdbId); + } + else + { + qc.Add("q"); + qc.Add(term.UrlEncode(Encoding)); + } + + searchUrl += string.Join("/", qc); + + var request = new IndexerRequest(searchUrl, HttpAccept.Html); + + yield return request; + } + + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public Func<IDictionary<string, string>> GetCookies { get; set; } + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + } + + public class SpeedCDParser : IParseIndexerResponse + { + private readonly SpeedCDSettings _settings; + private readonly IndexerCapabilitiesCategories _categories; + + public SpeedCDParser(SpeedCDSettings settings, IndexerCapabilitiesCategories categories) + { + _settings = settings; + _categories = categories; + } + + public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) + { + var torrentInfos = new List<ReleaseInfo>(); + + var parser = new HtmlParser(); + var dom = parser.ParseDocument(indexerResponse.Content); + var rows = dom.QuerySelectorAll("div.boxContent > table > tbody > tr"); + + foreach (var row in rows) + { + var cells = row.QuerySelectorAll("td"); + + var title = row.QuerySelector("td[class='lft'] > div > a").TextContent.Trim(); + var link = new Uri(_settings.BaseUrl + row.QuerySelector("img[title='Download']").ParentElement.GetAttribute("href").TrimStart('/')); + var details = new Uri(_settings.BaseUrl + row.QuerySelector("td[class='lft'] > div > a").GetAttribute("href").TrimStart('/')); + var size = ParseUtil.GetBytes(cells[5].TextContent); + var grabs = ParseUtil.CoerceInt(cells[6].TextContent); + var seeders = ParseUtil.CoerceInt(cells[7].TextContent); + var leechers = ParseUtil.CoerceInt(cells[8].TextContent); + + var pubDateStr = row.QuerySelector("span[class^='elapsedDate']").GetAttribute("title").Replace(" at", ""); + var publishDate = DateTime.ParseExact(pubDateStr, "dddd, MMMM d, yyyy h:mmtt", CultureInfo.InvariantCulture); + + var cat = row.QuerySelector("a").GetAttribute("href").Split('/').Last(); + var downloadVolumeFactor = row.QuerySelector("span:contains(\"[Freeleech]\")") != null ? 0 : 1; + + var release = new TorrentInfo + { + Title = title, + DownloadUrl = link.AbsoluteUri, + Guid = link.AbsoluteUri, + InfoUrl = details.AbsoluteUri, + PublishDate = publishDate, + Categories = _categories.MapTrackerCatToNewznab(cat), + Size = size, + Grabs = grabs, + Seeders = seeders, + Peers = seeders + leechers, + MinimumRatio = 1, + MinimumSeedTime = 259200, // 72 hours + DownloadVolumeFactor = downloadVolumeFactor, + UploadVolumeFactor = 1 + }; + + torrentInfos.Add(release); + } + + return torrentInfos.ToArray(); + } + + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + } + + public class SpeedCDSettingsValidator : AbstractValidator<SpeedCDSettings> + { + public SpeedCDSettingsValidator() + { + RuleFor(c => c.Username).NotEmpty(); + RuleFor(c => c.Password).NotEmpty(); + } + } + + public class SpeedCDSettings : IIndexerSettings + { + private static readonly SpeedCDSettingsValidator Validator = new SpeedCDSettingsValidator(); + + public SpeedCDSettings() + { + Username = ""; + Password = ""; + } + + [FieldDefinition(1, Label = "Base Url", HelpText = "Select which baseurl Prowlarr will use for requests to the site", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls")] + public string BaseUrl { get; set; } + + [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] + public string Username { get; set; } + + [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] + public string Password { get; set; } + + [FieldDefinition(4)] + public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} From eeebf3ecf0d9a73f55467123bc40624a30041e74 Mon Sep 17 00:00:00 2001 From: Dmitry Chepurovskiy <dm3ch@dm3ch.net> Date: Mon, 11 Oct 2021 00:58:59 +0300 Subject: [PATCH 0100/2320] Fixed: (Anilibria) Fix download torrent link (#529) --- src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs b/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs index 59948371d..eaa0487a0 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs @@ -172,6 +172,7 @@ namespace NzbDrone.Core.Indexers.Definitions { var torrentInfos = new List<ReleaseInfo>(); var queryResponseItems = JsonConvert.DeserializeObject<List<AnilibriaTitle>>(indexerResponse.Content); + var wwwUrl = Regex.Replace(_settings.BaseUrl, @"(https?:\/\/)(.*)", "$1www.$2/"); foreach (var tl in queryResponseItems) { @@ -190,8 +191,8 @@ namespace NzbDrone.Core.Indexers.Definitions // API provides timestamp in UTC+3 timezone, so we need to substract 3 hours PublishDate = DateTimeUtil.UnixTimestampToDateTime(tr.UploadedTimestamp).AddHours(-3), - Guid = _settings.BaseUrl + tr.Url, - DownloadUrl = _settings.BaseUrl + tr.Url, + Guid = wwwUrl + tr.Url, + DownloadUrl = wwwUrl + tr.Url, Size = tr.TotalSize, Resolution = tr.Quality.Resolution, Codec = tr.Quality.Encoder From d4bdb73b7c1bbb76ded291f958d9aa5f19b8a033 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sat, 9 Oct 2021 12:54:58 +0000 Subject: [PATCH 0101/2320] Translated using Weblate (French) Currently translated at 100.0% (441 of 441 strings) Co-authored-by: Nackophilz <clement.wigy@gmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/fr.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index 81694c566..0cc5b2baf 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -35,7 +35,7 @@ "UpdateCheckStartupTranslocationMessage": "Impossible d'installer la mise à jour car le dossier de démarrage '{0}' se trouve dans un dossier App Translocation.", "UpdateCheckStartupNotWritableMessage": "Impossible d'installer la mise à jour car le dossier de démarrage '{0}' n'est pas accessible en écriture par l'utilisateur '{1}'.", "UnselectAll": "Tout déselectionner", - "UISettingsSummary": "Options de date, de langue et de contraste de couleur", + "UISettingsSummary": "Date, langue, et perceptions des couleurs", "TagsSettingsSummary": "Voir toutes les tags et leur utilisation. Les tags inutilisées peuvent être supprimées", "Style": "Style", "Status": "Statut", @@ -162,7 +162,7 @@ "ApplyTags": "Appliquer les Tags", "AppDataDirectory": "Dossier AppData", "ApiKey": "Clé API", - "AnalyticsEnabledHelpText": "Envoyer des informations anonymes sur l'utilisation et les erreurs vers les serveurs de Prowlarr. Cela inclut des informations sur votre navigateur, quelle page Prowlarr WebUI vous utilisez, les rapports d'erreur ainsi que le système d'exploitation et sa version. Nous utiliserons ces informations pour prioriser les nouvelles fonctionnalités et les corrections de bugs.", + "AnalyticsEnabledHelpText": "Envoyer des informations anonymes sur l'utilisation et les erreurs vers les serveurs de Prowlarr. Cela inclut des informations sur votre navigateur, quelle page Prowlarr WebUI vous utilisez, les rapports d'erreurs, ainsi que le système d'exploitation et sa version. Nous utiliserons ces informations pour prioriser les nouvelles fonctionnalités et les corrections de bugs.", "IgnoredAddresses": "Adresses ignorées", "Hostname": "Nom d'hôte", "GeneralSettings": "Réglages Généraux", From d7e1043b7928e6e7a42f437e2a8f93814bddf18c Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 10 Oct 2021 17:12:18 -0500 Subject: [PATCH 0102/2320] Fixed: (Cardigann) Info field text pulling from DB instead of definition --- src/Prowlarr.Api.V1/Indexers/IndexerResource.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs b/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs index fc69ef06d..15808253e 100644 --- a/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs +++ b/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs @@ -63,7 +63,9 @@ namespace Prowlarr.Api.V1.Indexers foreach (var setting in settings.ExtraFieldData) { var field = extraFields.FirstOrDefault(x => x.Name == setting.Key); - if (field != null) + + //Use values from db for all but info type fields + if (field != null && field.Type != "info") { field.Value = setting.Value; } From 4347e1cf7aec78d7fc244befd8525cdde58e820c Mon Sep 17 00:00:00 2001 From: Nyuels <53974940+Nyuels@users.noreply.github.com> Date: Mon, 11 Oct 2021 00:21:39 +0200 Subject: [PATCH 0103/2320] New: (Internet Archive) Add Torrent File Only option. (#459) --- src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs b/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs index 0e1710969..4ae3ada07 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs @@ -243,7 +243,7 @@ namespace NzbDrone.Core.Indexers.Definitions UploadVolumeFactor = 1 }; - if (searchResult.InfoHash != null) + if (!_settings.TorrentFileOnly && searchResult.InfoHash != null) { release.MagnetUrl = MagnetLinkBuilder.BuildPublicMagnetLink(searchResult.InfoHash, title); } @@ -294,7 +294,10 @@ namespace NzbDrone.Core.Indexers.Definitions [FieldDefinition(4, Label = "Title Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Whether to search in title only.")] public bool TitleOnly { get; set; } - [FieldDefinition(5)] + [FieldDefinition(5, Label = "Torrent File Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Only use torrent files, not magnet links.")] + public bool TorrentFileOnly { get; set; } + + [FieldDefinition(6)] public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); public InternetArchiveSettings() @@ -302,6 +305,7 @@ namespace NzbDrone.Core.Indexers.Definitions SortBy = (int)InternetArchiveSort.PublicDate; SortOrder = (int)InternetArchiveSortOrder.Descending; TitleOnly = false; + TorrentFileOnly = false; } public NzbDroneValidationResult Validate() From e49d03ab7b2bc10948d4caf5194fa32bff8b9dcf Mon Sep 17 00:00:00 2001 From: Shane M <16828229+valesi@users.noreply.github.com> Date: Sun, 10 Oct 2021 17:14:03 -0700 Subject: [PATCH 0104/2320] Fixed: (RevolutionTT) Remove [REQ] prefix from torrent title (#545) [REQ] is an automatically generated prefix added to fulfilled requests, and very often breaks parsing for title matching Co-authored-by: Shane Moore <vales@users.noreply.github.com> --- src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs b/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs index f3bb2e387..d7de77b4a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs @@ -269,6 +269,12 @@ namespace NzbDrone.Core.Indexers.Definitions var details = _settings.BaseUrl + qDetails.GetAttribute("href"); var title = qDetails.QuerySelector("b").TextContent; + // Remove auto-generated [REQ] tag from fulfilled requests + if (title.StartsWith("[REQ] ")) + { + title = title.Substring(6); + } + var qLink = row.QuerySelector("td:nth-child(4) > a"); if (qLink == null) { From c21e323992bbf00b088d9719a02423b225d44d49 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Fri, 27 Aug 2021 19:18:34 -0500 Subject: [PATCH 0105/2320] New: Improved Logging of Search for ID based searches --- .../Definitions/MovieSearchCriteria.cs | 38 ++++++++++++++++ .../Definitions/SearchCriteriaBase.cs | 10 ++++- .../Definitions/TvSearchCriteria.cs | 45 +++++++++++++++++++ .../IndexerSearch/NzbSearchService.cs | 4 +- 4 files changed, 94 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/MovieSearchCriteria.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/MovieSearchCriteria.cs index 82b636775..73b688427 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/MovieSearchCriteria.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/MovieSearchCriteria.cs @@ -1,3 +1,4 @@ +using System.Text; using NzbDrone.Common.Extensions; using NzbDrone.Core.Parser; @@ -23,5 +24,42 @@ namespace NzbDrone.Core.IndexerSearch.Definitions } public string FullImdbId => ParseUtil.GetFullImdbId(ImdbId); + + public override string SearchQuery + { + get + { + var searchQueryTerm = $"Term: []"; + if (SearchTerm.IsNotNullOrWhiteSpace()) + { + searchQueryTerm = $"Term: [{SearchTerm}]"; + } + + if (!ImdbId.IsNotNullOrWhiteSpace() && !TmdbId.HasValue && !TraktId.HasValue) + { + return searchQueryTerm; + } + + var builder = new StringBuilder(searchQueryTerm); + builder = builder.Append(" | ID(s):"); + + if (ImdbId.IsNotNullOrWhiteSpace()) + { + builder = builder.Append($" IMDbId:[{ImdbId}]"); + } + + if (TmdbId.HasValue) + { + builder = builder.Append($" TMDbId:[{TmdbId}]"); + } + + if (TraktId.HasValue) + { + builder = builder.Append($" TraktId:[{TraktId}]"); + } + + return builder.ToString().Trim(); + } + } } } diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/SearchCriteriaBase.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/SearchCriteriaBase.cs index 49e4060db..3b4d86e42 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/SearchCriteriaBase.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/SearchCriteriaBase.cs @@ -21,9 +21,17 @@ namespace NzbDrone.Core.IndexerSearch.Definitions public string Source { get; set; } public string Host { get; set; } + public virtual string SearchQuery + { + get + { + return $"Term: [{SearchTerm}]"; + } + } + public override string ToString() { - return $"{{Term: {SearchTerm}, Offset: {Offset ?? 0}, Limit: {Limit ?? 0}, Categories: [{string.Join(", ", Categories)}]}}"; + return $"{SearchQuery}, Offset: {Offset ?? 0}, Limit: {Limit ?? 0}, Categories: [{string.Join(", ", Categories)}]"; } public virtual bool RssSearch diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/TvSearchCriteria.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/TvSearchCriteria.cs index 5a50335dc..a52361fb6 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/TvSearchCriteria.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/TvSearchCriteria.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using System.Text; using NzbDrone.Common.Extensions; using NzbDrone.Core.Parser; @@ -34,6 +35,50 @@ namespace NzbDrone.Core.IndexerSearch.Definitions } } + public override string SearchQuery + { + get + { + var searchQueryTerm = $"Term: []"; + var searchEpisodeTerm = $" for Season / Episode:[{EpisodeSearchString}]"; + if (SearchTerm.IsNotNullOrWhiteSpace()) + { + searchQueryTerm = $"Term: [{SearchTerm}]"; + } + + if (!ImdbId.IsNotNullOrWhiteSpace() && !TvdbId.HasValue && !RId.HasValue && !TraktId.HasValue) + { + return $"{searchQueryTerm}{searchEpisodeTerm}"; + } + + var builder = new StringBuilder(searchQueryTerm); + builder = builder.Append(" | ID(s):"); + + if (ImdbId.IsNotNullOrWhiteSpace()) + { + builder.Append($" IMDbId:[{ImdbId}]"); + } + + if (TvdbId.HasValue) + { + builder.Append($" TVDbId:[{TvdbId}]"); + } + + if (RId.HasValue) + { + builder.Append($" TVRageId:[{RId}]"); + } + + if (TraktId.HasValue) + { + builder.Append($" TraktId:[{TraktId}]"); + } + + builder = builder.Append(searchEpisodeTerm); + return builder.ToString().Trim(); + } + } + private string GetEpisodeSearchString() { if (Season == null || Season == 0) diff --git a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs b/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs index 2aeb7cf4c..b1d3574a4 100644 --- a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs @@ -147,7 +147,7 @@ namespace NzbDrone.Core.IndexerSearch .ToList(); } - _logger.ProgressInfo("Searching indexers: [{0}] for {1}", string.Join(", ", indexers.Select(i => i.Definition.Name).ToList()), criteriaBase.ToString()); + _logger.ProgressInfo("Searching indexer(s): [{0}] for {1}", string.Join(", ", indexers.Select(i => i.Definition.Name).ToList()), criteriaBase.ToString()); var tasks = indexers.Select(x => DispatchIndexer(searchAction, x, criteriaBase)); @@ -155,7 +155,7 @@ namespace NzbDrone.Core.IndexerSearch var reports = batch.SelectMany(x => x).ToList(); - _logger.Debug("Total of {0} reports were found for {1} from {2} indexers", reports.Count, criteriaBase, indexers.Count); + _logger.Debug("Total of {0} reports were found for {1} from {2} indexer(s)", reports.Count, criteriaBase, indexers.Count); return reports; } From 827741db174bd57b99c09576a91001c87339d0ea Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 15 Oct 2021 20:01:39 -0500 Subject: [PATCH 0106/2320] Fixed: (TVVault) add delay between requests and fix search & download --- src/NzbDrone.Core/Indexers/Definitions/TVVault.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs b/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs index fd796d284..25ef8fd83 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; +using System.Web; using AngleSharp.Html.Parser; using FluentValidation; using NLog; @@ -32,6 +33,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); + public override TimeSpan RateLimit => TimeSpan.FromSeconds(5); public TVVault(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) @@ -241,6 +243,13 @@ namespace NzbDrone.Core.Indexers.Definitions var parser = new HtmlParser(); var doc = parser.ParseDocument(indexerResponse.Content); + + // get params to build download link (user could be banned without those params) + var rssFeedUri = new Uri(_settings.BaseUrl + doc.QuerySelector("link[href^=\"/feeds.php?feed=\"]") + .GetAttribute("href")); + var rssFeedQuery = HttpUtility.ParseQueryString(rssFeedUri.Query); + var downloadLinkExtraParams = "&authkey=" + rssFeedQuery["authkey"] + "&torrent_pass=" + rssFeedQuery["passkey"]; + var rows = doc.QuerySelectorAll("table.torrent_table > tbody > tr.torrent"); foreach (var row in rows) @@ -252,7 +261,7 @@ namespace NzbDrone.Core.Indexers.Definitions title += " " + description; var details = _settings.BaseUrl + qDetailsLink.GetAttribute("href"); var torrentId = qDetailsLink.GetAttribute("href").Split('=').Last(); - var link = _settings.BaseUrl + "torrents.php?action=download&id=" + torrentId; + var link = _settings.BaseUrl + "torrents.php?action=download&id=" + torrentId + downloadLinkExtraParams; var files = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(3)").TextContent); var publishDate = DateTimeUtil.FromTimeAgo(row.QuerySelector("td:nth-child(4)").TextContent); From 327fd08059f5b128ef65702da9c8febc437ee3cb Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 15 Oct 2021 20:04:59 -0500 Subject: [PATCH 0107/2320] New: (RuTracker) Search by Categories --- src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs index 3717a04f7..d3fea79da 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs @@ -1443,6 +1443,11 @@ namespace NzbDrone.Core.Indexers.Definitions queryCollection.Add("nm", searchString); } + if (categories.Length > 0) + { + queryCollection.Add("f", string.Join(",", Capabilities.Categories.MapTorznabCapsToTrackers(categories))); + } + searchUrl = searchUrl + "?" + queryCollection.GetQueryString(); var request = new IndexerRequest(searchUrl, HttpAccept.Html); From 3e243eafdd3b88dfa32b5331284cabf1d1a5945d Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 16 Oct 2021 10:25:52 -0500 Subject: [PATCH 0108/2320] Bump FluentMigrator to 3.3.1 --- src/NuGet.config | 1 - .../Migration/Framework/NzbDroneSQLiteProcessor.cs | 7 ++++--- src/NzbDrone.Core/Prowlarr.Core.csproj | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NuGet.config b/src/NuGet.config index 5afe6530e..19fea7384 100644 --- a/src/NuGet.config +++ b/src/NuGet.config @@ -3,7 +3,6 @@ <packageSources> <clear /> <add key="nuget.org" value="https://api.nuget.org/v3/index.json" /> - <add key="FluentMigrator" value="https://pkgs.dev.azure.com/fluentmigrator/fluentmigrator/_packaging/fluentmigrator/nuget/v3/index.json" /> <add key="dotnet-bsd-crossbuild" value="https://pkgs.dev.azure.com/Servarr/Servarr/_packaging/dotnet-bsd-crossbuild/nuget/v3/index.json" /> <add key="Mono.Posix.NETStandard" value="https://pkgs.dev.azure.com/Servarr/Servarr/_packaging/Mono.Posix.NETStandard/nuget/v3/index.json" /> <add key="SQLite" value="https://pkgs.dev.azure.com/Servarr/Servarr/_packaging/SQLite/nuget/v3/index.json" /> diff --git a/src/NzbDrone.Core/Datastore/Migration/Framework/NzbDroneSQLiteProcessor.cs b/src/NzbDrone.Core/Datastore/Migration/Framework/NzbDroneSQLiteProcessor.cs index 8158edd65..e18565933 100644 --- a/src/NzbDrone.Core/Datastore/Migration/Framework/NzbDroneSQLiteProcessor.cs +++ b/src/NzbDrone.Core/Datastore/Migration/Framework/NzbDroneSQLiteProcessor.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; @@ -20,8 +20,9 @@ namespace NzbDrone.Core.Datastore.Migration.Framework ILogger<NzbDroneSQLiteProcessor> logger, IOptionsSnapshot<ProcessorOptions> options, IConnectionStringAccessor connectionStringAccessor, - IServiceProvider serviceProvider) - : base(factory, generator, logger, options, connectionStringAccessor, serviceProvider) + IServiceProvider serviceProvider, + SQLiteQuoter quoter) + : base(factory, generator, logger, options, connectionStringAccessor, serviceProvider, quoter) { } diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index 27565c348..e64305fbe 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -4,12 +4,12 @@ </PropertyGroup> <ItemGroup> <PackageReference Include="Dapper" Version="2.0.90" /> + <PackageReference Include="FluentMigrator.Runner" Version="3.3.1" /> <PackageReference Include="MailKit" Version="2.14.0" /> <PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" /> <PackageReference Include="System.Memory" Version="4.5.4" /> <PackageReference Include="System.ServiceModel.Syndication" Version="5.0.0" /> - <PackageReference Include="FluentMigrator.Runner" Version="4.0.0-alpha.268" /> - <PackageReference Include="FluentMigrator.Runner.SQLite" Version="4.0.0-alpha.268" /> + <PackageReference Include="FluentMigrator.Runner.SQLite" Version="3.3.1" /> <PackageReference Include="FluentValidation" Version="8.6.2" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="NLog" Version="4.7.9" /> From b65f4205fc6f86f968d464beb61b282e9f8dcf70 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 17 Oct 2021 11:58:48 -0500 Subject: [PATCH 0109/2320] Fixed: Don't delete down indexers if they still exist in DB Fixes #494 --- src/NzbDrone.Core/Applications/ApplicationService.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Applications/ApplicationService.cs b/src/NzbDrone.Core/Applications/ApplicationService.cs index 554fc1daa..80b7c840d 100644 --- a/src/NzbDrone.Core/Applications/ApplicationService.cs +++ b/src/NzbDrone.Core/Applications/ApplicationService.cs @@ -159,9 +159,11 @@ namespace NzbDrone.Core.Applications if (removeRemote) { + var allIndexers = _indexerFactory.All(); + foreach (var mapping in indexerMappings) { - if (!indexers.Any(x => x.Id == mapping.IndexerId)) + if (!allIndexers.Any(x => x.Id == mapping.IndexerId)) { _logger.Info("Indexer with the ID {0} was found within {1} but is no longer defined within Prowlarr, this is being removed.", mapping.IndexerId, app.Name); ExecuteAction(a => a.RemoveIndexer(mapping.IndexerId), app); From 0cfb7da41154aff7c8646bc3e036ff70ccfd33e9 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 17 Oct 2021 12:27:23 -0500 Subject: [PATCH 0110/2320] New: (Indexer) BitHDTV --- .../Extensions/IEnumerableExtensions.cs | 11 + .../Indexers/Definitions/BitHDTV.cs | 302 ++++++++++++++++++ 2 files changed, 313 insertions(+) create mode 100644 src/NzbDrone.Core/Indexers/Definitions/BitHDTV.cs diff --git a/src/NzbDrone.Common/Extensions/IEnumerableExtensions.cs b/src/NzbDrone.Common/Extensions/IEnumerableExtensions.cs index deb75de1e..ef687a922 100644 --- a/src/NzbDrone.Common/Extensions/IEnumerableExtensions.cs +++ b/src/NzbDrone.Common/Extensions/IEnumerableExtensions.cs @@ -160,5 +160,16 @@ namespace NzbDrone.Common.Extensions { return new HashSet<T>(source, comparer); } + + public static T FirstIfSingleOrDefault<T>(this IEnumerable<T> source, T replace = default) + { + if (source is ICollection<T> collection) + { + return collection.Count == 1 ? collection.First() : replace; + } + + var test = source.Take(2).ToList(); + return test.Count == 1 ? test[0] : replace; + } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/BitHDTV.cs b/src/NzbDrone.Core/Indexers/Definitions/BitHDTV.cs new file mode 100644 index 000000000..c457e9021 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/BitHDTV.cs @@ -0,0 +1,302 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Web; +using AngleSharp.Html.Parser; +using FluentValidation; +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Indexers.Definitions +{ + public class BitHDTV : TorrentIndexerBase<BitHDTVSettings> + { + public override string Name => "BitHDTV"; + public override string[] IndexerUrls => new string[] { "https://www.bit-hdtv.com/" }; + public override string Description => "BIT-HDTV - Home of High Definition"; + public override string Language => "en-US"; + public override Encoding Encoding => Encoding.GetEncoding("iso-8859-1"); + public override DownloadProtocol Protocol => DownloadProtocol.Torrent; + public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + public override IndexerCapabilities Capabilities => SetCapabilities(); + + public BitHDTV(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) + { + } + + public override IIndexerRequestGenerator GetRequestGenerator() + { + return new BitHDTVRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; + } + + public override IParseIndexerResponse GetParser() + { + return new BitHDTVParser(Settings, Capabilities.Categories); + } + + protected override IDictionary<string, string> GetCookies() + { + return CookieUtil.CookieHeaderToDictionary(Settings.Cookie); + } + + protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) + { + return false; + } + + private IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities + { + TvSearchParams = new List<TvSearchParam> + { + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId + }, + MovieSearchParams = new List<MovieSearchParam> + { + MovieSearchParam.Q, MovieSearchParam.ImdbId + } + }; + + caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.TVAnime, "Anime"); + caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.MoviesBluRay, "Movies/Blu-ray"); + caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.TVDocumentary, "Documentaries"); + caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.AudioLossless, "HQ Audio"); + caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.Movies, "Movies"); + caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.AudioVideo, "Music Videos"); + caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.Other, "Other"); + caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.TVSport, "Sports"); + caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.TV, "TV"); + caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.TV, "TV/Seasonpack"); + caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.XXX, "XXX"); + + return caps; + } + } + + public class BitHDTVRequestGenerator : IIndexerRequestGenerator + { + public BitHDTVSettings Settings { get; set; } + public IndexerCapabilities Capabilities { get; set; } + + public BitHDTVRequestGenerator() + { + } + + private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null) + { + var searchUrl = string.Format("{0}/torrents.php", Settings.BaseUrl.TrimEnd('/')); + + var qc = new NameValueCollection + { + { "cat", Capabilities.Categories.MapTorznabCapsToTrackers(categories, true).FirstIfSingleOrDefault("0") } + }; + + var search = new UriBuilder(searchUrl); + + if (imdbId.IsNotNullOrWhiteSpace()) + { + qc.Add("search", imdbId); + qc.Add("options", "4"); //Search URL field for IMDB link + search.Query = qc.GetQueryString(); + yield return new IndexerRequest(search.ToString(), HttpAccept.Html); + + qc["Options"] = "1"; //Search Title and Description + search.Query = qc.GetQueryString(); + yield return new IndexerRequest(search.ToString(), HttpAccept.Html); + } + else + { + //Site handles empty string on search param. No need to check for IsNullOrEmpty() + qc.Add("search", term); + qc.Add("options", "0"); //Search Title Only + search.Query = qc.GetQueryString(); + yield return new IndexerRequest(search.ToString(), HttpAccept.Html); + } + } + + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public Func<IDictionary<string, string>> GetCookies { get; set; } + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + } + + public class BitHDTVParser : IParseIndexerResponse + { + private readonly BitHDTVSettings _settings; + private readonly IndexerCapabilitiesCategories _categories; + + public BitHDTVParser(BitHDTVSettings settings, IndexerCapabilitiesCategories categories) + { + _settings = settings; + _categories = categories; + } + + public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) + { + var torrentInfos = new List<ReleaseInfo>(); + + var parser = new HtmlParser(); + var dom = parser.ParseDocument(indexerResponse.Content); + foreach (var child in dom.QuerySelectorAll("#needseed")) + { + child.Remove(); + } + + var table = dom.QuerySelector("table[align=center] + br + table > tbody"); + + // No results, so skip this search + if (table == null) + { + return torrentInfos; + } + + foreach (var row in table.Children.Skip(1)) + { + var release = new TorrentInfo(); + var qLink = row.Children[2].QuerySelector("a"); + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; // 48 hours + release.Title = qLink.GetAttribute("title"); + var detailsLink = new Uri(qLink.GetAttribute("href")); + + //Skip irrelevant and duplicate entries + if (torrentInfos.Any(r => r.Guid == detailsLink.AbsoluteUri)) + { + continue; + } + + release.Files = ParseUtil.CoerceInt(row.Children[3].TextContent); + release.Grabs = ParseUtil.CoerceInt(row.Children[7].TextContent); + release.Guid = detailsLink.AbsoluteUri; + release.InfoUrl = release.Guid; + release.DownloadUrl = new Uri(_settings.BaseUrl + row.QuerySelector("a[href^=\"download.php\"]").GetAttribute("href")).AbsoluteUri; + var catUrl = new Uri(_settings.BaseUrl + row.Children[1].FirstElementChild.GetAttribute("href")); + var catQuery = HttpUtility.ParseQueryString(catUrl.Query); + var catNum = catQuery["cat"]; + release.Categories = _categories.MapTrackerCatToNewznab(catNum); + + var dateString = row.Children[5].TextContent.Trim(); + var pubDate = DateTime.ParseExact(dateString, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture); + release.PublishDate = DateTime.SpecifyKind(pubDate, DateTimeKind.Local); + var sizeStr = row.Children[6].TextContent; + release.Size = ParseUtil.GetBytes(sizeStr); + release.Seeders = ParseUtil.CoerceInt(row.Children[8].TextContent.Trim()); + release.Peers = ParseUtil.CoerceInt(row.Children[9].TextContent.Trim()) + release.Seeders; + switch (row.GetAttribute("bgcolor")) + { + case "#DDDDDD": + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 2; + break; + case "#FFFF99": + release.DownloadVolumeFactor = 0; + release.UploadVolumeFactor = 1; + break; + case "#CCFF99": + release.DownloadVolumeFactor = 0; + release.UploadVolumeFactor = 2; + break; + default: + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; + break; + } + + torrentInfos.Add(release); + } + + return torrentInfos.ToArray(); + } + + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + } + + public class BitHDTVSettingsValidator : AbstractValidator<BitHDTVSettings> + { + public BitHDTVSettingsValidator() + { + RuleFor(c => c.Cookie).NotEmpty(); + } + } + + public class BitHDTVSettings : IIndexerSettings + { + private static readonly BitHDTVSettingsValidator Validator = new BitHDTVSettingsValidator(); + + public BitHDTVSettings() + { + Cookie = ""; + } + + [FieldDefinition(1, Label = "Base Url", HelpText = "Select which baseurl Prowlarr will use for requests to the site", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls")] + public string BaseUrl { get; set; } + + [FieldDefinition(2, Label = "Cookie", HelpText = "Login cookie from website")] + public string Cookie { get; set; } + + [FieldDefinition(3)] + public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} From f5f0dd6fae5bc9f308506d56be42ac9a4be908e7 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 17 Oct 2021 11:41:31 -0500 Subject: [PATCH 0111/2320] New: Support server notifications --- .../HealthCheck/HealthCheckServiceFixture.cs | 4 ++ .../HealthCheck/HealthCheckService.cs | 5 ++ .../ServerSideNotificationService.cs | 65 +++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 src/NzbDrone.Core/HealthCheck/ServerSideNotificationService.cs diff --git a/src/NzbDrone.Core.Test/HealthCheck/HealthCheckServiceFixture.cs b/src/NzbDrone.Core.Test/HealthCheck/HealthCheckServiceFixture.cs index fcf9d58c8..74802a39e 100644 --- a/src/NzbDrone.Core.Test/HealthCheck/HealthCheckServiceFixture.cs +++ b/src/NzbDrone.Core.Test/HealthCheck/HealthCheckServiceFixture.cs @@ -19,6 +19,10 @@ namespace NzbDrone.Core.Test.HealthCheck Mocker.SetConstant<IEnumerable<IProvideHealthCheck>>(new[] { _healthCheck }); Mocker.SetConstant<ICacheManager>(Mocker.Resolve<CacheManager>()); + + Mocker.GetMock<IServerSideNotificationService>() + .Setup(v => v.GetServerChecks()) + .Returns(new List<Core.HealthCheck.HealthCheck>()); } [Test] diff --git a/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs b/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs index 24b112207..679044083 100644 --- a/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs +++ b/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs @@ -25,6 +25,7 @@ namespace NzbDrone.Core.HealthCheck private readonly IProvideHealthCheck[] _startupHealthChecks; private readonly IProvideHealthCheck[] _scheduledHealthChecks; private readonly Dictionary<Type, IEventDrivenHealthCheck[]> _eventDrivenHealthChecks; + private readonly IServerSideNotificationService _serverSideNotificationService; private readonly IEventAggregator _eventAggregator; private readonly ICacheManager _cacheManager; private readonly Logger _logger; @@ -32,11 +33,13 @@ namespace NzbDrone.Core.HealthCheck private readonly ICached<HealthCheck> _healthCheckResults; public HealthCheckService(IEnumerable<IProvideHealthCheck> healthChecks, + IServerSideNotificationService serverSideNotificationService, IEventAggregator eventAggregator, ICacheManager cacheManager, Logger logger) { _healthChecks = healthChecks.ToArray(); + _serverSideNotificationService = serverSideNotificationService; _eventAggregator = eventAggregator; _cacheManager = cacheManager; _logger = logger; @@ -72,6 +75,8 @@ namespace NzbDrone.Core.HealthCheck var results = healthChecks.Select(c => c.Check()) .ToList(); + results.AddRange(_serverSideNotificationService.GetServerChecks()); + foreach (var result in results) { if (result.Type == HealthCheckResult.Ok) diff --git a/src/NzbDrone.Core/HealthCheck/ServerSideNotificationService.cs b/src/NzbDrone.Core/HealthCheck/ServerSideNotificationService.cs new file mode 100644 index 000000000..e5fc51dd7 --- /dev/null +++ b/src/NzbDrone.Core/HealthCheck/ServerSideNotificationService.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using NLog; +using NzbDrone.Common.Cloud; +using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Http; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Configuration; + +namespace NzbDrone.Core.HealthCheck +{ + public interface IServerSideNotificationService + { + public List<HealthCheck> GetServerChecks(); + } + + public class ServerSideNotificationService : IServerSideNotificationService + { + private readonly IHttpClient _client; + private readonly IConfigFileProvider _configFileProvider; + private readonly IHttpRequestBuilderFactory _cloudRequestBuilder; + private readonly Logger _logger; + + public ServerSideNotificationService(IHttpClient client, IConfigFileProvider configFileProvider, IProwlarrCloudRequestBuilder cloudRequestBuilder, Logger logger) + { + _client = client; + _configFileProvider = configFileProvider; + _cloudRequestBuilder = cloudRequestBuilder.Services; + _logger = logger; + } + + public List<HealthCheck> GetServerChecks() + { + var request = _cloudRequestBuilder.Create() + .Resource("/notification") + .AddQueryParam("version", BuildInfo.Version) + .AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant()) + .AddQueryParam("arch", RuntimeInformation.OSArchitecture) + .AddQueryParam("runtime", PlatformInfo.Platform.ToString().ToLowerInvariant()) + .AddQueryParam("branch", _configFileProvider.Branch) + .Build(); + try + { + _logger.Trace("Getting server side health notifications"); + var response = _client.Execute(request); + var result = Json.Deserialize<List<ServerNotificationResponse>>(response.Content); + return result.Select(x => new HealthCheck(GetType(), x.Type, x.Message, x.WikiUrl)).ToList(); + } + catch (Exception ex) + { + _logger.Error(ex, "Failed to retrieve server notifications"); + return new List<HealthCheck>(); + } + } + } + + public class ServerNotificationResponse + { + public HealthCheckResult Type { get; set; } + public string Message { get; set; } + public string WikiUrl { get; set; } + } +} From 3bbadb516db6c79e77181fd5fa28dfa83232c254 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Thu, 7 Oct 2021 15:42:49 -0500 Subject: [PATCH 0112/2320] New: (DesiTorrents) Convert from Gazelle to UNIT3D Fixes #532 --- .../Migration/013_desi_gazelle_to_unit3d.cs | 14 ++++++++++++++ .../Indexers/Definitions/DesiTorrents.cs | 18 ++++++++++-------- .../Definitions/UNIT3D/Unit3dParser.cs | 2 +- 3 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 src/NzbDrone.Core/Datastore/Migration/013_desi_gazelle_to_unit3d.cs diff --git a/src/NzbDrone.Core/Datastore/Migration/013_desi_gazelle_to_unit3d.cs b/src/NzbDrone.Core/Datastore/Migration/013_desi_gazelle_to_unit3d.cs new file mode 100644 index 000000000..c066fa8a8 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/013_desi_gazelle_to_unit3d.cs @@ -0,0 +1,14 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(13)] + public class desi_gazelle_to_unit3d : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Update.Table("Indexers").Set(new { ConfigContract = "Unit3dSettings", Enable = 0 }).Where(new { Implementation = "DesiTorrents" }); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs index f1c9e260d..572f9222f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs @@ -1,16 +1,18 @@ using System.Collections.Generic; +using System.Linq; using NLog; using NzbDrone.Core.Configuration; -using NzbDrone.Core.Indexers.Gazelle; +using NzbDrone.Core.Indexers.Definitions.UNIT3D; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers.Definitions { - public class DesiTorrents : Gazelle.Gazelle + public class DesiTorrents : Unit3dBase { public override string Name => "DesiTorrents"; - public override string[] IndexerUrls => new string[] { "https://desitorrents.tv/" }; + public override string Language => "en-US"; + public override string[] IndexerUrls => new[] { "https://desitorrents.tv/" }; public override string Description => "Desitorrents is a Private Torrent Tracker for BOLLYWOOD / TOLLYWOOD / GENERAL"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; @@ -21,7 +23,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IParseIndexerResponse GetParser() { - return new DesiTorrentsParser(Settings, Capabilities); + return new DesiTorrentsParser(Settings, Capabilities.Categories); } protected override IndexerCapabilities SetCapabilities() @@ -47,7 +49,7 @@ namespace NzbDrone.Core.Indexers.Definitions }; caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movies"); - caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "Tv shows"); + caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "TV"); caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Music"); caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.BooksEBook, "ebooks"); caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.TVSport, "Sports"); @@ -57,10 +59,10 @@ namespace NzbDrone.Core.Indexers.Definitions } } - public class DesiTorrentsParser : Gazelle.GazelleParser + public class DesiTorrentsParser : Unit3dParser { - public DesiTorrentsParser(GazelleSettings settings, IndexerCapabilities capabilities) - : base(settings, capabilities) + public DesiTorrentsParser(Unit3dSettings settings, IndexerCapabilitiesCategories categories) + : base(settings, categories) { } diff --git a/src/NzbDrone.Core/Indexers/Definitions/UNIT3D/Unit3dParser.cs b/src/NzbDrone.Core/Indexers/Definitions/UNIT3D/Unit3dParser.cs index 7dcb82aaa..77c97edb4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/UNIT3D/Unit3dParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/UNIT3D/Unit3dParser.cs @@ -26,7 +26,7 @@ namespace NzbDrone.Core.Indexers.Definitions.UNIT3D public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) + public virtual IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List<TorrentInfo>(); From 8ac721a30b92e9eeb702747a2969b77ed97145bb Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Fri, 22 Oct 2021 07:43:16 +0000 Subject: [PATCH 0113/2320] Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 96.8% (427 of 441 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 96.3% (425 of 441 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 96.3% (425 of 441 strings) Translated using Weblate (French) Currently translated at 100.0% (441 of 441 strings) Co-authored-by: Nackophilz <clement.wigy@gmail.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: muihiuwev <muihiuwev@outlook.com> Co-authored-by: yulelong <yulelong@foxmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/fr.json | 8 ++--- .../Localization/Core/zh_CN.json | 32 ++++++++++++++++--- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index 0cc5b2baf..4507c049c 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -153,13 +153,13 @@ "BindAddressHelpText": "Adresse IP4 valide ou '*' pour toutes les interfaces", "BindAddress": "Adresse d'attache", "Backups": "Sauvegardes", - "BackupRetentionHelpText": "Les sauvegardes automatiques plus anciennes que la période de conservation seront automatiquement effacées", + "BackupRetentionHelpText": "Les sauvegardes automatiques plus anciennes que la période de rétention seront automatiquement effacées", "BackupIntervalHelpText": "Intervalle entre les sauvegardes automatiques", "Automatic": "Automatique", - "AuthenticationMethodHelpText": "Un nom d'utilisateur et un mot de passe sont nécessaires pour accéder à Prowlarr", + "AuthenticationMethodHelpText": "Un nom d'utilisateur et un mot de passe sont requis pour accéder à Prowlarr", "Authentication": "Authentification", "AreYouSureYouWantToResetYourAPIKey": "Êtes vous sûr de vouloir réinitialiser votre clé API ?", - "ApplyTags": "Appliquer les Tags", + "ApplyTags": "Appliquer les tags", "AppDataDirectory": "Dossier AppData", "ApiKey": "Clé API", "AnalyticsEnabledHelpText": "Envoyer des informations anonymes sur l'utilisation et les erreurs vers les serveurs de Prowlarr. Cela inclut des informations sur votre navigateur, quelle page Prowlarr WebUI vous utilisez, les rapports d'erreurs, ainsi que le système d'exploitation et sa version. Nous utiliserons ces informations pour prioriser les nouvelles fonctionnalités et les corrections de bugs.", @@ -198,7 +198,7 @@ "ApplyTagsHelpTexts4": "Remplacer : Remplace les tags par les tags renseignés (ne pas renseigner de tags pour effacer tous les tags)", "ApplyTagsHelpTexts3": "Retirer : Retire les tags renseignés", "ApplyTagsHelpTexts2": "Ajouter : Ajouter les tags à la liste de tags existants", - "ApplyTagsHelpTexts1": "Comment appliquer des tags au film sélectionné", + "ApplyTagsHelpTexts1": "Comment appliquer les tags aux indexeurs sélectionner", "DeleteDownloadClientMessageText": "Êtes-vous sûr de vouloir supprimer le client de téléchargement '{0}' ?", "DeleteBackupMessageText": "Êtes-vous sûr de vouloir supprimer la sauvegarde '{0}' ?", "ErrorLoadingContents": "Erreur lors du chargement du contenu", diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index 85679accf..4bcf72f78 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -165,13 +165,13 @@ "CustomFilters": "自定义过滤", "Custom": "自定义", "CouldNotConnectSignalR": "无法连接至SignalR,不会升级UI", - "ConnectSettingsSummary": "通知、与媒体服务器/播放器的链接、自定义脚本", + "ConnectSettingsSummary": "通知和自定义脚本", "ConnectSettings": "连接设置", "Connections": "连接", "ConnectionLostMessage": "Prowlarr 已与服务端断开链接,请尝试刷新来恢复使用。", "ConnectionLostAutomaticMessage": "Prowlarr 将会自动重连,您也可以点击下方的重新加载。", "ConnectionLost": "连接丢失", - "Connect": "通知连接", + "Connect": "通知", "Component": "组件", "Columns": "列", "CloseCurrentModal": "关闭当前模组", @@ -215,7 +215,7 @@ "ApplyTagsHelpTexts3": "删除:删除输入的标签", "ApplyTagsHelpTexts2": "添加:将标签添加到现有标签列表", "Applications": "程序", - "AppDataLocationHealthCheckMessage": "由于防止程序数据在升级中被删除升级不可用", + "AppDataLocationHealthCheckMessage": "更新时可能会删除AppData", "AddRemoveOnly": "仅添加和删除", "AddDownloadClientToProwlarr": "添加下载客户端允许 Prowlarr 在进行手动搜索时从 UI直接发送结果", "AddDownloadClient": "添加下载客户端", @@ -233,7 +233,7 @@ "ProxyCheckBadRequestMessage": "测试代理失败,状态码: {0}", "ProxyBypassFilterHelpText": "使用“ , ”作为分隔符,和“ *. ”作为二级域名的通配符", "Proxy": "代理", - "ProwlarrSupportsAnyIndexer": "Prowlarr支持任何符合Newznab标准的搜刮器,以及以下列出的其他索引器。", + "ProwlarrSupportsAnyIndexer": "Prowlarr支持多种搜刮器,包括任何使用Newznab/Torznab标准的搜刮器(“通用Newznab”对应Usenet,“Generic Torznab”对应Torrents)。从以下搜索并选择你的搜刮器。", "ProwlarrSupportsAnyDownloadClient": "Prowlarr 支持以下列出的下载客户端。", "Protocol": "协议", "Privacy": "隐私", @@ -403,5 +403,27 @@ "Reset": "重置", "ResetAPIKey": "重置API Key", "Restart": "重启", - "RestartNow": "马上重启" + "RestartNow": "马上重启", + "UnableToLoadIndexerProxies": "无法加载搜刮器代理", + "UnableToLoadDevelopmentSettings": "无法加载开发设置", + "UnableToLoadAppProfiles": "无法加载应用配置", + "UISettingsSummary": "日期,语言及色盲选项", + "TestAllApps": "测试全部应用", + "SyncLevel": "同步级别", + "SettingsIndexerLogging": "增强型搜刮器日志", + "SettingsFilterSentryEvents": "筛选分析事件", + "SettingsConsoleLogLevel": "控制台日志级别", + "RestartProwlarr": "重启Prowlarr", + "Redirect": "重定向", + "Query": "查询字段", + "Notifications": "通知", + "Notification": "通知", + "NoSearchResultsFound": "无搜索结果,请在下面尝试新的搜索。", + "IndexerVipCheckExpiringClientMessage": "搜刮器VIP特权即将过期:{0}", + "IndexerVipCheckExpiredClientMessage": "搜刮器VIP特权已过期:{0}", + "IndexerProxy": "搜刮器代理", + "IndexerProxies": "搜刮器代理", + "DeleteIndexerProxy": "删除搜刮器代理", + "AddIndexerProxy": "添加搜刮器代理", + "AppSettingsSummary": "配置Prowlarr与PVR程序交互方式的应用和设置" } From 9ec8990a217768f8d219c146b4665c34867fca66 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 26 Oct 2021 18:05:33 -0400 Subject: [PATCH 0114/2320] Bump to 0.1.2 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 7380da790..8cb606cd0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,7 +7,7 @@ variables: outputFolder: './_output' artifactsFolder: './_artifacts' testsFolder: './_tests' - majorVersion: '0.1.1' + majorVersion: '0.1.2' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From 44aad1b94375250cbe0fac3c46b6f58674125f58 Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Thu, 28 Oct 2021 10:49:38 +0100 Subject: [PATCH 0115/2320] Fixed: Prowl notification priority --- src/NzbDrone.Core/Notifications/Prowl/Prowl.cs | 2 +- src/NzbDrone.Core/Notifications/Prowl/ProwlProxy.cs | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs b/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs index 1822319c7..c30209f19 100644 --- a/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs +++ b/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs @@ -18,7 +18,7 @@ namespace NzbDrone.Core.Notifications.Prowl public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck) { - _prowlProxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings.ApiKey, (ProwlPriority)Settings.Priority); + _prowlProxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings); } public override ValidationResult Test() diff --git a/src/NzbDrone.Core/Notifications/Prowl/ProwlProxy.cs b/src/NzbDrone.Core/Notifications/Prowl/ProwlProxy.cs index f44e982da..e8df63d2b 100644 --- a/src/NzbDrone.Core/Notifications/Prowl/ProwlProxy.cs +++ b/src/NzbDrone.Core/Notifications/Prowl/ProwlProxy.cs @@ -9,7 +9,7 @@ namespace NzbDrone.Core.Notifications.Prowl { public interface IProwlProxy { - void SendNotification(string title, string message, string apiKey, ProwlPriority priority = ProwlPriority.Normal, string url = null); + void SendNotification(string title, string message, ProwlSettings settings); ValidationFailure Test(ProwlSettings settings); } @@ -25,19 +25,18 @@ namespace NzbDrone.Core.Notifications.Prowl _logger = logger; } - public void SendNotification(string title, string message, string apiKey, ProwlPriority priority = ProwlPriority.Normal, string url = null) + public void SendNotification(string title, string message, ProwlSettings settings) { try { var requestBuilder = new HttpRequestBuilder(PUSH_URL); var request = requestBuilder.Post() - .AddFormParameter("apikey", apiKey) + .AddFormParameter("apikey", settings.ApiKey) .AddFormParameter("application", BuildInfo.AppName) .AddFormParameter("event", title) .AddFormParameter("description", message) - .AddFormParameter("priority", priority) - .AddFormParameter("url", url) + .AddFormParameter("priority", settings.Priority) .Build(); _httpClient.Post(request); @@ -46,7 +45,7 @@ namespace NzbDrone.Core.Notifications.Prowl { if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) { - _logger.Error(ex, "Apikey is invalid: {0}", apiKey); + _logger.Error(ex, "Apikey is invalid: {0}", settings.ApiKey); throw new ProwlException("Apikey is invalid", ex); } @@ -65,7 +64,7 @@ namespace NzbDrone.Core.Notifications.Prowl const string title = "Test Notification"; const string body = "This is a test message from Prowlarr"; - SendNotification(title, body, settings.ApiKey); + SendNotification(title, body, settings); } catch (Exception ex) { From 8b0760296a0ac075840e4934f8c85adf72676436 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 30 Oct 2021 11:40:02 -0500 Subject: [PATCH 0116/2320] Fixed: Set ContentType for Flaresolverr requests to ensure proper content encoding --- src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index 4c9b2b511..3e2344c1a 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -110,8 +110,9 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr var apiUrl = string.Format("{0}/v1", Settings.Host.TrimEnd('/')); var newRequest = new HttpRequest(apiUrl, HttpAccept.Json); - newRequest.SetContent(req.ToJson()); + newRequest.Headers.ContentType = "application/json"; newRequest.Method = HttpMethod.POST; + newRequest.SetContent(req.ToJson()); _logger.Debug("Applying FlareSolverr Proxy {0} to request {1}", Name, request.Url); From 998e21417193b13fdf2becde037b7f1556ab3270 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 26 Oct 2021 13:03:43 -0500 Subject: [PATCH 0117/2320] New: (DesiTorrents) Add Alt URL .rocks Closes #562 --- src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs index 572f9222f..8f0fe75a7 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs @@ -12,7 +12,7 @@ namespace NzbDrone.Core.Indexers.Definitions { public override string Name => "DesiTorrents"; public override string Language => "en-US"; - public override string[] IndexerUrls => new[] { "https://desitorrents.tv/" }; + public override string[] IndexerUrls => new[] { "https://desitorrents.tv/", "https://desitorrents.rocks/" }; public override string Description => "Desitorrents is a Private Torrent Tracker for BOLLYWOOD / TOLLYWOOD / GENERAL"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; From b309582d917a7a7925053a130be147a3f0406a37 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 30 Oct 2021 12:01:14 -0500 Subject: [PATCH 0118/2320] Fixed: (DanishBytes) Double slash in search urls --- src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs index b4a66c93e..b17c12565 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs @@ -108,7 +108,7 @@ namespace NzbDrone.Core.Indexers.Definitions qc.Add("tvdb", tvdbId.ToString()); } - var searchUrl = string.Format("{0}/api/torrents/v2/filter?{1}", Settings.BaseUrl, qc.GetQueryString()); + var searchUrl = string.Format("{0}/api/torrents/v2/filter?{1}", Settings.BaseUrl.TrimEnd('/'), qc.GetQueryString()); foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories)) { From e688dac0407c248a82f220b1c0c694278274513b Mon Sep 17 00:00:00 2001 From: dobbleg1000 <j8kap@hotmail.com> Date: Wed, 3 Nov 2021 19:15:39 -0500 Subject: [PATCH 0119/2320] Fixed: (Bakabt) Typo in Search link --- src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs index a24077037..eb964df8c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs @@ -171,7 +171,7 @@ namespace NzbDrone.Core.Indexers.Definitions private IEnumerable<IndexerRequest> GetPagedRequests(string term) { var searchString = term; - var searchUrl = Settings.BaseUrl + " browse.php?only=0&incomplete=1&lossless=1&hd=1&multiaudio=1&bonus=1&reorder=1&q="; + var searchUrl = Settings.BaseUrl + "browse.php?only=0&incomplete=1&lossless=1&hd=1&multiaudio=1&bonus=1&reorder=1&q="; if (Settings.AdultContent) { searchUrl = Settings.BaseUrl + "browse.php?only=0&hentai=1&incomplete=1&lossless=1&hd=1&multiaudio=1&bonus=1&reorder=1&q="; From e859bedef13dc0efdf3a90d4534b50b1fe1f2c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Dupont?= <aleistor@gmail.com> Date: Mon, 1 Nov 2021 16:02:08 +0000 Subject: [PATCH 0120/2320] Translated using Weblate (French) Currently translated at 100.0% (441 of 441 strings) Translation: Servarr/Prowlarr Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/ --- src/NzbDrone.Core/Localization/Core/fr.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index 4507c049c..ef2c3049b 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -153,15 +153,15 @@ "BindAddressHelpText": "Adresse IP4 valide ou '*' pour toutes les interfaces", "BindAddress": "Adresse d'attache", "Backups": "Sauvegardes", - "BackupRetentionHelpText": "Les sauvegardes automatiques plus anciennes que la période de rétention seront automatiquement effacées", + "BackupRetentionHelpText": "Les sauvegardes automatiques plus anciennes que la période de conservation seront automatiquement effacées", "BackupIntervalHelpText": "Intervalle entre les sauvegardes automatiques", "Automatic": "Automatique", - "AuthenticationMethodHelpText": "Un nom d'utilisateur et un mot de passe sont requis pour accéder à Prowlarr", + "AuthenticationMethodHelpText": "Exiger un identifiant et un mot de passe pour accéder à Prowlarr", "Authentication": "Authentification", - "AreYouSureYouWantToResetYourAPIKey": "Êtes vous sûr de vouloir réinitialiser votre clé API ?", - "ApplyTags": "Appliquer les tags", + "AreYouSureYouWantToResetYourAPIKey": "Êtes vous sûr de vouloir réinitialiser votre Clé d'API ?", + "ApplyTags": "Appliquer les Étiquettes", "AppDataDirectory": "Dossier AppData", - "ApiKey": "Clé API", + "ApiKey": "Clé d'API", "AnalyticsEnabledHelpText": "Envoyer des informations anonymes sur l'utilisation et les erreurs vers les serveurs de Prowlarr. Cela inclut des informations sur votre navigateur, quelle page Prowlarr WebUI vous utilisez, les rapports d'erreurs, ainsi que le système d'exploitation et sa version. Nous utiliserons ces informations pour prioriser les nouvelles fonctionnalités et les corrections de bugs.", "IgnoredAddresses": "Adresses ignorées", "Hostname": "Nom d'hôte", @@ -195,10 +195,10 @@ "BranchUpdateMechanism": "Branche utilisée par le mécanisme de mise à jour extérieur", "BranchUpdate": "Branche à utiliser pour mettre Prowlarr à jour", "BeforeUpdate": "Avant mise à jour", - "ApplyTagsHelpTexts4": "Remplacer : Remplace les tags par les tags renseignés (ne pas renseigner de tags pour effacer tous les tags)", - "ApplyTagsHelpTexts3": "Retirer : Retire les tags renseignés", - "ApplyTagsHelpTexts2": "Ajouter : Ajouter les tags à la liste de tags existants", - "ApplyTagsHelpTexts1": "Comment appliquer les tags aux indexeurs sélectionner", + "ApplyTagsHelpTexts4": "Remplacer : Remplace les étiquettes par les étiquettes renseignées (ne pas renseigner d'étiquette pour effacer toutes les étiquettes)", + "ApplyTagsHelpTexts3": "Retirer : Retire les étiquettes renseignées", + "ApplyTagsHelpTexts2": "Ajouter : Ajouter les étiquettes à la liste des étiquettes existantes", + "ApplyTagsHelpTexts1": "Comment appliquer des étiquettes aux indexeurs sélectionnés", "DeleteDownloadClientMessageText": "Êtes-vous sûr de vouloir supprimer le client de téléchargement '{0}' ?", "DeleteBackupMessageText": "Êtes-vous sûr de vouloir supprimer la sauvegarde '{0}' ?", "ErrorLoadingContents": "Erreur lors du chargement du contenu", @@ -374,7 +374,7 @@ "ClearHistoryMessageText": "Vous êtes sûr de vouloir effacer tout l'historique de Prowlarr ?", "ClearHistory": "Effacer l'historique", "ApplicationStatusCheckSingleClientMessage": "Applications indisponibles en raison de dysfonctionnements : {0}", - "ApplicationStatusCheckAllClientMessage": "Toutes les applications sont indisponibles en raison de dysfonctionnements.", + "ApplicationStatusCheckAllClientMessage": "Toutes les applications sont indisponibles en raison de dysfonctionnements", "AllIndexersHiddenDueToFilter": "Tous les indexeurs sont cachés en raison du filtre appliqué.", "AddToDownloadClient": "Ajouter un release au client", "AddedToDownloadClient": "Release ajoutée au client", From 6a6697c2c27734f86cfbd58c00372b566948ff35 Mon Sep 17 00:00:00 2001 From: zpengcom <z.peng.com@gmail.com> Date: Tue, 2 Nov 2021 06:24:10 +0000 Subject: [PATCH 0121/2320] Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 100.0% (441 of 441 strings) Translation: Servarr/Prowlarr Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ --- .../Localization/Core/zh_CN.json | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index 4bcf72f78..5574a5dc9 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -4,16 +4,16 @@ "Apply": "应用", "ApplicationStatusCheckSingleClientMessage": "由于故障应用程序不可用", "ApplicationStatusCheckAllClientMessage": "由于故障所用应用程序都不可用", - "AppDataDirectory": "AppData 路径", + "AppDataDirectory": "AppData目录", "ApiKey": "API 密钥", - "AnalyticsEnabledHelpText": "发送匿名操作和错误信息到 Prowlarr 服务器。包括你浏览器中与 Prowlarr WebUI、错误报告、操作系统和运行环境的信息。我们将这些信息用于确定功能优先级和 Bug 修复。", - "Analytics": "分析图表", - "AllIndexersHiddenDueToFilter": "隐藏所有索引器直至应用筛选器", + "AnalyticsEnabledHelpText": "将匿名使用情况和错误信息发送到Prowlarr的服务器。这包括有关您的浏览器的信息、您使用的Prowlarr WebUI页面、错误报告以及操作系统和运行时版本。我们将使用此信息来确定功能和错误修复的优先级。", + "Analytics": "分析", + "AllIndexersHiddenDueToFilter": "由于应用了筛选器,所有索引器都被隐藏。", "All": "全部", "Age": "年龄", "AddToDownloadClient": "添加发布到下载客户端", "AddNewIndexer": "添加新的索引器", - "AddingTag": "添加便签", + "AddingTag": "添加标签", "AddIndexer": "添加索引器", "AddedToDownloadClient": "发布已添加档案到客户端", "Added": "已添加", @@ -192,7 +192,7 @@ "BranchUpdateMechanism": "外部更新机制使用的分支", "BranchUpdate": "更新Prowlarr的分支", "Branch": "分支", - "BindAddressHelpText": "有效的IPV4地址或以'*'代表所有地址", + "BindAddressHelpText": "有效的 IP4 地址或以'*'代表所有地址", "BindAddress": "绑定地址", "BeforeUpdate": "更新前", "Backups": "备份", @@ -212,12 +212,12 @@ "AppProfileInUse": "正在使用的应用程序配置文件", "AppProfileDeleteConfirm": "您确认您想删除吗?", "ApplyTagsHelpTexts4": "替换:用输入的标签替换标签(不输入标签将清除所有标签)", - "ApplyTagsHelpTexts3": "删除:删除输入的标签", + "ApplyTagsHelpTexts3": "删除:移除输入的标签", "ApplyTagsHelpTexts2": "添加:将标签添加到现有标签列表", "Applications": "程序", - "AppDataLocationHealthCheckMessage": "更新时可能会删除AppData", + "AppDataLocationHealthCheckMessage": "更新时可能会删除应用数据", "AddRemoveOnly": "仅添加和删除", - "AddDownloadClientToProwlarr": "添加下载客户端允许 Prowlarr 在进行手动搜索时从 UI直接发送结果", + "AddDownloadClientToProwlarr": "添加下载客户端允许 Prowlarr 在进行手动搜索时从 UI直接发送结果.", "AddDownloadClient": "添加下载客户端", "Add": "添加", "SettingsEnableColorImpairedModeHelpText": "改变样式,以允许有颜色障碍的用户更好地区分颜色编码信息", @@ -311,7 +311,7 @@ "Wiki": "Wiki", "Yesterday": "昨天", "Torrent": "Torrents", - "Torrents": "Torrents", + "Torrents": "种子", "Type": "类型", "UnableToLoadNotifications": "无法加载通知连接", "UnableToLoadQualityDefinitions": "无法加载影片质量定义", @@ -425,5 +425,19 @@ "IndexerProxies": "搜刮器代理", "DeleteIndexerProxy": "删除搜刮器代理", "AddIndexerProxy": "添加搜刮器代理", - "AppSettingsSummary": "配置Prowlarr与PVR程序交互方式的应用和设置" + "AppSettingsSummary": "配置Prowlarr与PVR程序交互方式的应用和设置", + "SyncLevelFull": "完全同步:将保持此应用程序完全同步。当在Prowlarr中所做的更改将同步到与此关联的应用程序。任何关联应用上的更改都将在下次同步时被Prowlarr覆盖。", + "SyncLevelAddRemove": "仅添加和删除:当它从 Prowlarr 添加或删除时,它将更新与此关联的应用程序。", + "SyncAppIndexers": "同步应用索引", + "Stats": "统计数据", + "SettingsSqlLoggingHelpText": "记录来自Prowlarr的所有SQL查询", + "SettingsLogSql": "事务日志", + "SettingsLogRotateHelpText": "保存在日志文件夹中的最大日志文件数", + "SettingsLogRotate": "日志轮替", + "SettingsIndexerLoggingHelpText": "记录额外的搜刮器数据,包括响应", + "SettingsFilterSentryEventsHelpText": "过滤已知的用户错误事件,不让其作为分析报告发送", + "ReleaseBranchCheckPreviousVersionMessage": "分支 {0} 适用于 Prowlarr 的先前版本,将分支设置为“Nightly”以获得进一步更新", + "RedirectHelpText": "重定向搜刮器的传入下载请求并直接传递抓取,而不是通过Prowlarr代理请求搜刮器", + "IndexerTagsHelpText": "使用标签来指定默认客户端、搜刮器代理或仅群组搜刮器。", + "IndexerSettingsSummary": "配置全局索引器设置,包括代理。" } From d585ab56770445a86cfe81f5994031ad6b05ec49 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 7 Nov 2021 14:05:11 -0600 Subject: [PATCH 0122/2320] Fixed: (RuTracker.Org) Fails to add Closes #560 --- src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs index d3fea79da..c45cd1b8d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs @@ -1443,7 +1443,7 @@ namespace NzbDrone.Core.Indexers.Definitions queryCollection.Add("nm", searchString); } - if (categories.Length > 0) + if (categories != null && categories.Length > 0) { queryCollection.Add("f", string.Join(",", Capabilities.Categories.MapTorznabCapsToTrackers(categories))); } From e07ad14e8394726ea465726fbb798116131ca300 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sun, 7 Nov 2021 19:35:30 +0000 Subject: [PATCH 0123/2320] Translated using Weblate (Swedish) Currently translated at 100.0% (441 of 441 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (441 of 441 strings) Translated using Weblate (Swedish) Currently translated at 100.0% (441 of 441 strings) Co-authored-by: Havok Dan <havokdan@yahoo.com.br> Co-authored-by: LukkiHyde <lucas.bergstrom90@gmail.com> Co-authored-by: Weblate <noreply@weblate.org> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sv/ Translation: Servarr/Prowlarr --- .../Localization/Core/pt_BR.json | 2 +- src/NzbDrone.Core/Localization/Core/sv.json | 109 +++++++++++++++--- 2 files changed, 93 insertions(+), 18 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index a81c9b7e1..dc4fee9d2 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -362,7 +362,7 @@ "Version": "Versão", "View": "Exibir", "Warn": "Avisar", - "YesCancel": "Sim, cancelar", + "YesCancel": "Sim, Cancelar", "Yesterday": "Ontem", "EnableRssHelpText": "Habilitar feed RSS para o indexador", "EnableRss": "Habilitar RSS", diff --git a/src/NzbDrone.Core/Localization/Core/sv.json b/src/NzbDrone.Core/Localization/Core/sv.json index 3e0dca5f5..2af3172b7 100644 --- a/src/NzbDrone.Core/Localization/Core/sv.json +++ b/src/NzbDrone.Core/Localization/Core/sv.json @@ -6,7 +6,7 @@ "IndexerStatusCheckAllClientMessage": "Samtliga indexerare otillgängliga på grund av fel", "Indexers": "Indexerare", "Host": "Värd", - "History": "Historia", + "History": "Historik", "HideAdvanced": "Dölj avancerat", "Health": "Hälsa", "General": "Generell", @@ -25,9 +25,9 @@ "Date": "Datum", "CustomFilters": "Anpassade Filter", "Connections": "Anslutningar", - "Connect": "Anslut", + "Connect": "Aviseringar", "Clear": "Rensa", - "BackupNow": "Säkerhets- kopiera", + "BackupNow": "Säkerhetskopiera Nu", "Backup": "Säkerhetskopiering", "AppDataLocationHealthCheckMessage": "Uppdatering ej möjlig för att AppData inte skall raderas", "Analytics": "Analys", @@ -43,7 +43,7 @@ "UpdateCheckStartupTranslocationMessage": "Ej möjligt att installera uppdatering då uppstartsmappen '{0}' är i en \"App translocation\"-mapp.", "UpdateCheckStartupNotWritableMessage": "Ej möjligt att installera uppdatering då uppstartsmappen '{0}' inte är skrivbar för användaren '{1}'.", "UnselectAll": "Avmarkera samtliga", - "UISettingsSummary": "Alternativ för kalender, datum och färgblindhet", + "UISettingsSummary": "Datum, språk, och färgblindhetsinställningar", "UI": "Användargränssnitt", "Tasks": "Uppgifter", "TagsSettingsSummary": "Se samtliga taggar och hur de används. Oanvända taggar kan tas bort", @@ -77,7 +77,7 @@ "LastWriteTime": "Senast skriven tid", "Indexer": "Indexerare", "Grabbed": "Hämtad", - "GeneralSettingsSummary": "Port, SSL, användarnamn/lösenord, proxy, analys och uppdateringar", + "GeneralSettingsSummary": "Port, SSL, användarnamn/lösenord, proxy, analyser, och uppdateringar", "Filename": "Filnamn", "Failed": "Misslyckad", "EventType": "Händelsetyp", @@ -85,7 +85,7 @@ "DownloadClient": "Nedladdningsklient", "ReleaseStatus": "Releasestatus", "Details": "Detaljer", - "ConnectSettingsSummary": "Aviseringar, anslutningar till media-servrar/klienter och anpassade script", + "ConnectSettingsSummary": "Aviseringar och anpassade script", "Added": "Tillagd", "Actions": "Åtgärder", "Options": "Alternativ", @@ -159,7 +159,7 @@ "Yesterday": "Igår", "ShowSearchHelpText": "Visa sökknappen på svävaren", "ConnectSettings": "Anslutnings inställningar", - "Downloading": "Laddar ned", + "Downloading": "Laddar Ned", "EditIndexer": "Redigera indexerare", "EnableAutomaticSearchHelpText": "Används när automatiska sökningar utförs via användargränssnittet eller av Radarr", "EnableColorImpairedMode": "Aktivera färgskadat läge", @@ -168,19 +168,19 @@ "Port": "Port", "Add": "Lägg till", "ApplyTags": "Tillämpa taggar", - "ApplyTagsHelpTexts1": "Så här applicerar du taggar på de valda filmerna", + "ApplyTagsHelpTexts1": "Så här applicerar du taggar på de valda indexarna", "RestartRequiredHelpTextWarning": "Kräver omstart för att träda i kraft", "Restore": "Återställ", "Result": "Resultat", "Retention": "Bibehållande", "ApplyTagsHelpTexts2": "Lägg till: Lägg till taggarna i den befintliga listan med taggar", - "CertificateValidation": "Validering av certifikat", + "CertificateValidation": "Validering av Certifikat", "CloneIndexer": "Klona indexerare", "RSSIsNotSupportedWithThisIndexer": "RSS stöds inte av denna indexerare", "SaveSettings": "Spara inställningar", "ScriptPath": "Skriptsökväg", "CouldNotConnectSignalR": "Kunde inte ansluta till SignalR, UI uppdateras inte", - "DeleteTag": "Radera tagg", + "DeleteTag": "Radera Tagg", "Hostname": "Värdnamn", "MinutesSixty": "60 minuter: {0}", "Mode": "Läge", @@ -221,7 +221,7 @@ "Authentication": "Autentisera", "LogLevelTraceHelpTextWarning": "Spårloggning bör endast aktiveras tillfälligt", "DeleteIndexerProxyMessageText": "Är du säker på att du vill radera taggen '{0}'?", - "DeleteNotification": "Radera avisering", + "DeleteNotification": "Radera Avisering", "DownloadClientUnavailable": "Nedladdningsklient är otillgänglig", "Fixed": "Fast", "FocusSearchBox": "Fokus sökruta", @@ -241,7 +241,7 @@ "UnsavedChanges": "Osparade ändringar", "UpdateAutomaticallyHelpText": "Automatiskt ladda ned och installera uppdateringar. Du kommer fortfarande att kunna installera från System: Uppdateringar", "UrlBaseHelpText": "För omvänd proxy-stöd är standard tom", - "AnalyticsEnabledHelpText": "Skicka anonym användning och felinformation till Radarrs servrar. Detta inkluderar information i din webbläsare, vilka Radarr WebUI-sidor du använder, felrapportering samt operativsystem och runtime-version. Vi kommer att använda denna information för att prioritera funktioner och buggfixar.", + "AnalyticsEnabledHelpText": "Skicka anonym användning och felinformation till Prowlarr's servrar. Detta inkluderar information i din webbläsare, vilka Prowlarr's WebUI-sidor du använder, felrapportering samt operativsystem och runtime-version. Vi kommer att använda denna information för att prioritera funktioner och buggfixar.", "AppDataDirectory": "AppData-katalog", "ApplicationStatusCheckSingleClientMessage": "Listor otillgängliga på grund av fel: {0}", "ApplyTagsHelpTexts3": "Ta bort: Ta bort de angivna taggarna", @@ -263,8 +263,8 @@ "DeleteTagMessageText": "Är du säker på att du vill radera taggen '{0}'?", "Disabled": "Inaktiverad", "EnableAutoHelpText": "Om det är aktiverat läggs filmer automatiskt till Radarr från den här listan", - "EnableAutomaticAdd": "Aktivera automatisk tillägg", - "EnableAutomaticSearch": "Aktivera automatisk sökning", + "EnableAutomaticAdd": "Aktivera Automstisk Tillägg", + "EnableAutomaticSearch": "Aktivera Automatisk Sökning", "EnableAutomaticSearchHelpTextWarning": "Används när interaktiv sökning används", "EnableColorImpairedModeHelpText": "Ändrad stil för att göra det möjligt för användare med färgstörning att bättre skilja färgkodad information", "EnableHelpText": "Aktivera metadatafilskapande för denna metadatatyp", @@ -349,9 +349,9 @@ "NoLeaveIt": "Nej, lämna det", "NoLimitForAnyRuntime": "Ingen gräns för någon körtid", "UnableToLoadQualityDefinitions": "Det går inte att ladda kvalitetsdefinitioner", - "AuthenticationMethodHelpText": "Kräva användarnamn och lösenord för att komma åt Radarr", + "AuthenticationMethodHelpText": "Kräva användarnamn och lösenord för att komma åt Prowlarr", "AutomaticSearch": "Automatisk sökning", - "BackupFolderHelpText": "Relativa sökvägar finns under Radarrs AppData-katalog", + "BackupFolderHelpText": "Relativa sökvägar finns under Prowlarr's AppData-katalog", "BackupIntervalHelpText": "Intervall mellan automatiska säkerhetskopior", "BackupRetentionHelpText": "Automatiska säkerhetskopior som är äldre än lagringsperioden rensas automatiskt", "Backups": "Säkerhetskopior", @@ -364,5 +364,80 @@ "MonoVersion": "Mono version", "NoLogFiles": "Inga loggfiler", "UnableToLoadDownloadClients": "Det gick inte att ladda nedladdningsklienter", - "UpdateMechanismHelpText": "Använd Radarrs inbyggda uppdaterare eller ett skript" + "UpdateMechanismHelpText": "Använd Radarrs inbyggda uppdaterare eller ett skript", + "AddDownloadClientToProwlarr": "Lägg till en nedladdningsklient tillåter Prowlarr att sända nyutgåvor direkt från UI:t samtidigt som en manuell sökning genomförs.", + "UnableToLoadIndexerProxies": "Kunde inte ladda Indexer Proxies", + "UnableToLoadDevelopmentSettings": "Kunde inte ladda Utvecklingsinställningar", + "UnableToLoadAppProfiles": "Kunde inte ladda app-profiler", + "TestAllApps": "Testa Alla Appar", + "SyncLevelFull": "Full Synkronisering: Kommer att hålla den här appen fullständigt synkad. Ändringar gjorda i Prowlarr är sedan synkade till den här appen. Några ändringar gjorda fjärrvis kommer bli överskrivna av Prowlarr under nästa synkning.", + "SyncLevelAddRemove": "Lägg till och Ta bort Endast: När det är tillagt eller borttaget från Prowlarr, det kommer uppdatera den här fjärrstyrda appen.", + "SyncLevel": "Synka Nivå", + "SyncAppIndexers": "Synka App Indexers", + "Stats": "Statistik", + "SettingsSqlLoggingHelpText": "Logga alla SQL frågor från Prowlarr", + "SettingsLogSql": "Logga Sql", + "SettingsLogRotateHelpText": "Största nummer av loggfiler att ha sparat i logg-mappen", + "SettingsLogRotate": "Logga Rotation", + "SettingsIndexerLoggingHelpText": "Logga extra Indexer data inkluderat svar", + "SettingsIndexerLogging": "Förändra Indexer Loggning", + "SettingsFilterSentryEventsHelpText": "Filtrera kända användarfel-aktiviteter från att skickas som Analys", + "SettingsFilterSentryEvents": "Filtrera Analytiska Events", + "SettingsConsoleLogLevel": "Konsol Logg Nivå", + "SearchIndexers": "Sök Indexers", + "RestartProwlarr": "Starta om Prowlarr", + "RedirectHelpText": "Omdirigera inkomna nedladdningsförfrågningar för indexer och hoppa över \"hämta direkt\" istället för proxying förfrågan via Prowlarr", + "Redirect": "Omdirigera", + "Query": "Fråga", + "ProwlarrSupportsAnyIndexer": "Prowlarr stödjer många indexers i komplettering till vilken indexer som helst, som använder Newznab/Torznab standard användning 'Generic Newznab' (för usenet) eller 'Generic Torznab' (för torrents). Sök & Markera dina indexers nedan.", + "ProwlarrSupportsAnyDownloadClient": "Prowlarr stödjer alla nedladdningsklienter listade nedan.", + "Privacy": "Privat", + "NotificationTriggersHelpText": "Markera vilka event som ska utlösa den här notifikationen", + "Notification": "Notifikation", + "NoSearchResultsFound": "Inget sökresultat hittat, försök utföra en ny sökning nedan.", + "NetCore": ".NET", + "MaintenanceRelease": "Underhållsutgåva", + "IndexerVipCheckExpiringClientMessage": "Indexer VIP förmåner utgår snart: {0}", + "IndexerVipCheckExpiredClientMessage": "Indexer VIP förmåner har utgått: {0}", + "IndexerTagsHelpText": "Använd taggar för att specificera standardklient, specificera Indexer Proxies, eller bara för att organisera dina indexers.", + "IndexersSelectedInterp": "{0} Indexer(s) Markerade", + "IndexerSettingsSummary": "Konfigurera flera globala Indexerinställningar, includerat Proxies.", + "IndexerRss": "Indexer Rss", + "IndexerQuery": "Indexer Fråga", + "IndexerProxy": "Indexer Proxy", + "IndexerProxies": "Indexer Proxies", + "IndexerObsoleteCheckMessage": "Indexer är obsolete eller har blivit uppdaterad: {0}. Var god ta bort och (eller) lägg till igen i Prowlarr", + "IndexerHealthCheckNoIndexers": "Ingen indexer aktiverad, Prowlarr kommer inte returnera sökresultat", + "IndexerAuth": "Indexer Författa", + "Id": "Id", + "FullSync": "Full Synkronisering", + "FilterPlaceHolder": "Sök indexers", + "Encoding": "Enkodering", + "EnableRssHelpText": "Aktiverea Rss feed för Indexer", + "EnableIndexer": "Aktivera Indexer", + "EditAppProfile": "Hantera App Profil", + "DevelopmentSettings": "Utvecklingsinställningar", + "Description": "Beskrivning", + "DeleteIndexerProxy": "Radera Indexer Proxy", + "DeleteAppProfile": "Radera App Profil", + "DeleteApplication": "Radera Applikation", + "Notifications": "Anslut", + "ClearHistoryMessageText": "Är du säker på att du vill rensa all Prowlarr historik?", + "ClearHistory": "Rensa Historik", + "Category": "Kategori", + "AppProfile": "App Profil", + "AddToDownloadClient": "Lägg till nyutgåva i nedladdningsklienten", + "AddRemoveOnly": "Lägg till och Ta bort Endast", + "AddNewIndexer": "Lägg till Ny Indexer", + "AddIndexerProxy": "Lägg till Indexer Proxy", + "AddedToDownloadClient": "Nyutgåva lades till i klienten", + "AddAppProfile": "Lägg till App Sync Profil", + "Auth": "Förafa", + "AppSettingsSummary": "Applikationer och inställningar för att konfigurera hur Prowlarr interagerar med PVR program", + "Apps": "Appar", + "AppProfileSelectHelpText": "App profiler är använda för att kontrollera RSS, Automatisk Sökning och interaktiv Sökningsinställningar på applikationen sync", + "AppProfiles": "App Profiler", + "AppProfileInUse": "App Profil i användning", + "AppProfileDeleteConfirm": "Är du säker på att du vill radera {0}?", + "Applications": "Applikationer" } From 8d856b2edb8bf46a2b516d5f7644ae3fa1151323 Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Mon, 27 Sep 2021 23:30:44 +0100 Subject: [PATCH 0124/2320] New: Added UDP syslog support --- .../Configuration/ConfigFileProvider.cs | 5 ++++ .../Instrumentation/ReconfigureLogging.cs | 25 +++++++++++++++++++ src/NzbDrone.Core/Prowlarr.Core.csproj | 1 + 3 files changed, 31 insertions(+) diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index 28ae85048..28e5639cd 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -45,6 +45,8 @@ namespace NzbDrone.Core.Configuration bool UpdateAutomatically { get; } UpdateMechanism UpdateMechanism { get; } string UpdateScriptPath { get; } + string SyslogServer { get; } + int SyslogPort { get; } } public class ConfigFileProvider : IConfigFileProvider @@ -213,6 +215,9 @@ namespace NzbDrone.Core.Configuration public string UpdateScriptPath => GetValue("UpdateScriptPath", "", false); + public string SyslogServer => GetValue("SyslogServer", "", persist: false); + public int SyslogPort => GetValueInt("SyslogPort", 514, persist: false); + public int GetValueInt(string key, int defaultValue, bool persist = true) { return Convert.ToInt32(GetValue(key, defaultValue, persist)); diff --git a/src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs b/src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs index 36025d64e..1f3cfcba1 100644 --- a/src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs +++ b/src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs @@ -2,6 +2,8 @@ using System.Linq; using NLog; using NLog.Config; +using NLog.Targets.Syslog; +using NLog.Targets.Syslog.Settings; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; using NzbDrone.Common.Instrumentation; @@ -40,6 +42,11 @@ namespace NzbDrone.Core.Instrumentation minimumConsoleLogLevel = LogLevel.Info; } + if (_configFileProvider.SyslogServer.IsNotNullOrWhiteSpace()) + { + SetSyslogParameters(_configFileProvider.SyslogServer, _configFileProvider.SyslogPort, minimumLogLevel); + } + var rules = LogManager.Configuration.LoggingRules; //Console @@ -101,6 +108,24 @@ namespace NzbDrone.Core.Instrumentation } } + private void SetSyslogParameters(string syslogServer, int syslogPort, LogLevel minimumLogLevel) + { + var syslogTarget = new SyslogTarget(); + + syslogTarget.Name = "syslogTarget"; + syslogTarget.MessageSend.Protocol = ProtocolType.Udp; + syslogTarget.MessageSend.Udp.Port = syslogPort; + syslogTarget.MessageSend.Udp.Server = syslogServer; + syslogTarget.MessageSend.Udp.ReconnectInterval = 500; + syslogTarget.MessageCreation.Rfc = RfcNumber.Rfc5424; + syslogTarget.MessageCreation.Rfc5424.AppName = "Prowlarr"; + + var loggingRule = new LoggingRule("*", minimumLogLevel, syslogTarget); + + LogManager.Configuration.AddTarget("syslogTarget", syslogTarget); + LogManager.Configuration.LoggingRules.Add(loggingRule); + } + private List<LogLevel> GetLogLevels() { return new List<LogLevel> diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index e64305fbe..e7ffefc34 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -7,6 +7,7 @@ <PackageReference Include="FluentMigrator.Runner" Version="3.3.1" /> <PackageReference Include="MailKit" Version="2.14.0" /> <PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" /> + <PackageReference Include="NLog.Targets.Syslog" Version="6.0.2" /> <PackageReference Include="System.Memory" Version="4.5.4" /> <PackageReference Include="System.ServiceModel.Syndication" Version="5.0.0" /> <PackageReference Include="FluentMigrator.Runner.SQLite" Version="3.3.1" /> From 2054dcc127d86704b12c9abe0a377f6333444008 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 17 Oct 2021 12:22:58 -0500 Subject: [PATCH 0125/2320] Fixed: (TorrentLeech) Drop support for IMDb ID TV Searches Fixed: (TorrentLeech) Returning unrelated results for Season/Episode Searches Fixes #474 --- src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs index c2c74d7f1..aa47689d4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs @@ -89,7 +89,9 @@ namespace NzbDrone.Core.Indexers.Definitions { TvSearchParams = new List<TvSearchParam> { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId + // Torrentleech does technically support ImdbId Search but only with no other params + // ImdbId + S/E search returns unrelated results + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep }, MovieSearchParams = new List<MovieSearchParam> { @@ -228,7 +230,7 @@ namespace NzbDrone.Core.Indexers.Definitions { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId)); + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories)); return pageableRequests; } From f38d6c5b426e957f1eec030d47b933f88f5f7f0b Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 23 Oct 2021 15:47:29 -0500 Subject: [PATCH 0126/2320] Fixed: (Avistaz) Cleanse PID & Hash from response Fixes #557 --- .../InstrumentationTests/CleanseLogMessageFixture.cs | 4 ++++ src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs index e046ab2c0..e44bd5b13 100644 --- a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs +++ b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs @@ -24,6 +24,10 @@ namespace NzbDrone.Common.Test.InstrumentationTests [TestCase(@"https://beyond-hd.me/api/torrents/2b51db35e1912ffc138825a12b9933d2")] [TestCase(@"Req: [POST] https://www3.yggtorrent.nz/user/login: id=mySecret&pass=mySecret&ci_csrf_token=2b51db35e1912ffc138825a12b9933d2")] + // avistaz response + [TestCase(@"""download"":""https:\/\/avistaz.to\/rss\/download\/2b51db35e1910123321025a12b9933d2\/tb51db35e1910123321025a12b9933d2.torrent"",")] + [TestCase(@",""info_hash"":""2b51db35e1910123321025a12b9933d2"",")] + // NzbGet [TestCase(@"{ ""Name"" : ""ControlUsername"", ""Value"" : ""mySecret"" }, { ""Name"" : ""ControlPassword"", ""Value"" : ""mySecret"" }, ")] [TestCase(@"{ ""Name"" : ""Server1.Username"", ""Value"" : ""mySecret"" }, { ""Name"" : ""Server1.Password"", ""Value"" : ""mySecret"" }, ")] diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index a7906e705..17d64aedb 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -45,7 +45,11 @@ namespace NzbDrone.Common.Instrumentation new Regex(@"(?<=\?|&)(authkey|torrent_pass)=(?<secret>[^&=]+?)(?=""|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), // Plex - new Regex(@"(?<=\?|&)(X-Plex-Client-Identifier|X-Plex-Token)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase) + new Regex(@"(?<=\?|&)(X-Plex-Client-Identifier|X-Plex-Token)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + + //avistaz + new Regex(@"avistaz\.[a-z]{2,3}\\\/rss\\\/download\\\/(?<secret>[^&=]+?)\\\/(?<secret>[^&=]+?)\.torrent", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@",""info_hash"":""(?<secret>[^&=]+?)"",", RegexOptions.Compiled | RegexOptions.IgnoreCase), }; private static readonly Regex CleanseRemoteIPRegex = new Regex(@"(?:Auth-\w+(?<!Failure|Unauthorized) ip|from) (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", RegexOptions.Compiled); From 8e43ea4bbc61a485ae6c55054f038c57f7987d27 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 8 Nov 2021 23:17:01 -0600 Subject: [PATCH 0127/2320] New: (Indexer) Norbits --- .../Indexers/Definitions/NorBits.cs | 435 ++++++++++++++++++ 1 file changed, 435 insertions(+) create mode 100644 src/NzbDrone.Core/Indexers/Definitions/NorBits.cs diff --git a/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs b/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs new file mode 100644 index 000000000..3c314f396 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs @@ -0,0 +1,435 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using AngleSharp.Dom; +using AngleSharp.Html.Parser; +using FluentValidation; +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Indexers.Definitions +{ + public class NorBits : TorrentIndexerBase<NorBitsSettings> + { + public override string Name => "NorBits"; + public override string[] IndexerUrls => new string[] { "https://norbits.net/" }; + public override string Description => "NorBits is a Norwegian Private site for MOVIES / TV / GENERAL"; + public override string Language => "nb-NO"; + public override Encoding Encoding => Encoding.GetEncoding("iso-8859-1"); + public override DownloadProtocol Protocol => DownloadProtocol.Torrent; + public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + public override IndexerCapabilities Capabilities => SetCapabilities(); + + public NorBits(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) + { + } + + public override IIndexerRequestGenerator GetRequestGenerator() + { + return new NorBitsRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; + } + + public override IParseIndexerResponse GetParser() + { + return new NorBitsParser(Settings, Capabilities.Categories); + } + + protected override async Task DoLogin() + { + var requestBuilder = new HttpRequestBuilder(Settings.BaseUrl) + { + LogResponseContent = true, + AllowAutoRedirect = true + }; + + var indexPage = await ExecuteAuth(requestBuilder.Build()); + + var loginUrl = string.Format("{0}/{1}", Settings.BaseUrl.TrimEnd('/'), "login.php"); + + var requestBuilder2 = new HttpRequestBuilder(loginUrl) + { + LogResponseContent = true, + AllowAutoRedirect = true + }; + + var authLoginRequest = requestBuilder2 + .SetCookies(indexPage.GetCookies()) + .Build(); + + // Get login page -- (not used, but simulation needed by tracker security's checks) + await ExecuteAuth(authLoginRequest); + + var requestBuilder3 = new HttpRequestBuilder(string.Format("{0}/{1}", Settings.BaseUrl.TrimEnd('/'), "takelogin.php")) + { + LogResponseContent = true, + AllowAutoRedirect = true + }; + + var authLoginCheckRequest = requestBuilder3 + .AddFormParameter("username", Settings.Username) + .AddFormParameter("password", Settings.Password) + .SetCookies(indexPage.GetCookies()) + .SetHeader("Referer", loginUrl) + .Build(); + + authLoginCheckRequest.Method = HttpMethod.POST; + + var loginResponse = await ExecuteAuth(authLoginCheckRequest); + + if (!loginResponse.GetCookies().ContainsKey("uid")) + { + // Default error message + var message = "Error during attempt !"; + + // Oops, unable to login + _logger.Info("NorBits - Login failed: " + message, "error"); + + throw new IndexerAuthException(message); + } + + var cookies = loginResponse.GetCookies(); + UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); + + _logger.Debug("NorBits authentication succeeded."); + } + + protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) + { + if (!httpResponse.Content.Contains("logout.php")) + { + return true; + } + + return false; + } + + private IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities + { + TvSearchParams = new List<TvSearchParam> + { + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep + }, + MovieSearchParams = new List<MovieSearchParam> + { + MovieSearchParam.Q, MovieSearchParam.ImdbId + }, + MusicSearchParams = new List<MusicSearchParam> + { + MusicSearchParam.Q + }, + BookSearchParams = new List<BookSearchParam> + { + BookSearchParam.Q + } + }; + + 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&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&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&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; + } + } + + public class NorBitsRequestGenerator : IIndexerRequestGenerator + { + public NorBitsSettings Settings { get; set; } + public IndexerCapabilities Capabilities { get; set; } + + public NorBitsRequestGenerator() + { + } + + private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null) + { + var searchUrl = string.Format("{0}/browse.php", Settings.BaseUrl.TrimEnd('/')); + + var parameters = new NameValueCollection(); + var categoriesList = Capabilities.Categories.MapTorznabCapsToTrackers(categories); + var searchterm = term; + + // Building our tracker query + parameters.Add("incldead", "1"); + parameters.Add("fullsearch", Settings.UseFullSearch ? "1" : "0"); + parameters.Add("scenerelease", "0"); + + // If search term provided + if (!string.IsNullOrWhiteSpace(imdbId)) + { + searchterm = "imdbsearch=" + imdbId; + } + else if (!string.IsNullOrWhiteSpace(term)) + { + searchterm = "search=" + term.UrlEncode(Encoding.GetEncoding(28591)); + } + else + { + // Showing all torrents (just for output function) + searchterm = "search="; + } + + var catQryStr = ""; + + foreach (var cat in categoriesList) + { + catQryStr += "&" + cat; + } + + // Building our query + searchUrl += "?" + searchterm + "&" + parameters.GetQueryString() + "&" + catQryStr; + + var request = new IndexerRequest(searchUrl, HttpAccept.Html); + + yield return request; + } + + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public Func<IDictionary<string, string>> GetCookies { get; set; } + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + } + + public class NorBitsParser : IParseIndexerResponse + { + private readonly NorBitsSettings _settings; + private readonly IndexerCapabilitiesCategories _categories; + + public NorBitsParser(NorBitsSettings settings, IndexerCapabilitiesCategories categories) + { + _settings = settings; + _categories = categories; + } + + public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) + { + var torrentInfos = new List<ReleaseInfo>(); + + var parser = new HtmlParser(); + var dom = parser.ParseDocument(indexerResponse.Content); + + var firstPageRows = dom.QuerySelectorAll("#torrentTable > tbody > tr").Skip(1).ToCollection(); + + // If pagination available + int nbResults; + + // Check if we have a minimum of one result + if (firstPageRows?.Length >= 1) + { + // Retrieve total count on our alone page + nbResults = firstPageRows.Count(); + } + else + { + // No result found for this query + return torrentInfos; + } + + var torrentDetailsUrl = _settings.BaseUrl + "details.php?id={id}"; + var torrentDownloadUrl = _settings.BaseUrl + "download.php?id={id}&passkey={passkey}"; + + // Loop on results + foreach (var row in firstPageRows) + { + var id = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(1)").GetAttribute("href").Split('=').Last(); // ID + var name = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(1)").GetAttribute("title"); // Release Name + var categoryName = row.QuerySelector("td:nth-of-type(1) > div > a:nth-of-type(1)").GetAttribute("title"); // Category + var mainCat = row.QuerySelector("td:nth-of-type(1) > div > a:nth-of-type(1)").GetAttribute("href").Split('?').Last(); + var qSubCat2 = row.QuerySelector("td:nth-of-type(1) > div > a[href^=\"/browse.php?sub2_cat[]=\"]"); + var cat = mainCat; + if (qSubCat2 != null) + { + cat += '&' + qSubCat2.GetAttribute("href").Split('?').Last(); + } + + var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(9)").TextContent); // Seeders + var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(10)").TextContent); // Leechers + var regexObj = new Regex(@"[^\d]"); // Completed + var completed2 = row.QuerySelector("td:nth-of-type(8)").TextContent; + var completed = ParseUtil.CoerceInt(regexObj.Replace(completed2, "")); + var qFiles = row.QuerySelector("td:nth-of-type(3) > a"); // Files + var files = qFiles != null ? ParseUtil.CoerceInt(Regex.Match(qFiles.TextContent, @"\d+").Value) : 1; + var humanSize = row.QuerySelector("td:nth-of-type(7)").TextContent.ToLowerInvariant(); // Size + var size = ParseUtil.GetBytes(humanSize); // Date + var dateTimeOrig = row.QuerySelector("td:nth-of-type(5)").TextContent; + var dateTime = Regex.Replace(dateTimeOrig, @"<[^>]+>| ", "").Trim(); + var date = DateTime.ParseExact(dateTime, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime(); + var details = new Uri(torrentDetailsUrl.Replace("{id}", id.ToString())); // Description Link + var passkey = row.QuerySelector("td:nth-of-type(2) > a:nth-of-type(2)").GetAttribute("href"); // Download Link + var key = Regex.Match(passkey, "(?<=passkey\\=)([a-zA-z0-9]*)"); + var downloadLink = new Uri(torrentDownloadUrl.Replace("{id}", id.ToString()).Replace("{passkey}", key.ToString())); + + // Building release infos + var release = new TorrentInfo + { + Categories = _categories.MapTrackerCatToNewznab(cat), + Title = name, + Seeders = seeders, + Peers = seeders + leechers, + PublishDate = date, + Size = size, + Files = files, + Grabs = completed, + Guid = details.AbsoluteUri, + InfoUrl = details.AbsoluteUri, + DownloadUrl = downloadLink.AbsoluteUri, + MinimumRatio = 1, + MinimumSeedTime = 172800 // 48 hours + }; + + var genres = row.QuerySelector("span.genres")?.TextContent; + if (!string.IsNullOrEmpty(genres)) + { + release.Description = genres; + } + + // IMDB + var imdbLink = row.QuerySelector("a[href*=\"imdb.com/title/tt\"]")?.GetAttribute("href"); + release.ImdbId = ParseUtil.GetImdbID(imdbLink) ?? 0; + + if (row.QuerySelector("img[title=\"100% freeleech\"]") != null) + { + release.DownloadVolumeFactor = 0; + } + else if (row.QuerySelector("img[title=\"Halfleech\"]") != null) + { + release.DownloadVolumeFactor = 0.5; + } + else if (row.QuerySelector("img[title=\"90% Freeleech\"]") != null) + { + release.DownloadVolumeFactor = 0.1; + } + else + { + release.DownloadVolumeFactor = 1; + } + + release.UploadVolumeFactor = 1; + + torrentInfos.Add(release); + } + + return torrentInfos.ToArray(); + } + + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + } + + public class NorBitsSettingsValidator : AbstractValidator<NorBitsSettings> + { + public NorBitsSettingsValidator() + { + RuleFor(c => c.Username).NotEmpty(); + RuleFor(c => c.Password).NotEmpty(); + } + } + + public class NorBitsSettings : IIndexerSettings + { + private static readonly NorBitsSettingsValidator Validator = new NorBitsSettingsValidator(); + + public NorBitsSettings() + { + Username = ""; + Password = ""; + } + + [FieldDefinition(1, Label = "Base Url", HelpText = "Select which baseurl Prowlarr will use for requests to the site", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls")] + public string BaseUrl { get; set; } + + [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] + public string Username { get; set; } + + [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] + public string Password { get; set; } + + [FieldDefinition(4, Label = "Use Full Search", HelpText = "Use Full Search from Site", Type = FieldType.Checkbox)] + public bool UseFullSearch { get; set; } + + [FieldDefinition(5)] + public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} From 22412981bbbaea1194c60ee1bbaf2d09a42018e1 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 8 Nov 2021 23:29:31 -0600 Subject: [PATCH 0128/2320] Fixed: (SpeedCD) Incorrect Http Login Method Fixes #582 --- src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs index 520a6ea21..ef253a5eb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs @@ -57,11 +57,12 @@ namespace NzbDrone.Core.Indexers.Definitions { var requestBuilder = new HttpRequestBuilder(string.Format("{0}/{1}", Settings.BaseUrl.TrimEnd('/'), "checkpoint/API")) { + Method = HttpMethod.POST, LogResponseContent = true, AllowAutoRedirect = true }; - var loginPage = await ExecuteAuth(requestBuilder.Build()); + var loginPage = await ExecuteAuth(requestBuilder.AddFormParameter("username", Settings.Username).Build()); var tokenRegex = new Regex(@"name=\\""a\\"" value=\\""([^""]+)\\"""); var matches = tokenRegex.Match(loginPage.Content); @@ -76,6 +77,7 @@ namespace NzbDrone.Core.Indexers.Definitions var requestBuilder2 = new HttpRequestBuilder(string.Format("{0}/{1}", Settings.BaseUrl.TrimEnd('/'), "checkpoint/")) { + Method = HttpMethod.POST, LogResponseContent = true, AllowAutoRedirect = true }; From 61cff122065d494681900e7ac7925e4145a28f47 Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Sat, 23 Oct 2021 21:33:41 +0100 Subject: [PATCH 0129/2320] Fixed: Time column is first column on events page (cherry picked from commit c14ef7bee7477ad5d29498f1cba94267eb11daf0) --- frontend/src/Store/Actions/systemActions.js | 14 ++++++------- frontend/src/System/Events/LogsTableRow.js | 22 ++++++++++----------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/frontend/src/Store/Actions/systemActions.js b/frontend/src/Store/Actions/systemActions.js index 94221ed95..4910e462d 100644 --- a/frontend/src/Store/Actions/systemActions.js +++ b/frontend/src/Store/Actions/systemActions.js @@ -87,6 +87,13 @@ export const defaultState = { isVisible: true, isModifiable: false }, + { + name: 'time', + label: translate('Time'), + isSortable: true, + isVisible: true, + isModifiable: false + }, { name: 'logger', label: translate('Component'), @@ -100,13 +107,6 @@ export const defaultState = { isVisible: true, isModifiable: false }, - { - name: 'time', - label: translate('Time'), - isSortable: true, - isVisible: true, - isModifiable: false - }, { name: 'actions', columnLabel: translate('Actions'), diff --git a/frontend/src/System/Events/LogsTableRow.js b/frontend/src/System/Events/LogsTableRow.js index ab7bf8606..bebf80184 100644 --- a/frontend/src/System/Events/LogsTableRow.js +++ b/frontend/src/System/Events/LogsTableRow.js @@ -58,9 +58,9 @@ class LogsTableRow extends Component { render() { const { level, + time, logger, message, - time, exception, columns } = this.props; @@ -96,6 +96,15 @@ class LogsTableRow extends Component { ); } + if (name === 'time') { + return ( + <RelativeDateCellConnector + key={name} + date={time} + /> + ); + } + if (name === 'logger') { return ( <TableRowCell key={name}> @@ -112,15 +121,6 @@ class LogsTableRow extends Component { ); } - if (name === 'time') { - return ( - <RelativeDateCellConnector - key={name} - date={time} - /> - ); - } - if (name === 'actions') { return ( <TableRowCell @@ -148,9 +148,9 @@ class LogsTableRow extends Component { LogsTableRow.propTypes = { level: PropTypes.string.isRequired, + time: PropTypes.string.isRequired, logger: PropTypes.string.isRequired, message: PropTypes.string.isRequired, - time: PropTypes.string.isRequired, exception: PropTypes.string, columns: PropTypes.arrayOf(PropTypes.object).isRequired }; From 8ebec7c7e19d6a266029f74dd8df3765df3ce27a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 9 Nov 2021 22:12:56 -0600 Subject: [PATCH 0130/2320] Fixed: (Applications) Test fails when selecting sub-categories only for sync Fixes #588 --- src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs | 5 ++++- src/NzbDrone.Core/Applications/Radarr/Radarr.cs | 5 ++++- src/NzbDrone.Core/Applications/Readarr/Readarr.cs | 5 ++++- src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs | 5 ++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs index f241fd850..1af2b7901 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs @@ -40,7 +40,10 @@ namespace NzbDrone.Core.Applications.Lidarr Capabilities = new IndexerCapabilities() }; - testIndexer.Capabilities.Categories.AddCategoryMapping(1, NewznabStandardCategory.Audio); + foreach (var cat in NewznabStandardCategory.AllCats) + { + testIndexer.Capabilities.Categories.AddCategoryMapping(1, cat); + } try { diff --git a/src/NzbDrone.Core/Applications/Radarr/Radarr.cs b/src/NzbDrone.Core/Applications/Radarr/Radarr.cs index 0c5bcdfaa..e5c8c25ab 100644 --- a/src/NzbDrone.Core/Applications/Radarr/Radarr.cs +++ b/src/NzbDrone.Core/Applications/Radarr/Radarr.cs @@ -40,7 +40,10 @@ namespace NzbDrone.Core.Applications.Radarr Capabilities = new IndexerCapabilities() }; - testIndexer.Capabilities.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies); + foreach (var cat in NewznabStandardCategory.AllCats) + { + testIndexer.Capabilities.Categories.AddCategoryMapping(1, cat); + } try { diff --git a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs index b1205c5d1..f3603886d 100644 --- a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs +++ b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs @@ -40,7 +40,10 @@ namespace NzbDrone.Core.Applications.Readarr Capabilities = new IndexerCapabilities() }; - testIndexer.Capabilities.Categories.AddCategoryMapping(1, NewznabStandardCategory.Books); + foreach (var cat in NewznabStandardCategory.AllCats) + { + testIndexer.Capabilities.Categories.AddCategoryMapping(1, cat); + } try { diff --git a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs index 589e8eb72..196b6f14a 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs @@ -40,7 +40,10 @@ namespace NzbDrone.Core.Applications.Sonarr Capabilities = new IndexerCapabilities() }; - testIndexer.Capabilities.Categories.AddCategoryMapping(1, NewznabStandardCategory.TV); + foreach (var cat in NewznabStandardCategory.AllCats) + { + testIndexer.Capabilities.Categories.AddCategoryMapping(1, cat); + } try { From 5ca8148d3bc4903ee081bcc47cd6f63ec861b369 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 9 Nov 2021 18:37:57 -0600 Subject: [PATCH 0131/2320] Bump macOS build agent to 10.15 --- azure-pipelines.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8cb606cd0..5651e4b7a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -67,7 +67,7 @@ stages: enableAnalysis: 'true' Mac: osName: 'Mac' - imageName: 'macos-10.14' + imageName: 'macos-10.15' enableAnalysis: 'false' Windows: osName: 'Windows' @@ -144,7 +144,7 @@ stages: imageName: 'ubuntu-18.04' Mac: osName: 'Mac' - imageName: 'macos-10.14' + imageName: 'macos-10.15' Windows: osName: 'Windows' imageName: 'windows-2019' @@ -383,7 +383,7 @@ stages: osName: 'Mac' testName: 'MacCore' poolName: 'Azure Pipelines' - imageName: 'macos-10.14' + imageName: 'macos-10.15' WindowsCore: osName: 'Windows' testName: 'WindowsCore' @@ -510,7 +510,7 @@ stages: MacCore: osName: 'Mac' testName: 'MacCore' - imageName: 'macos-10.14' + imageName: 'macos-10.15' pattern: 'Prowlarr.*.osx-core-x64.tar.gz' WindowsCore: osName: 'Windows' @@ -686,7 +686,7 @@ stages: failBuild: false Mac: osName: 'Mac' - imageName: 'macos-10.14' + imageName: 'macos-10.15' pattern: 'Prowlarr.*.osx-core-x64.tar.gz' failBuild: false Windows: From 87d6cbd813af162089b3f24cd4c1e89bd5b47413 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 9 Nov 2021 22:26:30 -0600 Subject: [PATCH 0132/2320] Clarified Aria2 RPC Path field Co-Authored-By: Taloth <Taloth@users.noreply.github.com> --- src/NzbDrone.Core/Download/Clients/Aria2/Aria2Settings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Settings.cs b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Settings.cs index a78732c52..e88bc4cc1 100644 --- a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Settings.cs +++ b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Settings.cs @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Download.Clients.Aria2 [FieldDefinition(1, Label = "Port", Type = FieldType.Number)] public int Port { get; set; } - [FieldDefinition(2, Label = "RPC Path", Type = FieldType.Textbox)] + [FieldDefinition(2, Label = "XML RPC Path", Type = FieldType.Textbox)] public string RpcPath { get; set; } [FieldDefinition(3, Label = "Use SSL", Type = FieldType.Checkbox)] From 49793a3af0879d6310892526e73affcabee16b2b Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 9 Nov 2021 22:27:53 -0600 Subject: [PATCH 0133/2320] Rename NzbSearchService to ReleaseSearchService --- .../{NzbSearchService.cs => ReleaseSearchService.cs} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/NzbDrone.Core/IndexerSearch/{NzbSearchService.cs => ReleaseSearchService.cs} (98%) diff --git a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs similarity index 98% rename from src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs rename to src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs index b1d3574a4..4111cdd7d 100644 --- a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs @@ -17,14 +17,14 @@ namespace NzbDrone.Core.IndexerSearch Task<NewznabResults> Search(NewznabRequest request, List<int> indexerIds, bool interactiveSearch); } - public class NzbSearchService : ISearchForNzb + public class ReleaseSearchService : ISearchForNzb { private readonly IIndexerLimitService _indexerLimitService; private readonly IEventAggregator _eventAggregator; private readonly IIndexerFactory _indexerFactory; private readonly Logger _logger; - public NzbSearchService(IEventAggregator eventAggregator, + public ReleaseSearchService(IEventAggregator eventAggregator, IIndexerFactory indexerFactory, IIndexerLimitService indexerLimitService, Logger logger) From 11fad915d56468d6f1bb1ba5700785bcc4673615 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 9 Nov 2021 22:35:45 -0600 Subject: [PATCH 0134/2320] Drop prefix from issue templates --- .github/ISSUE_TEMPLATE/bug_report.yml | 1 - .github/ISSUE_TEMPLATE/feature_request.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index a3863e2eb..5a1141815 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,5 +1,4 @@ name: Bug Report -title: "[BUG]: " description: 'Report a new bug, if you are not 100% certain this is a bug please go to our Reddit or Discord first' labels: ['Type: Bug', 'Status: Needs Triage'] body: diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 78f2ddef4..df8fc1f4e 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,5 +1,4 @@ name: Feature Request -title: "[FEAT]: " description: 'Suggest an idea for Prowlarr' labels: ['Type: Feature Request', 'Status: Needs Triage'] body: From 51df1be144e6f4ea6c22c4a3833c160849fc5a32 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 10 Nov 2021 14:45:49 -0600 Subject: [PATCH 0135/2320] Fixed: Remove Defunct Usenet Indexer NZBXS closes #594 --- src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs index 1aa1cfd6b..d27b1df4d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs @@ -102,7 +102,6 @@ namespace NzbDrone.Core.Indexers.Newznab yield return GetDefinition("NZBNDX", GetSettings("https://www.nzbndx.com")); yield return GetDefinition("NzbPlanet", GetSettings("https://api.nzbplanet.net")); yield return GetDefinition("NZBStars", GetSettings("https://nzbstars.com")); - yield return GetDefinition("NZBXS", GetSettings("https://www.nzbxs.com")); yield return GetDefinition("OZnzb", GetSettings("https://api.oznzb.com")); yield return GetDefinition("SimplyNZBs", GetSettings("https://simplynzbs.com")); yield return GetDefinition("SpotNZB", GetSettings("https://spotnzb.xyz")); From 971c7557382b02a330ad86759136ffd8f7076cee Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 13 Nov 2021 19:24:11 -0600 Subject: [PATCH 0136/2320] Fixed: (RarBG) Remove Book Category & Support based on Jackett f018470d6951a496b3d274fdda825c26ae8f6425 --- src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs index 1ef5c112d..a0fb1ab53 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs @@ -59,10 +59,6 @@ namespace NzbDrone.Core.Indexers.Rarbg MusicSearchParams = new List<MusicSearchParam> { MusicSearchParam.Q - }, - BookSearchParams = new List<BookSearchParam> - { - BookSearchParam.Q } }; @@ -76,7 +72,6 @@ namespace NzbDrone.Core.Indexers.Rarbg caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.PCGames, "Games/PC RIP"); caps.Categories.AddCategoryMapping(32, NewznabStandardCategory.ConsoleXBox360, "Games/XBOX-360"); caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.PCISO, "Software/PC ISO"); - caps.Categories.AddCategoryMapping(35, NewznabStandardCategory.BooksEBook, "e-Books"); caps.Categories.AddCategoryMapping(40, NewznabStandardCategory.ConsolePS3, "Games/PS3"); caps.Categories.AddCategoryMapping(41, NewznabStandardCategory.TVHD, "TV HD Episodes"); caps.Categories.AddCategoryMapping(42, NewznabStandardCategory.MoviesBluRay, "Movies/Full BD"); From 93deb56e8ebe5f4ae612994ff0c92ed574dee89e Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Thu, 11 Nov 2021 11:43:49 -0600 Subject: [PATCH 0137/2320] Fixed: Cleanse RSSKey and PassKey from Indexer Response --- .../InstrumentationTests/CleanseLogMessageFixture.cs | 8 +++++++- src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs | 4 +++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs index e44bd5b13..5ac5edda2 100644 --- a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs +++ b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs @@ -24,10 +24,16 @@ namespace NzbDrone.Common.Test.InstrumentationTests [TestCase(@"https://beyond-hd.me/api/torrents/2b51db35e1912ffc138825a12b9933d2")] [TestCase(@"Req: [POST] https://www3.yggtorrent.nz/user/login: id=mySecret&pass=mySecret&ci_csrf_token=2b51db35e1912ffc138825a12b9933d2")] - // avistaz response + //Indexer Responses + + // avistaz response [TestCase(@"""download"":""https:\/\/avistaz.to\/rss\/download\/2b51db35e1910123321025a12b9933d2\/tb51db35e1910123321025a12b9933d2.torrent"",")] [TestCase(@",""info_hash"":""2b51db35e1910123321025a12b9933d2"",")] + // danish bytes response + [TestCase(@",""rsskey"":""2b51db35e1910123321025a12b9933d2"",")] + [TestCase(@",""passkey"":""2b51db35e1910123321025a12b9933d2"",")] + // NzbGet [TestCase(@"{ ""Name"" : ""ControlUsername"", ""Value"" : ""mySecret"" }, { ""Name"" : ""ControlPassword"", ""Value"" : ""mySecret"" }, ")] [TestCase(@"{ ""Name"" : ""Server1.Username"", ""Value"" : ""mySecret"" }, { ""Name"" : ""Server1.Password"", ""Value"" : ""mySecret"" }, ")] diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index 17d64aedb..5ead40baa 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -47,9 +47,11 @@ namespace NzbDrone.Common.Instrumentation // Plex new Regex(@"(?<=\?|&)(X-Plex-Client-Identifier|X-Plex-Token)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), - //avistaz + // Indexer Responses new Regex(@"avistaz\.[a-z]{2,3}\\\/rss\\\/download\\\/(?<secret>[^&=]+?)\\\/(?<secret>[^&=]+?)\.torrent", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@",""info_hash"":""(?<secret>[^&=]+?)"",", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@",""pass[- _]?key"":""(?<secret>[^&=]+?)"",", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@",""rss[- _]?key"":""(?<secret>[^&=]+?)"",", RegexOptions.Compiled | RegexOptions.IgnoreCase), }; private static readonly Regex CleanseRemoteIPRegex = new Regex(@"(?:Auth-\w+(?<!Failure|Unauthorized) ip|from) (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", RegexOptions.Compiled); From 2c0c6aa1581b019979f08d69b1475bde727f72e3 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 30 Oct 2021 16:19:22 -0500 Subject: [PATCH 0138/2320] New: Support JSON parsing in Cardigann Co-Authored-By: mikeoscar2006 <89641725+mikeoscar2006@users.noreply.github.com> --- .../IndexerDefinitionUpdateService.cs | 2 +- .../Definitions/Cardigann/CardigannBase.cs | 74 +- .../Cardigann/CardigannDefinition.cs | 12 +- .../Definitions/Cardigann/CardigannParser.cs | 785 ++++++++++-------- .../Definitions/Cardigann/CardigannRequest.cs | 7 +- .../Cardigann/CardigannRequestGenerator.cs | 2 +- 6 files changed, 531 insertions(+), 351 deletions(-) diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index d12d9a042..5941c3666 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -26,7 +26,7 @@ namespace NzbDrone.Core.IndexerVersions { /* Update Service will fall back if version # does not exist for an indexer per Ta */ - private const int DEFINITION_VERSION = 2; + private const int DEFINITION_VERSION = 3; private readonly List<string> _defintionBlocklist = new List<string>() { "aither", diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index fe4467ea3..d2b0b33cb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -141,7 +141,7 @@ namespace NzbDrone.Core.Indexers.Cardigann return element.QuerySelector(selector); } - protected string HandleSelector(SelectorBlock selector, IElement dom, Dictionary<string, object> variables = null) + protected string HandleSelector(SelectorBlock selector, IElement dom, Dictionary<string, object> variables = null, bool required = true) { if (selector.Text != null) { @@ -164,7 +164,12 @@ namespace NzbDrone.Core.Indexers.Cardigann if (selection == null) { - throw new Exception(string.Format("Selector \"{0}\" didn't match {1}", selector.Selector, dom.ToHtmlPretty())); + if (required) + { + throw new Exception(string.Format("Selector \"{0}\" didn't match {1}", selector.Selector, dom.ToHtmlPretty())); + } + + return null; } } @@ -189,7 +194,12 @@ namespace NzbDrone.Core.Indexers.Cardigann if (value == null) { - throw new Exception(string.Format("None of the case selectors \"{0}\" matched {1}", string.Join(",", selector.Case), selection.ToHtmlPretty())); + if (required) + { + throw new Exception(string.Format("None of the case selectors \"{0}\" matched {1}", string.Join(",", selector.Case), selection.ToHtmlPretty())); + } + + return null; } } else if (selector.Attribute != null) @@ -197,7 +207,12 @@ namespace NzbDrone.Core.Indexers.Cardigann value = selection.GetAttribute(selector.Attribute); if (value == null) { - throw new Exception(string.Format("Attribute \"{0}\" is not set for element {1}", selector.Attribute, selection.ToHtmlPretty())); + if (required) + { + throw new Exception(string.Format("Attribute \"{0}\" is not set for element {1}", selector.Attribute, selection.ToHtmlPretty())); + } + + return null; } } else @@ -208,6 +223,57 @@ namespace NzbDrone.Core.Indexers.Cardigann return ApplyFilters(ParseUtil.NormalizeSpace(value), selector.Filters, variables); } + protected string HandleJsonSelector(SelectorBlock selector, JToken parentObj, Dictionary<string, object> variables = null, bool required = true) + { + if (selector.Text != null) + { + return ApplyFilters(ApplyGoTemplateText(selector.Text, variables), selector.Filters, variables); + } + + string value = null; + + if (selector.Selector != null) + { + var selector_Selector = ApplyGoTemplateText(selector.Selector.TrimStart('.'), variables); + var selection = parentObj.SelectToken(selector_Selector); + if (selection == null) + { + if (required) + { + throw new Exception(string.Format("Selector \"{0}\" didn't match {1}", selector_Selector, parentObj.ToString())); + } + + return null; + } + + value = selection.Value<string>(); + } + + if (selector.Case != null) + { + foreach (var jcase in selector.Case) + { + if (value.Equals(jcase.Key) || jcase.Key.Equals("*")) + { + value = jcase.Value; + break; + } + } + + if (value == null) + { + if (required) + { + throw new Exception(string.Format("None of the case selectors \"{0}\" matched {1}", string.Join(",", selector.Case), parentObj.ToString())); + } + + return null; + } + } + + return ApplyFilters(ParseUtil.NormalizeSpace(value), selector.Filters, variables); + } + protected Dictionary<string, object> GetBaseTemplateVariables() { var indexerLogging = _configService.LogIndexerResponse; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs index c666af501..4c7f0f32f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs @@ -150,13 +150,15 @@ namespace NzbDrone.Core.Indexers.Cardigann { public int After { get; set; } public SelectorBlock Dateheaders { get; set; } + public SelectorBlock Count { get; set; } } public class SearchPathBlock : RequestBlock { public List<string> Categories { get; set; } public bool Inheritinputs { get; set; } = true; - public bool Followredirect { get; set; } = false; + public bool Followredirect { get; set; } + public ResponseBlock Response { get; set; } } public class RequestBlock @@ -194,4 +196,12 @@ namespace NzbDrone.Core.Indexers.Cardigann { public SelectorField Pathselector { get; set; } } + + public class ResponseBlock + { + public string Type { get; set; } + public string Attribute { get; set; } + public bool Multiple { get; set; } + public string NoResultsMessage { get; set; } + } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index 525e67410..b59eb8f9e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -5,6 +5,7 @@ using System.Net; using System.Text.RegularExpressions; using AngleSharp.Dom; using AngleSharp.Html.Parser; +using Newtonsoft.Json.Linq; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Core.Configuration; @@ -55,59 +56,46 @@ namespace NzbDrone.Core.Indexers.Cardigann var searchUrlUri = new Uri(request.Url.FullUri); - try + if (request.SearchPath.Response != null && request.SearchPath.Response.Type.Equals("json")) { - var searchResultParser = new HtmlParser(); - var searchResultDocument = searchResultParser.ParseDocument(results); - - /* checkForError(response, Definition.Search.Error); */ - - if (search.Preprocessingfilters != null) + if (request.SearchPath.Response != null && request.SearchPath.Response.NoResultsMessage != null && (request.SearchPath.Response.NoResultsMessage.Equals(results) || (request.SearchPath.Response.NoResultsMessage == string.Empty && results == string.Empty))) { - results = ApplyFilters(results, search.Preprocessingfilters, variables); - searchResultDocument = searchResultParser.ParseDocument(results); - _logger.Trace(string.Format("CardigannIndexer ({0}): result after preprocessingfilters: {1}", _definition.Id, results)); + return releases; } - var rowsSelector = ApplyGoTemplateText(search.Rows.Selector, variables); - var rowsDom = searchResultDocument.QuerySelectorAll(rowsSelector); - var rows = new List<IElement>(); - foreach (var rowDom in rowsDom) + var parsedJson = JToken.Parse(results); + if (parsedJson == null) { - rows.Add(rowDom); + throw new Exception("Error Parsing Json Response"); } - // merge following rows for After selector - var after = search.Rows.After; - if (after > 0) + if (search.Rows.Count != null) { - for (var i = 0; i < rows.Count; i += 1) + var countVal = HandleJsonSelector(search.Rows.Count, parsedJson, variables); + if (int.TryParse(countVal, out var count)) { - var currentRow = rows[i]; - for (var j = 0; j < after; j += 1) + if (count < 1) { - var mergeRowIndex = i + j + 1; - var mergeRow = rows[mergeRowIndex]; - var mergeNodes = new List<INode>(); - foreach (var node in mergeRow.ChildNodes) - { - mergeNodes.Add(node); - } - - currentRow.Append(mergeNodes.ToArray()); + return releases; } - - rows.RemoveRange(i + 1, after); } } - foreach (var row in rows) + var rowsObj = parsedJson.SelectToken(search.Rows.Selector); + if (rowsObj == null) { - try + throw new Exception("Error Parsing Rows Selector"); + } + + foreach (var row in rowsObj.Value<JArray>()) + { + var selObj = request.SearchPath.Response.Attribute != null ? row.SelectToken(request.SearchPath.Response.Attribute).Value<JToken>() : row; + var mulRows = request.SearchPath.Response.Multiple == true ? selObj.Values<JObject>() : new List<JObject> { selObj.Value<JObject>() }; + + foreach (var mulRow in mulRows) { var release = new TorrentInfo(); - // Parse fields foreach (var field in search.Fields) { var fieldParts = field.Key.Split('|'); @@ -120,200 +108,23 @@ namespace NzbDrone.Core.Indexers.Cardigann string value = null; var variablesKey = ".Result." + fieldName; + var isOptional = OptionalFields.Contains(field.Key) || fieldModifiers.Contains("optional") || field.Value.Optional; try { - value = HandleSelector(field.Value, row, variables); - switch (fieldName) + var parentObj = mulRow; + if (field.Value.Selector != null && field.Value.Selector.StartsWith("..")) { - case "download": - if (string.IsNullOrEmpty(value)) - { - value = null; - release.DownloadUrl = null; - break; - } - - if (value.StartsWith("magnet:")) - { - release.MagnetUrl = value; - value = release.MagnetUrl; - } - else - { - release.DownloadUrl = ResolvePath(value, searchUrlUri).AbsoluteUri; - value = release.DownloadUrl; - } - - break; - case "magnet": - var magnetUri = value; - release.MagnetUrl = magnetUri; - value = magnetUri.ToString(); - break; - case "infohash": - release.InfoHash = value; - break; - case "details": - var url = ResolvePath(value, searchUrlUri)?.AbsoluteUri; - release.InfoUrl = url; - release.Guid = url; - value = url.ToString(); - break; - case "comments": - var commentsUrl = ResolvePath(value, searchUrlUri); - if (release.CommentUrl == null) - { - release.CommentUrl = commentsUrl.AbsoluteUri; - } - - value = commentsUrl.ToString(); - break; - case "title": - if (fieldModifiers.Contains("append")) - { - release.Title += value; - } - else - { - release.Title = value; - } - - value = release.Title; - break; - case "description": - if (fieldModifiers.Contains("append")) - { - release.Description += value; - } - else - { - release.Description = value; - } - - value = release.Description; - break; - case "category": - var cats = MapTrackerCatToNewznab(value); - if (cats.Any()) - { - if (release.Categories == null || fieldModifiers.Contains("noappend")) - { - release.Categories = cats; - } - else - { - release.Categories = release.Categories.Union(cats).ToList(); - } - } - - value = release.Categories.ToString(); - break; - case "size": - release.Size = ParseUtil.GetBytes(value); - value = release.Size.ToString(); - break; - case "leechers": - var leechers = ParseUtil.CoerceLong(value); - leechers = leechers < 5000000L ? leechers : 0; // to fix #6558 - if (release.Peers == null) - { - release.Peers = (int)leechers; - } - else - { - release.Peers += (int)leechers; - } - - value = leechers.ToString(); - break; - case "seeders": - release.Seeders = ParseUtil.CoerceInt(value); - release.Seeders = release.Seeders < 5000000L ? release.Seeders : 0; // to fix #6558 - if (release.Peers == null) - { - release.Peers = release.Seeders; - } - else - { - release.Peers += release.Seeders; - } - - value = release.Seeders.ToString(); - break; - case "date": - release.PublishDate = DateTimeUtil.FromUnknown(value); - value = release.PublishDate.ToString(DateTimeUtil.Rfc1123ZPattern); - break; - case "files": - release.Files = ParseUtil.CoerceInt(value); - value = release.Files.ToString(); - break; - case "grabs": - release.Grabs = ParseUtil.CoerceInt(value); - value = release.Grabs.ToString(); - break; - case "downloadvolumefactor": - release.DownloadVolumeFactor = ParseUtil.CoerceDouble(value); - value = release.DownloadVolumeFactor.ToString(); - break; - case "uploadvolumefactor": - release.UploadVolumeFactor = ParseUtil.CoerceDouble(value); - value = release.UploadVolumeFactor.ToString(); - break; - case "minimumratio": - release.MinimumRatio = ParseUtil.CoerceDouble(value); - value = release.MinimumRatio.ToString(); - break; - case "minimumseedtime": - release.MinimumSeedTime = ParseUtil.CoerceLong(value); - value = release.MinimumSeedTime.ToString(); - break; - case "imdb": - release.ImdbId = (int)ParseUtil.GetLongFromString(value); - value = release.ImdbId.ToString(); - break; - case "tmdbid": - var tmdbIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); - var tmdbIDMatch = tmdbIDRegEx.Match(value); - var tmdbID = tmdbIDMatch.Groups[1].Value; - release.TmdbId = (int)ParseUtil.CoerceLong(tmdbID); - value = release.TmdbId.ToString(); - break; - case "rageid": - var rageIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); - var rageIDMatch = rageIDRegEx.Match(value); - var rageID = rageIDMatch.Groups[1].Value; - release.TvRageId = (int)ParseUtil.CoerceLong(rageID); - value = release.TvRageId.ToString(); - break; - case "tvdbid": - var tvdbIdRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); - var tvdbIdMatch = tvdbIdRegEx.Match(value); - var tvdbId = tvdbIdMatch.Groups[1].Value; - release.TvdbId = (int)ParseUtil.CoerceLong(tvdbId); - value = release.TvdbId.ToString(); - break; - case "poster": - if (!string.IsNullOrWhiteSpace(value)) - { - var poster = ResolvePath(value, searchUrlUri); - release.PosterUrl = poster.AbsoluteUri; - } - - value = release.PosterUrl; - break; - - //case "author": - // release.Author = value; - // break; - //case "booktitle": - // release.BookTitle = value; - // break; - default: - break; + parentObj = row.Value<JObject>(); } - variables[variablesKey] = value; + value = HandleJsonSelector(field.Value, parentObj, variables, !isOptional); + if (isOptional && string.IsNullOrWhiteSpace(value)) + { + variables[variablesKey] = null; + continue; + } + + variables[variablesKey] = ParseFields(value, fieldName, release, fieldModifiers, searchUrlUri); } catch (Exception ex) { @@ -322,141 +133,202 @@ namespace NzbDrone.Core.Indexers.Cardigann variables[variablesKey] = null; } - if (OptionalFields.Contains(field.Key) || fieldModifiers.Contains("optional") || field.Value.Optional) + if (isOptional) { variables[variablesKey] = null; continue; } - if (indexerLogging) - { - _logger.Trace("Error while parsing field={0}, selector={1}, value={2}: {3}", field.Key, field.Value.Selector, value == null ? "<null>" : value, ex.Message); - } - } - } - - var filters = search.Rows.Filters; - var skipRelease = false; - if (filters != null) - { - foreach (var filter in filters) - { - switch (filter.Name) - { - case "andmatch": - var characterLimit = -1; - if (filter.Args != null) - { - characterLimit = int.Parse(filter.Args); - } - - /* - if (query.ImdbID != null && TorznabCaps.SupportsImdbMovieSearch) - { - break; // skip andmatch filter for imdb searches - } - - if (query.TmdbID != null && TorznabCaps.SupportsTmdbMovieSearch) - { - break; // skip andmatch filter for tmdb searches - } - - if (query.TvdbID != null && TorznabCaps.SupportsTvdbSearch) - { - break; // skip andmatch filter for tvdb searches - } - - var queryKeywords = variables[".Keywords"] as string; - - if (!query.MatchQueryStringAND(release.Title, characterLimit, queryKeywords)) - { - _logger.Debug(string.Format("CardigannIndexer ({0}): skipping {1} (andmatch filter)", _definition.Id, release.Title)); - skipRelease = true; - } - */ - - break; - case "strdump": - // for debugging - _logger.Debug(string.Format("CardigannIndexer ({0}): row strdump: {1}", _definition.Id, row.ToHtmlPretty())); - break; - default: - _logger.Error(string.Format("CardigannIndexer ({0}): Unsupported rows filter: {1}", _definition.Id, filter.Name)); - break; - } - } - } - - if (skipRelease) - { - continue; - } - - // if DateHeaders is set go through the previous rows and look for the header selector - var dateHeaders = _definition.Search.Rows.Dateheaders; - if (release.PublishDate == DateTime.MinValue && dateHeaders != null) - { - var prevRow = row.PreviousElementSibling; - string value = null; - if (prevRow == null) - { - // continue with parent - var parent = row.ParentElement; - if (parent != null) - { - prevRow = parent.PreviousElementSibling; - } + throw new Exception(string.Format("Error while parsing field={0}, selector={1}, value={2}: {3}", field.Key, field.Value.Selector, value ?? "<null>", ex.Message)); } - while (prevRow != null) - { - var curRow = prevRow; - _logger.Debug(prevRow.OuterHtml); - try - { - value = HandleSelector(dateHeaders, curRow); - break; - } - catch (Exception) - { - // do nothing - } + var filters = search.Rows.Filters; + var skipRelease = ParseRowFilters(filters, release, variables, row); - prevRow = curRow.PreviousElementSibling; - if (prevRow == null) - { - // continue with parent - var parent = curRow.ParentElement; - if (parent != null) - { - prevRow = parent.PreviousElementSibling; - } - } - } - - if (value == null && dateHeaders.Optional == false) + if (skipRelease) { - throw new Exception(string.Format("No date header row found for {0}", release.ToString())); - } - - if (value != null) - { - release.PublishDate = DateTimeUtil.FromUnknown(value); + continue; } } releases.Add(release); } - catch (Exception ex) - { - _logger.Error(ex, "CardigannIndexer ({0}): Error while parsing row '{1}':\n\n{2}", _definition.Id, row.ToHtmlPretty()); - } } } - catch (Exception) + else { - // OnParseError(results, ex); - throw; + try + { + var searchResultParser = new HtmlParser(); + var searchResultDocument = searchResultParser.ParseDocument(results); + + /* checkForError(response, Definition.Search.Error); */ + + if (search.Preprocessingfilters != null) + { + results = ApplyFilters(results, search.Preprocessingfilters, variables); + searchResultDocument = searchResultParser.ParseDocument(results); + _logger.Trace(string.Format("CardigannIndexer ({0}): result after preprocessingfilters: {1}", _definition.Id, results)); + } + + var rowsSelector = ApplyGoTemplateText(search.Rows.Selector, variables); + var rowsDom = searchResultDocument.QuerySelectorAll(rowsSelector); + var rows = new List<IElement>(); + foreach (var rowDom in rowsDom) + { + rows.Add(rowDom); + } + + // merge following rows for After selector + var after = search.Rows.After; + if (after > 0) + { + for (var i = 0; i < rows.Count; i += 1) + { + var currentRow = rows[i]; + for (var j = 0; j < after; j += 1) + { + var mergeRowIndex = i + j + 1; + var mergeRow = rows[mergeRowIndex]; + var mergeNodes = new List<INode>(); + foreach (var node in mergeRow.ChildNodes) + { + mergeNodes.Add(node); + } + + currentRow.Append(mergeNodes.ToArray()); + } + + rows.RemoveRange(i + 1, after); + } + } + + foreach (var row in rows) + { + try + { + var release = new TorrentInfo(); + + // Parse fields + foreach (var field in search.Fields) + { + var fieldParts = field.Key.Split('|'); + var fieldName = fieldParts[0]; + var fieldModifiers = new List<string>(); + for (var i = 1; i < fieldParts.Length; i++) + { + fieldModifiers.Add(fieldParts[i]); + } + + string value = null; + var variablesKey = ".Result." + fieldName; + var isOptional = OptionalFields.Contains(field.Key) || fieldModifiers.Contains("optional") || field.Value.Optional; + try + { + value = HandleSelector(field.Value, row, variables, !isOptional); + + if (isOptional && string.IsNullOrWhiteSpace(value)) + { + variables[variablesKey] = null; + continue; + } + + variables[variablesKey] = ParseFields(value, fieldName, release, fieldModifiers, searchUrlUri); + } + catch (Exception ex) + { + if (!variables.ContainsKey(variablesKey)) + { + variables[variablesKey] = null; + } + + if (OptionalFields.Contains(field.Key) || fieldModifiers.Contains("optional") || field.Value.Optional) + { + variables[variablesKey] = null; + continue; + } + + if (indexerLogging) + { + _logger.Trace("Error while parsing field={0}, selector={1}, value={2}: {3}", field.Key, field.Value.Selector, value == null ? "<null>" : value, ex.Message); + } + } + } + + var filters = search.Rows.Filters; + var skipRelease = ParseRowFilters(filters, release, variables, row); + + if (skipRelease) + { + continue; + } + + // if DateHeaders is set go through the previous rows and look for the header selector + var dateHeaders = _definition.Search.Rows.Dateheaders; + if (release.PublishDate == DateTime.MinValue && dateHeaders != null) + { + var prevRow = row.PreviousElementSibling; + string value = null; + if (prevRow == null) + { + // continue with parent + var parent = row.ParentElement; + if (parent != null) + { + prevRow = parent.PreviousElementSibling; + } + } + + while (prevRow != null) + { + var curRow = prevRow; + _logger.Debug(prevRow.OuterHtml); + try + { + value = HandleSelector(dateHeaders, curRow); + break; + } + catch (Exception) + { + // do nothing + } + + prevRow = curRow.PreviousElementSibling; + if (prevRow == null) + { + // continue with parent + var parent = curRow.ParentElement; + if (parent != null) + { + prevRow = parent.PreviousElementSibling; + } + } + } + + if (value == null && dateHeaders.Optional == false) + { + throw new Exception(string.Format("No date header row found for {0}", release.ToString())); + } + + if (value != null) + { + release.PublishDate = DateTimeUtil.FromUnknown(value); + } + } + + releases.Add(release); + } + catch (Exception ex) + { + _logger.Error(ex, "CardigannIndexer ({0}): Error while parsing row '{1}':\n\n{2}", _definition.Id, row.ToHtmlPretty()); + } + } + } + catch (Exception) + { + // OnParseError(results, ex); + throw; + } } /* @@ -469,5 +341,234 @@ namespace NzbDrone.Core.Indexers.Cardigann return releases; } + + private string ParseFields(string value, string fieldName, TorrentInfo release, List<string> fieldModifiers, Uri searchUrlUri) + { + switch (fieldName) + { + case "download": + if (string.IsNullOrEmpty(value)) + { + value = null; + release.DownloadUrl = null; + break; + } + + if (value.StartsWith("magnet:")) + { + release.MagnetUrl = value; + value = release.MagnetUrl; + } + else + { + release.DownloadUrl = ResolvePath(value, searchUrlUri).AbsoluteUri; + value = release.DownloadUrl; + } + + break; + case "magnet": + var magnetUri = value; + release.MagnetUrl = magnetUri; + value = magnetUri.ToString(); + break; + case "infohash": + release.InfoHash = value; + break; + case "details": + var url = ResolvePath(value, searchUrlUri)?.AbsoluteUri; + release.InfoUrl = url; + release.Guid = url; + value = url.ToString(); + break; + case "comments": + var commentsUrl = ResolvePath(value, searchUrlUri); + if (release.CommentUrl == null) + { + release.CommentUrl = commentsUrl.AbsoluteUri; + } + + value = commentsUrl.ToString(); + break; + case "title": + if (fieldModifiers.Contains("append")) + { + release.Title += value; + } + else + { + release.Title = value; + } + + value = release.Title; + break; + case "description": + if (fieldModifiers.Contains("append")) + { + release.Description += value; + } + else + { + release.Description = value; + } + + value = release.Description; + break; + case "category": + var cats = MapTrackerCatToNewznab(value); + if (cats.Any()) + { + if (release.Categories == null || fieldModifiers.Contains("noappend")) + { + release.Categories = cats; + } + else + { + release.Categories = release.Categories.Union(cats).ToList(); + } + } + + value = release.Categories.ToString(); + break; + case "size": + release.Size = ParseUtil.GetBytes(value); + value = release.Size.ToString(); + break; + case "leechers": + var leechers = ParseUtil.CoerceLong(value); + leechers = leechers < 5000000L ? leechers : 0; // to fix #6558 + if (release.Peers == null) + { + release.Peers = (int)leechers; + } + else + { + release.Peers += (int)leechers; + } + + value = leechers.ToString(); + break; + case "seeders": + release.Seeders = ParseUtil.CoerceInt(value); + release.Seeders = release.Seeders < 5000000L ? release.Seeders : 0; // to fix #6558 + if (release.Peers == null) + { + release.Peers = release.Seeders; + } + else + { + release.Peers += release.Seeders; + } + + value = release.Seeders.ToString(); + break; + case "date": + release.PublishDate = DateTimeUtil.FromUnknown(value); + value = release.PublishDate.ToString(DateTimeUtil.Rfc1123ZPattern); + break; + case "files": + release.Files = ParseUtil.CoerceInt(value); + value = release.Files.ToString(); + break; + case "grabs": + release.Grabs = ParseUtil.CoerceInt(value); + value = release.Grabs.ToString(); + break; + case "downloadvolumefactor": + release.DownloadVolumeFactor = ParseUtil.CoerceDouble(value); + value = release.DownloadVolumeFactor.ToString(); + break; + case "uploadvolumefactor": + release.UploadVolumeFactor = ParseUtil.CoerceDouble(value); + value = release.UploadVolumeFactor.ToString(); + break; + case "minimumratio": + release.MinimumRatio = ParseUtil.CoerceDouble(value); + value = release.MinimumRatio.ToString(); + break; + case "minimumseedtime": + release.MinimumSeedTime = ParseUtil.CoerceLong(value); + value = release.MinimumSeedTime.ToString(); + break; + case "imdb": + release.ImdbId = (int)ParseUtil.GetLongFromString(value); + value = release.ImdbId.ToString(); + break; + case "tmdbid": + var tmdbIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); + var tmdbIDMatch = tmdbIDRegEx.Match(value); + var tmdbID = tmdbIDMatch.Groups[1].Value; + release.TmdbId = (int)ParseUtil.CoerceLong(tmdbID); + value = release.TmdbId.ToString(); + break; + case "rageid": + var rageIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); + var rageIDMatch = rageIDRegEx.Match(value); + var rageID = rageIDMatch.Groups[1].Value; + release.TvRageId = (int)ParseUtil.CoerceLong(rageID); + value = release.TvRageId.ToString(); + break; + case "tvdbid": + var tvdbIdRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); + var tvdbIdMatch = tvdbIdRegEx.Match(value); + var tvdbId = tvdbIdMatch.Groups[1].Value; + release.TvdbId = (int)ParseUtil.CoerceLong(tvdbId); + value = release.TvdbId.ToString(); + break; + case "poster": + if (!string.IsNullOrWhiteSpace(value)) + { + var poster = ResolvePath(value, searchUrlUri); + release.PosterUrl = poster.AbsoluteUri; + } + + value = release.PosterUrl; + break; + + //case "author": + // release.Author = value; + // break; + //case "booktitle": + // release.BookTitle = value; + // break; + default: + break; + } + + return value; + } + + private bool ParseRowFilters(List<FilterBlock> filters, ReleaseInfo release, Dictionary<string, object> variables, object row) + { + var skipRelease = false; + + if (filters != null) + { + foreach (var filter in filters) + { + switch (filter.Name) + { + case "andmatch": + var characterLimit = -1; + if (filter.Args != null) + { + characterLimit = int.Parse(filter.Args); + } + + var queryKeywords = variables[".Keywords"] as string; + + break; + case "strdump": + // for debugging + _logger.Debug(string.Format("CardigannIndexer ({0}): row strdump: {1}", _definition.Id, row.ToString())); + break; + default: + _logger.Error(string.Format("CardigannIndexer ({0}): Unsupported rows filter: {1}", _definition.Id, filter.Name)); + break; + } + } + } + + return skipRelease; + } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequest.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequest.cs index e9115cdc1..37a5c2149 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequest.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequest.cs @@ -6,17 +6,20 @@ namespace NzbDrone.Core.Indexers.Cardigann public class CardigannRequest : IndexerRequest { public Dictionary<string, object> Variables { get; private set; } + public SearchPathBlock SearchPath { get; private set; } - public CardigannRequest(string url, HttpAccept httpAccept, Dictionary<string, object> variables) + public CardigannRequest(string url, HttpAccept httpAccept, Dictionary<string, object> variables, SearchPathBlock searchPath) : base(url, httpAccept) { Variables = variables; + SearchPath = searchPath; } - public CardigannRequest(HttpRequest httpRequest, Dictionary<string, object> variables) + public CardigannRequest(HttpRequest httpRequest, Dictionary<string, object> variables, SearchPathBlock searchPath) : base(httpRequest) { Variables = variables; + SearchPath = searchPath; } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index b08755ca2..db85ca036 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -1067,7 +1067,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } } - var request = new CardigannRequest(requestbuilder.Build(), variables); + var request = new CardigannRequest(requestbuilder.Build(), variables, searchPath); // send HTTP request if (search.Headers != null) From 6200c9e496a8504769e8f8ef89c1908a7ec15aac Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 13 Nov 2021 17:37:44 -0600 Subject: [PATCH 0139/2320] New: (Cardigann) ImdbId and Description are optional --- .../Indexers/Definitions/Cardigann/CardigannBase.cs | 2 +- .../Indexers/Definitions/Cardigann/CardigannParser.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index d2b0b33cb..43a1353da 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.Indexers.Cardigann protected readonly List<CategoryMapping> _categoryMapping = new List<CategoryMapping>(); protected readonly List<string> _defaultCategories = new List<string>(); - protected readonly string[] OptionalFields = new string[] { "imdb", "rageid", "tvdbid", "banner" }; + protected readonly string[] OptionalFields = new string[] { "imdb", "imdbid", "rageid", "tvdbid", "banner", "description" }; protected static readonly string[] _SupportedLogicFunctions = { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index b59eb8f9e..f2ff99161 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -490,6 +490,7 @@ namespace NzbDrone.Core.Indexers.Cardigann value = release.MinimumSeedTime.ToString(); break; case "imdb": + case "imdbid": release.ImdbId = (int)ParseUtil.GetLongFromString(value); value = release.ImdbId.ToString(); break; From 1abd14ee865033cf62fd6700829335a80d9e42f6 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 13 Nov 2021 21:51:19 -0600 Subject: [PATCH 0140/2320] Allow Obsolete of C# Indexer Implementations --- .../HealthCheck/Checks/OutdatedDefinitionCheck.cs | 3 ++- .../IndexerDefinitionUpdateService.cs | 4 ---- src/NzbDrone.Core/Indexers/Definitions/Aither.cs | 2 ++ src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs | 2 ++ src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs | 2 ++ .../Indexers/Definitions/DesiTorrents.cs | 2 ++ .../Indexers/Definitions/DigitalCore.cs | 1 + .../Indexers/Definitions/InternetArchive.cs | 1 + src/NzbDrone.Core/Indexers/Definitions/Milkie.cs | 1 + .../Indexers/Definitions/ShareIsland.cs | 2 ++ src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs | 1 + .../Indexers/Definitions/ThePirateBay.cs | 1 + .../Indexers/Definitions/TorrentLeech.cs | 1 + .../Indexers/Definitions/TorrentParadiseMl.cs | 1 + src/NzbDrone.Core/Indexers/Definitions/YTS.cs | 1 + src/NzbDrone.Core/Indexers/IIndexer.cs | 1 + src/NzbDrone.Core/Indexers/IndexerBase.cs | 12 ++++++++++++ src/NzbDrone.Core/Indexers/IndexerFactory.cs | 5 +++++ src/NzbDrone.Core/ThingiProvider/IProvider.cs | 3 ++- 19 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs index f2e5bee0c..01f368951 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs @@ -27,7 +27,8 @@ namespace NzbDrone.Core.HealthCheck.Checks { var blocklist = _indexerDefinitionUpdateService.GetBlocklist(); - var oldIndexers = _indexerFactory.All().Where(i => i.Implementation == "Cardigann" && blocklist.Contains(((CardigannSettings)i.Settings).DefinitionFile)).ToList(); + var oldIndexers = _indexerFactory.AllProviders(false) + .Where(i => i.IsObsolete() || (i.Definition.Implementation == "Cardigann" && blocklist.Contains(((CardigannSettings)i.Definition.Settings).DefinitionFile))).ToList(); if (oldIndexers.Count == 0) { diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index 5941c3666..53c0249af 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -29,15 +29,11 @@ namespace NzbDrone.Core.IndexerVersions private const int DEFINITION_VERSION = 3; private readonly List<string> _defintionBlocklist = new List<string>() { - "aither", "animeworld", - "blutopia", "beyond-hd", "beyond-hd-oneurl", "danishbytes", - "desitorrents", "hdbits", - "shareisland", "lat-team" }; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Aither.cs b/src/NzbDrone.Core/Indexers/Definitions/Aither.cs index 1de88cea6..a3324507a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Aither.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Aither.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using NLog; using NzbDrone.Common.Http; @@ -7,6 +8,7 @@ using NzbDrone.Core.Messaging.Events; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete] public class Aither : Unit3dBase { public override string Name => "Aither"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs index 9a380fcf3..709a4b118 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using NLog; using NzbDrone.Common.Http; @@ -7,6 +8,7 @@ using NzbDrone.Core.Messaging.Events; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete] public class AnimeWorld : Unit3dBase { public override string Name => "AnimeWorld"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs b/src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs index 45302f0d9..c46c8e97d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using NLog; using NzbDrone.Common.Http; @@ -7,6 +8,7 @@ using NzbDrone.Core.Messaging.Events; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete] public class Blutopia : Unit3dBase { public override string Name => "Blutopia"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs index 8f0fe75a7..ed906e6dc 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using NLog; @@ -8,6 +9,7 @@ using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete] public class DesiTorrents : Unit3dBase { public override string Name => "DesiTorrents"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs b/src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs index 432946efb..12a26587a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs @@ -20,6 +20,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete] public class DigitalCore : TorrentIndexerBase<DigitalCoreSettings> { public override string Name => "DigitalCore"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs b/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs index 4ae3ada07..b5385f479 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs @@ -17,6 +17,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete] public class InternetArchive : TorrentIndexerBase<InternetArchiveSettings> { public override string Name => "Internet Archive"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Milkie.cs b/src/NzbDrone.Core/Indexers/Definitions/Milkie.cs index 6b465ca5a..d1baf4cc8 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Milkie.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Milkie.cs @@ -15,6 +15,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete] public class Milkie : TorrentIndexerBase<MilkieSettings> { public override string Name => "Milkie"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs b/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs index 76bc55ab3..9fbeae9fb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using NLog; using NzbDrone.Common.Http; @@ -7,6 +8,7 @@ using NzbDrone.Core.Messaging.Events; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete] public class ShareIsland : Unit3dBase { public override string Name => "ShareIsland"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs b/src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs index 4b433eea3..1ae39db67 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs @@ -18,6 +18,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete] public class SuperBits : TorrentIndexerBase<SuperBitsSettings> { public override string Name => "SuperBits"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs b/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs index a71a5da86..c88fb943c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs @@ -16,6 +16,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete] public class ThePirateBay : TorrentIndexerBase<ThePirateBaySettings> { public override string Name => "ThePirateBay"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs index aa47689d4..b4e256c5e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs @@ -20,6 +20,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete] public class TorrentLeech : TorrentIndexerBase<TorrentLeechSettings> { public override string Name => "TorrentLeech"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs index 1d7761bc9..7546ac313 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs @@ -18,6 +18,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete] public class TorrentParadiseMl : TorrentIndexerBase<TorrentParadiseMlSettings> { public override string Name => "TorrentParadiseMl"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/YTS.cs b/src/NzbDrone.Core/Indexers/Definitions/YTS.cs index 0716f85f5..530c976e1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/YTS.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/YTS.cs @@ -18,6 +18,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete] public class YTS : TorrentIndexerBase<YTSSettings> { public override string Name => "YTS"; diff --git a/src/NzbDrone.Core/Indexers/IIndexer.cs b/src/NzbDrone.Core/Indexers/IIndexer.cs index 4b4a7b783..1e02c896d 100644 --- a/src/NzbDrone.Core/Indexers/IIndexer.cs +++ b/src/NzbDrone.Core/Indexers/IIndexer.cs @@ -27,6 +27,7 @@ namespace NzbDrone.Core.Indexers Task<IndexerPageableQueryResult> Fetch(BasicSearchCriteria searchCriteria); Task<byte[]> Download(Uri link); + bool IsObsolete(); IndexerCapabilities GetCapabilities(); } diff --git a/src/NzbDrone.Core/Indexers/IndexerBase.cs b/src/NzbDrone.Core/Indexers/IndexerBase.cs index 2e10802a0..2e9f3058a 100644 --- a/src/NzbDrone.Core/Indexers/IndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/IndexerBase.cs @@ -45,6 +45,18 @@ namespace NzbDrone.Core.Indexers public Type ConfigContract => typeof(TSettings); + public bool IsObsolete() + { + var attributes = GetType().GetCustomAttributes(false); + + foreach (ObsoleteAttribute attribute in attributes.OfType<ObsoleteAttribute>()) + { + return true; + } + + return false; + } + public virtual ProviderMessage Message => null; public virtual IEnumerable<ProviderDefinition> DefaultDefinitions diff --git a/src/NzbDrone.Core/Indexers/IndexerFactory.cs b/src/NzbDrone.Core/Indexers/IndexerFactory.cs index 26f20a4e0..3b5c7bad2 100644 --- a/src/NzbDrone.Core/Indexers/IndexerFactory.cs +++ b/src/NzbDrone.Core/Indexers/IndexerFactory.cs @@ -147,6 +147,11 @@ namespace NzbDrone.Core.Indexers { foreach (var provider in _providers) { + if (provider.IsObsolete()) + { + continue; + } + var definitions = provider.DefaultDefinitions .Where(v => v.Name != null && (v.Name != typeof(Cardigann.Cardigann).Name || v.Name != typeof(Newznab.Newznab).Name || v.Name != typeof(Torznab.Torznab).Name)); diff --git a/src/NzbDrone.Core/ThingiProvider/IProvider.cs b/src/NzbDrone.Core/ThingiProvider/IProvider.cs index ea92d71cd..e40fb773d 100644 --- a/src/NzbDrone.Core/ThingiProvider/IProvider.cs +++ b/src/NzbDrone.Core/ThingiProvider/IProvider.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using FluentValidation.Results; @@ -11,6 +11,7 @@ namespace NzbDrone.Core.ThingiProvider ProviderMessage Message { get; } IEnumerable<ProviderDefinition> DefaultDefinitions { get; } ProviderDefinition Definition { get; set; } + ValidationResult Test(); object RequestAction(string stage, IDictionary<string, string> query); } From e94c8839f67aee8dcfd208493d8995d36a58094a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 13 Nov 2021 22:21:19 -0600 Subject: [PATCH 0141/2320] Fixed: (Cardigann) Raw search parameter failed to deserialize --- .../Indexers/Definitions/Cardigann/CardigannDefinition.cs | 2 +- src/NzbDrone.Core/Indexers/IndexerFactory.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs index 4c7f0f32f..602d0f662 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs @@ -71,7 +71,7 @@ namespace NzbDrone.Core.Indexers.Cardigann public Dictionary<string, string> Categories { get; set; } public List<CategorymappingBlock> Categorymappings { get; set; } public Dictionary<string, List<string>> Modes { get; set; } - public bool AllowRawSearch { get; set; } + public bool Allowrawsearch { get; set; } } public class CaptchaBlock diff --git a/src/NzbDrone.Core/Indexers/IndexerFactory.cs b/src/NzbDrone.Core/Indexers/IndexerFactory.cs index 3b5c7bad2..d23306583 100644 --- a/src/NzbDrone.Core/Indexers/IndexerFactory.cs +++ b/src/NzbDrone.Core/Indexers/IndexerFactory.cs @@ -97,7 +97,7 @@ namespace NzbDrone.Core.Indexers definition.Privacy = defFile.Type == "private" ? IndexerPrivacy.Private : IndexerPrivacy.Public; definition.Capabilities = new IndexerCapabilities(); definition.Capabilities.ParseCardigannSearchModes(defFile.Caps.Modes); - definition.Capabilities.SupportsRawSearch = defFile.Caps.AllowRawSearch; + definition.Capabilities.SupportsRawSearch = defFile.Caps.Allowrawsearch; MapCardigannCategories(definition, defFile); } From 9331d8e01359fde0e6853842db5c5664afc24a71 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 13 Nov 2021 23:47:35 -0600 Subject: [PATCH 0142/2320] Fixed: Parsing of 8 digit IMDb Ids --- src/NzbDrone.Core/Parser/ParseUtil.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Parser/ParseUtil.cs b/src/NzbDrone.Core/Parser/ParseUtil.cs index c157bf3dc..b6ba7b53b 100644 --- a/src/NzbDrone.Core/Parser/ParseUtil.cs +++ b/src/NzbDrone.Core/Parser/ParseUtil.cs @@ -93,7 +93,9 @@ namespace NzbDrone.Core.Parser return null; } - return "tt" + ((int)imdbid).ToString("D7"); + var imdbLen = ((int)imdbid > 9999999) ? "D8" : "D7"; + + return "tt" + ((int)imdbid).ToString(imdbLen); } public static string GetArgumentFromQueryString(string url, string argument) From 3e4ac89a4c22c1d7e9e9e03ed9211cff2ce40f64 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 14 Nov 2021 00:26:37 -0600 Subject: [PATCH 0143/2320] Fixed: (DanishBytes) Nullable error on TV Search Fixes #597 --- src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs index b17c12565..adf72a516 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs @@ -126,7 +126,7 @@ namespace NzbDrone.Core.Indexers.Definitions { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId, searchCriteria.TmdbId.GetValueOrDefault())); + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId, searchCriteria.TmdbId.GetValueOrDefault(0))); return pageableRequests; } @@ -144,7 +144,7 @@ namespace NzbDrone.Core.Indexers.Definitions { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId, 0, searchCriteria.TvdbId.Value)); + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId, 0, searchCriteria.TvdbId.GetValueOrDefault(0))); return pageableRequests; } From 0fb19160f4f5239285b2f407052d74f679dcc793 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 14 Nov 2021 00:28:19 -0600 Subject: [PATCH 0144/2320] Bump version to 0.1.3 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5651e4b7a..ab016901a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,7 +7,7 @@ variables: outputFolder: './_output' artifactsFolder: './_artifacts' testsFolder: './_tests' - majorVersion: '0.1.2' + majorVersion: '0.1.3' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From eccd72304c7b8224741145992e6407ed81818716 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 14 Nov 2021 00:32:19 -0600 Subject: [PATCH 0145/2320] Fixed: (NorBits) Set final login as POST prior to adding parameters Fixes #600 --- src/NzbDrone.Core/Indexers/Definitions/NorBits.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs b/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs index 3c314f396..2ab60205e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs @@ -78,7 +78,8 @@ namespace NzbDrone.Core.Indexers.Definitions var requestBuilder3 = new HttpRequestBuilder(string.Format("{0}/{1}", Settings.BaseUrl.TrimEnd('/'), "takelogin.php")) { LogResponseContent = true, - AllowAutoRedirect = true + AllowAutoRedirect = true, + Method = HttpMethod.POST }; var authLoginCheckRequest = requestBuilder3 @@ -88,8 +89,6 @@ namespace NzbDrone.Core.Indexers.Definitions .SetHeader("Referer", loginUrl) .Build(); - authLoginCheckRequest.Method = HttpMethod.POST; - var loginResponse = await ExecuteAuth(authLoginCheckRequest); if (!loginResponse.GetCookies().ContainsKey("uid")) From 1aa914986600e0a494f7752d2850cdc098887aa9 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Fri, 12 Nov 2021 13:38:23 -0600 Subject: [PATCH 0146/2320] Fixed: Orpheus failing to grab if token is not used Closes #592 --- .../Indexers/Definitions/Orpheus.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs index a0316a18b..6d68c8829 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using NLog; using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Gazelle; using NzbDrone.Core.Messaging.Events; namespace NzbDrone.Core.Indexers.Definitions @@ -50,5 +51,34 @@ namespace NzbDrone.Core.Indexers.Definitions return caps; } + + public override IParseIndexerResponse GetParser() + { + return new OrpheusParser(Settings, Capabilities); + } + } + + public class OrpheusParser : GazelleParser + { + public OrpheusParser(GazelleSettings settings, IndexerCapabilities capabilities) + : base(settings, capabilities) + { + } + + protected override string GetDownloadUrl(int torrentId) + { + var url = new HttpUri(_settings.BaseUrl) + .CombinePath("/torrents.php") + .AddQueryParam("action", "download") + .AddQueryParam("id", torrentId); + + // Orpheus fails to download if usetoken=0 so we need to only add if we will use one + if (_settings.UseFreeleechToken) + { + url.AddQueryParam("useToken", "1"); + } + + return url.FullUri; + } } } From 89a1b0f53454874d9453c10e53a1d7cd35dbce30 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 16 Nov 2021 13:36:10 -0600 Subject: [PATCH 0147/2320] Fixed: (Cardigann) Do not log config RSSKey or APIKey Fixed: (Cardigann) (v3) Pass APIKey as headers --- .../Indexers/Definitions/Cardigann/CardigannBase.cs | 4 ++-- .../Definitions/Cardigann/CardigannRequestGenerator.cs | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index 43a1353da..b7a4eb87c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -292,7 +292,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var name = ".Config." + setting.Name; var value = Settings.ExtraFieldData.GetValueOrDefault(setting.Name, setting.Default); - if (setting.Type != "password" && indexerLogging) + if ((setting.Type != "password" && setting.Name != "apikey" && setting.Name != "rsskey") && indexerLogging) { _logger.Trace($"{name} got value {value.ToJson()}"); } @@ -334,7 +334,7 @@ namespace NzbDrone.Core.Indexers.Cardigann throw new NotSupportedException(); } - if (setting.Type != "password" && indexerLogging) + if (setting.Type != "password" && setting.Name != "apikey" && setting.Name != "rsskey" && indexerLogging) { _logger.Debug($"Setting {setting.Name} to {variables[name]}"); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index db85ca036..a29f2cc9d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -1067,17 +1067,15 @@ namespace NzbDrone.Core.Indexers.Cardigann } } - var request = new CardigannRequest(requestbuilder.Build(), variables, searchPath); - // send HTTP request if (search.Headers != null) { - foreach (var header in search.Headers) - { - request.HttpRequest.Headers.Add(header.Key, header.Value[0]); - } + var headers = ParseCustomHeaders(search.Headers, variables); + requestbuilder.SetHeaders(headers ?? new Dictionary<string, string>()); } + var request = new CardigannRequest(requestbuilder.Build(), variables, searchPath); + yield return request; } } From 39fd9bea8943d068996c9e6dd29344daa3d7fcc8 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 16 Nov 2021 21:38:00 -0600 Subject: [PATCH 0148/2320] Fixed: (Cardigann) add headers from search block for all downloads based on jackett https://github.com/Jackett/Jackett/commit/c567f47ad100dac8d67fdbee0fcc3ff8ff29aa39 --- .../Definitions/Cardigann/CardigannRequestGenerator.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index a29f2cc9d..5bcbcd578 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -714,6 +714,7 @@ namespace NzbDrone.Core.Indexers.Cardigann { Cookies = GetCookies(); var method = HttpMethod.GET; + var headers = new Dictionary<string, string>(); if (_definition.Download != null) { @@ -722,7 +723,7 @@ namespace NzbDrone.Core.Indexers.Cardigann AddTemplateVariablesFromUri(variables, link, ".DownloadUri"); - var headers = ParseCustomHeaders(_definition.Search?.Headers, variables); + headers = ParseCustomHeaders(_definition.Search?.Headers, variables); HttpResponse response = null; var request = new HttpRequestBuilder(link.ToString()) @@ -753,8 +754,6 @@ namespace NzbDrone.Core.Indexers.Cardigann { try { - headers = ParseCustomHeaders(_definition.Search?.Headers, variables); - if (!download.Infohash.UseBeforeResponse || download.Before == null || response == null) { response = await HttpClient.ExecuteProxiedAsync(request, Definition); @@ -777,6 +776,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var hashDownloadRequest = new HttpRequestBuilder(torrentLink.AbsoluteUri) .SetCookies(Cookies ?? new Dictionary<string, string>()) + .SetHeaders(headers ?? new Dictionary<string, string>()) .Build(); hashDownloadRequest.Method = method; @@ -793,8 +793,6 @@ namespace NzbDrone.Core.Indexers.Cardigann } else if (download.Selectors != null) { - headers = ParseCustomHeaders(_definition.Search?.Headers, variables); - foreach (var selector in download.Selectors) { var queryselector = ApplyGoTemplateText(selector.Selector, variables); @@ -836,6 +834,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var selectorDownloadRequest = new HttpRequestBuilder(link.AbsoluteUri) .SetCookies(Cookies ?? new Dictionary<string, string>()) + .SetHeaders(headers ?? new Dictionary<string, string>()) .Build(); selectorDownloadRequest.Method = method; @@ -854,6 +853,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var downloadRequest = new HttpRequestBuilder(link.AbsoluteUri) .SetCookies(Cookies ?? new Dictionary<string, string>()) + .SetHeaders(headers ?? new Dictionary<string, string>()) .Build(); downloadRequest.Method = method; From 4a8131e00f875d5ef129f40caf01b0a20c2747e9 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 17 Nov 2021 20:31:12 -0600 Subject: [PATCH 0149/2320] Fixed: Cleanse APIKey from Newznab Response --- .../InstrumentationTests/CleanseLogMessageFixture.cs | 3 +++ src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs index 5ac5edda2..4fceb804c 100644 --- a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs +++ b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs @@ -34,6 +34,9 @@ namespace NzbDrone.Common.Test.InstrumentationTests [TestCase(@",""rsskey"":""2b51db35e1910123321025a12b9933d2"",")] [TestCase(@",""passkey"":""2b51db35e1910123321025a12b9933d2"",")] + // nzbgeek & usenet response + [TestCase(@"<guid isPermaLink=""true"">https://api.nzbgeek.info/api?t=details&id=2b51db35e1910123321025a12b9933d2&apikey=2b51db35e1910123321025a12b9933d2</guid>")] + // NzbGet [TestCase(@"{ ""Name"" : ""ControlUsername"", ""Value"" : ""mySecret"" }, { ""Name"" : ""ControlPassword"", ""Value"" : ""mySecret"" }, ")] [TestCase(@"{ ""Name"" : ""Server1.Username"", ""Value"" : ""mySecret"" }, { ""Name"" : ""Server1.Password"", ""Value"" : ""mySecret"" }, ")] diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index 5ead40baa..2a73e4d35 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -11,7 +11,7 @@ namespace NzbDrone.Common.Instrumentation private static readonly Regex[] CleansingRules = new[] { // Url - new Regex(@"(?<=[?&: ;])(apikey|token|pass(?:key|wd)?|auth|authkey|user|u?id|api|[a-z_]*apikey|account|pwd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"(?<=[?&: ;])(apikey|token|pass(?:key|wd)?|auth|authkey|user|u?id|api|[a-z_]*apikey|account|pwd)=(?<secret>[^&=]+?)(?= |&|$|<)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"(?<=[?& ])[^=]*?(_?(?<!use)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"rss\.torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"rss\.torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), From 701c7d349ab2928ba7ce5abd342cb8870300bf19 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 17 Nov 2021 21:01:17 -0600 Subject: [PATCH 0150/2320] New: (Cardigann) XML Parser Suppport --- .../Definitions/Cardigann/CardigannParser.cs | 40 ++++++++++++++----- src/NzbDrone.Core/Prowlarr.Core.csproj | 1 + 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index f2ff99161..bcf2bf5f2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -5,6 +5,7 @@ using System.Net; using System.Text.RegularExpressions; using AngleSharp.Dom; using AngleSharp.Html.Parser; +using AngleSharp.Xml.Parser; using Newtonsoft.Json.Linq; using NLog; using NzbDrone.Common.Extensions; @@ -159,20 +160,39 @@ namespace NzbDrone.Core.Indexers.Cardigann { try { - var searchResultParser = new HtmlParser(); - var searchResultDocument = searchResultParser.ParseDocument(results); + IHtmlCollection<IElement> rowsDom; - /* checkForError(response, Definition.Search.Error); */ - - if (search.Preprocessingfilters != null) + if (request.SearchPath.Response != null && request.SearchPath.Response.Type.Equals("xml")) { - results = ApplyFilters(results, search.Preprocessingfilters, variables); - searchResultDocument = searchResultParser.ParseDocument(results); - _logger.Trace(string.Format("CardigannIndexer ({0}): result after preprocessingfilters: {1}", _definition.Id, results)); + var searchResultParser = new XmlParser(); + var searchResultDocument = searchResultParser.ParseDocument(results); + + if (search.Preprocessingfilters != null) + { + results = ApplyFilters(results, search.Preprocessingfilters, variables); + searchResultDocument = searchResultParser.ParseDocument(results); + _logger.Trace(string.Format("CardigannIndexer ({0}): result after preprocessingfilters: {1}", _definition.Id, results)); + } + + var rowsSelector = ApplyGoTemplateText(search.Rows.Selector, variables); + rowsDom = searchResultDocument.QuerySelectorAll(rowsSelector); + } + else + { + var searchResultParser = new HtmlParser(); + var searchResultDocument = searchResultParser.ParseDocument(results); + + if (search.Preprocessingfilters != null) + { + results = ApplyFilters(results, search.Preprocessingfilters, variables); + searchResultDocument = searchResultParser.ParseDocument(results); + _logger.Trace(string.Format("CardigannIndexer ({0}): result after preprocessingfilters: {1}", _definition.Id, results)); + } + + var rowsSelector = ApplyGoTemplateText(search.Rows.Selector, variables); + rowsDom = searchResultDocument.QuerySelectorAll(rowsSelector); } - var rowsSelector = ApplyGoTemplateText(search.Rows.Selector, variables); - var rowsDom = searchResultDocument.QuerySelectorAll(rowsSelector); var rows = new List<IElement>(); foreach (var rowDom in rowsDom) { diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index e7ffefc34..ee0ffddc3 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -3,6 +3,7 @@ <TargetFrameworks>net5.0</TargetFrameworks> </PropertyGroup> <ItemGroup> + <PackageReference Include="AngleSharp.Xml" Version="0.16.0" /> <PackageReference Include="Dapper" Version="2.0.90" /> <PackageReference Include="FluentMigrator.Runner" Version="3.3.1" /> <PackageReference Include="MailKit" Version="2.14.0" /> From c263c6f365f6285789fbb7a19e9c3b3efe5d9d55 Mon Sep 17 00:00:00 2001 From: Servarr <32001786+ServarrAdmin@users.noreply.github.com> Date: Wed, 17 Nov 2021 22:36:45 -0500 Subject: [PATCH 0151/2320] Translations from Weblate --- src/NzbDrone.Core/Localization/Core/de.json | 20 +++++++++---------- .../Localization/Core/zh_CN.json | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/de.json b/src/NzbDrone.Core/Localization/Core/de.json index c0266e450..7e451b681 100644 --- a/src/NzbDrone.Core/Localization/Core/de.json +++ b/src/NzbDrone.Core/Localization/Core/de.json @@ -1,7 +1,7 @@ { "About": "Über", "All": "Alle", - "Analytics": "Statistiken", + "Analytics": "Analytik", "AppDataLocationHealthCheckMessage": "Ein Update ist nicht möglich, um das Löschen von AppData beim Update zu verhindern", "Backup": "Backups", "BackupNow": "Jetzt sichern", @@ -89,7 +89,7 @@ "EventType": "Event Typ", "DownloadClient": "Downloader", "Details": "Details", - "ConnectSettingsSummary": "Benachrichtigungen, Verbindungen zu Medien Server/Clients und benutzerdefinierte Scripte", + "ConnectSettingsSummary": "Benachrichtigungen und eigene Scripte", "Added": "Hinzugefügt", "Actions": "Aktionen", "Warn": "Warnung", @@ -149,12 +149,12 @@ "ApplyTags": "Tags setzen", "Authentication": "Authentifizierung", "Automatic": "Automatisch", - "BackupIntervalHelpText": "Intervall zwischen automatischen Backups", + "BackupIntervalHelpText": "Intervall zum sichern der Datenbank und Einstellungen", "BackupRetentionHelpText": "Automatische Backups, die älter als die Aufbewahrungsfrist sind, werden automatisch gelöscht", "Backups": "Backups", - "BindAddress": "Bindungsadresse", + "BindAddress": "Adresse binden", "BindAddressHelpText": "Gültige IPv4 Adresse oder \"*\" für alle Netzwerke", - "Branch": "Branch", + "Branch": "Git-Branch", "BypassProxyForLocalAddresses": "Proxy für lokale Adressen umgehen", "CertificateValidation": "Zertifikat Validierung", "CertificateValidationHelpText": "Ändere wie streng die Validierung der HTTPS-Zertifizierung ist", @@ -170,7 +170,7 @@ "Enable": "Aktivieren", "EnableAutomaticAdd": "Automatisch hinzufügen", "EnableAutomaticSearch": "Automatisch suchen", - "EnableColorImpairedMode": "Farbbeeinträchtigter Modus", + "EnableColorImpairedMode": "Farbbeeinträchtigter Modus aktivieren", "EnableCompletedDownloadHandlingHelpText": "Importiere fertige Downloads vom Downloader automatisch", "EnabledHelpText": "Aktiviere diese Liste", "EnableHelpText": "Metadaten Dateien erstellen für diesen Metadata Typ", @@ -243,7 +243,7 @@ "Username": "Benutzername", "Version": "Version", "YesCancel": "Ja, abbrechen", - "EnableColorImpairedModeHelpText": "Alternativer Style, um farbbeeinträchtigten Benutzern eine bessere Unterscheidung farbcodierter Informationen zu ermöglichen", + "EnableColorImpairedModeHelpText": "Alternativer Stil, um farbbeeinträchtigten Benutzern eine bessere Unterscheidung farbcodierter Informationen zu ermöglichen", "EnableMediaInfoHelpText": "Videoinformationen wie Auflösung, Laufzeit und Codec aus Datien erkennen. Dazu ist es erforderlich, dass Prowlarr Teile der Datei liest, was zu hoher Festplatten- oder Netzwerkaktivität während der Scans führen kann.", "NoMinimumForAnyRuntime": "Kein Minimum für Laufzeiten", "AnalyticsEnabledHelpText": "Sende anonyme Nutzungs- und Fehlerinformationen an die Server von Prowlarr. Dazu gehören Informationen über Browser, welche Seiten der Prowlarr-Weboberfläche aufgerufen wurden, Fehlerberichte sowie Betriebssystem- und Laufzeitversion. Wir werden diese Informationen verwenden, um Funktionen und Fehlerbehebungen zu priorisieren.", @@ -258,7 +258,7 @@ "LaunchBrowserHelpText": " Öffne die Startseite von Prowlarr im Webbrowser nach dem Start.", "ReadTheWikiForMoreInformation": "Lese das Wiki für mehr Informationen", "BackupFolderHelpText": "Relative Pfade befinden sich unter Prowlarrs AppData Ordner", - "DelayProfile": "Verzögerungs Profil", + "DelayProfile": "Verzögerungsprofil", "MaximumLimits": "Maximale Grenzen", "DeleteNotification": "Benachrichtigung löschen", "CloneIndexer": "Indexer kopieren", @@ -286,7 +286,7 @@ "DeleteDownloadClientMessageText": "Downloader '{0}' wirklich löschen?", "DeleteBackupMessageText": "Backup '{0}' wirkich löschen?", "CancelPendingTask": "Diese laufende Aufgabe wirklich abbrechen?", - "BranchUpdateMechanism": "Branch für den externen Updateablauf", + "BranchUpdateMechanism": "Git-Branch für den externen Updateablauf", "BranchUpdate": "Verwendeter Branch zur Aktualisierung von Prowlarr", "BeforeUpdate": "Vor dem Update", "AddingTag": "Tag hinzufügen", @@ -317,7 +317,7 @@ "ApplyTagsHelpTexts4": "Ersetzen: Nur eingegebene Tags übernehmen und vorhandene entfernen( keine Tags eingeben um alle zu entfernen )", "ApplyTagsHelpTexts3": "Entfernen: Eingegebene Tags entfernen", "ApplyTagsHelpTexts2": "Hinzufügen: Füge neu Tags zu den existierenden Tags hinzu", - "ApplyTagsHelpTexts1": "Wie werden Tags zu ausgewählten Filmen zugeteilt", + "ApplyTagsHelpTexts1": "Wie werden Tags zu ausgewählten Indexern zugeteilt", "UILanguageHelpTextWarning": "Webseite muss neu geladen werden", "UILanguageHelpText": "Sprache für die gesamte Oberfläche", "UILanguage": "Oberflächen Sprache ( UI Language )", diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index 5574a5dc9..d34964835 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -60,8 +60,8 @@ "IndexerPriorityHelpText": "搜刮器优先级从1(最高)到50(最低),默认25。", "IndexerPriority": "搜刮器优先级", "IndexerObsoleteCheckMessage": "搜刮器已过弃用或已更新:{0}。请将其删除和(或)重新添加到 Prowlarr", - "IndexerLongTermStatusCheckSingleClientMessage": "所有搜刮器由于故障都已不可用6小时:{0}", - "IndexerLongTermStatusCheckAllClientMessage": "所有搜刮器由于故障都已不可用6小时", + "IndexerLongTermStatusCheckSingleClientMessage": "由于故障6小时,下列搜刮器都已不可用:{0}", + "IndexerLongTermStatusCheckAllClientMessage": "由于故障超过6小时,所有搜刮器均不可用", "IndexerHealthCheckNoIndexers": "未启用任何搜刮器,Prowlarr将不会返回搜索结果", "IndexerFlags": "搜刮器标记", "IndexerAuth": "搜刮器认证", @@ -282,7 +282,7 @@ "IndexerProxyStatusCheckAllClientMessage": "所有搜刮器都因错误不可用", "SettingsShowRelativeDates": "显示相对日期", "SettingsShowRelativeDatesHelpText": "显示相对日期(今天昨天等)或绝对日期", - "Source": "源代码", + "Source": "源路径", "SSLCertPasswordHelpText": "pfx文件密码", "TagCannotBeDeletedWhileInUse": "使用中无法删除", "TagIsNotUsedAndCanBeDeleted": "标签未被使用,可删除", From cb7cbb74e0417d9d53906c3b3e467e762db96996 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 17 Nov 2021 21:59:15 -0600 Subject: [PATCH 0152/2320] New: Build on Net6 --- .editorconfig | 2 +- azure-pipelines.yml | 44 +++++----- build.sh | 34 +++---- package.json | 2 +- src/Directory.Build.props | 4 +- .../Prowlarr.Automation.Test.csproj | 2 +- .../Http/HttpClientFixture.cs | 2 +- .../Prowlarr.Common.Test.csproj | 2 +- .../EnvironmentInfo/RuntimeInfo.cs | 2 +- .../Extensions/IEnumerableExtensions.cs | 7 -- src/NzbDrone.Common/Prowlarr.Common.csproj | 8 +- src/NzbDrone.Console/Prowlarr.Console.csproj | 2 +- .../Prowlarr.Core.Test.csproj | 2 +- .../Datastore/Converters/CookieConverter.cs | 5 +- .../Converters/EmbeddedDocumentConverter.cs | 2 +- src/NzbDrone.Core/Hashing.cs | 4 +- .../Indexers/Definitions/ZonaQ.cs | 2 +- .../Messaging/Commands/CommandExecutor.cs | 1 - src/NzbDrone.Core/Parser/StringUtil.cs | 3 +- src/NzbDrone.Core/Prowlarr.Core.csproj | 6 +- .../ThingiProvider/ProviderRepository.cs | 2 +- .../Prowlarr.Host.Test.csproj | 2 +- src/NzbDrone.Host/Prowlarr.Host.csproj | 6 +- .../Prowlarr.Integration.Test.csproj | 4 +- .../Prowlarr.Libraries.Test.csproj | 2 +- .../Prowlarr.Mono.Test.csproj | 2 +- src/NzbDrone.Mono/Prowlarr.Mono.csproj | 2 +- src/NzbDrone.SignalR/Prowlarr.SignalR.csproj | 2 +- src/NzbDrone.Test.Common/NzbDroneRunner.cs | 2 +- .../Prowlarr.Test.Common.csproj | 2 +- .../Prowlarr.Test.Dummy.csproj | 2 +- .../Prowlarr.Update.Test.csproj | 2 +- src/NzbDrone.Update/Prowlarr.Update.csproj | 2 +- .../Prowlarr.Windows.Test.csproj | 2 +- src/NzbDrone.Windows/Prowlarr.Windows.csproj | 2 +- src/NzbDrone/Prowlarr.csproj | 4 +- .../Prowlarr.Api.V1.Test.csproj | 2 +- src/Prowlarr.Api.V1/ProviderControllerBase.cs | 3 +- src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj | 2 +- src/Prowlarr.Http/Prowlarr.Http.csproj | 2 +- .../ServiceInstall/ServiceInstall.csproj | 2 +- .../ServiceUninstall/ServiceUninstall.csproj | 2 +- yarn.lock | 88 ++++++++++--------- 43 files changed, 139 insertions(+), 138 deletions(-) diff --git a/.editorconfig b/.editorconfig index 39fecc26b..e324f2b01 100644 --- a/.editorconfig +++ b/.editorconfig @@ -260,7 +260,7 @@ dotnet_diagnostic.CA5392.severity = suggestion dotnet_diagnostic.CA5394.severity = suggestion dotnet_diagnostic.CA5397.severity = suggestion - +dotnet_diagnostic.SYSLIB0014.severity = none [*.{js,html,js,hbs,less,css}] charset = utf-8 diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ab016901a..dc92b9dc3 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -13,7 +13,7 @@ variables: buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' sentryOrg: 'servarr' sentryUrl: 'https://sentry.servarr.com' - dotnetVersion: '5.0.400' + dotnetVersion: '6.0.100' yarnCacheFolder: $(Pipeline.Workspace)/.yarn trigger: @@ -111,23 +111,23 @@ stages: artifact: '$(osName)Backend' displayName: Publish Backend condition: and(succeeded(), eq(variables['osName'], 'Windows')) - - publish: '$(testsFolder)/net5.0/win-x64/publish' + - publish: '$(testsFolder)/net6.0/win-x64/publish' artifact: WindowsCoreTests displayName: Publish Windows Test Package condition: and(succeeded(), eq(variables['osName'], 'Windows')) - - publish: '$(testsFolder)/net5.0/linux-x64/publish' + - publish: '$(testsFolder)/net6.0/linux-x64/publish' artifact: LinuxCoreTests displayName: Publish Linux Test Package condition: and(succeeded(), eq(variables['osName'], 'Windows')) - - publish: '$(testsFolder)/net5.0/linux-musl-x64/publish' + - publish: '$(testsFolder)/net6.0/linux-musl-x64/publish' artifact: LinuxMuslCoreTests displayName: Publish Linux Musl Test Package condition: and(succeeded(), eq(variables['osName'], 'Windows')) - - publish: '$(testsFolder)/net5.0/freebsd-x64/publish' + - publish: '$(testsFolder)/net6.0/freebsd-x64/publish' artifact: FreebsdCoreTests displayName: Publish FreeBSD Test Package condition: and(succeeded(), eq(variables['osName'], 'Windows')) - - publish: '$(testsFolder)/net5.0/osx-x64/publish' + - publish: '$(testsFolder)/net6.0/osx-x64/publish' artifact: MacCoreTests displayName: Publish MacOS Test Package condition: and(succeeded(), eq(variables['osName'], 'Windows')) @@ -203,12 +203,12 @@ stages: - bash: ./build.sh --packages displayName: Create Packages - bash: | - distribution/windows/setup/inno/ISCC.exe distribution/windows/setup/prowlarr.iss //DFramework=net5.0 //DRuntime=win-x86 - cp distribution/windows/setup/output/Prowlarr.*windows.net5.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Prowlarr.${BUILDNAME}.windows-core-x86-installer.exe + distribution/windows/setup/inno/ISCC.exe distribution/windows/setup/prowlarr.iss //DFramework=net6.0 //DRuntime=win-x86 + cp distribution/windows/setup/output/Prowlarr.*windows.net6.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Prowlarr.${BUILDNAME}.windows-core-x86-installer.exe displayName: Create x86 .NET Core Windows installer - bash: | - distribution/windows/setup/inno/ISCC.exe distribution/windows/setup/prowlarr.iss //DFramework=net5.0 //DRuntime=win-x64 - cp distribution/windows/setup/output/Prowlarr.*windows.net5.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Prowlarr.${BUILDNAME}.windows-core-x64-installer.exe + distribution/windows/setup/inno/ISCC.exe distribution/windows/setup/prowlarr.iss //DFramework=net6.0 //DRuntime=win-x64 + cp distribution/windows/setup/output/Prowlarr.*windows.net6.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Prowlarr.${BUILDNAME}.windows-core-x64-installer.exe displayName: Create x64 .NET Core Windows installer - publish: $(Build.ArtifactStagingDirectory) artifact: 'WindowsInstaller' @@ -250,21 +250,21 @@ stages: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).windows-core-x64.zip' archiveType: 'zip' includeRootFolder: false - rootFolderOrFile: $(artifactsFolder)/win-x64/net5.0 + rootFolderOrFile: $(artifactsFolder)/win-x64/net6.0 - task: ArchiveFiles@2 displayName: Create Windows x86 Core zip inputs: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).windows-core-x86.zip' archiveType: 'zip' includeRootFolder: false - rootFolderOrFile: $(artifactsFolder)/win-x86/net5.0 + rootFolderOrFile: $(artifactsFolder)/win-x86/net6.0 - task: ArchiveFiles@2 displayName: Create MacOS Core app inputs: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).osx-app-core-x64.zip' archiveType: 'zip' includeRootFolder: false - rootFolderOrFile: $(artifactsFolder)/macos-app/net5.0 + rootFolderOrFile: $(artifactsFolder)/macos-app/net6.0 - task: ArchiveFiles@2 displayName: Create MacOS Core tar inputs: @@ -272,7 +272,7 @@ stages: archiveType: 'tar' tarCompression: 'gz' includeRootFolder: false - rootFolderOrFile: $(artifactsFolder)/macos/net5.0 + rootFolderOrFile: $(artifactsFolder)/macos/net6.0 - task: ArchiveFiles@2 displayName: Create Linux Core tar inputs: @@ -280,7 +280,7 @@ stages: archiveType: 'tar' tarCompression: 'gz' includeRootFolder: false - rootFolderOrFile: $(artifactsFolder)/linux-x64/net5.0 + rootFolderOrFile: $(artifactsFolder)/linux-x64/net6.0 - task: ArchiveFiles@2 displayName: Create Linux Musl Core tar inputs: @@ -288,7 +288,7 @@ stages: archiveType: 'tar' tarCompression: 'gz' includeRootFolder: false - rootFolderOrFile: $(artifactsFolder)/linux-musl-x64/net5.0 + rootFolderOrFile: $(artifactsFolder)/linux-musl-x64/net6.0 - task: ArchiveFiles@2 displayName: Create ARM32 Linux Core tar inputs: @@ -296,7 +296,7 @@ stages: archiveType: 'tar' tarCompression: 'gz' includeRootFolder: false - rootFolderOrFile: $(artifactsFolder)/linux-arm/net5.0 + rootFolderOrFile: $(artifactsFolder)/linux-arm/net6.0 - task: ArchiveFiles@2 displayName: Create ARM64 Linux Core tar inputs: @@ -304,7 +304,7 @@ stages: archiveType: 'tar' tarCompression: 'gz' includeRootFolder: false - rootFolderOrFile: $(artifactsFolder)/linux-arm64/net5.0 + rootFolderOrFile: $(artifactsFolder)/linux-arm64/net6.0 - task: ArchiveFiles@2 displayName: Create ARM64 Linux Musl Core tar inputs: @@ -312,7 +312,7 @@ stages: archiveType: 'tar' tarCompression: 'gz' includeRootFolder: false - rootFolderOrFile: $(artifactsFolder)/linux-musl-arm64/net5.0 + rootFolderOrFile: $(artifactsFolder)/linux-musl-arm64/net6.0 - task: ArchiveFiles@2 displayName: Create FreeBSD Core Core tar inputs: @@ -320,7 +320,7 @@ stages: archiveType: 'tar' tarCompression: 'gz' includeRootFolder: false - rootFolderOrFile: $(artifactsFolder)/freebsd-x64/net5.0 + rootFolderOrFile: $(artifactsFolder)/freebsd-x64/net6.0 - publish: $(Build.ArtifactStagingDirectory) artifact: 'Packages' displayName: Publish Packages @@ -838,8 +838,8 @@ stages: sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml sonar.cs.nunit.reportsPaths=$(Build.SourcesDirectory)/TestResult.xml - bash: | - ./build.sh --backend -f net5.0 -r win-x64 - TEST_DIR=_tests/net5.0/win-x64/publish/ ./test.sh Windows Unit Coverage + ./build.sh --backend -f net6.0 -r win-x64 + TEST_DIR=_tests/net6.0/win-x64/publish/ ./test.sh Windows Unit Coverage displayName: Coverage Unit Tests - task: SonarCloudAnalyze@1 condition: eq(variables['System.PullRequest.IsFork'], 'False') diff --git a/build.sh b/build.sh index 056f9e30c..d606e558d 100755 --- a/build.sh +++ b/build.sh @@ -130,7 +130,7 @@ PackageLinux() echo "Adding Prowlarr.Mono to UpdatePackage" cp $folder/Prowlarr.Mono.* $folder/Prowlarr.Update - if [ "$framework" = "net5.0" ]; then + if [ "$framework" = "net6.0" ]; then cp $folder/Mono.Posix.NETStandard.* $folder/Prowlarr.Update cp $folder/libMonoPosixHelper.* $folder/Prowlarr.Update fi @@ -157,7 +157,7 @@ PackageMacOS() echo "Adding Prowlarr.Mono to UpdatePackage" cp $folder/Prowlarr.Mono.* $folder/Prowlarr.Update - if [ "$framework" = "net5.0" ]; then + if [ "$framework" = "net6.0" ]; then cp $folder/Mono.Posix.NETStandard.* $folder/Prowlarr.Update cp $folder/libMonoPosixHelper.* $folder/Prowlarr.Update fi @@ -327,14 +327,14 @@ then Build if [[ -z "$RID" || -z "$FRAMEWORK" ]]; then - PackageTests "net5.0" "win-x64" - PackageTests "net5.0" "win-x86" - PackageTests "net5.0" "linux-x64" - PackageTests "net5.0" "linux-musl-x64" - PackageTests "net5.0" "osx-x64" + PackageTests "net6.0" "win-x64" + PackageTests "net6.0" "win-x86" + PackageTests "net6.0" "linux-x64" + PackageTests "net6.0" "linux-musl-x64" + PackageTests "net6.0" "osx-x64" if [ "$ENABLE_BSD" = "YES" ]; then - PackageTests "net5.0" "freebsd-x64" + PackageTests "net6.0" "freebsd-x64" fi else PackageTests "$FRAMEWORK" "$RID" @@ -363,17 +363,17 @@ then if [[ -z "$RID" || -z "$FRAMEWORK" ]]; then - Package "net5.0" "win-x64" - Package "net5.0" "win-x86" - Package "net5.0" "linux-x64" - Package "net5.0" "linux-musl-x64" - Package "net5.0" "linux-arm64" - Package "net5.0" "linux-musl-arm64" - Package "net5.0" "linux-arm" - Package "net5.0" "osx-x64" + Package "net6.0" "win-x64" + Package "net6.0" "win-x86" + Package "net6.0" "linux-x64" + Package "net6.0" "linux-musl-x64" + Package "net6.0" "linux-arm64" + Package "net6.0" "linux-musl-arm64" + Package "net6.0" "linux-arm" + Package "net6.0" "osx-x64" if [ "$ENABLE_BSD" = "YES" ]; then - Package "net5.0" "freebsd-x64" + Package "net6.0" "freebsd-x64" fi else Package "$FRAMEWORK" "$RID" diff --git a/package.json b/package.json index cbfa48c71..366d76dc4 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "@fortawesome/free-regular-svg-icons": "5.15.3", "@fortawesome/free-solid-svg-icons": "5.15.3", "@fortawesome/react-fontawesome": "0.1.14", - "@microsoft/signalr": "5.0.9", + "@microsoft/signalr": "6.0.0", "@sentry/browser": "6.10.0", "@sentry/integrations": "6.10.0", "chart.js": "3.2.0", diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 78a356827..04b080c03 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,7 +2,7 @@ <!-- Common to all Prowlarr Projects --> <PropertyGroup> <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - + <ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles> <PlatformTarget>AnyCPU</PlatformTarget> <TargetLatestRuntimePatch>true</TargetLatestRuntimePatch> <RuntimeIdentifiers>win-x64;win-x86;osx-x64;linux-x64;linux-musl-x64;linux-arm;linux-arm64;linux-musl-arm64</RuntimeIdentifiers> @@ -94,7 +94,7 @@ <!-- Standard testing packages --> <ItemGroup Condition="'$(TestProject)'=='true'"> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> <PackageReference Include="NUnit" Version="3.13.1" /> <PackageReference Include="NUnit3TestAdapter" Version="3.17.0" /> <PackageReference Include="NunitXml.TestLogger" Version="3.0.97" /> diff --git a/src/NzbDrone.Automation.Test/Prowlarr.Automation.Test.csproj b/src/NzbDrone.Automation.Test/Prowlarr.Automation.Test.csproj index 82fd1bda6..fcaa91554 100644 --- a/src/NzbDrone.Automation.Test/Prowlarr.Automation.Test.csproj +++ b/src/NzbDrone.Automation.Test/Prowlarr.Automation.Test.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <PackageReference Include="Selenium.Support" Version="3.141.0" /> diff --git a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs index 8a9d96997..f0e84583d 100644 --- a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs +++ b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs @@ -728,7 +728,7 @@ namespace NzbDrone.Common.Test.Http { try { - string url = $"https://{_httpBinHost}/response-headers?Set-Cookie={Uri.EscapeUriString(malformedCookie)}"; + string url = $"https://{_httpBinHost}/response-headers?Set-Cookie={Uri.EscapeDataString(malformedCookie)}"; var requestSet = new HttpRequest(url); requestSet.AllowAutoRedirect = false; diff --git a/src/NzbDrone.Common.Test/Prowlarr.Common.Test.csproj b/src/NzbDrone.Common.Test/Prowlarr.Common.Test.csproj index b32888b74..0bf15596a 100644 --- a/src/NzbDrone.Common.Test/Prowlarr.Common.Test.csproj +++ b/src/NzbDrone.Common.Test/Prowlarr.Common.Test.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Host\Prowlarr.Host.csproj" /> diff --git a/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs index acf844abd..b5467c2e9 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs @@ -23,7 +23,7 @@ namespace NzbDrone.Common.EnvironmentInfo serviceProvider.ServiceExist(ServiceProvider.SERVICE_NAME) && serviceProvider.GetStatus(ServiceProvider.SERVICE_NAME) == ServiceControllerStatus.StartPending; - // net5.0 will return Radarr.dll for entry assembly, we need the actual + // net6.0 will return Radarr.dll for entry assembly, we need the actual // executable name (Radarr on linux). On mono this will return the location of // the mono executable itself, which is not what we want. var entry = Process.GetCurrentProcess().MainModule; diff --git a/src/NzbDrone.Common/Extensions/IEnumerableExtensions.cs b/src/NzbDrone.Common/Extensions/IEnumerableExtensions.cs index ef687a922..d18e58e51 100644 --- a/src/NzbDrone.Common/Extensions/IEnumerableExtensions.cs +++ b/src/NzbDrone.Common/Extensions/IEnumerableExtensions.cs @@ -6,13 +6,6 @@ namespace NzbDrone.Common.Extensions { public static class EnumerableExtensions { - public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) - { - var knownKeys = new HashSet<TKey>(); - - return source.Where(element => knownKeys.Add(keySelector(element))); - } - public static IEnumerable<TFirst> IntersectBy<TFirst, TSecond, TKey>(this IEnumerable<TFirst> first, Func<TFirst, TKey> firstKeySelector, IEnumerable<TSecond> second, diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index 6156b1fd9..f3cb5557f 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -1,12 +1,12 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> <DefineConstants Condition="'$(RuntimeIdentifier)' == 'linux-musl-x64' or '$(RuntimeIdentifier)' == 'linux-musl-arm64'">ISMUSL</DefineConstants> </PropertyGroup> <ItemGroup> <PackageReference Include="DotNet4.SocksProxy" Version="1.4.0.1" /> <PackageReference Include="DryIoc.dll" Version="4.8.1" /> - <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.2" /> + <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" /> <PackageReference Include="NLog.Extensions.Logging" Version="1.7.2" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="NLog" Version="4.7.9" /> @@ -14,10 +14,10 @@ <PackageReference Include="SharpZipLib" Version="1.3.1" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.113.0-0" /> - <PackageReference Include="System.Configuration.ConfigurationManager" Version="5.0.0" /> + <PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" /> <PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" /> <PackageReference Include="System.Runtime.Loader" Version="4.3.0" /> - <PackageReference Include="System.ServiceProcess.ServiceController" Version="5.0.0" /> + <PackageReference Include="System.ServiceProcess.ServiceController" Version="6.0.0" /> <PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" /> </ItemGroup> <ItemGroup> diff --git a/src/NzbDrone.Console/Prowlarr.Console.csproj b/src/NzbDrone.Console/Prowlarr.Console.csproj index 16f42bea3..bbfa0a0fa 100644 --- a/src/NzbDrone.Console/Prowlarr.Console.csproj +++ b/src/NzbDrone.Console/Prowlarr.Console.csproj @@ -1,7 +1,7 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> <ApplicationIcon>..\NzbDrone.Host\Prowlarr.ico</ApplicationIcon> <ApplicationManifest>app.manifest</ApplicationManifest> diff --git a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj index 49557c26d..9b2fb1692 100644 --- a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <PackageReference Include="Dapper" Version="2.0.90" /> diff --git a/src/NzbDrone.Core/Datastore/Converters/CookieConverter.cs b/src/NzbDrone.Core/Datastore/Converters/CookieConverter.cs index f62038f12..484ca108e 100644 --- a/src/NzbDrone.Core/Datastore/Converters/CookieConverter.cs +++ b/src/NzbDrone.Core/Datastore/Converters/CookieConverter.cs @@ -1,6 +1,7 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Data; using System.Text.Json; +using System.Text.Json.Serialization; using Dapper; using NzbDrone.Common.Serializer; @@ -15,7 +16,7 @@ namespace NzbDrone.Core.Datastore.Converters var serializerSettings = new JsonSerializerOptions { AllowTrailingCommas = true, - IgnoreNullValues = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, PropertyNameCaseInsensitive = true, WriteIndented = true }; diff --git a/src/NzbDrone.Core/Datastore/Converters/EmbeddedDocumentConverter.cs b/src/NzbDrone.Core/Datastore/Converters/EmbeddedDocumentConverter.cs index 8acf352e8..e56eb0566 100644 --- a/src/NzbDrone.Core/Datastore/Converters/EmbeddedDocumentConverter.cs +++ b/src/NzbDrone.Core/Datastore/Converters/EmbeddedDocumentConverter.cs @@ -15,7 +15,7 @@ namespace NzbDrone.Core.Datastore.Converters var serializerSettings = new JsonSerializerOptions { AllowTrailingCommas = true, - IgnoreNullValues = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, PropertyNameCaseInsensitive = true, DictionaryKeyPolicy = JsonNamingPolicy.CamelCase, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, diff --git a/src/NzbDrone.Core/Hashing.cs b/src/NzbDrone.Core/Hashing.cs index 531de210d..761255a6e 100644 --- a/src/NzbDrone.Core/Hashing.cs +++ b/src/NzbDrone.Core/Hashing.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Core { public static string SHA256Hash(this string input) { - using (var hash = SHA256Managed.Create()) + using (var hash = SHA256.Create()) { var enc = Encoding.UTF8; return GetHash(hash.ComputeHash(enc.GetBytes(input))); @@ -17,7 +17,7 @@ namespace NzbDrone.Core public static string SHA256Hash(this Stream input) { - using (var hash = SHA256Managed.Create()) + using (var hash = SHA256.Create()) { return GetHash(hash.ComputeHash(input)); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs b/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs index 328ca8aef..6e1233841 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs @@ -139,7 +139,7 @@ namespace NzbDrone.Core.Indexers.Definitions private static string Sha1Hash(string input) { - var hash = new SHA1Managed().ComputeHash(Encoding.UTF8.GetBytes(input)); + var hash = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(input)); return string.Concat(hash.Select(b => b.ToString("x2"))); } diff --git a/src/NzbDrone.Core/Messaging/Commands/CommandExecutor.cs b/src/NzbDrone.Core/Messaging/Commands/CommandExecutor.cs index c725316dc..05b031a6a 100644 --- a/src/NzbDrone.Core/Messaging/Commands/CommandExecutor.cs +++ b/src/NzbDrone.Core/Messaging/Commands/CommandExecutor.cs @@ -52,7 +52,6 @@ namespace NzbDrone.Core.Messaging.Commands catch (ThreadAbortException ex) { _logger.Error(ex, "Thread aborted"); - Thread.ResetAbort(); } catch (OperationCanceledException) { diff --git a/src/NzbDrone.Core/Parser/StringUtil.cs b/src/NzbDrone.Core/Parser/StringUtil.cs index 634bc4313..d52e7456d 100644 --- a/src/NzbDrone.Core/Parser/StringUtil.cs +++ b/src/NzbDrone.Core/Parser/StringUtil.cs @@ -242,7 +242,8 @@ namespace NzbDrone.Core.Parser { var chars = "abcdefghijklmnopqrstuvwxyz0123456789"; var randBytes = new byte[length]; - using (var rngCsp = new RNGCryptoServiceProvider()) + + using (var rngCsp = RandomNumberGenerator.Create()) { rngCsp.GetBytes(randBytes); var key = ""; diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index ee0ffddc3..2e43ae263 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <PackageReference Include="AngleSharp.Xml" Version="0.16.0" /> @@ -10,7 +10,7 @@ <PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" /> <PackageReference Include="NLog.Targets.Syslog" Version="6.0.2" /> <PackageReference Include="System.Memory" Version="4.5.4" /> - <PackageReference Include="System.ServiceModel.Syndication" Version="5.0.0" /> + <PackageReference Include="System.ServiceModel.Syndication" Version="6.0.0" /> <PackageReference Include="FluentMigrator.Runner.SQLite" Version="3.3.1" /> <PackageReference Include="FluentValidation" Version="8.6.2" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> @@ -18,7 +18,7 @@ <PackageReference Include="TinyTwitter" Version="1.1.2" /> <PackageReference Include="Kveer.XmlRPC" Version="1.1.1" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.113.0-0" /> - <PackageReference Include="System.Text.Json" Version="5.0.2" /> + <PackageReference Include="System.Text.Json" Version="6.0.0" /> <PackageReference Include="MonoTorrent" Version="1.0.29" /> <PackageReference Include="YamlDotNet" Version="11.2.1" /> <PackageReference Include="AngleSharp" Version="0.16.0" /> diff --git a/src/NzbDrone.Core/ThingiProvider/ProviderRepository.cs b/src/NzbDrone.Core/ThingiProvider/ProviderRepository.cs index 3de882618..50797e8df 100644 --- a/src/NzbDrone.Core/ThingiProvider/ProviderRepository.cs +++ b/src/NzbDrone.Core/ThingiProvider/ProviderRepository.cs @@ -21,7 +21,7 @@ namespace NzbDrone.Core.ThingiProvider var serializerSettings = new JsonSerializerOptions { AllowTrailingCommas = true, - IgnoreNullValues = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, PropertyNameCaseInsensitive = true, DictionaryKeyPolicy = JsonNamingPolicy.CamelCase, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, diff --git a/src/NzbDrone.Host.Test/Prowlarr.Host.Test.csproj b/src/NzbDrone.Host.Test/Prowlarr.Host.Test.csproj index 12f52273c..6e9231a1a 100644 --- a/src/NzbDrone.Host.Test/Prowlarr.Host.Test.csproj +++ b/src/NzbDrone.Host.Test/Prowlarr.Host.Test.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Host\Prowlarr.Host.csproj" /> diff --git a/src/NzbDrone.Host/Prowlarr.Host.csproj b/src/NzbDrone.Host/Prowlarr.Host.csproj index edddca01b..204117551 100644 --- a/src/NzbDrone.Host/Prowlarr.Host.csproj +++ b/src/NzbDrone.Host/Prowlarr.Host.csproj @@ -1,12 +1,12 @@ <Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> <OutputType>Library</OutputType> </PropertyGroup> <ItemGroup> <PackageReference Include="NLog.Extensions.Logging" Version="1.7.2" /> - <PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" /> - <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="5.0.1" /> + <PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" /> + <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> <PackageReference Include="DryIoc.dll" Version="4.8.1" /> <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="5.1.0" /> </ItemGroup> diff --git a/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj b/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj index 02846b5c8..ea2df08de 100644 --- a/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj +++ b/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj @@ -1,10 +1,10 @@ <Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> <OutputType>Library</OutputType> </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="5.0.9" /> + <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.0" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" /> diff --git a/src/NzbDrone.Libraries.Test/Prowlarr.Libraries.Test.csproj b/src/NzbDrone.Libraries.Test/Prowlarr.Libraries.Test.csproj index 4d86db6e1..e905dd74d 100644 --- a/src/NzbDrone.Libraries.Test/Prowlarr.Libraries.Test.csproj +++ b/src/NzbDrone.Libraries.Test/Prowlarr.Libraries.Test.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" /> diff --git a/src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj b/src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj index 476de6309..7f5fa8645 100644 --- a/src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj +++ b/src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <PackageReference Include="Mono.Posix.NETStandard" Version="5.20.1-servarr1" /> diff --git a/src/NzbDrone.Mono/Prowlarr.Mono.csproj b/src/NzbDrone.Mono/Prowlarr.Mono.csproj index bb883bc5c..fddefed59 100644 --- a/src/NzbDrone.Mono/Prowlarr.Mono.csproj +++ b/src/NzbDrone.Mono/Prowlarr.Mono.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <PackageReference Include="Mono.Posix.NETStandard" Version="5.20.1-servarr1" /> diff --git a/src/NzbDrone.SignalR/Prowlarr.SignalR.csproj b/src/NzbDrone.SignalR/Prowlarr.SignalR.csproj index 316e17154..b33b66994 100644 --- a/src/NzbDrone.SignalR/Prowlarr.SignalR.csproj +++ b/src/NzbDrone.SignalR/Prowlarr.SignalR.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> <OutputType>Library</OutputType> </PropertyGroup> <ItemGroup> diff --git a/src/NzbDrone.Test.Common/NzbDroneRunner.cs b/src/NzbDrone.Test.Common/NzbDroneRunner.cs index 30135f975..0a7251fc9 100644 --- a/src/NzbDrone.Test.Common/NzbDroneRunner.cs +++ b/src/NzbDrone.Test.Common/NzbDroneRunner.cs @@ -55,7 +55,7 @@ namespace NzbDrone.Test.Common if (BuildInfo.IsDebug) { - var frameworkFolder = "net5.0"; + var frameworkFolder = "net6.0"; Start(Path.Combine(TestContext.CurrentContext.TestDirectory, "..", "..", "_output", frameworkFolder, consoleExe)); } else diff --git a/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj b/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj index c09d17dc4..bff730d28 100644 --- a/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj +++ b/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <PackageReference Include="FluentAssertions" Version="5.10.3" /> diff --git a/src/NzbDrone.Test.Dummy/Prowlarr.Test.Dummy.csproj b/src/NzbDrone.Test.Dummy/Prowlarr.Test.Dummy.csproj index 244fa2aeb..1ead72088 100644 --- a/src/NzbDrone.Test.Dummy/Prowlarr.Test.Dummy.csproj +++ b/src/NzbDrone.Test.Dummy/Prowlarr.Test.Dummy.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> </Project> \ No newline at end of file diff --git a/src/NzbDrone.Update.Test/Prowlarr.Update.Test.csproj b/src/NzbDrone.Update.Test/Prowlarr.Update.Test.csproj index 3ba4a7e16..448d0869e 100644 --- a/src/NzbDrone.Update.Test/Prowlarr.Update.Test.csproj +++ b/src/NzbDrone.Update.Test/Prowlarr.Update.Test.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" /> diff --git a/src/NzbDrone.Update/Prowlarr.Update.csproj b/src/NzbDrone.Update/Prowlarr.Update.csproj index a103670ce..aebe9ea33 100644 --- a/src/NzbDrone.Update/Prowlarr.Update.csproj +++ b/src/NzbDrone.Update/Prowlarr.Update.csproj @@ -1,7 +1,7 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>WinExe</OutputType> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <PackageReference Include="DryIoc.dll" Version="4.8.1" /> diff --git a/src/NzbDrone.Windows.Test/Prowlarr.Windows.Test.csproj b/src/NzbDrone.Windows.Test/Prowlarr.Windows.Test.csproj index 8be630814..632293b92 100644 --- a/src/NzbDrone.Windows.Test/Prowlarr.Windows.Test.csproj +++ b/src/NzbDrone.Windows.Test/Prowlarr.Windows.Test.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Common.Test\Prowlarr.Common.Test.csproj" /> diff --git a/src/NzbDrone.Windows/Prowlarr.Windows.csproj b/src/NzbDrone.Windows/Prowlarr.Windows.csproj index 96dc93eec..449211184 100644 --- a/src/NzbDrone.Windows/Prowlarr.Windows.csproj +++ b/src/NzbDrone.Windows/Prowlarr.Windows.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <PackageReference Include="NLog" Version="4.7.9" /> diff --git a/src/NzbDrone/Prowlarr.csproj b/src/NzbDrone/Prowlarr.csproj index 67d609f0b..3f990da36 100644 --- a/src/NzbDrone/Prowlarr.csproj +++ b/src/NzbDrone/Prowlarr.csproj @@ -1,7 +1,7 @@ <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> <PropertyGroup> <OutputType>WinExe</OutputType> - <TargetFrameworks>net5.0-windows</TargetFrameworks> + <TargetFrameworks>net6.0-windows</TargetFrameworks> <RuntimeIdentifiers>win-x64;win-x86</RuntimeIdentifiers> <UseWindowsForms>true</UseWindowsForms> <ApplicationIcon>..\NzbDrone.Host\Prowlarr.ico</ApplicationIcon> @@ -9,7 +9,7 @@ <GenerateResourceUsePreserializedResources>true</GenerateResourceUsePreserializedResources> </PropertyGroup> <ItemGroup> - <PackageReference Include="System.Resources.Extensions" Version="5.0.0" /> + <PackageReference Include="System.Resources.Extensions" Version="6.0.0" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Host\Prowlarr.Host.csproj" /> diff --git a/src/Prowlarr.Api.V1.Test/Prowlarr.Api.V1.Test.csproj b/src/Prowlarr.Api.V1.Test/Prowlarr.Api.V1.Test.csproj index 5d72e6996..0c72fa8ca 100644 --- a/src/Prowlarr.Api.V1.Test/Prowlarr.Api.V1.Test.csproj +++ b/src/Prowlarr.Api.V1.Test/Prowlarr.Api.V1.Test.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <PackageReference Include="NBuilder" Version="6.1.0" /> diff --git a/src/Prowlarr.Api.V1/ProviderControllerBase.cs b/src/Prowlarr.Api.V1/ProviderControllerBase.cs index d57d3f50e..4784421db 100644 --- a/src/Prowlarr.Api.V1/ProviderControllerBase.cs +++ b/src/Prowlarr.Api.V1/ProviderControllerBase.cs @@ -102,10 +102,9 @@ namespace Prowlarr.Api.V1 } [RestDeleteById] - public object DeleteProvider(int id) + public void DeleteProvider(int id) { _providerFactory.Delete(id); - return new object(); } [HttpGet("schema")] diff --git a/src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj b/src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj index 40230a47f..df70ed8b9 100644 --- a/src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj +++ b/src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <PackageReference Include="FluentValidation" Version="8.6.2" /> diff --git a/src/Prowlarr.Http/Prowlarr.Http.csproj b/src/Prowlarr.Http/Prowlarr.Http.csproj index 0922a89d0..a7d87cb78 100644 --- a/src/Prowlarr.Http/Prowlarr.Http.csproj +++ b/src/Prowlarr.Http/Prowlarr.Http.csproj @@ -1,6 +1,6 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <PackageReference Include="FluentValidation" Version="8.6.2" /> diff --git a/src/ServiceHelpers/ServiceInstall/ServiceInstall.csproj b/src/ServiceHelpers/ServiceInstall/ServiceInstall.csproj index cfe8281cc..21e3125e0 100644 --- a/src/ServiceHelpers/ServiceInstall/ServiceInstall.csproj +++ b/src/ServiceHelpers/ServiceInstall/ServiceInstall.csproj @@ -1,7 +1,7 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>WinExe</OutputType> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" /> diff --git a/src/ServiceHelpers/ServiceUninstall/ServiceUninstall.csproj b/src/ServiceHelpers/ServiceUninstall/ServiceUninstall.csproj index cfe8281cc..21e3125e0 100644 --- a/src/ServiceHelpers/ServiceUninstall/ServiceUninstall.csproj +++ b/src/ServiceHelpers/ServiceUninstall/ServiceUninstall.csproj @@ -1,7 +1,7 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>WinExe</OutputType> - <TargetFrameworks>net5.0</TargetFrameworks> + <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> <PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" /> diff --git a/yarn.lock b/yarn.lock index e416d2c54..2d43abb17 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1095,16 +1095,16 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== -"@microsoft/signalr@5.0.9": - version "5.0.9" - resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-5.0.9.tgz#cff2b0a091298049fd012e7b6cd015a814f8698d" - integrity sha512-pQufk3+mChfystnmYpglyRYQFp+036QmOxbZUFr2cFf2iiS8ekBX5uVBOG8OexKcsG4TcJNAU/ref90Y9+3ZiA== +"@microsoft/signalr@6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-6.0.0.tgz#cb9cb166d8ee0522547e13c100a0992a1f027ce1" + integrity sha512-Y38bG/i9V1fOfOLcfTl2+OqPH7+0A7DgojJ7YILgfQ0vGGmnZwdCtrzCvSsRIzKTIrB/ZSQ3n4BA5VOO+MFkrA== dependencies: abort-controller "^3.0.0" eventsource "^1.0.7" - fetch-cookie "^0.7.3" - node-fetch "^2.6.0" - ws "^6.0.0" + fetch-cookie "^0.11.0" + node-fetch "^2.6.1" + ws "^7.4.5" "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" @@ -1826,11 +1826,6 @@ astral-regex@^2.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - async@^2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" @@ -2885,11 +2880,6 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -es6-denodeify@^0.1.1: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-denodeify/-/es6-denodeify-0.1.5.tgz#31d4d5fe9c5503e125460439310e16a2a3f39c1f" - integrity sha1-MdTV/pxVA+ElRgQ5MQ4WoqPznB8= - es6-promise@^4.0.3, es6-promise@^4.2.8: version "4.2.8" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" @@ -3309,13 +3299,12 @@ fb-watchman@^2.0.0, fb-watchman@^2.0.1: dependencies: bser "2.1.1" -fetch-cookie@^0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.7.3.tgz#b8d023f421dd2b2f4a0eca9cd7318a967ed4eed8" - integrity sha512-rZPkLnI8x5V+zYAiz8QonAHsTb4BY+iFowFBI1RFn0zrO343AVp9X7/yUj/9wL6Ef/8fLls8b/vGtzUvmyAUGA== +fetch-cookie@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.11.0.tgz#e046d2abadd0ded5804ce7e2cae06d4331c15407" + integrity sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA== dependencies: - es6-denodeify "^0.1.1" - tough-cookie "^2.3.3" + tough-cookie "^2.3.3 || ^3.0.1 || ^4.0.0" file-entry-cache@^6.0.1: version "6.0.1" @@ -4877,10 +4866,12 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" -node-fetch@^2.6.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== +node-fetch@^2.6.1: + version "2.6.6" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89" + integrity sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA== + dependencies: + whatwg-url "^5.0.0" node-int64@^0.4.0: version "0.4.0" @@ -5619,7 +5610,7 @@ prop-types@15.7.2, prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.5.4, object-assign "^4.1.1" react-is "^16.8.1" -psl@^1.1.28: +psl@^1.1.33: version "1.8.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== @@ -6999,13 +6990,19 @@ to-space-case@^1.0.0: dependencies: to-no-case "^1.0.0" -tough-cookie@^2.3.3: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== +"tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== dependencies: - psl "^1.1.28" + psl "^1.1.33" punycode "^2.1.1" + universalify "^0.1.2" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= trim-newlines@^3.0.0: version "3.0.1" @@ -7150,6 +7147,11 @@ unist-util-stringify-position@^2.0.0: dependencies: "@types/unist" "^2.0.2" +universalify@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + universalify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" @@ -7283,6 +7285,11 @@ watchpack@^2.0.0: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + webpack-cli@4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.6.0.tgz#27ae86bfaec0cf393fcfd58abdc5a229ad32fd16" @@ -7380,6 +7387,14 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" @@ -7439,13 +7454,6 @@ write-file-atomic@^3.0.3: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" - integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== - dependencies: - async-limiter "~1.0.0" - ws@^7.4.5: version "7.5.3" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74" From c35e257a82dcacdc282124d1fd7d8fefc7cba61f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 17 Nov 2021 22:10:59 -0600 Subject: [PATCH 0153/2320] New: Add osx-arm64 and linux-musl-arm builds --- azure-pipelines.yml | 31 ++++++++++++++++--- build.sh | 20 +++++++----- src/Directory.Build.props | 2 +- src/NzbDrone.Common/Prowlarr.Common.csproj | 2 +- .../Prowlarr.Core.Test.csproj | 2 +- src/NzbDrone.Core/Prowlarr.Core.csproj | 2 +- .../Prowlarr.Mono.Test.csproj | 2 +- src/NzbDrone.Mono/Prowlarr.Mono.csproj | 2 +- 8 files changed, 45 insertions(+), 18 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index dc92b9dc3..f2a62a6cb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -259,20 +259,35 @@ stages: includeRootFolder: false rootFolderOrFile: $(artifactsFolder)/win-x86/net6.0 - task: ArchiveFiles@2 - displayName: Create MacOS Core app + displayName: Create MacOS x64 Core app inputs: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).osx-app-core-x64.zip' archiveType: 'zip' includeRootFolder: false - rootFolderOrFile: $(artifactsFolder)/macos-app/net6.0 + rootFolderOrFile: $(artifactsFolder)/osx-x64-app/net6.0 - task: ArchiveFiles@2 - displayName: Create MacOS Core tar + displayName: Create MacOS x64 Core tar inputs: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).osx-core-x64.tar.gz' archiveType: 'tar' tarCompression: 'gz' includeRootFolder: false - rootFolderOrFile: $(artifactsFolder)/macos/net6.0 + rootFolderOrFile: $(artifactsFolder)/osx-x64/net6.0 + - task: ArchiveFiles@2 + displayName: Create MacOS arm64 Core app + inputs: + archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).osx-app-core-arm64.zip' + archiveType: 'zip' + includeRootFolder: false + rootFolderOrFile: $(artifactsFolder)/osx-arm64-app/net6.0 + - task: ArchiveFiles@2 + displayName: Create MacOS arm64 Core tar + inputs: + archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).osx-core-arm64.tar.gz' + archiveType: 'tar' + tarCompression: 'gz' + includeRootFolder: false + rootFolderOrFile: $(artifactsFolder)/osx-arm64/net6.0 - task: ArchiveFiles@2 displayName: Create Linux Core tar inputs: @@ -297,6 +312,14 @@ stages: tarCompression: 'gz' includeRootFolder: false rootFolderOrFile: $(artifactsFolder)/linux-arm/net6.0 + - task: ArchiveFiles@2 + displayName: Create ARM32 Linux Musl Core tar + inputs: + archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).linux-musl-core-arm.tar.gz' + archiveType: 'tar' + tarCompression: 'gz' + includeRootFolder: false + rootFolderOrFile: $(artifactsFolder)/linux-musl-arm/net6.0 - task: ArchiveFiles@2 displayName: Create ARM64 Linux Core tar inputs: diff --git a/build.sh b/build.sh index d606e558d..1e31e7dd1 100755 --- a/build.sh +++ b/build.sh @@ -141,12 +141,13 @@ PackageLinux() PackageMacOS() { local framework="$1" + local runtime="$2" - ProgressStart "Creating MacOS Package for $framework" + ProgressStart "Creating MacOS Package for $framework $runtime" - local folder=$artifactsFolder/macos/$framework/Prowlarr + local folder=$artifactsFolder/$runtime/$framework/Prowlarr - PackageFiles "$folder" "$framework" "osx-x64" + PackageFiles "$folder" "$framework" "$runtime" echo "Removing Service helpers" rm -f $folder/ServiceUninstall.* @@ -168,10 +169,11 @@ PackageMacOS() PackageMacOSApp() { local framework="$1" + local runtime="$2" - ProgressStart "Creating macOS App Package for $framework" + ProgressStart "Creating macOS App Package for $framework $runtime" - local folder=$artifactsFolder/macos-app/$framework + local folder="$artifactsFolder/$runtime-app/$framework" rm -rf $folder mkdir -p $folder @@ -179,7 +181,7 @@ PackageMacOSApp() mkdir -p $folder/Prowlarr.app/Contents/MacOS echo "Copying Binaries" - cp -r $artifactsFolder/macos/$framework/Prowlarr/* $folder/Prowlarr.app/Contents/MacOS + cp -r $artifactsFolder/$runtime/$framework/Prowlarr/* $folder/Prowlarr.app/Contents/MacOS echo "Removing Update Folder" rm -r $folder/Prowlarr.app/Contents/MacOS/Prowlarr.Update @@ -226,8 +228,8 @@ Package() PackageWindows "$framework" "$runtime" ;; osx) - PackageMacOS "$framework" - PackageMacOSApp "$framework" + PackageMacOS "$framework" "$runtime" + PackageMacOSApp "$framework" "$runtime" ;; esac } @@ -370,7 +372,9 @@ then Package "net6.0" "linux-arm64" Package "net6.0" "linux-musl-arm64" Package "net6.0" "linux-arm" + Package "net6.0" "linux-musl-arm" Package "net6.0" "osx-x64" + Package "net6.0" "osx-arm64" if [ "$ENABLE_BSD" = "YES" ]; then Package "net6.0" "freebsd-x64" diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 04b080c03..88e435bda 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -5,7 +5,7 @@ <ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles> <PlatformTarget>AnyCPU</PlatformTarget> <TargetLatestRuntimePatch>true</TargetLatestRuntimePatch> - <RuntimeIdentifiers>win-x64;win-x86;osx-x64;linux-x64;linux-musl-x64;linux-arm;linux-arm64;linux-musl-arm64</RuntimeIdentifiers> + <RuntimeIdentifiers>win-x64;win-x86;osx-x64;osx-arm64;linux-x64;linux-musl-x64;linux-musl-arm;linux-arm;linux-arm64;linux-musl-arm64</RuntimeIdentifiers> <ProwlarrRootDir>$(MSBuildThisFileDirectory)..\</ProwlarrRootDir> diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index f3cb5557f..87080ea74 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -13,7 +13,7 @@ <PackageReference Include="Sentry" Version="3.8.3" /> <PackageReference Include="SharpZipLib" Version="1.3.1" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" /> - <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.113.0-0" /> + <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-12" /> <PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" /> <PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" /> <PackageReference Include="System.Runtime.Loader" Version="4.3.0" /> diff --git a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj index 9b2fb1692..a53ccde77 100644 --- a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj @@ -5,7 +5,7 @@ <ItemGroup> <PackageReference Include="Dapper" Version="2.0.90" /> <PackageReference Include="NBuilder" Version="6.1.0" /> - <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.113.0-0" /> + <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-12" /> <PackageReference Include="YamlDotNet" Version="11.2.1" /> </ItemGroup> <ItemGroup> diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index 2e43ae263..a71c71fbb 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -17,7 +17,7 @@ <PackageReference Include="NLog" Version="4.7.9" /> <PackageReference Include="TinyTwitter" Version="1.1.2" /> <PackageReference Include="Kveer.XmlRPC" Version="1.1.1" /> - <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.113.0-0" /> + <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-12" /> <PackageReference Include="System.Text.Json" Version="6.0.0" /> <PackageReference Include="MonoTorrent" Version="1.0.29" /> <PackageReference Include="YamlDotNet" Version="11.2.1" /> diff --git a/src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj b/src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj index 7f5fa8645..3ca751434 100644 --- a/src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj +++ b/src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj @@ -3,7 +3,7 @@ <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> - <PackageReference Include="Mono.Posix.NETStandard" Version="5.20.1-servarr1" /> + <PackageReference Include="Mono.Posix.NETStandard" Version="5.20.1.34-servarr17" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Common.Test\Prowlarr.Common.Test.csproj" /> diff --git a/src/NzbDrone.Mono/Prowlarr.Mono.csproj b/src/NzbDrone.Mono/Prowlarr.Mono.csproj index fddefed59..0c7cb60ec 100644 --- a/src/NzbDrone.Mono/Prowlarr.Mono.csproj +++ b/src/NzbDrone.Mono/Prowlarr.Mono.csproj @@ -3,7 +3,7 @@ <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> - <PackageReference Include="Mono.Posix.NETStandard" Version="5.20.1-servarr1" /> + <PackageReference Include="Mono.Posix.NETStandard" Version="5.20.1.34-servarr17" /> <PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" /> </ItemGroup> <ItemGroup> From f5cb81951ac2ab8d654fc3d9a6665b6b6c7ee31f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 17 Nov 2021 22:33:39 -0600 Subject: [PATCH 0154/2320] New: Use native .NET socks proxy --- .../Http/Proxy/ManagedWebProxyFactory.cs | 71 +++++++------------ src/NzbDrone.Common/Prowlarr.Common.csproj | 1 - .../IndexerProxies/Socks4/Socks4.cs | 42 +++-------- .../IndexerProxies/Socks5/Socks5.cs | 42 +++-------- 4 files changed, 47 insertions(+), 109 deletions(-) diff --git a/src/NzbDrone.Common/Http/Proxy/ManagedWebProxyFactory.cs b/src/NzbDrone.Common/Http/Proxy/ManagedWebProxyFactory.cs index ca58fedee..7a972d84f 100644 --- a/src/NzbDrone.Common/Http/Proxy/ManagedWebProxyFactory.cs +++ b/src/NzbDrone.Common/Http/Proxy/ManagedWebProxyFactory.cs @@ -1,9 +1,5 @@ -using System; -using System.Linq; +using System; using System.Net; -using System.Net.Sockets; -using com.LandonKey.SocksWebProxy; -using com.LandonKey.SocksWebProxy.Proxy; using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; @@ -33,54 +29,37 @@ namespace NzbDrone.Common.Http.Proxy } private IWebProxy CreateWebProxy(HttpProxySettings proxySettings) + { + var uri = GetProxyUri(proxySettings); + + if (uri == null) + { + return null; + } + + if (proxySettings.Username.IsNotNullOrWhiteSpace() && proxySettings.Password.IsNotNullOrWhiteSpace()) + { + return new WebProxy(uri, proxySettings.BypassLocalAddress, proxySettings.BypassListAsArray, new NetworkCredential(proxySettings.Username, proxySettings.Password)); + } + else + { + return new WebProxy(uri, proxySettings.BypassLocalAddress, proxySettings.BypassListAsArray); + } + } + + private Uri GetProxyUri(HttpProxySettings proxySettings) { switch (proxySettings.Type) { case ProxyType.Http: - if (proxySettings.Username.IsNotNullOrWhiteSpace() && proxySettings.Password.IsNotNullOrWhiteSpace()) - { - return new WebProxy(proxySettings.Host + ":" + proxySettings.Port, proxySettings.BypassLocalAddress, proxySettings.BypassListAsArray, new NetworkCredential(proxySettings.Username, proxySettings.Password)); - } - else - { - return new WebProxy(proxySettings.Host + ":" + proxySettings.Port, proxySettings.BypassLocalAddress, proxySettings.BypassListAsArray); - } - + return new Uri("http://" + proxySettings.Host + ":" + proxySettings.Port); case ProxyType.Socks4: - return new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(proxySettings.Host), proxySettings.Port, ProxyConfig.SocksVersion.Four, proxySettings.Username, proxySettings.Password), false); + return new Uri("socks4://" + proxySettings.Host + ":" + proxySettings.Port); case ProxyType.Socks5: - return new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(proxySettings.Host), proxySettings.Port, ProxyConfig.SocksVersion.Five, proxySettings.Username, proxySettings.Password), false); + return new Uri("socks5://" + proxySettings.Host + ":" + proxySettings.Port); + default: + return null; } - - return null; - } - - private static IPAddress GetProxyIpAddress(string host) - { - IPAddress ipAddress; - if (!IPAddress.TryParse(host, out ipAddress)) - { - try - { - ipAddress = Dns.GetHostEntry(host).AddressList.OrderByDescending(a => a.AddressFamily == AddressFamily.InterNetwork).First(); - } - catch (Exception e) - { - throw new InvalidOperationException(string.Format("Unable to resolve proxy hostname '{0}' to a valid IP address.", host), e); - } - } - - return ipAddress; - } - - private static int GetNextFreePort() - { - var listener = new TcpListener(IPAddress.Loopback, 0); - listener.Start(); - var port = ((IPEndPoint)listener.LocalEndpoint).Port; - listener.Stop(); - - return port; } } } diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index 87080ea74..ea03b36c4 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -4,7 +4,6 @@ <DefineConstants Condition="'$(RuntimeIdentifier)' == 'linux-musl-x64' or '$(RuntimeIdentifier)' == 'linux-musl-arm64'">ISMUSL</DefineConstants> </PropertyGroup> <ItemGroup> - <PackageReference Include="DotNet4.SocksProxy" Version="1.4.0.1" /> <PackageReference Include="DryIoc.dll" Version="4.8.1" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" /> <PackageReference Include="NLog.Extensions.Logging" Version="1.7.2" /> diff --git a/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs b/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs index 54177a917..9fccb766a 100644 --- a/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs +++ b/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs @@ -1,9 +1,5 @@ using System; -using System.Linq; using System.Net; -using System.Net.Sockets; -using com.LandonKey.SocksWebProxy; -using com.LandonKey.SocksWebProxy.Proxy; using NLog; using NzbDrone.Common.Cloud; using NzbDrone.Common.Extensions; @@ -22,13 +18,20 @@ namespace NzbDrone.Core.IndexerProxies.Socks4 public override string Name => "Socks4"; public override HttpRequest PreRequest(HttpRequest request) { + var uri = GetProxyUri(Settings); + + if (uri == null) + { + return null; + } + if (Settings.Username.IsNotNullOrWhiteSpace() && Settings.Password.IsNotNullOrWhiteSpace()) { - request.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(Settings.Host), Settings.Port, ProxyConfig.SocksVersion.Four, Settings.Username, Settings.Password), false); + request.Proxy = new WebProxy(uri, false, null, new NetworkCredential(Settings.Username, Settings.Password)); } else { - request.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(Settings.Host), Settings.Port, ProxyConfig.SocksVersion.Four), false); + request.Proxy = new WebProxy(uri); } _logger.Debug("Applying Socks4 Proxy {0} to request {1}", Name, request.Url); @@ -36,32 +39,9 @@ namespace NzbDrone.Core.IndexerProxies.Socks4 return request; } - private static int GetNextFreePort() + private Uri GetProxyUri(Socks4Settings proxySettings) { - var listener = new TcpListener(IPAddress.Loopback, 0); - listener.Start(); - var port = ((IPEndPoint)listener.LocalEndpoint).Port; - listener.Stop(); - - return port; - } - - private static IPAddress GetProxyIpAddress(string host) - { - IPAddress ipAddress; - if (!IPAddress.TryParse(host, out ipAddress)) - { - try - { - ipAddress = Dns.GetHostEntry(host).AddressList.OrderByDescending(a => a.AddressFamily == AddressFamily.InterNetwork).First(); - } - catch (Exception e) - { - throw new InvalidOperationException(string.Format("Unable to resolve proxy hostname '{0}' to a valid IP address.", host), e); - } - } - - return ipAddress; + return new Uri("socks4://" + proxySettings.Host + ":" + proxySettings.Port); } } } diff --git a/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs b/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs index c41c00549..dfd572977 100644 --- a/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs +++ b/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs @@ -1,9 +1,5 @@ using System; -using System.Linq; using System.Net; -using System.Net.Sockets; -using com.LandonKey.SocksWebProxy; -using com.LandonKey.SocksWebProxy.Proxy; using NLog; using NzbDrone.Common.Cloud; using NzbDrone.Common.Extensions; @@ -23,13 +19,20 @@ namespace NzbDrone.Core.IndexerProxies.Socks5 public override HttpRequest PreRequest(HttpRequest request) { + var uri = GetProxyUri(Settings); + + if (uri == null) + { + return null; + } + if (Settings.Username.IsNotNullOrWhiteSpace() && Settings.Password.IsNotNullOrWhiteSpace()) { - request.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(Settings.Host), Settings.Port, ProxyConfig.SocksVersion.Five, Settings.Username, Settings.Password), false); + request.Proxy = new WebProxy(uri, false, null, new NetworkCredential(Settings.Username, Settings.Password)); } else { - request.Proxy = new SocksWebProxy(new ProxyConfig(IPAddress.Loopback, GetNextFreePort(), GetProxyIpAddress(Settings.Host), Settings.Port, ProxyConfig.SocksVersion.Five), false); + request.Proxy = new WebProxy(uri); } _logger.Debug("Applying Socks5 Proxy {0} to request {1}", Name, request.Url); @@ -37,32 +40,9 @@ namespace NzbDrone.Core.IndexerProxies.Socks5 return request; } - private static int GetNextFreePort() + private Uri GetProxyUri(Socks5Settings proxySettings) { - var listener = new TcpListener(IPAddress.Loopback, 0); - listener.Start(); - var port = ((IPEndPoint)listener.LocalEndpoint).Port; - listener.Stop(); - - return port; - } - - private static IPAddress GetProxyIpAddress(string host) - { - IPAddress ipAddress; - if (!IPAddress.TryParse(host, out ipAddress)) - { - try - { - ipAddress = Dns.GetHostEntry(host).AddressList.OrderByDescending(a => a.AddressFamily == AddressFamily.InterNetwork).First(); - } - catch (Exception e) - { - throw new InvalidOperationException(string.Format("Unable to resolve proxy hostname '{0}' to a valid IP address.", host), e); - } - } - - return ipAddress; + return new Uri("socks5://" + proxySettings.Host + ":" + proxySettings.Port); } } } From 4c4614cfab92ee9ec7d12d447cf41769a385a162 Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Wed, 17 Nov 2021 21:45:11 +0000 Subject: [PATCH 0155/2320] Fixed: Actually use freeleech tokens for Orpheus when enabled --- src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs index 6d68c8829..5acab3183 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs @@ -75,7 +75,7 @@ namespace NzbDrone.Core.Indexers.Definitions // Orpheus fails to download if usetoken=0 so we need to only add if we will use one if (_settings.UseFreeleechToken) { - url.AddQueryParam("useToken", "1"); + url = url.AddQueryParam("useToken", "1"); } return url.FullUri; From a31971472d454076f1be80a6554dd786d45c7fb9 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 14 Nov 2021 14:25:39 -0600 Subject: [PATCH 0156/2320] Fixed: Cleanse APIKey from Signalr logging (cherry picked from (Readarr PR) commit 571b4647702737858d890ec2d18b73703b4b5a88) --- .../InstrumentationTests/CleanseLogMessageFixture.cs | 1 + src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs index 4fceb804c..2ba4a776b 100644 --- a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs +++ b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs @@ -75,6 +75,7 @@ namespace NzbDrone.Common.Test.InstrumentationTests // Notifiarr [TestCase("https://notifiarr.com/notifier.php: api=1234530f-422f-4aac-b6b3-01233210aaaa&radarr_health_issue_message=Download")] + [TestCase("/readarr/signalr/messages/negotiate?access_token=1234530f422f4aacb6b301233210aaaa&negotiateVersion=1")] // RSS [TestCase(@"<atom:link href = ""https://api.nzb.su/api?t=search&extended=1&cat=3030&apikey=mySecret&q=Diggers"" rel=""self"" type=""application/rss+xml"" />")] diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index 2a73e4d35..8d79f2c97 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -11,7 +11,7 @@ namespace NzbDrone.Common.Instrumentation private static readonly Regex[] CleansingRules = new[] { // Url - new Regex(@"(?<=[?&: ;])(apikey|token|pass(?:key|wd)?|auth|authkey|user|u?id|api|[a-z_]*apikey|account|pwd)=(?<secret>[^&=]+?)(?= |&|$|<)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"(?<=[?&: ;])(apikey|(?:access[-_]?)?token|pass(?:key|wd)?|auth|authkey|user|u?id|api|[a-z_]*apikey|account|pwd)=(?<secret>[^&=]+?)(?= |&|$|<)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"(?<=[?& ])[^=]*?(_?(?<!use)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"rss\.torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"rss\.torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), From 470b751f4453bc575aa65f7edb3e4f5d9b863ae1 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 18 Nov 2021 20:14:41 -0600 Subject: [PATCH 0157/2320] Fixed: (Cardigann) Don't try re-auth if can't html parse json --- .../Cardigann/CardigannRequestGenerator.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 5bcbcd578..e74eb57bb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -924,15 +924,19 @@ namespace NzbDrone.Core.Indexers.Cardigann return true; } - var parser = new HtmlParser(); - var document = parser.ParseDocument(response.Content); - - if (_definition.Login.Test.Selector != null) + // Only run html test selector on html responses + if (response.Headers.ContentType.Contains("text/html")) { - var selection = document.QuerySelectorAll(_definition.Login.Test.Selector); - if (selection.Length == 0) + var parser = new HtmlParser(); + var document = parser.ParseDocument(response.Content); + + if (_definition.Login.Test.Selector != null) { - return true; + var selection = document.QuerySelectorAll(_definition.Login.Test.Selector); + if (selection.Length == 0) + { + return true; + } } } From 17008ace5c775c76e95a5f756642357f8572bea5 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 18 Nov 2021 21:46:42 -0600 Subject: [PATCH 0158/2320] Fixed: (FlareSolverr) Don't attempt solve if CF not detected. Fixes #478 --- .../FlareSolverr/FlareSolverr.cs | 33 +++++++++++++++++-- .../Cardigann/CardigannRequestGenerator.cs | 2 +- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index 3e2344c1a..5f48a435d 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Net; using FluentValidation.Results; using Newtonsoft.Json; @@ -14,6 +15,8 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr { public class FlareSolverr : HttpIndexerProxyBase<FlareSolverrSettings> { + private static readonly HashSet<string> CloudflareServerNames = new HashSet<string> { "cloudflare", "cloudflare-nginx" }; + public FlareSolverr(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger, ILocalizationService localizationService) : base(cloudRequestBuilder, httpClient, logger, localizationService) { @@ -23,19 +26,28 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr public override HttpRequest PreRequest(HttpRequest request) { - return GenerateFlareSolverrRequest(request); + //Try original request first, detect CF in post response + return request; } public override HttpResponse PostResponse(HttpResponse response) { + if (!IsCloudflareProtected(response)) + { + _logger.Debug("CF Protection not detected, returning original response"); + return response; + } + + var flaresolverrResponse = _httpClient.Execute(GenerateFlareSolverrRequest(response.Request)); + FlareSolverrResponse result = null; - if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.InternalServerError) + if (flaresolverrResponse.StatusCode != HttpStatusCode.OK && flaresolverrResponse.StatusCode != HttpStatusCode.InternalServerError) { throw new FlareSolverrException("HTTP StatusCode not 200 or 500. Status is :" + response.StatusCode); } - result = JsonConvert.DeserializeObject<FlareSolverrResponse>(response.Content); + result = JsonConvert.DeserializeObject<FlareSolverrResponse>(flaresolverrResponse.Content); var cookieCollection = new CookieCollection(); var responseHeader = new HttpHeader(); @@ -51,6 +63,20 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr return newResponse; } + private static bool IsCloudflareProtected(HttpResponse response) + { + // check status code + if (response.StatusCode.Equals(HttpStatusCode.ServiceUnavailable) || + response.StatusCode.Equals(HttpStatusCode.Forbidden)) + { + // check response headers + return response.Headers.Any(i => + i.Key != null && i.Key == "server" && CloudflareServerNames.Contains(i.Value.ToLower())); + } + + return false; + } + private HttpRequest GenerateFlareSolverrRequest(HttpRequest request) { FlareSolverrRequest req; @@ -152,6 +178,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr public string Cmd { get; set; } public string Url { get; set; } public string UserAgent { get; set; } + public Cookie[] Cookies { get; set; } } public class FlareSolverrRequestGet : FlareSolverrRequest diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index e74eb57bb..9352bca44 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -925,7 +925,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } // Only run html test selector on html responses - if (response.Headers.ContentType.Contains("text/html")) + if (response.Headers.ContentType?.Contains("text/html") ?? true) { var parser = new HtmlParser(); var document = parser.ParseDocument(response.Content); From d8c9225d09e7aee5e544008a8585afd04b1bc398 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 18 Nov 2021 22:23:54 -0600 Subject: [PATCH 0159/2320] Fixed: (Cardigann) Use correct encoding for search requests Fixes #496 --- src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs | 1 + .../Definitions/Cardigann/CardigannRequestGenerator.cs | 3 +++ src/NzbDrone.Core/Indexers/HttpIndexerBase.cs | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs index f2759f848..23bbc1dd2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs @@ -124,6 +124,7 @@ namespace NzbDrone.Core.Indexers.Cardigann Name = definition.Name, Language = definition.Language, Description = definition.Description, + Encoding = Encoding.GetEncoding(definition.Encoding), Implementation = GetType().Name, IndexerUrls = definition.Links.ToArray(), Settings = new CardigannSettings { DefinitionFile = definition.File }, diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 9352bca44..5e5526492 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Net; +using System.Text; using System.Threading.Tasks; using AngleSharp.Html.Dom; using AngleSharp.Html.Parser; @@ -1080,6 +1081,8 @@ namespace NzbDrone.Core.Indexers.Cardigann var request = new CardigannRequest(requestbuilder.Build(), variables, searchPath); + request.HttpRequest.Encoding = Encoding.GetEncoding(_definition.Encoding); + yield return request; } } diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index 377acd25e..c07af6852 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -377,7 +377,7 @@ namespace NzbDrone.Core.Indexers } request.HttpRequest.SuppressHttpError = true; - request.HttpRequest.Encoding = Encoding; + request.HttpRequest.Encoding = request.HttpRequest.Encoding ?? Encoding; var response = await _httpClient.ExecuteProxiedAsync(request.HttpRequest, Definition); From 29dcbadfca994455abb8d49de195fd9a3799eca0 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 18 Nov 2021 22:44:53 -0600 Subject: [PATCH 0160/2320] Fixed: (DanishBytes) Set GUID for search results Fixes #597 --- src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs index adf72a516..b3a420854 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs @@ -200,11 +200,14 @@ namespace NzbDrone.Core.Indexers.Definitions foreach (var row in jsonResponse.Resource.Torrents) { + var infoUrl = $"{_settings.BaseUrl}torrents/{row.Id}"; + var release = new TorrentInfo { Title = row.Name, - InfoUrl = $"{_settings.BaseUrl}torrents/{row.Id}", + InfoUrl = infoUrl, DownloadUrl = $"{_settings.BaseUrl}torrent/download/{row.Id}.{jsonResponse.Resource.Rsskey}", + Guid = infoUrl, PosterUrl = row.PosterImage, PublishDate = row.CreatedAt, Categories = _categories.MapTrackerCatToNewznab(row.CategoryId), From a3fd37b27ec2a43bb2ac46808481c4f27838364f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 18 Nov 2021 23:17:22 -0600 Subject: [PATCH 0161/2320] Fixed: (Avistaz) Handle cases when Avistaz returns strings for ids Fixes #556 --- .../Files/Indexers/Avistaz/recentfeed.json | 4872 +++++++++++++++++ .../AvistazTests/AvistazFixture.cs | 64 + .../Definitions/Avistaz/AvistazParser.cs | 4 +- .../Definitions/Cardigann/Cardigann.cs | 1 - 4 files changed, 4938 insertions(+), 3 deletions(-) create mode 100644 src/NzbDrone.Core.Test/Files/Indexers/Avistaz/recentfeed.json create mode 100644 src/NzbDrone.Core.Test/IndexerTests/AvistazTests/AvistazFixture.cs diff --git a/src/NzbDrone.Core.Test/Files/Indexers/Avistaz/recentfeed.json b/src/NzbDrone.Core.Test/Files/Indexers/Avistaz/recentfeed.json new file mode 100644 index 000000000..1eccb3c23 --- /dev/null +++ b/src/NzbDrone.Core.Test/Files/Indexers/Avistaz/recentfeed.json @@ -0,0 +1,4872 @@ +{ + "current_page": 1, + "data": [ + { + "id": 187240, + "url": "https:\/\/avistaz.to\/torrent\/187240-japan-sinks-people-of-hope-2021-s01e05-720p-nf-web-dl-ddp20-x264-seikel", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "a879261d4e6e792402f92401141a21de70d51bf2", + "file_name": "JAPAN SINKS: People of Hope 2021 S01E05 720p NF WEB-DL DDP2.0 x264-SEIKEL", + "file_size": 935127615, + "file_count": 1, + "seed": 20, + "leech": 0, + "completed": 23, + "downloaded": 33, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt15569106", + "tmdb": "135144", + "tvdb": "410548", + "title": "JAPAN SINKS: People of Hope", + "tv_season": 1, + "tv_episode": 5, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 79, + "language": "Japanese" + } + ], + "subtitle": [ + { + "id": 7, + "language": "Arabic" + }, + { + "id": 33, + "language": "Chinese" + }, + { + "id": 39, + "language": "Croatian" + }, + { + "id": 40, + "language": "Czech" + }, + { + "id": 41, + "language": "Danish" + }, + { + "id": 43, + "language": "Dutch" + }, + { + "id": 45, + "language": "English" + }, + { + "id": 51, + "language": "Finnish" + }, + { + "id": 52, + "language": "French" + }, + { + "id": 58, + "language": "German" + }, + { + "id": 59, + "language": "Greek" + }, + { + "id": 64, + "language": "Hebrew" + }, + { + "id": 68, + "language": "Hungarian" + }, + { + "id": 72, + "language": "Indonesian" + }, + { + "id": 78, + "language": "Italian" + }, + { + "id": 79, + "language": "Japanese" + }, + { + "id": 104, + "language": "Malay" + }, + { + "id": 130, + "language": "Polish" + }, + { + "id": 131, + "language": "Portuguese" + }, + { + "id": 134, + "language": "Romanian" + }, + { + "id": 137, + "language": "Russian" + }, + { + "id": 151, + "language": "Spanish" + }, + { + "id": 155, + "language": "Swedish" + }, + { + "id": 162, + "language": "Thai" + }, + { + "id": 168, + "language": "Turkish" + }, + { + "id": 172, + "language": "Ukrainian" + }, + { + "id": 176, + "language": "Vietnamese" + } + ], + "music_type": null, + "created_at": "2021-11-14 23:26:21" + }, + { + "id": 187239, + "url": "https:\/\/avistaz.to\/torrent\/187239-the-heartland-hero-2021-s01e54-1080p-web-dl-aac-20-h264-ordinaryperson", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "The Heartland Hero 2021 S01E54 1080p WEB-DL AAC 2.0 H.264 - OrdinaryPerson", + "file_size": 703242056, + "file_count": 1, + "seed": 5, + "leech": 1, + "completed": 4, + "downloaded": 10, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": null, + "tmdb": null, + "tvdb": "409041", + "title": "The Heartland Hero", + "tv_season": 1, + "tv_episode": 54, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 33, + "language": "Chinese" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 23:11:49" + }, + { + "id": 187238, + "url": "https:\/\/avistaz.to\/torrent\/187238-the-heartland-hero-2021-s01e54-720p-web-dl-aac-20-h264-ordinaryperson", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "The Heartland Hero 2021 S01E54 720p WEB-DL AAC 2.0 H.264 - OrdinaryPerson", + "file_size": 446243216, + "file_count": 1, + "seed": 1, + "leech": 0, + "completed": 0, + "downloaded": 6, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": null, + "tmdb": null, + "tvdb": "409041", + "title": "The Heartland Hero", + "tv_season": 1, + "tv_episode": 54, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 33, + "language": "Chinese" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 23:09:11" + }, + { + "id": 187237, + "url": "https:\/\/avistaz.to\/torrent\/187237-this-land-is-mine-2021-s01-1080p-web-dl-aac-20-h264-ordinaryperson", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "This Land Is Mine 2021 S01 1080p WEB-DL AAC 2.0 H.264 - OrdinaryPerson", + "file_size": 21195285723, + "file_count": 15, + "seed": 2, + "leech": 1, + "completed": 1, + "downloaded": 8, + "upload_multiply": 1, + "download_multiply": 0.5, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt15212912", + "tmdb": "136236", + "tvdb": "408898", + "title": "This Land Is Mine", + "tv_season": null, + "tv_episode": null, + "tv_full_season": false, + "tv_complete": true + }, + "audio": [ + { + "id": 45, + "language": "English" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 23:05:30" + }, + { + "id": 187236, + "url": "https:\/\/avistaz.to\/torrent\/187236-this-land-is-mine-2021-s01-720p-web-dl-aac-20-h264-ordinaryperson", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "This Land Is Mine 2021 S01 720p WEB-DL AAC 2.0 H.264 - OrdinaryPerson", + "file_size": 13507070774, + "file_count": 15, + "seed": 1, + "leech": 0, + "completed": 0, + "downloaded": 5, + "upload_multiply": 1, + "download_multiply": 0.5, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt15212912", + "tmdb": "136236", + "tvdb": "408898", + "title": "This Land Is Mine", + "tv_season": null, + "tv_episode": null, + "tv_full_season": false, + "tv_complete": true + }, + "audio": [ + { + "id": 45, + "language": "English" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 22:59:26" + }, + { + "id": 187234, + "url": "https:\/\/avistaz.to\/torrent\/187234-this-land-is-mine-2021-s01e15-1080p-web-dl-aac-20-h264-ordinaryperson", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "This Land Is Mine 2021 S01E15 1080p WEB-DL AAC 2.0 H.264 - OrdinaryPerson", + "file_size": 1593348666, + "file_count": 1, + "seed": 4, + "leech": 0, + "completed": 3, + "downloaded": 12, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt15212912", + "tmdb": "136236", + "tvdb": "408898", + "title": "This Land Is Mine", + "tv_season": 1, + "tv_episode": 15, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 45, + "language": "English" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 22:38:33" + }, + { + "id": 187233, + "url": "https:\/\/avistaz.to\/torrent\/187233-this-land-is-mine-2021-s01e15-720p-web-dl-aac-20-h264-ordinaryperson", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "This Land Is Mine 2021 S01E15 720p WEB-DL AAC 2.0 H.264 - OrdinaryPerson", + "file_size": 1014623541, + "file_count": 1, + "seed": 1, + "leech": 0, + "completed": 0, + "downloaded": 5, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt15212912", + "tmdb": "136236", + "tvdb": "408898", + "title": "This Land Is Mine", + "tv_season": 1, + "tv_episode": 15, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 45, + "language": "English" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 22:35:13" + }, + { + "id": 187231, + "url": "https:\/\/avistaz.to\/torrent\/187231-kaikyou-sp-2007-complete-720p-hdtv-mp3-divx", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Kaikyou SP 2007 Complete 720p HDTV mp3 DivX", + "file_size": 6821851136, + "file_count": 3, + "seed": 7, + "leech": 2, + "completed": 7, + "downloaded": 35, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt1143942", + "tmdb": "83665", + "tvdb": null, + "title": "Kaiky\u00f4", + "tv_season": 1, + "tv_episode": null, + "tv_full_season": true, + "tv_complete": false + }, + "audio": [ + { + "id": 79, + "language": "Japanese" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 18:02:28" + }, + { + "id": 187229, + "url": "https:\/\/avistaz.to\/torrent\/187229-chimera-s01e06-1080p-viu-web-dl-aac-h264-its", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Chimera S01E06 1080p VIU WEB-DL AAC H.264-iTs", + "file_size": 1010568184, + "file_count": 1, + "seed": 20, + "leech": 1, + "completed": 19, + "downloaded": 35, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt15616218", + "tmdb": "96262", + "tvdb": "410613", + "title": "Chimera", + "tv_season": 1, + "tv_episode": 6, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 15:41:55" + }, + { + "id": 187225, + "url": "https:\/\/avistaz.to\/torrent\/187225-fragrance-of-the-first-flower-s01e02-1080p-web-dl-aac20-h264-fre3lov", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Fragrance of the First Flower S01E02 1080p WEB-DL AAC2.0 H.264-FRE3LOV", + "file_size": 650349912, + "file_count": 1, + "seed": 15, + "leech": 0, + "completed": 17, + "downloaded": 34, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": null, + "tmdb": "135422", + "tvdb": "409450", + "title": "Fragrance of the First Flower", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 107, + "language": "Mandarin" + } + ], + "subtitle": [ + { + "id": 33, + "language": "Chinese" + }, + { + "id": 45, + "language": "English" + }, + { + "id": 72, + "language": "Indonesian" + }, + { + "id": 79, + "language": "Japanese" + }, + { + "id": 151, + "language": "Spanish" + }, + { + "id": 162, + "language": "Thai" + } + ], + "music_type": null, + "created_at": "2021-11-14 13:49:11" + }, + { + "id": 187224, + "url": "https:\/\/avistaz.to\/torrent\/187224-game-winning-hit-2009-720p-webrip-aac-h264", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Game Winning Hit 2009 720p WEBRip AAC H.264", + "file_size": 45518363661, + "file_count": 40, + "seed": 10, + "leech": 3, + "completed": 11, + "downloaded": 38, + "upload_multiply": 1, + "download_multiply": 0, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 13, + "rip_type": "WEBRip", + "movie_tv": { + "imdb": "https:\/\/www.imdb.com", + "tmdb": "https:\/\/www.themovie", + "tvdb": "https:\/\/thetvdb.com\/", + "title": "Game Winning Hit \/ Play Ball \/ \u6bd4\u8cfd\u958b\u59cb", + "tv_season": null, + "tv_episode": null, + "tv_full_season": false, + "tv_complete": true + }, + "audio": [ + { + "id": 33, + "language": "Chinese" + } + ], + "subtitle": [ + { + "id": 33, + "language": "Chinese" + }, + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 13:15:51" + }, + { + "id": 187223, + "url": "https:\/\/avistaz.to\/torrent\/187223-viral-scandal-2021-s01e02-1080p-web-dl-aac-x264", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Viral Scandal 2021 S01E02 1080p WEB-DL AAC x264", + "file_size": 406379186, + "file_count": 1, + "seed": 7, + "leech": 0, + "completed": 6, + "downloaded": 22, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": null, + "tmdb": null, + "tvdb": null, + "title": "Viral Scandal", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 156, + "language": "Tagalog" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 12:56:09" + }, + { + "id": 187221, + "url": "https:\/\/avistaz.to\/torrent\/187221-1-night-2-days-s04e100-720p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "1 Night 2 Days S04E100 720p HDTV AAC H.264-NEXT", + "file_size": 2010287890, + "file_count": 1, + "seed": 22, + "leech": 0, + "completed": 22, + "downloaded": 35, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt3247300", + "tmdb": "30801", + "tvdb": "212151", + "title": "2 Days & 1 Night", + "tv_season": 4, + "tv_episode": 100, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-14 11:47:24" + }, + { + "id": 187219, + "url": "https:\/\/avistaz.to\/torrent\/187219-inspector-koo-2021-s01e06-1080p-nf-web-dl-ddp20-x264-hbo", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Inspector Koo 2021 S01E06 1080p NF WEB-DL DDP2.0 x264-HBO", + "file_size": 3250064430, + "file_count": 1, + "seed": 57, + "leech": 0, + "completed": 66, + "downloaded": 78, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt14731794", + "tmdb": "129475", + "tvdb": "401493", + "title": "Inspector Koo", + "tv_season": 1, + "tv_episode": 6, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 7, + "language": "Arabic" + }, + { + "id": 33, + "language": "Chinese" + }, + { + "id": 45, + "language": "English" + }, + { + "id": 72, + "language": "Indonesian" + }, + { + "id": 79, + "language": "Japanese" + }, + { + "id": 91, + "language": "Korean" + }, + { + "id": 104, + "language": "Malay" + }, + { + "id": 162, + "language": "Thai" + }, + { + "id": 176, + "language": "Vietnamese" + } + ], + "music_type": null, + "created_at": "2021-11-14 10:59:37" + }, + { + "id": 187218, + "url": "https:\/\/avistaz.to\/torrent\/187218-inspector-koo-2021-s01e05-1080p-nf-web-dl-ddp20-x264-hbo", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Inspector Koo 2021 S01E05 1080p NF WEB-DL DDP2.0 x264-HBO", + "file_size": 2846807072, + "file_count": 1, + "seed": 34, + "leech": 0, + "completed": 34, + "downloaded": 52, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt14731794", + "tmdb": "129475", + "tvdb": "401493", + "title": "Inspector Koo", + "tv_season": 1, + "tv_episode": 5, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 7, + "language": "Arabic" + }, + { + "id": 33, + "language": "Chinese" + }, + { + "id": 45, + "language": "English" + }, + { + "id": 72, + "language": "Indonesian" + }, + { + "id": 79, + "language": "Japanese" + }, + { + "id": 91, + "language": "Korean" + }, + { + "id": 104, + "language": "Malay" + }, + { + "id": 162, + "language": "Thai" + }, + { + "id": 176, + "language": "Vietnamese" + } + ], + "music_type": null, + "created_at": "2021-11-14 10:58:36" + }, + { + "id": 187216, + "url": "https:\/\/avistaz.to\/torrent\/187216-chimera-s01e06-1080p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Chimera S01E06 1080p HDTV AAC H.264-NEXT", + "file_size": 2575771367, + "file_count": 1, + "seed": 39, + "leech": 0, + "completed": 42, + "downloaded": 53, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt15616218", + "tmdb": "96262", + "tvdb": "410613", + "title": "Chimera", + "tv_season": 1, + "tv_episode": 6, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-14 10:31:45" + }, + { + "id": 187215, + "url": "https:\/\/avistaz.to\/torrent\/187215-chimera-s01e06-720p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Chimera S01E06 720p HDTV AAC H.264-NEXT", + "file_size": 1449508477, + "file_count": 1, + "seed": 58, + "leech": 0, + "completed": 70, + "downloaded": 85, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt15616218", + "tmdb": "96262", + "tvdb": "410613", + "title": "Chimera", + "tv_season": 1, + "tv_episode": 6, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + }, + { + "id": 134, + "language": "Romanian" + } + ], + "music_type": null, + "created_at": "2021-11-14 10:31:44" + }, + { + "id": 187214, + "url": "https:\/\/avistaz.to\/torrent\/187214-chimera-s01e06-450p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Chimera S01E06 450p HDTV AAC H.264-NEXT", + "file_size": 743146271, + "file_count": 1, + "seed": 9, + "leech": 0, + "completed": 11, + "downloaded": 20, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt15616218", + "tmdb": "96262", + "tvdb": "410613", + "title": "Chimera", + "tv_season": 1, + "tv_episode": 6, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-14 10:31:43" + }, + { + "id": 187213, + "url": "https:\/\/avistaz.to\/torrent\/187213-chimera-s01e06-360p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Chimera S01E06 360p HDTV AAC H.264-NEXT", + "file_size": 549881711, + "file_count": 1, + "seed": 10, + "leech": 0, + "completed": 15, + "downloaded": 24, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt15616218", + "tmdb": "96262", + "tvdb": "410613", + "title": "Chimera", + "tv_season": 1, + "tv_episode": 6, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-14 10:31:42" + }, + { + "id": 187212, + "url": "https:\/\/avistaz.to\/torrent\/187212-inspector-koo-s01e06-1080p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Inspector Koo S01E06 1080p HDTV AAC H.264-NEXT", + "file_size": 2851058883, + "file_count": 1, + "seed": 35, + "leech": 0, + "completed": 37, + "downloaded": 48, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14731794", + "tmdb": "129475", + "tvdb": "401493", + "title": "Inspector Koo", + "tv_season": 1, + "tv_episode": 6, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 10:28:11" + }, + { + "id": 187210, + "url": "https:\/\/avistaz.to\/torrent\/187210-inspector-koo-s01e06-450p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Inspector Koo S01E06 450p HDTV AAC H.264-NEXT", + "file_size": 823500419, + "file_count": 1, + "seed": 12, + "leech": 0, + "completed": 13, + "downloaded": 18, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14731794", + "tmdb": "129475", + "tvdb": "401493", + "title": "Inspector Koo", + "tv_season": 1, + "tv_episode": 6, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-14 10:28:10" + }, + { + "id": 187211, + "url": "https:\/\/avistaz.to\/torrent\/187211-inspector-koo-s01e06-720p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Inspector Koo S01E06 720p HDTV AAC H.264-NEXT", + "file_size": 1607084970, + "file_count": 1, + "seed": 55, + "leech": 0, + "completed": 67, + "downloaded": 73, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14731794", + "tmdb": "129475", + "tvdb": "401493", + "title": "Inspector Koo", + "tv_season": 1, + "tv_episode": 6, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 10:28:10" + }, + { + "id": 187209, + "url": "https:\/\/avistaz.to\/torrent\/187209-inspector-koo-s01e06-360p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Inspector Koo S01E06 360p HDTV AAC H.264-NEXT", + "file_size": 609276889, + "file_count": 1, + "seed": 11, + "leech": 0, + "completed": 14, + "downloaded": 18, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14731794", + "tmdb": "129475", + "tvdb": "401493", + "title": "Inspector Koo", + "tv_season": 1, + "tv_episode": 6, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-14 10:28:09" + }, + { + "id": 187208, + "url": "https:\/\/avistaz.to\/torrent\/187208-jirisan-s01e08-1080p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Jirisan S01E08 1080p HDTV AAC H.264-NEXT", + "file_size": 2421653977, + "file_count": 1, + "seed": 38, + "leech": 0, + "completed": 43, + "downloaded": 54, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt13400300", + "tmdb": "110533", + "tvdb": "393773", + "title": "Jirisan", + "tv_season": 1, + "tv_episode": 8, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 09:24:47" + }, + { + "id": 187207, + "url": "https:\/\/avistaz.to\/torrent\/187207-jirisan-s01e08-720p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Jirisan S01E08 720p HDTV AAC H.264-NEXT", + "file_size": 1362045049, + "file_count": 1, + "seed": 83, + "leech": 0, + "completed": 102, + "downloaded": 107, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt13400300", + "tmdb": "110533", + "tvdb": "393773", + "title": "Jirisan", + "tv_season": 1, + "tv_episode": 8, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + }, + { + "id": 134, + "language": "Romanian" + } + ], + "music_type": null, + "created_at": "2021-11-14 09:24:46" + }, + { + "id": 187206, + "url": "https:\/\/avistaz.to\/torrent\/187206-jirisan-s01e08-450p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Jirisan S01E08 450p HDTV AAC H.264-NEXT", + "file_size": 697453395, + "file_count": 1, + "seed": 14, + "leech": 0, + "completed": 17, + "downloaded": 24, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt13400300", + "tmdb": "110533", + "tvdb": "393773", + "title": "Jirisan", + "tv_season": 1, + "tv_episode": 8, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-14 09:24:45" + }, + { + "id": 187205, + "url": "https:\/\/avistaz.to\/torrent\/187205-jirisan-s01e08-360p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Jirisan S01E08 360p HDTV AAC H.264-NEXT", + "file_size": 515601960, + "file_count": 1, + "seed": 20, + "leech": 0, + "completed": 28, + "downloaded": 36, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt13400300", + "tmdb": "110533", + "tvdb": "393773", + "title": "Jirisan", + "tv_season": 1, + "tv_episode": 8, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-14 09:24:44" + }, + { + "id": 187204, + "url": "https:\/\/avistaz.to\/torrent\/187204-young-lady-and-gentleman-s01e16-720p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Young Lady and Gentleman S01E16 720p HDTV AAC H.264-NEXT", + "file_size": 1644051553, + "file_count": 1, + "seed": 65, + "leech": 0, + "completed": 72, + "downloaded": 84, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt15514606", + "tmdb": "129473", + "tvdb": "408414", + "title": "Young Lady and Gentleman", + "tv_season": 1, + "tv_episode": 16, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 09:20:56" + }, + { + "id": 187203, + "url": "https:\/\/avistaz.to\/torrent\/187203-young-lady-and-gentleman-s01e16-1080p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Young Lady and Gentleman S01E16 1080p HDTV AAC H.264-NEXT", + "file_size": 2914026524, + "file_count": 1, + "seed": 42, + "leech": 0, + "completed": 46, + "downloaded": 59, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt15514606", + "tmdb": "129473", + "tvdb": "408414", + "title": "Young Lady and Gentleman", + "tv_season": 1, + "tv_episode": 16, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-14 09:20:55" + }, + { + "id": 187202, + "url": "https:\/\/avistaz.to\/torrent\/187202-young-lady-and-gentleman-s01e16-450p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Young Lady and Gentleman S01E16 450p HDTV AAC H.264-NEXT", + "file_size": 842283097, + "file_count": 1, + "seed": 15, + "leech": 0, + "completed": 19, + "downloaded": 24, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt15514606", + "tmdb": "129473", + "tvdb": "408414", + "title": "Young Lady and Gentleman", + "tv_season": 1, + "tv_episode": 16, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-14 09:20:54" + }, + { + "id": 187201, + "url": "https:\/\/avistaz.to\/torrent\/187201-young-lady-and-gentleman-s01e16-360p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Young Lady and Gentleman S01E16 360p HDTV AAC H.264-NEXT", + "file_size": 622795198, + "file_count": 1, + "seed": 14, + "leech": 0, + "completed": 18, + "downloaded": 26, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt15514606", + "tmdb": "129473", + "tvdb": "408414", + "title": "Young Lady and Gentleman", + "tv_season": 1, + "tv_episode": 16, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-14 09:20:53" + }, + { + "id": 187200, + "url": "https:\/\/avistaz.to\/torrent\/187200-king-of-masked-singer-e331-1080p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "King of Masked Singer E331 1080p HDTV AAC H.264-NEXT", + "file_size": 3509344239, + "file_count": 1, + "seed": 5, + "leech": 0, + "completed": 6, + "downloaded": 13, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt6289510", + "tmdb": "66046", + "tvdb": "296529", + "title": "King of Masked Singer", + "tv_season": 1, + "tv_episode": 331, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-14 09:17:35" + }, + { + "id": 187199, + "url": "https:\/\/avistaz.to\/torrent\/187199-king-of-masked-singer-e331-720p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "King of Masked Singer E331 720p HDTV AAC H.264-NEXT", + "file_size": 1981240764, + "file_count": 1, + "seed": 12, + "leech": 0, + "completed": 11, + "downloaded": 21, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt6289510", + "tmdb": "66046", + "tvdb": "296529", + "title": "King of Masked Singer", + "tv_season": 1, + "tv_episode": 331, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-14 09:17:34" + }, + { + "id": 187197, + "url": "https:\/\/avistaz.to\/torrent\/187197-let-me-be-your-knight-s01e02-1080p-iq-web-dl-aac-h264-its", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Let Me Be Your Knight S01E02 1080p IQ WEB-DL AAC H.264-iTs", + "file_size": 800912574, + "file_count": 1, + "seed": 54, + "leech": 0, + "completed": 69, + "downloaded": 73, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt15729630", + "tmdb": "134071", + "tvdb": "377959", + "title": "Let Me Be Your Knight", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 33, + "language": "Chinese" + }, + { + "id": 45, + "language": "English" + }, + { + "id": 72, + "language": "Indonesian" + }, + { + "id": 104, + "language": "Malay" + }, + { + "id": 162, + "language": "Thai" + }, + { + "id": 176, + "language": "Vietnamese" + } + ], + "music_type": null, + "created_at": "2021-11-14 09:14:24" + }, + { + "id": 187196, + "url": "https:\/\/avistaz.to\/torrent\/187196-running-man-e579-1080p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Running Man E579 1080p HDTV AAC H.264-NEXT", + "file_size": 3546791641, + "file_count": 1, + "seed": 160, + "leech": 5, + "completed": 206, + "downloaded": 212, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt2185037", + "tmdb": "33238", + "tvdb": "248870", + "title": "Running Man", + "tv_season": 1, + "tv_episode": 579, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 09:08:42" + }, + { + "id": 187195, + "url": "https:\/\/avistaz.to\/torrent\/187195-running-man-e579-720p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Running Man E579 720p HDTV AAC H.264-NEXT", + "file_size": 1999500573, + "file_count": 1, + "seed": 233, + "leech": 3, + "completed": 320, + "downloaded": 319, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt2185037", + "tmdb": "33238", + "tvdb": "248870", + "title": "Running Man", + "tv_season": 1, + "tv_episode": 579, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-14 09:08:29" + }, + { + "id": 187191, + "url": "https:\/\/avistaz.to\/torrent\/187191-beware-of-your-bosom-buddies-1984-720p-complete-web-dl-aac-h264-carmee", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Beware of Your Bosom Buddies \u78a7\u8840\u6d17\u94f6\u67aa (1984) 720p Complete WEB-DL AAC H.264-CARMEE", + "file_size": 4075094335, + "file_count": 5, + "seed": 7, + "leech": 0, + "completed": 8, + "downloaded": 13, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": null, + "tmdb": "107936", + "tvdb": null, + "title": "\u78a7\u8840\u6d17\u94f6\u67aa", + "tv_season": null, + "tv_episode": null, + "tv_full_season": false, + "tv_complete": true + }, + "audio": [ + { + "id": 27, + "language": "Cantonese" + }, + { + "id": 107, + "language": "Mandarin" + } + ], + "subtitle": [ + { + "id": 27, + "language": "Cantonese" + }, + { + "id": 33, + "language": "Chinese" + } + ], + "music_type": null, + "created_at": "2021-11-14 07:34:25" + }, + { + "id": 187190, + "url": "https:\/\/avistaz.to\/torrent\/187190-novoland-pearl-eclipse-s01e14-1080p-web-dl-aac-h264-kmx", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Novoland: Pearl Eclipse S01E14 1080p WEB-DL AAC H.264-KMX", + "file_size": 889019421, + "file_count": 1, + "seed": 28, + "leech": 1, + "completed": 41, + "downloaded": 51, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt13130228", + "tmdb": "103310", + "tvdb": "382022", + "title": "Novoland: Pearl Eclipse", + "tv_season": 1, + "tv_episode": 14, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 33, + "language": "Chinese" + } + ], + "subtitle": [ + { + "id": 7, + "language": "Arabic" + }, + { + "id": 27, + "language": "Cantonese" + }, + { + "id": 33, + "language": "Chinese" + }, + { + "id": 45, + "language": "English" + }, + { + "id": 72, + "language": "Indonesian" + }, + { + "id": 104, + "language": "Malay" + }, + { + "id": 162, + "language": "Thai" + } + ], + "music_type": null, + "created_at": "2021-11-14 07:24:31" + }, + { + "id": 187189, + "url": "https:\/\/avistaz.to\/torrent\/187189-novoland-pearl-eclipse-s01e13-1080p-web-dl-aac-h264-kmx", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Novoland: Pearl Eclipse S01E13 1080p WEB-DL AAC H.264-KMX", + "file_size": 616490137, + "file_count": 1, + "seed": 28, + "leech": 1, + "completed": 40, + "downloaded": 51, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt13130228", + "tmdb": "103310", + "tvdb": "382022", + "title": "Novoland: Pearl Eclipse", + "tv_season": 1, + "tv_episode": 13, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 33, + "language": "Chinese" + } + ], + "subtitle": [ + { + "id": 7, + "language": "Arabic" + }, + { + "id": 27, + "language": "Cantonese" + }, + { + "id": 33, + "language": "Chinese" + }, + { + "id": 45, + "language": "English" + }, + { + "id": 72, + "language": "Indonesian" + }, + { + "id": 104, + "language": "Malay" + }, + { + "id": 162, + "language": "Thai" + } + ], + "music_type": null, + "created_at": "2021-11-14 07:24:26" + }, + { + "id": 187188, + "url": "https:\/\/avistaz.to\/torrent\/187188-jirisan-s01e08-1080p-iq-web-dl-aac-h264-its", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Jirisan S01E08 1080p IQ WEB-DL AAC H.264-iTs", + "file_size": 932907486, + "file_count": 1, + "seed": 110, + "leech": 0, + "completed": 150, + "downloaded": 144, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt13400300", + "tmdb": "110533", + "tvdb": "393773", + "title": "Jirisan", + "tv_season": 1, + "tv_episode": 8, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 7, + "language": "Arabic" + }, + { + "id": 33, + "language": "Chinese" + }, + { + "id": 45, + "language": "English" + }, + { + "id": 72, + "language": "Indonesian" + }, + { + "id": 104, + "language": "Malay" + }, + { + "id": 151, + "language": "Spanish" + }, + { + "id": 162, + "language": "Thai" + }, + { + "id": 176, + "language": "Vietnamese" + } + ], + "music_type": null, + "created_at": "2021-11-14 07:12:25" + }, + { + "id": 187169, + "url": "https:\/\/avistaz.to\/torrent\/187169-daughters-2020-s01-1080p-iqiyi-web-dl-aac-h265-hbo", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Daughters (2020) S01 1080p IQiyi WEB-DL AAC H.265-HBO", + "file_size": 39159699312, + "file_count": 24, + "seed": 26, + "leech": 1, + "completed": 25, + "downloaded": 46, + "upload_multiply": 1, + "download_multiply": 0, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": null, + "tmdb": null, + "tvdb": "392886", + "title": "Daughters", + "tv_season": 1, + "tv_episode": null, + "tv_full_season": true, + "tv_complete": false + }, + "audio": [ + { + "id": 162, + "language": "Thai" + } + ], + "subtitle": [ + { + "id": 7, + "language": "Arabic" + }, + { + "id": 33, + "language": "Chinese" + }, + { + "id": 45, + "language": "English" + }, + { + "id": 72, + "language": "Indonesian" + }, + { + "id": 91, + "language": "Korean" + }, + { + "id": 104, + "language": "Malay" + }, + { + "id": 151, + "language": "Spanish" + }, + { + "id": 176, + "language": "Vietnamese" + } + ], + "music_type": null, + "created_at": "2021-11-14 01:18:23" + }, + { + "id": 187168, + "url": "https:\/\/avistaz.to\/torrent\/187168-pasabuy-2021-complete-1080p-web-dl-aac-x264", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Pasabuy 2021 Complete 1080p WEB-DL AAC x264", + "file_size": 2730588469, + "file_count": 5, + "seed": 13, + "leech": 0, + "completed": 15, + "downloaded": 30, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": null, + "tmdb": null, + "tvdb": null, + "title": "Pasabuy", + "tv_season": null, + "tv_episode": null, + "tv_full_season": false, + "tv_complete": true + }, + "audio": [ + { + "id": 156, + "language": "Tagalog" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 00:57:43" + }, + { + "id": 187167, + "url": "https:\/\/avistaz.to\/torrent\/187167-viral-scandal-2021-s01e01-1080p-web-dl-aac-x264", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Viral Scandal 2021 S01E01 1080p WEB-DL AAC x264", + "file_size": 685278374, + "file_count": 1, + "seed": 23, + "leech": 0, + "completed": 26, + "downloaded": 41, + "upload_multiply": 1, + "download_multiply": 0, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": null, + "tmdb": null, + "tvdb": null, + "title": "Viral Scandal", + "tv_season": 1, + "tv_episode": 1, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 156, + "language": "Tagalog" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 00:42:20" + }, + { + "id": 187165, + "url": "https:\/\/avistaz.to\/torrent\/187165-jikou-keisatsu-2006-s01-amzn-1080p-web-dl-ddp20-h264-hdctv", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Jikou Keisatsu (2006) S01 AMZN 1080p WEB-DL DDP2.0 H.264-HDCTV", + "file_size": 39007353371, + "file_count": 9, + "seed": 23, + "leech": 2, + "completed": 27, + "downloaded": 45, + "upload_multiply": 1, + "download_multiply": 0, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt0809732", + "tmdb": "36916", + "tvdb": "82349", + "title": "Time Limit Investigator", + "tv_season": 1, + "tv_episode": null, + "tv_full_season": true, + "tv_complete": false + }, + "audio": [ + { + "id": 79, + "language": "Japanese" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-14 00:03:50" + }, + { + "id": 187164, + "url": "https:\/\/avistaz.to\/torrent\/187164-happiness-s01e04-1080p-iq-web-dl-aac-h264-its", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Happiness S01E04 1080p IQ WEB-DL AAC H.264-iTs", + "file_size": 918517651, + "file_count": 1, + "seed": 30, + "leech": 0, + "completed": 39, + "downloaded": 52, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt14979052", + "tmdb": "135340", + "tvdb": "404667", + "title": "Happiness", + "tv_season": 1, + "tv_episode": 4, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 7, + "language": "Arabic" + }, + { + "id": 33, + "language": "Chinese" + }, + { + "id": 45, + "language": "English" + }, + { + "id": 72, + "language": "Indonesian" + }, + { + "id": 104, + "language": "Malay" + }, + { + "id": 162, + "language": "Thai" + }, + { + "id": 176, + "language": "Vietnamese" + } + ], + "music_type": null, + "created_at": "2021-11-13 23:07:25" + }, + { + "id": 187163, + "url": "https:\/\/avistaz.to\/torrent\/187163-the-adventures-1980-720p-complete-web-dl-aac-h264-carmee", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "The Adventures \u51b2\u51fb (1980) 720p Complete WEB-DL AAC H.264-CARMEE", + "file_size": 26365692689, + "file_count": 45, + "seed": 13, + "leech": 2, + "completed": 14, + "downloaded": 33, + "upload_multiply": 1, + "download_multiply": 0, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": null, + "tmdb": "138573", + "tvdb": null, + "title": "\u51b2\u51fb", + "tv_season": null, + "tv_episode": null, + "tv_full_season": false, + "tv_complete": true + }, + "audio": [ + { + "id": 27, + "language": "Cantonese" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 22:46:14" + }, + { + "id": 187162, + "url": "https:\/\/avistaz.to\/torrent\/187162-until-we-meet-again-2019-s01-1080p-iqiyi-web-dl-aac-h265-hbo", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Until We Meet Again (2019) S01 1080p IQiyi WEB-DL AAC H.265-HBO", + "file_size": 13388115901, + "file_count": 17, + "seed": 9, + "leech": 1, + "completed": 9, + "downloaded": 25, + "upload_multiply": 1, + "download_multiply": 0.5, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt11815104", + "tmdb": "95279", + "tvdb": "367677", + "title": "Until We Meet Again", + "tv_season": 1, + "tv_episode": null, + "tv_full_season": true, + "tv_complete": false + }, + "audio": [ + { + "id": 162, + "language": "Thai" + } + ], + "subtitle": [ + { + "id": 33, + "language": "Chinese" + }, + { + "id": 45, + "language": "English" + }, + { + "id": 104, + "language": "Malay" + }, + { + "id": 176, + "language": "Vietnamese" + } + ], + "music_type": null, + "created_at": "2021-11-13 22:10:28" + }, + { + "id": 187158, + "url": "https:\/\/avistaz.to\/torrent\/187158-kids-lives-matter-2021-s01e20-1080p-hdtv-dd51-h264-kmx", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Kids' Lives Matter 2021 S01E20 1080p HDTV DD5.1 H.264-KMX", + "file_size": 1513563143, + "file_count": 1, + "seed": 42, + "leech": 0, + "completed": 55, + "downloaded": 60, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": null, + "tmdb": "136197", + "tvdb": "411282", + "title": "Kids' Lives Matter", + "tv_season": 1, + "tv_episode": 20, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 27, + "language": "Cantonese" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 20:58:54" + }, + { + "id": 187157, + "url": "https:\/\/avistaz.to\/torrent\/187157-kids-lives-matter-2021-s01e19-1080p-hdtv-dd51-h264-kmx", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Kids' Lives Matter 2021 S01E19 1080p HDTV DD5.1 H.264-KMX", + "file_size": 1522787978, + "file_count": 1, + "seed": 40, + "leech": 0, + "completed": 54, + "downloaded": 58, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": null, + "tmdb": "136197", + "tvdb": "411282", + "title": "Kids' Lives Matter", + "tv_season": 1, + "tv_episode": 19, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 27, + "language": "Cantonese" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 20:58:52" + }, + { + "id": 187156, + "url": "https:\/\/avistaz.to\/torrent\/187156-kids-lives-matter-2021-s01e18-1080p-hdtv-dd51-h264-kmx", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Kids' Lives Matter 2021 S01E18 1080p HDTV DD5.1 H.264-KMX", + "file_size": 1695599088, + "file_count": 1, + "seed": 40, + "leech": 0, + "completed": 54, + "downloaded": 56, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": null, + "tmdb": "136197", + "tvdb": "411282", + "title": "Kids' Lives Matter", + "tv_season": 1, + "tv_episode": 18, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 27, + "language": "Cantonese" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 20:58:49" + }, + { + "id": 187155, + "url": "https:\/\/avistaz.to\/torrent\/187155-huwag-kang-mangamba-2021-complete-1080p-web-dl-aac-x264", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Huwag Kang Mangamba 2021 Complete 1080p WEB-DL AAC x264", + "file_size": 76871091758, + "file_count": 168, + "seed": 21, + "leech": 3, + "completed": 23, + "downloaded": 47, + "upload_multiply": 1, + "download_multiply": 0, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": null, + "tmdb": null, + "tvdb": null, + "title": "Huwag Kang Mangamba", + "tv_season": null, + "tv_episode": null, + "tv_full_season": false, + "tv_complete": true + }, + "audio": [ + { + "id": 156, + "language": "Tagalog" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 19:53:29" + }, + { + "id": 187150, + "url": "https:\/\/avistaz.to\/torrent\/187150-momo-ume-s01e16-1080p-hulu-web-dl-aac-h264-magicstar", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Momo Ume S01E16 1080p HULU WEB-DL AAC H.264-MagicStar", + "file_size": 273332660, + "file_count": 1, + "seed": 8, + "leech": 0, + "completed": 8, + "downloaded": 17, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": null, + "tmdb": null, + "tvdb": "409295", + "title": "Momo Ume", + "tv_season": 1, + "tv_episode": 16, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 79, + "language": "Japanese" + } + ], + "subtitle": [ + { + "id": 79, + "language": "Japanese" + } + ], + "music_type": null, + "created_at": "2021-11-13 17:04:28" + }, + { + "id": 187149, + "url": "https:\/\/avistaz.to\/torrent\/187149-momo-ume-s01e15-1080p-hulu-web-dl-aac-h264-magicstar", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Momo Ume S01E15 1080p HULU WEB-DL AAC H.264-MagicStar", + "file_size": 269996533, + "file_count": 1, + "seed": 8, + "leech": 0, + "completed": 8, + "downloaded": 16, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": null, + "tmdb": null, + "tvdb": "409295", + "title": "Momo Ume", + "tv_season": 1, + "tv_episode": 15, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 79, + "language": "Japanese" + } + ], + "subtitle": [ + { + "id": 79, + "language": "Japanese" + } + ], + "music_type": null, + "created_at": "2021-11-13 17:04:26" + }, + { + "id": 187148, + "url": "https:\/\/avistaz.to\/torrent\/187148-momo-ume-s01e14-1080p-hulu-web-dl-aac-h264-magicstar", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Momo Ume S01E14 1080p HULU WEB-DL AAC H.264-MagicStar", + "file_size": 289130625, + "file_count": 1, + "seed": 8, + "leech": 0, + "completed": 8, + "downloaded": 16, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": null, + "tmdb": null, + "tvdb": "409295", + "title": "Momo Ume", + "tv_season": 1, + "tv_episode": 14, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 79, + "language": "Japanese" + } + ], + "subtitle": [ + { + "id": 79, + "language": "Japanese" + } + ], + "music_type": null, + "created_at": "2021-11-13 17:04:23" + }, + { + "id": 187147, + "url": "https:\/\/avistaz.to\/torrent\/187147-momo-ume-s01e13-1080p-hulu-web-dl-aac-h264-magicstar", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Momo Ume S01E13 1080p HULU WEB-DL AAC H.264-MagicStar", + "file_size": 292439914, + "file_count": 1, + "seed": 8, + "leech": 0, + "completed": 8, + "downloaded": 16, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": null, + "tmdb": null, + "tvdb": "409295", + "title": "Momo Ume", + "tv_season": 1, + "tv_episode": 13, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 79, + "language": "Japanese" + } + ], + "subtitle": [ + { + "id": 79, + "language": "Japanese" + } + ], + "music_type": null, + "created_at": "2021-11-13 17:04:11" + }, + { + "id": 187146, + "url": "https:\/\/avistaz.to\/torrent\/187146-kenjushou-mitsukuni-kou-to-ore-e02-1080p-hdtv-aac-x265", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Kenjushou: Mitsukuni Kou to Ore E02 1080p HDTV AAC x265", + "file_size": 902068803, + "file_count": 1, + "seed": 7, + "leech": 0, + "completed": 10, + "downloaded": 19, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": null, + "tmdb": "137550", + "tvdb": null, + "title": "Kenjushou ~Mitsukuni-kou to Ore~", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 79, + "language": "Japanese" + } + ], + "subtitle": [ + { + "id": 79, + "language": "Japanese" + } + ], + "music_type": null, + "created_at": "2021-11-13 16:59:50" + }, + { + "id": 187145, + "url": "https:\/\/avistaz.to\/torrent\/187145-gunjou-ryouiki-e04-1080p-hdtv-aac-x265", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Gunjou Ryouiki E04 1080p HDTV AAC x265", + "file_size": 934541483, + "file_count": 1, + "seed": 6, + "leech": 0, + "completed": 6, + "downloaded": 14, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": null, + "tmdb": "135542", + "tvdb": "411192", + "title": "Gunjou Ryouiki", + "tv_season": 1, + "tv_episode": 4, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 79, + "language": "Japanese" + } + ], + "subtitle": [ + { + "id": 79, + "language": "Japanese" + } + ], + "music_type": null, + "created_at": "2021-11-13 16:57:51" + }, + { + "id": 187144, + "url": "https:\/\/avistaz.to\/torrent\/187144-come-come-everybody-e10-1080p-hdtv-aac-x265", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Come Come Everybody E10 1080p HDTV AAC x265", + "file_size": 409659322, + "file_count": 1, + "seed": 15, + "leech": 0, + "completed": 16, + "downloaded": 23, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": null, + "tmdb": "137265", + "tvdb": null, + "title": "Come Come Everybody", + "tv_season": 1, + "tv_episode": 10, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 79, + "language": "Japanese" + } + ], + "subtitle": [ + { + "id": 79, + "language": "Japanese" + } + ], + "music_type": null, + "created_at": "2021-11-13 16:54:53" + }, + { + "id": 187143, + "url": "https:\/\/avistaz.to\/torrent\/187143-come-come-everybody-e09-1080p-hdtv-aac-x265", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Come Come Everybody E09 1080p HDTV AAC x265", + "file_size": 231372429, + "file_count": 1, + "seed": 15, + "leech": 0, + "completed": 16, + "downloaded": 22, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": null, + "tmdb": "137265", + "tvdb": null, + "title": "Come Come Everybody", + "tv_season": 1, + "tv_episode": 9, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 79, + "language": "Japanese" + } + ], + "subtitle": [ + { + "id": 79, + "language": "Japanese" + } + ], + "music_type": null, + "created_at": "2021-11-13 16:54:51" + }, + { + "id": 187142, + "url": "https:\/\/avistaz.to\/torrent\/187142-come-come-everybody-e08-1080p-hdtv-aac-x265", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Come Come Everybody E08 1080p HDTV AAC x265", + "file_size": 257436470, + "file_count": 1, + "seed": 14, + "leech": 0, + "completed": 16, + "downloaded": 23, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": null, + "tmdb": "137265", + "tvdb": null, + "title": "Come Come Everybody", + "tv_season": 1, + "tv_episode": 8, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 79, + "language": "Japanese" + } + ], + "subtitle": [ + { + "id": 79, + "language": "Japanese" + } + ], + "music_type": null, + "created_at": "2021-11-13 16:54:49" + }, + { + "id": 187141, + "url": "https:\/\/avistaz.to\/torrent\/187141-come-come-everybody-e07-1080p-hdtv-aac-x265", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Come Come Everybody E07 1080p HDTV AAC x265", + "file_size": 286473908, + "file_count": 1, + "seed": 15, + "leech": 0, + "completed": 17, + "downloaded": 23, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": null, + "tmdb": "137265", + "tvdb": null, + "title": "Come Come Everybody", + "tv_season": 1, + "tv_episode": 7, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 79, + "language": "Japanese" + } + ], + "subtitle": [ + { + "id": 79, + "language": "Japanese" + } + ], + "music_type": null, + "created_at": "2021-11-13 16:54:46" + }, + { + "id": 187140, + "url": "https:\/\/avistaz.to\/torrent\/187140-come-come-everybody-e06-1080p-hdtv-aac-x265", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Come Come Everybody E06 1080p HDTV AAC x265", + "file_size": 434941389, + "file_count": 1, + "seed": 13, + "leech": 0, + "completed": 14, + "downloaded": 18, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": null, + "tmdb": "137265", + "tvdb": null, + "title": "Come Come Everybody", + "tv_season": 1, + "tv_episode": 6, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 79, + "language": "Japanese" + } + ], + "subtitle": [ + { + "id": 79, + "language": "Japanese" + } + ], + "music_type": null, + "created_at": "2021-11-13 16:54:43" + }, + { + "id": 187139, + "url": "https:\/\/avistaz.to\/torrent\/187139-the-red-sleeve-s01e02-1080p-viu-web-dl-aac-h264-its", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "The Red Sleeve S01E02 1080p VIU WEB-DL AAC H.264-iTs", + "file_size": 1190616474, + "file_count": 1, + "seed": 19, + "leech": 0, + "completed": 21, + "downloaded": 28, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt14687200", + "tmdb": "132925", + "tvdb": "402635", + "title": "The Red Sleeve", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 16:03:36" + }, + { + "id": 187138, + "url": "https:\/\/avistaz.to\/torrent\/187138-chimera-s01e05-1080p-viu-web-dl-aac-h264-its", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Chimera S01E05 1080p VIU WEB-DL AAC H.264-iTs", + "file_size": 1002083306, + "file_count": 1, + "seed": 18, + "leech": 0, + "completed": 18, + "downloaded": 27, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt15616218", + "tmdb": "96262", + "tvdb": "410613", + "title": "Chimera", + "tv_season": 1, + "tv_episode": 5, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 16:03:31" + }, + { + "id": 187137, + "url": "https:\/\/avistaz.to\/torrent\/187137-the-red-sleeve-2021-s01e02-1080p-viki-web-dl-aac-x264-honeyg", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "The Red Sleeve 2021 S01E02 1080p Viki WEB-DL AAC x264-HoneyG", + "file_size": 1100872682, + "file_count": 1, + "seed": 26, + "leech": 0, + "completed": 33, + "downloaded": 48, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt14687200", + "tmdb": "132925", + "tvdb": "402635", + "title": "The Red Sleeve", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 14:47:56" + }, + { + "id": 187136, + "url": "https:\/\/avistaz.to\/torrent\/187136-now-we-are-breaking-up-2021-s01e02-1080p-viki-web-dl-aac-x264-honeyg", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Now, We Are Breaking Up 2021 S01E02 1080p Viki WEB-DL AAC x264-HoneyG", + "file_size": 1045465733, + "file_count": 1, + "seed": 17, + "leech": 0, + "completed": 20, + "downloaded": 36, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt14408016", + "tmdb": "129887", + "tvdb": "398219", + "title": "Now, We Are Breaking Up", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 13:54:18" + }, + { + "id": 187135, + "url": "https:\/\/avistaz.to\/torrent\/187135-i-live-alone-e421-1080p-web-dl-aac-h264-mmr", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "I Live Alone E421 1080p WEB-DL AAC H.264-MMR", + "file_size": 2556057863, + "file_count": 1, + "seed": 57, + "leech": 0, + "completed": 66, + "downloaded": 78, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt7997010", + "tmdb": "65282", + "tvdb": "298704", + "title": "I Live Alone", + "tv_season": 1, + "tv_episode": 421, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 33, + "language": "Chinese" + }, + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 13:01:47" + }, + { + "id": 187134, + "url": "https:\/\/avistaz.to\/torrent\/187134-stars-top-recipe-at-fun-staurant-s01e105-1080p-web-dl-aac-h264-mmr", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Stars Top Recipe at Fun-Staurant S01E105 1080p WEB-DL AAC H.264-MMR", + "file_size": 2923142162, + "file_count": 1, + "seed": 20, + "leech": 0, + "completed": 22, + "downloaded": 34, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": null, + "tmdb": "96108", + "tvdb": "382874", + "title": "Stars' Top Recipe at Fun-Staurant", + "tv_season": 1, + "tv_episode": 105, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 12:57:53" + }, + { + "id": 187133, + "url": "https:\/\/avistaz.to\/torrent\/187133-now-we-are-breaking-up-s01e02-1080p-web-dl-aac-h264-appletor", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Now We Are Breaking Up S01E02 1080p WEB-DL AAC H.264-AppleTor", + "file_size": 2410391135, + "file_count": 1, + "seed": 67, + "leech": 0, + "completed": 95, + "downloaded": 106, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt14408016", + "tmdb": "129887", + "tvdb": "398219", + "title": "Now, We Are Breaking Up", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 12:48:57" + }, + { + "id": 187132, + "url": "https:\/\/avistaz.to\/torrent\/187132-reincarnated-1979-s01-remastered-576i-dvd-remux-mpeg-2-dd-20-kmx", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Reincarnated (1979) S01 Remastered 576i DVD REMUX MPEG-2 DD 2.0-KMX", + "file_size": 106571873382, + "file_count": 60, + "seed": 16, + "leech": 2, + "completed": 20, + "downloaded": 44, + "upload_multiply": 1, + "download_multiply": 0, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 17, + "rip_type": "DVD Remux", + "movie_tv": { + "imdb": "tt1988438", + "tmdb": "17454", + "tvdb": "403197", + "title": "Reincarnated ", + "tv_season": 1, + "tv_episode": null, + "tv_full_season": true, + "tv_complete": false + }, + "audio": [ + { + "id": 27, + "language": "Cantonese" + }, + { + "id": 33, + "language": "Chinese" + }, + { + "id": 107, + "language": "Mandarin" + } + ], + "subtitle": [ + { + "id": 27, + "language": "Cantonese" + }, + { + "id": 33, + "language": "Chinese" + } + ], + "music_type": null, + "created_at": "2021-11-13 12:10:57" + }, + { + "id": 187131, + "url": "https:\/\/avistaz.to\/torrent\/187131-young-lady-and-gentleman-s01e15-1080p-web-dl-aac-h264-appletor", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Young Lady and Gentleman S01E15 1080p WEB-DL AAC H.264-AppleTor", + "file_size": 5543272093, + "file_count": 1, + "seed": 19, + "leech": 0, + "completed": 20, + "downloaded": 38, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt15514606", + "tmdb": "129473", + "tvdb": "408414", + "title": "Young Lady and Gentleman", + "tv_season": 1, + "tv_episode": 15, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 11:35:53" + }, + { + "id": 187130, + "url": "https:\/\/avistaz.to\/torrent\/187130-kieta-hatsukoi-2021-s01e06-1080p-web-dl-aac-h264mar", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Kieta Hatsukoi 2021 S01E06 1080p WEB-DL AAC H.264.MAR", + "file_size": 512339577, + "file_count": 1, + "seed": 51, + "leech": 0, + "completed": 98, + "downloaded": 102, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt15666846", + "tmdb": "135929", + "tvdb": "408996", + "title": "My Love Mix-Up!", + "tv_season": 1, + "tv_episode": 6, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 79, + "language": "Japanese" + } + ], + "subtitle": [ + { + "id": 79, + "language": "Japanese" + } + ], + "music_type": null, + "created_at": "2021-11-13 11:03:19" + }, + { + "id": 187129, + "url": "https:\/\/avistaz.to\/torrent\/187129-amazing-saturday-e186-1080p-web-dl-aac-h264-appletor", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Amazing Saturday E186 1080p WEB-DL AAC H.264-AppleTor", + "file_size": 3382552795, + "file_count": 1, + "seed": 12, + "leech": 0, + "completed": 12, + "downloaded": 27, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt10160132", + "tmdb": "78648", + "tvdb": "350134", + "title": "Amazing Saturday", + "tv_season": 1, + "tv_episode": 186, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 11:02:54" + }, + { + "id": 187128, + "url": "https:\/\/avistaz.to\/torrent\/187128-jirisan-s01e07-1080p-web-dl-aac-h264-appletor", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Jirisan S01E07 1080p WEB-DL AAC H.264-AppleTor", + "file_size": 2388468637, + "file_count": 1, + "seed": 83, + "leech": 0, + "completed": 102, + "downloaded": 114, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt13400300", + "tmdb": "110533", + "tvdb": "393773", + "title": "Jirisan", + "tv_season": 1, + "tv_episode": 7, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + }, + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 11:00:29" + }, + { + "id": 187127, + "url": "https:\/\/avistaz.to\/torrent\/187127-chimera-s01e05-1080p-web-dl-aac-h264-appletor", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Chimera S01E05 1080p WEB-DL AAC H.264-AppleTor", + "file_size": 2260893774, + "file_count": 1, + "seed": 51, + "leech": 0, + "completed": 68, + "downloaded": 77, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt15616218", + "tmdb": "96262", + "tvdb": "410613", + "title": "Chimera", + "tv_season": 1, + "tv_episode": 5, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 10:57:36" + }, + { + "id": 187126, + "url": "https:\/\/avistaz.to\/torrent\/187126-happiness-s01e04-1080p-web-dl-aac-h264-appletor", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Happiness S01E04 1080p WEB-DL AAC H.264-AppleTor", + "file_size": 2349441937, + "file_count": 1, + "seed": 100, + "leech": 0, + "completed": 127, + "downloaded": 139, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt14979052", + "tmdb": "135340", + "tvdb": "404667", + "title": "Happiness", + "tv_season": 1, + "tv_episode": 4, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + }, + { + "id": 129, + "language": "Persian" + } + ], + "music_type": null, + "created_at": "2021-11-13 10:55:31" + }, + { + "id": 187125, + "url": "https:\/\/avistaz.to\/torrent\/187125-inspector-koo-s01e05-1080p-web-dl-aac-h264-appletor", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Inspector Koo S01E05 1080p WEB-DL AAC H.264-AppleTor", + "file_size": 1749182320, + "file_count": 1, + "seed": 36, + "leech": 0, + "completed": 40, + "downloaded": 49, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt14731794", + "tmdb": "129475", + "tvdb": "401493", + "title": "Inspector Koo", + "tv_season": 1, + "tv_episode": 5, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 10:53:16" + }, + { + "id": 187124, + "url": "https:\/\/avistaz.to\/torrent\/187124-happiness-s01e04-1080p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Happiness S01E04 1080p HDTV AAC H.264-NEXT", + "file_size": 2616325535, + "file_count": 1, + "seed": 40, + "leech": 0, + "completed": 46, + "downloaded": 57, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14979052", + "tmdb": "135340", + "tvdb": "404667", + "title": "Happiness", + "tv_season": 1, + "tv_episode": 4, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 10:23:32" + }, + { + "id": 187123, + "url": "https:\/\/avistaz.to\/torrent\/187123-happiness-s01e04-720p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Happiness S01E04 720p HDTV AAC H.264-NEXT", + "file_size": 1474463312, + "file_count": 1, + "seed": 106, + "leech": 0, + "completed": 163, + "downloaded": 163, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14979052", + "tmdb": "135340", + "tvdb": "404667", + "title": "Happiness", + "tv_season": 1, + "tv_episode": 4, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + }, + { + "id": 129, + "language": "Persian" + } + ], + "music_type": null, + "created_at": "2021-11-13 10:23:31" + }, + { + "id": 187122, + "url": "https:\/\/avistaz.to\/torrent\/187122-happiness-s01e04-450p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Happiness S01E04 450p HDTV AAC H.264-NEXT", + "file_size": 756608772, + "file_count": 1, + "seed": 12, + "leech": 0, + "completed": 14, + "downloaded": 23, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14979052", + "tmdb": "135340", + "tvdb": "404667", + "title": "Happiness", + "tv_season": 1, + "tv_episode": 4, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 10:23:30" + }, + { + "id": 187121, + "url": "https:\/\/avistaz.to\/torrent\/187121-happiness-s01e04-360p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Happiness S01E04 360p HDTV AAC H.264-NEXT", + "file_size": 559858586, + "file_count": 1, + "seed": 14, + "leech": 0, + "completed": 22, + "downloaded": 33, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14979052", + "tmdb": "135340", + "tvdb": "404667", + "title": "Happiness", + "tv_season": 1, + "tv_episode": 4, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 10:23:29" + }, + { + "id": 187120, + "url": "https:\/\/avistaz.to\/torrent\/187120-inspector-koo-s01e05-1080p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Inspector Koo S01E05 1080p HDTV AAC H.264-NEXT", + "file_size": 2498350340, + "file_count": 1, + "seed": 31, + "leech": 0, + "completed": 39, + "downloaded": 52, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14731794", + "tmdb": "129475", + "tvdb": "401493", + "title": "Inspector Koo", + "tv_season": 1, + "tv_episode": 5, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 10:15:29" + }, + { + "id": 187119, + "url": "https:\/\/avistaz.to\/torrent\/187119-inspector-koo-s01e05-720p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Inspector Koo S01E05 720p HDTV AAC H.264-NEXT", + "file_size": 1407465853, + "file_count": 1, + "seed": 68, + "leech": 0, + "completed": 91, + "downloaded": 100, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14731794", + "tmdb": "129475", + "tvdb": "401493", + "title": "Inspector Koo", + "tv_season": 1, + "tv_episode": 5, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 10:15:28" + }, + { + "id": 187118, + "url": "https:\/\/avistaz.to\/torrent\/187118-inspector-koo-s01e05-450p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Inspector Koo S01E05 450p HDTV AAC H.264-NEXT", + "file_size": 720829719, + "file_count": 1, + "seed": 12, + "leech": 0, + "completed": 13, + "downloaded": 24, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14731794", + "tmdb": "129475", + "tvdb": "401493", + "title": "Inspector Koo", + "tv_season": 1, + "tv_episode": 5, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 10:15:27" + }, + { + "id": 187117, + "url": "https:\/\/avistaz.to\/torrent\/187117-inspector-koo-s01e05-360p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Inspector Koo S01E05 360p HDTV AAC H.264-NEXT", + "file_size": 533191281, + "file_count": 1, + "seed": 12, + "leech": 0, + "completed": 17, + "downloaded": 31, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14731794", + "tmdb": "129475", + "tvdb": "401493", + "title": "Inspector Koo", + "tv_season": 1, + "tv_episode": 5, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 10:15:26" + }, + { + "id": 187116, + "url": "https:\/\/avistaz.to\/torrent\/187116-chimera-s01e05-1080p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Chimera S01E05 1080p HDTV AAC H.264-NEXT", + "file_size": 2507362185, + "file_count": 1, + "seed": 31, + "leech": 0, + "completed": 36, + "downloaded": 45, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt15616218", + "tmdb": "96262", + "tvdb": "410613", + "title": "Chimera", + "tv_season": 1, + "tv_episode": 5, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 09:54:52" + }, + { + "id": 187115, + "url": "https:\/\/avistaz.to\/torrent\/187115-chimera-s01e05-720p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Chimera S01E05 720p HDTV AAC H.264-NEXT", + "file_size": 1412291838, + "file_count": 1, + "seed": 69, + "leech": 0, + "completed": 88, + "downloaded": 98, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt15616218", + "tmdb": "96262", + "tvdb": "410613", + "title": "Chimera", + "tv_season": 1, + "tv_episode": 5, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + }, + { + "id": 134, + "language": "Romanian" + } + ], + "music_type": null, + "created_at": "2021-11-13 09:54:51" + }, + { + "id": 187114, + "url": "https:\/\/avistaz.to\/torrent\/187114-chimera-s01e05-450p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Chimera S01E05 450p HDTV AAC H.264-NEXT", + "file_size": 722863649, + "file_count": 1, + "seed": 10, + "leech": 0, + "completed": 12, + "downloaded": 18, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt15616218", + "tmdb": "96262", + "tvdb": "410613", + "title": "Chimera", + "tv_season": 1, + "tv_episode": 5, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 09:54:50" + }, + { + "id": 187113, + "url": "https:\/\/avistaz.to\/torrent\/187113-chimera-s01e05-360p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Chimera S01E05 360p HDTV AAC H.264-NEXT", + "file_size": 534431415, + "file_count": 1, + "seed": 11, + "leech": 0, + "completed": 19, + "downloaded": 25, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt15616218", + "tmdb": "96262", + "tvdb": "410613", + "title": "Chimera", + "tv_season": 1, + "tv_episode": 5, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 09:54:48" + }, + { + "id": 187112, + "url": "https:\/\/avistaz.to\/torrent\/187112-the-red-sleeve-s01e02-1080p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "The Red Sleeve S01E02 1080p HDTV AAC H.264-NEXT", + "file_size": 2938482783, + "file_count": 1, + "seed": 38, + "leech": 0, + "completed": 44, + "downloaded": 47, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14687200", + "tmdb": "132925", + "tvdb": "402635", + "title": "The Red Sleeve", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 09:50:35" + }, + { + "id": 187111, + "url": "https:\/\/avistaz.to\/torrent\/187111-the-red-sleeve-s01e02-720p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "The Red Sleeve S01E02 720p HDTV AAC H.264-NEXT", + "file_size": 1656808519, + "file_count": 1, + "seed": 86, + "leech": 0, + "completed": 122, + "downloaded": 122, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14687200", + "tmdb": "132925", + "tvdb": "402635", + "title": "The Red Sleeve", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + }, + { + "id": 45, + "language": "English" + }, + { + "id": 134, + "language": "Romanian" + } + ], + "music_type": null, + "created_at": "2021-11-13 09:50:34" + }, + { + "id": 187110, + "url": "https:\/\/avistaz.to\/torrent\/187110-the-red-sleeve-s01e02-450p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "The Red Sleeve S01E02 450p HDTV AAC H.264-NEXT", + "file_size": 847103434, + "file_count": 1, + "seed": 13, + "leech": 0, + "completed": 18, + "downloaded": 21, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14687200", + "tmdb": "132925", + "tvdb": "402635", + "title": "The Red Sleeve", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 09:50:32" + }, + { + "id": 187109, + "url": "https:\/\/avistaz.to\/torrent\/187109-the-red-sleeve-s01e02-360p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "The Red Sleeve S01E02 360p HDTV AAC H.264-NEXT", + "file_size": 626493282, + "file_count": 1, + "seed": 17, + "leech": 0, + "completed": 29, + "downloaded": 33, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14687200", + "tmdb": "132925", + "tvdb": "402635", + "title": "The Red Sleeve", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 09:50:31" + }, + { + "id": 187107, + "url": "https:\/\/avistaz.to\/torrent\/187107-now-we-are-breaking-up-s01e02-1080p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Now, We Are Breaking Up S01E02 1080p HDTV AAC H.264-NEXT", + "file_size": 2445446006, + "file_count": 1, + "seed": 36, + "leech": 0, + "completed": 50, + "downloaded": 47, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14408016", + "tmdb": "129887", + "tvdb": "398219", + "title": "Now, We Are Breaking Up", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 09:44:55" + }, + { + "id": 187106, + "url": "https:\/\/avistaz.to\/torrent\/187106-now-we-are-breaking-up-s01e02-720p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Now, We Are Breaking Up S01E02 720p HDTV AAC H.264-NEXT", + "file_size": 1378479991, + "file_count": 1, + "seed": 94, + "leech": 0, + "completed": 144, + "downloaded": 141, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14408016", + "tmdb": "129887", + "tvdb": "398219", + "title": "Now, We Are Breaking Up", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 09:44:54" + }, + { + "id": 187105, + "url": "https:\/\/avistaz.to\/torrent\/187105-now-we-are-breaking-up-s01e02-450p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Now, We Are Breaking Up S01E02 450p HDTV AAC H.264-NEXT", + "file_size": 707254650, + "file_count": 1, + "seed": 12, + "leech": 0, + "completed": 17, + "downloaded": 18, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14408016", + "tmdb": "129887", + "tvdb": "398219", + "title": "Now, We Are Breaking Up", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 09:44:53" + }, + { + "id": 187104, + "url": "https:\/\/avistaz.to\/torrent\/187104-now-we-are-breaking-up-s01e02-360p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Now, We Are Breaking Up S01E02 360p HDTV AAC H.264-NEXT", + "file_size": 523997519, + "file_count": 1, + "seed": 20, + "leech": 0, + "completed": 32, + "downloaded": 34, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 1, + "video_quality": "SD", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt14408016", + "tmdb": "129887", + "tvdb": "398219", + "title": "Now, We Are Breaking Up", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": null, + "music_type": null, + "created_at": "2021-11-13 09:44:51" + }, + { + "id": 187103, + "url": "https:\/\/avistaz.to\/torrent\/187103-now-we-are-breaking-up-s01e02-1080p-viu-web-dl-aac-h264-its", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Now, We Are Breaking Up S01E02 1080p VIU WEB-DL AAC H.264-iTs", + "file_size": 1083586807, + "file_count": 1, + "seed": 51, + "leech": 1, + "completed": 84, + "downloaded": 77, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 12, + "rip_type": "WEB-DL", + "movie_tv": { + "imdb": "tt14408016", + "tmdb": "129887", + "tvdb": "398219", + "title": "Now, We Are Breaking Up", + "tv_season": 1, + "tv_episode": 2, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 09:40:07" + }, + { + "id": 187102, + "url": "https:\/\/avistaz.to\/torrent\/187102-jirisan-s01e07-1080p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Jirisan S01E07 1080p HDTV AAC H.264-NEXT", + "file_size": 2371074239, + "file_count": 1, + "seed": 38, + "leech": 1, + "completed": 46, + "downloaded": 47, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 3, + "video_quality": "1080p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt13400300", + "tmdb": "110533", + "tvdb": "393773", + "title": "Jirisan", + "tv_season": 1, + "tv_episode": 7, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + }, + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 09:39:53" + }, + { + "id": 187101, + "url": "https:\/\/avistaz.to\/torrent\/187101-jirisan-s01e07-720p-hdtv-aac-h264-next", + "download": "https:\/\/avistaz.to\/rss\/download\/(removed)\/(removed).torrent", + "type_id": 2, + "type": "TV-Show", + "info_hash": "(removed)", + "file_name": "Jirisan S01E07 720p HDTV AAC H.264-NEXT", + "file_size": 1330835290, + "file_count": 1, + "seed": 94, + "leech": 0, + "completed": 129, + "downloaded": 124, + "upload_multiply": 1, + "download_multiply": 1, + "adult": false, + "video_quality_id": 2, + "video_quality": "720p", + "rip_type_id": 7, + "rip_type": "HDTV", + "movie_tv": { + "imdb": "tt13400300", + "tmdb": "110533", + "tvdb": "393773", + "title": "Jirisan", + "tv_season": 1, + "tv_episode": 7, + "tv_full_season": false, + "tv_complete": false + }, + "audio": [ + { + "id": 91, + "language": "Korean" + } + ], + "subtitle": [ + { + "id": 45, + "language": "English" + } + ], + "music_type": null, + "created_at": "2021-11-13 09:39:52" + } + ], + "first_page_url": "https:\/\/avistaz.to\/api\/v1\/jackett\/torrents?type=2&page=1", + "from": 1, + "last_page": 314, + "last_page_url": "https:\/\/avistaz.to\/api\/v1\/jackett\/torrents?type=2&page=314", + "next_page_url": "https:\/\/avistaz.to\/api\/v1\/jackett\/torrents?type=2&page=2", + "path": "https:\/\/avistaz.to\/api\/v1\/jackett\/torrents", + "per_page": 100, + "prev_page_url": null, + "to": 100, + "total": 31393 +} diff --git a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/AvistazFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/AvistazFixture.cs new file mode 100644 index 000000000..50443ac8f --- /dev/null +++ b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/AvistazFixture.cs @@ -0,0 +1,64 @@ +using System; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Common.Http; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Indexers.Definitions; +using NzbDrone.Core.Indexers.Definitions.Avistaz; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.IndexerTests.AvistazTests +{ + [TestFixture] + public class AvistazFixture : CoreTest<AvistaZ> + { + [SetUp] + public void Setup() + { + Subject.Definition = new IndexerDefinition() + { + Name = "AvistaZ", + Settings = new AvistazSettings() { Username = "someuser", Password = "somepass", Pid = "somepid" } + }; + } + + [Test] + public async Task should_parse_recent_feed_from_AvistaZ() + { + var recentFeed = ReadAllText(@"Files/Indexers/Avistaz/recentfeed.json"); + + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader { { "Content-Type", "application/json" } }, new CookieCollection(), recentFeed))); + + var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; + + releases.Should().HaveCount(100); + releases.First().Should().BeOfType<TorrentInfo>(); + + var torrentInfo = releases.First() as TorrentInfo; + + torrentInfo.Title.Should().Be("JAPAN SINKS: People of Hope 2021 S01E05 720p NF WEB-DL DDP2.0 x264-SEIKEL"); + torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent); + torrentInfo.DownloadUrl.Should().Be("https://avistaz.to/rss/download/(removed)/(removed).torrent"); + torrentInfo.InfoUrl.Should().Be("https://avistaz.to/torrent/187240-japan-sinks-people-of-hope-2021-s01e05-720p-nf-web-dl-ddp20-x264-seikel"); + torrentInfo.CommentUrl.Should().BeNullOrEmpty(); + torrentInfo.Indexer.Should().Be(Subject.Definition.Name); + torrentInfo.PublishDate.Should().Be(DateTime.Parse("2021-11-14 23:26:21")); + torrentInfo.Size.Should().Be(935127615); + torrentInfo.InfoHash.Should().Be("a879261d4e6e792402f92401141a21de70d51bf2"); + torrentInfo.MagnetUrl.Should().Be(null); + torrentInfo.Peers.Should().Be(20); + torrentInfo.Seeders.Should().Be(20); + torrentInfo.ImdbId.Should().Be(15569106); + torrentInfo.TmdbId.Should().Be(135144); + torrentInfo.TvdbId.Should().Be(410548); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs index 5c48c835a..4029b45c0 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs @@ -71,8 +71,8 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz if (row.MovieTvinfo != null) { release.ImdbId = ParseUtil.GetImdbID(row.MovieTvinfo.Imdb).GetValueOrDefault(); - release.TmdbId = row.MovieTvinfo.Tmdb.IsNullOrWhiteSpace() ? 0 : ParseUtil.CoerceInt(row.MovieTvinfo.Tmdb); - release.TvdbId = row.MovieTvinfo.Tvdb.IsNullOrWhiteSpace() ? 0 : ParseUtil.CoerceInt(row.MovieTvinfo.Tvdb); + release.TmdbId = row.MovieTvinfo.Tmdb.IsNullOrWhiteSpace() ? 0 : ParseUtil.TryCoerceInt(row.MovieTvinfo.Tmdb, out var tmdbResult) ? tmdbResult : 0; + release.TvdbId = row.MovieTvinfo.Tvdb.IsNullOrWhiteSpace() ? 0 : ParseUtil.TryCoerceInt(row.MovieTvinfo.Tvdb, out var tvdbResult) ? tvdbResult : 0; } torrentInfos.Add(release); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs index 23bbc1dd2..f2759f848 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs @@ -124,7 +124,6 @@ namespace NzbDrone.Core.Indexers.Cardigann Name = definition.Name, Language = definition.Language, Description = definition.Description, - Encoding = Encoding.GetEncoding(definition.Encoding), Implementation = GetType().Name, IndexerUrls = definition.Links.ToArray(), Settings = new CardigannSettings { DefinitionFile = definition.File }, From b8a42a7998090f70635e0f8ad474960535538999 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Fri, 19 Nov 2021 16:18:56 -0600 Subject: [PATCH 0162/2320] Fixed: (FlareSolverr) Detection of Cloudflare --- src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index 5f48a435d..ca3f7691a 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -71,7 +71,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr { // check response headers return response.Headers.Any(i => - i.Key != null && i.Key == "server" && CloudflareServerNames.Contains(i.Value.ToLower())); + i.Key != null && i.Key.ToLower() == "server" && CloudflareServerNames.Contains(i.Value.ToLower())); } return false; From 77fa113d77658136c3b2ceffbeb3d127a4206ded Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 20 Nov 2021 03:27:00 -0600 Subject: [PATCH 0163/2320] Bump version to 0.1.4 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f2a62a6cb..6d25219ef 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,7 +7,7 @@ variables: outputFolder: './_output' artifactsFolder: './_artifacts' testsFolder: './_tests' - majorVersion: '0.1.3' + majorVersion: '0.1.4' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From f69f96695b1262a89ff1ea4ff2de376a55925b99 Mon Sep 17 00:00:00 2001 From: Chris Sandvik <9214195+csandman@users.noreply.github.com> Date: Sat, 20 Nov 2021 12:31:45 -0500 Subject: [PATCH 0164/2320] New: Add a filter bar to the "Add Indexers" modal (#607) * Add a filter bar to the "Add Indexers" modal * Fix stylelint errors * Hide AddIndexerModal alert on small screens --- .../Indexer/Add/AddIndexerModalContent.css | 45 +++++++- .../src/Indexer/Add/AddIndexerModalContent.js | 102 +++++++++++++++--- 2 files changed, 130 insertions(+), 17 deletions(-) diff --git a/frontend/src/Indexer/Add/AddIndexerModalContent.css b/frontend/src/Indexer/Add/AddIndexerModalContent.css index 9e175cacf..38c00ad82 100644 --- a/frontend/src/Indexer/Add/AddIndexerModalContent.css +++ b/frontend/src/Indexer/Add/AddIndexerModalContent.css @@ -16,7 +16,7 @@ composes: input from '~Components/Form/TextInput.css'; flex: 0 0 auto; - margin-bottom: 20px; + margin-bottom: 16px; } .alert { @@ -28,3 +28,46 @@ .scroller { flex: 1 1 auto; } + +.filterRow { + display: flex; + margin-bottom: 20px; +} + +.filterContainer { + display: flex; + align-items: stretch; + flex: 1; + flex-direction: column; + margin-right: 12px; +} + +.filterContainer:last-child { + margin-right: 0; +} + +.filterLabel { + margin-bottom: 3px; + font-weight: bold; +} + +@media only screen and (max-width: $breakpointSmall) { + .alert { + display: none; + } + + .filterRow { + flex-direction: column; + } + + .filterContainer { + margin-right: 0; + margin-bottom: 12px; + } + + .scroller { + margin-right: -30px; + margin-bottom: -30px; + margin-left: -30px; + } +} diff --git a/frontend/src/Indexer/Add/AddIndexerModalContent.js b/frontend/src/Indexer/Add/AddIndexerModalContent.js index 86f595512..1c5e0f28a 100644 --- a/frontend/src/Indexer/Add/AddIndexerModalContent.js +++ b/frontend/src/Indexer/Add/AddIndexerModalContent.js @@ -1,6 +1,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import Alert from 'Components/Alert'; +import EnhancedSelectInput from 'Components/Form/EnhancedSelectInput'; import TextInput from 'Components/Form/TextInput'; import Button from 'Components/Link/Button'; import LoadingIndicator from 'Components/Loading/LoadingIndicator'; @@ -44,6 +45,17 @@ const columns = [ } ]; +const protocols = [ + { + key: 'torrent', + value: 'torrent' + }, + { + key: 'usenet', + value: 'nzb' + } +]; + class AddIndexerModalContent extends Component { // @@ -53,7 +65,10 @@ class AddIndexerModalContent extends Component { super(props, context); this.state = { - filter: '' + filter: '', + filterProtocols: [], + filterLanguages: [], + filterPrivacyLevels: [] }; } @@ -80,8 +95,35 @@ class AddIndexerModalContent extends Component { onModalClose } = this.props; - const filter = this.state.filter; - const filterLower = filter.toLowerCase(); + const languages = Array.from(new Set(indexers.map(({ language }) => language))) + .sort((a, b) => a.localeCompare(b)) + .map((language) => ({ key: language, value: language })); + + const privacyLevels = Array.from(new Set(indexers.map(({ privacy }) => privacy))) + .sort((a, b) => a.localeCompare(b)) + .map((privacy) => ({ key: privacy, value: privacy })); + + const filteredIndexers = indexers.filter((indexer) => { + const { filter, filterProtocols, filterLanguages, filterPrivacyLevels } = this.state; + + if (!indexer.name.toLowerCase().includes(filter.toLocaleLowerCase())) { + return false; + } + + if (filterProtocols.length && !filterProtocols.includes(indexer.protocol)) { + return false; + } + + if (filterLanguages.length && !filterLanguages.includes(indexer.language)) { + return false; + } + + if (filterPrivacyLevels.length && !filterPrivacyLevels.includes(indexer.privacy)) { + return false; + } + + return true; + }); const errorMessage = getErrorMessage(error, 'Unable to load indexers'); @@ -99,11 +141,43 @@ class AddIndexerModalContent extends Component { className={styles.filterInput} placeholder={translate('FilterPlaceHolder')} name="filter" - value={filter} + value={this.state.filter} autoFocus={true} onChange={this.onFilterChange} /> + <div className={styles.filterRow}> + <div className={styles.filterContainer}> + <label className={styles.filterLabel}>Protocol</label> + <EnhancedSelectInput + name="indexerProtocols" + value={this.state.filterProtocols} + values={protocols} + onChange={({ value }) => this.setState({ filterProtocols: value })} + /> + </div> + + <div className={styles.filterContainer}> + <label className={styles.filterLabel}>Language</label> + <EnhancedSelectInput + name="indexerLanguages" + value={this.state.filterLanguages} + values={languages} + onChange={({ value }) => this.setState({ filterLanguages: value })} + /> + </div> + + <div className={styles.filterContainer}> + <label className={styles.filterLabel}>Privacy</label> + <EnhancedSelectInput + name="indexerPrivacyLevels" + value={this.state.filterPrivacyLevels} + values={privacyLevels} + onChange={({ value }) => this.setState({ filterPrivacyLevels: value })} + /> + </div> + </div> + <Alert kind={kinds.INFO} className={styles.alert} @@ -133,18 +207,14 @@ class AddIndexerModalContent extends Component { > <TableBody> { - indexers.map((indexer) => { - return indexer.name.toLowerCase().includes(filterLower) ? - ( - <SelectIndexerRow - key={indexer.name} - implementation={indexer.implementation} - {...indexer} - onIndexerSelect={onIndexerSelect} - /> - ) : - null; - }) + filteredIndexers.map((indexer) => ( + <SelectIndexerRow + key={indexer.name} + implementation={indexer.implementation} + {...indexer} + onIndexerSelect={onIndexerSelect} + /> + )) } </TableBody> </Table> : From 5d32bcf8b9140468da4cd64765f615c4fb15b643 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 20 Nov 2021 02:52:26 -0600 Subject: [PATCH 0165/2320] New: Bulk Grab Releases and Parameter Search --- frontend/src/Helpers/Props/icons.js | 8 + frontend/src/Search/QueryParameterModal.css | 35 +++ frontend/src/Search/QueryParameterModal.js | 270 ++++++++++++++++++ frontend/src/Search/QueryParameterOption.css | 66 +++++ frontend/src/Search/QueryParameterOption.js | 83 ++++++ frontend/src/Search/SearchFooter.css | 10 +- frontend/src/Search/SearchFooter.js | 127 +++++++- frontend/src/Search/SearchFooterConnector.js | 6 +- frontend/src/Search/SearchIndex.js | 99 ++++++- frontend/src/Search/SearchIndexConnector.js | 7 +- .../src/Search/Table/SearchIndexHeader.css | 7 +- .../src/Search/Table/SearchIndexHeader.js | 18 ++ frontend/src/Search/Table/SearchIndexRow.css | 7 +- frontend/src/Search/Table/SearchIndexRow.js | 23 +- frontend/src/Search/Table/SearchIndexTable.js | 21 +- frontend/src/Store/Actions/releaseActions.js | 58 ++++ ...eleaseClientSideCollectionItemsSelector.js | 6 +- .../IndexerSearch/NewznabRequest.cs | 105 +++++++ src/NzbDrone.Core/Localization/Core/en.json | 6 + .../Search/SearchController.cs | 49 +++- 20 files changed, 961 insertions(+), 50 deletions(-) create mode 100644 frontend/src/Search/QueryParameterModal.css create mode 100644 frontend/src/Search/QueryParameterModal.js create mode 100644 frontend/src/Search/QueryParameterOption.css create mode 100644 frontend/src/Search/QueryParameterOption.js diff --git a/frontend/src/Helpers/Props/icons.js b/frontend/src/Helpers/Props/icons.js index 01b4a3205..4c3328caa 100644 --- a/frontend/src/Helpers/Props/icons.js +++ b/frontend/src/Helpers/Props/icons.js @@ -22,10 +22,12 @@ import { import { faArrowCircleLeft as fasArrowCircleLeft, faArrowCircleRight as fasArrowCircleRight, + faAsterisk as fasAsterisk, faBackward as fasBackward, faBan as fasBan, faBars as fasBars, faBolt as fasBolt, + faBook as fasBook, faBookmark as fasBookmark, faBookReader as fasBookReader, faBroadcastTower as fasBroadcastTower, @@ -74,6 +76,7 @@ import { faLock as fasLock, faMedkit as fasMedkit, faMinus as fasMinus, + faMusic as fasMusic, faPause as fasPause, faPlay as fasPlay, faPlus as fasPlus, @@ -104,6 +107,7 @@ import { faTimes as fasTimes, faTimesCircle as fasTimesCircle, faTrashAlt as fasTrashAlt, + faTv as fasTv, faUser as fasUser, faUserPlus as fasUserPlus, faVial as fasVial, @@ -121,7 +125,9 @@ export const ADVANCED_SETTINGS = fasCog; export const ANNOUNCED = fasBullhorn; export const ARROW_LEFT = fasArrowCircleLeft; export const ARROW_RIGHT = fasArrowCircleRight; +export const AUDIO = fasMusic; export const BACKUP = farFileArchive; +export const BOOK = fasBook; export const BUG = fasBug; export const CALENDAR = fasCalendarAlt; export const CALENDAR_O = farCalendar; @@ -158,6 +164,7 @@ export const FILTER = fasFilter; export const FLAG = fasFlag; export const FOLDER = farFolder; export const FOLDER_OPEN = fasFolderOpen; +export const FOOTNOTE = fasAsterisk; export const GENRE = fasTheaterMasks; export const GROUP = farObjectGroup; export const HEALTH = fasMedkit; @@ -220,6 +227,7 @@ export const TAGS = fasTags; export const TBA = fasQuestionCircle; export const TEST = fasVial; export const TRANSLATE = fasLanguage; +export const TV = fasTv; export const UNGROUP = farObjectUngroup; export const UNKNOWN = fasQuestion; export const UNMONITORED = farBookmark; diff --git a/frontend/src/Search/QueryParameterModal.css b/frontend/src/Search/QueryParameterModal.css new file mode 100644 index 000000000..66e9bd73a --- /dev/null +++ b/frontend/src/Search/QueryParameterModal.css @@ -0,0 +1,35 @@ +.groups { + display: flex; + justify-content: space-between; + flex-wrap: wrap; + margin-bottom: 20px; +} + +.namingSelectContainer { + display: flex; + justify-content: flex-end; +} + +.namingSelect { + composes: select from '~Components/Form/SelectInput.css'; + + margin-left: 10px; + width: 200px; +} + +.footNote { + display: flex; + color: $helpTextColor; + + .icon { + margin-top: 3px; + margin-right: 5px; + padding: 2px; + } + + code { + padding: 0 1px; + border: 1px solid $borderColor; + background-color: #f7f7f7; + } +} diff --git a/frontend/src/Search/QueryParameterModal.js b/frontend/src/Search/QueryParameterModal.js new file mode 100644 index 000000000..237d5a6e6 --- /dev/null +++ b/frontend/src/Search/QueryParameterModal.js @@ -0,0 +1,270 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import FieldSet from 'Components/FieldSet'; +import SelectInput from 'Components/Form/SelectInput'; +import TextInput from 'Components/Form/TextInput'; +import Button from 'Components/Link/Button'; +import Modal from 'Components/Modal/Modal'; +import ModalBody from 'Components/Modal/ModalBody'; +import ModalContent from 'Components/Modal/ModalContent'; +import ModalFooter from 'Components/Modal/ModalFooter'; +import ModalHeader from 'Components/Modal/ModalHeader'; +import translate from 'Utilities/String/translate'; +import QueryParameterOption from './QueryParameterOption'; +import styles from './QueryParameterModal.css'; + +const searchOptions = [ + { key: 'search', value: 'Basic Search' }, + { key: 'tvsearch', value: 'TV Search' }, + { key: 'movie', value: 'Movie Search' }, + { key: 'music', value: 'Audio Search' }, + { key: 'book', value: 'Book Search' } +]; + +const seriesTokens = [ + { token: '{ImdbId:tt1234567}', example: 'tt12345' }, + { token: '{TvdbId:12345}', example: '12345' }, + { token: '{TvMazeId:12345}', example: '54321' }, + { token: '{Season:00}', example: '01' }, + { token: '{Episode:00}', example: '01' } +]; + +const movieTokens = [ + { token: '{ImdbId:tt1234567}', example: 'tt12345' }, + { token: '{TmdbId:12345}', example: '12345' }, + { token: '{Year:2000}', example: '2005' } +]; + +const audioTokens = [ + { token: '{Artist:Some Body}', example: 'Nirvana' }, + { token: '{Album:Some Album}', example: 'Nevermind' }, + { token: '{Label:Some Label}', example: 'Geffen' } +]; + +const bookTokens = [ + { token: '{Author:Some Author}', example: 'J. R. R. Tolkien' }, + { token: '{Title:Some Book}', example: 'Lord of the Rings' } +]; + +class QueryParameterModal extends Component { + + // + // Lifecycle + + constructor(props, context) { + super(props, context); + + this._selectionStart = null; + this._selectionEnd = null; + + this.state = { + separator: ' ' + }; + } + + // + // Listeners + + onInputSelectionChange = (selectionStart, selectionEnd) => { + this._selectionStart = selectionStart; + this._selectionEnd = selectionEnd; + } + + onOptionPress = ({ isFullFilename, tokenValue }) => { + const { + name, + value, + onSearchInputChange + } = this.props; + + const selectionStart = this._selectionStart; + const selectionEnd = this._selectionEnd; + + if (isFullFilename) { + onSearchInputChange({ name, value: tokenValue }); + } else if (selectionStart == null) { + onSearchInputChange({ + name, + value: `${value}${tokenValue}` + }); + } else { + const start = value.substring(0, selectionStart); + const end = value.substring(selectionEnd); + const newValue = `${start}${tokenValue}${end}`; + + onSearchInputChange({ name, value: newValue }); + this._selectionStart = newValue.length - 1; + this._selectionEnd = newValue.length - 1; + } + } + + onInputChange = ({ name, value }) => { + this.props.onSearchInputChange({ value: '' }); + this.props.onInputChange({ name, value }); + } + + // + // Render + + render() { + const { + name, + value, + searchType, + isOpen, + onSearchInputChange, + onModalClose + } = this.props; + + const { + separator: tokenSeparator + } = this.state; + + return ( + <Modal + isOpen={isOpen} + onModalClose={onModalClose} + > + <ModalContent onModalClose={onModalClose}> + <ModalHeader> + {translate('QueryOptions')} + </ModalHeader> + + <ModalBody> + <FieldSet legend={translate('SearchType')}> + <div className={styles.groups}> + <SelectInput + className={styles.namingSelect} + name="searchType" + value={searchType} + values={searchOptions} + onChange={this.onInputChange} + /> + </div> + </FieldSet> + + { + searchType === 'tvsearch' && + <FieldSet legend={translate('TvSearch')}> + <div className={styles.groups}> + { + seriesTokens.map(({ token, example }) => { + return ( + <QueryParameterOption + key={token} + name={name} + value={value} + token={token} + example={example} + tokenSeparator={tokenSeparator} + onPress={this.onOptionPress} + /> + ); + } + ) + } + </div> + </FieldSet> + } + + { + searchType === 'movie' && + <FieldSet legend={translate('MovieSearch')}> + <div className={styles.groups}> + { + movieTokens.map(({ token, example }) => { + return ( + <QueryParameterOption + key={token} + name={name} + value={value} + token={token} + example={example} + tokenSeparator={tokenSeparator} + onPress={this.onOptionPress} + /> + ); + } + ) + } + </div> + </FieldSet> + } + + { + searchType === 'music' && + <FieldSet legend={translate('AudioSearch')}> + <div className={styles.groups}> + { + audioTokens.map(({ token, example }) => { + return ( + <QueryParameterOption + key={token} + name={name} + value={value} + token={token} + example={example} + tokenSeparator={tokenSeparator} + onPress={this.onOptionPress} + /> + ); + } + ) + } + </div> + </FieldSet> + } + + { + searchType === 'book' && + <FieldSet legend={translate('BookSearch')}> + <div className={styles.groups}> + { + bookTokens.map(({ token, example }) => { + return ( + <QueryParameterOption + key={token} + name={name} + value={value} + token={token} + example={example} + tokenSeparator={tokenSeparator} + onPress={this.onOptionPress} + /> + ); + } + ) + } + </div> + </FieldSet> + } + </ModalBody> + + <ModalFooter> + <TextInput + name={name} + value={value} + onChange={onSearchInputChange} + onSelectionChange={this.onInputSelectionChange} + /> + <Button onPress={onModalClose}> + Close + </Button> + </ModalFooter> + </ModalContent> + </Modal> + ); + } +} + +QueryParameterModal.propTypes = { + name: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, + searchType: PropTypes.string.isRequired, + isOpen: PropTypes.bool.isRequired, + onSearchInputChange: PropTypes.func.isRequired, + onInputChange: PropTypes.func.isRequired, + onModalClose: PropTypes.func.isRequired +}; + +export default QueryParameterModal; diff --git a/frontend/src/Search/QueryParameterOption.css b/frontend/src/Search/QueryParameterOption.css new file mode 100644 index 000000000..cdfb186db --- /dev/null +++ b/frontend/src/Search/QueryParameterOption.css @@ -0,0 +1,66 @@ +.option { + display: flex; + align-items: stretch; + flex-wrap: wrap; + margin: 3px; + border: 1px solid $borderColor; + + &:hover { + .token { + background-color: #ddd; + } + + .example { + background-color: #ccc; + } + } +} + +.small { + width: 480px; +} + +.large { + width: 100%; +} + +.token { + flex: 0 0 50%; + padding: 6px 16px; + background-color: #eee; + font-family: $monoSpaceFontFamily; +} + +.example { + display: flex; + align-items: center; + justify-content: space-between; + flex: 0 0 50%; + padding: 6px 16px; + background-color: #ddd; + + .footNote { + padding: 2px; + color: #aaa; + } +} + +.isFullFilename { + .token, + .example { + flex: 1 0 auto; + } +} + +@media only screen and (max-width: $breakpointSmall) { + .option.small { + width: 100%; + } +} + +@media only screen and (max-width: $breakpointExtraSmall) { + .token, + .example { + flex: 1 0 auto; + } +} diff --git a/frontend/src/Search/QueryParameterOption.js b/frontend/src/Search/QueryParameterOption.js new file mode 100644 index 000000000..6a31a1efa --- /dev/null +++ b/frontend/src/Search/QueryParameterOption.js @@ -0,0 +1,83 @@ +import classNames from 'classnames'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import Icon from 'Components/Icon'; +import Link from 'Components/Link/Link'; +import { icons, sizes } from 'Helpers/Props'; +import styles from './QueryParameterOption.css'; + +class QueryParameterOption extends Component { + + // + // Listeners + + onPress = () => { + const { + token, + tokenSeparator, + isFullFilename, + onPress + } = this.props; + + let tokenValue = token; + + tokenValue = tokenValue.replace(/ /g, tokenSeparator); + + onPress({ isFullFilename, tokenValue }); + } + + // + // Render + render() { + const { + token, + tokenSeparator, + example, + footNote, + isFullFilename, + size + } = this.props; + + return ( + <Link + className={classNames( + styles.option, + styles[size], + isFullFilename && styles.isFullFilename + )} + onPress={this.onPress} + > + <div className={styles.token}> + {token.replace(/ /g, tokenSeparator)} + </div> + + <div className={styles.example}> + {example.replace(/ /g, tokenSeparator)} + + { + footNote !== 0 && + <Icon className={styles.footNote} name={icons.FOOTNOTE} /> + } + </div> + </Link> + ); + } +} + +QueryParameterOption.propTypes = { + token: PropTypes.string.isRequired, + example: PropTypes.string.isRequired, + footNote: PropTypes.number.isRequired, + tokenSeparator: PropTypes.string.isRequired, + isFullFilename: PropTypes.bool.isRequired, + size: PropTypes.oneOf([sizes.SMALL, sizes.LARGE]), + onPress: PropTypes.func.isRequired +}; + +QueryParameterOption.defaultProps = { + footNote: 0, + size: sizes.SMALL, + isFullFilename: false +}; + +export default QueryParameterOption; diff --git a/frontend/src/Search/SearchFooter.css b/frontend/src/Search/SearchFooter.css index 83eb700cd..54e68660b 100644 --- a/frontend/src/Search/SearchFooter.css +++ b/frontend/src/Search/SearchFooter.css @@ -31,6 +31,12 @@ height: 35px; } +.selectedReleasesLabel { + margin-bottom: 3px; + text-align: right; + font-weight: bold; +} + @media only screen and (max-width: $breakpointSmall) { .inputContainer { margin-right: 0; @@ -47,8 +53,4 @@ .buttons { justify-content: space-between; } - - .selectedMovieLabel { - text-align: left; - } } diff --git a/frontend/src/Search/SearchFooter.js b/frontend/src/Search/SearchFooter.js index 4468e80f8..f17fc8dca 100644 --- a/frontend/src/Search/SearchFooter.js +++ b/frontend/src/Search/SearchFooter.js @@ -1,13 +1,17 @@ import _ from 'lodash'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; +import FormInputButton from 'Components/Form/FormInputButton'; +import FormInputGroup from 'Components/Form/FormInputGroup'; import IndexersSelectInputConnector from 'Components/Form/IndexersSelectInputConnector'; import NewznabCategorySelectInputConnector from 'Components/Form/NewznabCategorySelectInputConnector'; -import TextInput from 'Components/Form/TextInput'; +import Icon from 'Components/Icon'; import keyboardShortcuts from 'Components/keyboardShortcuts'; import SpinnerButton from 'Components/Link/SpinnerButton'; import PageContentFooter from 'Components/Page/PageContentFooter'; +import { icons, inputTypes, kinds } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; +import QueryParameterModal from './QueryParameterModal'; import SearchFooterLabel from './SearchFooterLabel'; import styles from './SearchFooter.css'; @@ -22,10 +26,14 @@ class SearchFooter extends Component { const { defaultIndexerIds, defaultCategories, - defaultSearchQuery + defaultSearchQuery, + defaultSearchType } = props; this.state = { + isQueryParameterModalOpen: false, + queryModalOptions: null, + searchType: defaultSearchType, searchingReleases: false, searchQuery: defaultSearchQuery || '', searchIndexerIds: defaultIndexerIds, @@ -53,12 +61,14 @@ class SearchFooter extends Component { defaultIndexerIds, defaultCategories, defaultSearchQuery, + defaultSearchType, searchError } = this.props; const { searchIndexerIds, - searchCategories + searchCategories, + searchType } = this.state; const newState = {}; @@ -67,6 +77,10 @@ class SearchFooter extends Component { newState.searchQuery = defaultSearchQuery; } + if (searchType !== defaultSearchType) { + newState.searchType = defaultSearchType; + } + if (searchIndexerIds !== defaultIndexerIds) { newState.searchIndexerIds = defaultIndexerIds; } @@ -87,8 +101,21 @@ class SearchFooter extends Component { // // Listeners + onQueryParameterModalOpenClick = () => { + this.setState({ + queryModalOptions: { + name: 'queryParameters' + }, + isQueryParameterModalOpen: true + }); + } + + onQueryParameterModalClose = () => { + this.setState({ isQueryParameterModalOpen: false }); + } + onSearchPress = () => { - this.props.onSearchPress(this.state.searchQuery, this.state.searchIndexerIds, this.state.searchCategories); + this.props.onSearchPress(this.state.searchQuery, this.state.searchIndexerIds, this.state.searchCategories, this.state.searchType); } onSearchInputChange = ({ value }) => { @@ -101,36 +128,77 @@ class SearchFooter extends Component { render() { const { isFetching, + isPopulated, + isGrabbing, hasIndexers, - onInputChange + onInputChange, + onBulkGrabPress, + itemCount, + selectedCount } = this.props; const { searchQuery, searchIndexerIds, - searchCategories + searchCategories, + isQueryParameterModalOpen, + queryModalOptions, + searchType } = this.state; + let icon = icons.SEARCH; + + switch (searchType) { + case 'book': + icon = icons.BOOK; + break; + case 'tvsearch': + icon = icons.TV; + break; + case 'movie': + icon = icons.FILM; + break; + case 'music': + icon = icons.AUDIO; + break; + default: + icon = icons.SEARCH; + } + + let footerLabel = `Search ${searchIndexerIds.length === 0 ? 'all' : searchIndexerIds.length} Indexers`; + + if (isPopulated) { + footerLabel = selectedCount === 0 ? `Found ${itemCount} releases` : `Selected ${selectedCount} of ${itemCount} releases`; + } + return ( <PageContentFooter> <div className={styles.inputContainer}> <SearchFooterLabel - label={'Query'} + label={translate('Query')} isSaving={false} /> - <TextInput - name='searchQuery' - autoFocus={true} + <FormInputGroup + type={inputTypes.TEXT} + name="searchQuery" value={searchQuery} - isDisabled={isFetching} + buttons={ + <FormInputButton onPress={this.onQueryParameterModalOpenClick}> + <Icon + name={icon} + /> + </FormInputButton>} onChange={this.onSearchInputChange} + onFocus={this.onApikeyFocus} + isDisabled={isFetching} + {...searchQuery} /> </div> <div className={styles.indexerContainer}> <SearchFooterLabel - label={'Indexers'} + label={translate('Indexers')} isSaving={false} /> @@ -144,7 +212,7 @@ class SearchFooter extends Component { <div className={styles.indexerContainer}> <SearchFooterLabel - label={'Categories'} + label={translate('Categories')} isSaving={false} /> @@ -159,12 +227,26 @@ class SearchFooter extends Component { <div className={styles.buttonContainer}> <div className={styles.buttonContainerContent}> <SearchFooterLabel - label={`Search ${searchIndexerIds.length === 0 ? 'all' : searchIndexerIds.length} Indexers`} + className={styles.selectedReleasesLabel} + label={footerLabel} isSaving={false} /> <div className={styles.buttons}> + { + isPopulated && + <SpinnerButton + className={styles.searchButton} + kind={kinds.SUCCESS} + isSpinning={isGrabbing} + isDisabled={isFetching || !hasIndexers || selectedCount === 0} + onPress={onBulkGrabPress} + > + {translate('Grab Releases')} + </SpinnerButton> + } + <SpinnerButton className={styles.searchButton} isSpinning={isFetching} @@ -176,6 +258,17 @@ class SearchFooter extends Component { </div> </div> </div> + + <QueryParameterModal + isOpen={isQueryParameterModalOpen} + {...queryModalOptions} + name='queryParameters' + value={searchQuery} + searchType={searchType} + onSearchInputChange={this.onSearchInputChange} + onInputChange={onInputChange} + onModalClose={this.onQueryParameterModalClose} + /> </PageContentFooter> ); } @@ -185,8 +278,14 @@ SearchFooter.propTypes = { defaultIndexerIds: PropTypes.arrayOf(PropTypes.number).isRequired, defaultCategories: PropTypes.arrayOf(PropTypes.number).isRequired, defaultSearchQuery: PropTypes.string.isRequired, + defaultSearchType: PropTypes.string.isRequired, + selectedCount: PropTypes.number.isRequired, + itemCount: PropTypes.number.isRequired, isFetching: PropTypes.bool.isRequired, + isPopulated: PropTypes.bool.isRequired, + isGrabbing: PropTypes.bool.isRequired, onSearchPress: PropTypes.func.isRequired, + onBulkGrabPress: PropTypes.func.isRequired, hasIndexers: PropTypes.bool.isRequired, onInputChange: PropTypes.func.isRequired, searchError: PropTypes.object, diff --git a/frontend/src/Search/SearchFooterConnector.js b/frontend/src/Search/SearchFooterConnector.js index c4afc5979..0478ec329 100644 --- a/frontend/src/Search/SearchFooterConnector.js +++ b/frontend/src/Search/SearchFooterConnector.js @@ -12,13 +12,15 @@ function createMapStateToProps() { const { searchQuery: defaultSearchQuery, searchIndexerIds: defaultIndexerIds, - searchCategories: defaultCategories + searchCategories: defaultCategories, + searchType: defaultSearchType } = releases.defaults; return { defaultSearchQuery, defaultIndexerIds, - defaultCategories + defaultCategories, + defaultSearchType }; } ); diff --git a/frontend/src/Search/SearchIndex.js b/frontend/src/Search/SearchIndex.js index 716aa6910..d629224de 100644 --- a/frontend/src/Search/SearchIndex.js +++ b/frontend/src/Search/SearchIndex.js @@ -18,6 +18,9 @@ import * as keyCodes from 'Utilities/Constants/keyCodes'; import getErrorMessage from 'Utilities/Object/getErrorMessage'; import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder'; import translate from 'Utilities/String/translate'; +import getSelectedIds from 'Utilities/Table/getSelectedIds'; +import selectAll from 'Utilities/Table/selectAll'; +import toggleSelected from 'Utilities/Table/toggleSelected'; import SearchIndexFilterMenu from './Menus/SearchIndexFilterMenu'; import SearchIndexSortMenu from './Menus/SearchIndexSortMenu'; import NoSearchResults from './NoSearchResults'; @@ -44,12 +47,16 @@ class SearchIndex extends Component { isAddIndexerModalOpen: false, isEditIndexerModalOpen: false, searchType: null, - lastToggled: null + lastToggled: null, + allSelected: false, + allUnselected: false, + selectedState: {} }; } componentDidMount() { this.setJumpBarItems(); + this.setSelectedState(); window.addEventListener('keyup', this.onKeyUp); } @@ -66,6 +73,7 @@ class SearchIndex extends Component { hasDifferentItemsOrOrder(prevProps.items, items) ) { this.setJumpBarItems(); + this.setSelectedState(); } if (this.state.jumpToCharacter != null) { @@ -80,6 +88,48 @@ class SearchIndex extends Component { this.setState({ scroller: ref }); } + getSelectedIds = () => { + if (this.state.allUnselected) { + return []; + } + return getSelectedIds(this.state.selectedState, { parseIds: false }); + } + + setSelectedState() { + const { + items + } = this.props; + + const { + selectedState + } = this.state; + + const newSelectedState = {}; + + items.forEach((release) => { + const isItemSelected = selectedState[release.guid]; + + if (isItemSelected) { + newSelectedState[release.guid] = isItemSelected; + } else { + newSelectedState[release.guid] = false; + } + }); + + const selectedCount = getSelectedIds(newSelectedState).length; + const newStateCount = Object.keys(newSelectedState).length; + let isAllSelected = false; + let isAllUnselected = false; + + if (selectedCount === 0) { + isAllUnselected = true; + } else if (selectedCount === newStateCount) { + isAllSelected = true; + } + + this.setState({ selectedState: newSelectedState, allSelected: isAllSelected, allUnselected: isAllUnselected }); + } + setJumpBarItems() { const { items, @@ -146,8 +196,14 @@ class SearchIndex extends Component { this.setState({ jumpToCharacter }); } - onSearchPress = (query, indexerIds, categories) => { - this.props.onSearchPress({ query, indexerIds, categories }); + onSearchPress = (query, indexerIds, categories, type) => { + this.props.onSearchPress({ query, indexerIds, categories, type }); + } + + onBulkGrabPress = () => { + const selectedIds = this.getSelectedIds(); + const result = _.filter(this.props.items, (release) => _.indexOf(selectedIds, release.guid) !== -1); + this.props.onBulkGrabPress(result); } onKeyUp = (event) => { @@ -162,6 +218,20 @@ class SearchIndex extends Component { } } + onSelectAllChange = ({ value }) => { + this.setState(selectAll(this.state.selectedState, value)); + } + + onSelectAllPress = () => { + this.onSelectAllChange({ value: !this.state.allSelected }); + } + + onSelectedChange = ({ id, value, shiftKey = false }) => { + this.setState((state) => { + return toggleSelected(state, this.props.items, id, value, shiftKey); + }); + } + // // Render @@ -169,7 +239,9 @@ class SearchIndex extends Component { const { isFetching, isPopulated, + isGrabbing, error, + grabError, totalItems, items, columns, @@ -190,9 +262,14 @@ class SearchIndex extends Component { jumpBarItems, isAddIndexerModalOpen, isEditIndexerModalOpen, - jumpToCharacter + jumpToCharacter, + selectedState, + allSelected, + allUnselected } = this.state; + const selectedIndexerIds = this.getSelectedIds(); + const ViewComponent = getViewComponent(); const isLoaded = !!(!error && isPopulated && items.length && scroller); const hasNoIndexer = !totalItems; @@ -263,6 +340,11 @@ class SearchIndex extends Component { sortDirection={sortDirection} columns={columns} jumpToCharacter={jumpToCharacter} + allSelected={allSelected} + allUnselected={allUnselected} + onSelectedChange={this.onSelectedChange} + onSelectAllChange={this.onSelectAllChange} + selectedState={selectedState} {...otherProps} /> </div> @@ -293,8 +375,14 @@ class SearchIndex extends Component { <SearchFooterConnector isFetching={isFetching} + isPopulated={isPopulated} + isGrabbing={isGrabbing} + grabError={grabError} + selectedCount={selectedIndexerIds.length} + itemCount={items.length} hasIndexers={hasIndexers} onSearchPress={this.onSearchPress} + onBulkGrabPress={this.onBulkGrabPress} /> <AddIndexerModal @@ -314,7 +402,9 @@ class SearchIndex extends Component { SearchIndex.propTypes = { isFetching: PropTypes.bool.isRequired, isPopulated: PropTypes.bool.isRequired, + isGrabbing: PropTypes.bool.isRequired, error: PropTypes.object, + grabError: PropTypes.object, totalItems: PropTypes.number.isRequired, items: PropTypes.arrayOf(PropTypes.object).isRequired, columns: PropTypes.arrayOf(PropTypes.object).isRequired, @@ -327,6 +417,7 @@ SearchIndex.propTypes = { onSortSelect: PropTypes.func.isRequired, onFilterSelect: PropTypes.func.isRequired, onSearchPress: PropTypes.func.isRequired, + onBulkGrabPress: PropTypes.func.isRequired, onScroll: PropTypes.func.isRequired, hasIndexers: PropTypes.bool.isRequired }; diff --git a/frontend/src/Search/SearchIndexConnector.js b/frontend/src/Search/SearchIndexConnector.js index 6e0532044..a32dd47c0 100644 --- a/frontend/src/Search/SearchIndexConnector.js +++ b/frontend/src/Search/SearchIndexConnector.js @@ -3,7 +3,7 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; import withScrollPosition from 'Components/withScrollPosition'; -import { cancelFetchReleases, clearReleases, fetchReleases, setReleasesFilter, setReleasesSort, setReleasesTableOption } from 'Store/Actions/releaseActions'; +import { bulkGrabReleases, cancelFetchReleases, clearReleases, fetchReleases, setReleasesFilter, setReleasesSort, setReleasesTableOption } from 'Store/Actions/releaseActions'; import scrollPositions from 'Store/scrollPositions'; import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector'; import createReleaseClientSideCollectionItemsSelector from 'Store/Selectors/createReleaseClientSideCollectionItemsSelector'; @@ -46,6 +46,10 @@ function createMapDispatchToProps(dispatch, props) { dispatch(fetchReleases(payload)); }, + onBulkGrabPress(payload) { + dispatch(bulkGrabReleases(payload)); + }, + dispatchCancelFetchReleases() { dispatch(cancelFetchReleases()); }, @@ -83,6 +87,7 @@ class SearchIndexConnector extends Component { SearchIndexConnector.propTypes = { isSmallScreen: PropTypes.bool.isRequired, onSearchPress: PropTypes.func.isRequired, + onBulkGrabPress: PropTypes.func.isRequired, dispatchCancelFetchReleases: PropTypes.func.isRequired, dispatchClearReleases: PropTypes.func.isRequired, items: PropTypes.arrayOf(PropTypes.object) diff --git a/frontend/src/Search/Table/SearchIndexHeader.css b/frontend/src/Search/Table/SearchIndexHeader.css index 0cd0e8b00..669c93125 100644 --- a/frontend/src/Search/Table/SearchIndexHeader.css +++ b/frontend/src/Search/Table/SearchIndexHeader.css @@ -10,18 +10,13 @@ flex: 4 0 110px; } +.indexer, .category { composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css'; flex: 0 0 110px; } -.indexer { - composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css'; - - flex: 0 0 85px; -} - .age, .size, .files, diff --git a/frontend/src/Search/Table/SearchIndexHeader.js b/frontend/src/Search/Table/SearchIndexHeader.js index df132e0a7..f69cd5a48 100644 --- a/frontend/src/Search/Table/SearchIndexHeader.js +++ b/frontend/src/Search/Table/SearchIndexHeader.js @@ -4,6 +4,7 @@ import IconButton from 'Components/Link/IconButton'; import TableOptionsModal from 'Components/Table/TableOptions/TableOptionsModal'; import VirtualTableHeader from 'Components/Table/VirtualTableHeader'; import VirtualTableHeaderCell from 'Components/Table/VirtualTableHeaderCell'; +import VirtualTableSelectAllHeaderCell from 'Components/Table/VirtualTableSelectAllHeaderCell'; import { icons } from 'Helpers/Props'; import styles from './SearchIndexHeader.css'; @@ -38,6 +39,9 @@ class SearchIndexHeader extends Component { const { columns, onTableOptionChange, + allSelected, + allUnselected, + onSelectAllChange, ...otherProps } = this.props; @@ -56,6 +60,17 @@ class SearchIndexHeader extends Component { return null; } + if (name === 'select') { + return ( + <VirtualTableSelectAllHeaderCell + key={name} + allSelected={allSelected} + allUnselected={allUnselected} + onSelectAllChange={onSelectAllChange} + /> + ); + } + if (name === 'actions') { return ( <VirtualTableHeaderCell @@ -100,6 +115,9 @@ class SearchIndexHeader extends Component { SearchIndexHeader.propTypes = { columns: PropTypes.arrayOf(PropTypes.object).isRequired, + allSelected: PropTypes.bool.isRequired, + allUnselected: PropTypes.bool.isRequired, + onSelectAllChange: PropTypes.func.isRequired, onTableOptionChange: PropTypes.func.isRequired }; diff --git a/frontend/src/Search/Table/SearchIndexRow.css b/frontend/src/Search/Table/SearchIndexRow.css index a867e6666..205ed42df 100644 --- a/frontend/src/Search/Table/SearchIndexRow.css +++ b/frontend/src/Search/Table/SearchIndexRow.css @@ -17,18 +17,13 @@ flex: 4 0 110px; } +.indexer, .category { composes: cell; flex: 0 0 110px; } -.indexer { - composes: cell; - - flex: 0 0 85px; -} - .age, .size, .files, diff --git a/frontend/src/Search/Table/SearchIndexRow.js b/frontend/src/Search/Table/SearchIndexRow.js index 9925e45cd..bd508d2e5 100644 --- a/frontend/src/Search/Table/SearchIndexRow.js +++ b/frontend/src/Search/Table/SearchIndexRow.js @@ -5,6 +5,7 @@ import IconButton from 'Components/Link/IconButton'; import Link from 'Components/Link/Link'; import SpinnerIconButton from 'Components/Link/SpinnerIconButton'; import VirtualTableRowCell from 'Components/Table/Cells/VirtualTableRowCell'; +import VirtualTableSelectCell from 'Components/Table/Cells/VirtualTableSelectCell'; import Popover from 'Components/Tooltip/Popover'; import { icons, kinds, tooltipPositions } from 'Helpers/Props'; import formatDateTime from 'Utilities/Date/formatDateTime'; @@ -75,6 +76,7 @@ class SearchIndexRow extends Component { render() { const { + guid, protocol, categories, age, @@ -96,7 +98,9 @@ class SearchIndexRow extends Component { isGrabbed, grabError, longDateFormat, - timeFormat + timeFormat, + isSelected, + onSelectedChange } = this.props; return ( @@ -111,6 +115,19 @@ class SearchIndexRow extends Component { return null; } + if (column.name === 'select') { + return ( + <VirtualTableSelectCell + inputClassName={styles.checkInput} + id={guid} + key={column.name} + isSelected={isSelected} + isDisabled={false} + onSelectedChange={onSelectedChange} + /> + ); + } + if (column.name === 'protocol') { return ( <VirtualTableRowCell @@ -322,7 +339,9 @@ SearchIndexRow.propTypes = { isGrabbed: PropTypes.bool.isRequired, grabError: PropTypes.string, longDateFormat: PropTypes.string.isRequired, - timeFormat: PropTypes.string.isRequired + timeFormat: PropTypes.string.isRequired, + isSelected: PropTypes.bool, + onSelectedChange: PropTypes.func.isRequired }; SearchIndexRow.defaultProps = { diff --git a/frontend/src/Search/Table/SearchIndexTable.js b/frontend/src/Search/Table/SearchIndexTable.js index 953095dec..b2a6973fd 100644 --- a/frontend/src/Search/Table/SearchIndexTable.js +++ b/frontend/src/Search/Table/SearchIndexTable.js @@ -49,6 +49,8 @@ class SearchIndexTable extends Component { columns, longDateFormat, timeFormat, + selectedState, + onSelectedChange, onGrabPress } = this.props; @@ -64,6 +66,8 @@ class SearchIndexTable extends Component { component={SearchIndexRow} columns={columns} guid={release.guid} + isSelected={selectedState[release.guid]} + onSelectedChange={onSelectedChange} longDateFormat={longDateFormat} timeFormat={timeFormat} onGrabPress={onGrabPress} @@ -83,7 +87,11 @@ class SearchIndexTable extends Component { sortDirection, isSmallScreen, onSortPress, - scroller + scroller, + allSelected, + allUnselected, + onSelectAllChange, + selectedState } = this.props; return ( @@ -102,8 +110,12 @@ class SearchIndexTable extends Component { sortKey={sortKey} sortDirection={sortDirection} onSortPress={onSortPress} + allSelected={allSelected} + allUnselected={allUnselected} + onSelectAllChange={onSelectAllChange} /> } + selectedState={selectedState} columns={columns} /> ); @@ -121,7 +133,12 @@ SearchIndexTable.propTypes = { longDateFormat: PropTypes.string.isRequired, timeFormat: PropTypes.string.isRequired, onSortPress: PropTypes.func.isRequired, - onGrabPress: PropTypes.func.isRequired + onGrabPress: PropTypes.func.isRequired, + allSelected: PropTypes.bool.isRequired, + allUnselected: PropTypes.bool.isRequired, + selectedState: PropTypes.object.isRequired, + onSelectedChange: PropTypes.func.isRequired, + onSelectAllChange: PropTypes.func.isRequired }; export default SearchIndexTable; diff --git a/frontend/src/Store/Actions/releaseActions.js b/frontend/src/Store/Actions/releaseActions.js index 6bbabc69b..89ea9ffda 100644 --- a/frontend/src/Store/Actions/releaseActions.js +++ b/frontend/src/Store/Actions/releaseActions.js @@ -1,10 +1,12 @@ import { createAction } from 'redux-actions'; +import { batchActions } from 'redux-batched-actions'; import { filterBuilderTypes, filterBuilderValueTypes, sortDirections } from 'Helpers/Props'; import { createThunk, handleThunks } from 'Store/thunks'; import createAjaxRequest from 'Utilities/createAjaxRequest'; import getSectionState from 'Utilities/State/getSectionState'; import updateSectionState from 'Utilities/State/updateSectionState'; import translate from 'Utilities/String/translate'; +import { set } from './baseActions'; import createFetchHandler from './Creators/createFetchHandler'; import createHandleActions from './Creators/createHandleActions'; import createSetClientSideCollectionFilterReducer from './Creators/Reducers/createSetClientSideCollectionFilterReducer'; @@ -24,7 +26,9 @@ let abortCurrentRequest = null; export const defaultState = { isFetching: false, isPopulated: false, + isGrabbing: false, error: null, + grabError: null, items: [], sortKey: 'title', sortDirection: sortDirections.ASCENDING, @@ -32,12 +36,21 @@ export const defaultState = { secondarySortDirection: sortDirections.ASCENDING, defaults: { + searchType: 'basic', searchQuery: '', searchIndexerIds: [], searchCategories: [] }, columns: [ + { + name: 'select', + columnLabel: 'Select', + isSortable: false, + isVisible: true, + isModifiable: false, + isHidden: true + }, { name: 'protocol', label: translate('Protocol'), @@ -201,6 +214,8 @@ export const defaultState = { }; export const persistState = [ + 'releases.sortKey', + 'releases.sortDirection', 'releases.customFilters', 'releases.selectedFilterKey', 'releases.columns' @@ -214,6 +229,7 @@ export const CANCEL_FETCH_RELEASES = 'releases/cancelFetchReleases'; export const SET_RELEASES_SORT = 'releases/setReleasesSort'; export const CLEAR_RELEASES = 'releases/clearReleases'; export const GRAB_RELEASE = 'releases/grabRelease'; +export const BULK_GRAB_RELEASES = 'release/bulkGrabReleases'; export const UPDATE_RELEASE = 'releases/updateRelease'; export const SET_RELEASES_FILTER = 'releases/setReleasesFilter'; export const SET_RELEASES_TABLE_OPTION = 'releases/setReleasesTableOption'; @@ -227,6 +243,7 @@ export const cancelFetchReleases = createThunk(CANCEL_FETCH_RELEASES); export const setReleasesSort = createAction(SET_RELEASES_SORT); export const clearReleases = createAction(CLEAR_RELEASES); export const grabRelease = createThunk(GRAB_RELEASE); +export const bulkGrabReleases = createThunk(BULK_GRAB_RELEASES); export const updateRelease = createAction(UPDATE_RELEASE); export const setReleasesFilter = createAction(SET_RELEASES_FILTER); export const setReleasesTableOption = createAction(SET_RELEASES_TABLE_OPTION); @@ -285,6 +302,47 @@ export const actionHandlers = handleThunks({ grabError })); }); + }, + + [BULK_GRAB_RELEASES]: function(getState, payload, dispatch) { + dispatch(set({ + section, + isGrabbing: true + })); + + console.log(payload); + + const promise = createAjaxRequest({ + url: '/search/bulk', + method: 'POST', + contentType: 'application/json', + data: JSON.stringify(payload) + }).request; + + promise.done((data) => { + dispatch(batchActions([ + ...data.map((release) => { + return updateRelease({ + isGrabbing: false, + isGrabbed: true, + grabError: null + }); + }), + + set({ + section, + isGrabbing: false + }) + ])); + }); + + promise.fail((xhr) => { + dispatch(set({ + section, + isGrabbing: false, + grabError: xhr + })); + }); } }); diff --git a/frontend/src/Store/Selectors/createReleaseClientSideCollectionItemsSelector.js b/frontend/src/Store/Selectors/createReleaseClientSideCollectionItemsSelector.js index 9e6f3721c..c76ba4236 100644 --- a/frontend/src/Store/Selectors/createReleaseClientSideCollectionItemsSelector.js +++ b/frontend/src/Store/Selectors/createReleaseClientSideCollectionItemsSelector.js @@ -9,12 +9,14 @@ function createUnoptimizedSelector(uiSection) { const items = releases.items.map((s) => { const { guid, - title + title, + indexerId } = s; return { guid, - sortTitle: title + sortTitle: title, + indexerId }; }); diff --git a/src/NzbDrone.Core/IndexerSearch/NewznabRequest.cs b/src/NzbDrone.Core/IndexerSearch/NewznabRequest.cs index cb66ef969..912c108fb 100644 --- a/src/NzbDrone.Core/IndexerSearch/NewznabRequest.cs +++ b/src/NzbDrone.Core/IndexerSearch/NewznabRequest.cs @@ -1,7 +1,14 @@ +using System.Text.RegularExpressions; + namespace NzbDrone.Core.IndexerSearch { public class NewznabRequest { + private static readonly Regex TvRegex = new Regex(@"\{((?:imdbid\:)(?<imdbid>[^{]+)|(?:tvdbid\:)(?<tvdbid>[^{]+)|(?:season\:)(?<season>[^{]+)|(?:episode\:)(?<episode>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex MovieRegex = new Regex(@"\{((?:imdbid\:)(?<imdbid>[^{]+)|(?:tmdbid\:)(?<tmdbid>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex MusicRegex = new Regex(@"\{((?:artist\:)(?<artist>[^{]+)|(?:album\:)(?<album>[^{]+)|(?:label\:)(?<label>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex BookRegex = new Regex(@"\{((?:author\:)(?<author>[^{]+)|(?:title\:)(?<title>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); + public string t { get; set; } public string q { get; set; } public string cat { get; set; } @@ -28,5 +35,103 @@ namespace NzbDrone.Core.IndexerSearch public string source { get; set; } public string host { get; set; } public string server { get; set; } + + public void QueryToParams() + { + if (t == "tvsearch") + { + var matches = TvRegex.Matches(q); + + foreach (Match match in matches) + { + if (match.Groups["tvdbid"].Success) + { + tvdbid = int.TryParse(match.Groups["tvdbid"].Value, out var tvdb) ? tvdb : null; + } + + if (match.Groups["season"].Success) + { + season = int.TryParse(match.Groups["season"].Value, out var seasonParsed) ? seasonParsed : null; + } + + if (match.Groups["imdbid"].Success) + { + imdbid = match.Groups["imdbid"].Value; + } + + if (match.Groups["episode"].Success) + { + ep = match.Groups["episode"].Value; + } + + q = q.Replace(match.Value, ""); + } + } + + if (t == "movie") + { + var matches = MovieRegex.Matches(q); + + foreach (Match match in matches) + { + if (match.Groups["tmdbid"].Success) + { + tmdbid = int.TryParse(match.Groups["tmdbid"].Value, out var tmdb) ? tmdb : null; + } + + if (match.Groups["imdbid"].Success) + { + imdbid = match.Groups["imdbid"].Value; + } + + q = q.Replace(match.Value, "").Trim(); + } + } + + if (t == "music") + { + var matches = MusicRegex.Matches(q); + + foreach (Match match in matches) + { + if (match.Groups["artist"].Success) + { + artist = match.Groups["artist"].Value; + } + + if (match.Groups["album"].Success) + { + album = match.Groups["album"].Value; + } + + if (match.Groups["label"].Success) + { + label = match.Groups["label"].Value; + } + + q = q.Replace(match.Value, "").Trim(); + } + } + + if (t == "book") + { + var matches = BookRegex.Matches(q); + + foreach (Match match in matches) + { + if (match.Groups["author"].Success) + { + author = match.Groups["author"].Value; + } + + if (match.Groups["title"].Success) + { + title = match.Groups["title"].Value; + } + + q = q.Replace(match.Value, "").Trim(); + } + } + } } } diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 99d88cf71..16f81c7b7 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -39,6 +39,7 @@ "Apps": "Apps", "AppSettingsSummary": "Applications and settings to configure how Prowlarr interacts with your PVR programs", "AreYouSureYouWantToResetYourAPIKey": "Are you sure you want to reset your API Key?", + "AudioSearch": "Audio Search", "Auth": "Auth", "Authentication": "Authentication", "AuthenticationMethodHelpText": "Require Username and Password to access Prowlarr", @@ -53,6 +54,7 @@ "BeforeUpdate": "Before update", "BindAddress": "Bind Address", "BindAddressHelpText": "Valid IP4 address or '*' for all interfaces", + "BookSearch": "Book Search", "Branch": "Branch", "BranchUpdate": "Branch to use to update Prowlarr", "BranchUpdateMechanism": "Branch used by external update mechanism", @@ -239,6 +241,7 @@ "MovieIndexScrollBottom": "Movie Index: Scroll Bottom", "MovieIndexScrollTop": "Movie Index: Scroll Top", "Movies": "Movies", + "MovieSearch": "Movie Search", "Name": "Name", "NetCore": ".NET", "New": "New", @@ -295,6 +298,7 @@ "QualityDefinitions": "Quality Definitions", "QualitySettings": "Quality Settings", "Query": "Query", + "QueryOptions": "Query Options", "Queue": "Queue", "ReadTheWikiForMoreInformation": "Read the Wiki for more information", "Reddit": "Reddit", @@ -329,6 +333,7 @@ "ScriptPath": "Script Path", "Search": "Search", "SearchIndexers": "Search Indexers", + "SearchType": "Search Type", "Security": "Security", "Seeders": "Seeders", "SelectAll": "Select All", @@ -394,6 +399,7 @@ "Tomorrow": "Tomorrow", "Torrent": "Torrent", "Torrents": "Torrents", + "TvSearch": "TV Search", "Type": "Type", "UI": "UI", "UILanguage": "UI Language", diff --git a/src/Prowlarr.Api.V1/Search/SearchController.cs b/src/Prowlarr.Api.V1/Search/SearchController.cs index 3990026f4..f9f515901 100644 --- a/src/Prowlarr.Api.V1/Search/SearchController.cs +++ b/src/Prowlarr.Api.V1/Search/SearchController.cs @@ -52,7 +52,7 @@ namespace Prowlarr.Api.V1.Search } [HttpPost] - public ActionResult<SearchResource> Create(SearchResource release) + public ActionResult<SearchResource> GrabRelease(SearchResource release) { ValidateResource(release); @@ -75,32 +75,67 @@ namespace Prowlarr.Api.V1.Search return Ok(release); } + [HttpPost("bulk")] + public ActionResult<SearchResource> GrabReleases(List<SearchResource> releases) + { + var source = UserAgentParser.ParseSource(Request.Headers["User-Agent"]); + var host = Request.GetHostName(); + + var groupedReleases = releases.GroupBy(r => r.IndexerId); + + foreach (var indexerReleases in groupedReleases) + { + var indexerDef = _indexerFactory.Get(indexerReleases.Key); + + foreach (var release in indexerReleases) + { + ValidateResource(release); + + var releaseInfo = _remoteReleaseCache.Find(GetCacheKey(release)); + + try + { + _downloadService.SendReportToClient(releaseInfo, source, host, indexerDef.Redirect); + } + catch (ReleaseDownloadException ex) + { + _logger.Error(ex, "Getting release from indexer failed"); + } + } + } + + return Ok(releases); + } + [HttpGet] - public Task<List<SearchResource>> GetAll(string query, [FromQuery] List<int> indexerIds, [FromQuery] List<int> categories) + public Task<List<SearchResource>> GetAll(string query, [FromQuery] List<int> indexerIds, [FromQuery] List<int> categories, [FromQuery] string type = "search") { if (indexerIds.Any()) { - return GetSearchReleases(query, indexerIds, categories); + return GetSearchReleases(query, type, indexerIds, categories); } else { - return GetSearchReleases(query, null, categories); + return GetSearchReleases(query, type, null, categories); } } - private async Task<List<SearchResource>> GetSearchReleases(string query, List<int> indexerIds, List<int> categories) + private async Task<List<SearchResource>> GetSearchReleases(string query, string type, List<int> indexerIds, List<int> categories) { try { var request = new NewznabRequest { - q = query, source = "Prowlarr", - t = "search", + q = query, + t = type, + source = "Prowlarr", cat = string.Join(",", categories), server = Request.GetServerUrl(), host = Request.GetHostName() }; + request.QueryToParams(); + var result = await _nzbSearhService.Search(request, indexerIds, true); var decisions = result.Releases; From ce901ae8a36aac05ce181087e2b1abae264274ff Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 21 Nov 2021 17:46:24 -0600 Subject: [PATCH 0166/2320] Update translate.js to use createAjaxRequest --- frontend/src/Utilities/String/translate.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/frontend/src/Utilities/String/translate.js b/frontend/src/Utilities/String/translate.js index f98655c49..2858014d0 100644 --- a/frontend/src/Utilities/String/translate.js +++ b/frontend/src/Utilities/String/translate.js @@ -1,22 +1,18 @@ -import $ from 'jquery'; +import createAjaxRequest from 'Utilities/createAjaxRequest'; function getTranslations() { let localization = null; const ajaxOptions = { async: false, - type: 'GET', - global: false, dataType: 'json', - url: `${window.Prowlarr.apiRoot}/localization`, + url: '/localization', success: function(data) { localization = data.Strings; } }; - ajaxOptions.headers = ajaxOptions.headers || {}; - ajaxOptions.headers['X-Api-Key'] = window.Prowlarr.apiKey; + createAjaxRequest(ajaxOptions); - $.ajax(ajaxOptions); return localization; } From a4c92fc62935c5ddff56aefa6fc7b7cc7557920e Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 21 Nov 2021 17:57:24 -0600 Subject: [PATCH 0167/2320] Update lint packages --- package.json | 14 +- yarn.lock | 2919 ++++++++++++++++++++++---------------------------- 2 files changed, 1291 insertions(+), 1642 deletions(-) diff --git a/package.json b/package.json index 366d76dc4..33ae8b796 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ }, "devDependencies": { "@babel/core": "7.13.16", + "@babel/eslint-parser": "7.13.14", "@babel/plugin-proposal-class-properties": "7.13.0", "@babel/plugin-proposal-decorators": "7.13.15", "@babel/plugin-proposal-export-default-from": "7.12.13", @@ -91,17 +92,16 @@ "@babel/plugin-syntax-dynamic-import": "7.8.3", "@babel/preset-env": "7.13.15", "@babel/preset-react": "7.13.13", - "@babel/eslint-parser": "7.13.14", "autoprefixer": "10.2.5", "babel-loader": "8.2.2", "babel-plugin-inline-classnames": "2.0.1", "babel-plugin-transform-react-remove-prop-types": "0.4.24", "core-js": "3.11.0", "css-loader": "5.2.4", - "eslint": "7.31.0", + "eslint": "8.3.0", "eslint-plugin-filenames": "1.3.2", - "eslint-plugin-import": "2.23.4", - "eslint-plugin-react": "7.24.0", + "eslint-plugin-import": "2.25.3", + "eslint-plugin-react": "7.27.1", "eslint-plugin-simple-import-sort": "7.0.0", "esprint": "3.1.0", "file-loader": "6.2.0", @@ -121,11 +121,11 @@ "run-sequence": "2.2.1", "streamqueue": "1.1.2", "style-loader": "2.0.0", + "stylelint": "14.1.0", + "stylelint-order": "5.0.0", "url-loader": "4.1.1", "webpack": "5.35.1", "webpack-cli": "4.6.0", - "webpack-livereload-plugin": "3.0.1", - "stylelint": "13.13.1", - "stylelint-order": "4.1.0" + "webpack-livereload-plugin": "3.0.1" } } diff --git a/yarn.lock b/yarn.lock index 2d43abb17..84c7f5d61 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,24 +2,17 @@ # yarn lockfile v1 -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" + integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA== dependencies: - "@babel/highlight" "^7.10.4" + "@babel/highlight" "^7.16.0" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" - integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== - dependencies: - "@babel/highlight" "^7.12.13" - -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.13.15", "@babel/compat-data@^7.14.4": - version "7.14.4" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.4.tgz#45720fe0cecf3fd42019e1d12cc3d27fadc98d58" - integrity sha512-i2wXrWQNkH6JplJQGn3Rd2I4Pij8GdHkXwHMxm+zV5YG/Jci+bCNrWZEWC4o+umiDkRrRs4dVzH3X4GP7vyjQQ== +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.13.15", "@babel/compat-data@^7.16.0": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e" + integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q== "@babel/core@7.13.16": version "7.13.16" @@ -42,27 +35,6 @@ semver "^6.3.0" source-map "^0.5.0" -"@babel/core@>=7.9.0": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.3.tgz#5395e30405f0776067fbd9cf0884f15bfb770a38" - integrity sha512-jB5AmTKOCSJIZ72sd78ECEhuPiDMKlQdDI/4QRI6lzYATx5SSogS1oQA2AoPecRCknm30gHi2l+QVvNUu3wZAg== - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.14.3" - "@babel/helper-compilation-targets" "^7.13.16" - "@babel/helper-module-transforms" "^7.14.2" - "@babel/helpers" "^7.14.0" - "@babel/parser" "^7.14.3" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.14.2" - "@babel/types" "^7.14.2" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - semver "^6.3.0" - source-map "^0.5.0" - "@babel/eslint-parser@7.13.14": version "7.13.14" resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.13.14.tgz#f80fd23bdd839537221914cb5d17720a5ea6ba3a" @@ -72,64 +44,64 @@ eslint-visitor-keys "^1.3.0" semver "^6.3.0" -"@babel/generator@^7.13.16", "@babel/generator@^7.14.2", "@babel/generator@^7.14.3": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.3.tgz#0c2652d91f7bddab7cccc6ba8157e4f40dcedb91" - integrity sha512-bn0S6flG/j0xtQdz3hsjJ624h3W0r3llttBMfyHX3YrZ/KtLYr15bjA0FXkgW7FpvrDuTuElXeVjiKlYRpnOFA== +"@babel/generator@^7.13.16", "@babel/generator@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2" + integrity sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew== dependencies: - "@babel/types" "^7.14.2" + "@babel/types" "^7.16.0" jsesc "^2.5.1" source-map "^0.5.0" -"@babel/helper-annotate-as-pure@^7.10.4", "@babel/helper-annotate-as-pure@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz#0f58e86dfc4bb3b1fcd7db806570e177d439b6ab" - integrity sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw== +"@babel/helper-annotate-as-pure@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz#9a1f0ebcda53d9a2d00108c4ceace6a5d5f1f08d" + integrity sha512-ItmYF9vR4zA8cByDocY05o0LGUkp1zhbTQOH1NFyl5xXEqlTJQCEJjieriw+aFpxo16swMxUnUiKS7a/r4vtHg== dependencies: - "@babel/types" "^7.12.13" + "@babel/types" "^7.16.0" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz#6bc20361c88b0a74d05137a65cac8d3cbf6f61fc" - integrity sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA== +"@babel/helper-builder-binary-assignment-operator-visitor@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.0.tgz#f1a686b92da794020c26582eb852e9accd0d7882" + integrity sha512-9KuleLT0e77wFUku6TUkqZzCEymBdtuQQ27MhEKzf9UOOJu3cYj98kyaDAzxpC7lV6DGiZFuC8XqDsq8/Kl6aQ== dependencies: - "@babel/helper-explode-assignable-expression" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/helper-explode-assignable-expression" "^7.16.0" + "@babel/types" "^7.16.0" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.13", "@babel/helper-compilation-targets@^7.13.16", "@babel/helper-compilation-targets@^7.14.4": - version "7.14.4" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.4.tgz#33ebd0ffc34248051ee2089350a929ab02f2a516" - integrity sha512-JgdzOYZ/qGaKTVkn5qEDV/SXAh8KcyUVkCoSWGN8T3bwrgd6m+/dJa2kVGi6RJYJgEYPBdZ84BZp9dUjNWkBaA== +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.13", "@babel/helper-compilation-targets@^7.13.16", "@babel/helper-compilation-targets@^7.16.0": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz#5b480cd13f68363df6ec4dc8ac8e2da11363cbf0" + integrity sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA== dependencies: - "@babel/compat-data" "^7.14.4" - "@babel/helper-validator-option" "^7.12.17" - browserslist "^4.16.6" + "@babel/compat-data" "^7.16.0" + "@babel/helper-validator-option" "^7.14.5" + browserslist "^4.17.5" semver "^6.3.0" -"@babel/helper-create-class-features-plugin@^7.13.0", "@babel/helper-create-class-features-plugin@^7.13.11": - version "7.14.4" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.4.tgz#abf888d836a441abee783c75229279748705dc42" - integrity sha512-idr3pthFlDCpV+p/rMgGLGYIVtazeatrSOQk8YzO2pAepIjQhCN3myeihVg58ax2bbbGK9PUE1reFi7axOYIOw== +"@babel/helper-create-class-features-plugin@^7.13.0", "@babel/helper-create-class-features-plugin@^7.13.11", "@babel/helper-create-class-features-plugin@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.0.tgz#090d4d166b342a03a9fec37ef4fd5aeb9c7c6a4b" + integrity sha512-XLwWvqEaq19zFlF5PTgOod4bUA+XbkR4WLQBct1bkzmxJGB0ZEJaoKF4c8cgH9oBtCDuYJ8BP5NB9uFiEgO5QA== dependencies: - "@babel/helper-annotate-as-pure" "^7.12.13" - "@babel/helper-function-name" "^7.14.2" - "@babel/helper-member-expression-to-functions" "^7.13.12" - "@babel/helper-optimise-call-expression" "^7.12.13" - "@babel/helper-replace-supers" "^7.14.4" - "@babel/helper-split-export-declaration" "^7.12.13" + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-member-expression-to-functions" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" -"@babel/helper-create-regexp-features-plugin@^7.12.13": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.3.tgz#149aa6d78c016e318c43e2409a0ae9c136a86688" - integrity sha512-JIB2+XJrb7v3zceV2XzDhGIB902CmKGSpSl4q2C6agU9SNLG/2V1RtFRGPG1Ajh9STj3+q6zJMOC+N/pp2P9DA== +"@babel/helper-create-regexp-features-plugin@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.0.tgz#06b2348ce37fccc4f5e18dcd8d75053f2a7c44ff" + integrity sha512-3DyG0zAFAZKcOp7aVr33ddwkxJ0Z0Jr5V99y3I690eYLpukJsJvAbzTy1ewoCqsML8SbIrjH14Jc/nSQ4TvNPA== dependencies: - "@babel/helper-annotate-as-pure" "^7.12.13" + "@babel/helper-annotate-as-pure" "^7.16.0" regexpu-core "^4.7.1" -"@babel/helper-define-polyfill-provider@^0.2.2": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz#0525edec5094653a282688d34d846e4c75e9c0b6" - integrity sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew== +"@babel/helper-define-polyfill-provider@^0.2.2", "@babel/helper-define-polyfill-provider@^0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.4.tgz#8867aed79d3ea6cade40f801efb7ac5c66916b10" + integrity sha512-OrpPZ97s+aPi6h2n1OXzdhVis1SGSsMU2aMHgLcOKfsp4/v1NWpx3CWT3lBj5eeBq9cDkPkh+YCfdF7O12uNDQ== dependencies: "@babel/helper-compilation-targets" "^7.13.0" "@babel/helper-module-imports" "^7.12.13" @@ -140,179 +112,178 @@ resolve "^1.14.2" semver "^6.1.2" -"@babel/helper-explode-assignable-expression@^7.12.13": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz#17b5c59ff473d9f956f40ef570cf3a76ca12657f" - integrity sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA== +"@babel/helper-explode-assignable-expression@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz#753017337a15f46f9c09f674cff10cee9b9d7778" + integrity sha512-Hk2SLxC9ZbcOhLpg/yMznzJ11W++lg5GMbxt1ev6TXUiJB0N42KPC+7w8a+eWGuqDnUYuwStJoZHM7RgmIOaGQ== dependencies: - "@babel/types" "^7.13.0" + "@babel/types" "^7.16.0" -"@babel/helper-function-name@^7.12.13", "@babel/helper-function-name@^7.14.2": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.14.2.tgz#397688b590760b6ef7725b5f0860c82427ebaac2" - integrity sha512-NYZlkZRydxw+YT56IlhIcS8PAhb+FEUiOzuhFTfqDyPmzAhRge6ua0dQYT/Uh0t/EDHq05/i+e5M2d4XvjgarQ== +"@babel/helper-function-name@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481" + integrity sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog== dependencies: - "@babel/helper-get-function-arity" "^7.12.13" - "@babel/template" "^7.12.13" - "@babel/types" "^7.14.2" + "@babel/helper-get-function-arity" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/types" "^7.16.0" -"@babel/helper-get-function-arity@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583" - integrity sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg== +"@babel/helper-get-function-arity@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa" + integrity sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ== dependencies: - "@babel/types" "^7.12.13" + "@babel/types" "^7.16.0" -"@babel/helper-hoist-variables@^7.13.0": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.16.tgz#1b1651249e94b51f8f0d33439843e33e39775b30" - integrity sha512-1eMtTrXtrwscjcAeO4BVK+vvkxaLJSPFz1w1KLawz6HLNi9bPFGBNwwDyVfiu1Tv/vRRFYfoGaKhmAQPGPn5Wg== +"@babel/helper-hoist-variables@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a" + integrity sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg== dependencies: - "@babel/traverse" "^7.13.15" - "@babel/types" "^7.13.16" + "@babel/types" "^7.16.0" -"@babel/helper-member-expression-to-functions@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz#dfe368f26d426a07299d8d6513821768216e6d72" - integrity sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw== +"@babel/helper-member-expression-to-functions@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz#29287040efd197c77636ef75188e81da8bccd5a4" + integrity sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ== dependencies: - "@babel/types" "^7.13.12" + "@babel/types" "^7.16.0" -"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977" - integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA== +"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3" + integrity sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg== dependencies: - "@babel/types" "^7.13.12" + "@babel/types" "^7.16.0" -"@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.13.14", "@babel/helper-module-transforms@^7.14.0", "@babel/helper-module-transforms@^7.14.2": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.2.tgz#ac1cc30ee47b945e3e0c4db12fa0c5389509dfe5" - integrity sha512-OznJUda/soKXv0XhpvzGWDnml4Qnwp16GN+D/kZIdLsWoHj05kyu8Rm5kXmMef+rVJZ0+4pSGLkeixdqNUATDA== +"@babel/helper-module-transforms@^7.13.14", "@babel/helper-module-transforms@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5" + integrity sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA== dependencies: - "@babel/helper-module-imports" "^7.13.12" - "@babel/helper-replace-supers" "^7.13.12" - "@babel/helper-simple-access" "^7.13.12" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/helper-validator-identifier" "^7.14.0" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.14.2" - "@babel/types" "^7.14.2" + "@babel/helper-module-imports" "^7.16.0" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-simple-access" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/helper-validator-identifier" "^7.15.7" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" -"@babel/helper-optimise-call-expression@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea" - integrity sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA== +"@babel/helper-optimise-call-expression@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338" + integrity sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw== dependencies: - "@babel/types" "^7.12.13" + "@babel/types" "^7.16.0" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af" - integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ== +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" + integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== -"@babel/helper-remap-async-to-generator@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz#376a760d9f7b4b2077a9dd05aa9c3927cadb2209" - integrity sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg== +"@babel/helper-remap-async-to-generator@^7.16.0", "@babel/helper-remap-async-to-generator@^7.16.4": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.4.tgz#5d7902f61349ff6b963e07f06a389ce139fbfe6e" + integrity sha512-vGERmmhR+s7eH5Y/cp8PCVzj4XEjerq8jooMfxFdA5xVtAk9Sh4AQsrWgiErUEBjtGrBtOFKDUcWQFW4/dFwMA== dependencies: - "@babel/helper-annotate-as-pure" "^7.12.13" - "@babel/helper-wrap-function" "^7.13.0" - "@babel/types" "^7.13.0" + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-wrap-function" "^7.16.0" + "@babel/types" "^7.16.0" -"@babel/helper-replace-supers@^7.12.13", "@babel/helper-replace-supers@^7.13.12", "@babel/helper-replace-supers@^7.14.4": - version "7.14.4" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.14.4.tgz#b2ab16875deecfff3ddfcd539bc315f72998d836" - integrity sha512-zZ7uHCWlxfEAAOVDYQpEf/uyi1dmeC7fX4nCf2iz9drnCwi1zvwXL3HwWWNXUQEJ1k23yVn3VbddiI9iJEXaTQ== +"@babel/helper-replace-supers@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz#73055e8d3cf9bcba8ddb55cad93fedc860f68f17" + integrity sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA== dependencies: - "@babel/helper-member-expression-to-functions" "^7.13.12" - "@babel/helper-optimise-call-expression" "^7.12.13" - "@babel/traverse" "^7.14.2" - "@babel/types" "^7.14.4" + "@babel/helper-member-expression-to-functions" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" -"@babel/helper-simple-access@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6" - integrity sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA== +"@babel/helper-simple-access@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz#21d6a27620e383e37534cf6c10bba019a6f90517" + integrity sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw== dependencies: - "@babel/types" "^7.13.12" + "@babel/types" "^7.16.0" -"@babel/helper-skip-transparent-expression-wrappers@^7.12.1": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz#462dc63a7e435ade8468385c63d2b84cce4b3cbf" - integrity sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA== +"@babel/helper-skip-transparent-expression-wrappers@^7.12.1", "@babel/helper-skip-transparent-expression-wrappers@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" + integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== dependencies: - "@babel/types" "^7.12.1" + "@babel/types" "^7.16.0" -"@babel/helper-split-export-declaration@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz#e9430be00baf3e88b0e13e6f9d4eaf2136372b05" - integrity sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg== +"@babel/helper-split-export-declaration@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438" + integrity sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw== dependencies: - "@babel/types" "^7.12.13" + "@babel/types" "^7.16.0" -"@babel/helper-validator-identifier@^7.12.11", "@babel/helper-validator-identifier@^7.14.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" - integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== +"@babel/helper-validator-identifier@^7.15.7": + version "7.15.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" + integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== -"@babel/helper-validator-option@^7.12.17": - version "7.12.17" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" - integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw== +"@babel/helper-validator-option@^7.12.17", "@babel/helper-validator-option@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" + integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== -"@babel/helper-wrap-function@^7.12.13", "@babel/helper-wrap-function@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz#bdb5c66fda8526ec235ab894ad53a1235c79fcc4" - integrity sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA== +"@babel/helper-wrap-function@^7.12.13", "@babel/helper-wrap-function@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.0.tgz#b3cf318afce774dfe75b86767cd6d68f3482e57c" + integrity sha512-VVMGzYY3vkWgCJML+qVLvGIam902mJW0FvT7Avj1zEe0Gn7D93aWdLblYARTxEw+6DhZmtzhBM2zv0ekE5zg1g== dependencies: - "@babel/helper-function-name" "^7.12.13" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.0" - "@babel/types" "^7.13.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" -"@babel/helpers@^7.13.16", "@babel/helpers@^7.14.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.14.0.tgz#ea9b6be9478a13d6f961dbb5f36bf75e2f3b8f62" - integrity sha512-+ufuXprtQ1D1iZTO/K9+EBRn+qPWMJjZSw/S0KlFrxCw4tkrzv9grgpDHkY9MeQTjTY8i2sp7Jep8DfU6tN9Mg== +"@babel/helpers@^7.13.16": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.3.tgz#27fc64f40b996e7074dc73128c3e5c3e7f55c43c" + integrity sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w== dependencies: - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.14.0" - "@babel/types" "^7.14.0" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.3" + "@babel/types" "^7.16.0" -"@babel/highlight@^7.10.4", "@babel/highlight@^7.12.13": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.0.tgz#3197e375711ef6bf834e67d0daec88e4f46113cf" - integrity sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg== +"@babel/highlight@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a" + integrity sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g== dependencies: - "@babel/helper-validator-identifier" "^7.14.0" + "@babel/helper-validator-identifier" "^7.15.7" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.12.13", "@babel/parser@^7.13.16", "@babel/parser@^7.14.2", "@babel/parser@^7.14.3": - version "7.14.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.4.tgz#a5c560d6db6cd8e6ed342368dea8039232cbab18" - integrity sha512-ArliyUsWDUqEGfWcmzpGUzNfLxTdTp6WU4IuP6QFSp9gGfWS6boxFCkJSJ/L4+RG8z/FnIU3WxCk6hPL9SSWeA== +"@babel/parser@^7.13.16", "@babel/parser@^7.16.0", "@babel/parser@^7.16.3": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e" + integrity sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng== "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.13.12.tgz#a3484d84d0b549f3fc916b99ee4783f26fabad2a" - integrity sha512-d0u3zWKcoZf379fOeJdr1a5WPDny4aOFZ6hlfKivgK0LY7ZxNfoaHL2fWwdGtHyVvra38FC+HVYkO+byfSA8AQ== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.0.tgz#358972eaab006f5eb0826183b0c93cbcaf13e1e2" + integrity sha512-4tcFwwicpWTrpl9qjf7UsoosaArgImF85AxqCRZlgc3IQDvkUHjJpruXAL58Wmj+T6fypWTC/BakfEkwIL/pwA== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" - "@babel/plugin-proposal-optional-chaining" "^7.13.12" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-proposal-optional-chaining" "^7.16.0" "@babel/plugin-proposal-async-generator-functions@^7.13.15": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.2.tgz#3a2085abbf5d5f962d480dbc81347385ed62eb1e" - integrity sha512-b1AM4F6fwck4N8ItZ/AtC4FP/cqZqmKRQ4FaTDutwSYyjuhtvsGEMLK4N/ztV/ImP40BjIDyMgBQAeAMsQYVFQ== + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.4.tgz#e606eb6015fec6fa5978c940f315eae4e300b081" + integrity sha512-/CUekqaAaZCQHleSK/9HajvcD/zdnJiKRiuUFq8ITE+0HsPzquf53cpFiqAwl/UfmJbR6n5uGPQSPdrmKOvHHg== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-remap-async-to-generator" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.16.4" "@babel/plugin-syntax-async-generators" "^7.8.4" -"@babel/plugin-proposal-class-properties@7.13.0", "@babel/plugin-proposal-class-properties@^7.13.0": +"@babel/plugin-proposal-class-properties@7.13.0": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz#146376000b94efd001e57a40a88a525afaab9f37" integrity sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg== @@ -320,6 +291,14 @@ "@babel/helper-create-class-features-plugin" "^7.13.0" "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-proposal-class-properties@^7.13.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.0.tgz#c029618267ddebc7280fa286e0f8ca2a278a2d1a" + integrity sha512-mCF3HcuZSY9Fcx56Lbn+CGdT44ioBMMvjNVldpKtj8tpniETdLjnxdHI1+sDWXIM1nNt+EanJOZ3IG9lzVjs7A== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-proposal-decorators@7.13.15": version "7.13.15" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.13.15.tgz#e91ccfef2dc24dd5bd5dcc9fc9e2557c684ecfb8" @@ -330,11 +309,11 @@ "@babel/plugin-syntax-decorators" "^7.12.13" "@babel/plugin-proposal-dynamic-import@^7.13.8": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.2.tgz#01ebabd7c381cff231fa43e302939a9de5be9d9f" - integrity sha512-oxVQZIWFh91vuNEMKltqNsKLFWkOIyJc95k2Gv9lWVyDfPUQGSSlbDEgWuJUU1afGE9WwlzpucMZ3yDRHIItkA== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.0.tgz#783eca61d50526202f9b296095453977e88659f1" + integrity sha512-QGSA6ExWk95jFQgwz5GQ2Dr95cf7eI7TKutIXXTb7B1gCLTCz5hTjFTQGfLFBBiC5WSNi7udNwWsqbbMh1c4yQ== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-dynamic-import" "^7.8.3" "@babel/plugin-proposal-export-default-from@7.12.13": @@ -354,11 +333,11 @@ "@babel/plugin-syntax-export-namespace-from" "^7.8.3" "@babel/plugin-proposal-export-namespace-from@^7.12.13": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.2.tgz#62542f94aa9ce8f6dba79eec698af22112253791" - integrity sha512-sRxW3z3Zp3pFfLAgVEvzTFutTXax837oOatUIvSG9o5gRj9mKwm3br1Se5f4QalTQs9x4AzlA/HrCWbQIHASUQ== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.0.tgz#9c01dee40b9d6b847b656aaf4a3976a71740f222" + integrity sha512-CjI4nxM/D+5wCnhD11MHB1AwRSAYeDT+h8gCdcVJZ/OK7+wRzFsf7PFPWVpVpNRkHMmMkQWAHpTq+15IXQ1diA== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" "@babel/plugin-proposal-function-sent@7.12.13": @@ -371,19 +350,19 @@ "@babel/plugin-syntax-function-sent" "^7.12.13" "@babel/plugin-proposal-json-strings@^7.13.8": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.2.tgz#830b4e2426a782e8b2878fbfe2cba85b70cbf98c" - integrity sha512-w2DtsfXBBJddJacXMBhElGEYqCZQqN99Se1qeYn8DVLB33owlrlLftIbMzn5nz1OITfDVknXF433tBrLEAOEjA== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.0.tgz#cae35a95ed1d2a7fa29c4dc41540b84a72e9ab25" + integrity sha512-kouIPuiv8mSi5JkEhzApg5Gn6hFyKPnlkO0a9YSzqRurH8wYzSlf6RJdzluAsbqecdW5pBvDJDfyDIUR/vLxvg== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-json-strings" "^7.8.3" "@babel/plugin-proposal-logical-assignment-operators@^7.13.8": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.2.tgz#222348c080a1678e0e74ea63fe76f275882d1fd7" - integrity sha512-1JAZtUrqYyGsS7IDmFeaem+/LJqujfLZ2weLR9ugB0ufUPjzf8cguyVT1g5im7f7RXxuLq1xUxEzvm68uYRtGg== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.0.tgz#a711b8ceb3ffddd3ef88d3a49e86dbd3cc7db3fd" + integrity sha512-pbW0fE30sVTYXXm9lpVQQ/Vc+iTeQKiXlaNRZPPN2A2VdlWyAtsUrsQ3xydSlDW00TFMK7a8m3cDTkBF5WnV3Q== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-proposal-nullish-coalescing-operator@7.13.8": @@ -395,11 +374,11 @@ "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" "@babel/plugin-proposal-nullish-coalescing-operator@^7.13.8": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.2.tgz#425b11dc62fc26939a2ab42cbba680bdf5734546" - integrity sha512-ebR0zU9OvI2N4qiAC38KIAK75KItpIPTpAtd2r4OZmMFeKbKJpUFLYP2EuDut82+BmYi8sz42B+TfTptJ9iG5Q== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.0.tgz#44e1cce08fe2427482cf446a91bb451528ed0596" + integrity sha512-3bnHA8CAFm7cG93v8loghDYyQ8r97Qydf63BeYiGgYbjKKB/XP53W15wfRC7dvKfoiJ34f6Rbyyx2btExc8XsQ== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" "@babel/plugin-proposal-numeric-separator@7.12.13": @@ -411,30 +390,30 @@ "@babel/plugin-syntax-numeric-separator" "^7.10.4" "@babel/plugin-proposal-numeric-separator@^7.12.13": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.2.tgz#82b4cc06571143faf50626104b335dd71baa4f9e" - integrity sha512-DcTQY9syxu9BpU3Uo94fjCB3LN9/hgPS8oUL7KrSW3bA2ePrKZZPJcc5y0hoJAM9dft3pGfErtEUvxXQcfLxUg== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.0.tgz#5d418e4fbbf8b9b7d03125d3a52730433a373734" + integrity sha512-FAhE2I6mjispy+vwwd6xWPyEx3NYFS13pikDBWUAFGZvq6POGs5eNchw8+1CYoEgBl9n11I3NkzD7ghn25PQ9Q== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-numeric-separator" "^7.10.4" "@babel/plugin-proposal-object-rest-spread@^7.13.8": - version "7.14.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.4.tgz#0e2b4de419915dc0b409378e829412e2031777c4" - integrity sha512-AYosOWBlyyXEagrPRfLJ1enStufsr7D1+ddpj8OLi9k7B6+NdZ0t/9V7Fh+wJ4g2Jol8z2JkgczYqtWrZd4vbA== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.0.tgz#5fb32f6d924d6e6712810362a60e12a2609872e6" + integrity sha512-LU/+jp89efe5HuWJLmMmFG0+xbz+I2rSI7iLc1AlaeSMDMOGzWlc5yJrMN1d04osXN4sSfpo4O+azkBNBes0jg== dependencies: - "@babel/compat-data" "^7.14.4" - "@babel/helper-compilation-targets" "^7.14.4" - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/compat-data" "^7.16.0" + "@babel/helper-compilation-targets" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.14.2" + "@babel/plugin-transform-parameters" "^7.16.0" "@babel/plugin-proposal-optional-catch-binding@^7.13.8": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.2.tgz#150d4e58e525b16a9a1431bd5326c4eed870d717" - integrity sha512-XtkJsmJtBaUbOxZsNk0Fvrv8eiqgneug0A6aqLFZ4TSkar2L5dSXWcnUKHgmjJt49pyB/6ZHvkr3dPgl9MOWRQ== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.0.tgz#5910085811ab4c28b00d6ebffa4ab0274d1e5f16" + integrity sha512-kicDo0A/5J0nrsCPbn89mTG3Bm4XgYi0CZtvex9Oyw7gGZE3HXGD0zpQNH+mo+tEfbo8wbmMvJftOwpmPy7aVw== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-proposal-optional-chaining@7.13.12": @@ -446,22 +425,22 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -"@babel/plugin-proposal-optional-chaining@^7.13.12": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.2.tgz#df8171a8b9c43ebf4c1dabe6311b432d83e1b34e" - integrity sha512-qQByMRPwMZJainfig10BoaDldx/+VDtNcrA7qdNaEOAj6VXud+gfrkA8j4CRAU5HjnWREXqIpSpH30qZX1xivA== +"@babel/plugin-proposal-optional-chaining@^7.13.12", "@babel/plugin-proposal-optional-chaining@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.0.tgz#56dbc3970825683608e9efb55ea82c2a2d6c8dc0" + integrity sha512-Y4rFpkZODfHrVo70Uaj6cC1JJOt3Pp0MdWSwIKtb8z1/lsjl9AmnB7ErRFV+QNGIfcY1Eruc2UMx5KaRnXjMyg== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-proposal-private-methods@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.13.0.tgz#04bd4c6d40f6e6bbfa2f57e2d8094bad900ef787" - integrity sha512-MXyyKQd9inhx1kDYPkFRVOBXQ20ES8Pto3T7UZ92xj2mY0EVD8oAVzeyYuVfy/mxAdTSIayOvg+aVzcHV2bn6Q== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.0.tgz#b4dafb9c717e4301c5776b30d080d6383c89aff6" + integrity sha512-IvHmcTHDFztQGnn6aWq4t12QaBXTKr1whF/dgp9kz84X6GUcwq9utj7z2wFCUfeOup/QKnOlt2k0zxkGFx9ubg== dependencies: - "@babel/helper-create-class-features-plugin" "^7.13.0" - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-proposal-throw-expressions@7.12.13": version "7.12.13" @@ -472,12 +451,12 @@ "@babel/plugin-syntax-throw-expressions" "^7.12.13" "@babel/plugin-proposal-unicode-property-regex@^7.12.13", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz#bebde51339be829c17aaaaced18641deb62b39ba" - integrity sha512-XyJmZidNfofEkqFV5VC/bLabGmO5QzenPO/YOfGuEbgU+2sSwMmio3YLb4WtBgcmmdwZHyVyv8on77IUjQ5Gvg== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.0.tgz#890482dfc5ea378e42e19a71e709728cabf18612" + integrity sha512-ti7IdM54NXv29cA4+bNNKEMS4jLMCbJgl+Drv+FgYy0erJLAxNAIXcNjNjrRZEcWq0xJHsNVwQezskMFpF8N9g== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.12.13" - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -494,11 +473,11 @@ "@babel/helper-plugin-utils" "^7.12.13" "@babel/plugin-syntax-decorators@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.12.13.tgz#fac829bf3c7ef4a1bc916257b403e58c6bdaf648" - integrity sha512-Rw6aIXGuqDLr6/LoBBYE57nKOzQpz/aDkKlMqEwH+Vp0MXbG6H/TfRjaY343LKxzAKAMXIHsQ8JzaZKuDZ9MwA== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.16.0.tgz#eb8d811cdd1060f6ac3c00956bf3f6335505a32f" + integrity sha512-nxnnngZClvlY13nHJAIDow0S7Qzhq64fQ/NlqS+VER3kjW/4F0jLhXjeL8jcwSwz6Ca3rotT5NJD2T9I7lcv7g== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-dynamic-import@7.8.3", "@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" @@ -508,11 +487,11 @@ "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-export-default-from@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.12.13.tgz#3c807d37efaf0a806f1deb556ccb3b2f562ae9c2" - integrity sha512-gVry0zqoums0hA+EniCYK3gABhjYSLX1dVuwYpPw9DrLNA4/GovXySHVg4FGRsZht09ON/5C2NVx3keq+qqVGQ== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.16.0.tgz#648520667776781f9a0da178f245fff85bc9e36f" + integrity sha512-xllLOdBj77mFSw8s02I+2SSQGHOftbWTlGmagheuNk/gjQsk7IrYsR/EosXVAVpgIUFffLckB/iPRioQYLHSrQ== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-export-namespace-from@^7.8.3": version "7.8.3" @@ -522,11 +501,11 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-function-sent@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-function-sent/-/plugin-syntax-function-sent-7.12.13.tgz#60cb34f7395b0325ffbb5b0794cd5b88e23e1928" - integrity sha512-Uv9lAv+/vX8hmvC2rTUvywJacR517eRqTKfLZrtLAoMGUjfQSZ0nPEFJWmfJs1H54zBaIj15ATfUnkheZnSK9w== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-function-sent/-/plugin-syntax-function-sent-7.16.0.tgz#c6e0eb280a101cd7bdaf6d3f750eb27b59978c48" + integrity sha512-CrwPwHy+ks1xokbZ5x2ZbRwZ5qptN0PE/N5M+o8eQ2LHXGFxlSuDVx515crT7DxUnT+uKctKDuk0NAwG7c1Ebw== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" @@ -535,12 +514,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.13.tgz#044fb81ebad6698fe62c478875575bcbb9b70f15" - integrity sha512-d4HM23Q1K7oq/SLNmG6mRt85l2csmQ0cHRaxRXjKW0YFdEXqlZ5kzFQKH5Uc3rDJECgu+yCRgPkG04Mm98R/1g== +"@babel/plugin-syntax-jsx@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.0.tgz#f9624394317365a9a88c82358d3f8471154698f1" + integrity sha512-8zv2+xiPHwly31RK4RmnEYY5zziuF3O7W2kIDW+07ewWDh6Oi0dRq8kwvulRkFgt6DB97RlKs5c1y068iPlCUg== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" @@ -585,299 +564,299 @@ "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-throw-expressions@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-throw-expressions/-/plugin-syntax-throw-expressions-7.12.13.tgz#bb02bfbaf57d71ab69280ebf6a53aa45ad4c3f1a" - integrity sha512-vbpx/IxHR3qqWEfYeiVLq4+RFj2F4GjsMzoXEx/YU/pgmTA6o7T92DQHWIeetg7msKQFnyG1PwmPLWMlAn+Fmg== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-throw-expressions/-/plugin-syntax-throw-expressions-7.16.0.tgz#9d5fc5c185617bc5f727fbecc360601a52cf6879" + integrity sha512-tr5wm8EYRpFW47uVJ2B660pJQXgmeCShz82tE6LkIVkcLzXMz5xhj0drYyehuAl1utNGFqPnMmjpzs5zavAbNQ== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-top-level-await@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz#c5f0fa6e249f5b739727f923540cf7a806130178" - integrity sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ== + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-arrow-functions@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz#10a59bebad52d637a027afa692e8d5ceff5e3dae" - integrity sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.0.tgz#951706f8b449c834ed07bd474c0924c944b95a8e" + integrity sha512-vIFb5250Rbh7roWARvCLvIJ/PtAU5Lhv7BtZ1u24COwpI9Ypjsh+bZcKk6rlIyalK+r0jOc1XQ8I4ovNxNrWrA== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-async-to-generator@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz#8e112bf6771b82bf1e974e5e26806c5c99aa516f" - integrity sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.0.tgz#df12637f9630ddfa0ef9d7a11bc414d629d38604" + integrity sha512-PbIr7G9kR8tdH6g8Wouir5uVjklETk91GMVSUq+VaOgiinbCkBP6Q7NN/suM/QutZkMJMvcyAriogcYAdhg8Gw== dependencies: - "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-remap-async-to-generator" "^7.13.0" + "@babel/helper-module-imports" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.16.0" "@babel/plugin-transform-block-scoped-functions@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz#a9bf1836f2a39b4eb6cf09967739de29ea4bf4c4" - integrity sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.0.tgz#c618763233ad02847805abcac4c345ce9de7145d" + integrity sha512-V14As3haUOP4ZWrLJ3VVx5rCnrYhMSHN/jX7z6FAt5hjRkLsb0snPCmJwSOML5oxkKO4FNoNv7V5hw/y2bjuvg== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-block-scoping@^7.12.13": - version "7.14.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.4.tgz#caf140b0b2e2462c509553d140e6d0abefb61ed8" - integrity sha512-5KdpkGxsZlTk+fPleDtGKsA+pon28+ptYmMO8GBSa5fHERCJWAzj50uAfCKBqq42HO+Zot6JF1x37CRprwmN4g== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.0.tgz#bcf433fb482fe8c3d3b4e8a66b1c4a8e77d37c16" + integrity sha512-27n3l67/R3UrXfizlvHGuTwsRIFyce3D/6a37GRxn28iyTPvNXaW4XvznexRh1zUNLPjbLL22Id0XQElV94ruw== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-classes@^7.13.0": - version "7.14.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.4.tgz#a83c15503fc71a0f99e876fdce7dadbc6575ec3a" - integrity sha512-p73t31SIj6y94RDVX57rafVjttNr8MvKEgs5YFatNB/xC68zM3pyosuOEcQmYsYlyQaGY9R7rAULVRcat5FKJQ== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.0.tgz#54cf5ff0b2242c6573d753cd4bfc7077a8b282f5" + integrity sha512-HUxMvy6GtAdd+GKBNYDWCIA776byUQH8zjnfjxwT1P1ARv/wFu8eBDpmXQcLS/IwRtrxIReGiplOwMeyO7nsDQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.12.13" - "@babel/helper-function-name" "^7.14.2" - "@babel/helper-optimise-call-expression" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-replace-supers" "^7.14.4" - "@babel/helper-split-export-declaration" "^7.12.13" + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" globals "^11.1.0" "@babel/plugin-transform-computed-properties@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz#845c6e8b9bb55376b1fa0b92ef0bdc8ea06644ed" - integrity sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.0.tgz#e0c385507d21e1b0b076d66bed6d5231b85110b7" + integrity sha512-63l1dRXday6S8V3WFY5mXJwcRAnPYxvFfTlt67bwV1rTyVTM5zrp0DBBb13Kl7+ehkCVwIZPumPpFP/4u70+Tw== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-destructuring@^7.13.0": - version "7.14.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.4.tgz#acbec502e9951f30f4441eaca1d2f29efade59ed" - integrity sha512-JyywKreTCGTUsL1OKu1A3ms/R1sTP0WxbpXlALeGzF53eB3bxtNkYdMj9SDgK7g6ImPy76J5oYYKoTtQImlhQA== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.0.tgz#ad3d7e74584ad5ea4eadb1e6642146c590dee33c" + integrity sha512-Q7tBUwjxLTsHEoqktemHBMtb3NYwyJPTJdM+wDwb0g8PZ3kQUIzNvwD5lPaqW/p54TXBc/MXZu9Jr7tbUEUM8Q== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-dotall-regex@^7.12.13", "@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz#3f1601cc29905bfcb67f53910f197aeafebb25ad" - integrity sha512-foDrozE65ZFdUC2OfgeOCrEPTxdB3yjqxpXh8CH+ipd9CHd4s/iq81kcUpyH8ACGNEPdFqbtzfgzbT/ZGlbDeQ== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.0.tgz#50bab00c1084b6162d0a58a818031cf57798e06f" + integrity sha512-FXlDZfQeLILfJlC6I1qyEwcHK5UpRCFkaoVyA1nk9A1L1Yu583YO4un2KsLBsu3IJb4CUbctZks8tD9xPQubLw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.12.13" - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-duplicate-keys@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.13.tgz#6f06b87a8b803fd928e54b81c258f0a0033904de" - integrity sha512-NfADJiiHdhLBW3pulJlJI2NB0t4cci4WTZ8FtdIuNc2+8pslXdPtRRAEWqUY+m9kNOk2eRYbTAOipAxlrOcwwQ== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.0.tgz#8bc2e21813e3e89e5e5bf3b60aa5fc458575a176" + integrity sha512-LIe2kcHKAZOJDNxujvmp6z3mfN6V9lJxubU4fJIGoQCkKe3Ec2OcbdlYP+vW++4MpxwG0d1wSDOJtQW5kLnkZQ== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-exponentiation-operator@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz#4d52390b9a273e651e4aba6aee49ef40e80cd0a1" - integrity sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.0.tgz#a180cd2881e3533cef9d3901e48dad0fbeff4be4" + integrity sha512-OwYEvzFI38hXklsrbNivzpO3fh87skzx8Pnqi4LoSYeav0xHlueSoCJrSgTPfnbyzopo5b3YVAJkFIcUpK2wsw== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.12.13" - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-for-of@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz#c799f881a8091ac26b54867a845c3e97d2696062" - integrity sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.0.tgz#f7abaced155260e2461359bbc7c7248aca5e6bd2" + integrity sha512-5QKUw2kO+GVmKr2wMYSATCTTnHyscl6sxFRAY+rvN7h7WB0lcG0o4NoV6ZQU32OZGVsYUsfLGgPQpDFdkfjlJQ== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-function-name@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz#bb024452f9aaed861d374c8e7a24252ce3a50051" - integrity sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.0.tgz#02e3699c284c6262236599f751065c5d5f1f400e" + integrity sha512-lBzMle9jcOXtSOXUpc7tvvTpENu/NuekNJVova5lCCWCV9/U1ho2HH2y0p6mBg8fPm/syEAbfaaemYGOHCY3mg== dependencies: - "@babel/helper-function-name" "^7.12.13" - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-literals@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz#2ca45bafe4a820197cf315794a4d26560fe4bdb9" - integrity sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.0.tgz#79711e670ffceb31bd298229d50f3621f7980cac" + integrity sha512-gQDlsSF1iv9RU04clgXqRjrPyyoJMTclFt3K1cjLmTKikc0s/6vE3hlDeEVC71wLTRu72Fq7650kABrdTc2wMQ== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-member-expression-literals@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz#5ffa66cd59b9e191314c9f1f803b938e8c081e40" - integrity sha512-kxLkOsg8yir4YeEPHLuO2tXP9R/gTjpuTOjshqSpELUN3ZAg2jfDnKUvzzJxObun38sw3wm4Uu69sX/zA7iRvg== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.0.tgz#5251b4cce01eaf8314403d21aedb269d79f5e64b" + integrity sha512-WRpw5HL4Jhnxw8QARzRvwojp9MIE7Tdk3ez6vRyUk1MwgjJN0aNpRoXainLR5SgxmoXx/vsXGZ6OthP6t/RbUg== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-modules-amd@^7.13.0": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.2.tgz#6622806fe1a7c07a1388444222ef9535f2ca17b0" - integrity sha512-hPC6XBswt8P3G2D1tSV2HzdKvkqOpmbyoy+g73JG0qlF/qx2y3KaMmXb1fLrpmWGLZYA0ojCvaHdzFWjlmV+Pw== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.0.tgz#09abd41e18dcf4fd479c598c1cef7bd39eb1337e" + integrity sha512-rWFhWbCJ9Wdmzln1NmSCqn7P0RAD+ogXG/bd9Kg5c7PKWkJtkiXmYsMBeXjDlzHpVTJ4I/hnjs45zX4dEv81xw== dependencies: - "@babel/helper-module-transforms" "^7.14.2" - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-commonjs@^7.13.8": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.0.tgz#52bc199cb581e0992edba0f0f80356467587f161" - integrity sha512-EX4QePlsTaRZQmw9BsoPeyh5OCtRGIhwfLquhxGp5e32w+dyL8htOcDwamlitmNFK6xBZYlygjdye9dbd9rUlQ== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.0.tgz#add58e638c8ddc4875bd9a9ecb5c594613f6c922" + integrity sha512-Dzi+NWqyEotgzk/sb7kgQPJQf7AJkQBWsVp1N6JWc1lBVo0vkElUnGdr1PzUBmfsCCN5OOFya3RtpeHk15oLKQ== dependencies: - "@babel/helper-module-transforms" "^7.14.0" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-simple-access" "^7.13.12" + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-simple-access" "^7.16.0" babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-systemjs@^7.13.8": - version "7.13.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.13.8.tgz#6d066ee2bff3c7b3d60bf28dec169ad993831ae3" - integrity sha512-hwqctPYjhM6cWvVIlOIe27jCIBgHCsdH2xCJVAYQm7V5yTMoilbVMi9f6wKg0rpQAOn6ZG4AOyvCqFF/hUh6+A== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.0.tgz#a92cf240afeb605f4ca16670453024425e421ea4" + integrity sha512-yuGBaHS3lF1m/5R+6fjIke64ii5luRUg97N2wr+z1sF0V+sNSXPxXDdEEL/iYLszsN5VKxVB1IPfEqhzVpiqvg== dependencies: - "@babel/helper-hoist-variables" "^7.13.0" - "@babel/helper-module-transforms" "^7.13.0" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-validator-identifier" "^7.12.11" + "@babel/helper-hoist-variables" "^7.16.0" + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-identifier" "^7.15.7" babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-umd@^7.13.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.0.tgz#2f8179d1bbc9263665ce4a65f305526b2ea8ac34" - integrity sha512-nPZdnWtXXeY7I87UZr9VlsWme3Y0cfFFE41Wbxz4bbaexAjNMInXPFUpRRUJ8NoMm0Cw+zxbqjdPmLhcjfazMw== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.0.tgz#195f26c2ad6d6a391b70880effce18ce625e06a7" + integrity sha512-nx4f6no57himWiHhxDM5pjwhae5vLpTK2zCnDH8+wNLJy0TVER/LJRHl2bkt6w9Aad2sPD5iNNoUpY3X9sTGDg== dependencies: - "@babel/helper-module-transforms" "^7.14.0" - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-named-capturing-groups-regex@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.13.tgz#2213725a5f5bbbe364b50c3ba5998c9599c5c9d9" - integrity sha512-Xsm8P2hr5hAxyYblrfACXpQKdQbx4m2df9/ZZSQ8MAhsadw06+jW7s9zsSw6he+mJZXRlVMyEnVktJo4zjk1WA== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.0.tgz#d3db61cc5d5b97986559967cd5ea83e5c32096ca" + integrity sha512-LogN88uO+7EhxWc8WZuQ8vxdSyVGxhkh8WTC3tzlT8LccMuQdA81e9SGV6zY7kY2LjDhhDOFdQVxdGwPyBCnvg== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.12.13" + "@babel/helper-create-regexp-features-plugin" "^7.16.0" "@babel/plugin-transform-new-target@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.13.tgz#e22d8c3af24b150dd528cbd6e685e799bf1c351c" - integrity sha512-/KY2hbLxrG5GTQ9zzZSc3xWiOy379pIETEhbtzwZcw9rvuaVV4Fqy7BYGYOWZnaoXIQYbbJ0ziXLa/sKcGCYEQ== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.0.tgz#af823ab576f752215a49937779a41ca65825ab35" + integrity sha512-fhjrDEYv2DBsGN/P6rlqakwRwIp7rBGLPbrKxwh7oVt5NNkIhZVOY2GRV+ULLsQri1bDqwDWnU3vhlmx5B2aCw== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-object-super@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz#b4416a2d63b8f7be314f3d349bd55a9c1b5171f7" - integrity sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.0.tgz#fb20d5806dc6491a06296ac14ea8e8d6fedda72b" + integrity sha512-fds+puedQHn4cPLshoHcR1DTMN0q1V9ou0mUjm8whx9pGcNvDrVVrgw+KJzzCaiTdaYhldtrUps8DWVMgrSEyg== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/helper-replace-supers" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.16.0" -"@babel/plugin-transform-parameters@^7.13.0", "@babel/plugin-transform-parameters@^7.14.2": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.2.tgz#e4290f72e0e9e831000d066427c4667098decc31" - integrity sha512-NxoVmA3APNCC1JdMXkdYXuQS+EMdqy0vIwyDHeKHiJKRxmp1qGSdb0JLEIoPRhkx6H/8Qi3RJ3uqOCYw8giy9A== +"@babel/plugin-transform-parameters@^7.13.0", "@babel/plugin-transform-parameters@^7.16.0": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.3.tgz#fa9e4c874ee5223f891ee6fa8d737f4766d31d15" + integrity sha512-3MaDpJrOXT1MZ/WCmkOFo7EtmVVC8H4EUZVrHvFOsmwkk4lOjQj8rzv8JKUZV4YoQKeoIgk07GO+acPU9IMu/w== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-property-literals@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz#4e6a9e37864d8f1b3bc0e2dce7bf8857db8b1a81" - integrity sha512-nqVigwVan+lR+g8Fj8Exl0UQX2kymtjcWfMOYM1vTYEKujeyv2SkMgazf2qNcK7l4SDiKyTA/nHCPqL4e2zo1A== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.0.tgz#a95c552189a96a00059f6776dc4e00e3690c78d1" + integrity sha512-XLldD4V8+pOqX2hwfWhgwXzGdnDOThxaNTgqagOcpBgIxbUvpgU2FMvo5E1RyHbk756WYgdbS0T8y0Cj9FKkWQ== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-react-display-name@^7.12.13": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.14.2.tgz#2e854544d42ab3bb9c21f84e153d62e800fbd593" - integrity sha512-zCubvP+jjahpnFJvPaHPiGVfuVUjXHhFvJKQdNnsmSsiU9kR/rCZ41jHc++tERD2zV+p7Hr6is+t5b6iWTCqSw== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.0.tgz#9a0ad8aa8e8790883a7bd2736f66229a58125676" + integrity sha512-FJFdJAqaCpndL+pIf0aeD/qlQwT7QXOvR6Cc8JPvNhKJBi2zc/DPc4g05Y3fbD/0iWAMQFGij4+Xw+4L/BMpTg== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-react-jsx-development@^7.12.17": - version "7.12.17" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.17.tgz#f510c0fa7cd7234153539f9a362ced41a5ca1447" - integrity sha512-BPjYV86SVuOaudFhsJR1zjgxxOhJDt6JHNoD48DxWEIxUCAMjV1ys6DYw4SDYZh0b1QsS2vfIA9t/ZsQGsDOUQ== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.0.tgz#1cb52874678d23ab11d0d16488d54730807303ef" + integrity sha512-qq65iSqBRq0Hr3wq57YG2AmW0H6wgTnIzpffTphrUWUgLCOK+zf1f7G0vuOiXrp7dU1qq+fQBoqZ3wCDAkhFzw== dependencies: - "@babel/plugin-transform-react-jsx" "^7.12.17" + "@babel/plugin-transform-react-jsx" "^7.16.0" -"@babel/plugin-transform-react-jsx@^7.12.17", "@babel/plugin-transform-react-jsx@^7.13.12": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.14.3.tgz#0e26597805cf0862da735f264550933c38babb66" - integrity sha512-uuxuoUNVhdgYzERiHHFkE4dWoJx+UFVyuAl0aqN8P2/AKFHwqgUC5w2+4/PjpKXJsFgBlYAFXlUmDQ3k3DUkXw== +"@babel/plugin-transform-react-jsx@^7.13.12", "@babel/plugin-transform-react-jsx@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.0.tgz#55b797d4960c3de04e07ad1c0476e2bc6a4889f1" + integrity sha512-rqDgIbukZ44pqq7NIRPGPGNklshPkvlmvqjdx3OZcGPk4zGIenYkxDTvl3LsSL8gqcc3ZzGmXPE6hR/u/voNOw== dependencies: - "@babel/helper-annotate-as-pure" "^7.12.13" - "@babel/helper-module-imports" "^7.13.12" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-jsx" "^7.12.13" - "@babel/types" "^7.14.2" + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-module-imports" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-jsx" "^7.16.0" + "@babel/types" "^7.16.0" "@babel/plugin-transform-react-pure-annotations@^7.12.1": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.12.1.tgz#05d46f0ab4d1339ac59adf20a1462c91b37a1a42" - integrity sha512-RqeaHiwZtphSIUZ5I85PEH19LOSzxfuEazoY7/pWASCAIBuATQzpSVD+eT6MebeeZT2F4eSL0u4vw6n4Nm0Mjg== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.0.tgz#23db6ddf558d8abde41b8ad9d59f48ad5532ccab" + integrity sha512-NC/Bj2MG+t8Ef5Pdpo34Ay74X4Rt804h5y81PwOpfPtmAK3i6CizmQqwyBQzIepz1Yt8wNr2Z2L7Lu3qBMfZMA== dependencies: - "@babel/helper-annotate-as-pure" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-regenerator@^7.13.15": - version "7.13.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.13.15.tgz#e5eb28945bf8b6563e7f818945f966a8d2997f39" - integrity sha512-Bk9cOLSz8DiurcMETZ8E2YtIVJbFCPGW28DJWUakmyVWtQSm6Wsf0p4B4BfEr/eL2Nkhe/CICiUiMOCi1TPhuQ== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.0.tgz#eaee422c84b0232d03aea7db99c97deeaf6125a4" + integrity sha512-JAvGxgKuwS2PihiSFaDrp94XOzzTUeDeOQlcKzVAyaPap7BnZXK/lvMDiubkPTdotPKOIZq9xWXWnggUMYiExg== dependencies: regenerator-transform "^0.14.2" "@babel/plugin-transform-reserved-words@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.13.tgz#7d9988d4f06e0fe697ea1d9803188aa18b472695" - integrity sha512-xhUPzDXxZN1QfiOy/I5tyye+TRz6lA7z6xaT4CLOjPRMVg1ldRf0LHw0TDBpYL4vG78556WuHdyO9oi5UmzZBg== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.0.tgz#fff4b9dcb19e12619394bda172d14f2d04c0379c" + integrity sha512-Dgs8NNCehHSvXdhEhln8u/TtJxfVwGYCgP2OOr5Z3Ar+B+zXicEOKNTyc+eca2cuEOMtjW6m9P9ijOt8QdqWkg== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-shorthand-properties@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz#db755732b70c539d504c6390d9ce90fe64aff7ad" - integrity sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.0.tgz#090372e3141f7cc324ed70b3daf5379df2fa384d" + integrity sha512-iVb1mTcD8fuhSv3k99+5tlXu5N0v8/DPm2mO3WACLG6al1CGZH7v09HJyUb1TtYl/Z+KrM6pHSIJdZxP5A+xow== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-spread@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz#84887710e273c1815ace7ae459f6f42a5d31d5fd" - integrity sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.0.tgz#d21ca099bbd53ab307a8621e019a7bd0f40cdcfb" + integrity sha512-Ao4MSYRaLAQczZVp9/7E7QHsCuK92yHRrmVNRe/SlEJjhzivq0BSn8mEraimL8wizHZ3fuaHxKH0iwzI13GyGg== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" "@babel/plugin-transform-sticky-regex@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz#760ffd936face73f860ae646fb86ee82f3d06d1f" - integrity sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.0.tgz#c35ea31a02d86be485f6aa510184b677a91738fd" + integrity sha512-/ntT2NljR9foobKk4E/YyOSwcGUXtYWv5tinMK/3RkypyNBNdhHUaq6Orw5DWq9ZcNlS03BIlEALFeQgeVAo4Q== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-template-literals@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz#a36049127977ad94438dee7443598d1cefdf409d" - integrity sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.0.tgz#a8eced3a8e7b8e2d40ec4ec4548a45912630d302" + integrity sha512-Rd4Ic89hA/f7xUSJQk5PnC+4so50vBoBfxjdQAdvngwidM8jYIBVxBZ/sARxD4e0yMXRbJVDrYf7dyRtIIKT6Q== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-typeof-symbol@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz#785dd67a1f2ea579d9c2be722de8c84cb85f5a7f" - integrity sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.0.tgz#8b19a244c6f8c9d668dca6a6f754ad6ead1128f2" + integrity sha512-++V2L8Bdf4vcaHi2raILnptTBjGEFxn5315YU+e8+EqXIucA+q349qWngCLpUYqqv233suJ6NOienIVUpS9cqg== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-unicode-escapes@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz#840ced3b816d3b5127dd1d12dcedc5dead1a5e74" - integrity sha512-0bHEkdwJ/sN/ikBHfSmOXPypN/beiGqjo+o4/5K+vxEFNPRPdImhviPakMKG4x96l85emoa0Z6cDflsdBusZbw== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.0.tgz#1a354064b4c45663a32334f46fa0cf6100b5b1f3" + integrity sha512-VFi4dhgJM7Bpk8lRc5CMaRGlKZ29W9C3geZjt9beuzSUrlJxsNwX7ReLwaL6WEvsOf2EQkyIJEPtF8EXjB/g2A== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-unicode-regex@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz#b52521685804e155b1202e83fc188d34bb70f5ac" - integrity sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA== + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.0.tgz#293b80950177c8c85aede87cef280259fb995402" + integrity sha512-jHLK4LxhHjvCeZDWyA9c+P9XH1sOxRd1RO9xMtDVRAOND/PczPqizEtVdx4TQF/wyPaewqpT+tgQFYMnN/P94A== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.12.13" - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" "@babel/preset-env@7.13.15": version "7.13.15" @@ -955,9 +934,9 @@ semver "^6.3.0" "@babel/preset-modules@^0.1.4": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" - integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg== + version "0.1.5" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" @@ -978,41 +957,42 @@ "@babel/plugin-transform-react-pure-annotations" "^7.12.1" "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6" - integrity sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA== + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.3.tgz#b86f0db02a04187a3c17caa77de69840165d42d5" + integrity sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ== dependencies: regenerator-runtime "^0.13.4" -"@babel/template@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327" - integrity sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA== +"@babel/template@^7.12.13", "@babel/template@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" + integrity sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A== dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/parser" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/code-frame" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/types" "^7.16.0" -"@babel/traverse@^7.13.0", "@babel/traverse@^7.13.15", "@babel/traverse@^7.14.0", "@babel/traverse@^7.14.2": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.2.tgz#9201a8d912723a831c2679c7ebbf2fe1416d765b" - integrity sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA== +"@babel/traverse@^7.13.0", "@babel/traverse@^7.13.15", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.3": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.3.tgz#f63e8a938cc1b780f66d9ed3c54f532ca2d14787" + integrity sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag== dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.14.2" - "@babel/helper-function-name" "^7.14.2" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/parser" "^7.14.2" - "@babel/types" "^7.14.2" + "@babel/code-frame" "^7.16.0" + "@babel/generator" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-hoist-variables" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/parser" "^7.16.3" + "@babel/types" "^7.16.0" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.14", "@babel/types@^7.13.16", "@babel/types@^7.14.0", "@babel/types@^7.14.2", "@babel/types@^7.14.4", "@babel/types@^7.4.4": - version "7.14.4" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.4.tgz#bfd6980108168593b38b3eb48a24aa026b919bc0" - integrity sha512-lCj4aIs0xUefJFQnwwQv2Bxg7Omd6bgquZ6LGC+gGMh6/s5qDVfjuCMlDmYQ15SLsWHd9n+X3E75lKIhl5Lkiw== +"@babel/types@^7.13.14", "@babel/types@^7.13.16", "@babel/types@^7.16.0", "@babel/types@^7.4.4": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" + integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== dependencies: - "@babel/helper-validator-identifier" "^7.14.0" + "@babel/helper-validator-identifier" "^7.15.7" to-fast-properties "^2.0.0" "@cnakazawa/watch@^1.0.3": @@ -1024,29 +1004,29 @@ minimist "^1.2.0" "@discoveryjs/json-ext@^0.5.0": - version "0.5.3" - resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz#90420f9f9c6d3987f176a19a7d8e764271a2f55d" - integrity sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g== + version "0.5.5" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz#9283c9ce5b289a3c4f61c12757469e59377f81f3" + integrity sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA== -"@eslint/eslintrc@^0.4.3": - version "0.4.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" - integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== +"@eslint/eslintrc@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.4.tgz#dfe0ff7ba270848d10c5add0715e04964c034b31" + integrity sha512-h8Vx6MdxwWI2WM8/zREHMoqdgLNXEL4QX3MWSVMdyNJGvXVOs+6lp+m2hc3FnuMHDc4poxFNI20vCk0OmI4G0Q== dependencies: ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" + debug "^4.3.2" + espree "^9.0.0" globals "^13.9.0" ignore "^4.0.6" import-fresh "^3.2.1" - js-yaml "^3.13.1" + js-yaml "^4.1.0" minimatch "^3.0.4" strip-json-comments "^3.1.1" "@fortawesome/fontawesome-common-types@^0.2.35": - version "0.2.35" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.35.tgz#01dd3d054da07a00b764d78748df20daf2b317e9" - integrity sha512-IHUfxSEDS9dDGqYwIW7wTN6tn/O8E0n5PcAHz9cAaBoZw6UpG20IG/YM3NNLaGPwPqgjBAFjIURzqoQs3rrtuw== + version "0.2.36" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz#b44e52db3b6b20523e0c57ef8c42d315532cb903" + integrity sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg== "@fortawesome/fontawesome-free@5.15.3": version "5.15.3" @@ -1081,19 +1061,19 @@ dependencies: prop-types "^15.7.2" -"@humanwhocodes/config-array@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" - integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== +"@humanwhocodes/config-array@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.6.0.tgz#b5621fdb3b32309d2d16575456cbc277fa8f021a" + integrity sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A== dependencies: "@humanwhocodes/object-schema" "^1.2.0" debug "^4.1.1" minimatch "^3.0.4" "@humanwhocodes/object-schema@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" - integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== "@microsoft/signalr@6.0.0": version "6.0.0" @@ -1114,18 +1094,18 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" -"@nodelib/fs.scandir@2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69" - integrity sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA== +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== dependencies: - "@nodelib/fs.stat" "2.0.4" + "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.4", "@nodelib/fs.stat@^2.0.2": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz#a3f2dd61bab43b8db8fa108a121cfffe4c676655" - integrity sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q== +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== "@nodelib/fs.stat@^1.1.2": version "1.1.3" @@ -1133,11 +1113,11 @@ integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== "@nodelib/fs.walk@^1.2.3": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz#cce9396b30aa5afe9e3756608f5831adcb53d063" - integrity sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow== + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== dependencies: - "@nodelib/fs.scandir" "2.1.4" + "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" "@react-dnd/asap@^4.0.0": @@ -1217,62 +1197,52 @@ "@sentry/types" "6.10.0" tslib "^1.9.3" -"@stylelint/postcss-css-in-js@^0.37.2": - version "0.37.2" - resolved "https://registry.yarnpkg.com/@stylelint/postcss-css-in-js/-/postcss-css-in-js-0.37.2.tgz#7e5a84ad181f4234a2480803422a47b8749af3d2" - integrity sha512-nEhsFoJurt8oUmieT8qy4nk81WRHmJynmVwn/Vts08PL9fhgIsMhk1GId5yAN643OzqEEb5S/6At2TZW7pqPDA== - dependencies: - "@babel/core" ">=7.9.0" - -"@stylelint/postcss-markdown@^0.36.2": - version "0.36.2" - resolved "https://registry.yarnpkg.com/@stylelint/postcss-markdown/-/postcss-markdown-0.36.2.tgz#0a540c4692f8dcdfc13c8e352c17e7bfee2bb391" - integrity sha512-2kGbqUVJUGE8dM+bMzXG/PYUWKkjLIkRLWNh39OaADkiabDRdw8ATFCgbMz5xdIcvwspPAluSL7uY+ZiTWdWmQ== - dependencies: - remark "^13.0.0" - unist-util-find-all-after "^3.0.2" - "@types/connect@^3.4.33": - version "3.4.34" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.34.tgz#170a40223a6d666006d93ca128af2beb1d9b1901" - integrity sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ== + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== dependencies: "@types/node" "*" "@types/eslint-scope@^3.7.0": - version "3.7.0" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.0.tgz#4792816e31119ebd506902a482caec4951fabd86" - integrity sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw== + version "3.7.1" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.1.tgz#8dc390a7b4f9dd9f1284629efce982e41612116e" + integrity sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g== dependencies: "@types/eslint" "*" "@types/estree" "*" "@types/eslint@*": - version "7.2.12" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.12.tgz#fefaa48a4db2415b621fe315e4baeedde525927e" - integrity sha512-HjikV/jX6e0Pg4DcB+rtOBKSrG6w5IaxWpmi3efL/eLxMz5lZTK+W1DKERrX5a+mNzL78axfsDNXu7JHFP4uLg== + version "8.2.0" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.2.0.tgz#afd0519223c29c347087542cbaee2fedc0873b16" + integrity sha512-74hbvsnc+7TEDa1z5YLSe4/q8hGYB3USNvCuzHUJrjPV6hXaq8IXcngCrHkuvFt0+8rFz7xYXrHgNayIX0UZvQ== dependencies: "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*", "@types/estree@^0.0.47": +"@types/estree@*": + version "0.0.50" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" + integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== + +"@types/estree@^0.0.47": version "0.0.47" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.47.tgz#d7a51db20f0650efec24cd04994f523d93172ed4" integrity sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg== "@types/express-serve-static-core@^4.17.9": - version "4.17.20" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.20.tgz#44caee029f2c26c46711da5e845cdc12167ad72d" - integrity sha512-8qqFN4W53IEWa9bdmuVrUcVkFemQWnt5DKPQ/oa8xKDYgtjCr2OO6NX5TIK49NLFr3mPYU2cLh92DQquC3oWWQ== + version "4.17.25" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.25.tgz#e42f7046adc65ece2eb6059b77aecfbe9e9f82e0" + integrity sha512-OUJIVfRMFijZukGGwTpKNFprqCCXk5WjNGvUgB/CxxBR40QWSjsNK86+yvGKlCOGc7sbwfHLaXhkG+NsytwBaQ== dependencies: "@types/node" "*" "@types/qs" "*" "@types/range-parser" "*" "@types/glob@^7.1.1": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" - integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w== + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== dependencies: "@types/minimatch" "*" "@types/node" "*" @@ -1286,14 +1256,14 @@ hoist-non-react-statics "^3.3.0" "@types/html-minifier-terser@^5.0.0": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#3c9ee980f1a10d6021ae6632ca3e79ca2ec4fb50" - integrity sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA== + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz#693b316ad323ea97eed6b38ed1a3cc02b1672b57" + integrity sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w== -"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6": - version "7.0.7" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" - integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== +"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== "@types/json5@^0.0.29": version "0.0.29" @@ -1301,41 +1271,34 @@ integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= "@types/lodash@^4.14.159": - version "4.14.170" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.170.tgz#0d67711d4bf7f4ca5147e9091b847479b87925d6" - integrity sha512-bpcvu/MKHHeYX+qeEN8GE7DIravODWdACVA1ctevD8CN24RhPZIKMn9ntfAsrvLfSX3cR5RrBKAbYm9bGs0A+Q== - -"@types/mdast@^3.0.0": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.3.tgz#2d7d671b1cd1ea3deb306ea75036c2a0407d2deb" - integrity sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw== - dependencies: - "@types/unist" "*" + version "4.14.177" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.177.tgz#f70c0d19c30fab101cad46b52be60363c43c4578" + integrity sha512-0fDwydE2clKe9MNfvXHBHF9WEahRuj+msTuQqOmAApNORFvhMYZKNGGJdCzuhheVjMps/ti0Ak/iJPACMaevvw== "@types/minimatch@*": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21" - integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA== + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== "@types/minimist@^1.2.0": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.1.tgz#283f669ff76d7b8260df8ab7a4262cc83d988256" - integrity sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg== + version "1.2.2" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" + integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== "@types/node@*": - version "15.6.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-15.6.1.tgz#32d43390d5c62c5b6ec486a9bc9c59544de39a08" - integrity sha512-7EIraBEyRHEe7CH+Fm1XvgqU6uwZN8Q7jppJGcqjROMT29qhAuuOxYB1uEY5UMYQKEmA5D+5tBnhdaPXSsLONA== + version "16.11.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.9.tgz#879be3ad7af29f4c1a5c433421bf99fab7047185" + integrity sha512-MKmdASMf3LtPzwLyRrFjtFFZ48cMf8jmX5VRYrDQiJa8Ybu5VAmkqBWqKU8fdCwD8ysw4mQ9nrEHvzg6gunR7A== "@types/node@^12.12.54": - version "12.20.13" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.13.tgz#e743bae112bd779ac9650f907197dd2caa7f0364" - integrity sha512-1x8W5OpxPq+T85OUsHRP6BqXeosKmeXRtjoF39STcdf/UWLqUsoehstZKOi0CunhVqHG17AyZgpj20eRVooK6A== + version "12.20.37" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.37.tgz#abb38afa9d6e8a2f627a8cb52290b3c80fbe61ed" + integrity sha512-i1KGxqcvJaLQali+WuypQnXwcplhtNtjs66eNsZpp2P2FL/trJJxx/VWsM0YCL2iMoIJrbXje48lvIQAQ4p2ZA== "@types/normalize-package-data@^2.4.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" - integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== + version "2.4.1" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" + integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== "@types/parse-json@^4.0.0": version "4.0.0" @@ -1343,24 +1306,24 @@ integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== "@types/prop-types@*": - version "15.7.3" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" - integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== + version "15.7.4" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" + integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== "@types/qs@*": - version "6.9.6" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.6.tgz#df9c3c8b31a247ec315e6996566be3171df4b3b1" - integrity sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA== + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== "@types/range-parser@*": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" - integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== "@types/react-redux@^7.1.16": - version "7.1.16" - resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.16.tgz#0fbd04c2500c12105494c83d4a3e45c084e3cb21" - integrity sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw== + version "7.1.20" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.20.tgz#42f0e61ababb621e12c66c96dda94c58423bd7df" + integrity sha512-q42es4c8iIeTgcnB+yJgRTTzftv3eYYvCZOh1Ckn2eX/3o5TdsQYKUWpLoLuGlcY/p+VAhV9IOEZJcWk/vfkXw== dependencies: "@types/hoist-non-react-statics" "^3.3.0" "@types/react" "*" @@ -1368,23 +1331,18 @@ redux "^4.0.0" "@types/react@*": - version "17.0.8" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.8.tgz#fe76e3ba0fbb5602704110fd1e3035cf394778e3" - integrity sha512-3sx4c0PbXujrYAKwXxNONXUtRp9C+hE2di0IuxFyf5BELD+B+AXL8G7QrmSKhVwKZDbv0igiAjQAMhXj8Yg3aw== + version "17.0.36" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.36.tgz#0d81e0e2419e6a8e9ba6af5e3a0608e70835d7d1" + integrity sha512-CUFUp01OdfbpN/76v4koqgcpcRGT3sYOq3U3N6q0ZVGcyeP40NUdVU+EWe3hs34RNaTefiYyBzOpxBBidCc5zw== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" csstype "^3.0.2" "@types/scheduler@*": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.1.tgz#18845205e86ff0038517aab7a18a62a6b9f71275" - integrity sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA== - -"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e" - integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ== + version "0.16.2" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== "@types/ws@^7.4.4": version "7.4.7" @@ -1515,21 +1473,21 @@ "@xtuc/long" "4.2.2" "@webpack-cli/configtest@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.0.3.tgz#204bcff87cda3ea4810881f7ea96e5f5321b87b9" - integrity sha512-WQs0ep98FXX2XBAfQpRbY0Ma6ADw8JR6xoIkaIiJIzClGOMqVRvPCWqndTxf28DgFopWan0EKtHtg/5W1h0Zkw== + version "1.1.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.1.0.tgz#8342bef0badfb7dfd3b576f2574ab80c725be043" + integrity sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg== "@webpack-cli/info@^1.2.3": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.2.4.tgz#7381fd41c9577b2d8f6c2594fad397ef49ad5573" - integrity sha512-ogE2T4+pLhTTPS/8MM3IjHn0IYplKM4HbVNMCWA9N4NrdPzunwenpCsqKEXyejMfRu6K8mhauIPYf8ZxWG5O6g== + version "1.4.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.4.0.tgz#b9179c3227ab09cbbb149aa733475fcf99430223" + integrity sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw== dependencies: envinfo "^7.7.3" "@webpack-cli/serve@^1.3.1": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.4.0.tgz#f84fd07bcacefe56ce762925798871092f0f228e" - integrity sha512-xgT/HqJ+uLWGX+Mzufusl3cgjAcnqYYskaB7o0vRcwOEfuu6hMzSILQpnIzFMGsTaeaX4Nnekl+6fadLbl1/Vg== + version "1.6.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.0.tgz#2c275aa05c895eccebbfc34cfb223c6e8bd591a2" + integrity sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA== "@xtuc/ieee754@^1.2.0": version "1.2.0" @@ -1557,19 +1515,14 @@ abort-controller@^3.0.0: event-target-shim "^5.0.0" acorn-jsx@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" - integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -acorn@^8.0.4: - version "8.2.4" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.2.4.tgz#caba24b08185c3b56e3168e97d15ed17f4d31fd0" - integrity sha512-Ibt84YwBDDA890eDiDCEqcbwvHlBvzzDkU2cGBBDDI1QWT12jTiXIOn2CIw5KK4i6N5Z2HUxwYjzriDyqaqqZg== +acorn@^8.0.4, acorn@^8.6.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895" + integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw== add-px-to-style@1.0.0: version "1.0.0" @@ -1584,11 +1537,25 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== +ajv-keywords@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -1599,10 +1566,10 @@ ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.1: - version "8.5.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.5.0.tgz#695528274bcb5afc865446aa275484049a18ae4b" - integrity sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ== +ajv@^8.0.0, ajv@^8.0.1, ajv@^8.8.0: + version "8.8.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb" + integrity sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -1640,10 +1607,10 @@ ansi-regex@^2.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-styles@^2.2.1: version "2.2.1" @@ -1714,12 +1681,10 @@ archiver@^5.3.0: tar-stream "^2.2.0" zip-stream "^4.1.0" -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== arr-diff@^1.0.1: version "1.1.0" @@ -1749,16 +1714,16 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= -array-includes@^3.1.2, array-includes@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.3.tgz#c7f619b382ad2afaf5326cddfdc0afc61af7690a" - integrity sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A== +array-includes@^3.1.3, array-includes@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" + integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" + es-abstract "^1.19.1" get-intrinsic "^1.1.1" - is-string "^1.0.5" + is-string "^1.0.7" array-slice@^0.2.3: version "0.2.3" @@ -1787,24 +1752,23 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -array.prototype.flat@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz#6ef638b43312bd401b4c6199fdec7e2dc9e9a123" - integrity sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg== +array.prototype.flat@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" + integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" + es-abstract "^1.19.0" -array.prototype.flatmap@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz#94cfd47cc1556ec0747d97f7c7738c58122004c9" - integrity sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q== +array.prototype.flatmap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" + integrity sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA== dependencies: call-bind "^1.0.0" define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - function-bind "^1.1.1" + es-abstract "^1.19.0" arrify@^1.0.1: version "1.0.1" @@ -1834,9 +1798,9 @@ async@^2.6.2: lodash "^4.17.14" async@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" - integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== + version "3.2.2" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.2.tgz#2eb7671034bb2194d45d30e31e24ec7e7f9670cd" + integrity sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g== atob@^2.1.2: version "2.1.2" @@ -1855,19 +1819,6 @@ autoprefixer@10.2.5: normalize-range "^0.1.2" postcss-value-parser "^4.1.0" -autoprefixer@^9.8.6: - version "9.8.6" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" - integrity sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg== - dependencies: - browserslist "^4.12.0" - caniuse-lite "^1.0.30001109" - colorette "^1.2.1" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - postcss "^7.0.32" - postcss-value-parser "^4.1.0" - babel-loader@8.2.2: version "8.2.2" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.2.tgz#9363ce84c10c9a40e6c753748e1441b60c8a0b81" @@ -1891,28 +1842,28 @@ babel-plugin-inline-classnames@2.0.1: integrity sha512-Pq/jJ6hTiGiqcMmy2d4CyJcfBDeUHOdQl1t1MDWNaSKR2RxDmShSAx4Zqz6NDmFaiinaRqF8eQoTVgSRGU+McQ== babel-plugin-polyfill-corejs2@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz#e9124785e6fd94f94b618a7954e5693053bf5327" - integrity sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ== + version "0.2.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.3.tgz#6ed8e30981b062f8fe6aca8873a37ebcc8cc1c0f" + integrity sha512-NDZ0auNRzmAfE1oDDPW2JhzIMXUk+FFe2ICejmt5T4ocKgiQx3e0VCRx9NCAidcMtL2RUZaWtXnmjTCkx0tcbA== dependencies: "@babel/compat-data" "^7.13.11" - "@babel/helper-define-polyfill-provider" "^0.2.2" + "@babel/helper-define-polyfill-provider" "^0.2.4" semver "^6.1.1" babel-plugin-polyfill-corejs3@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.2.tgz#7424a1682ee44baec817327710b1b094e5f8f7f5" - integrity sha512-l1Cf8PKk12eEk5QP/NQ6TH8A1pee6wWDJ96WjxrMXFLHLOBFzYM4moG80HFgduVhTqAFez4alnZKEhP/bYHg0A== + version "0.2.5" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.5.tgz#2779846a16a1652244ae268b1e906ada107faf92" + integrity sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw== dependencies: "@babel/helper-define-polyfill-provider" "^0.2.2" - core-js-compat "^3.9.1" + core-js-compat "^3.16.2" babel-plugin-polyfill-regenerator@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz#b310c8d642acada348c1fa3b3e6ce0e851bee077" - integrity sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg== + version "0.2.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.3.tgz#2e9808f5027c4336c994992b48a4262580cb8d6d" + integrity sha512-JVE78oRZPKFIeUqFGrSORNzQnrDwZR16oiWeGM8ZyjBn2XAT5OjP+wXx5ESuo33nUsFUEJYjtklnsKbxW5L+7g== dependencies: - "@babel/helper-define-polyfill-provider" "^0.2.2" + "@babel/helper-define-polyfill-provider" "^0.2.4" babel-plugin-transform-react-remove-prop-types@0.4.24: version "0.4.24" @@ -1927,11 +1878,6 @@ babel-runtime@^6.26.0: core-js "^2.4.0" regenerator-runtime "^0.11.0" -bail@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" - integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== - balanced-match@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.1.0.tgz#b504bd05869b39259dd0c5efc35d843176dccc4a" @@ -1989,7 +1935,7 @@ body@^5.1.0: raw-body "~1.1.0" safe-json-parse "~1.0.1" -boolbase@^1.0.0, boolbase@~1.0.0: +boolbase@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= @@ -2025,16 +1971,16 @@ braces@^3.0.1: dependencies: fill-range "^7.0.1" -browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.3, browserslist@^4.16.6: - version "4.16.6" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" - integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ== +browserslist@^4.14.5, browserslist@^4.16.3, browserslist@^4.17.5, browserslist@^4.17.6: + version "4.18.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.18.1.tgz#60d3920f25b6860eb917c6c7b185576f4d8b017f" + integrity sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ== dependencies: - caniuse-lite "^1.0.30001219" - colorette "^1.2.2" - electron-to-chromium "^1.3.723" + caniuse-lite "^1.0.30001280" + electron-to-chromium "^1.3.896" escalade "^3.1.1" - node-releases "^1.1.71" + node-releases "^2.0.1" + picocolors "^1.0.0" bser@2.1.1: version "2.1.1" @@ -2049,9 +1995,9 @@ buffer-crc32@^0.2.1, buffer-crc32@^0.2.13: integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== buffer@^5.5.0: version "5.7.1" @@ -2127,14 +2073,14 @@ camelcase@^5.3.1: integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== camelcase@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" - integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== + version "6.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.1.tgz#250fd350cfd555d0d2160b1d51510eaf8326e86e" + integrity sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA== -caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001196, caniuse-lite@^1.0.30001219: - version "1.0.30001230" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz#8135c57459854b2240b57a4a6786044bdc5a9f71" - integrity sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ== +caniuse-lite@^1.0.30001196, caniuse-lite@^1.0.30001280: + version "1.0.30001282" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001282.tgz#38c781ee0a90ccfe1fe7fefd00e43f5ffdcb96fd" + integrity sha512-YhF/hG6nqBEllymSIjLtR2iWDDnChvhnVJqp+vloyt2tEHFG1yBR+ac2B/rOw0qOK0m0lEXU2dv4E/sMk5P9Kg== capture-exit@^2.0.0: version "2.0.0" @@ -2154,7 +2100,7 @@ chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -2163,29 +2109,14 @@ chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" - integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" -character-entities-legacy@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" - integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== - -character-entities@^1.0.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" - integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== - -character-reference-invalid@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" - integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== - chart.js@3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.2.0.tgz#3d0a4b62b6bee428f8547db6aa68c792b130c260" @@ -2212,9 +2143,9 @@ classnames@2.3.1: integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== clean-css@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78" - integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA== + version "4.2.4" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.4.tgz#733bf46eba4e607c6891ea57c24a989356831178" + integrity sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A== dependencies: source-map "~0.6.0" @@ -2321,9 +2252,9 @@ color@^0.11.0: color-string "^0.3.0" colorette@^1.2.1, colorette@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" - integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== + version "1.4.0" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" + integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== commander@^2.20.0, commander@^2.20.3: version "2.20.3" @@ -2351,12 +2282,12 @@ component-emitter@^1.2.1: integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== compress-commons@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.0.tgz#25ec7a4528852ccd1d441a7d4353cd0ece11371b" - integrity sha512-ofaaLqfraD1YRTkrRKPCrGJ1pFeDG/MVCkVVV2FNGeWquSlqw5wOrwOfPQ1xF2u+blpeWASie5EubHz+vsNIgA== + version "4.1.1" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.1.tgz#df2a09a7ed17447642bad10a85cc9a19e5c42a7d" + integrity sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ== dependencies: buffer-crc32 "^0.2.13" - crc32-stream "^4.0.1" + crc32-stream "^4.0.2" normalize-path "^3.0.0" readable-stream "^3.6.0" @@ -2382,9 +2313,9 @@ continuable-cache@^0.3.1: integrity sha1-vXJ6f67XfnH/OYWskzUakSczrQ8= convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== dependencies: safe-buffer "~5.1.1" @@ -2393,12 +2324,12 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -core-js-compat@^3.9.0, core-js-compat@^3.9.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.13.1.tgz#05444caa8f153be0c67db03cf8adb8ec0964e58e" - integrity sha512-mdrcxc0WznfRd8ZicEZh1qVeJ2mu6bwQFh8YVUK48friy/FOwFV5EJj9/dlh+nMQ74YusdVfBFDuomKgUspxWQ== +core-js-compat@^3.16.2, core-js-compat@^3.9.0: + version "3.19.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.19.1.tgz#fe598f1a9bf37310d77c3813968e9f7c7bb99476" + integrity sha512-Q/VJ7jAF/y68+aUsQJ/afPOewdsGkDtcMb40J8MbuWKlK3Y+wtHq8bTHKPj2WKWLIqmS5JhHs4CzHtz6pT2W6g== dependencies: - browserslist "^4.16.6" + browserslist "^4.17.6" semver "7.0.0" core-js@3.11.0: @@ -2412,14 +2343,14 @@ core-js@^2.4.0: integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cosmiconfig@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3" - integrity sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA== +cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== dependencies: "@types/parse-json" "^4.0.0" import-fresh "^3.2.1" @@ -2460,7 +2391,7 @@ crc-32@^1.2.0: exit-on-epipe "~1.0.1" printj "~1.1.0" -crc32-stream@^4.0.1: +crc32-stream@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.2.tgz#c922ad22b38395abe9d3870f02fa8134ed709007" integrity sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w== @@ -2523,20 +2454,21 @@ css-loader@5.2.4: schema-utils "^3.0.0" semver "^7.3.5" -css-select@^2.0.2: - version "2.1.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" - integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== +css-select@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" + integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA== dependencies: boolbase "^1.0.0" - css-what "^3.2.1" - domutils "^1.7.0" - nth-check "^1.0.2" + css-what "^5.0.0" + domhandler "^4.2.0" + domutils "^2.6.0" + nth-check "^2.0.0" -css-what@^3.2.1: - version "3.4.2" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" - integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== +css-what@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" + integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw== cssesc@^3.0.0: version "3.0.0" @@ -2544,9 +2476,9 @@ cssesc@^3.0.0: integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== csstype@^3.0.2: - version "3.0.8" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340" - integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw== + version "3.0.10" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" + integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== cuint@^0.2.2: version "0.2.2" @@ -2567,10 +2499,10 @@ debug@^3.1.0, debug@^3.1.1, debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== +debug@^4.1.0, debug@^4.1.1, debug@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== dependencies: ms "2.1.2" @@ -2605,9 +2537,9 @@ deep-equal@^1.1.1: regexp.prototype.flags "^1.2.0" deep-is@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== define-properties@^1.1.3: version "1.1.3" @@ -2709,7 +2641,7 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -dom-converter@^0.2: +dom-converter@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== @@ -2732,38 +2664,35 @@ dom-css@^2.0.0: dependencies: "@babel/runtime" "^7.1.2" -dom-serializer@0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" - integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== +dom-serializer@^1.0.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" + integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== dependencies: domelementtype "^2.0.1" + domhandler "^4.2.0" entities "^2.0.0" -domelementtype@1, domelementtype@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" - integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== - -domelementtype@^2.0.1: +domelementtype@^2.0.1, domelementtype@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== -domhandler@^2.3.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" - integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== +domhandler@^4.0.0, domhandler@^4.2.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.2.tgz#e825d721d19a86b8c201a35264e226c678ee755f" + integrity sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w== dependencies: - domelementtype "1" + domelementtype "^2.2.0" -domutils@^1.5.1, domutils@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== +domutils@^2.5.2, domutils@^2.6.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== dependencies: - dom-serializer "0" - domelementtype "1" + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" dot-case@^3.0.4: version "3.0.4" @@ -2773,10 +2702,10 @@ dot-case@^3.0.4: no-case "^3.0.4" tslib "^2.0.3" -electron-to-chromium@^1.3.723: - version "1.3.742" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.742.tgz#7223215acbbd3a5284962ebcb6df85d88b95f200" - integrity sha512-ihL14knI9FikJmH2XUIDdZFWJxvr14rPSdOhJ7PpS27xbz8qmaRwCwyg/bmFwjWKmWK9QyamiCZVCvXm5CH//Q== +electron-to-chromium@^1.3.896: + version "1.3.904" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.904.tgz#52a353994faeb0f2a9fab3606b4e0614d1af7b58" + integrity sha512-x5uZWXcVNYkTh4JubD7KSC1VMKz0vZwJUqVwY3ihsW0bst1BXDe494Uqbg3Y0fDGVjJqA8vEeGuvO5foyH2+qw== element-class@0.2.2: version "0.2.2" @@ -2801,9 +2730,9 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: once "^1.4.0" enhanced-resolve@^5.8.0: - version "5.8.2" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz#15ddc779345cbb73e97c611cd00c01c1e7bf4d8b" - integrity sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA== + version "5.8.3" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0" + integrity sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -2815,11 +2744,6 @@ enquirer@^2.3.5, enquirer@^2.3.6: dependencies: ansi-colors "^4.1.1" -entities@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" - integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== - entities@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" @@ -2844,22 +2768,26 @@ error@^7.0.0: dependencies: string-template "~0.2.1" -es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2: - version "1.18.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.3.tgz#25c4c3380a27aa203c44b2b685bba94da31b63e0" - integrity sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw== +es-abstract@^1.19.0, es-abstract@^1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" + integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== dependencies: call-bind "^1.0.2" es-to-primitive "^1.2.1" function-bind "^1.1.1" get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" has "^1.0.3" has-symbols "^1.0.2" - is-callable "^1.2.3" + internal-slot "^1.0.3" + is-callable "^1.2.4" is-negative-zero "^2.0.1" - is-regex "^1.1.3" - is-string "^1.0.6" - object-inspect "^1.10.3" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.1" + is-string "^1.0.7" + is-weakref "^1.0.1" + object-inspect "^1.11.0" object-keys "^1.1.1" object.assign "^4.1.2" string.prototype.trimend "^1.0.4" @@ -2907,20 +2835,21 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-import-resolver-node@^0.3.4: - version "0.3.4" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" - integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA== - dependencies: - debug "^2.6.9" - resolve "^1.13.1" - -eslint-module-utils@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz#b51be1e473dd0de1c5ea638e22429c2490ea8233" - integrity sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A== +eslint-import-resolver-node@^0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" + integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== dependencies: debug "^3.2.7" + resolve "^1.20.0" + +eslint-module-utils@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz#b435001c9f8dd4ab7f6d0efcae4b9696d4c24b7c" + integrity sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ== + dependencies: + debug "^3.2.7" + find-up "^2.1.0" pkg-dir "^2.0.0" eslint-plugin-filenames@1.3.2: @@ -2933,44 +2862,44 @@ eslint-plugin-filenames@1.3.2: lodash.snakecase "4.1.1" lodash.upperfirst "4.3.1" -eslint-plugin-import@2.23.4: - version "2.23.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz#8dceb1ed6b73e46e50ec9a5bb2411b645e7d3d97" - integrity sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ== +eslint-plugin-import@2.25.3: + version "2.25.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz#a554b5f66e08fb4f6dc99221866e57cfff824766" + integrity sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg== dependencies: - array-includes "^3.1.3" - array.prototype.flat "^1.2.4" + array-includes "^3.1.4" + array.prototype.flat "^1.2.5" debug "^2.6.9" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.4" - eslint-module-utils "^2.6.1" - find-up "^2.0.0" + eslint-import-resolver-node "^0.3.6" + eslint-module-utils "^2.7.1" has "^1.0.3" - is-core-module "^2.4.0" + is-core-module "^2.8.0" + is-glob "^4.0.3" minimatch "^3.0.4" - object.values "^1.1.3" - pkg-up "^2.0.0" - read-pkg-up "^3.0.0" + object.values "^1.1.5" resolve "^1.20.0" - tsconfig-paths "^3.9.0" + tsconfig-paths "^3.11.0" -eslint-plugin-react@7.24.0: - version "7.24.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.24.0.tgz#eadedfa351a6f36b490aa17f4fa9b14e842b9eb4" - integrity sha512-KJJIx2SYx7PBx3ONe/mEeMz4YE0Lcr7feJTCMyyKb/341NcjuAgim3Acgan89GfPv7nxXK2+0slu0CWXYM4x+Q== +eslint-plugin-react@7.27.1: + version "7.27.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.27.1.tgz#469202442506616f77a854d91babaae1ec174b45" + integrity sha512-meyunDjMMYeWr/4EBLTV1op3iSG3mjT/pz5gti38UzfM4OPpNc2m0t2xvKCOMU5D6FSdd34BIMFOvQbW+i8GAA== dependencies: - array-includes "^3.1.3" - array.prototype.flatmap "^1.2.4" + array-includes "^3.1.4" + array.prototype.flatmap "^1.2.5" doctrine "^2.1.0" - has "^1.0.3" + estraverse "^5.3.0" jsx-ast-utils "^2.4.1 || ^3.0.0" minimatch "^3.0.4" - object.entries "^1.1.4" - object.fromentries "^2.0.4" - object.values "^1.1.4" + object.entries "^1.1.5" + object.fromentries "^2.0.5" + object.hasown "^1.1.0" + object.values "^1.1.5" prop-types "^15.7.2" resolve "^2.0.0-next.3" - string.prototype.matchall "^4.0.5" + semver "^6.3.0" + string.prototype.matchall "^4.0.6" eslint-plugin-simple-import-sort@7.0.0: version "7.0.0" @@ -2985,14 +2914,22 @@ eslint-scope@^5.1.0, eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== +eslint-scope@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.0.tgz#c1f6ea30ac583031f203d65c73e723b01298f153" + integrity sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg== dependencies: - eslint-visitor-keys "^1.1.0" + esrecurse "^4.3.0" + estraverse "^5.2.0" -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== @@ -3002,37 +2939,41 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint@7.31.0: - version "7.31.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.31.0.tgz#f972b539424bf2604907a970860732c5d99d3aca" - integrity sha512-vafgJpSh2ia8tnTkNUkwxGmnumgckLh5aAbLa1xRmIn9+owi8qBNGKL+B881kNKNTy7FFqTEkpNkUvmw0n6PkA== +eslint-visitor-keys@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz#eee4acea891814cda67a7d8812d9647dd0179af2" + integrity sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA== + +eslint@8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.3.0.tgz#a3c2409507403c1c7f6c42926111d6cbefbc3e85" + integrity sha512-aIay56Ph6RxOTC7xyr59Kt3ewX185SaGnAr8eWukoPLeriCrvGjvAubxuvaXOfsxhtwV5g0uBOsyhAom4qJdww== dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.3" - "@humanwhocodes/config-array" "^0.5.0" + "@eslint/eslintrc" "^1.0.4" + "@humanwhocodes/config-array" "^0.6.0" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" - debug "^4.0.1" + debug "^4.3.2" doctrine "^3.0.0" enquirer "^2.3.5" escape-string-regexp "^4.0.0" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" + eslint-scope "^7.1.0" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.1.0" + espree "^9.1.0" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" functional-red-black-tree "^1.0.1" - glob-parent "^5.1.2" + glob-parent "^6.0.1" globals "^13.6.0" ignore "^4.0.6" import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - js-yaml "^3.13.1" + js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" @@ -3040,27 +2981,21 @@ eslint@7.31.0: natural-compare "^1.4.0" optionator "^0.9.1" progress "^2.0.0" - regexpp "^3.1.0" + regexpp "^3.2.0" semver "^7.2.1" - strip-ansi "^6.0.0" + strip-ansi "^6.0.1" strip-json-comments "^3.1.0" - table "^6.0.9" text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== +espree@^9.0.0, espree@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.1.0.tgz#ba9d3c9b34eeae205724124e31de4543d59fbf74" + integrity sha512-ZgYLvCS1wxOczBYGcQT9DDWgicXwJ4dbocr9uYN+/eresBAUuBu+O4WzB21ufQ/JqQT8gyp7hJ3z8SHii32mTQ== dependencies: - acorn "^7.4.0" + acorn "^8.6.0" acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + eslint-visitor-keys "^3.1.0" esprint@3.1.0: version "3.1.0" @@ -3093,10 +3028,10 @@ estraverse@^4.1.1: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== esutils@^2.0.2: version "2.0.3" @@ -3139,9 +3074,9 @@ execa@^1.0.0: strip-eof "^1.0.0" execa@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.0.0.tgz#4029b0007998a841fbd1032e5f4de86a3c1e3376" - integrity sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ== + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== dependencies: cross-spawn "^7.0.3" get-stream "^6.0.0" @@ -3200,11 +3135,6 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" @@ -3251,17 +3181,16 @@ fast-glob@^2.2.6: merge2 "^1.2.3" micromatch "^3.1.10" -fast-glob@^3.1.1, fast-glob@^3.2.5: - version "3.2.5" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" - integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg== +fast-glob@^3.1.1, fast-glob@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" + integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" + glob-parent "^5.1.2" merge2 "^1.3.0" - micromatch "^4.0.2" - picomatch "^2.2.1" + micromatch "^4.0.4" fast-json-stable-stringify@^2.0.0: version "2.1.0" @@ -3279,9 +3208,9 @@ fastest-levenshtein@^1.0.12: integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow== fastq@^1.6.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.11.0.tgz#bb9fb955a07130a918eb63c1f5161cc32a5d0858" - integrity sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g== + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== dependencies: reusify "^1.0.4" @@ -3356,15 +3285,15 @@ fill-range@^7.0.1: to-regex-range "^5.0.1" find-cache-dir@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" - integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== + version "3.3.2" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" + integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== dependencies: commondir "^1.0.1" make-dir "^3.0.2" pkg-dir "^4.1.0" -find-up@^2.0.0, find-up@^2.1.0: +find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= @@ -3388,9 +3317,9 @@ flat-cache@^3.0.4: rimraf "^3.0.2" flatted@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469" - integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA== + version "3.2.4" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2" + integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw== focus-lock@^0.8.1: version "0.8.1" @@ -3405,9 +3334,9 @@ for-in@^1.0.2: integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= fraction.js@^4.0.13: - version "4.1.1" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.1.tgz#ac4e520473dae67012d618aab91eda09bcb400ff" - integrity sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg== + version "4.1.2" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.2.tgz#13e420a92422b6cf244dff8690ed89401029fbe8" + integrity sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA== fragment-cache@^0.2.1: version "0.2.1" @@ -3486,6 +3415,14 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -3499,13 +3436,20 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob-parent@^5.1.0, glob-parent@^5.1.2: +glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob-to-regexp@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" @@ -3517,9 +3461,9 @@ glob-to-regexp@^0.4.1: integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== glob@^7.1.3, glob@^7.1.4, glob@^7.1.7: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -3549,24 +3493,17 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.6.0: - version "13.9.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.9.0.tgz#4bf2bf635b334a173fb1daf7c5e6b218ecdc06cb" - integrity sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA== +globals@^13.6.0, globals@^13.9.0: + version "13.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" + integrity sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg== dependencies: type-fest "^0.20.2" -globals@^13.9.0: - version "13.10.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.10.0.tgz#60ba56c3ac2ca845cfbf4faeca727ad9dd204676" - integrity sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g== - dependencies: - type-fest "^0.20.2" - -globby@^11.0.1, globby@^11.0.2, globby@^11.0.3: - version "11.0.3" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.3.tgz#9b1f0cb523e171dd1ad8c7b2a9fb4b644b9593cb" - integrity sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg== +globby@^11.0.1, globby@^11.0.2, globby@^11.0.4: + version "11.0.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== dependencies: array-union "^2.1.0" dir-glob "^3.0.1" @@ -3594,13 +3531,6 @@ globjoin@^0.1.4: resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" integrity sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM= -gonzales-pe@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.3.0.tgz#fe9dec5f3c557eead09ff868c65826be54d067b3" - integrity sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ== - dependencies: - minimist "^1.2.5" - good-listener@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" @@ -3609,9 +3539,9 @@ good-listener@^1.2.2: delegate "^3.1.2" graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: - version "4.2.6" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" - integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== + version "4.2.8" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== gud@^1.0.0: version "1.0.0" @@ -3657,6 +3587,13 @@ has-symbols@^1.0.1, has-symbols@^1.0.2: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" @@ -3760,17 +3697,15 @@ html-webpack-plugin@5.3.1: pretty-error "^2.1.1" tapable "^2.0.0" -htmlparser2@^3.10.0, htmlparser2@^3.10.1: - version "3.10.1" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" - integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== +htmlparser2@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" + integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== dependencies: - domelementtype "^1.3.1" - domhandler "^2.3.0" - domutils "^1.5.1" - entities "^1.1.1" - inherits "^2.0.1" - readable-stream "^3.1.1" + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.5.2" + entities "^2.0.0" http-parser-js@>=0.5.1: version "0.5.3" @@ -3802,10 +3737,10 @@ ignore@^4.0.3, ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.4, ignore@^5.1.8: - version "5.1.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== +ignore@^5.1.4, ignore@^5.1.9: + version "5.1.9" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.9.tgz#9ec1a5cbe8e1446ec60d4420060d43aa6e7382fb" + integrity sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ== immediate@~3.0.5: version "3.0.6" @@ -3813,9 +3748,9 @@ immediate@~3.0.5: integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= "immutable@^3.8.1 || ^4.0.0-rc.1": - version "4.0.0-rc.12" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0-rc.12.tgz#ca59a7e4c19ae8d9bf74a97bdf0f6e2f2a5d0217" - integrity sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A== + version "4.0.0" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23" + integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw== import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" @@ -3831,9 +3766,9 @@ import-lazy@^4.0.0: integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== import-local@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6" - integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA== + version "3.0.3" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.3.tgz#4d51c2c495ca9393da259ec66b62e022920211e0" + integrity sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA== dependencies: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" @@ -3856,7 +3791,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: +inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -3901,25 +3836,13 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" -is-alphabetical@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" - integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== - -is-alphanumerical@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" - integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== - dependencies: - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" - is-arguments@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9" - integrity sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg== + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" + has-tostringtag "^1.0.0" is-arrayish@^0.2.1: version "0.2.1" @@ -3927,43 +3850,34 @@ is-arrayish@^0.2.1: integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= is-bigint@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.2.tgz#ffb381442503235ad245ea89e45b3dbff040ee5a" - integrity sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA== + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" is-boolean-object@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.1.tgz#3c0878f035cb821228d350d2e1e36719716a3de8" - integrity sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng== + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== dependencies: call-bind "^1.0.2" + has-tostringtag "^1.0.0" is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-buffer@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" - integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== +is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== -is-callable@^1.1.4, is-callable@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" - integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== - -is-core-module@^2.2.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1" - integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A== - dependencies: - has "^1.0.3" - -is-core-module@^2.4.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.5.0.tgz#f754843617c70bfd29b7bd87327400cda5c18491" - integrity sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg== +is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" + integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== dependencies: has "^1.0.3" @@ -3982,14 +3896,11 @@ is-data-descriptor@^1.0.0: kind-of "^6.0.0" is-date-object@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.4.tgz#550cfcc03afada05eea3dd30981c7b09551f73e5" - integrity sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A== - -is-decimal@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" - integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" is-descriptor@^0.1.0: version "0.1.6" @@ -4038,27 +3949,24 @@ is-glob@^3.0.0, is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-glob@^4.0.0, is-glob@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" -is-hexadecimal@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" - integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== - is-negative-zero@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== is-number-object@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.5.tgz#6edfaeed7950cff19afedce9fbfca9ee6dd289eb" - integrity sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw== + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + dependencies: + has-tostringtag "^1.0.0" is-number@^3.0.0: version "3.0.0" @@ -4087,11 +3995,6 @@ is-plain-obj@^1.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= -is-plain-obj@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -4099,33 +4002,45 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-regex@^1.0.4, is-regex@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.3.tgz#d029f9aff6448b93ebbe3f33dac71511fdcbef9f" - integrity sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ== +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== + +is-regex@^1.0.4, is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== dependencies: call-bind "^1.0.2" - has-symbols "^1.0.2" + has-tostringtag "^1.0.0" is-regexp@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-2.1.0.tgz#cd734a56864e23b956bf4e7c66c396a4c0b22c2d" integrity sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA== +is-shared-array-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" + integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== + is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= is-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" - integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-string@^1.0.5, is-string@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.6.tgz#3fe5d5992fb0d93404f32584d4b0179a71b54a5f" - integrity sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w== +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" is-symbol@^1.0.2, is-symbol@^1.0.3: version "1.0.4" @@ -4139,10 +4054,12 @@ is-typedarray@^1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= -is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== +is-weakref@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.1.tgz#842dba4ec17fa9ac9850df2d6efbc1737274f2a2" + integrity sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ== + dependencies: + call-bind "^1.0.0" is-windows@^1.0.2: version "1.0.2" @@ -4187,9 +4104,9 @@ isstream@^0.1.2: integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= jayson@^3.6.3: - version "3.6.4" - resolved "https://registry.yarnpkg.com/jayson/-/jayson-3.6.4.tgz#9e9d1ba2a75d811f254bceff61a096772fa04832" - integrity sha512-GH63DsRFFlodS8krFgAhxwYvQFmSwjsFxKnPrHQtp+BJj/tpeSj3hyBGGqmTkuq043U1Gn6u8VdsVRFZX1EEiQ== + version "3.6.5" + resolved "https://registry.yarnpkg.com/jayson/-/jayson-3.6.5.tgz#e560bcad4daf098c7391f46ba8efc9d6f34a4102" + integrity sha512-wmOjX+eQcnCDyPF4KORomaIj9wj3h0B5VEbeD0+2VHfTfErB+h1zpR7oBkgCZp36AFjp3+a4CLz6U72BYpFHAw== dependencies: "@types/connect" "^3.4.33" "@types/express-serve-static-core" "^4.17.9" @@ -4212,19 +4129,10 @@ jdu@1.0.0: resolved "https://registry.yarnpkg.com/jdu/-/jdu-1.0.0.tgz#28f1e388501785ae0a1d93e93ed0b14dd41e51ce" integrity sha1-KPHjiFAXha4KHZPpPtCxTdQeUc4= -jest-worker@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" - integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^7.0.0" - -jest-worker@^27.0.2: - version "27.0.6" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.0.6.tgz#a5fdb1e14ad34eb228cfe162d9f729cdbfa28aed" - integrity sha512-qupxcj/dRuA3xHPMUd40gr2EaAurFbkwzOh7wfPaeE9id7hyjURRQoqNfHifHK3XjJU6YJJUQKILGUnwGPEOCA== +jest-worker@^27.0.2, jest-worker@^27.0.6: + version "27.3.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.3.1.tgz#0def7feae5b8042be38479799aeb7b5facac24b2" + integrity sha512-ks3WCzsiZaOPJl/oMsDjaf0TRiSv7ctNgs0FqRr2nARsovz6AWWy4oLElwcquGSz692DzgZQrCLScPNs5YlC4g== dependencies: "@types/node" "*" merge-stream "^2.0.0" @@ -4240,13 +4148,12 @@ jquery@3.6.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: - argparse "^1.0.7" - esprima "^4.0.0" + argparse "^2.0.1" jsesc@^2.5.1: version "2.5.2" @@ -4258,7 +4165,7 @@ jsesc@~0.5.0: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= -json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: +json-parse-better-errors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== @@ -4317,11 +4224,11 @@ jsonparse@^1.2.0: integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= "jsx-ast-utils@^2.4.1 || ^3.0.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz#41108d2cec408c3453c1bbe8a4aae9e1e2bd8f82" - integrity sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q== + version "3.2.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b" + integrity sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA== dependencies: - array-includes "^3.1.2" + array-includes "^3.1.3" object.assign "^4.1.2" junk@^3.1.0: @@ -4364,19 +4271,19 @@ kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== klona@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0" - integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA== + version "2.0.5" + resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" + integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== -known-css-properties@^0.21.0: - version "0.21.0" - resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.21.0.tgz#15fbd0bbb83447f3ce09d8af247ed47c68ede80d" - integrity sha512-sZLUnTqimCkvkgRS+kbPlYW5o8q5w1cu+uIisKpEWkj31I8mx8kNG162DwRav8Zirkva6N5uoFsm9kzK4mUXjw== +known-css-properties@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.23.0.tgz#e643e1bab2b1f8ba292eea9557121cc02e9846a0" + integrity sha512-h9ivI88e1lFNmTT4HovBN33Ysn0OIJG7IPG2mkpx2uniQXFWqo35QdiX7w0TovlUFXfW8aPFblP5/q0jlOr2sA== lazystream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" - integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ= + version "1.0.1" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" + integrity sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw== dependencies: readable-stream "^2.0.5" @@ -4401,25 +4308,15 @@ linear-layout-vector@0.0.1: integrity sha1-OYEU1zA7bsx/1rJzr3uEAdi6nHA= lines-and-columns@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" - integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== livereload-js@^2.3.0: version "2.4.0" resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.4.0.tgz#447c31cf1ea9ab52fc20db615c5ddf678f78009c" integrity sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw== -load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - loader-runner@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" @@ -4435,18 +4332,18 @@ loader-utils@^1.4.0: json5 "^1.0.1" loader-utils@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" - integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== + version "2.0.2" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" + integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A== dependencies: big.js "^5.2.2" emojis-list "^3.0.0" json5 "^2.1.2" localforage@^1.8.1: - version "1.9.0" - resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.9.0.tgz#f3e4d32a8300b362b4634cc4e066d9d00d2f09d1" - integrity sha512-rR1oyNrKulpe+VM9cYmcFn6tsHuokyVHFaCM3+osEmxaHTbEk8oQu6eGDfS6DQLWi/N67XRmB8ECG37OES368g== + version "1.10.0" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" + integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg== dependencies: lie "3.1.1" @@ -4470,11 +4367,6 @@ lodash.camelcase@4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= - lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" @@ -4535,24 +4427,11 @@ lodash.upperfirst@4.3.1: resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" integrity sha1-E2Xt9DFIBIHvDRxolXpe2Z1J984= -lodash@4.17.21, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21: +lodash@4.17.21, lodash@^4.17.14, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" - -longest-streak@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" - integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg== - loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -4581,12 +4460,12 @@ make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0, make-dir@~3.1.0: dependencies: semver "^6.0.0" -makeerror@1.0.x: - version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" - integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== dependencies: - tmpl "1.0.x" + tmpl "1.0.5" map-cache@^0.2.2: version "0.2.2" @@ -4599,9 +4478,9 @@ map-obj@^1.0.0: integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= map-obj@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.1.tgz#e4ea399dbc979ae735c83c863dd31bdf364277b7" - integrity sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ== + version "4.3.0" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" + integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== map-visit@^1.0.0: version "1.0.0" @@ -4615,34 +4494,6 @@ mathml-tag-names@^2.1.3: resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== -mdast-util-from-markdown@^0.8.0: - version "0.8.5" - resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz#d1ef2ca42bc377ecb0463a987910dae89bd9a28c" - integrity sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ== - dependencies: - "@types/mdast" "^3.0.0" - mdast-util-to-string "^2.0.0" - micromark "~2.11.0" - parse-entities "^2.0.0" - unist-util-stringify-position "^2.0.0" - -mdast-util-to-markdown@^0.6.0: - version "0.6.5" - resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz#b33f67ca820d69e6cc527a93d4039249b504bebe" - integrity sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ== - dependencies: - "@types/unist" "^2.0.0" - longest-streak "^2.0.0" - mdast-util-to-string "^2.0.0" - parse-entities "^2.0.0" - repeat-string "^1.0.0" - zwitch "^1.0.0" - -mdast-util-to-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b" - integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w== - meow@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/meow/-/meow-9.0.0.tgz#cd9510bc5cac9dee7d03c73ee1f9ad959f4ea364" @@ -4671,14 +4522,6 @@ merge2@^1.2.3, merge2@^1.3.0: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromark@~2.11.0: - version "2.11.4" - resolved "https://registry.yarnpkg.com/micromark/-/micromark-2.11.4.tgz#d13436138eea826383e822449c9a5c50ee44665a" - integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA== - dependencies: - debug "^4.0.0" - parse-entities "^2.0.0" - micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -4698,7 +4541,7 @@ micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.2, micromatch@^4.0.4: +micromatch@^4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== @@ -4706,17 +4549,17 @@ micromatch@^4.0.2, micromatch@^4.0.4: braces "^3.0.1" picomatch "^2.2.3" -mime-db@1.47.0: - version "1.47.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.47.0.tgz#8cb313e59965d3c05cfbf898915a267af46a335c" - integrity sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw== +mime-db@1.51.0: + version "1.51.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" + integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== mime-types@^2.1.27: - version "2.1.30" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.30.tgz#6e7be8b4c479825f85ed6326695db73f9305d62d" - integrity sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg== + version "2.1.34" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" + integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== dependencies: - mime-db "1.47.0" + mime-db "1.51.0" mime@~2.5.2: version "2.5.2" @@ -4816,10 +4659,10 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nanoid@^3.1.22, nanoid@^3.1.23: - version "3.1.23" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81" - integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw== +nanoid@^3.1.22, nanoid@^3.1.30: + version "3.1.30" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" + integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ== nanomatch@^1.2.9: version "1.2.13" @@ -4878,12 +4721,12 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= -node-releases@^1.1.71: - version "1.1.72" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe" - integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw== +node-releases@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" + integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== -normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: +normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== @@ -4894,12 +4737,12 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: validate-npm-package-license "^3.0.1" normalize-package-data@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.2.tgz#cae5c410ae2434f9a6c1baa65d5bc3b9366c8699" - integrity sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg== + version "3.0.3" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" + integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== dependencies: hosted-git-info "^4.0.1" - resolve "^1.20.0" + is-core-module "^2.5.0" semver "^7.3.4" validate-npm-package-license "^3.0.1" @@ -4944,17 +4787,12 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" -nth-check@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" - integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== +nth-check@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" + integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== dependencies: - boolbase "~1.0.0" - -num2fraction@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" - integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= + boolbase "^1.0.0" object-assign@^3.0.0: version "3.0.0" @@ -4975,10 +4813,10 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.10.3, object-inspect@^1.9.0: - version "1.10.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369" - integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw== +object-inspect@^1.11.0, object-inspect@^1.9.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" + integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== object-is@^1.0.1: version "1.1.5" @@ -5010,24 +4848,31 @@ object.assign@^4.1.0, object.assign@^4.1.2: has-symbols "^1.0.1" object-keys "^1.1.1" -object.entries@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.4.tgz#43ccf9a50bc5fd5b649d45ab1a579f24e088cafd" - integrity sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA== +object.entries@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" + integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.2" + es-abstract "^1.19.1" -object.fromentries@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.4.tgz#26e1ba5c4571c5c6f0890cef4473066456a120b8" - integrity sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ== +object.fromentries@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" + integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - has "^1.0.3" + es-abstract "^1.19.1" + +object.hasown@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5" + integrity sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.19.1" object.pick@^1.3.0: version "1.3.0" @@ -5036,14 +4881,14 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" -object.values@^1.1.3, object.values@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.4.tgz#0d273762833e816b693a637d30073e7051535b30" - integrity sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg== +object.values@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" + integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.2" + es-abstract "^1.19.1" once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" @@ -5118,13 +4963,6 @@ p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -5190,26 +5028,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-entities@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" - integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== - dependencies: - character-entities "^1.0.0" - character-entities-legacy "^1.0.0" - character-reference-invalid "^1.0.0" - is-alphanumerical "^1.0.0" - is-decimal "^1.0.0" - is-hexadecimal "^1.0.0" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - parse-json@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" @@ -5297,7 +5115,12 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.3: version "2.3.0" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== @@ -5326,13 +5149,6 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" - integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= - dependencies: - find-up "^2.1.0" - plugin-error@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" @@ -5373,13 +5189,6 @@ postcss-color-function@4.1.0: postcss-message-helpers "^2.0.0" postcss-value-parser "^3.3.1" -postcss-html@^0.36.0: - version "0.36.0" - resolved "https://registry.yarnpkg.com/postcss-html/-/postcss-html-0.36.0.tgz#b40913f94eaacc2453fd30a1327ad6ee1f88b204" - integrity sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw== - dependencies: - htmlparser2 "^3.10.0" - postcss-js@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-3.0.3.tgz#2f0bd370a2e8599d45439f6970403b5873abda33" @@ -5388,13 +5197,6 @@ postcss-js@^3.0.3: camelcase-css "^2.0.1" postcss "^8.1.6" -postcss-less@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/postcss-less/-/postcss-less-3.1.4.tgz#369f58642b5928ef898ffbc1a6e93c958304c5ad" - integrity sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA== - dependencies: - postcss "^7.0.14" - postcss-loader@5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-5.2.0.tgz#ccd6668a778902d653602289c765a8bc481986dc" @@ -5464,29 +5266,12 @@ postcss-resolve-nested-selector@^0.1.1: resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz#29ccbc7c37dedfac304e9fff0bf1596b3f6a0e4e" integrity sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4= -postcss-safe-parser@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz#a6d4e48f0f37d9f7c11b2a581bf00f8ba4870b96" - integrity sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g== - dependencies: - postcss "^7.0.26" +postcss-safe-parser@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz#bb4c29894171a94bc5c996b9a30317ef402adaa1" + integrity sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ== -postcss-sass@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/postcss-sass/-/postcss-sass-0.4.4.tgz#91f0f3447b45ce373227a98b61f8d8f0785285a3" - integrity sha512-BYxnVYx4mQooOhr+zer0qWbSPYnarAy8ZT7hAQtbxtgVf8gy+LSLT/hHGe35h14/pZDTw1DsxdbrwxBN++H+fg== - dependencies: - gonzales-pe "^4.3.0" - postcss "^7.0.21" - -postcss-scss@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-2.1.1.tgz#ec3a75fa29a55e016b90bf3269026c53c1d2b383" - integrity sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA== - dependencies: - postcss "^7.0.6" - -postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5: +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.6: version "6.0.6" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== @@ -5499,18 +5284,10 @@ postcss-simple-vars@6.0.3, postcss-simple-vars@^6.0.3: resolved "https://registry.yarnpkg.com/postcss-simple-vars/-/postcss-simple-vars-6.0.3.tgz#e66516c7fe980da3498f4a8ad400b9c53861806c" integrity sha512-fkNn4Zio8vN4vIig9IFdb8lVlxWnYR769RgvxCM6YWlFKie/nQaOcaMMMFz/s4gsfHW4/5bJW+i57zD67mQU7g== -postcss-sorting@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-sorting/-/postcss-sorting-5.0.1.tgz#10d5d0059eea8334dacc820c0121864035bc3f11" - integrity sha512-Y9fUFkIhfrm6i0Ta3n+89j56EFqaNRdUKqXyRp6kvTcSXnmgEjaVowCXH+JBe9+YKWqd4nc28r2sgwnzJalccA== - dependencies: - lodash "^4.17.14" - postcss "^7.0.17" - -postcss-syntax@^0.36.2: - version "0.36.2" - resolved "https://registry.yarnpkg.com/postcss-syntax/-/postcss-syntax-0.36.2.tgz#f08578c7d95834574e5593a82dfbfa8afae3b51c" - integrity sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w== +postcss-sorting@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-sorting/-/postcss-sorting-7.0.1.tgz#923b5268451cf2d93ebf8835e17a6537757049a5" + integrity sha512-iLBFYz6VRYyLJEJsBJ8M3TCqNcckVzz4wFounSc5Oez35ogE/X+aoC5fFu103Ot7NyvjU3/xqIXn93Gp3kJk4g== postcss-url@10.1.3: version "10.1.3" @@ -5550,22 +5327,13 @@ postcss@^6.0.23: source-map "^0.6.1" supports-color "^5.4.0" -postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.26, postcss@^7.0.31, postcss@^7.0.32, postcss@^7.0.35, postcss@^7.0.6: - version "7.0.35" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.35.tgz#d2be00b998f7f211d8a276974079f2e92b970e24" - integrity sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg== +postcss@^8.1.6, postcss@^8.2.10, postcss@^8.3.11: + version "8.3.11" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.11.tgz#c3beca7ea811cd5e1c4a3ec6d2e7599ef1f8f858" + integrity sha512-hCmlUAIlUiav8Xdqw3Io4LcpA1DOt7h3LSTAC4G6JGHFFaWzI6qvFt9oilvl8BmkbBRX1IhM90ZAmpk68zccQA== dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - -postcss@^8.1.6, postcss@^8.2.10: - version "8.3.0" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.0.tgz#b1a713f6172ca427e3f05ef1303de8b65683325f" - integrity sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ== - dependencies: - colorette "^1.2.2" - nanoid "^3.1.23" + nanoid "^3.1.30" + picocolors "^1.0.0" source-map-js "^0.6.2" prefix-style@2.0.1: @@ -5906,14 +5674,6 @@ react@17.0.2: loose-envify "^1.1.0" object-assign "^4.1.1" -read-pkg-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" - integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= - dependencies: - find-up "^2.0.0" - read-pkg "^3.0.0" - read-pkg-up@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" @@ -5923,15 +5683,6 @@ read-pkg-up@^7.0.1: read-pkg "^5.2.0" type-fest "^0.8.1" -read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - read-pkg@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" @@ -5972,9 +5723,9 @@ readdir-glob@^1.0.0: minimatch "^3.0.4" rechoir@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.0.tgz#32650fd52c21ab252aa5d65b19310441c7e03aca" - integrity sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q== + version "0.7.1" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686" + integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg== dependencies: resolve "^1.9.0" @@ -6017,21 +5768,28 @@ redux-thunk@2.3.0: resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622" integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw== -redux@4.1.0, redux@^4.0.0, redux@^4.0.5: +redux@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.0.tgz#eb049679f2f523c379f1aff345c8612f294c88d4" integrity sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g== dependencies: "@babel/runtime" "^7.9.2" -regenerate-unicode-properties@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" - integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== +redux@^4.0.0, redux@^4.0.5: + version "4.1.2" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.2.tgz#140f35426d99bb4729af760afcf79eaaac407104" + integrity sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw== dependencies: - regenerate "^1.4.0" + "@babel/runtime" "^7.9.2" -regenerate@^1.4.0: +regenerate-unicode-properties@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326" + integrity sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: version "1.4.2" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== @@ -6042,9 +5800,9 @@ regenerator-runtime@^0.11.0: integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== regenerator-runtime@^0.13.4: - version "0.13.7" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" - integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== regenerator-transform@^0.14.2: version "0.14.5" @@ -6069,32 +5827,32 @@ regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.1: call-bind "^1.0.2" define-properties "^1.1.3" -regexpp@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" - integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== +regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== regexpu-core@^4.7.1: - version "4.7.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6" - integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ== + version "4.8.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.8.0.tgz#e5605ba361b67b1718478501327502f4479a98f0" + integrity sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg== dependencies: - regenerate "^1.4.0" - regenerate-unicode-properties "^8.2.0" - regjsgen "^0.5.1" - regjsparser "^0.6.4" - unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.2.0" + regenerate "^1.4.2" + regenerate-unicode-properties "^9.0.0" + regjsgen "^0.5.2" + regjsparser "^0.7.0" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.0.0" -regjsgen@^0.5.1: +regjsgen@^0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== -regjsparser@^0.6.4: - version "0.6.9" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.9.tgz#b489eef7c9a2ce43727627011429cf833a7183e6" - integrity sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ== +regjsparser@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.7.0.tgz#a6b667b54c885e18b52554cb4960ef71187e9968" + integrity sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ== dependencies: jsesc "~0.5.0" @@ -6103,51 +5861,28 @@ relateurl@^0.2.7: resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= -remark-parse@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-9.0.0.tgz#4d20a299665880e4f4af5d90b7c7b8a935853640" - integrity sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw== - dependencies: - mdast-util-from-markdown "^0.8.0" - -remark-stringify@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-9.0.1.tgz#576d06e910548b0a7191a71f27b33f1218862894" - integrity sha512-mWmNg3ZtESvZS8fv5PTvaPckdL4iNlCHTt8/e/8oN08nArHRHjNZMKzA/YW3+p7/lYqIw4nx1XsjCBo/AxNChg== - dependencies: - mdast-util-to-markdown "^0.6.0" - -remark@^13.0.0: - version "13.0.0" - resolved "https://registry.yarnpkg.com/remark/-/remark-13.0.0.tgz#d15d9bf71a402f40287ebe36067b66d54868e425" - integrity sha512-HDz1+IKGtOyWN+QgBiAT0kn+2s6ovOxHyPAFGKVE81VSzJ+mq7RwHFledEvB5F1p4iJvOah/LOKdFuzvRnNLCA== - dependencies: - remark-parse "^9.0.0" - remark-stringify "^9.0.0" - unified "^9.1.0" - remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= renderkid@^2.0.4: - version "2.0.5" - resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.5.tgz#483b1ac59c6601ab30a7a596a5965cabccfdd0a5" - integrity sha512-ccqoLg+HLOHq1vdfYNm4TBeaCDIi1FLt3wGojTDSvdewUv65oTmI3cnT2E4hRjl1gzKZIPK+KZrXzlUYKnR+vQ== + version "2.0.7" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.7.tgz#464f276a6bdcee606f4a15993f9b29fc74ca8609" + integrity sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ== dependencies: - css-select "^2.0.2" - dom-converter "^0.2" - htmlparser2 "^3.10.1" - lodash "^4.17.20" - strip-ansi "^3.0.0" + css-select "^4.1.3" + dom-converter "^0.2.0" + htmlparser2 "^6.1.0" + lodash "^4.17.21" + strip-ansi "^3.0.1" repeat-element@^1.1.2: version "1.1.4" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== -repeat-string@^1.0.0, repeat-string@^1.6.1: +repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= @@ -6209,7 +5944,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.10.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.9.0: +resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.9.0: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -6313,14 +6048,15 @@ scheduler@^0.20.2: loose-envify "^1.1.0" object-assign "^4.1.1" -schema-utils@>1.0.0, schema-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.0.0.tgz#67502f6aa2b66a2d4032b4279a2944978a0913ef" - integrity sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA== +schema-utils@>1.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" + integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== dependencies: - "@types/json-schema" "^7.0.6" - ajv "^6.12.5" - ajv-keywords "^3.5.2" + "@types/json-schema" "^7.0.9" + ajv "^8.8.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.0.0" schema-utils@^2.6.5: version "2.7.1" @@ -6331,6 +6067,15 @@ schema-utils@^2.6.5: ajv "^6.12.4" ajv-keywords "^3.5.2" +schema-utils@^3.0.0, schema-utils@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + seamless-immutable@^7.1.3: version "7.1.4" resolved "https://registry.yarnpkg.com/seamless-immutable/-/seamless-immutable-7.1.4.tgz#6e9536def083ddc4dea0207d722e0e80d0f372f8" @@ -6368,10 +6113,10 @@ semver@^7.2.1, semver@^7.3.4, semver@^7.3.5: dependencies: lru-cache "^6.0.0" -serialize-javascript@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" - integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== +serialize-javascript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== dependencies: randombytes "^2.1.0" @@ -6436,9 +6181,9 @@ side-channel@^1.0.4: object-inspect "^1.9.0" signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + version "3.0.6" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" + integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== slash@^2.0.0: version "2.0.0" @@ -6510,10 +6255,10 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@~0.5.12, source-map-support@~0.5.19: - version "0.5.19" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== +source-map-support@~0.5.12, source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -6560,9 +6305,9 @@ spdx-expression-parse@^3.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.9" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz#8a595135def9592bda69709474f1cbeea7c2467f" - integrity sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ== + version "3.0.11" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" + integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== specificity@^0.4.1: version "0.4.1" @@ -6576,11 +6321,6 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -6602,23 +6342,23 @@ string-template@~0.2.1: resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0= -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" - integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" + strip-ansi "^6.0.1" -string.prototype.matchall@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz#59370644e1db7e4c0c045277690cf7b01203c4da" - integrity sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q== +string.prototype.matchall@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" + integrity sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.2" + es-abstract "^1.19.1" get-intrinsic "^1.1.1" has-symbols "^1.0.2" internal-slot "^1.0.3" @@ -6660,19 +6400,19 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -strip-ansi@^3.0.0: +strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= dependencies: ansi-regex "^2.0.0" -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: - ansi-regex "^5.0.0" + ansi-regex "^5.0.1" strip-bom@^3.0.0: version "3.0.0" @@ -6714,76 +6454,58 @@ style-search@^0.1.0: resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI= -stylelint-order@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/stylelint-order/-/stylelint-order-4.1.0.tgz#692d05b7d0c235ac66fcf5ea1d9e5f08a76747f6" - integrity sha512-sVTikaDvMqg2aJjh4r48jsdfmqLT+nqB1MOsaBnvM3OwLx4S+WXcsxsgk5w18h/OZoxZCxuyXMh61iBHcj9Qiw== +stylelint-order@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/stylelint-order/-/stylelint-order-5.0.0.tgz#abd20f6b85ac640774cbe40e70d3fe9c6fdf4400" + integrity sha512-OWQ7pmicXufDw5BlRqzdz3fkGKJPgLyDwD1rFY3AIEfIH/LQY38Vu/85v8/up0I+VPiuGRwbc2Hg3zLAsJaiyw== dependencies: - lodash "^4.17.15" - postcss "^7.0.31" - postcss-sorting "^5.0.1" + postcss "^8.3.11" + postcss-sorting "^7.0.1" -stylelint@13.13.1: - version "13.13.1" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-13.13.1.tgz#fca9c9f5de7990ab26a00f167b8978f083a18f3c" - integrity sha512-Mv+BQr5XTUrKqAXmpqm6Ddli6Ief+AiPZkRsIrAoUKFuq/ElkUh9ZMYxXD0iQNZ5ADghZKLOWz1h7hTClB7zgQ== +stylelint@14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.1.0.tgz#8cefb64df6158b30f678c2d93a7052e2c1d8235b" + integrity sha512-IedkssuNVA11+v++2PIV2OHOU5A3SfRcXVi56vZVSsMhGrgtwmmit69jeM+08/Tun5DTBe7BuH1Zp1mMLmtKLA== dependencies: - "@stylelint/postcss-css-in-js" "^0.37.2" - "@stylelint/postcss-markdown" "^0.36.2" - autoprefixer "^9.8.6" balanced-match "^2.0.0" - chalk "^4.1.1" - cosmiconfig "^7.0.0" - debug "^4.3.1" + cosmiconfig "^7.0.1" + debug "^4.3.2" execall "^2.0.0" - fast-glob "^3.2.5" + fast-glob "^3.2.7" fastest-levenshtein "^1.0.12" file-entry-cache "^6.0.1" get-stdin "^8.0.0" global-modules "^2.0.0" - globby "^11.0.3" + globby "^11.0.4" globjoin "^0.1.4" html-tags "^3.1.0" - ignore "^5.1.8" + ignore "^5.1.9" import-lazy "^4.0.0" imurmurhash "^0.1.4" - known-css-properties "^0.21.0" - lodash "^4.17.21" - log-symbols "^4.1.0" + is-plain-object "^5.0.0" + known-css-properties "^0.23.0" mathml-tag-names "^2.1.3" meow "^9.0.0" micromatch "^4.0.4" + normalize-path "^3.0.0" normalize-selector "^0.2.0" - postcss "^7.0.35" - postcss-html "^0.36.0" - postcss-less "^3.1.4" + picocolors "^1.0.0" + postcss "^8.3.11" postcss-media-query-parser "^0.2.3" postcss-resolve-nested-selector "^0.1.1" - postcss-safe-parser "^4.0.2" - postcss-sass "^0.4.4" - postcss-scss "^2.1.1" - postcss-selector-parser "^6.0.5" - postcss-syntax "^0.36.2" + postcss-safe-parser "^6.0.0" + postcss-selector-parser "^6.0.6" postcss-value-parser "^4.1.0" resolve-from "^5.0.0" - slash "^3.0.0" specificity "^0.4.1" - string-width "^4.2.2" - strip-ansi "^6.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" style-search "^0.1.0" - sugarss "^2.0.0" svg-tags "^1.0.0" - table "^6.6.0" + table "^6.7.3" v8-compile-cache "^2.3.0" write-file-atomic "^3.0.3" -sugarss@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-2.0.0.tgz#ddd76e0124b297d40bf3cca31c8b22ecb43bc61d" - integrity sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ== - dependencies: - postcss "^7.0.2" - sugarss@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-3.0.3.tgz#bb2489961b98fbd15e4e35d6b9f4f2ee5547a6cb" @@ -6803,14 +6525,7 @@ supports-color@^5.3.0, supports-color@^5.4.0: dependencies: has-flag "^3.0.0" -supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.0.0, supports-color@^7.1.0: +supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -6829,22 +6544,21 @@ svg-tags@^1.0.0: resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= -table@^6.0.9, table@^6.6.0: - version "6.7.1" - resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2" - integrity sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg== +table@^6.7.3: + version "6.7.3" + resolved "https://registry.yarnpkg.com/table/-/table-6.7.3.tgz#255388439715a738391bd2ee4cbca89a4d05a9b7" + integrity sha512-5DkIxeA7XERBqMwJq0aHZOdMadBx4e6eDoFRuyT5VR82J0Ycg2DwM6GfA/EQAhJ+toRTaS1lIdSQCqgrmhPnlw== dependencies: ajv "^8.0.1" - lodash.clonedeep "^4.5.0" lodash.truncate "^4.4.2" slice-ansi "^4.0.0" - string-width "^4.2.0" - strip-ansi "^6.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b" - integrity sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw== + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== tar-stream@^2.2.0: version "2.2.0" @@ -6858,16 +6572,15 @@ tar-stream@^2.2.0: readable-stream "^3.1.1" terser-webpack-plugin@^5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.1.2.tgz#51d295eb7cc56785a67a372575fdc46e42d5c20c" - integrity sha512-6QhDaAiVHIQr5Ab3XUWZyDmrIPCHMiqJVljMF91YKyqwKkL5QHnYMkrMBy96v9Z7ev1hGhSEw1HQZc2p/s5Z8Q== + version "5.2.5" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.2.5.tgz#ce65b9880a0c36872555c4874f45bbdb02ee32c9" + integrity sha512-3luOVHku5l0QBeYS8r4CdHYWEGMmIj3H1U64jgkdZzECcSOJAyJ9TjuqcQZvw1Y+4AOBN9SeYJPJmFn2cM4/2g== dependencies: - jest-worker "^26.6.2" - p-limit "^3.1.0" - schema-utils "^3.0.0" - serialize-javascript "^5.0.1" + jest-worker "^27.0.6" + schema-utils "^3.1.1" + serialize-javascript "^6.0.0" source-map "^0.6.1" - terser "^5.7.0" + terser "^5.7.2" terser@^4.6.3: version "4.8.0" @@ -6878,14 +6591,14 @@ terser@^4.6.3: source-map "~0.6.1" source-map-support "~0.5.12" -terser@^5.7.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.0.tgz#a761eeec206bc87b605ab13029876ead938ae693" - integrity sha512-HP5/9hp2UaZt5fYkuhNBR8YyRcT8juw8+uFbAme53iN9hblvKnLUTKkmwJG6ocWpIKf8UK4DoeWG4ty0J6S6/g== +terser@^5.7.2: + version "5.10.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" + integrity sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA== dependencies: commander "^2.20.0" source-map "~0.7.2" - source-map-support "~0.5.19" + source-map-support "~0.5.20" text-table@^0.2.0: version "0.2.0" @@ -6908,9 +6621,9 @@ tiny-emitter@^2.0.0: integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== tiny-invariant@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" - integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== + version "1.2.0" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" + integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg== tiny-lr@^1.1.1: version "1.1.1" @@ -6929,10 +6642,10 @@ tiny-warning@^1.0.0, tiny-warning@^1.0.3: resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== -tmpl@1.0.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" - integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== to-camel-case@1.0.0, to-camel-case@^1.0.0: version "1.0.0" @@ -7009,15 +6722,10 @@ trim-newlines@^3.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== -trough@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" - integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== - -tsconfig-paths@^3.9.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" - integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== +tsconfig-paths@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b" + integrity sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.1" @@ -7030,9 +6738,9 @@ tslib@^1.9.3: integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tslib@^2.0.3: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" - integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" @@ -7083,40 +6791,28 @@ unbox-primitive@^1.0.1: has-symbols "^1.0.2" which-boxed-primitive "^1.0.2" -unicode-canonical-property-names-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" - integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== -unicode-match-property-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" - integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" -unicode-match-property-value-ecmascript@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" - integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== +unicode-match-property-value-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" + integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== -unicode-property-aliases-ecmascript@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" - integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== - -unified@^9.1.0: - version "9.2.1" - resolved "https://registry.yarnpkg.com/unified/-/unified-9.2.1.tgz#ae18d5674c114021bfdbdf73865ca60f410215a3" - integrity sha512-juWjuI8Z4xFg8pJbnEZ41b5xjGUWGHqXALmBZ3FC3WX0PIx1CZBIIJ6mXbYMcf6Yw4Fi0rFUTA1cdz/BglbOhA== - dependencies: - bail "^1.0.0" - extend "^3.0.0" - is-buffer "^2.0.0" - is-plain-obj "^2.0.0" - trough "^1.0.0" - vfile "^4.0.0" +unicode-property-aliases-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" + integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== union-value@^1.0.0: version "1.0.1" @@ -7128,25 +6824,6 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^2.0.1" -unist-util-find-all-after@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/unist-util-find-all-after/-/unist-util-find-all-after-3.0.2.tgz#fdfecd14c5b7aea5e9ef38d5e0d5f774eeb561f6" - integrity sha512-xaTC/AGZ0rIM2gM28YVRAFPIZpzbpDtU3dRmp7EXlNVA8ziQc4hY3H7BHXM1J49nEmiqc3svnqMReW+PGqbZKQ== - dependencies: - unist-util-is "^4.0.0" - -unist-util-is@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" - integrity sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg== - -unist-util-stringify-position@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" - integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g== - dependencies: - "@types/unist" "^2.0.2" - universalify@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -7187,9 +6864,9 @@ url-loader@4.1.1: schema-utils "^3.0.0" url-parse@^1.4.3: - version "1.5.1" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.1.tgz#d5fa9890af8a5e1f274a2c98376510f6425f6e3b" - integrity sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q== + version "1.5.3" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862" + integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ== dependencies: querystringify "^2.1.1" requires-port "^1.0.0" @@ -7245,30 +6922,12 @@ value-equal@^1.0.1: resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== -vfile-message@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a" - integrity sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ== - dependencies: - "@types/unist" "^2.0.0" - unist-util-stringify-position "^2.0.0" - -vfile@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-4.2.1.tgz#03f1dce28fc625c625bc6514350fbdb00fa9e624" - integrity sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA== - dependencies: - "@types/unist" "^2.0.0" - is-buffer "^2.0.0" - unist-util-stringify-position "^2.0.0" - vfile-message "^2.0.0" - walker@~1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" - integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== dependencies: - makeerror "1.0.x" + makeerror "1.0.12" warning@^4.0.2, warning@^4.0.3: version "4.0.3" @@ -7321,9 +6980,9 @@ webpack-livereload-plugin@3.0.1: tiny-lr "^1.1.1" webpack-merge@^5.7.3: - version "5.7.3" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.7.3.tgz#2a0754e1877a25a8bbab3d2475ca70a052708213" - integrity sha512-6/JUQv0ELQ1igjGDzHkXbVDRxkfA57Zw7PfiupdLFJYrgFqY5ZP8xxbpp2lU3EPwYx89ht5Z/aDkD40hFCm5AA== + version "5.8.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" + integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== dependencies: clone-deep "^4.0.1" wildcard "^2.0.0" @@ -7337,9 +6996,9 @@ webpack-sources@^1.1.0: source-map "~0.6.1" webpack-sources@^2.1.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.3.0.tgz#9ed2de69b25143a4c18847586ad9eccb19278cfa" - integrity sha512-WyOdtwSvOML1kbgtXbTDnEW0jkJ7hZr/bDByIwszhWd/4XX1A3XMkrbFMsuH4+/MfLlZCUzlAdg4r7jaGKEIgQ== + version "2.3.1" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.3.1.tgz#570de0af163949fe272233c2cefe1b56f74511fd" + integrity sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA== dependencies: source-list-map "^2.0.1" source-map "^0.6.1" @@ -7455,9 +7114,9 @@ write-file-atomic@^3.0.3: typedarray-to-buffer "^3.1.5" ws@^7.4.5: - version "7.5.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74" - integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg== + version "7.5.5" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881" + integrity sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w== xxhashjs@~0.2.2: version "0.2.2" @@ -7482,14 +7141,14 @@ yaml@^1.10.0: integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== yargs-parser@^20.2.2, yargs-parser@^20.2.3: - version "20.2.7" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" - integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== yargs@^17.0.1: - version "17.0.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.0.1.tgz#6a1ced4ed5ee0b388010ba9fd67af83b9362e0bb" - integrity sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ== + version "17.2.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.2.1.tgz#e2c95b9796a0e1f7f3bf4427863b42e0418191ea" + integrity sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q== dependencies: cliui "^7.0.2" escalade "^3.1.1" @@ -7499,11 +7158,6 @@ yargs@^17.0.1: y18n "^5.0.5" yargs-parser "^20.2.2" -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - zip-stream@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.0.tgz#51dd326571544e36aa3f756430b313576dc8fc79" @@ -7512,8 +7166,3 @@ zip-stream@^4.1.0: archiver-utils "^2.1.0" compress-commons "^4.1.0" readable-stream "^3.6.0" - -zwitch@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" - integrity sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw== From 4273f2d6f33d683462c1c77853dc86f1b9f8cbca Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 21 Nov 2021 18:00:02 -0600 Subject: [PATCH 0168/2320] Bump Webpack to 5.64.2 --- package.json | 6 +- yarn.lock | 305 ++++++++++++++++++++++++++------------------------- 2 files changed, 156 insertions(+), 155 deletions(-) diff --git a/package.json b/package.json index 33ae8b796..b5a1e0255 100644 --- a/package.json +++ b/package.json @@ -124,8 +124,8 @@ "stylelint": "14.1.0", "stylelint-order": "5.0.0", "url-loader": "4.1.1", - "webpack": "5.35.1", - "webpack-cli": "4.6.0", - "webpack-livereload-plugin": "3.0.1" + "webpack": "5.64.2", + "webpack-cli": "4.9.1", + "webpack-livereload-plugin": "3.0.2" } } diff --git a/yarn.lock b/yarn.lock index 84c7f5d61..c408c9763 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1220,16 +1220,11 @@ "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*": +"@types/estree@*", "@types/estree@^0.0.50": version "0.0.50" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== -"@types/estree@^0.0.47": - version "0.0.47" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.47.tgz#d7a51db20f0650efec24cd04994f523d93172ed4" - integrity sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg== - "@types/express-serve-static-core@^4.17.9": version "4.17.25" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.25.tgz#e42f7046adc65ece2eb6059b77aecfbe9e9f82e0" @@ -1351,140 +1346,140 @@ dependencies: "@types/node" "*" -"@webassemblyjs/ast@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.0.tgz#a5aa679efdc9e51707a4207139da57920555961f" - integrity sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg== +"@webassemblyjs/ast@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" + integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== dependencies: - "@webassemblyjs/helper-numbers" "1.11.0" - "@webassemblyjs/helper-wasm-bytecode" "1.11.0" + "@webassemblyjs/helper-numbers" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" -"@webassemblyjs/floating-point-hex-parser@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz#34d62052f453cd43101d72eab4966a022587947c" - integrity sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA== +"@webassemblyjs/floating-point-hex-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" + integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== -"@webassemblyjs/helper-api-error@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz#aaea8fb3b923f4aaa9b512ff541b013ffb68d2d4" - integrity sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w== +"@webassemblyjs/helper-api-error@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" + integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== -"@webassemblyjs/helper-buffer@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz#d026c25d175e388a7dbda9694e91e743cbe9b642" - integrity sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA== +"@webassemblyjs/helper-buffer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" + integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== -"@webassemblyjs/helper-numbers@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz#7ab04172d54e312cc6ea4286d7d9fa27c88cd4f9" - integrity sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ== +"@webassemblyjs/helper-numbers@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" + integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.0" - "@webassemblyjs/helper-api-error" "1.11.0" + "@webassemblyjs/floating-point-hex-parser" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" "@xtuc/long" "4.2.2" -"@webassemblyjs/helper-wasm-bytecode@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz#85fdcda4129902fe86f81abf7e7236953ec5a4e1" - integrity sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA== +"@webassemblyjs/helper-wasm-bytecode@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" + integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== -"@webassemblyjs/helper-wasm-section@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz#9ce2cc89300262509c801b4af113d1ca25c1a75b" - integrity sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew== +"@webassemblyjs/helper-wasm-section@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" + integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== dependencies: - "@webassemblyjs/ast" "1.11.0" - "@webassemblyjs/helper-buffer" "1.11.0" - "@webassemblyjs/helper-wasm-bytecode" "1.11.0" - "@webassemblyjs/wasm-gen" "1.11.0" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" -"@webassemblyjs/ieee754@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz#46975d583f9828f5d094ac210e219441c4e6f5cf" - integrity sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA== +"@webassemblyjs/ieee754@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" + integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/leb128@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.0.tgz#f7353de1df38aa201cba9fb88b43f41f75ff403b" - integrity sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g== +"@webassemblyjs/leb128@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" + integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== dependencies: "@xtuc/long" "4.2.2" -"@webassemblyjs/utf8@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.0.tgz#86e48f959cf49e0e5091f069a709b862f5a2cadf" - integrity sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw== +"@webassemblyjs/utf8@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" + integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== -"@webassemblyjs/wasm-edit@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz#ee4a5c9f677046a210542ae63897094c2027cb78" - integrity sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ== +"@webassemblyjs/wasm-edit@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" + integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== dependencies: - "@webassemblyjs/ast" "1.11.0" - "@webassemblyjs/helper-buffer" "1.11.0" - "@webassemblyjs/helper-wasm-bytecode" "1.11.0" - "@webassemblyjs/helper-wasm-section" "1.11.0" - "@webassemblyjs/wasm-gen" "1.11.0" - "@webassemblyjs/wasm-opt" "1.11.0" - "@webassemblyjs/wasm-parser" "1.11.0" - "@webassemblyjs/wast-printer" "1.11.0" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/helper-wasm-section" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-opt" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + "@webassemblyjs/wast-printer" "1.11.1" -"@webassemblyjs/wasm-gen@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz#3cdb35e70082d42a35166988dda64f24ceb97abe" - integrity sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ== +"@webassemblyjs/wasm-gen@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" + integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== dependencies: - "@webassemblyjs/ast" "1.11.0" - "@webassemblyjs/helper-wasm-bytecode" "1.11.0" - "@webassemblyjs/ieee754" "1.11.0" - "@webassemblyjs/leb128" "1.11.0" - "@webassemblyjs/utf8" "1.11.0" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" -"@webassemblyjs/wasm-opt@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz#1638ae188137f4bb031f568a413cd24d32f92978" - integrity sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg== +"@webassemblyjs/wasm-opt@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" + integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== dependencies: - "@webassemblyjs/ast" "1.11.0" - "@webassemblyjs/helper-buffer" "1.11.0" - "@webassemblyjs/wasm-gen" "1.11.0" - "@webassemblyjs/wasm-parser" "1.11.0" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" -"@webassemblyjs/wasm-parser@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz#3e680b8830d5b13d1ec86cc42f38f3d4a7700754" - integrity sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw== +"@webassemblyjs/wasm-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" + integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== dependencies: - "@webassemblyjs/ast" "1.11.0" - "@webassemblyjs/helper-api-error" "1.11.0" - "@webassemblyjs/helper-wasm-bytecode" "1.11.0" - "@webassemblyjs/ieee754" "1.11.0" - "@webassemblyjs/leb128" "1.11.0" - "@webassemblyjs/utf8" "1.11.0" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" -"@webassemblyjs/wast-printer@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz#680d1f6a5365d6d401974a8e949e05474e1fab7e" - integrity sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ== +"@webassemblyjs/wast-printer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" + integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== dependencies: - "@webassemblyjs/ast" "1.11.0" + "@webassemblyjs/ast" "1.11.1" "@xtuc/long" "4.2.2" -"@webpack-cli/configtest@^1.0.2": +"@webpack-cli/configtest@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.1.0.tgz#8342bef0badfb7dfd3b576f2574ab80c725be043" integrity sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg== -"@webpack-cli/info@^1.2.3": +"@webpack-cli/info@^1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.4.0.tgz#b9179c3227ab09cbbb149aa733475fcf99430223" integrity sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw== dependencies: envinfo "^7.7.3" -"@webpack-cli/serve@^1.3.1": +"@webpack-cli/serve@^1.6.0": version "1.6.0" resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.0.tgz#2c275aa05c895eccebbfc34cfb223c6e8bd591a2" integrity sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA== @@ -1514,12 +1509,17 @@ abort-controller@^3.0.0: dependencies: event-target-shim "^5.0.0" +acorn-import-assertions@^1.7.6: + version "1.8.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" + integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== + acorn-jsx@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.0.4, acorn@^8.6.0: +acorn@^8.4.1, acorn@^8.6.0: version "8.6.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895" integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw== @@ -2251,11 +2251,16 @@ color@^0.11.0: color-convert "^1.3.0" color-string "^0.3.0" -colorette@^1.2.1, colorette@^1.2.2: +colorette@^1.2.2: version "1.4.0" resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== +colorette@^2.0.14: + version "2.0.16" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" + integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== + commander@^2.20.0, commander@^2.20.3: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -2729,7 +2734,7 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -enhanced-resolve@^5.8.0: +enhanced-resolve@^5.8.3: version "5.8.3" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0" integrity sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA== @@ -2737,7 +2742,7 @@ enhanced-resolve@^5.8.0: graceful-fs "^4.2.4" tapable "^2.2.0" -enquirer@^2.3.5, enquirer@^2.3.6: +enquirer@^2.3.5: version "2.3.6" resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== @@ -2794,10 +2799,10 @@ es-abstract@^1.19.0, es-abstract@^1.19.1: string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.1" -es-module-lexer@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.4.1.tgz#dda8c6a14d8f340a24e34331e0fab0cb50438e0e" - integrity sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA== +es-module-lexer@^0.9.0: + version "0.9.3" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" + integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== es-to-primitive@^1.2.1: version "1.2.1" @@ -2906,7 +2911,7 @@ eslint-plugin-simple-import-sort@7.0.0: resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-7.0.0.tgz#a1dad262f46d2184a90095a60c66fef74727f0f8" integrity sha512-U3vEDB5zhYPNfxT5TYR7u01dboFZp+HNpnGhkDB2g/2E4wZ/g1Q9Ton8UwCLfRV9yAKyYqDh62oHOamvkFxsvw== -eslint-scope@^5.1.0, eslint-scope@^5.1.1: +eslint-scope@5.1.1, eslint-scope@^5.1.0: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -6067,7 +6072,7 @@ schema-utils@^2.6.5: ajv "^6.12.4" ajv-keywords "^3.5.2" -schema-utils@^3.0.0, schema-utils@^3.1.1: +schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== @@ -6234,7 +6239,7 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -source-list-map@^2.0.0, source-list-map@^2.0.1: +source-list-map@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== @@ -6571,7 +6576,7 @@ tar-stream@^2.2.0: inherits "^2.0.3" readable-stream "^3.1.1" -terser-webpack-plugin@^5.1.1: +terser-webpack-plugin@^5.1.3: version "5.2.5" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.2.5.tgz#ce65b9880a0c36872555c4874f45bbdb02ee32c9" integrity sha512-3luOVHku5l0QBeYS8r4CdHYWEGMmIj3H1U64jgkdZzECcSOJAyJ9TjuqcQZvw1Y+4AOBN9SeYJPJmFn2cM4/2g== @@ -6904,7 +6909,7 @@ uuid@^3.4.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -v8-compile-cache@^2.0.3, v8-compile-cache@^2.2.0, v8-compile-cache@^2.3.0: +v8-compile-cache@^2.0.3, v8-compile-cache@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== @@ -6936,7 +6941,7 @@ warning@^4.0.2, warning@^4.0.3: dependencies: loose-envify "^1.0.0" -watchpack@^2.0.0: +watchpack@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.2.0.tgz#47d78f5415fe550ecd740f99fe2882323a58b1ce" integrity sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA== @@ -6949,30 +6954,28 @@ webidl-conversions@^3.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= -webpack-cli@4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.6.0.tgz#27ae86bfaec0cf393fcfd58abdc5a229ad32fd16" - integrity sha512-9YV+qTcGMjQFiY7Nb1kmnupvb1x40lfpj8pwdO/bom+sQiP4OBMKjHq29YQrlDWDPZO9r/qWaRRywKaRDKqBTA== +webpack-cli@4.9.1: + version "4.9.1" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.1.tgz#b64be825e2d1b130f285c314caa3b1ba9a4632b3" + integrity sha512-JYRFVuyFpzDxMDB+v/nanUdQYcZtqFPGzmlW4s+UkPMFhSpfRNmf1z4AwYcHJVdvEFAM7FFCQdNTpsBYhDLusQ== dependencies: "@discoveryjs/json-ext" "^0.5.0" - "@webpack-cli/configtest" "^1.0.2" - "@webpack-cli/info" "^1.2.3" - "@webpack-cli/serve" "^1.3.1" - colorette "^1.2.1" + "@webpack-cli/configtest" "^1.1.0" + "@webpack-cli/info" "^1.4.0" + "@webpack-cli/serve" "^1.6.0" + colorette "^2.0.14" commander "^7.0.0" - enquirer "^2.3.6" execa "^5.0.0" fastest-levenshtein "^1.0.12" import-local "^3.0.2" interpret "^2.2.0" rechoir "^0.7.0" - v8-compile-cache "^2.2.0" webpack-merge "^5.7.3" -webpack-livereload-plugin@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webpack-livereload-plugin/-/webpack-livereload-plugin-3.0.1.tgz#89b9b6978a13735f00f9b6f55661a7aa605d5be0" - integrity sha512-HFjUFH9kY8P5l8jYqiKsa9keE/DN1riOWH5l6VV27c9j/5rlqWLK0PPbErgqRyP1FON5GuKOgvOJo+0Ep0mYyQ== +webpack-livereload-plugin@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/webpack-livereload-plugin/-/webpack-livereload-plugin-3.0.2.tgz#b12f4ab56c75f03715eb32883bc2f24621f06da1" + integrity sha512-5JeZ2dgsvSNG+clrkD/u2sEiPcNk4qwCVZZmW8KpqKcNlkGv7IJjdVrq13+etAmMZYaCF1EGXdHkVFuLgP4zfw== dependencies: anymatch "^3.1.1" portfinder "^1.0.17" @@ -6995,30 +6998,28 @@ webpack-sources@^1.1.0: source-list-map "^2.0.0" source-map "~0.6.1" -webpack-sources@^2.1.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.3.1.tgz#570de0af163949fe272233c2cefe1b56f74511fd" - integrity sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA== - dependencies: - source-list-map "^2.0.1" - source-map "^0.6.1" +webpack-sources@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.2.tgz#d88e3741833efec57c4c789b6010db9977545260" + integrity sha512-cp5qdmHnu5T8wRg2G3vZZHoJPN14aqQ89SyQ11NpGH5zEMDCclt49rzo+MaRazk7/UeILhAI+/sEtcM+7Fr0nw== -webpack@5.35.1: - version "5.35.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.35.1.tgz#857670799465c8a5cbb94c4c175d60ac42d18ba3" - integrity sha512-uWKYStqJ23+N6/EnMEwUjPSSKUG1tFmcuKhALEh/QXoUxwN8eb3ATNIZB38A+fO6QZ0xfc7Cu7KNV9LXNhDCsw== +webpack@5.64.2: + version "5.64.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.64.2.tgz#152e28d4712a6223b06c06cba0d3e622a61611a0" + integrity sha512-4KGc0+Ozi0aS3EaLNRvEppfZUer+CaORKqL6OBjDLZOPf9YfN8leagFzwe6/PoBdHFxc/utKArl8LMC0Ivtmdg== dependencies: "@types/eslint-scope" "^3.7.0" - "@types/estree" "^0.0.47" - "@webassemblyjs/ast" "1.11.0" - "@webassemblyjs/wasm-edit" "1.11.0" - "@webassemblyjs/wasm-parser" "1.11.0" - acorn "^8.0.4" + "@types/estree" "^0.0.50" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/wasm-edit" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + acorn "^8.4.1" + acorn-import-assertions "^1.7.6" browserslist "^4.14.5" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.8.0" - es-module-lexer "^0.4.0" - eslint-scope "^5.1.1" + enhanced-resolve "^5.8.3" + es-module-lexer "^0.9.0" + eslint-scope "5.1.1" events "^3.2.0" glob-to-regexp "^0.4.1" graceful-fs "^4.2.4" @@ -7026,11 +7027,11 @@ webpack@5.35.1: loader-runner "^4.2.0" mime-types "^2.1.27" neo-async "^2.6.2" - schema-utils "^3.0.0" + schema-utils "^3.1.0" tapable "^2.1.1" - terser-webpack-plugin "^5.1.1" - watchpack "^2.0.0" - webpack-sources "^2.1.1" + terser-webpack-plugin "^5.1.3" + watchpack "^2.2.0" + webpack-sources "^3.2.2" websocket-driver@>=0.5.1: version "0.7.4" From 230a0e5aa0e22df4a37cece6f2ff04590c39fa7d Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 21 Nov 2021 18:03:07 -0600 Subject: [PATCH 0169/2320] Bump Sentry to 6.15.0 --- package.json | 4 +-- yarn.lock | 84 ++++++++++++++++++++++++++-------------------------- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/package.json b/package.json index b5a1e0255..923e58c92 100644 --- a/package.json +++ b/package.json @@ -31,8 +31,8 @@ "@fortawesome/free-solid-svg-icons": "5.15.3", "@fortawesome/react-fontawesome": "0.1.14", "@microsoft/signalr": "6.0.0", - "@sentry/browser": "6.10.0", - "@sentry/integrations": "6.10.0", + "@sentry/browser": "6.15.0", + "@sentry/integrations": "6.15.0", "chart.js": "3.2.0", "classnames": "2.3.1", "clipboard": "2.0.8", diff --git a/yarn.lock b/yarn.lock index c408c9763..b8657a34a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1135,66 +1135,66 @@ resolved "https://registry.yarnpkg.com/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz#a3031eb54129f2c66b2753f8404266ec7bf67f0a" integrity sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg== -"@sentry/browser@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.10.0.tgz#92e72edca584d940fba80cf6477d4a54c6dea573" - integrity sha512-H0Blgp8f8bomebkkGWIgxHVjabtQAlsKJDiFXBg7gIc75YcarRxwH0R3hMog1/h8mmv4CGGUsy5ljYW6jsNnvA== +"@sentry/browser@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.15.0.tgz#7a1d316dd31cedee446e359a21774bf93d1e553d" + integrity sha512-ZiqfHK5DMVgDsgMTuSwxilWIqEnZzy4yuJ9Sr6Iap1yZddPSiKHYjbBieSHn57UsWHViRB3ojbwu44LfvXKJdQ== dependencies: - "@sentry/core" "6.10.0" - "@sentry/types" "6.10.0" - "@sentry/utils" "6.10.0" + "@sentry/core" "6.15.0" + "@sentry/types" "6.15.0" + "@sentry/utils" "6.15.0" tslib "^1.9.3" -"@sentry/core@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.10.0.tgz#70af9dc72bb6a5b59062a31b7de023f7f1878357" - integrity sha512-5KlxHJlbD7AMo+b9pMGkjxUOfMILtsqCtGgI7DMvZNfEkdohO8QgUY+hPqr540kmwArFS91ipQYWhqzGaOhM3Q== +"@sentry/core@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.15.0.tgz#5e877042fe18452f2273247126b32e139d5f907c" + integrity sha512-mCbKyqvD1G3Re6gv6N8tRkBz84gvVWDfLtC6d1WBArIopzter6ktEbvq0cMT6EOvGI2OLXuJ6mtHA93/Q0gGpw== dependencies: - "@sentry/hub" "6.10.0" - "@sentry/minimal" "6.10.0" - "@sentry/types" "6.10.0" - "@sentry/utils" "6.10.0" + "@sentry/hub" "6.15.0" + "@sentry/minimal" "6.15.0" + "@sentry/types" "6.15.0" + "@sentry/utils" "6.15.0" tslib "^1.9.3" -"@sentry/hub@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.10.0.tgz#d59be18016426fd3a5e8d38712c2080466aafe3c" - integrity sha512-MV8wjhWiFAXZAhmj7Ef5QdBr2IF93u8xXiIo2J+dRZ7eVa4/ZszoUiDbhUcl/TPxczaw4oW2a6tINBNFLzXiig== +"@sentry/hub@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.15.0.tgz#fb8a91d12fdd2726a884374ea7242f6bbd081d69" + integrity sha512-cUbHPeG6kKpGBaEMgbTWeU03Y1Up5T3urGF+cgtrn80PmPYYSUPvVvWlZQWPb8CJZ1yQ0gySWo5RUTatBFrEHA== dependencies: - "@sentry/types" "6.10.0" - "@sentry/utils" "6.10.0" + "@sentry/types" "6.15.0" + "@sentry/utils" "6.15.0" tslib "^1.9.3" -"@sentry/integrations@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-6.10.0.tgz#f8f9e7efd55ec44d0408bd4493df1c9ceabaaa63" - integrity sha512-NMtB0jjFYFZRxyjYu2dWLThk9YPIwqhi4hYywmWkbv4/ILzi5Rwnh+aqNW6yrj8qG4b9itNMh3YvEzmf0aqauw== +"@sentry/integrations@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-6.15.0.tgz#3c83617c301b5f77a57514ad7812aedc03613a31" + integrity sha512-fSBAipas6zwyYo4U91pyQOnaTcRCfwvH6ZFwu0Fqmkm64nU9rYpbTNiKkwOWbbiXXT6+LEF6RzBpsyhm4QvgmQ== dependencies: - "@sentry/types" "6.10.0" - "@sentry/utils" "6.10.0" + "@sentry/types" "6.15.0" + "@sentry/utils" "6.15.0" localforage "^1.8.1" tslib "^1.9.3" -"@sentry/minimal@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.10.0.tgz#9404b93fae649b6c48e1da8f0991b87cf9999561" - integrity sha512-yarm046UgUFIBoxqnBan2+BEgaO9KZCrLzsIsmALiQvpfW92K1lHurSawl5W6SR7wCYBnNn7CPvPE/BHFdy4YA== +"@sentry/minimal@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.15.0.tgz#fcc083ba901cfe57d25303d0b5fa8cd13e164466" + integrity sha512-7RJIvZsjBa1qFUfMrAzQsWdfZT6Gm4t6ZTYfkpsXPBA35hkzglKbBrhhsUvkxGIhUGw/PiCUqxBUjcmzQP0vfg== dependencies: - "@sentry/hub" "6.10.0" - "@sentry/types" "6.10.0" + "@sentry/hub" "6.15.0" + "@sentry/types" "6.15.0" tslib "^1.9.3" -"@sentry/types@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.10.0.tgz#6b1f44e5ed4dbc2710bead24d1b32fb08daf04e1" - integrity sha512-M7s0JFgG7/6/yNVYoPUbxzaXDhnzyIQYRRJJKRaTD77YO4MHvi4Ke8alBWqD5fer0cPIfcSkBqa9BLdqRqcMWw== +"@sentry/types@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.15.0.tgz#a2917f8aed91471bdfd6651384ffcd47b95c43ad" + integrity sha512-zBw5gPUsofXUSpS3ZAXqRNedLRBvirl3sqkj2Lez7X2EkKRgn5D8m9fQIrig/X3TsKcXUpijDW5Buk5zeCVzJA== -"@sentry/utils@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.10.0.tgz#839a099fa0a1f0ca0893c7ce8c55ba0608c1d80f" - integrity sha512-F9OczOcZMFtazYVZ6LfRIe65/eOfQbiAedIKS0li4npuMz0jKYRbxrjd/U7oLiNQkPAp4/BujU4m1ZIwq6a+tg== +"@sentry/utils@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.15.0.tgz#0c247cb092b1796d39c3d16d8e6977b9cdab9ca2" + integrity sha512-gnhKKyFtnNmKWjDizo7VKD0/Vx8cgW1lCusM6WI7jy2jlO3bQA0+Dzgmr4mIReZ74mq4VpOd2Vfrx7ZldW1DMw== dependencies: - "@sentry/types" "6.10.0" + "@sentry/types" "6.15.0" tslib "^1.9.3" "@types/connect@^3.4.33": From 19862cda6c64fe5bdc728242faa705916a6156b8 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 21 Nov 2021 18:32:39 -0600 Subject: [PATCH 0170/2320] Bump Webpack plugins and loaders --- package.json | 48 ++-- yarn.lock | 754 ++++++++++++++++++++++++--------------------------- 2 files changed, 385 insertions(+), 417 deletions(-) diff --git a/package.json b/package.json index 923e58c92..72090b7ce 100644 --- a/package.json +++ b/package.json @@ -78,26 +78,26 @@ "reselect": "4.0.0" }, "devDependencies": { - "@babel/core": "7.13.16", - "@babel/eslint-parser": "7.13.14", - "@babel/plugin-proposal-class-properties": "7.13.0", - "@babel/plugin-proposal-decorators": "7.13.15", - "@babel/plugin-proposal-export-default-from": "7.12.13", - "@babel/plugin-proposal-export-namespace-from": "7.12.13", - "@babel/plugin-proposal-function-sent": "7.12.13", - "@babel/plugin-proposal-nullish-coalescing-operator": "7.13.8", - "@babel/plugin-proposal-numeric-separator": "7.12.13", - "@babel/plugin-proposal-optional-chaining": "7.13.12", - "@babel/plugin-proposal-throw-expressions": "7.12.13", + "@babel/core": "7.16.0", + "@babel/eslint-parser": "7.16.3", + "@babel/plugin-proposal-class-properties": "7.16.0", + "@babel/plugin-proposal-decorators": "7.16.4", + "@babel/plugin-proposal-export-default-from": "7.16.0", + "@babel/plugin-proposal-export-namespace-from": "7.16.0", + "@babel/plugin-proposal-function-sent": "7.16.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.16.0", + "@babel/plugin-proposal-numeric-separator": "7.16.0", + "@babel/plugin-proposal-optional-chaining": "7.16.0", + "@babel/plugin-proposal-throw-expressions": "7.16.0", "@babel/plugin-syntax-dynamic-import": "7.8.3", - "@babel/preset-env": "7.13.15", - "@babel/preset-react": "7.13.13", + "@babel/preset-env": "7.16.4", + "@babel/preset-react": "7.16.0", "autoprefixer": "10.2.5", - "babel-loader": "8.2.2", + "babel-loader": "8.2.3", "babel-plugin-inline-classnames": "2.0.1", "babel-plugin-transform-react-remove-prop-types": "0.4.24", "core-js": "3.11.0", - "css-loader": "5.2.4", + "css-loader": "6.5.1", "eslint": "8.3.0", "eslint-plugin-filenames": "1.3.2", "eslint-plugin-import": "2.25.3", @@ -105,22 +105,22 @@ "eslint-plugin-simple-import-sort": "7.0.0", "esprint": "3.1.0", "file-loader": "6.2.0", - "filemanager-webpack-plugin": "5.0.0", - "html-webpack-plugin": "5.3.1", - "loader-utils": "^2.0.0", - "mini-css-extract-plugin": "1.5.0", - "postcss": "8.2.12", + "filemanager-webpack-plugin": "6.1.7", + "html-webpack-plugin": "5.5.0", + "loader-utils": "^3.0.0", + "mini-css-extract-plugin": "2.4.5", + "postcss": "8.3.11", "postcss-color-function": "4.1.0", - "postcss-loader": "5.2.0", - "postcss-mixins": "7.0.3", - "postcss-nested": "5.0.5", + "postcss-loader": "6.2.0", + "postcss-mixins": "8.1.0", + "postcss-nested": "5.0.6", "postcss-simple-vars": "6.0.3", "postcss-url": "10.1.3", "require-nocache": "1.0.0", "rimraf": "3.0.2", "run-sequence": "2.2.1", "streamqueue": "1.1.2", - "style-loader": "2.0.0", + "style-loader": "3.3.1", "stylelint": "14.1.0", "stylelint-order": "5.0.0", "url-loader": "4.1.1", diff --git a/yarn.lock b/yarn.lock index b8657a34a..0fc5ec714 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,32 +2,32 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA== dependencies: "@babel/highlight" "^7.16.0" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.13.15", "@babel/compat-data@^7.16.0": +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.0", "@babel/compat-data@^7.16.4": version "7.16.4" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e" integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q== -"@babel/core@7.13.16": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.16.tgz#7756ab24396cc9675f1c3fcd5b79fcce192ea96a" - integrity sha512-sXHpixBiWWFti0AV2Zq7avpTasr6sIAu7Y396c608541qAU2ui4a193m0KSQmfPSKFZLnQ3cvlKDOm3XkuXm3Q== +"@babel/core@7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.0.tgz#c4ff44046f5fe310525cc9eb4ef5147f0c5374d4" + integrity sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ== dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.13.16" - "@babel/helper-compilation-targets" "^7.13.16" - "@babel/helper-module-transforms" "^7.13.14" - "@babel/helpers" "^7.13.16" - "@babel/parser" "^7.13.16" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.15" - "@babel/types" "^7.13.16" + "@babel/code-frame" "^7.16.0" + "@babel/generator" "^7.16.0" + "@babel/helper-compilation-targets" "^7.16.0" + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helpers" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -35,16 +35,16 @@ semver "^6.3.0" source-map "^0.5.0" -"@babel/eslint-parser@7.13.14": - version "7.13.14" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.13.14.tgz#f80fd23bdd839537221914cb5d17720a5ea6ba3a" - integrity sha512-I0HweR36D73Ibn/FfrRDMKlMqJHFwidIUgYdMpH+aXYuQC+waq59YaJ6t9e9N36axJ82v1jR041wwqDrDXEwRA== +"@babel/eslint-parser@7.16.3": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.16.3.tgz#2a6b1702f3f5aea48e00cea5a5bcc241c437e459" + integrity sha512-iB4ElZT0jAt7PKVaeVulOECdGe6UnmA/O0P9jlF5g5GBOwDVbna8AXhHRu4s27xQf6OkveyA8iTDv1jHdDejgQ== dependencies: - eslint-scope "^5.1.0" - eslint-visitor-keys "^1.3.0" + eslint-scope "^5.1.1" + eslint-visitor-keys "^2.1.0" semver "^6.3.0" -"@babel/generator@^7.13.16", "@babel/generator@^7.16.0": +"@babel/generator@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2" integrity sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew== @@ -68,7 +68,7 @@ "@babel/helper-explode-assignable-expression" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.13", "@babel/helper-compilation-targets@^7.13.16", "@babel/helper-compilation-targets@^7.16.0": +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.0", "@babel/helper-compilation-targets@^7.16.3": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz#5b480cd13f68363df6ec4dc8ac8e2da11363cbf0" integrity sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA== @@ -78,7 +78,7 @@ browserslist "^4.17.5" semver "^6.3.0" -"@babel/helper-create-class-features-plugin@^7.13.0", "@babel/helper-create-class-features-plugin@^7.13.11", "@babel/helper-create-class-features-plugin@^7.16.0": +"@babel/helper-create-class-features-plugin@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.0.tgz#090d4d166b342a03a9fec37ef4fd5aeb9c7c6a4b" integrity sha512-XLwWvqEaq19zFlF5PTgOod4bUA+XbkR4WLQBct1bkzmxJGB0ZEJaoKF4c8cgH9oBtCDuYJ8BP5NB9uFiEgO5QA== @@ -98,10 +98,10 @@ "@babel/helper-annotate-as-pure" "^7.16.0" regexpu-core "^4.7.1" -"@babel/helper-define-polyfill-provider@^0.2.2", "@babel/helper-define-polyfill-provider@^0.2.4": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.4.tgz#8867aed79d3ea6cade40f801efb7ac5c66916b10" - integrity sha512-OrpPZ97s+aPi6h2n1OXzdhVis1SGSsMU2aMHgLcOKfsp4/v1NWpx3CWT3lBj5eeBq9cDkPkh+YCfdF7O12uNDQ== +"@babel/helper-define-polyfill-provider@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.0.tgz#c5b10cf4b324ff840140bb07e05b8564af2ae971" + integrity sha512-7hfT8lUljl/tM3h+izTX/pO3W3frz2ok6Pk+gzys8iJqDfZrZy2pXjRTZAvG2YmfHun1X4q8/UZRLatMfqc5Tg== dependencies: "@babel/helper-compilation-targets" "^7.13.0" "@babel/helper-module-imports" "^7.12.13" @@ -156,7 +156,7 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-module-transforms@^7.13.14", "@babel/helper-module-transforms@^7.16.0": +"@babel/helper-module-transforms@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5" integrity sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA== @@ -208,7 +208,7 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-skip-transparent-expression-wrappers@^7.12.1", "@babel/helper-skip-transparent-expression-wrappers@^7.16.0": +"@babel/helper-skip-transparent-expression-wrappers@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== @@ -227,12 +227,12 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== -"@babel/helper-validator-option@^7.12.17", "@babel/helper-validator-option@^7.14.5": +"@babel/helper-validator-option@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== -"@babel/helper-wrap-function@^7.12.13", "@babel/helper-wrap-function@^7.16.0": +"@babel/helper-wrap-function@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.0.tgz#b3cf318afce774dfe75b86767cd6d68f3482e57c" integrity sha512-VVMGzYY3vkWgCJML+qVLvGIam902mJW0FvT7Avj1zEe0Gn7D93aWdLblYARTxEw+6DhZmtzhBM2zv0ekE5zg1g== @@ -242,7 +242,7 @@ "@babel/traverse" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/helpers@^7.13.16": +"@babel/helpers@^7.16.0": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.3.tgz#27fc64f40b996e7074dc73128c3e5c3e7f55c43c" integrity sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w== @@ -260,12 +260,19 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.13.16", "@babel/parser@^7.16.0", "@babel/parser@^7.16.3": +"@babel/parser@^7.16.0", "@babel/parser@^7.16.3": version "7.16.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e" integrity sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng== -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.13.12": +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.2": + version "7.16.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.2.tgz#2977fca9b212db153c195674e57cfab807733183" + integrity sha512-h37CvpLSf8gb2lIJ2CgC3t+EjFbi0t8qS7LCS1xcJIlEXE4czlofwaW7W1HA8zpgOCzI9C1nmoqNR1zWkk0pQg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.0.tgz#358972eaab006f5eb0826183b0c93cbcaf13e1e2" integrity sha512-4tcFwwicpWTrpl9qjf7UsoosaArgImF85AxqCRZlgc3IQDvkUHjJpruXAL58Wmj+T6fypWTC/BakfEkwIL/pwA== @@ -274,7 +281,7 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" "@babel/plugin-proposal-optional-chaining" "^7.16.0" -"@babel/plugin-proposal-async-generator-functions@^7.13.15": +"@babel/plugin-proposal-async-generator-functions@^7.16.4": version "7.16.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.4.tgz#e606eb6015fec6fa5978c940f315eae4e300b081" integrity sha512-/CUekqaAaZCQHleSK/9HajvcD/zdnJiKRiuUFq8ITE+0HsPzquf53cpFiqAwl/UfmJbR6n5uGPQSPdrmKOvHHg== @@ -283,15 +290,7 @@ "@babel/helper-remap-async-to-generator" "^7.16.4" "@babel/plugin-syntax-async-generators" "^7.8.4" -"@babel/plugin-proposal-class-properties@7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz#146376000b94efd001e57a40a88a525afaab9f37" - integrity sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.13.0" - "@babel/helper-plugin-utils" "^7.13.0" - -"@babel/plugin-proposal-class-properties@^7.13.0": +"@babel/plugin-proposal-class-properties@7.16.0", "@babel/plugin-proposal-class-properties@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.0.tgz#c029618267ddebc7280fa286e0f8ca2a278a2d1a" integrity sha512-mCF3HcuZSY9Fcx56Lbn+CGdT44ioBMMvjNVldpKtj8tpniETdLjnxdHI1+sDWXIM1nNt+EanJOZ3IG9lzVjs7A== @@ -299,16 +298,25 @@ "@babel/helper-create-class-features-plugin" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-proposal-decorators@7.13.15": - version "7.13.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.13.15.tgz#e91ccfef2dc24dd5bd5dcc9fc9e2557c684ecfb8" - integrity sha512-ibAMAqUm97yzi+LPgdr5Nqb9CMkeieGHvwPg1ywSGjZrZHQEGqE01HmOio8kxRpA/+VtOHouIVy2FMpBbtltjA== +"@babel/plugin-proposal-class-static-block@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.0.tgz#5296942c564d8144c83eea347d0aa8a0b89170e7" + integrity sha512-mAy3sdcY9sKAkf3lQbDiv3olOfiLqI51c9DR9b19uMoR2Z6r5pmGl7dfNFqEvqOyqbf1ta4lknK4gc5PJn3mfA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.13.11" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-decorators" "^7.12.13" + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-class-static-block" "^7.14.5" -"@babel/plugin-proposal-dynamic-import@^7.13.8": +"@babel/plugin-proposal-decorators@7.16.4": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.16.4.tgz#9b35ce0716425a93b978e79099e5f7ba217c1364" + integrity sha512-RESBNX16eNqnBeEVR5sCJpnW0mHiNLNNvGA8PrRuK/4ZJ4TO+6bHleRUuGQYDERVySOKtOhSya/C4MIhwAMAgg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-decorators" "^7.16.0" + +"@babel/plugin-proposal-dynamic-import@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.0.tgz#783eca61d50526202f9b296095453977e88659f1" integrity sha512-QGSA6ExWk95jFQgwz5GQ2Dr95cf7eI7TKutIXXTb7B1gCLTCz5hTjFTQGfLFBBiC5WSNi7udNwWsqbbMh1c4yQ== @@ -316,23 +324,15 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-dynamic-import" "^7.8.3" -"@babel/plugin-proposal-export-default-from@7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.12.13.tgz#f110284108a9b2b96f01b15b3be9e54c2610a989" - integrity sha512-idIsBT+DGXdOHL82U+8bwX4goHm/z10g8sGGrQroh+HCRcm7mDv/luaGdWJQMTuCX2FsdXS7X0Nyyzp4znAPJA== +"@babel/plugin-proposal-export-default-from@7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.16.0.tgz#f8a07008ffcb0d3de4945f3eb52022ecc28b56ad" + integrity sha512-kFAhaIbh5qbBwETRNa/cgGmPJ/BicXhIyrZhAkyYhf/Z9LXCTRGO1mvUwczto0Hl1q4YtzP9cRtTKT4wujm38Q== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-syntax-export-default-from" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-export-default-from" "^7.16.0" -"@babel/plugin-proposal-export-namespace-from@7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.13.tgz#393be47a4acd03fa2af6e3cde9b06e33de1b446d" - integrity sha512-INAgtFo4OnLN3Y/j0VwAgw3HDXcDtX+C/erMvWzuV9v71r7urb6iyMXu7eM9IgLr1ElLlOkaHjJ0SbCmdOQ3Iw== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - -"@babel/plugin-proposal-export-namespace-from@^7.12.13": +"@babel/plugin-proposal-export-namespace-from@7.16.0", "@babel/plugin-proposal-export-namespace-from@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.0.tgz#9c01dee40b9d6b847b656aaf4a3976a71740f222" integrity sha512-CjI4nxM/D+5wCnhD11MHB1AwRSAYeDT+h8gCdcVJZ/OK7+wRzFsf7PFPWVpVpNRkHMmMkQWAHpTq+15IXQ1diA== @@ -340,16 +340,16 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" -"@babel/plugin-proposal-function-sent@7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-function-sent/-/plugin-proposal-function-sent-7.12.13.tgz#553f47e4b7f7e9becb6b5013ed5c4dd72b72400e" - integrity sha512-nw5dSsy0+o+WBE372ooERkkZmFv2KJcujzTB5SdhQPKIElVA1pa7hclD23Vzl4VlcoJsC7KCCXpww2qAkbrrKA== +"@babel/plugin-proposal-function-sent@7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-function-sent/-/plugin-proposal-function-sent-7.16.0.tgz#6a873e125e4081e48d9b37518e8e2c63c9a8cddb" + integrity sha512-CkUaPsTiRB72BlsB1Istdb6LSJDi4SU4gH+hW9EKo2/o6naq0HEkuY2OV5anl5Tsnwtdn3FmpteguRc9kXd3Ig== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/helper-wrap-function" "^7.12.13" - "@babel/plugin-syntax-function-sent" "^7.12.13" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-wrap-function" "^7.16.0" + "@babel/plugin-syntax-function-sent" "^7.16.0" -"@babel/plugin-proposal-json-strings@^7.13.8": +"@babel/plugin-proposal-json-strings@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.0.tgz#cae35a95ed1d2a7fa29c4dc41540b84a72e9ab25" integrity sha512-kouIPuiv8mSi5JkEhzApg5Gn6hFyKPnlkO0a9YSzqRurH8wYzSlf6RJdzluAsbqecdW5pBvDJDfyDIUR/vLxvg== @@ -357,7 +357,7 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-json-strings" "^7.8.3" -"@babel/plugin-proposal-logical-assignment-operators@^7.13.8": +"@babel/plugin-proposal-logical-assignment-operators@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.0.tgz#a711b8ceb3ffddd3ef88d3a49e86dbd3cc7db3fd" integrity sha512-pbW0fE30sVTYXXm9lpVQQ/Vc+iTeQKiXlaNRZPPN2A2VdlWyAtsUrsQ3xydSlDW00TFMK7a8m3cDTkBF5WnV3Q== @@ -365,15 +365,7 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-proposal-nullish-coalescing-operator@7.13.8": - version "7.13.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.13.8.tgz#3730a31dafd3c10d8ccd10648ed80a2ac5472ef3" - integrity sha512-iePlDPBn//UhxExyS9KyeYU7RM9WScAG+D3Hhno0PLJebAEpDZMocbDe64eqynhNAnwz/vZoL/q/QB2T1OH39A== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.13.8": +"@babel/plugin-proposal-nullish-coalescing-operator@7.16.0", "@babel/plugin-proposal-nullish-coalescing-operator@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.0.tgz#44e1cce08fe2427482cf446a91bb451528ed0596" integrity sha512-3bnHA8CAFm7cG93v8loghDYyQ8r97Qydf63BeYiGgYbjKKB/XP53W15wfRC7dvKfoiJ34f6Rbyyx2btExc8XsQ== @@ -381,15 +373,7 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" -"@babel/plugin-proposal-numeric-separator@7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.13.tgz#bd9da3188e787b5120b4f9d465a8261ce67ed1db" - integrity sha512-O1jFia9R8BUCl3ZGB7eitaAPu62TXJRHn7rh+ojNERCFyqRwJMTmhz+tJ+k0CwI6CLjX/ee4qW74FSqlq9I35w== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - -"@babel/plugin-proposal-numeric-separator@^7.12.13": +"@babel/plugin-proposal-numeric-separator@7.16.0", "@babel/plugin-proposal-numeric-separator@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.0.tgz#5d418e4fbbf8b9b7d03125d3a52730433a373734" integrity sha512-FAhE2I6mjispy+vwwd6xWPyEx3NYFS13pikDBWUAFGZvq6POGs5eNchw8+1CYoEgBl9n11I3NkzD7ghn25PQ9Q== @@ -397,7 +381,7 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.13.8": +"@babel/plugin-proposal-object-rest-spread@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.0.tgz#5fb32f6d924d6e6712810362a60e12a2609872e6" integrity sha512-LU/+jp89efe5HuWJLmMmFG0+xbz+I2rSI7iLc1AlaeSMDMOGzWlc5yJrMN1d04osXN4sSfpo4O+azkBNBes0jg== @@ -408,7 +392,7 @@ "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-transform-parameters" "^7.16.0" -"@babel/plugin-proposal-optional-catch-binding@^7.13.8": +"@babel/plugin-proposal-optional-catch-binding@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.0.tgz#5910085811ab4c28b00d6ebffa4ab0274d1e5f16" integrity sha512-kicDo0A/5J0nrsCPbn89mTG3Bm4XgYi0CZtvex9Oyw7gGZE3HXGD0zpQNH+mo+tEfbo8wbmMvJftOwpmPy7aVw== @@ -416,16 +400,7 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-proposal-optional-chaining@7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.13.12.tgz#ba9feb601d422e0adea6760c2bd6bbb7bfec4866" - integrity sha512-fcEdKOkIB7Tf4IxrgEVeFC4zeJSTr78no9wTdBuZZbqF64kzllU0ybo2zrzm7gUQfxGhBgq4E39oRs8Zx/RMYQ== - dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - -"@babel/plugin-proposal-optional-chaining@^7.13.12", "@babel/plugin-proposal-optional-chaining@^7.16.0": +"@babel/plugin-proposal-optional-chaining@7.16.0", "@babel/plugin-proposal-optional-chaining@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.0.tgz#56dbc3970825683608e9efb55ea82c2a2d6c8dc0" integrity sha512-Y4rFpkZODfHrVo70Uaj6cC1JJOt3Pp0MdWSwIKtb8z1/lsjl9AmnB7ErRFV+QNGIfcY1Eruc2UMx5KaRnXjMyg== @@ -434,7 +409,7 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -"@babel/plugin-proposal-private-methods@^7.13.0": +"@babel/plugin-proposal-private-methods@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.0.tgz#b4dafb9c717e4301c5776b30d080d6383c89aff6" integrity sha512-IvHmcTHDFztQGnn6aWq4t12QaBXTKr1whF/dgp9kz84X6GUcwq9utj7z2wFCUfeOup/QKnOlt2k0zxkGFx9ubg== @@ -442,15 +417,25 @@ "@babel/helper-create-class-features-plugin" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-proposal-throw-expressions@7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-throw-expressions/-/plugin-proposal-throw-expressions-7.12.13.tgz#48a6e4a5988041d16b0a2f1568a3b518f8b6c1d4" - integrity sha512-zhItTJGy2xLYneBdOk9CeyuEXWJt9J+pwTEIDl+A/VKMCq6E9ij3l1RRuTYBwtktTO9bCcIfA4/+d0HibVWSEA== +"@babel/plugin-proposal-private-property-in-object@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.0.tgz#69e935b2c5c79d2488112d886f0c4e2790fee76f" + integrity sha512-3jQUr/HBbMVZmi72LpjQwlZ55i1queL8KcDTQEkAHihttJnAPrcvG9ZNXIfsd2ugpizZo595egYV6xy+pv4Ofw== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-syntax-throw-expressions" "^7.12.13" + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" -"@babel/plugin-proposal-unicode-property-regex@^7.12.13", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": +"@babel/plugin-proposal-throw-expressions@7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-throw-expressions/-/plugin-proposal-throw-expressions-7.16.0.tgz#f9450e11d90159eff29a36e5bcacc9b49eefc4d7" + integrity sha512-8u4KrMqdzRLkfHMN6WOK4taEwV6Dv69O/TuJ2TCGapRXtbjRKDW2UyTxEzlZpA1Eu+MxquSW9+y8qy89TIJfOA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-throw-expressions" "^7.16.0" + +"@babel/plugin-proposal-unicode-property-regex@^7.16.0", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.0.tgz#890482dfc5ea378e42e19a71e709728cabf18612" integrity sha512-ti7IdM54NXv29cA4+bNNKEMS4jLMCbJgl+Drv+FgYy0erJLAxNAIXcNjNjrRZEcWq0xJHsNVwQezskMFpF8N9g== @@ -472,7 +457,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-syntax-decorators@^7.12.13": +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-decorators@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.16.0.tgz#eb8d811cdd1060f6ac3c00956bf3f6335505a32f" integrity sha512-nxnnngZClvlY13nHJAIDow0S7Qzhq64fQ/NlqS+VER3kjW/4F0jLhXjeL8jcwSwz6Ca3rotT5NJD2T9I7lcv7g== @@ -486,7 +478,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-export-default-from@^7.12.13": +"@babel/plugin-syntax-export-default-from@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.16.0.tgz#648520667776781f9a0da178f245fff85bc9e36f" integrity sha512-xllLOdBj77mFSw8s02I+2SSQGHOftbWTlGmagheuNk/gjQsk7IrYsR/EosXVAVpgIUFffLckB/iPRioQYLHSrQ== @@ -500,7 +492,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-function-sent@^7.12.13": +"@babel/plugin-syntax-function-sent@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-function-sent/-/plugin-syntax-function-sent-7.16.0.tgz#c6e0eb280a101cd7bdaf6d3f750eb27b59978c48" integrity sha512-CrwPwHy+ks1xokbZ5x2ZbRwZ5qptN0PE/N5M+o8eQ2LHXGFxlSuDVx515crT7DxUnT+uKctKDuk0NAwG7c1Ebw== @@ -563,28 +555,35 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-throw-expressions@^7.12.13": +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-throw-expressions@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-throw-expressions/-/plugin-syntax-throw-expressions-7.16.0.tgz#9d5fc5c185617bc5f727fbecc360601a52cf6879" integrity sha512-tr5wm8EYRpFW47uVJ2B660pJQXgmeCShz82tE6LkIVkcLzXMz5xhj0drYyehuAl1utNGFqPnMmjpzs5zavAbNQ== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-top-level-await@^7.12.13": +"@babel/plugin-syntax-top-level-await@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-arrow-functions@^7.13.0": +"@babel/plugin-transform-arrow-functions@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.0.tgz#951706f8b449c834ed07bd474c0924c944b95a8e" integrity sha512-vIFb5250Rbh7roWARvCLvIJ/PtAU5Lhv7BtZ1u24COwpI9Ypjsh+bZcKk6rlIyalK+r0jOc1XQ8I4ovNxNrWrA== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-async-to-generator@^7.13.0": +"@babel/plugin-transform-async-to-generator@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.0.tgz#df12637f9630ddfa0ef9d7a11bc414d629d38604" integrity sha512-PbIr7G9kR8tdH6g8Wouir5uVjklETk91GMVSUq+VaOgiinbCkBP6Q7NN/suM/QutZkMJMvcyAriogcYAdhg8Gw== @@ -593,21 +592,21 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-remap-async-to-generator" "^7.16.0" -"@babel/plugin-transform-block-scoped-functions@^7.12.13": +"@babel/plugin-transform-block-scoped-functions@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.0.tgz#c618763233ad02847805abcac4c345ce9de7145d" integrity sha512-V14As3haUOP4ZWrLJ3VVx5rCnrYhMSHN/jX7z6FAt5hjRkLsb0snPCmJwSOML5oxkKO4FNoNv7V5hw/y2bjuvg== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-block-scoping@^7.12.13": +"@babel/plugin-transform-block-scoping@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.0.tgz#bcf433fb482fe8c3d3b4e8a66b1c4a8e77d37c16" integrity sha512-27n3l67/R3UrXfizlvHGuTwsRIFyce3D/6a37GRxn28iyTPvNXaW4XvznexRh1zUNLPjbLL22Id0XQElV94ruw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-classes@^7.13.0": +"@babel/plugin-transform-classes@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.0.tgz#54cf5ff0b2242c6573d753cd4bfc7077a8b282f5" integrity sha512-HUxMvy6GtAdd+GKBNYDWCIA776byUQH8zjnfjxwT1P1ARv/wFu8eBDpmXQcLS/IwRtrxIReGiplOwMeyO7nsDQ== @@ -620,21 +619,21 @@ "@babel/helper-split-export-declaration" "^7.16.0" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.13.0": +"@babel/plugin-transform-computed-properties@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.0.tgz#e0c385507d21e1b0b076d66bed6d5231b85110b7" integrity sha512-63l1dRXday6S8V3WFY5mXJwcRAnPYxvFfTlt67bwV1rTyVTM5zrp0DBBb13Kl7+ehkCVwIZPumPpFP/4u70+Tw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-destructuring@^7.13.0": +"@babel/plugin-transform-destructuring@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.0.tgz#ad3d7e74584ad5ea4eadb1e6642146c590dee33c" integrity sha512-Q7tBUwjxLTsHEoqktemHBMtb3NYwyJPTJdM+wDwb0g8PZ3kQUIzNvwD5lPaqW/p54TXBc/MXZu9Jr7tbUEUM8Q== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-dotall-regex@^7.12.13", "@babel/plugin-transform-dotall-regex@^7.4.4": +"@babel/plugin-transform-dotall-regex@^7.16.0", "@babel/plugin-transform-dotall-regex@^7.4.4": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.0.tgz#50bab00c1084b6162d0a58a818031cf57798e06f" integrity sha512-FXlDZfQeLILfJlC6I1qyEwcHK5UpRCFkaoVyA1nk9A1L1Yu583YO4un2KsLBsu3IJb4CUbctZks8tD9xPQubLw== @@ -642,14 +641,14 @@ "@babel/helper-create-regexp-features-plugin" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-duplicate-keys@^7.12.13": +"@babel/plugin-transform-duplicate-keys@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.0.tgz#8bc2e21813e3e89e5e5bf3b60aa5fc458575a176" integrity sha512-LIe2kcHKAZOJDNxujvmp6z3mfN6V9lJxubU4fJIGoQCkKe3Ec2OcbdlYP+vW++4MpxwG0d1wSDOJtQW5kLnkZQ== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-exponentiation-operator@^7.12.13": +"@babel/plugin-transform-exponentiation-operator@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.0.tgz#a180cd2881e3533cef9d3901e48dad0fbeff4be4" integrity sha512-OwYEvzFI38hXklsrbNivzpO3fh87skzx8Pnqi4LoSYeav0xHlueSoCJrSgTPfnbyzopo5b3YVAJkFIcUpK2wsw== @@ -657,14 +656,14 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-for-of@^7.13.0": +"@babel/plugin-transform-for-of@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.0.tgz#f7abaced155260e2461359bbc7c7248aca5e6bd2" integrity sha512-5QKUw2kO+GVmKr2wMYSATCTTnHyscl6sxFRAY+rvN7h7WB0lcG0o4NoV6ZQU32OZGVsYUsfLGgPQpDFdkfjlJQ== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-function-name@^7.12.13": +"@babel/plugin-transform-function-name@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.0.tgz#02e3699c284c6262236599f751065c5d5f1f400e" integrity sha512-lBzMle9jcOXtSOXUpc7tvvTpENu/NuekNJVova5lCCWCV9/U1ho2HH2y0p6mBg8fPm/syEAbfaaemYGOHCY3mg== @@ -672,21 +671,21 @@ "@babel/helper-function-name" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-literals@^7.12.13": +"@babel/plugin-transform-literals@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.0.tgz#79711e670ffceb31bd298229d50f3621f7980cac" integrity sha512-gQDlsSF1iv9RU04clgXqRjrPyyoJMTclFt3K1cjLmTKikc0s/6vE3hlDeEVC71wLTRu72Fq7650kABrdTc2wMQ== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-member-expression-literals@^7.12.13": +"@babel/plugin-transform-member-expression-literals@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.0.tgz#5251b4cce01eaf8314403d21aedb269d79f5e64b" integrity sha512-WRpw5HL4Jhnxw8QARzRvwojp9MIE7Tdk3ez6vRyUk1MwgjJN0aNpRoXainLR5SgxmoXx/vsXGZ6OthP6t/RbUg== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-modules-amd@^7.13.0": +"@babel/plugin-transform-modules-amd@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.0.tgz#09abd41e18dcf4fd479c598c1cef7bd39eb1337e" integrity sha512-rWFhWbCJ9Wdmzln1NmSCqn7P0RAD+ogXG/bd9Kg5c7PKWkJtkiXmYsMBeXjDlzHpVTJ4I/hnjs45zX4dEv81xw== @@ -695,7 +694,7 @@ "@babel/helper-plugin-utils" "^7.14.5" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-commonjs@^7.13.8": +"@babel/plugin-transform-modules-commonjs@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.0.tgz#add58e638c8ddc4875bd9a9ecb5c594613f6c922" integrity sha512-Dzi+NWqyEotgzk/sb7kgQPJQf7AJkQBWsVp1N6JWc1lBVo0vkElUnGdr1PzUBmfsCCN5OOFya3RtpeHk15oLKQ== @@ -705,7 +704,7 @@ "@babel/helper-simple-access" "^7.16.0" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-systemjs@^7.13.8": +"@babel/plugin-transform-modules-systemjs@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.0.tgz#a92cf240afeb605f4ca16670453024425e421ea4" integrity sha512-yuGBaHS3lF1m/5R+6fjIke64ii5luRUg97N2wr+z1sF0V+sNSXPxXDdEEL/iYLszsN5VKxVB1IPfEqhzVpiqvg== @@ -716,7 +715,7 @@ "@babel/helper-validator-identifier" "^7.15.7" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-umd@^7.13.0": +"@babel/plugin-transform-modules-umd@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.0.tgz#195f26c2ad6d6a391b70880effce18ce625e06a7" integrity sha512-nx4f6no57himWiHhxDM5pjwhae5vLpTK2zCnDH8+wNLJy0TVER/LJRHl2bkt6w9Aad2sPD5iNNoUpY3X9sTGDg== @@ -724,21 +723,21 @@ "@babel/helper-module-transforms" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-named-capturing-groups-regex@^7.12.13": +"@babel/plugin-transform-named-capturing-groups-regex@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.0.tgz#d3db61cc5d5b97986559967cd5ea83e5c32096ca" integrity sha512-LogN88uO+7EhxWc8WZuQ8vxdSyVGxhkh8WTC3tzlT8LccMuQdA81e9SGV6zY7kY2LjDhhDOFdQVxdGwPyBCnvg== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.16.0" -"@babel/plugin-transform-new-target@^7.12.13": +"@babel/plugin-transform-new-target@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.0.tgz#af823ab576f752215a49937779a41ca65825ab35" integrity sha512-fhjrDEYv2DBsGN/P6rlqakwRwIp7rBGLPbrKxwh7oVt5NNkIhZVOY2GRV+ULLsQri1bDqwDWnU3vhlmx5B2aCw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-object-super@^7.12.13": +"@babel/plugin-transform-object-super@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.0.tgz#fb20d5806dc6491a06296ac14ea8e8d6fedda72b" integrity sha512-fds+puedQHn4cPLshoHcR1DTMN0q1V9ou0mUjm8whx9pGcNvDrVVrgw+KJzzCaiTdaYhldtrUps8DWVMgrSEyg== @@ -746,35 +745,35 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-replace-supers" "^7.16.0" -"@babel/plugin-transform-parameters@^7.13.0", "@babel/plugin-transform-parameters@^7.16.0": +"@babel/plugin-transform-parameters@^7.16.0", "@babel/plugin-transform-parameters@^7.16.3": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.3.tgz#fa9e4c874ee5223f891ee6fa8d737f4766d31d15" integrity sha512-3MaDpJrOXT1MZ/WCmkOFo7EtmVVC8H4EUZVrHvFOsmwkk4lOjQj8rzv8JKUZV4YoQKeoIgk07GO+acPU9IMu/w== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-property-literals@^7.12.13": +"@babel/plugin-transform-property-literals@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.0.tgz#a95c552189a96a00059f6776dc4e00e3690c78d1" integrity sha512-XLldD4V8+pOqX2hwfWhgwXzGdnDOThxaNTgqagOcpBgIxbUvpgU2FMvo5E1RyHbk756WYgdbS0T8y0Cj9FKkWQ== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-react-display-name@^7.12.13": +"@babel/plugin-transform-react-display-name@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.0.tgz#9a0ad8aa8e8790883a7bd2736f66229a58125676" integrity sha512-FJFdJAqaCpndL+pIf0aeD/qlQwT7QXOvR6Cc8JPvNhKJBi2zc/DPc4g05Y3fbD/0iWAMQFGij4+Xw+4L/BMpTg== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-react-jsx-development@^7.12.17": +"@babel/plugin-transform-react-jsx-development@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.0.tgz#1cb52874678d23ab11d0d16488d54730807303ef" integrity sha512-qq65iSqBRq0Hr3wq57YG2AmW0H6wgTnIzpffTphrUWUgLCOK+zf1f7G0vuOiXrp7dU1qq+fQBoqZ3wCDAkhFzw== dependencies: "@babel/plugin-transform-react-jsx" "^7.16.0" -"@babel/plugin-transform-react-jsx@^7.13.12", "@babel/plugin-transform-react-jsx@^7.16.0": +"@babel/plugin-transform-react-jsx@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.0.tgz#55b797d4960c3de04e07ad1c0476e2bc6a4889f1" integrity sha512-rqDgIbukZ44pqq7NIRPGPGNklshPkvlmvqjdx3OZcGPk4zGIenYkxDTvl3LsSL8gqcc3ZzGmXPE6hR/u/voNOw== @@ -785,7 +784,7 @@ "@babel/plugin-syntax-jsx" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/plugin-transform-react-pure-annotations@^7.12.1": +"@babel/plugin-transform-react-pure-annotations@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.0.tgz#23db6ddf558d8abde41b8ad9d59f48ad5532ccab" integrity sha512-NC/Bj2MG+t8Ef5Pdpo34Ay74X4Rt804h5y81PwOpfPtmAK3i6CizmQqwyBQzIepz1Yt8wNr2Z2L7Lu3qBMfZMA== @@ -793,28 +792,28 @@ "@babel/helper-annotate-as-pure" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-regenerator@^7.13.15": +"@babel/plugin-transform-regenerator@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.0.tgz#eaee422c84b0232d03aea7db99c97deeaf6125a4" integrity sha512-JAvGxgKuwS2PihiSFaDrp94XOzzTUeDeOQlcKzVAyaPap7BnZXK/lvMDiubkPTdotPKOIZq9xWXWnggUMYiExg== dependencies: regenerator-transform "^0.14.2" -"@babel/plugin-transform-reserved-words@^7.12.13": +"@babel/plugin-transform-reserved-words@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.0.tgz#fff4b9dcb19e12619394bda172d14f2d04c0379c" integrity sha512-Dgs8NNCehHSvXdhEhln8u/TtJxfVwGYCgP2OOr5Z3Ar+B+zXicEOKNTyc+eca2cuEOMtjW6m9P9ijOt8QdqWkg== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-shorthand-properties@^7.12.13": +"@babel/plugin-transform-shorthand-properties@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.0.tgz#090372e3141f7cc324ed70b3daf5379df2fa384d" integrity sha512-iVb1mTcD8fuhSv3k99+5tlXu5N0v8/DPm2mO3WACLG6al1CGZH7v09HJyUb1TtYl/Z+KrM6pHSIJdZxP5A+xow== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-spread@^7.13.0": +"@babel/plugin-transform-spread@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.0.tgz#d21ca099bbd53ab307a8621e019a7bd0f40cdcfb" integrity sha512-Ao4MSYRaLAQczZVp9/7E7QHsCuK92yHRrmVNRe/SlEJjhzivq0BSn8mEraimL8wizHZ3fuaHxKH0iwzI13GyGg== @@ -822,35 +821,35 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" -"@babel/plugin-transform-sticky-regex@^7.12.13": +"@babel/plugin-transform-sticky-regex@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.0.tgz#c35ea31a02d86be485f6aa510184b677a91738fd" integrity sha512-/ntT2NljR9foobKk4E/YyOSwcGUXtYWv5tinMK/3RkypyNBNdhHUaq6Orw5DWq9ZcNlS03BIlEALFeQgeVAo4Q== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-template-literals@^7.13.0": +"@babel/plugin-transform-template-literals@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.0.tgz#a8eced3a8e7b8e2d40ec4ec4548a45912630d302" integrity sha512-Rd4Ic89hA/f7xUSJQk5PnC+4so50vBoBfxjdQAdvngwidM8jYIBVxBZ/sARxD4e0yMXRbJVDrYf7dyRtIIKT6Q== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-typeof-symbol@^7.12.13": +"@babel/plugin-transform-typeof-symbol@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.0.tgz#8b19a244c6f8c9d668dca6a6f754ad6ead1128f2" integrity sha512-++V2L8Bdf4vcaHi2raILnptTBjGEFxn5315YU+e8+EqXIucA+q349qWngCLpUYqqv233suJ6NOienIVUpS9cqg== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-unicode-escapes@^7.12.13": +"@babel/plugin-transform-unicode-escapes@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.0.tgz#1a354064b4c45663a32334f46fa0cf6100b5b1f3" integrity sha512-VFi4dhgJM7Bpk8lRc5CMaRGlKZ29W9C3geZjt9beuzSUrlJxsNwX7ReLwaL6WEvsOf2EQkyIJEPtF8EXjB/g2A== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-unicode-regex@^7.12.13": +"@babel/plugin-transform-unicode-regex@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.0.tgz#293b80950177c8c85aede87cef280259fb995402" integrity sha512-jHLK4LxhHjvCeZDWyA9c+P9XH1sOxRd1RO9xMtDVRAOND/PczPqizEtVdx4TQF/wyPaewqpT+tgQFYMnN/P94A== @@ -858,31 +857,35 @@ "@babel/helper-create-regexp-features-plugin" "^7.16.0" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/preset-env@7.13.15": - version "7.13.15" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.13.15.tgz#c8a6eb584f96ecba183d3d414a83553a599f478f" - integrity sha512-D4JAPMXcxk69PKe81jRJ21/fP/uYdcTZ3hJDF5QX2HSI9bBxxYw/dumdR6dGumhjxlprHPE4XWoPaqzZUVy2MA== +"@babel/preset-env@7.16.4": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.16.4.tgz#4f6ec33b2a3fe72d6bfdcdf3859500232563a2e3" + integrity sha512-v0QtNd81v/xKj4gNKeuAerQ/azeNn/G1B1qMLeXOcV8+4TWlD2j3NV1u8q29SDFBXx/NBq5kyEAO+0mpRgacjA== dependencies: - "@babel/compat-data" "^7.13.15" - "@babel/helper-compilation-targets" "^7.13.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-validator-option" "^7.12.17" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.13.12" - "@babel/plugin-proposal-async-generator-functions" "^7.13.15" - "@babel/plugin-proposal-class-properties" "^7.13.0" - "@babel/plugin-proposal-dynamic-import" "^7.13.8" - "@babel/plugin-proposal-export-namespace-from" "^7.12.13" - "@babel/plugin-proposal-json-strings" "^7.13.8" - "@babel/plugin-proposal-logical-assignment-operators" "^7.13.8" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.13.8" - "@babel/plugin-proposal-numeric-separator" "^7.12.13" - "@babel/plugin-proposal-object-rest-spread" "^7.13.8" - "@babel/plugin-proposal-optional-catch-binding" "^7.13.8" - "@babel/plugin-proposal-optional-chaining" "^7.13.12" - "@babel/plugin-proposal-private-methods" "^7.13.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.12.13" + "@babel/compat-data" "^7.16.4" + "@babel/helper-compilation-targets" "^7.16.3" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.2" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.0" + "@babel/plugin-proposal-async-generator-functions" "^7.16.4" + "@babel/plugin-proposal-class-properties" "^7.16.0" + "@babel/plugin-proposal-class-static-block" "^7.16.0" + "@babel/plugin-proposal-dynamic-import" "^7.16.0" + "@babel/plugin-proposal-export-namespace-from" "^7.16.0" + "@babel/plugin-proposal-json-strings" "^7.16.0" + "@babel/plugin-proposal-logical-assignment-operators" "^7.16.0" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.0" + "@babel/plugin-proposal-numeric-separator" "^7.16.0" + "@babel/plugin-proposal-object-rest-spread" "^7.16.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.16.0" + "@babel/plugin-proposal-optional-chaining" "^7.16.0" + "@babel/plugin-proposal-private-methods" "^7.16.0" + "@babel/plugin-proposal-private-property-in-object" "^7.16.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.16.0" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" "@babel/plugin-syntax-dynamic-import" "^7.8.3" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" "@babel/plugin-syntax-json-strings" "^7.8.3" @@ -892,48 +895,49 @@ "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.12.13" - "@babel/plugin-transform-arrow-functions" "^7.13.0" - "@babel/plugin-transform-async-to-generator" "^7.13.0" - "@babel/plugin-transform-block-scoped-functions" "^7.12.13" - "@babel/plugin-transform-block-scoping" "^7.12.13" - "@babel/plugin-transform-classes" "^7.13.0" - "@babel/plugin-transform-computed-properties" "^7.13.0" - "@babel/plugin-transform-destructuring" "^7.13.0" - "@babel/plugin-transform-dotall-regex" "^7.12.13" - "@babel/plugin-transform-duplicate-keys" "^7.12.13" - "@babel/plugin-transform-exponentiation-operator" "^7.12.13" - "@babel/plugin-transform-for-of" "^7.13.0" - "@babel/plugin-transform-function-name" "^7.12.13" - "@babel/plugin-transform-literals" "^7.12.13" - "@babel/plugin-transform-member-expression-literals" "^7.12.13" - "@babel/plugin-transform-modules-amd" "^7.13.0" - "@babel/plugin-transform-modules-commonjs" "^7.13.8" - "@babel/plugin-transform-modules-systemjs" "^7.13.8" - "@babel/plugin-transform-modules-umd" "^7.13.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.12.13" - "@babel/plugin-transform-new-target" "^7.12.13" - "@babel/plugin-transform-object-super" "^7.12.13" - "@babel/plugin-transform-parameters" "^7.13.0" - "@babel/plugin-transform-property-literals" "^7.12.13" - "@babel/plugin-transform-regenerator" "^7.13.15" - "@babel/plugin-transform-reserved-words" "^7.12.13" - "@babel/plugin-transform-shorthand-properties" "^7.12.13" - "@babel/plugin-transform-spread" "^7.13.0" - "@babel/plugin-transform-sticky-regex" "^7.12.13" - "@babel/plugin-transform-template-literals" "^7.13.0" - "@babel/plugin-transform-typeof-symbol" "^7.12.13" - "@babel/plugin-transform-unicode-escapes" "^7.12.13" - "@babel/plugin-transform-unicode-regex" "^7.12.13" - "@babel/preset-modules" "^0.1.4" - "@babel/types" "^7.13.14" - babel-plugin-polyfill-corejs2 "^0.2.0" - babel-plugin-polyfill-corejs3 "^0.2.0" - babel-plugin-polyfill-regenerator "^0.2.0" - core-js-compat "^3.9.0" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-transform-arrow-functions" "^7.16.0" + "@babel/plugin-transform-async-to-generator" "^7.16.0" + "@babel/plugin-transform-block-scoped-functions" "^7.16.0" + "@babel/plugin-transform-block-scoping" "^7.16.0" + "@babel/plugin-transform-classes" "^7.16.0" + "@babel/plugin-transform-computed-properties" "^7.16.0" + "@babel/plugin-transform-destructuring" "^7.16.0" + "@babel/plugin-transform-dotall-regex" "^7.16.0" + "@babel/plugin-transform-duplicate-keys" "^7.16.0" + "@babel/plugin-transform-exponentiation-operator" "^7.16.0" + "@babel/plugin-transform-for-of" "^7.16.0" + "@babel/plugin-transform-function-name" "^7.16.0" + "@babel/plugin-transform-literals" "^7.16.0" + "@babel/plugin-transform-member-expression-literals" "^7.16.0" + "@babel/plugin-transform-modules-amd" "^7.16.0" + "@babel/plugin-transform-modules-commonjs" "^7.16.0" + "@babel/plugin-transform-modules-systemjs" "^7.16.0" + "@babel/plugin-transform-modules-umd" "^7.16.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.16.0" + "@babel/plugin-transform-new-target" "^7.16.0" + "@babel/plugin-transform-object-super" "^7.16.0" + "@babel/plugin-transform-parameters" "^7.16.3" + "@babel/plugin-transform-property-literals" "^7.16.0" + "@babel/plugin-transform-regenerator" "^7.16.0" + "@babel/plugin-transform-reserved-words" "^7.16.0" + "@babel/plugin-transform-shorthand-properties" "^7.16.0" + "@babel/plugin-transform-spread" "^7.16.0" + "@babel/plugin-transform-sticky-regex" "^7.16.0" + "@babel/plugin-transform-template-literals" "^7.16.0" + "@babel/plugin-transform-typeof-symbol" "^7.16.0" + "@babel/plugin-transform-unicode-escapes" "^7.16.0" + "@babel/plugin-transform-unicode-regex" "^7.16.0" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.16.0" + babel-plugin-polyfill-corejs2 "^0.3.0" + babel-plugin-polyfill-corejs3 "^0.4.0" + babel-plugin-polyfill-regenerator "^0.3.0" + core-js-compat "^3.19.1" semver "^6.3.0" -"@babel/preset-modules@^0.1.4": +"@babel/preset-modules@^0.1.5": version "0.1.5" resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== @@ -944,17 +948,17 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-react@7.13.13": - version "7.13.13" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.13.13.tgz#fa6895a96c50763fe693f9148568458d5a839761" - integrity sha512-gx+tDLIE06sRjKJkVtpZ/t3mzCDOnPG+ggHZG9lffUbX8+wC739x20YQc9V35Do6ZAxaUc/HhVHIiOzz5MvDmA== +"@babel/preset-react@7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.16.0.tgz#f71d3e8dff5218478011df037fad52660ee6d82a" + integrity sha512-d31IFW2bLRB28uL1WoElyro8RH5l6531XfxMtCeCmp6RVAF1uTfxxUA0LH1tXl+psZdwfmIbwoG4U5VwgbhtLw== dependencies: - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-validator-option" "^7.12.17" - "@babel/plugin-transform-react-display-name" "^7.12.13" - "@babel/plugin-transform-react-jsx" "^7.13.12" - "@babel/plugin-transform-react-jsx-development" "^7.12.17" - "@babel/plugin-transform-react-pure-annotations" "^7.12.1" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-transform-react-display-name" "^7.16.0" + "@babel/plugin-transform-react-jsx" "^7.16.0" + "@babel/plugin-transform-react-jsx-development" "^7.16.0" + "@babel/plugin-transform-react-pure-annotations" "^7.16.0" "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.16.3" @@ -963,7 +967,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/template@^7.12.13", "@babel/template@^7.16.0": +"@babel/template@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" integrity sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A== @@ -972,7 +976,7 @@ "@babel/parser" "^7.16.0" "@babel/types" "^7.16.0" -"@babel/traverse@^7.13.0", "@babel/traverse@^7.13.15", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.3": +"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.3": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.3.tgz#f63e8a938cc1b780f66d9ed3c54f532ca2d14787" integrity sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag== @@ -987,7 +991,7 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.13.14", "@babel/types@^7.13.16", "@babel/types@^7.16.0", "@babel/types@^7.4.4": +"@babel/types@^7.16.0", "@babel/types@^7.4.4": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== @@ -1197,6 +1201,13 @@ "@sentry/types" "6.15.0" tslib "^1.9.3" +"@types/archiver@^5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-5.1.1.tgz#d6d7610de4386b293abd5c1cb1875e0a4f4e1c30" + integrity sha512-heuaCk0YH5m274NOLSi66H1zX6GtZoMsdE6TYFcpFFjBjg0FoU4i4/M/a/kNlgNg26Xk3g364mNOYe1JaiEPOQ== + dependencies: + "@types/glob" "*" + "@types/connect@^3.4.33": version "3.4.35" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" @@ -1234,7 +1245,7 @@ "@types/qs" "*" "@types/range-parser" "*" -"@types/glob@^7.1.1": +"@types/glob@*", "@types/glob@^7.1.1": version "7.2.0" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== @@ -1250,10 +1261,10 @@ "@types/react" "*" hoist-non-react-statics "^3.3.0" -"@types/html-minifier-terser@^5.0.0": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz#693b316ad323ea97eed6b38ed1a3cc02b1672b57" - integrity sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w== +"@types/html-minifier-terser@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.0.0.tgz#563c1c6c132cd204e71512f9c0b394ff90d3fae7" + integrity sha512-NZwaaynfs1oIoLAV1vg18e7QMVDvw+6SQrdJc8w3BwUaoroVSf6EBj/Sk4PBWGxsq0dzhA2drbsuMC1/6C6KgQ== "@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.9" @@ -1819,10 +1830,10 @@ autoprefixer@10.2.5: normalize-range "^0.1.2" postcss-value-parser "^4.1.0" -babel-loader@8.2.2: - version "8.2.2" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.2.tgz#9363ce84c10c9a40e6c753748e1441b60c8a0b81" - integrity sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g== +babel-loader@8.2.3: + version "8.2.3" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.3.tgz#8986b40f1a64cacfcb4b8429320085ef68b1342d" + integrity sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw== dependencies: find-cache-dir "^3.3.1" loader-utils "^1.4.0" @@ -1841,29 +1852,29 @@ babel-plugin-inline-classnames@2.0.1: resolved "https://registry.yarnpkg.com/babel-plugin-inline-classnames/-/babel-plugin-inline-classnames-2.0.1.tgz#d871490af06781a42f231a1e090bc4133594f168" integrity sha512-Pq/jJ6hTiGiqcMmy2d4CyJcfBDeUHOdQl1t1MDWNaSKR2RxDmShSAx4Zqz6NDmFaiinaRqF8eQoTVgSRGU+McQ== -babel-plugin-polyfill-corejs2@^0.2.0: - version "0.2.3" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.3.tgz#6ed8e30981b062f8fe6aca8873a37ebcc8cc1c0f" - integrity sha512-NDZ0auNRzmAfE1oDDPW2JhzIMXUk+FFe2ICejmt5T4ocKgiQx3e0VCRx9NCAidcMtL2RUZaWtXnmjTCkx0tcbA== +babel-plugin-polyfill-corejs2@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.0.tgz#407082d0d355ba565af24126fb6cb8e9115251fd" + integrity sha512-wMDoBJ6uG4u4PNFh72Ty6t3EgfA91puCuAwKIazbQlci+ENb/UU9A3xG5lutjUIiXCIn1CY5L15r9LimiJyrSA== dependencies: "@babel/compat-data" "^7.13.11" - "@babel/helper-define-polyfill-provider" "^0.2.4" + "@babel/helper-define-polyfill-provider" "^0.3.0" semver "^6.1.1" -babel-plugin-polyfill-corejs3@^0.2.0: - version "0.2.5" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.5.tgz#2779846a16a1652244ae268b1e906ada107faf92" - integrity sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw== +babel-plugin-polyfill-corejs3@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.4.0.tgz#0b571f4cf3d67f911512f5c04842a7b8e8263087" + integrity sha512-YxFreYwUfglYKdLUGvIF2nJEsGwj+RhWSX/ije3D2vQPOXuyMLMtg/cCGMDpOA7Nd+MwlNdnGODbd2EwUZPlsw== dependencies: - "@babel/helper-define-polyfill-provider" "^0.2.2" - core-js-compat "^3.16.2" + "@babel/helper-define-polyfill-provider" "^0.3.0" + core-js-compat "^3.18.0" -babel-plugin-polyfill-regenerator@^0.2.0: - version "0.2.3" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.3.tgz#2e9808f5027c4336c994992b48a4262580cb8d6d" - integrity sha512-JVE78oRZPKFIeUqFGrSORNzQnrDwZR16oiWeGM8ZyjBn2XAT5OjP+wXx5ESuo33nUsFUEJYjtklnsKbxW5L+7g== +babel-plugin-polyfill-regenerator@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.0.tgz#9ebbcd7186e1a33e21c5e20cae4e7983949533be" + integrity sha512-dhAPTDLGoMW5/84wkgwiLRwMnio2i1fUe53EuvtKMv0pn2p3S8OCoV1xAzfJPl0KOX7IB89s2ib85vbYiea3jg== dependencies: - "@babel/helper-define-polyfill-provider" "^0.2.4" + "@babel/helper-define-polyfill-provider" "^0.3.0" babel-plugin-transform-react-remove-prop-types@0.4.24: version "0.4.24" @@ -2045,7 +2056,7 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camel-case@^4.1.1: +camel-case@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== @@ -2072,11 +2083,6 @@ camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -camelcase@^6.2.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.1.tgz#250fd350cfd555d0d2160b1d51510eaf8326e86e" - integrity sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA== - caniuse-lite@^1.0.30001196, caniuse-lite@^1.0.30001280: version "1.0.30001282" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001282.tgz#38c781ee0a90ccfe1fe7fefd00e43f5ffdcb96fd" @@ -2142,10 +2148,10 @@ classnames@2.3.1: resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== -clean-css@^4.2.3: - version "4.2.4" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.4.tgz#733bf46eba4e607c6891ea57c24a989356831178" - integrity sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A== +clean-css@^5.1.5: + version "5.2.2" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.2.2.tgz#d3a7c6ee2511011e051719838bdcf8314dc4548d" + integrity sha512-/eR8ru5zyxKzpBLv9YZvMXgTSSQn7AdkMItMYynsFgGwTveCRVam9IUPFloE85B4vAIj05IuKmmEoV7/AQjT0w== dependencies: source-map "~0.6.0" @@ -2266,16 +2272,16 @@ commander@^2.20.0, commander@^2.20.3: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" - integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== - commander@^7.0.0: version "7.2.0" resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== +commander@^8.1.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -2329,7 +2335,7 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -core-js-compat@^3.16.2, core-js-compat@^3.9.0: +core-js-compat@^3.18.0, core-js-compat@^3.19.1: version "3.19.1" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.19.1.tgz#fe598f1a9bf37310d77c3813968e9f7c7bb99476" integrity sha512-Q/VJ7jAF/y68+aUsQJ/afPOewdsGkDtcMb40J8MbuWKlK3Y+wtHq8bTHKPj2WKWLIqmS5JhHs4CzHtz6pT2W6g== @@ -2442,21 +2448,18 @@ css-color-function@~1.3.3: debug "^3.1.0" rgb "~0.1.0" -css-loader@5.2.4: - version "5.2.4" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.2.4.tgz#e985dcbce339812cb6104ef3670f08f9893a1536" - integrity sha512-OFYGyINCKkdQsTrSYxzGSFnGS4gNjcXkKkQgWxK138jgnPt+lepxdjSZNc8sHAl5vP3DhsJUxufWIjOwI8PMMw== +css-loader@6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.5.1.tgz#0c43d4fbe0d97f699c91e9818cb585759091d1b1" + integrity sha512-gEy2w9AnJNnD9Kuo4XAP9VflW/ujKoS9c/syO+uWMlm5igc7LysKzPXaDoR2vroROkSwsTS2tGr1yGGEbZOYZQ== dependencies: - camelcase "^6.2.0" icss-utils "^5.1.0" - loader-utils "^2.0.0" - postcss "^8.2.10" + postcss "^8.2.15" postcss-modules-extract-imports "^3.0.0" postcss-modules-local-by-default "^4.0.0" postcss-modules-scope "^3.0.0" postcss-modules-values "^4.0.0" postcss-value-parser "^4.1.0" - schema-utils "^3.0.0" semver "^7.3.5" css-select@^4.1.3: @@ -2911,7 +2914,7 @@ eslint-plugin-simple-import-sort@7.0.0: resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-7.0.0.tgz#a1dad262f46d2184a90095a60c66fef74727f0f8" integrity sha512-U3vEDB5zhYPNfxT5TYR7u01dboFZp+HNpnGhkDB2g/2E4wZ/g1Q9Ton8UwCLfRV9yAKyYqDh62oHOamvkFxsvw== -eslint-scope@5.1.1, eslint-scope@^5.1.0: +eslint-scope@5.1.1, eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -2934,12 +2937,7 @@ eslint-utils@^3.0.0: dependencies: eslint-visitor-keys "^2.0.0" -eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint-visitor-keys@^2.0.0: +eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== @@ -3255,17 +3253,18 @@ file-loader@6.2.0: loader-utils "^2.0.0" schema-utils "^3.0.0" -filemanager-webpack-plugin@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/filemanager-webpack-plugin/-/filemanager-webpack-plugin-5.0.0.tgz#c5f3f3a8cdfcf670251577f169ee3102da4f88c0" - integrity sha512-PMYuEgHcWdksFnf5jWCr9tkiQOwcpuinXPEk7LPuxsmucbwyrlT5lX/vZR9wHqNszxQLWWb6PWXB1blFE8+GNw== +filemanager-webpack-plugin@6.1.7: + version "6.1.7" + resolved "https://registry.yarnpkg.com/filemanager-webpack-plugin/-/filemanager-webpack-plugin-6.1.7.tgz#2365c4b1aaeeb7aa093f842c9e7ad951a03e0ccf" + integrity sha512-0hhPpmod5t0xy1hBSA9gXi0WlOHL3+x56IBt0b/VMhvbZ5/z6jakXvNOTuVmn4wOZwAORvAeH5qQ5Qs6NdPyiw== dependencies: + "@types/archiver" "^5.1.1" archiver "^5.3.0" cpy "^8.1.2" del "^6.0.0" fs-extra "^10.0.0" is-glob "^4.0.1" - schema-utils "^3.0.0" + schema-utils "^3.1.1" filesize@6.3.0: version "6.3.0" @@ -3505,7 +3504,7 @@ globals@^13.6.0, globals@^13.9.0: dependencies: type-fest "^0.20.2" -globby@^11.0.1, globby@^11.0.2, globby@^11.0.4: +globby@^11.0.1, globby@^11.0.3, globby@^11.0.4: version "11.0.4" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== @@ -3673,33 +3672,33 @@ hosted-git-info@^4.0.1: dependencies: lru-cache "^6.0.0" -html-minifier-terser@^5.0.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#922e96f1f3bb60832c2634b79884096389b1f054" - integrity sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg== +html-minifier-terser@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.0.2.tgz#14059ad64b69bf9f8b8a33f25b53411d8321e75d" + integrity sha512-AgYO3UGhMYQx2S/FBJT3EM0ZYcKmH6m9XL9c1v77BeK/tYJxGPxT1/AtsdUi4FcP8kZGmqqnItCcjFPcX9hk6A== dependencies: - camel-case "^4.1.1" - clean-css "^4.2.3" - commander "^4.1.1" + camel-case "^4.1.2" + clean-css "^5.1.5" + commander "^8.1.0" he "^1.2.0" - param-case "^3.0.3" + param-case "^3.0.4" relateurl "^0.2.7" - terser "^4.6.3" + terser "^5.7.2" html-tags@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg== -html-webpack-plugin@5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.3.1.tgz#8797327548e3de438e3494e0c6d06f181a7f20d1" - integrity sha512-rZsVvPXUYFyME0cuGkyOHfx9hmkFa4pWfxY/mdY38PsBEaVNsRoA+Id+8z6DBDgyv3zaw6XQszdF8HLwfQvcdQ== +html-webpack-plugin@5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz#c3911936f57681c1f9f4d8b68c158cd9dfe52f50" + integrity sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw== dependencies: - "@types/html-minifier-terser" "^5.0.0" - html-minifier-terser "^5.0.1" - lodash "^4.17.20" - pretty-error "^2.1.1" + "@types/html-minifier-terser" "^6.0.0" + html-minifier-terser "^6.0.2" + lodash "^4.17.21" + pretty-error "^4.0.0" tapable "^2.0.0" htmlparser2@^6.1.0: @@ -4345,6 +4344,11 @@ loader-utils@^2.0.0: emojis-list "^3.0.0" json5 "^2.1.2" +loader-utils@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-3.2.0.tgz#bcecc51a7898bee7473d4bc6b845b23af8304d4f" + integrity sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ== + localforage@^1.8.1: version "1.10.0" resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" @@ -4589,14 +4593,12 @@ mini-create-react-context@^0.4.0: "@babel/runtime" "^7.12.1" tiny-warning "^1.0.3" -mini-css-extract-plugin@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-1.5.0.tgz#69bee3b273d2d4ee8649a2eb409514b7df744a27" - integrity sha512-SIbuLMv6jsk1FnLIU5OUG/+VMGUprEjM1+o2trOAx8i5KOKMrhyezb1dJ4Ugsykb8Jgq8/w5NEopy6escV9G7g== +mini-css-extract-plugin@2.4.5: + version "2.4.5" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.4.5.tgz#191d6c170226037212c483af1180b4010b7b9eef" + integrity sha512-oEIhRucyn1JbT/1tU2BhnwO6ft1jjH1iCX9Gc59WFMg0n5773rQU0oyQ0zzeYFFuBfONaRbQJyGoPtuNseMxjA== dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - webpack-sources "^1.1.0" + schema-utils "^4.0.0" minimatch@^3.0.4, minimatch@~3.0.4: version "3.0.4" @@ -4664,7 +4666,7 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nanoid@^3.1.22, nanoid@^3.1.30: +nanoid@^3.1.30: version "3.1.30" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ== @@ -5018,7 +5020,7 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -param-case@^3.0.3: +param-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== @@ -5202,14 +5204,14 @@ postcss-js@^3.0.3: camelcase-css "^2.0.1" postcss "^8.1.6" -postcss-loader@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-5.2.0.tgz#ccd6668a778902d653602289c765a8bc481986dc" - integrity sha512-uSuCkENFeUaOYsKrXm0eNNgVIxc71z8RcckLMbVw473rGojFnrUeqEz6zBgXsH2q1EIzXnO/4pEz9RhALjlITA== +postcss-loader@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-6.2.0.tgz#714370a3f567141cf4cadcdf9575f5234d186bc5" + integrity sha512-H9hv447QjQJVDbHj3OUdciyAXY3v5+UDduzEytAlZCVHCpNAAg/mCSwhYYqZr9BiGYhmYspU8QXxZwiHTLn3yA== dependencies: cosmiconfig "^7.0.0" klona "^2.0.4" - semver "^7.3.4" + semver "^7.3.5" postcss-media-query-parser@^0.2.3: version "0.2.3" @@ -5221,12 +5223,12 @@ postcss-message-helpers@^2.0.0: resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" integrity sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4= -postcss-mixins@7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/postcss-mixins/-/postcss-mixins-7.0.3.tgz#99dd2671b4f7f118d176e7b358f98fc3527439ba" - integrity sha512-YLiJbOBiFmj3dX0gfo74fPDKtRvcQSntzgyqwD1noW1dne6sAJkuCtoOlGaFX8dLxcv9+qkOA6Uh1Ae0/6C56w== +postcss-mixins@8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/postcss-mixins/-/postcss-mixins-8.1.0.tgz#bbb46f017ca6b0b6ec88b5814b106cdf2fea2817" + integrity sha512-c8zHQm0QtiGUe5fpn8jAjZauQwCg2BsKyJDynamJ6cxVakBQFFh0qpo0FPnrb0/diz7tt/emUhOq+fo48rp5Cw== dependencies: - globby "^11.0.2" + globby "^11.0.3" postcss-js "^3.0.3" postcss-simple-vars "^6.0.3" sugarss "^3.0.3" @@ -5259,12 +5261,12 @@ postcss-modules-values@^4.0.0: dependencies: icss-utils "^5.0.0" -postcss-nested@5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-5.0.5.tgz#f0a107d33a9fab11d7637205f5321e27223e3603" - integrity sha512-GSRXYz5bccobpTzLQZXOnSOfKl6TwVr5CyAQJUPub4nuRJSOECK5AqurxVgmtxP48p0Kc/ndY/YyS1yqldX0Ew== +postcss-nested@5.0.6: + version "5.0.6" + resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-5.0.6.tgz#466343f7fc8d3d46af3e7dba3fcd47d052a945bc" + integrity sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA== dependencies: - postcss-selector-parser "^6.0.4" + postcss-selector-parser "^6.0.6" postcss-resolve-nested-selector@^0.1.1: version "0.1.1" @@ -5314,14 +5316,14 @@ postcss-value-parser@^4.1.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== -postcss@8.2.12: - version "8.2.12" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.12.tgz#81248a1a87e0f575cc594a99a08207fd1c4addc4" - integrity sha512-BJnGT5+0q2tzvs6oQfnY2NpEJ7rIXNfBnZtQOKCIsweeWXBXeDd5k31UgTdS3d/c02ouspufn37mTaHWkJyzMQ== +postcss@8.3.11, postcss@^8.1.6, postcss@^8.2.15, postcss@^8.3.11: + version "8.3.11" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.11.tgz#c3beca7ea811cd5e1c4a3ec6d2e7599ef1f8f858" + integrity sha512-hCmlUAIlUiav8Xdqw3Io4LcpA1DOt7h3LSTAC4G6JGHFFaWzI6qvFt9oilvl8BmkbBRX1IhM90ZAmpk68zccQA== dependencies: - colorette "^1.2.2" - nanoid "^3.1.22" - source-map "^0.6.1" + nanoid "^3.1.30" + picocolors "^1.0.0" + source-map-js "^0.6.2" postcss@^6.0.23: version "6.0.23" @@ -5332,15 +5334,6 @@ postcss@^6.0.23: source-map "^0.6.1" supports-color "^5.4.0" -postcss@^8.1.6, postcss@^8.2.10, postcss@^8.3.11: - version "8.3.11" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.11.tgz#c3beca7ea811cd5e1c4a3ec6d2e7599ef1f8f858" - integrity sha512-hCmlUAIlUiav8Xdqw3Io4LcpA1DOt7h3LSTAC4G6JGHFFaWzI6qvFt9oilvl8BmkbBRX1IhM90ZAmpk68zccQA== - dependencies: - nanoid "^3.1.30" - picocolors "^1.0.0" - source-map-js "^0.6.2" - prefix-style@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/prefix-style/-/prefix-style-2.0.1.tgz#66bba9a870cfda308a5dc20e85e9120932c95a06" @@ -5351,13 +5344,13 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -pretty-error@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6" - integrity sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw== +pretty-error@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-4.0.0.tgz#90a703f46dd7234adb46d0f84823e9d1cb8f10d6" + integrity sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw== dependencies: lodash "^4.17.20" - renderkid "^2.0.4" + renderkid "^3.0.0" printj@~1.1.0: version "1.1.2" @@ -5871,16 +5864,16 @@ remove-trailing-separator@^1.0.1: resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= -renderkid@^2.0.4: - version "2.0.7" - resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.7.tgz#464f276a6bdcee606f4a15993f9b29fc74ca8609" - integrity sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ== +renderkid@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a" + integrity sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg== dependencies: css-select "^4.1.3" dom-converter "^0.2.0" htmlparser2 "^6.1.0" lodash "^4.17.21" - strip-ansi "^3.0.1" + strip-ansi "^6.0.1" repeat-element@^1.1.2: version "1.1.4" @@ -6053,7 +6046,7 @@ scheduler@^0.20.2: loose-envify "^1.1.0" object-assign "^4.1.1" -schema-utils@>1.0.0: +schema-utils@>1.0.0, schema-utils@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== @@ -6239,11 +6232,6 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -source-list-map@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" - integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== - source-map-js@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" @@ -6260,7 +6248,7 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@~0.5.12, source-map-support@~0.5.20: +source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -6278,7 +6266,7 @@ source-map@^0.5.0, source-map@^0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -6405,7 +6393,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -strip-ansi@^3.0.0, strip-ansi@^3.0.1: +strip-ansi@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= @@ -6446,13 +6434,10 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -style-loader@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-2.0.0.tgz#9669602fd4690740eaaec137799a03addbbc393c" - integrity sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" +style-loader@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575" + integrity sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ== style-search@^0.1.0: version "0.1.0" @@ -6587,15 +6572,6 @@ terser-webpack-plugin@^5.1.3: source-map "^0.6.1" terser "^5.7.2" -terser@^4.6.3: - version "4.8.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" - integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== - dependencies: - commander "^2.20.0" - source-map "~0.6.1" - source-map-support "~0.5.12" - terser@^5.7.2: version "5.10.0" resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" @@ -6990,14 +6966,6 @@ webpack-merge@^5.7.3: clone-deep "^4.0.1" wildcard "^2.0.0" -webpack-sources@^1.1.0: - version "1.4.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" - integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - webpack-sources@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.2.tgz#d88e3741833efec57c4c789b6010db9977545260" From 03cde56333a8bf1178ed2dbcf2bfdaa8676cfd52 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 21 Nov 2021 18:46:12 -0600 Subject: [PATCH 0171/2320] New: Additional logging for requests when query/grab limit are set --- .../Indexers/IndexerLimitService.cs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/IndexerLimitService.cs b/src/NzbDrone.Core/Indexers/IndexerLimitService.cs index 4392d73ef..4fa742612 100644 --- a/src/NzbDrone.Core/Indexers/IndexerLimitService.cs +++ b/src/NzbDrone.Core/Indexers/IndexerLimitService.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Core.History; -using NzbDrone.Core.Messaging.Events; namespace NzbDrone.Core.Indexers { @@ -15,15 +14,12 @@ namespace NzbDrone.Core.Indexers public class IndexerLimitService : IIndexerLimitService { - private readonly IEventAggregator _eventAggregator; private readonly IHistoryService _historyService; private readonly Logger _logger; - public IndexerLimitService(IEventAggregator eventAggregator, - IHistoryService historyService, - Logger logger) + public IndexerLimitService(IHistoryService historyService, + Logger logger) { - _eventAggregator = eventAggregator; _historyService = historyService; _logger = logger; } @@ -32,14 +28,17 @@ namespace NzbDrone.Core.Indexers { if (indexer.Id > 0 && ((IIndexerSettings)indexer.Settings).BaseSettings.GrabLimit.HasValue) { - var queryCount = _historyService.CountSince(indexer.Id, DateTime.Now.StartOfDay(), new List<HistoryEventType> { HistoryEventType.ReleaseGrabbed }); + var grabCount = _historyService.CountSince(indexer.Id, DateTime.Now.StartOfDay(), new List<HistoryEventType> { HistoryEventType.ReleaseGrabbed }); + var grabLimit = ((IIndexerSettings)indexer.Settings).BaseSettings.QueryLimit; - if (queryCount > ((IIndexerSettings)indexer.Settings).BaseSettings.GrabLimit) + if (grabCount > grabLimit) { _logger.Info("Indexer {0} has exceeded maximum grab limit for today", indexer.Name); return true; } + + _logger.Debug("Indexer {0} has performed {1} of possible {2} grabs for today, proceeding", indexer.Name, grabCount, grabLimit); } return false; @@ -50,13 +49,16 @@ namespace NzbDrone.Core.Indexers if (indexer.Id > 0 && ((IIndexerSettings)indexer.Settings).BaseSettings.QueryLimit.HasValue) { var queryCount = _historyService.CountSince(indexer.Id, DateTime.Now.StartOfDay(), new List<HistoryEventType> { HistoryEventType.IndexerQuery, HistoryEventType.IndexerRss }); + var queryLimit = ((IIndexerSettings)indexer.Settings).BaseSettings.QueryLimit; - if (queryCount > ((IIndexerSettings)indexer.Settings).BaseSettings.QueryLimit) + if (queryCount > queryLimit) { _logger.Info("Indexer {0} has exceeded maximum query limit for today", indexer.Name); return true; } + + _logger.Debug("Indexer {0} has performed {1} of possible {2} queries for today, proceeding", indexer.Name, queryCount, queryLimit); } return false; From f19a81990b485ec061894a0c28894584c616d574 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Mon, 22 Nov 2021 00:32:55 +0000 Subject: [PATCH 0172/2320] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (447 of 447 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (447 of 447 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (441 of 441 strings) Co-authored-by: Havok Dan <havokdan@yahoo.com.br> Co-authored-by: Oskari Lavinto <olavinto@protonmail.com> Co-authored-by: Weblate <noreply@weblate.org> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/fi.json | 584 ++++++++++-------- .../Localization/Core/pt_BR.json | 12 +- 2 files changed, 345 insertions(+), 251 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/fi.json b/src/NzbDrone.Core/Localization/Core/fi.json index d32c061d1..70f21cc25 100644 --- a/src/NzbDrone.Core/Localization/Core/fi.json +++ b/src/NzbDrone.Core/Localization/Core/fi.json @@ -1,182 +1,182 @@ { - "IndexerProxyStatusCheckSingleClientMessage": "Hakemistot eivät ole käytettävissä vikojen takia: {0}", - "Logging": "Kirjaaminen", - "LogLevel": "Lokitaso", - "MovieIndexScrollTop": "Elokuvahakemisto: Vieritä alkuun", + "IndexerProxyStatusCheckSingleClientMessage": "Välityspalvelimet eivät ole käytettävissä virheiden vuoksi: {0}", + "Logging": "Kirjaus", + "LogLevel": "Kirjauksen taso", + "MovieIndexScrollTop": "Elokuvahakemisto: Vieritä yläreunaan", "Apply": "Käytä", - "ClientPriority": "Asiakkaan prioriteetti", - "EnabledHelpText": "Ota tämä luettelo käyttöön Radarrissa", - "IndexerPriorityHelpText": "Hakemistoprioriteetti 1 (korkein) 50 (matalin). Oletus: 25.", + "ClientPriority": "Lataustyökalun painotus", + "EnabledHelpText": "Käytä tätä listaa Prowlarissa", + "IndexerPriorityHelpText": "Indeksoinnin painotus: 1 (korkein) - 50 (matalin). Oletusarvo on 25.", "Manual": "Manuaalinen", - "Add": "Lisätä", + "Add": "Lisää", "Reload": "Lataa uudelleen", - "Indexers": "Hakemistot", - "MovieIndexScrollBottom": "Elokuvahakemisto: Vieritä alareunaa", + "Indexers": "Indeksoinnit", + "MovieIndexScrollBottom": "Elokuvahakemisto: Vieritä alareunaan", "Movies": "Elokuvat", - "PtpOldSettingsCheckMessage": "Seuraavilla PassThePopcorn-indeksoijilla on vanhentuneet asetukset, ja ne tulisi päivittää: {0}", - "QualityDefinitions": "Laadun määritelmät", + "PtpOldSettingsCheckMessage": "Seuraavat PassThePopcorn-indeksoinnit sisältävät vanhentuneita asetuksia, jotka olisi syytä päivittää: {0}", + "QualityDefinitions": "Laatumääritelmät", "SSLCertPassword": "SSL-varmenteen salasana", "Style": "Tyyli", - "Tags": "Tunnisteet", + "Tags": "Tagit", "Today": "Tänään", - "About": "Noin", - "AcceptConfirmationModal": "Hyväksy vahvistusmoodi", + "About": "Tietoja", + "AcceptConfirmationModal": "Hyväksy vahvistus", "Actions": "Toiminnot", - "ApplicationStatusCheckAllClientMessage": "Kaikki luettelot eivät ole käytettävissä vikojen takia", - "ApplicationStatusCheckSingleClientMessage": "Luettelot eivät ole käytettävissä vikojen takia: {0}", + "ApplicationStatusCheckAllClientMessage": "Sovellukset eivät ole käytettävissä virheiden vuoksi", + "ApplicationStatusCheckSingleClientMessage": "Sovellukset eivät ole käytettävissä virheiden vuoksi: {0}", "Date": "Päivämäärä", - "Dates": "Päivämäärät", - "SettingsTimeFormat": "Aikamuoto", + "Dates": "Päiväykset", + "SettingsTimeFormat": "Ajan esitystapa", "Message": "Viesti", - "Seeders": "Kylvökoneet", - "TestAll": "Testaa kaikki", - "AddDownloadClient": "Lisää latausasiakas", - "CustomFilters": "Mukautetut suodattimet", - "DeleteIndexer": "Poista indeksointilaite", - "DeleteTag": "Poista tunniste", - "DownloadClientCheckNoneAvailableMessage": "Latausasiakasta ei ole käytettävissä", - "EnableRss": "Ota RSS käyttöön", - "Filter": "Suodattaa", + "Seeders": "Jakajat", + "TestAll": "Koesta kaikki", + "AddDownloadClient": "Lisää lataustyökalu", + "CustomFilters": "Omat suodattimet", + "DeleteIndexer": "Poista indeksointi", + "DeleteTag": "Poista tagi", + "DownloadClientCheckNoneAvailableMessage": "Lataustyökaluja ei ole käytettävissä", + "EnableRss": "Käytä RSS-syötettä", + "Filter": "Suodata", "Fixed": "Kiinteä", "FocusSearchBox": "Kohdista hakukenttä", - "ForMoreInformationOnTheIndividualDownloadClients": "Saat lisätietoja yksittäisistä latausohjelmista napsauttamalla tietopainikkeita.", - "HideAdvanced": "Piilota Lisäasetukset", + "ForMoreInformationOnTheIndividualDownloadClients": "Saat lisätietoja yksittäisestä lataustyökalusta painamalla lisätietopainikkeita.", + "HideAdvanced": "Piilota lisäasetukset", "History": "Historia", - "MIA": "MIA", + "MIA": "Puuttuu", "MonoVersion": "Mono-versio", - "MonoVersionCheckUpgradeRecommendedMessage": "Tällä hetkellä asennettua mono-versiota {0} tuetaan, mutta päivittämistä versioon {1} suositellaan.", + "MonoVersionCheckUpgradeRecommendedMessage": "Tällä hetkellä asennettua mono-versiota {0} tuetaan, mutta sen päivitystä versioon {1} suositellaan.", "New": "Uusi", - "PageSizeHelpText": "Kullakin sivulla näytettävien kohteiden määrä", + "PageSizeHelpText": "Sivulla näytettävien kohteiden määrä", "Proxy": "Välityspalvelin", - "ProxyBypassFilterHelpText": "Käytä erottimena ',' ja '*.' jokerimerkkinä aliverkkotunnuksille", + "ProxyBypassFilterHelpText": "Käytä erottimena ',' ja '*.' jokerimerkkinä aliverkkotunnuksille (esim. www.esimerkki.fi,*.esimerkki.fi)", "Reddit": "Reddit", - "Refresh": "virkistää", + "Refresh": "Päivitä", "RefreshMovie": "Päivitä elokuva", - "ReleaseBranchCheckOfficialBranchMessage": "Branch {0} ei ole kelvollinen Radarr-julkaisuhakemisto, et saa päivityksiä", - "RestartRequiredHelpTextWarning": "Edellyttää uudelleenkäynnistystä voimaantulemiseksi", + "ReleaseBranchCheckOfficialBranchMessage": "'{0}' ei ole kelvollinen Prowlarr-julkaisuhaara, etkä saa päivityksiä sen kautta", + "RestartRequiredHelpTextWarning": "Käyttöönotto vaatii uudelleenkäynnistyksen", "Result": "Tulos", - "Settings": "asetukset", - "SettingsLongDateFormat": "Pitkä päivämäärämuoto", - "SettingsShortDateFormat": "Lyhyt päivämäärämuoto", - "UnselectAll": "Poista kaikkien valinta", - "UpdateCheckStartupTranslocationMessage": "Päivitystä ei voi asentaa, koska käynnistyskansio {0} on App Translocation -kansiossa.", - "UpdateCheckUINotWritableMessage": "Päivitystä ei voi asentaa, koska käyttäjä {1} ei voi kirjoittaa käyttöliittymäkansiota {0}.", - "UpdateMechanismHelpText": "Käytä Radarrin sisäänrakennettua päivitysohjelmaa tai komentosarjaa", - "ApplyTagsHelpTexts3": "Poista: Poista syötetyt tunnisteet", - "Enable": "ota käyttöön", - "UI": "UI", - "UrlBaseHelpText": "Käänteisen välityspalvelimen tuen oletus on tyhjä", + "Settings": "Asetukset", + "SettingsLongDateFormat": "Päiväyksen pitkä esitystapa", + "SettingsShortDateFormat": "Päiväyksen lyhyt esitystapa", + "UnselectAll": "Tyhjennä kaikki valinnat", + "UpdateCheckStartupTranslocationMessage": "Päivitystä ei voi asentaa, koska käynnistyskansio '{0}' sijaitsee 'App Translocation' -kansiossa.", + "UpdateCheckUINotWritableMessage": "Päivitystä ei voi asentaa, koska käyttäjällä '{1}' ei ole kirjoitusoikeutta käyttöliittymäkansioon '{0}'.", + "UpdateMechanismHelpText": "Käytä Prowlarrin sisäänrakennettua päivitystoimintoa tai omaa komentosarjaa", + "ApplyTagsHelpTexts3": "Poista: Poista syötetyt tagit", + "Enable": "Käytä", + "UI": "Käyttöliittymä", + "UrlBaseHelpText": "Käänteisen välityspalvelimen tuki (esim. 'http://[host]:[port]/[urlBase]'). Oletus on tyhjä.", "Usenet": "Usenet", "BackupNow": "Varmuuskopioi nyt", "NoBackupsAreAvailable": "Varmuuskopioita ei ole saatavilla", - "UpdateCheckStartupNotWritableMessage": "Päivitystä ei voi asentaa, koska Käynnistyskansiota {0} ei voi kirjoittaa käyttäjä {1}.", + "UpdateCheckStartupNotWritableMessage": "Päivitystä ei voi asentaa, koska käyttäjällä '{1}' ei ole kirjoitusoikeutta käynnistyskansioon '{0}'.", "Updates": "Päivitykset", - "UpdateScriptPathHelpText": "Polku mukautettuun komentosarjaan, joka vie puretun päivityspaketin ja käsittelee loput päivitysprosessista", - "Uptime": "Käyttöaste", - "URLBase": "URL-pohja", + "UpdateScriptPathHelpText": "Polku komentosarjaan, joka käsittelee puretun päivitystiedoston ja hoitaa asennuksen loppuosuuden.", + "Uptime": "Käyttöaika", + "URLBase": "URL-perusta", "UseProxy": "Käytä välityspalvelinta", "Username": "Käyttäjätunnus", - "YesCancel": "Kyllä, Peruuta", - "NoTagsHaveBeenAddedYet": "Tunnisteita ei ole vielä lisätty", - "ApplyTags": "Käytä tunnisteita", + "YesCancel": "Kyllä, peruuta", + "NoTagsHaveBeenAddedYet": "Tageja ei ole vielä lisätty", + "ApplyTags": "Käytä tageja", "Authentication": "Todennus", - "AuthenticationMethodHelpText": "Vaadi käyttäjätunnus ja salasana käyttääksesi Radarria", - "BindAddressHelpText": "Voimassa oleva IP4-osoite tai '*' kaikille liitännöille", - "Close": "kiinni", + "AuthenticationMethodHelpText": "Vaadi Prowlarrin käyttöön käyttäjätunnus ja salasana", + "BindAddressHelpText": "Toimiva IPv4-osoite tai jokerimerkkinä '*' (tähti) kaikille yhteyksille.", + "Close": "Sulje", "DeleteNotification": "Poista ilmoitus", - "Docker": "Satamatyöläinen", - "DownloadClient": "Lataa asiakasohjelma", - "EnableMediaInfoHelpText": "Pura tiedostoista videotiedot, kuten tarkkuus, ajonaika ja koodekkitiedot. Tämä edellyttää, että Radarr lukee tiedoston osat, jotka voivat aiheuttaa paljon levyn tai verkon toimintaa tarkistusten aikana.", + "Docker": "Docker", + "DownloadClient": "Lataustyökalu", + "EnableMediaInfoHelpText": "Pura videotiedostoista tietoja, kuten videon resoluutio, kesto ja koodekki. Tätä varten Prowlarrin on luettava tiedostoja osittain ja tämä saattaa aiheuttaa korkeampaa levyn ja/tai verkon kuormitusta tarkistusten aikana.", "Language": "Kieli", - "Search": "Hae", - "Details": "Yksityiskohdat", - "InteractiveSearch": "Interaktiivinen haku", - "Interval": "Intervalli", + "Search": "Haku", + "Details": "Tiedot", + "InteractiveSearch": "Vuorovaikutteinen haku", + "Interval": "Aikaväli", "KeyboardShortcuts": "Pikanäppäimet", - "Languages": "Kieli (kielet", - "LastWriteTime": "Viimeinen kirjoitusaika", + "Languages": "Kielet", + "LastWriteTime": "Viimeisin kirjoitusaika", "LogFiles": "Lokitiedostot", - "LogLevelTraceHelpTextWarning": "Jäljityksen kirjaaminen tulisi ottaa käyttöön vain väliaikaisesti", - "Logs": "Lokit", - "MaximumLimits": "Enimmäisrajat", + "LogLevelTraceHelpTextWarning": "Jäljityskirjausta tulisi käyttää vain väliaikaisesti", + "Logs": "Lokitiedot", + "MaximumLimits": "Enimmäismäärät", "Mechanism": "Mekanismi", - "MonoTlsCheckMessage": "Radarr Mono 4.x -tls -kiertotapa on edelleen käytössä, harkitse MONO_TLS_PROVIDER = vanhan ympäristön vaihtoehdon poistamista", + "MonoTlsCheckMessage": "Radarr Mono 4.x tls -ongelmankiertotapa on edelleen käytössä. Pyri poistamaan MONO_TLS_PROVIDER = vanhan ympäristön vaihtoehto.", "MovieDetailsNextMovie": "Elokuvan tiedot: Seuraava elokuva", "MovieDetailsPreviousMovie": "Elokuvan tiedot: Edellinen elokuva", "Name": "Nimi", "NoLinks": "Ei linkkejä", - "Peers": "Peers", + "Peers": "Vertaiset", "Pending": "Odottaa", "PreferredSize": "Haluttu koko", "Presets": "Esiasetukset", - "Priority": "Prioriteetti", - "PriorityHelpText": "Priorisoi useita latausasiakkaita. Round-Robinia käytetään asiakkaille, joilla on sama prioriteetti.", - "PrioritySettings": "Prioriteetti", - "Protocol": "Pöytäkirja", - "ProxyCheckBadRequestMessage": "Välityspalvelimen testaaminen epäonnistui. StatusCode: {0}", - "ProxyCheckFailedToTestMessage": "Välityspalvelimen testaaminen epäonnistui: {0}", - "ProxyCheckResolveIpMessage": "Määritetyn välityspalvelimen {0} IP-osoitteen selvittäminen epäonnistui", - "ProxyPasswordHelpText": "Käyttäjänimi ja salasana on annettava vain, jos niitä tarvitaan. Jätä ne muuten tyhjiksi.", + "Priority": "Painotus", + "PriorityHelpText": "Määritä useiden lataustyökalujen painotusasetukset. Tasaveroisesti painotettujen työkalujen käyttöä tasapainotetaan Round-Robin-tekniikalla.", + "PrioritySettings": "Painotus", + "Protocol": "Protokolla", + "ProxyCheckBadRequestMessage": "Välityspalvelintesti epäonnistui. Tilakoodi: {0}", + "ProxyCheckFailedToTestMessage": "Välityspalvelintesti epäonnistui: {0}", + "ProxyCheckResolveIpMessage": "Määritetyn välityspalvelimen '{0}' IP-osoitteen selvitys epäonnistui", + "ProxyPasswordHelpText": "Käyttäjätunnus ja salasana tulee syöttää vain tarvittaessa. Muussa tapauksessa jätä kentät tyhjiksi.", "ProxyType": "Välityspalvelimen tyyppi", - "ProxyUsernameHelpText": "Käyttäjänimi ja salasana on annettava vain, jos niitä tarvitaan. Jätä ne muuten tyhjiksi.", - "QualitySettings": "Laatuasetukset", - "Queue": "Jonottaa", + "ProxyUsernameHelpText": "Käyttäjätunnus ja salasana tulee syöttää vain tarvittaessa. Muussa tapauksessa jätä kentät tyhjiksi.", + "QualitySettings": "Laadun asetukset", + "Queue": "Jono", "ReadTheWikiForMoreInformation": "Lue lisätietoja Wikistä", - "ReleaseStatus": "Vapauta tila", + "ReleaseStatus": "Julkaisutila", "RemovedFromTaskQueue": "Poistettu tehtäväjonosta", "RemoveFilter": "Poista suodatin", "RemovingTag": "Poistetaan tagia", - "Reset": "Nollaa", - "ResetAPIKey": "Nollaa API-avain", - "Restart": "Uudelleenkäynnistää", + "Reset": "Uudista", + "ResetAPIKey": "Uudista API-avain", + "Restart": "Käynnistä uudelleen", "RestartNow": "Käynnistä uudelleen nyt", - "Restore": "Palauttaa", + "Restore": "Palauta", "RSS": "RSS", - "RSSIsNotSupportedWithThisIndexer": "RSS-tiedostoa ei tueta tässä hakemistossa", - "ScriptPath": "Komentosarjan polku", - "Security": "Turvallisuus", + "RSSIsNotSupportedWithThisIndexer": "Tämä indeksointi ei tue RSS-syötteitä", + "ScriptPath": "Komentosarjan sijainti", + "Security": "Suojaus", "SuggestTranslationChange": "Ehdota käännösmuutosta", "System": "Järjestelmä", - "SystemTimeCheckMessage": "Järjestelmäaika on pois päältä yli päivällä. Ajoitetut tehtävät eivät välttämättä toimi oikein ennen kuin aika on korjattu", - "TagCannotBeDeletedWhileInUse": "Ei voida poistaa käytön aikana", - "TagIsNotUsedAndCanBeDeleted": "Tunnistetta ei käytetä ja se voidaan poistaa", - "TagsSettingsSummary": "Katso kaikki tunnisteet ja niiden käyttö. Käyttämättömät tunnisteet voidaan poistaa", + "SystemTimeCheckMessage": "Järjestelmän aika on heittä yli vuorokauden verran. Ajoitetut tehtävät eivät luultavasti toimi oikein ennen ajan korjausta.", + "TagCannotBeDeletedWhileInUse": "Tagia ei voi poistaa, koska se on käytössä", + "TagIsNotUsedAndCanBeDeleted": "Tagi ei ole käytössä, joten sen voi poistaa", + "TagsSettingsSummary": "Näytä kaikki tagit ja niiden käyttökohteet. Käyttämättömät tagit voi poistaa.", "Tasks": "Tehtävät", - "Test": "Testata", - "TestAllClients": "Testaa kaikki asiakkaat", + "Test": "Koesta", + "TestAllClients": "Koesta kaikki lataustyökalut", "Time": "Aika", - "Title": "Otsikko", + "Title": "Nimi", "Tomorrow": "Huomenna", - "Torrent": "Torrentit", + "Torrent": "Torrent", "Torrents": "Torrentit", "Type": "Tyyppi", "UILanguage": "Käyttöliittymän kieli", - "UnableToAddANewApplicationPleaseTryAgain": "Uutta ilmoitusta ei voi lisätä, yritä uudelleen.", - "UnableToAddANewIndexerPleaseTryAgain": "Uutta hakemistoa ei voi lisätä, yritä uudelleen.", - "UnableToAddANewIndexerProxyPleaseTryAgain": "Uutta hakemistoa ei voi lisätä, yritä uudelleen.", - "UnableToLoadBackups": "Varmuuskopioita ei voi ladata", - "UnableToLoadDownloadClients": "Latausohjelmia ei voi ladata", - "UnableToLoadGeneralSettings": "Yleisiä asetuksia ei voi ladata", - "UpdateAutomaticallyHelpText": "Lataa ja asenna päivitykset automaattisesti. Voit silti asentaa System: Updates -sovelluksesta", + "UnableToAddANewApplicationPleaseTryAgain": "Uuden sovelluksen lisäys epäonnistui. Yritä uudelleen.", + "UnableToAddANewIndexerPleaseTryAgain": "Uuden indeksoinnin lisäys epäonnistui. Yritä uudelleen.", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Uuden indeksoinnin välityspalvelimen lisäys epäonnistui. Yritä uudelleen.", + "UnableToLoadBackups": "Varmuuskopioiden lataus epäonnistui", + "UnableToLoadDownloadClients": "Lataustyökalujen lataus epäonnistui", + "UnableToLoadGeneralSettings": "Yleisten asetusten lataus epäonnistui", + "UpdateAutomaticallyHelpText": "Lataa ja asenna päivitykset automaattisesti. Voit silti asentaa ne myös lähteestä System:Updates.", "Added": "Lisätty", - "AddIndexer": "Lisää indeksoija", - "AddingTag": "Lisätään tagi", + "AddIndexer": "Lisää indeksointi", + "AddingTag": "Lisätään tagia", "Age": "Ikä", "All": "Kaikki", - "AllIndexersHiddenDueToFilter": "Kaikki elokuvat on piilotettu käytetyn suodattimen takia.", - "Analytics": "Analytics", - "AnalyticsEnabledHelpText": "Lähetä nimettömiä käyttö- ja virhetietoja Radarrin palvelimille. Tämä sisältää tietoja selaimestasi, mitä Radarr WebUI -sivuja käytät, virheraportoinnista sekä käyttöjärjestelmästä ja ajonaikaisesta versiosta. Käytämme näitä tietoja priorisoimaan ominaisuuksia ja virhekorjauksia.", + "AllIndexersHiddenDueToFilter": "Aktiivinen suodatin on piilottanut kaikki indeksoinnit.", + "Analytics": "Analytiikka", + "AnalyticsEnabledHelpText": "Lähetä nimettömiä käyttö- ja virhetietoja Prowlarin palvelimille. Tämä sisältää tietoja selaimestasi, verkkokäyttöliittymän sivujen käytöstä, virheraportoinnista sekä käyttöjärjestelmästäsi ja versiosta. Käytämme näitä tietoja ominaisuuksien ja virhekorjauksien painotukseen.", "ApiKey": "API-avain", - "AppDataDirectory": "AppData-hakemisto", - "DBMigration": "DB-siirto", - "Delete": "Poistaa", - "DeleteIndexerProxyMessageText": "Haluatko varmasti poistaa tagin {0}?", - "DeleteNotificationMessageText": "Haluatko varmasti poistaa ilmoituksen {0}?", - "Disabled": "Liikuntarajoitteinen", - "DownloadClientCheckUnableToCommunicateMessage": "Ei voida kommunikoida käyttäjän {0} kanssa.", - "DownloadClients": "Lataa asiakkaita", - "DownloadClientSettings": "Lataa asiakasasetukset", - "DownloadClientStatusCheckAllClientMessage": "Kaikki latausasiakkaat eivät ole käytettävissä vikojen takia", + "AppDataDirectory": "AppData-kansio", + "DBMigration": "Tietokannan siirto", + "Delete": "Poista", + "DeleteIndexerProxyMessageText": "Haluatko varmasti poistaa välityspalvelimen \"{0}\"?", + "DeleteNotificationMessageText": "Haluatko varmasti poistaa ilmoituksen '{0}'?", + "Disabled": "Ei käytössä", + "DownloadClientCheckUnableToCommunicateMessage": "Lataustyökalun '{0}' kanssa ei voida viestiä.", + "DownloadClients": "Lataustyökalut", + "DownloadClientSettings": "Lataustyökalujen asetukset", + "DownloadClientStatusCheckAllClientMessage": "Yhtään lataustyökalua ei ole virheiden vuoksi käytettävissä", "MinutesHundredTwenty": "120 minuuttia: {0}", "MinutesNinety": "90 minuuttia: {0}", "MinutesSixty": "60 minuuttia: {0}", @@ -184,178 +184,266 @@ "MoreInfo": "Lisätietoja", "SelectAll": "Valitse kaikki", "SendAnonymousUsageData": "Lähetä nimettömiä käyttötietoja", - "SetTags": "Aseta tunnisteet", - "SettingsEnableColorImpairedMode": "Ota käyttöön Värin heikentynyt tila", - "ShowAdvanced": "Näytä Lisäasetukset", - "ShowSearchHelpText": "Näytä hakupainike hiirellä", - "Shutdown": "Sammuttaa", + "SetTags": "Määritä tageja", + "SettingsEnableColorImpairedMode": "Käytä heikentyneelle värinäölle sopivaa tilaa", + "ShowAdvanced": "Näytä lisäasetukset", + "ShowSearchHelpText": "Näytä hakupainike osoitettaessa", + "Shutdown": "Sammuta", "Size": "Koko", - "Sort": "Järjestellä", - "UnableToAddANewDownloadClientPleaseTryAgain": "Uutta latausasiakasta ei voi lisätä, yritä uudelleen.", - "AppDataLocationHealthCheckMessage": "Päivittäminen ei ole mahdollista estää AppDatan poistamista päivityksestä", - "UnableToLoadHistory": "Historiaa ei voi ladata", - "UnableToLoadIndexers": "Hakemistoja ei voi ladata", - "UnableToLoadNotifications": "Ilmoituksia ei voi ladata", - "UnableToLoadQualityDefinitions": "Laatumääritelmiä ei voi ladata", - "UnableToLoadTags": "Tunnisteita ei voi ladata", - "UnableToLoadUISettings": "Käyttöliittymän asetuksia ei voi ladata", - "UnsavedChanges": "Tallentamattomat muutokset", + "Sort": "Järjestä", + "UnableToAddANewDownloadClientPleaseTryAgain": "Uuden lataustyökalun lisäys epäonnistui. Yitä uudelleen.", + "AppDataLocationHealthCheckMessage": "Päivitystä ei sallita, jotta voidaan estää AppData-kansion poisto päivityksen yhteydessä.", + "UnableToLoadHistory": "Historian lataus epäonnistui", + "UnableToLoadIndexers": "Indeksointien lataus epäonnistui", + "UnableToLoadNotifications": "Ilmoitusten lataus epäonnistui", + "UnableToLoadQualityDefinitions": "Laatumääritelmien lataus epäonnistui", + "UnableToLoadTags": "Tagien lataus epäonnistui", + "UnableToLoadUISettings": "Käyttöliittymän asetusten lataus epäonnistui", + "UnsavedChanges": "Tallentamattomia muutoksia", "Yesterday": "Eilen", - "ConnectionLost": "Yhteys kadotettu", - "ConnectionLostAutomaticMessage": "Radarr yrittää muodostaa yhteyden automaattisesti, tai voit napsauttaa Lataa alla.", - "DeleteDownloadClientMessageText": "Haluatko varmasti poistaa latausasiakasohjelman {0}?", - "DeleteTagMessageText": "Haluatko varmasti poistaa tagin {0}?", - "Discord": "Erimielisyydet", + "ConnectionLost": "Yhteys on katkennut", + "ConnectionLostAutomaticMessage": "Radarr pyrkii muodostamaan yhteyden automaattisesti tai voit painaa alta \"Lataa uudelleen\".", + "DeleteDownloadClientMessageText": "Haluatko varmasti poistaa lataustyökalun '{0}'?", + "DeleteTagMessageText": "Haluatko varmasti poistaa tagin '{0}'?", + "Discord": "Discord", "Donations": "Lahjoitukset", - "DownloadClientUnavailable": "Latausohjelma ei ole käytettävissä", + "DownloadClientUnavailable": "Lataustyökalu ei ole käytettävissä", "Downloading": "Ladataan", - "Edit": "Muokata", - "EnableAutomaticSearchHelpText": "Käytetään, kun automaattiset haut suoritetaan käyttöliittymän tai Radarrin kautta", - "EnableAutomaticSearchHelpTextWarning": "Käytetään, kun käytetään interaktiivista hakua", - "EnableColorImpairedModeHelpText": "Muutettu tyyli, jotta värivammaiset käyttäjät voivat erottaa paremmin värikoodatut tiedot", + "Edit": "Muokkaa", + "EnableAutomaticSearchHelpText": "Käytetään, kun automaattiset haut suoritetaan käyttöliittymästä tai Prowlarin toimesta", + "EnableAutomaticSearchHelpTextWarning": "Käytetään vuorovaikutteisen haun yhteydessä", + "EnableColorImpairedModeHelpText": "Muokattu tyyli käyttäjille, joiden värinäkö on heikentynyt", "Enabled": "Käytössä", - "EnableInteractiveSearchHelpTextWarning": "Hakemistoa ei tueta tällä hakemistolla", + "EnableInteractiveSearchHelpTextWarning": "Hakua ei tueta tällä indeksoinnilla", "EventType": "Tapahtumatyyppi", "Exception": "Poikkeus", - "FeatureRequests": "Ominaisuuspyynnöt", - "Grabbed": "Tarttui", + "FeatureRequests": "Ominaisuusehdotukset", + "Grabbed": "Siepattu", "IgnoredAddresses": "Ohitetut osoitteet", - "IllRestartLater": "Aloitan myöhemmin uudelleen", + "IllRestartLater": "Käynnistän uudelleen myöhemmin", "Info": "Tiedot", - "LaunchBrowserHelpText": " Avaa verkkoselain ja siirry Radarrin kotisivulle sovelluksen alkaessa.", - "MinimumLimits": "Vähimmäisrajat", + "LaunchBrowserHelpText": " Avaa Radarrin sivusto verkkoselaimeen sovelluksen käynnistyessä.", + "MinimumLimits": "Vähimmäismäärät", "NoChanges": "Ei muutoksia", - "NoLeaveIt": "Ei, jätä se", - "PendingChangesMessage": "Sinulla on tallentamattomia muutoksia. Haluatko varmasti poistua tältä sivulta?", - "PendingChangesStayReview": "Pysy ja tarkista muutokset", - "Save": "Tallentaa", + "NoLeaveIt": "Ei, anna olla", + "PendingChangesMessage": "On tallentamattomia muutoksia. Haluatko varmasti poistua sivulta?", + "PendingChangesStayReview": "Älä poistu ja tarkista muutokset", + "Save": "Tallenna", "SaveChanges": "Tallenna muutokset", "SaveSettings": "Tallenna asetukset", - "Scheduled": "Suunniteltu", - "SettingsEnableColorImpairedModeHelpText": "Muutettu tyyli, jotta värivammaiset käyttäjät voivat erottaa paremmin värikoodatut tiedot", - "SettingsShowRelativeDates": "Näytä suhteelliset päivämäärät", - "SettingsShowRelativeDatesHelpText": "Näytä suhteelliset (tänään / eilen / jne.) Tai absoluuttiset päivämäärät", - "ShownClickToHide": "Näkyy, piilota napsauttamalla", + "Scheduled": "Ajoitettu", + "SettingsEnableColorImpairedModeHelpText": "Mukautettu tyyli käyttäjille, joilla on heikentynyt värinäkö", + "SettingsShowRelativeDates": "Näytä suhteutetut päiväykset", + "SettingsShowRelativeDatesHelpText": "Näytä suhteutetut (tänään/eilen/yms.) tai absoluuttiset päiväykset", + "ShownClickToHide": "Näkyvissä, piilota painamalla", "ShowSearch": "Näytä haku", "Source": "Lähde", "SSLPort": "SSL-portti", - "StartTypingOrSelectAPathBelow": "Aloita kirjoittaminen tai valitse alla oleva polku", - "StartupDirectory": "Käynnistyshakemisto", - "TableOptions": "Taulukon asetukset", - "TableOptionsColumnsMessage": "Valitse mitkä sarakkeet ovat näkyvissä ja missä järjestyksessä ne näkyvät", - "TagsHelpText": "Koskee elokuvia, joissa on vähintään yksi vastaava tunniste", - "UnableToAddANewAppProfilePleaseTryAgain": "Uutta laatuprofiilia ei voi lisätä, yritä uudelleen.", - "UnableToAddANewNotificationPleaseTryAgain": "Uutta ilmoitusta ei voi lisätä, yritä uudelleen.", + "StartTypingOrSelectAPathBelow": "Aloita kirjoitus tai valitse sijainti alta", + "StartupDirectory": "Käynnistyskansio", + "TableOptions": "Taulukkoasetukset", + "TableOptionsColumnsMessage": "Valitse näytettävät sarakkeet ja niiden järjestys", + "TagsHelpText": "Koskee indeksointeja, jotka on merkitty ainakin yhdellä täsmäävällä tagilla.", + "UnableToAddANewAppProfilePleaseTryAgain": "Uuden sovellusprofiilin lisäys epäonnistui. Yritä uudelleen.", + "UnableToAddANewNotificationPleaseTryAgain": "Uuden ilmoituksen lisäys epäonnistui. Yritä uudelleen.", "Version": "Versio", "View": "Näytä", - "Warn": "Varoittaa", + "Warn": "Varoita", "Wiki": "Wiki", - "ApplyTagsHelpTexts1": "Kuinka lisätä tunnisteita valittuihin elokuviin", - "ApplyTagsHelpTexts2": "Lisää: Lisää tunnisteet olemassa olevaan tunnisteiden luetteloon", - "ApplyTagsHelpTexts4": "Korvaa: Korvaa tunnisteet syötetyillä tunnisteilla (tyhjennä kaikki tunnisteet kirjoittamalla mitään tunnisteita)", - "Importing": "Tuonti", - "Port": "Satama", - "AreYouSureYouWantToResetYourAPIKey": "Haluatko varmasti nollata API-avaimesi?", + "ApplyTagsHelpTexts1": "Miten tageja lisätään valituille indeksoinneille", + "ApplyTagsHelpTexts2": "Lisää: Lisää tagit olemassa olevaan tagilistaan", + "ApplyTagsHelpTexts4": "Korvaa: Korvaa tagit syötetyillä tageilla (jätä tyjäksi poistaaksesi kaikki tagit)", + "Importing": "Tuodaan", + "Port": "Portti", + "AreYouSureYouWantToResetYourAPIKey": "Haluatko varmasti uudistaa API-avaimesi?", "Automatic": "Automaattinen", "AutomaticSearch": "Automaattinen haku", - "Backup": "Varmuuskopioida", - "BackupFolderHelpText": "Suhteelliset polut ovat Radarrin AppData-hakemistossa", - "BackupIntervalHelpText": "Automaattisten varmuuskopioiden väli", - "BackupRetentionHelpText": "Säilytysjaksoa vanhemmat automaattiset varmuuskopiot puhdistetaan automaattisesti", + "Backup": "Varmuuskopio", + "BackupFolderHelpText": "Suhteelliset polut sijaitsevat Prowlarrin AppData-kansiossa", + "BackupIntervalHelpText": "Automaattisen varmuuskopioinnin aikaväli", + "BackupRetentionHelpText": "Säilytysjaksoa vanhemmat automaattiset varmuuskopiot poistetaan automaattisesti", "Backups": "Varmuuskopiot", "BeforeUpdate": "Ennen päivitystä", - "BindAddress": "Sitova osoite", - "Branch": "Haara", - "BranchUpdate": "Haara, jota käytetään Radarrin päivittämiseen", - "BranchUpdateMechanism": "Ulkoisen päivitysmekanismin käyttämä haara", - "BypassProxyForLocalAddresses": "Ohita välityspalvelin paikallisille osoitteille", - "Cancel": "Peruuttaa", - "CancelPendingTask": "Haluatko varmasti peruuttaa tämän odottavan tehtävän?", + "BindAddress": "Sidososoite", + "Branch": "Kehityshaara", + "BranchUpdate": "Haara, jota käytetään Prowlarrin päivitykseen", + "BranchUpdateMechanism": "Ulkoisen päivittysmekanismin käyttämä kehityshaara", + "BypassProxyForLocalAddresses": "Ohjaa paikalliset osoitteet välityspalvelimen ohi", + "Cancel": "Peruuta", + "CancelPendingTask": "Haluatko varmasti perua tämän odottavan tehtävän?", "CertificateValidation": "Varmenteen vahvistus", - "CertificateValidationHelpText": "Muuta, kuinka tiukka HTTPS-sertifikaatin vahvistus on", + "CertificateValidationHelpText": "Aseta HTTPS-varmenteen vahvistuksen tiukkuus", "ChangeHasNotBeenSavedYet": "Muutosta ei ole vielä tallennettu", - "Clear": "Asia selvä", - "CloneIndexer": "Kloonihakemisto", - "CloneProfile": "Klooniprofiili", - "CloseCurrentModal": "Sulje nykyinen modaali", + "Clear": "Tyhjennä", + "CloneIndexer": "Kloonaa indeksointi", + "CloneProfile": "Kloonaa profiili", + "CloseCurrentModal": "Sulje nykyinen ikkuna", "Columns": "Sarakkeet", "Component": "Komponentti", - "Connections": "Liitännät", - "ConnectSettings": "Yhdistä asetukset", - "CouldNotConnectSignalR": "Yhdistäminen SignalR-verkkoon epäonnistui, käyttöliittymää ei päivitetä", - "Custom": "Mukautettu", - "DelayProfile": "Viivytä profiili", - "DeleteApplicationMessageText": "Haluatko varmasti poistaa ilmoituksen {0}?", + "Connections": "Kytkennät", + "ConnectSettings": "Kytkentöjen asetukset", + "CouldNotConnectSignalR": "SignalR-kirjastoa ei tavoitettu, eikä käyttöliittymää päivitetä", + "Custom": "Oma", + "DelayProfile": "Viiveprofiili", + "DeleteApplicationMessageText": "Haluatko varmasti poistaa sovelluksen \"{0}\"?", "DeleteBackup": "Poista varmuuskopio", - "DeleteBackupMessageText": "Haluatko varmasti poistaa varmuuskopion {0}?", - "DeleteDownloadClient": "Poista Download Client", - "DeleteIndexerMessageText": "Haluatko varmasti poistaa indeksoijan {0}?", - "DownloadClientStatusCheckSingleClientMessage": "Latausasiakkaat eivät ole käytettävissä vikojen takia: {0}", - "EditIndexer": "Muokkaa hakemistoa", - "EnableAutoHelpText": "Jos tämä on käytössä, Elokuvat lisätään automaattisesti Radarriin tästä luettelosta", - "EnableAutomaticAdd": "Ota automaattinen lisäys käyttöön", - "EnableAutomaticSearch": "Ota automaattinen haku käyttöön", - "EnableColorImpairedMode": "Ota käyttöön Värin heikentynyt tila", - "EnableCompletedDownloadHandlingHelpText": "Tuo valmiit lataukset automaattisesti latausohjelmasta", - "EnableHelpText": "Ota käyttöön metatietotiedoston luominen tälle metatietotyypille", - "EnableInteractiveSearch": "Ota interaktiivinen haku käyttöön", - "EnableInteractiveSearchHelpText": "Käytetään, kun käytetään interaktiivista hakua", - "EnableSSL": "Ota SSL käyttöön", - "EnableSslHelpText": " Edellyttää uudelleenkäynnistyksen järjestelmänvalvojana voimaantuloa varten", + "DeleteBackupMessageText": "Haluatko varmasti poistaa varmuuskopion '{0}'?", + "DeleteDownloadClient": "Poista lataustyökalu", + "DeleteIndexerMessageText": "Haluatko varmasti poistaa indeksoinnin '{0}'?", + "DownloadClientStatusCheckSingleClientMessage": "Lataustyökalut eivät ole virheiden vuoksi käytettävissä: {0}", + "EditIndexer": "Muokkaa indeksointia", + "EnableAutoHelpText": "Jos käytössä, lisätään tällä listalla olevat elokuvat automaattisesti Prowlariin", + "EnableAutomaticAdd": "Käytä automaattilisäystä", + "EnableAutomaticSearch": "Käytä automaattihakua", + "EnableColorImpairedMode": "Käytä heikentyneelle värinäölle sopivaa tilaa", + "EnableCompletedDownloadHandlingHelpText": "Tuo valmistuneet lataukset lataustyökalusta automaattisesti", + "EnableHelpText": "Käytä metatietotiedostojen luontia tälle metatietotyypille", + "EnableInteractiveSearch": "Käytä vuorovaikutteista hakua", + "EnableInteractiveSearchHelpText": "Käytetään vuorovaikutteisen haun yhteydessä", + "EnableSSL": "Käytä SSL-suojausta", + "EnableSslHelpText": " Käyttöönotto edellyttää uudelleenkäynnistystä järjestelmänvalvojan oikeuksilla", "Error": "Virhe", - "ErrorLoadingContents": "Virhe sisällön lataamisessa", + "ErrorLoadingContents": "Sisältöä ladattaessa havaittiin virhe", "Events": "Tapahtumat", - "ExistingMovies": "Olemassa olevat elokuvat", - "ExistingTag": "Olemassa oleva tunniste", + "ExistingMovies": "Olemassa olevat elokuva(t)", + "ExistingTag": "Olemassa oleva tagi", "Failed": "Epäonnistui", - "Filename": "Tiedoston nimi", + "Filename": "Tiedostonimi", "Files": "Tiedostot", "Folder": "Kansio", - "General": "Kenraali", + "General": "Yleiset", "GeneralSettings": "Yleiset asetukset", - "GeneralSettingsSummary": "Portti, SSL, käyttäjänimi / salasana, välityspalvelin, analytiikka ja päivitykset", - "Grabs": "Napata", - "Health": "Terveys", + "GeneralSettingsSummary": "Portti, SSL-salaus, käyttäjätunnus/salasana, välityspalvelin, analytiikka ja päivitykset", + "Grabs": "Sieppaukset", + "Health": "Kunto", "Level": "Taso", - "HealthNoIssues": "Ei ongelmia kokoonpanossasi", - "HiddenClickToShow": "Piilotettu, napsauta näyttääksesi", - "HomePage": "Kotisivu", - "Host": "Isäntä", - "Hostname": "Isäntänimi", - "IncludeHealthWarningsHelpText": "Sisällytä terveysvaroitukset", - "Indexer": "Hakemisto", - "IndexerFlags": "Hakemistoliput", - "IndexerLongTermStatusCheckAllClientMessage": "Kaikki indeksoijat eivät ole käytettävissä yli 6 tunnin vikojen takia", - "IndexerLongTermStatusCheckSingleClientMessage": "Indeksoijat eivät ole käytettävissä yli 6 tunnin vikojen takia: {0}", - "IndexerPriority": "Hakemistoprioriteetti", - "IndexerProxyStatusCheckAllClientMessage": "Kaikki luettelot eivät ole käytettävissä vikojen takia", - "IndexerStatusCheckAllClientMessage": "Kaikki indeksoijat eivät ole käytettävissä vikojen takia", - "IndexerStatusCheckSingleClientMessage": "Hakemistot eivät ole käytettävissä vikojen takia: {0}", + "HealthNoIssues": "Kokoonpanossasi ei ole ongelmia", + "HiddenClickToShow": "Piilotettu, näytä painalla", + "HomePage": "Verkkosivusto", + "Host": "Osoite", + "Hostname": "Osoite", + "IncludeHealthWarningsHelpText": "Sisällytä kuntovaroitukset", + "Indexer": "Indeksointi", + "IndexerFlags": "Indeksoinnnin liput", + "IndexerLongTermStatusCheckAllClientMessage": "Indeksoinnint eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi", + "IndexerLongTermStatusCheckSingleClientMessage": "Indeksoinnit eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi: {0}", + "IndexerPriority": "Indeksointien painotus", + "IndexerProxyStatusCheckAllClientMessage": "Välityspalvelimet eivät ole käytettävissä virheiden vuoksi", + "IndexerStatusCheckAllClientMessage": "Indeksoinnit eivät ole käytettävissä virheiden vuoksi", + "IndexerStatusCheckSingleClientMessage": "Indeksoinnit eivät ole käytettävissä virheiden vuoksi: {0}", "NoChange": "Ei muutosta", - "NoLimitForAnyRuntime": "Ei rajoituksia ajonajalle", + "NoLimitForAnyRuntime": "Ei toistoajan rajoitusta", "NoLogFiles": "Ei lokitiedostoja", - "NoMinimumForAnyRuntime": "Ei vähimmäismäärää millään ajon aikana", - "SSLCertPasswordHelpText": "Salasana pfx-tiedostolle", - "SSLCertPath": "SSL-varmenteen polku", - "SSLCertPathHelpText": "Polku pfx-tiedostoon", + "NoMinimumForAnyRuntime": "Ei toistoajan vähimmäiskestoa", + "SSLCertPasswordHelpText": "PFX-tiedoston salasana", + "SSLCertPath": "SSL-varmenteen sijainti", + "SSLCertPathHelpText": "PFX-tiedoston sijainti", "Status": "Tila", "NotificationTriggers": "Ilmoituksen laukaisimet", "NoUpdatesAreAvailable": "Päivityksiä ei ole saatavilla", - "OAuthPopupMessage": "Selaimesi estää ponnahdusikkunat", + "OAuthPopupMessage": "Selaimesi estää ponnahdukset", "Ok": "Ok", - "OnHealthIssueHelpText": "Terveyskysymyksestä", + "OnHealthIssueHelpText": "Kuntoon liittyvä ongelma", "OpenBrowserOnStart": "Avaa selain käynnistyksen yhteydessä", - "OpenThisModal": "Avaa tämä tila", - "Options": "Vaihtoehdot", + "OpenThisModal": "Avaa tämä ikkuna", + "Options": "Valinnat", "PackageVersion": "Pakettiversio", "PageSize": "Sivun koko", "Password": "Salasana", - "PendingChangesDiscardChanges": "Hylkää muutokset ja lähde", - "PortNumber": "Porttinumero", + "PendingChangesDiscardChanges": "Hylkää muutokset ja poistu", + "PortNumber": "Portti", "RestoreBackup": "Palauta varmuuskopio", "Restrictions": "Rajoitukset", "Retention": "Säilytys", - "UILanguageHelpText": "Kieli, jota Radarr käyttää käyttöliittymään", - "UILanguageHelpTextWarning": "Selaimen uudelleenlataus vaaditaan", - "UISettings": "Käyttöliittymän asetukset" + "UILanguageHelpText": "Prowlarin käyttöliittymä näytetään tällä kielellä", + "UILanguageHelpTextWarning": "Selaimen sivupäivitys vaaditaan", + "UISettings": "Käyttöliittymän asetukset", + "DownloadClientsSettingsSummary": "Lataustyökalujen asetukset Prowlarr-käyttöliittymästä suoritettavalle haulle", + "ProwlarrSupportsAnyDownloadClient": "Prowlarr tukee alla listatuja lataustyökaluja.", + "AddDownloadClientToProwlarr": "Lisäämällä lataustyökalun Prowlarr voi lähettää julkaisut suoraan käyttöliittymästä, kun sisältöä etsitään manuaalisesti.", + "RedirectHelpText": "Uudelleenohjaa indeksoinnin saapuvat latauspyynnöt ja ohjaa sieppaus suoraan sen sijaan, että se välitettäisiin Prowlarin kautta.", + "FullSync": "Täysi synkronointi", + "SyncLevelFull": "Täysi synkronointi: Pitää sovelluksen täysin synkronoituna. Prowlarissa tehdyt muutokset synkronoidaan etäsovellukseen ja kaikki etäsovelluksessa tehdyt muutokset korvataan seuraavan synkronoinnin yhteydessä.", + "AppProfile": "Sovellusprofiili", + "EnableIndexer": "Käytä indeksointia", + "FilterPlaceHolder": "Hae indeksoinneista", + "IndexerHealthCheckNoIndexers": "Indeksointeja ei ole käytössä, eikä Prowlarr tuota hakutuloksia", + "IndexerObsoleteCheckMessage": "Indeksoinnit ovat vanhentuneita tai niitä on päivitetty: {0}. Poista ja/tai lisää ne Prowlariin uudelleen.", + "IndexerProxy": "Indeksoinnin välityspalvelin", + "IndexerSettingsSummary": "Määritä useita globaaleita indeksoinnin asetuksia, kuten välityspalvelimia.", + "IndexerVipCheckExpiringClientMessage": "Indeksoinnin VIP-edut erääntyvät pian: {0}", + "ProwlarrSupportsAnyIndexer": "Prowlarr tukee Newznab/Torznab-standardin mukaisten indeksointien lisäksi myös useita muita indeksointeja käyttäen \"Yleinen Newznab\" (usenetille) tai \"Yleinen Torznab\"(torrenteille) -määrityksiä.", + "SettingsIndexerLogging": "Tehostettu indeksointien valvonta", + "AddIndexerProxy": "Lisää indeksoinnin välityspalvelin", + "UISettingsSummary": "Päiväyksen ja kielen sekä heikentyneen värinäön asetukset", + "SettingsIndexerLoggingHelpText": "Kirjaa tarkempia tietoja indeksoitien toiminnasta, mukaanlukien vastaukset", + "IndexerTagsHelpText": "Käytä tageja oletusarvoisten lataustyökalujen ja indeksoinnin välityspalvelimien määritykseen tai indeksointiesi organisointiin.", + "UnableToLoadAppProfiles": "Sovellusprofiilien lataus epäonnistui", + "AppProfileSelectHelpText": "Sovellusprofiilien avulla voidaan hallinnoida sovellussynkronoinnin RSS-syötteiden sekä automaattihaun ja vuorovaikutteisen haun asetuksia.", + "AddAppProfile": "Lisää sovelluksen synkronointiprofiili", + "AppProfiles": "Sovellusprofiilit", + "IndexerQuery": "Indeksoinnin kysely", + "IndexerRss": "Indeksoinnin RSS-syöte", + "SearchIndexers": "Hae indeksointeja", + "AddRemoveOnly": "Ainoastaan lisää/poista", + "IndexerVipCheckExpiredClientMessage": "Indeksoinnin VIP-edut ovat erääntyneet: {0}", + "MaintenanceRelease": "Huoltojulkaisu: Virhekorjauksia ja muita parannuksia. Lue lisää Githubin historiasta muutoshistoriasta.", + "Query": "Kysely", + "Redirect": "Uudelleenohjaus", + "RestartProwlarr": "Käynnistä Prowlarr uudelleen", + "SyncLevel": "Synkronoinnin laajuus", + "SyncLevelAddRemove": "Ainoastaan lisää/poista: Etäsovellus päivitetään, kun sovellus lisätään tai poistetaan Prowlarista.", + "SyncAppIndexers": "Synkronoi sovellusten indeksoinnit", + "TestAllApps": "Koesta kaikki sovellukset", + "UnableToLoadIndexerProxies": "Indeksoinnin välityspalvelimien lataus epäonnistui", + "AddedToDownloadClient": "Julkaisu lisättiin lataustyökaluun", + "AddNewIndexer": "Lisää uusi indeksointi", + "AddToDownloadClient": "Lisää julkaisu lataustyökaluun", + "NoSearchResultsFound": "Ei hakutuloksia. Kokeile uutta hakua alta.", + "Notification": "Ilmoitus", + "DeleteIndexerProxy": "Poista indeksoinnin välityspalvelin", + "Encoding": "Enkoodaus", + "MonoNotNetCoreCheckMessage": "Päivitä Prowlar sen .NET Core -versioon", + "SettingsLogRotateHelpText": "Lokien tallennuskansiossa säilytettävien lokitiedostojen enimmäismäärä", + "SettingsLogRotate": "Lokitiedostojen kierrätys", + "SettingsLogSql": "Kirjaa SQL", + "SettingsSqlLoggingHelpText": "Kirjaa kaikki Prowlarrin SQL-kyselyt", + "ConnectionLostMessage": "Prowlarr on menettänyt yhteyden taustajärjestelmään ja sivu on päivitettävä toiminnallisuuden palauttamiseksi.", + "ConnectSettingsSummary": "Ilmoitukset ja omat komentosarjat", + "DevelopmentSettings": "Kehittäjäasetukset", + "Description": "Kuvaus", + "Id": "Tunniste", + "ReleaseBranchCheckPreviousVersionMessage": "'{0}' on edellisen Prowlarr-version julkaisuhaara. Aseta haaraksi 'Nighly' saadaksesi päivityksiä jatkossa", + "SettingsConsoleLogLevel": "Valvontalokin taso", + "SettingsFilterSentryEvents": "Suodata analytiikan tapahtumia", + "SettingsFilterSentryEventsHelpText": "Suodata tunnetut käyttäjävirheet pois analytiikkalähetyksistä", + "AppProfileDeleteConfirm": "Haluatko varmasti poistaa sovellusprofiilin {0}?", + "Applications": "Sovellukset", + "AppProfileInUse": "Sovellusprofiili on käytössä", + "Apps": "Sovellukset", + "Auth": "Todennus", + "Category": "Luokitus", + "ClearHistory": "Tyhjennä historia", + "ClearHistoryMessageText": "Haluatko varmasti tyhjentää kaiken Prowlarr-historian?", + "Connect": "Ilmoitukset", + "EnableRssHelpText": "Käytä indeksoinnille RSS-syötettä", + "DeleteApplication": "Poista sovellus", + "DeleteAppProfile": "Poista sovellusprofiili", + "IndexerProxies": "Indeksoinnin välityspalvelimet", + "IndexerAuth": "Indeksoinnin todennus", + "IndexersSelectedInterp": "{0} indeksointia valittu", + "Notifications": "Ilmoitukset", + "NotificationTriggersHelpText": "Valitse tapahtumat, jotka laukaisevat tämän ilmoituksen", + "Stats": "Tilastot", + "UnableToLoadDevelopmentSettings": "Kehittäjäasetusten lataus epäonnistui", + "AppSettingsSummary": "Sovellukset ja asetukset, joilla määritetään miten Prowlarr viestii PVR-sovellustesi kanssa.", + "EditAppProfile": "Muokkaa sovellusprofiilia", + "Privacy": "Yksityisyys", + "NetCore": ".NET", + "BookSearch": "Kirjahaku", + "SearchType": "Hakutyyppi", + "AudioSearch": "Äänihaku", + "MovieSearch": "Elokuvahaku", + "QueryOptions": "Kyselyasetukset", + "TvSearch": "TV-sarjahaku" } diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index dc4fee9d2..0127b2257 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -60,7 +60,7 @@ "Added": "Adicionado", "AddedToDownloadClient": "Lançamento adicionado ao cliente", "AddIndexer": "Adicionar indexador", - "AddingTag": "Adicionando tag", + "AddingTag": "Adicionando etiqueta", "AddNewIndexer": "Adicionar novo indexador", "AddToDownloadClient": "Adicionar lançamento ao cliente de download", "Age": "Tempo de vida", @@ -329,7 +329,7 @@ "TestAll": "Testar tudo", "TestAllApps": "Testar todos os aplicativos", "TestAllClients": "Testar todos os clientes", - "Time": "Hora", + "Time": "Tempo", "Title": "Título", "Today": "Hoje", "Tomorrow": "Amanhã", @@ -439,5 +439,11 @@ "IndexerProxy": "Proxy do Indexador", "IndexerVipCheckExpiringClientMessage": "Os benefícios VIPS do Indexador expirarão em breve: {0}", "NoLinks": "Sem Links", - "Notification": "Notificação" + "Notification": "Notificação", + "BookSearch": "Pesquisar Livro", + "AudioSearch": "Pesquisar Áudio", + "MovieSearch": "Pesquisar Filme", + "QueryOptions": "Opções de Consulta", + "SearchType": "Tipo de Pesquisa", + "TvSearch": "Pesquisar Séries" } From 520d82ed20648aa9c28881759f72f888badfe9cb Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 21 Nov 2021 18:57:22 -0600 Subject: [PATCH 0173/2320] lint fixup --- .../FileBrowser/FileBrowserModalContent.js | 8 +++--- .../FileBrowserModalContentConnector.js | 6 ++-- .../Components/FileBrowser/FileBrowserRow.js | 2 +- .../Builder/DateFilterBuilderRowValue.js | 4 +-- .../Builder/FilterBuilderModalContent.js | 10 +++---- .../Filter/Builder/FilterBuilderRow.js | 8 +++--- .../Filter/Builder/FilterBuilderRowValue.js | 4 +-- .../IndexerFilterBuilderRowValueConnector.js | 2 +- .../Filter/CustomFilters/CustomFilter.js | 4 +-- frontend/src/Components/Filter/FilterModal.js | 8 +++--- .../Form/AppProfileSelectInputConnector.js | 2 +- .../src/Components/Form/AutoCompleteInput.js | 8 +++--- .../src/Components/Form/AutoSuggestInput.js | 10 +++---- .../Components/Form/CaptchaInputConnector.js | 6 ++-- .../Form/CardigannCaptchaInputConnector.js | 4 +-- frontend/src/Components/Form/CheckInput.js | 8 +++--- frontend/src/Components/Form/DeviceInput.js | 4 +-- .../Components/Form/DeviceInputConnector.js | 6 ++-- .../Components/Form/EnhancedSelectInput.js | 18 ++++++------ .../Form/EnhancedSelectInputConnector.js | 8 +++--- .../Form/EnhancedSelectInputOption.js | 4 +-- .../Form/IndexerFlagsSelectInputConnector.js | 2 +- .../Form/IndexersSelectInputConnector.js | 2 +- .../src/Components/Form/KeyValueListInput.js | 8 +++--- .../Components/Form/KeyValueListInputItem.js | 10 +++---- .../NewznabCategorySelectInputConnector.js | 2 +- frontend/src/Components/Form/NumberInput.js | 6 ++-- .../Components/Form/OAuthInputConnector.js | 4 +-- frontend/src/Components/Form/PathInput.js | 16 +++++------ .../src/Components/Form/PathInputConnector.js | 4 +-- frontend/src/Components/Form/SelectInput.js | 2 +- frontend/src/Components/Form/TagInput.js | 24 ++++++++-------- .../src/Components/Form/TagInputConnector.js | 6 ++-- frontend/src/Components/Form/TagInputInput.js | 2 +- frontend/src/Components/Form/TagInputTag.js | 2 +- .../Form/TagSelectInputConnector.js | 4 +-- frontend/src/Components/Form/TextArea.js | 14 +++++----- frontend/src/Components/Form/TextInput.js | 14 +++++----- .../Components/Form/TextTagInputConnector.js | 4 +-- .../src/Components/Link/ClipboardButton.js | 6 ++-- frontend/src/Components/Link/Link.js | 2 +- .../src/Components/Link/SpinnerErrorButton.js | 2 +- frontend/src/Components/Measure.js | 2 +- frontend/src/Components/Menu/FilterMenu.js | 4 +-- .../src/Components/Menu/FilterMenuItem.js | 2 +- frontend/src/Components/Menu/Menu.js | 10 +++---- .../src/Components/Menu/SearchMenuItem.js | 2 +- .../src/Components/Menu/SelectedMenuItem.js | 2 +- frontend/src/Components/Modal/Modal.js | 8 +++--- .../Page/Header/IndexerSearchInput.js | 16 +++++------ .../src/Components/Page/Header/PageHeader.js | 4 +-- .../Header/PageHeaderActionsMenuConnector.js | 4 +-- frontend/src/Components/Page/Page.js | 6 ++-- frontend/src/Components/Page/PageConnector.js | 2 +- .../src/Components/Page/PageContentBody.js | 2 +- frontend/src/Components/Page/PageJumpBar.js | 2 +- .../src/Components/Page/PageJumpBarItem.js | 2 +- .../Page/Sidebar/Messages/MessageConnector.js | 4 +-- .../Components/Page/Sidebar/PageSidebar.js | 16 +++++------ .../Page/Sidebar/PageSidebarItem.js | 2 +- .../Page/Toolbar/PageToolbarSection.js | 2 +- .../Components/Scroller/OverlayScroller.js | 16 +++++------ frontend/src/Components/Scroller/Scroller.js | 2 +- frontend/src/Components/SignalRConnector.js | 28 +++++++++---------- .../Components/Table/Cells/TableSelectCell.js | 2 +- .../Table/Cells/VirtualTableSelectCell.js | 2 +- .../src/Components/Table/TableHeaderCell.js | 2 +- .../Table/TableOptions/TableOptionsModal.js | 8 +++--- .../TableOptions/TableOptionsModalWrapper.js | 4 +-- frontend/src/Components/Table/TablePager.js | 6 ++-- frontend/src/Components/Table/VirtualTable.js | 4 +-- .../Table/VirtualTableHeaderCell.js | 2 +- frontend/src/Components/Tooltip/Tooltip.js | 10 +++---- frontend/src/Components/keyboardShortcuts.js | 8 +++--- frontend/src/History/History.js | 6 ++-- frontend/src/History/HistoryConnector.js | 20 ++++++------- frontend/src/History/HistoryOptions.js | 2 +- frontend/src/History/HistoryRow.js | 6 ++-- frontend/src/History/HistoryRowConnector.js | 4 +-- .../src/Indexer/Add/AddIndexerModalContent.js | 2 +- .../Add/AddIndexerModalContentConnector.js | 4 +-- .../Indexer/Add/AddIndexerPresetMenuItem.js | 2 +- frontend/src/Indexer/Add/SelectIndexerRow.js | 2 +- .../Delete/DeleteIndexerModalContent.js | 6 ++-- .../DeleteIndexerModalContentConnector.js | 2 +- .../Indexer/Edit/EditIndexerModalConnector.js | 2 +- .../Edit/EditIndexerModalContentConnector.js | 10 +++---- .../Delete/DeleteIndexerModalContent.js | 2 +- .../src/Indexer/Editor/IndexerEditorFooter.js | 12 ++++---- .../Indexer/Editor/Tags/TagsModalContent.js | 4 +-- frontend/src/Indexer/Index/IndexerIndex.js | 24 ++++++++-------- .../Indexer/Index/IndexerIndexConnector.js | 4 +-- .../Index/Table/IndexerIndexActionsCell.js | 8 +++--- .../Indexer/Index/Table/IndexerIndexHeader.js | 4 +-- .../Indexer/Index/Table/IndexerIndexRow.js | 14 +++++----- .../Indexer/Index/Table/IndexerIndexTable.js | 2 +- .../Index/Table/IndexerIndexTableOptions.js | 2 +- frontend/src/Search/QueryParameterModal.js | 6 ++-- frontend/src/Search/QueryParameterOption.js | 2 +- frontend/src/Search/SearchFooter.js | 8 +++--- frontend/src/Search/SearchFooterConnector.js | 2 +- frontend/src/Search/SearchIndex.js | 24 ++++++++-------- frontend/src/Search/SearchIndexConnector.js | 2 +- .../src/Search/Table/SearchIndexHeader.js | 4 +-- frontend/src/Search/Table/SearchIndexRow.js | 2 +- frontend/src/Search/Table/SearchIndexTable.js | 2 +- .../Applications/AddApplicationItem.js | 2 +- .../AddApplicationModalContentConnector.js | 2 +- .../AddApplicationPresetMenuItem.js | 2 +- .../Applications/Applications/Application.js | 10 +++---- .../Applications/Applications/Applications.js | 6 ++-- .../Applications/ApplicationsConnector.js | 2 +- .../EditApplicationModalConnector.js | 2 +- .../EditApplicationModalContentConnector.js | 8 +++--- .../DevelopmentSettingsConnector.js | 4 +-- .../DownloadClients/DownloadClientSettings.js | 6 ++-- .../DownloadClients/AddDownloadClientItem.js | 2 +- .../AddDownloadClientModalContentConnector.js | 2 +- .../AddDownloadClientPresetMenuItem.js | 2 +- .../DownloadClients/DownloadClient.js | 10 +++---- .../DownloadClients/DownloadClients.js | 6 ++-- .../DownloadClientsConnector.js | 2 +- .../EditDownloadClientModalConnector.js | 2 +- ...EditDownloadClientModalContentConnector.js | 8 +++--- .../src/Settings/General/GeneralSettings.js | 4 +-- .../General/GeneralSettingsConnector.js | 8 +++--- .../src/Settings/General/SecuritySettings.js | 8 +++--- .../IndexerProxies/AddIndexerProxyItem.js | 2 +- .../AddIndexerProxyModalContentConnector.js | 2 +- .../AddIndexerProxyPresetMenuItem.js | 2 +- .../EditIndexerProxyModalConnector.js | 2 +- .../EditIndexerProxyModalContentConnector.js | 8 +++--- .../Indexers/IndexerProxies/IndexerProxies.js | 6 ++-- .../IndexerProxies/IndexerProxiesConnector.js | 2 +- .../Indexers/IndexerProxies/IndexerProxy.js | 10 +++---- .../Notifications/AddNotificationItem.js | 2 +- .../AddNotificationModalContentConnector.js | 2 +- .../AddNotificationPresetMenuItem.js | 2 +- .../EditNotificationModalConnector.js | 2 +- .../EditNotificationModalContentConnector.js | 8 +++--- .../Notifications/Notification.js | 10 +++---- .../Notifications/Notifications.js | 6 ++-- .../Notifications/NotificationsConnector.js | 2 +- .../src/Settings/Profiles/App/AppProfile.js | 12 ++++---- .../src/Settings/Profiles/App/AppProfiles.js | 6 ++-- .../Profiles/App/AppProfilesConnector.js | 4 +-- .../App/EditAppProfileModalConnector.js | 2 +- .../EditAppProfileModalContentConnector.js | 4 +-- frontend/src/Settings/SettingsToolbar.js | 2 +- .../src/Settings/SettingsToolbarConnector.js | 8 +++--- frontend/src/Settings/Tags/Tag.js | 10 +++---- .../src/Settings/UI/UISettingsConnector.js | 4 +-- frontend/src/System/Backup/BackupRow.js | 10 +++---- frontend/src/System/Backup/Backups.js | 4 +-- .../Backup/RestoreBackupModalContent.js | 4 +-- .../src/System/Events/LogsTableConnector.js | 20 ++++++------- frontend/src/System/Events/LogsTableRow.js | 4 +-- .../System/Logs/Files/LogFilesConnector.js | 4 +-- frontend/src/System/Logs/LogsNavMenu.js | 4 +-- .../Logs/Updates/UpdateLogFilesConnector.js | 4 +-- frontend/src/System/Status/About/StartTime.js | 2 +- .../src/System/Tasks/Queued/QueuedTaskRow.js | 4 +-- .../src/System/Updates/UpdatesConnector.js | 2 +- 163 files changed, 466 insertions(+), 466 deletions(-) diff --git a/frontend/src/Components/FileBrowser/FileBrowserModalContent.js b/frontend/src/Components/FileBrowser/FileBrowserModalContent.js index 6cf4103cd..3c8aa81a6 100644 --- a/frontend/src/Components/FileBrowser/FileBrowserModalContent.js +++ b/frontend/src/Components/FileBrowser/FileBrowserModalContent.js @@ -70,18 +70,18 @@ class FileBrowserModalContent extends Component { } else { this._scrollerNode = null; } - } + }; // // Listeners onPathInputChange = ({ value }) => { this.setState({ currentPath: value }); - } + }; onRowPress = (path) => { this.props.onFetchPaths(path); - } + }; onOkPress = () => { this.props.onChange({ @@ -91,7 +91,7 @@ class FileBrowserModalContent extends Component { this.props.onClearPaths(); this.props.onModalClose(); - } + }; // // Render diff --git a/frontend/src/Components/FileBrowser/FileBrowserModalContentConnector.js b/frontend/src/Components/FileBrowser/FileBrowserModalContentConnector.js index 1cff6cbc0..1a3a41ef0 100644 --- a/frontend/src/Components/FileBrowser/FileBrowserModalContentConnector.js +++ b/frontend/src/Components/FileBrowser/FileBrowserModalContentConnector.js @@ -78,16 +78,16 @@ class FileBrowserModalContentConnector extends Component { allowFoldersWithoutTrailingSlashes: true, includeFiles }); - } + }; onClearPaths = () => { // this.props.dispatchClearPaths(); - } + }; onModalClose = () => { this.props.dispatchClearPaths(); this.props.onModalClose(); - } + }; // // Render diff --git a/frontend/src/Components/FileBrowser/FileBrowserRow.js b/frontend/src/Components/FileBrowser/FileBrowserRow.js index 067e9a1e7..06bb3029d 100644 --- a/frontend/src/Components/FileBrowser/FileBrowserRow.js +++ b/frontend/src/Components/FileBrowser/FileBrowserRow.js @@ -28,7 +28,7 @@ class FileBrowserRow extends Component { onPress = () => { this.props.onPress(this.props.path); - } + }; // // Render diff --git a/frontend/src/Components/Filter/Builder/DateFilterBuilderRowValue.js b/frontend/src/Components/Filter/Builder/DateFilterBuilderRowValue.js index 26d879dff..6300dd917 100644 --- a/frontend/src/Components/Filter/Builder/DateFilterBuilderRowValue.js +++ b/frontend/src/Components/Filter/Builder/DateFilterBuilderRowValue.js @@ -102,7 +102,7 @@ class DateFilterBuilderRowValue extends Component { name: NAME, value: newValue }); - } + }; onTimeChange = ({ value }) => { const { @@ -117,7 +117,7 @@ class DateFilterBuilderRowValue extends Component { value: filterValue.value } }); - } + }; // // Render diff --git a/frontend/src/Components/Filter/Builder/FilterBuilderModalContent.js b/frontend/src/Components/Filter/Builder/FilterBuilderModalContent.js index 10250e2dd..d5a8c65b8 100644 --- a/frontend/src/Components/Filter/Builder/FilterBuilderModalContent.js +++ b/frontend/src/Components/Filter/Builder/FilterBuilderModalContent.js @@ -63,7 +63,7 @@ class FilterBuilderModalContent extends Component { onLabelChange = ({ value }) => { this.setState({ label: value }); - } + }; onFilterChange = (index, filter) => { const filters = [...this.state.filters]; @@ -72,7 +72,7 @@ class FilterBuilderModalContent extends Component { this.setState({ filters }); - } + }; onAddFilterPress = () => { const filters = [...this.state.filters]; @@ -81,7 +81,7 @@ class FilterBuilderModalContent extends Component { this.setState({ filters }); - } + }; onRemoveFilterPress = (index) => { const filters = [...this.state.filters]; @@ -90,7 +90,7 @@ class FilterBuilderModalContent extends Component { this.setState({ filters }); - } + }; onSaveFilterPress = () => { const { @@ -122,7 +122,7 @@ class FilterBuilderModalContent extends Component { label, filters }); - } + }; // // Render diff --git a/frontend/src/Components/Filter/Builder/FilterBuilderRow.js b/frontend/src/Components/Filter/Builder/FilterBuilderRow.js index 9add7fb3b..9365ee04c 100644 --- a/frontend/src/Components/Filter/Builder/FilterBuilderRow.js +++ b/frontend/src/Components/Filter/Builder/FilterBuilderRow.js @@ -138,7 +138,7 @@ class FilterBuilderRow extends Component { this.selectedFilterBuilderProp = selectedFilterBuilderProp; onFilterChange(index, filter); - } + }; onFilterChange = ({ name, value }) => { const { @@ -158,7 +158,7 @@ class FilterBuilderRow extends Component { filter[name] = value; onFilterChange(index, filter); - } + }; onAddPress = () => { const { @@ -167,7 +167,7 @@ class FilterBuilderRow extends Component { } = this.props; onAddPress(index); - } + }; onRemovePress = () => { const { @@ -176,7 +176,7 @@ class FilterBuilderRow extends Component { } = this.props; onRemovePress(index); - } + }; // // Render diff --git a/frontend/src/Components/Filter/Builder/FilterBuilderRowValue.js b/frontend/src/Components/Filter/Builder/FilterBuilderRowValue.js index 0c36e1810..68fa5c557 100644 --- a/frontend/src/Components/Filter/Builder/FilterBuilderRowValue.js +++ b/frontend/src/Components/Filter/Builder/FilterBuilderRowValue.js @@ -84,7 +84,7 @@ class FilterBuilderRowValue extends Component { name: NAME, value: [...filterValue, value] }); - } + }; onTagDelete = ({ index }) => { const { @@ -98,7 +98,7 @@ class FilterBuilderRowValue extends Component { name: NAME, value }); - } + }; // // Render diff --git a/frontend/src/Components/Filter/Builder/IndexerFilterBuilderRowValueConnector.js b/frontend/src/Components/Filter/Builder/IndexerFilterBuilderRowValueConnector.js index f9b7b7e95..bb4e594cc 100644 --- a/frontend/src/Components/Filter/Builder/IndexerFilterBuilderRowValueConnector.js +++ b/frontend/src/Components/Filter/Builder/IndexerFilterBuilderRowValueConnector.js @@ -47,7 +47,7 @@ class IndexerFilterBuilderRowValueConnector extends Component { if (!this.props.isPopulated) { this.props.dispatchFetchIndexers(); } - } + }; // // Render diff --git a/frontend/src/Components/Filter/CustomFilters/CustomFilter.js b/frontend/src/Components/Filter/CustomFilters/CustomFilter.js index 8c0ae2170..7407f729a 100644 --- a/frontend/src/Components/Filter/CustomFilters/CustomFilter.js +++ b/frontend/src/Components/Filter/CustomFilters/CustomFilter.js @@ -55,7 +55,7 @@ class CustomFilter extends Component { } = this.props; onEditPress(id); - } + }; onRemovePress = () => { const { @@ -67,7 +67,7 @@ class CustomFilter extends Component { dispatchDeleteCustomFilter({ id }); }); - } + }; // // Render diff --git a/frontend/src/Components/Filter/FilterModal.js b/frontend/src/Components/Filter/FilterModal.js index 729f380e7..d52362d7b 100644 --- a/frontend/src/Components/Filter/FilterModal.js +++ b/frontend/src/Components/Filter/FilterModal.js @@ -25,14 +25,14 @@ class FilterModal extends Component { this.setState({ filterBuilder: true }); - } + }; onEditCustomFilter = (id) => { this.setState({ filterBuilder: true, id }); - } + }; onCancelPress = () => { if (this.state.filterBuilder) { @@ -43,7 +43,7 @@ class FilterModal extends Component { } else { this.onModalClose(); } - } + }; onModalClose = () => { this.setState({ @@ -52,7 +52,7 @@ class FilterModal extends Component { }, () => { this.props.onModalClose(); }); - } + }; // // Render diff --git a/frontend/src/Components/Form/AppProfileSelectInputConnector.js b/frontend/src/Components/Form/AppProfileSelectInputConnector.js index 44a81aaca..fc40e9d3c 100644 --- a/frontend/src/Components/Form/AppProfileSelectInputConnector.js +++ b/frontend/src/Components/Form/AppProfileSelectInputConnector.js @@ -69,7 +69,7 @@ class AppProfileSelectInputConnector extends Component { onChange = ({ name, value }) => { this.props.onChange({ name, value: parseInt(value) }); - } + }; // // Render diff --git a/frontend/src/Components/Form/AutoCompleteInput.js b/frontend/src/Components/Form/AutoCompleteInput.js index b12017f8a..d35969c4c 100644 --- a/frontend/src/Components/Form/AutoCompleteInput.js +++ b/frontend/src/Components/Form/AutoCompleteInput.js @@ -35,11 +35,11 @@ class AutoCompleteInput extends Component { name: this.props.name, value: newValue }); - } + }; onInputBlur = () => { this.setState({ suggestions: [] }); - } + }; onSuggestionsFetchRequested = ({ value }) => { const { values } = this.props; @@ -50,11 +50,11 @@ class AutoCompleteInput extends Component { }); this.setState({ suggestions: filteredValues }); - } + }; onSuggestionsClearRequested = () => { this.setState({ suggestions: [] }); - } + }; // // Render diff --git a/frontend/src/Components/Form/AutoSuggestInput.js b/frontend/src/Components/Form/AutoSuggestInput.js index f6e6c28fd..34ec7530b 100644 --- a/frontend/src/Components/Form/AutoSuggestInput.js +++ b/frontend/src/Components/Form/AutoSuggestInput.js @@ -49,7 +49,7 @@ class AutoSuggestInput extends Component { }} </Reference> ); - } + }; renderSuggestionsContainer = ({ containerProps, children }) => { return ( @@ -90,7 +90,7 @@ class AutoSuggestInput extends Component { </Popper> </Portal> ); - } + }; // // Listeners @@ -113,14 +113,14 @@ class AutoSuggestInput extends Component { data.styles.width = width; return data; - } + }; onInputChange = (event, { newValue }) => { this.props.onChange({ name: this.props.name, value: newValue }); - } + }; onInputKeyDown = (event) => { const { @@ -144,7 +144,7 @@ class AutoSuggestInput extends Component { }); } } - } + }; // // Render diff --git a/frontend/src/Components/Form/CaptchaInputConnector.js b/frontend/src/Components/Form/CaptchaInputConnector.js index d29c33757..ad83bf02f 100644 --- a/frontend/src/Components/Form/CaptchaInputConnector.js +++ b/frontend/src/Components/Form/CaptchaInputConnector.js @@ -39,7 +39,7 @@ class CaptchaInputConnector extends Component { componentWillUnmount = () => { this.props.resetCaptcha(); - } + }; // // Listeners @@ -51,7 +51,7 @@ class CaptchaInputConnector extends Component { } = this.props; this.props.refreshCaptcha({ provider, providerData }); - } + }; onCaptchaChange = (captchaResponse) => { // If the captcha has expired `captchaResponse` will be null. @@ -68,7 +68,7 @@ class CaptchaInputConnector extends Component { } = this.props; this.props.getCaptchaCookie({ provider, providerData, captchaResponse }); - } + }; // // Render diff --git a/frontend/src/Components/Form/CardigannCaptchaInputConnector.js b/frontend/src/Components/Form/CardigannCaptchaInputConnector.js index 728755bd9..f77a17de6 100644 --- a/frontend/src/Components/Form/CardigannCaptchaInputConnector.js +++ b/frontend/src/Components/Form/CardigannCaptchaInputConnector.js @@ -31,7 +31,7 @@ class CardigannCaptchaInputConnector extends Component { componentWillUnmount = () => { this.props.resetCaptcha(); - } + }; // // Listeners @@ -48,7 +48,7 @@ class CardigannCaptchaInputConnector extends Component { this.props.resetCaptcha(); this.props.refreshCaptcha({ provider, providerData }); - } + }; // // Render diff --git a/frontend/src/Components/Form/CheckInput.js b/frontend/src/Components/Form/CheckInput.js index f3769a420..26d915880 100644 --- a/frontend/src/Components/Form/CheckInput.js +++ b/frontend/src/Components/Form/CheckInput.js @@ -59,14 +59,14 @@ class CheckInput extends Component { shiftKey }); } - } + }; // // Listeners setRef = (ref) => { this._checkbox = ref; - } + }; onClick = (event) => { if (this.props.isDisabled) { @@ -78,14 +78,14 @@ class CheckInput extends Component { event.preventDefault(); this.toggleChecked(checked, shiftKey); - } + }; onChange = (event) => { const checked = event.target.checked; const shiftKey = event.nativeEvent.shiftKey; this.toggleChecked(checked, shiftKey); - } + }; // // Render diff --git a/frontend/src/Components/Form/DeviceInput.js b/frontend/src/Components/Form/DeviceInput.js index cb250c3d1..55c239cb8 100644 --- a/frontend/src/Components/Form/DeviceInput.js +++ b/frontend/src/Components/Form/DeviceInput.js @@ -23,7 +23,7 @@ class DeviceInput extends Component { name, value: [...value, deviceId] }); - } + }; onTagDelete = ({ index }) => { const { @@ -39,7 +39,7 @@ class DeviceInput extends Component { name, value: newValue }); - } + }; // // Render diff --git a/frontend/src/Components/Form/DeviceInputConnector.js b/frontend/src/Components/Form/DeviceInputConnector.js index 4e3281169..2af9a79f6 100644 --- a/frontend/src/Components/Form/DeviceInputConnector.js +++ b/frontend/src/Components/Form/DeviceInputConnector.js @@ -48,11 +48,11 @@ class DeviceInputConnector extends Component { componentDidMount = () => { this._populate(); - } + }; componentWillUnmount = () => { this.props.dispatchClearOptions({ section: 'devices' }); - } + }; // // Control @@ -77,7 +77,7 @@ class DeviceInputConnector extends Component { onRefreshPress = () => { this._populate(); - } + }; // // Render diff --git a/frontend/src/Components/Form/EnhancedSelectInput.js b/frontend/src/Components/Form/EnhancedSelectInput.js index 8de415dba..fd8e48b9b 100644 --- a/frontend/src/Components/Form/EnhancedSelectInput.js +++ b/frontend/src/Components/Form/EnhancedSelectInput.js @@ -149,7 +149,7 @@ class EnhancedSelectInput extends Component { } return data; - } + }; onWindowClick = (event) => { const button = document.getElementById(this._buttonId); @@ -168,14 +168,14 @@ class EnhancedSelectInput extends Component { this.setState({ isOpen: false }); this._removeListener(); } - } + }; onFocus = () => { if (this.state.isOpen) { this._removeListener(); this.setState({ isOpen: false }); } - } + }; onBlur = () => { if (!this.props.isEditable) { @@ -186,7 +186,7 @@ class EnhancedSelectInput extends Component { this.setState({ selectedIndex: origIndex }); } } - } + }; onKeyDown = (event) => { const { @@ -253,7 +253,7 @@ class EnhancedSelectInput extends Component { if (!_.isEmpty(newState)) { this.setState(newState); } - } + }; onPress = () => { if (this.state.isOpen) { @@ -267,7 +267,7 @@ class EnhancedSelectInput extends Component { } this.setState({ isOpen: !this.state.isOpen }); - } + }; onSelect = (value) => { if (Array.isArray(this.props.value)) { @@ -291,15 +291,15 @@ class EnhancedSelectInput extends Component { value }); } - } + }; onMeasure = ({ width }) => { this.setState({ width }); - } + }; onOptionsModalClose = () => { this.setState({ isOpen: false }); - } + }; // // Render diff --git a/frontend/src/Components/Form/EnhancedSelectInputConnector.js b/frontend/src/Components/Form/EnhancedSelectInputConnector.js index 0311a920c..81f792083 100644 --- a/frontend/src/Components/Form/EnhancedSelectInputConnector.js +++ b/frontend/src/Components/Form/EnhancedSelectInputConnector.js @@ -73,7 +73,7 @@ class EnhancedSelectInputConnector extends Component { componentDidMount = () => { this._populate(); - } + }; componentDidUpdate = (prevProps) => { const prevKey = getProviderDataKey(prevProps.providerData); @@ -82,11 +82,11 @@ class EnhancedSelectInputConnector extends Component { if (!_.isEqual(prevKey, nextKey)) { this.setState({ refetchRequired: true }); } - } + }; componentWillUnmount = () => { this._cleanup(); - } + }; // // Listeners @@ -95,7 +95,7 @@ class EnhancedSelectInputConnector extends Component { if (this.state.refetchRequired) { this._populate(); } - } + }; // // Control diff --git a/frontend/src/Components/Form/EnhancedSelectInputOption.js b/frontend/src/Components/Form/EnhancedSelectInputOption.js index 04d448aa7..b2783dbaa 100644 --- a/frontend/src/Components/Form/EnhancedSelectInputOption.js +++ b/frontend/src/Components/Form/EnhancedSelectInputOption.js @@ -21,11 +21,11 @@ class EnhancedSelectInputOption extends Component { } = this.props; onSelect(id); - } + }; onCheckPress = () => { // CheckInput requires a handler. Swallow the change event because onPress will already handle it via event propagation. - } + }; // // Render diff --git a/frontend/src/Components/Form/IndexerFlagsSelectInputConnector.js b/frontend/src/Components/Form/IndexerFlagsSelectInputConnector.js index 588488c29..8d5c44193 100644 --- a/frontend/src/Components/Form/IndexerFlagsSelectInputConnector.js +++ b/frontend/src/Components/Form/IndexerFlagsSelectInputConnector.js @@ -43,7 +43,7 @@ class IndexerFlagsSelectInputConnector extends Component { }); this.props.onChange({ name, value: indexerFlags }); - } + }; // // Render diff --git a/frontend/src/Components/Form/IndexersSelectInputConnector.js b/frontend/src/Components/Form/IndexersSelectInputConnector.js index 8e596650f..bc411d5cc 100644 --- a/frontend/src/Components/Form/IndexersSelectInputConnector.js +++ b/frontend/src/Components/Form/IndexersSelectInputConnector.js @@ -43,7 +43,7 @@ class IndexersSelectInputConnector extends Component { onChange = ({ name, value }) => { this.props.onChange({ name, value }); - } + }; // // Render diff --git a/frontend/src/Components/Form/KeyValueListInput.js b/frontend/src/Components/Form/KeyValueListInput.js index 1b7f06049..36f25c508 100644 --- a/frontend/src/Components/Form/KeyValueListInput.js +++ b/frontend/src/Components/Form/KeyValueListInput.js @@ -39,7 +39,7 @@ class KeyValueListInput extends Component { name, value: newValue }); - } + }; onRemoveItem = (index) => { const { @@ -55,13 +55,13 @@ class KeyValueListInput extends Component { name, value: newValue }); - } + }; onFocus = () => { this.setState({ isFocused: true }); - } + }; onBlur = () => { this.setState({ @@ -88,7 +88,7 @@ class KeyValueListInput extends Component { value: newValue }); } - } + }; // // Render diff --git a/frontend/src/Components/Form/KeyValueListInputItem.js b/frontend/src/Components/Form/KeyValueListInputItem.js index cf20bb547..5379c2129 100644 --- a/frontend/src/Components/Form/KeyValueListInputItem.js +++ b/frontend/src/Components/Form/KeyValueListInputItem.js @@ -18,7 +18,7 @@ class KeyValueListInputItem extends Component { } = this.props; onChange(index, { key: keyValue, value }); - } + }; onValueChange = ({ value }) => { // TODO: Validate here or validate at a lower level component @@ -30,7 +30,7 @@ class KeyValueListInputItem extends Component { } = this.props; onChange(index, { key: keyValue, value }); - } + }; onRemovePress = () => { const { @@ -39,15 +39,15 @@ class KeyValueListInputItem extends Component { } = this.props; onRemove(index); - } + }; onFocus = () => { this.props.onFocus(); - } + }; onBlur = () => { this.props.onBlur(); - } + }; // // Render diff --git a/frontend/src/Components/Form/NewznabCategorySelectInputConnector.js b/frontend/src/Components/Form/NewznabCategorySelectInputConnector.js index 2c1ac58b9..d9cd3d178 100644 --- a/frontend/src/Components/Form/NewznabCategorySelectInputConnector.js +++ b/frontend/src/Components/Form/NewznabCategorySelectInputConnector.js @@ -42,7 +42,7 @@ class IndexersSelectInputConnector extends Component { onChange = ({ name, value }) => { this.props.onChange({ name, value }); - } + }; // // Render diff --git a/frontend/src/Components/Form/NumberInput.js b/frontend/src/Components/Form/NumberInput.js index c4ecc7e86..8db1cd7b6 100644 --- a/frontend/src/Components/Form/NumberInput.js +++ b/frontend/src/Components/Form/NumberInput.js @@ -59,11 +59,11 @@ class NumberInput extends Component { value: parseValue(this.props, value) }); - } + }; onFocus = () => { this.setState({ isFocused: true }); - } + }; onBlur = () => { const { @@ -88,7 +88,7 @@ class NumberInput extends Component { name, value: parsedValue }); - } + }; // // Render diff --git a/frontend/src/Components/Form/OAuthInputConnector.js b/frontend/src/Components/Form/OAuthInputConnector.js index ff9edfa7d..1567c7e6c 100644 --- a/frontend/src/Components/Form/OAuthInputConnector.js +++ b/frontend/src/Components/Form/OAuthInputConnector.js @@ -41,7 +41,7 @@ class OAuthInputConnector extends Component { componentWillUnmount = () => { this.props.resetOAuth(); - } + }; // // Listeners @@ -60,7 +60,7 @@ class OAuthInputConnector extends Component { providerData, section }); - } + }; // // Render diff --git a/frontend/src/Components/Form/PathInput.js b/frontend/src/Components/Form/PathInput.js index 5e4e61879..972d8f99f 100644 --- a/frontend/src/Components/Form/PathInput.js +++ b/frontend/src/Components/Form/PathInput.js @@ -62,7 +62,7 @@ class PathInput extends Component { onInputChange = ({ value }) => { this.setState({ value }); - } + }; onInputKeyDown = (event) => { if (event.key === 'Tab') { @@ -80,7 +80,7 @@ class PathInput extends Component { } } } - } + }; onInputBlur = () => { this.props.onChange({ @@ -89,28 +89,28 @@ class PathInput extends Component { }); this.props.onClearPaths(); - } + }; onSuggestionsFetchRequested = ({ value }) => { this.props.onFetchPaths(value); - } + }; onSuggestionsClearRequested = () => { // Required because props aren't always rendered, but no-op // because we don't want to reset the paths after a path is selected. - } + }; onSuggestionSelected = (event, { suggestionValue }) => { this.props.onFetchPaths(suggestionValue); - } + }; onFileBrowserOpenPress = () => { this.setState({ isFileBrowserModalOpen: true }); - } + }; onFileBrowserModalClose = () => { this.setState({ isFileBrowserModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/Components/Form/PathInputConnector.js b/frontend/src/Components/Form/PathInputConnector.js index 9e72f5c70..3917a8d3f 100644 --- a/frontend/src/Components/Form/PathInputConnector.js +++ b/frontend/src/Components/Form/PathInputConnector.js @@ -47,11 +47,11 @@ class PathInputConnector extends Component { path, includeFiles }); - } + }; onClearPaths = () => { this.props.dispatchClearPaths(); - } + }; // // Render diff --git a/frontend/src/Components/Form/SelectInput.js b/frontend/src/Components/Form/SelectInput.js index 8cd0fcee3..0a60ffe1e 100644 --- a/frontend/src/Components/Form/SelectInput.js +++ b/frontend/src/Components/Form/SelectInput.js @@ -13,7 +13,7 @@ class SelectInput extends Component { name: this.props.name, value: event.target.value }); - } + }; // // Render diff --git a/frontend/src/Components/Form/TagInput.js b/frontend/src/Components/Form/TagInput.js index 7c0e9ae73..0dd21e0ee 100644 --- a/frontend/src/Components/Form/TagInput.js +++ b/frontend/src/Components/Form/TagInput.js @@ -49,7 +49,7 @@ class TagInput extends Component { _setAutosuggestRef = (ref) => { this._autosuggestRef = ref; - } + }; getSuggestionValue({ name }) { return name; @@ -57,7 +57,7 @@ class TagInput extends Component { shouldRenderSuggestions = (value) => { return value.length >= this.props.minQueryLength; - } + }; renderSuggestion({ name }) { return name; @@ -70,14 +70,14 @@ class TagInput extends Component { value: '', suggestions: [] }); - }, 250, { leading: true, trailing: false }) + }, 250, { leading: true, trailing: false }); // // Listeners onInputContainerPress = () => { this._autosuggestRef.input.focus(); - } + }; onInputChange = (event, { newValue, method }) => { const value = _.isObject(newValue) ? newValue.name : newValue; @@ -85,7 +85,7 @@ class TagInput extends Component { if (method === 'type') { this.setState({ value }); } - } + }; onInputKeyDown = (event) => { const { @@ -125,11 +125,11 @@ class TagInput extends Component { event.preventDefault(); } } - } + }; onInputFocus = () => { this.setState({ isFocused: true }); - } + }; onInputBlur = () => { this.setState({ isFocused: false }); @@ -153,7 +153,7 @@ class TagInput extends Component { if (tag) { this.addTag(tag); } - } + }; onSuggestionsFetchRequested = ({ value }) => { const lowerCaseValue = value.toLowerCase(); @@ -170,16 +170,16 @@ class TagInput extends Component { }); this.setState({ suggestions }); - } + }; onSuggestionsClearRequested = () => { // Required because props aren't always rendered, but no-op // because we don't want to reset the paths after a path is selected. - } + }; onSuggestionSelected = (event, { suggestion }) => { this.addTag(suggestion); - } + }; // // Render @@ -204,7 +204,7 @@ class TagInput extends Component { onInputContainerPress={this.onInputContainerPress} /> ); - } + }; render() { const { diff --git a/frontend/src/Components/Form/TagInputConnector.js b/frontend/src/Components/Form/TagInputConnector.js index 5265e9e4f..9504a2d73 100644 --- a/frontend/src/Components/Form/TagInputConnector.js +++ b/frontend/src/Components/Form/TagInputConnector.js @@ -101,7 +101,7 @@ class TagInputConnector extends Component { newValue.push(tag.id); this.props.onChange({ name, value: newValue }); - } + }; onTagDelete = ({ index }) => { const { @@ -116,7 +116,7 @@ class TagInputConnector extends Component { name, value: newValue }); - } + }; onTagCreated = (tag) => { const { @@ -128,7 +128,7 @@ class TagInputConnector extends Component { newValue.push(tag.id); this.props.onChange({ name, value: newValue }); - } + }; // // Render diff --git a/frontend/src/Components/Form/TagInputInput.js b/frontend/src/Components/Form/TagInputInput.js index 3e28830e9..e28eb3c40 100644 --- a/frontend/src/Components/Form/TagInputInput.js +++ b/frontend/src/Components/Form/TagInputInput.js @@ -19,7 +19,7 @@ class TagInputInput extends Component { } onInputContainerPress(); - } + }; render() { const { diff --git a/frontend/src/Components/Form/TagInputTag.js b/frontend/src/Components/Form/TagInputTag.js index d7b906ce3..1a012eabe 100644 --- a/frontend/src/Components/Form/TagInputTag.js +++ b/frontend/src/Components/Form/TagInputTag.js @@ -22,7 +22,7 @@ class TagInputTag extends Component { index, id: tag.id }); - } + }; // // Render diff --git a/frontend/src/Components/Form/TagSelectInputConnector.js b/frontend/src/Components/Form/TagSelectInputConnector.js index 71d7c4f06..23afe6da1 100644 --- a/frontend/src/Components/Form/TagSelectInputConnector.js +++ b/frontend/src/Components/Form/TagSelectInputConnector.js @@ -60,7 +60,7 @@ class TagSelectInputConnector extends Component { } this.props.onChange({ name, value: newValue }); - } + }; onTagDelete = ({ index }) => { const { @@ -75,7 +75,7 @@ class TagSelectInputConnector extends Component { name, value: newValue }); - } + }; // // Render diff --git a/frontend/src/Components/Form/TextArea.js b/frontend/src/Components/Form/TextArea.js index 5da04dc78..44fd3a249 100644 --- a/frontend/src/Components/Form/TextArea.js +++ b/frontend/src/Components/Form/TextArea.js @@ -35,7 +35,7 @@ class TextArea extends Component { setInputRef = (ref) => { this._input = ref; - } + }; selectionChange() { if (this._selectionTimeout) { @@ -75,7 +75,7 @@ class TextArea extends Component { }; onChange(payload); - } + }; onFocus = (event) => { if (this.props.onFocus) { @@ -83,19 +83,19 @@ class TextArea extends Component { } this.selectionChange(); - } + }; onKeyUp = () => { this.selectionChange(); - } + }; onMouseDown = () => { this._isMouseTarget = true; - } + }; onMouseUp = () => { this.selectionChange(); - } + }; onDocumentMouseUp = () => { if (this._isMouseTarget) { @@ -103,7 +103,7 @@ class TextArea extends Component { } this._isMouseTarget = false; - } + }; // // Render diff --git a/frontend/src/Components/Form/TextInput.js b/frontend/src/Components/Form/TextInput.js index a1831ed33..e2808ce54 100644 --- a/frontend/src/Components/Form/TextInput.js +++ b/frontend/src/Components/Form/TextInput.js @@ -35,7 +35,7 @@ class TextInput extends Component { setInputRef = (ref) => { this._input = ref; - } + }; selectionChange() { if (this._selectionTimeout) { @@ -82,7 +82,7 @@ class TextInput extends Component { } onChange(payload); - } + }; onFocus = (event) => { if (this.props.onFocus) { @@ -90,19 +90,19 @@ class TextInput extends Component { } this.selectionChange(); - } + }; onKeyUp = () => { this.selectionChange(); - } + }; onMouseDown = () => { this._isMouseTarget = true; - } + }; onMouseUp = () => { this.selectionChange(); - } + }; onDocumentMouseUp = () => { if (this._isMouseTarget) { @@ -110,7 +110,7 @@ class TextInput extends Component { } this._isMouseTarget = false; - } + }; // // Render diff --git a/frontend/src/Components/Form/TextTagInputConnector.js b/frontend/src/Components/Form/TextTagInputConnector.js index 587066610..cba307e26 100644 --- a/frontend/src/Components/Form/TextTagInputConnector.js +++ b/frontend/src/Components/Form/TextTagInputConnector.js @@ -53,7 +53,7 @@ class TextTagInputConnector extends Component { }); onChange({ name, value: newValue.join(',') }); - } + }; onTagDelete = ({ index }) => { const { @@ -69,7 +69,7 @@ class TextTagInputConnector extends Component { name, value: newValue.join(',') }); - } + }; // // Render diff --git a/frontend/src/Components/Link/ClipboardButton.js b/frontend/src/Components/Link/ClipboardButton.js index c2d2ef3a1..55843f05f 100644 --- a/frontend/src/Components/Link/ClipboardButton.js +++ b/frontend/src/Components/Link/ClipboardButton.js @@ -63,7 +63,7 @@ class ClipboardButton extends Component { showSuccess: false, showError: false }); - } + }; // // Listeners @@ -72,13 +72,13 @@ class ClipboardButton extends Component { this.setState({ showSuccess: true }); - } + }; onError = () => { this.setState({ showError: true }); - } + }; // // Render diff --git a/frontend/src/Components/Link/Link.js b/frontend/src/Components/Link/Link.js index 1ad8fabf6..3a582e217 100644 --- a/frontend/src/Components/Link/Link.js +++ b/frontend/src/Components/Link/Link.js @@ -18,7 +18,7 @@ class Link extends Component { if (!isDisabled && onPress) { onPress(event); } - } + }; // // Render diff --git a/frontend/src/Components/Link/SpinnerErrorButton.js b/frontend/src/Components/Link/SpinnerErrorButton.js index b83210c76..81d34f7c2 100644 --- a/frontend/src/Components/Link/SpinnerErrorButton.js +++ b/frontend/src/Components/Link/SpinnerErrorButton.js @@ -90,7 +90,7 @@ class SpinnerErrorButton extends Component { hasWarning: false, hasError: false }); - } + }; // // Render diff --git a/frontend/src/Components/Measure.js b/frontend/src/Components/Measure.js index a2f113de7..c41187fbf 100644 --- a/frontend/src/Components/Measure.js +++ b/frontend/src/Components/Measure.js @@ -17,7 +17,7 @@ class Measure extends Component { onMeasure = _.debounce((payload) => { this.props.onMeasure(payload); - }, 250, { leading: true, trailing: false }) + }, 250, { leading: true, trailing: false }); // // Render diff --git a/frontend/src/Components/Menu/FilterMenu.js b/frontend/src/Components/Menu/FilterMenu.js index 5238fd6c6..f1be6a7cd 100644 --- a/frontend/src/Components/Menu/FilterMenu.js +++ b/frontend/src/Components/Menu/FilterMenu.js @@ -25,11 +25,11 @@ class FilterMenu extends Component { onCustomFiltersPress = () => { this.setState({ isFilterModalOpen: true }); - } + }; onFiltersModalClose = () => { this.setState({ isFilterModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/Components/Menu/FilterMenuItem.js b/frontend/src/Components/Menu/FilterMenuItem.js index d2c495187..85ac48c78 100644 --- a/frontend/src/Components/Menu/FilterMenuItem.js +++ b/frontend/src/Components/Menu/FilterMenuItem.js @@ -14,7 +14,7 @@ class FilterMenuItem extends Component { } = this.props; onPress(filterKey); - } + }; // // Render diff --git a/frontend/src/Components/Menu/Menu.js b/frontend/src/Components/Menu/Menu.js index 4cf21f0d9..7e5e0b672 100644 --- a/frontend/src/Components/Menu/Menu.js +++ b/frontend/src/Components/Menu/Menu.js @@ -124,7 +124,7 @@ class Menu extends Component { this.setState({ isMenuOpen: false }); this._removeListener(); } - } + }; onTouchStart = (event) => { const menuButton = document.getElementById(this._menuButtonId); @@ -148,17 +148,17 @@ class Menu extends Component { this.setState({ isMenuOpen: false }); this._removeListener(); } - } + }; onWindowResize = () => { this.setMaxHeight(); - } + }; onWindowScroll = (event) => { if (this.state.isMenuOpen) { this.setMaxHeight(); } - } + }; onMenuButtonPress = () => { const state = { @@ -173,7 +173,7 @@ class Menu extends Component { } this.setState(state); - } + }; // // Render diff --git a/frontend/src/Components/Menu/SearchMenuItem.js b/frontend/src/Components/Menu/SearchMenuItem.js index e9a75c9b2..151fbcd14 100644 --- a/frontend/src/Components/Menu/SearchMenuItem.js +++ b/frontend/src/Components/Menu/SearchMenuItem.js @@ -14,7 +14,7 @@ class SearchMenuItem extends Component { } = this.props; onPress(name); - } + }; // // Render diff --git a/frontend/src/Components/Menu/SelectedMenuItem.js b/frontend/src/Components/Menu/SelectedMenuItem.js index 325b4a134..b80f4f305 100644 --- a/frontend/src/Components/Menu/SelectedMenuItem.js +++ b/frontend/src/Components/Menu/SelectedMenuItem.js @@ -17,7 +17,7 @@ class SelectedMenuItem extends Component { } = this.props; onPress(name); - } + }; // // Render diff --git a/frontend/src/Components/Modal/Modal.js b/frontend/src/Components/Modal/Modal.js index 0ba1690ff..6868d70b3 100644 --- a/frontend/src/Components/Modal/Modal.js +++ b/frontend/src/Components/Modal/Modal.js @@ -66,7 +66,7 @@ class Modal extends Component { _setBackgroundRef = (ref) => { this._backgroundRef = ref; - } + }; _openModal() { openModals.push(this._modalId); @@ -131,7 +131,7 @@ class Modal extends Component { onBackdropBeginPress = (event) => { this._isBackdropPressed = this._isBackdropTarget(event); - } + }; onBackdropEndPress = (event) => { const { @@ -148,7 +148,7 @@ class Modal extends Component { } this._isBackdropPressed = false; - } + }; onKeyDown = (event) => { const keyCode = event.keyCode; @@ -161,7 +161,7 @@ class Modal extends Component { this.props.onModalClose(); } } - } + }; // // Render diff --git a/frontend/src/Components/Page/Header/IndexerSearchInput.js b/frontend/src/Components/Page/Header/IndexerSearchInput.js index b869ddc14..4293788ab 100644 --- a/frontend/src/Components/Page/Header/IndexerSearchInput.js +++ b/frontend/src/Components/Page/Header/IndexerSearchInput.js @@ -36,12 +36,12 @@ class IndexerSearchInput extends Component { setAutosuggestRef = (ref) => { this._autosuggest = ref; - } + }; focusInput = (event) => { event.preventDefault(); this._autosuggest.input.focus(); - } + }; getSectionSuggestions(section) { return section.suggestions; @@ -102,7 +102,7 @@ class IndexerSearchInput extends Component { } this.setState({ value: newValue }); - } + }; onKeyDown = (event) => { if (event.shiftKey || event.altKey || event.ctrlKey) { @@ -137,31 +137,31 @@ class IndexerSearchInput extends Component { this._autosuggest.input.blur(); this.reset(); - } + }; onBlur = () => { this.reset(); - } + }; onSuggestionsClearRequested = () => { this.setState({ suggestions: [], loading: false }); - } + }; onSuggestionsFetchRequested = () => { this.setState({ suggestions: [], loading: false }); - } + }; onSuggestionSelected = (event, { suggestion }) => { if (suggestion.type === ADD_NEW_TYPE) { this.props.onGoToAddNewMovie(this.state.value); } - } + }; // // Render diff --git a/frontend/src/Components/Page/Header/PageHeader.js b/frontend/src/Components/Page/Header/PageHeader.js index e3865fae9..22e71ca4c 100644 --- a/frontend/src/Components/Page/Header/PageHeader.js +++ b/frontend/src/Components/Page/Header/PageHeader.js @@ -32,14 +32,14 @@ class PageHeader extends Component { onOpenKeyboardShortcutsModal = () => { this.setState({ isKeyboardShortcutsModalOpen: true }); - } + }; // // Listeners onKeyboardShortcutsModalClose = () => { this.setState({ isKeyboardShortcutsModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/Components/Page/Header/PageHeaderActionsMenuConnector.js b/frontend/src/Components/Page/Header/PageHeaderActionsMenuConnector.js index 66d131521..3aba95065 100644 --- a/frontend/src/Components/Page/Header/PageHeaderActionsMenuConnector.js +++ b/frontend/src/Components/Page/Header/PageHeaderActionsMenuConnector.js @@ -28,11 +28,11 @@ class PageHeaderActionsMenuConnector extends Component { onRestartPress = () => { this.props.restart(); - } + }; onShutdownPress = () => { this.props.shutdown(); - } + }; // // Render diff --git a/frontend/src/Components/Page/Page.js b/frontend/src/Components/Page/Page.js index e0ad15203..dce638e4a 100644 --- a/frontend/src/Components/Page/Page.js +++ b/frontend/src/Components/Page/Page.js @@ -54,15 +54,15 @@ class Page extends Component { width: window.innerWidth, height: window.innerHeight }); - } + }; onUpdatedModalClose = () => { this.setState({ isUpdatedModalOpen: false }); - } + }; onConnectionLostModalClose = () => { this.setState({ isConnectionLostModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/Components/Page/PageConnector.js b/frontend/src/Components/Page/PageConnector.js index b2f026801..0f826fd68 100644 --- a/frontend/src/Components/Page/PageConnector.js +++ b/frontend/src/Components/Page/PageConnector.js @@ -232,7 +232,7 @@ class PageConnector extends Component { onSidebarToggle = () => { this.props.onSidebarVisibleChange(!this.props.isSidebarVisible); - } + }; // // Render diff --git a/frontend/src/Components/Page/PageContentBody.js b/frontend/src/Components/Page/PageContentBody.js index 5e238ae79..69b6c79d5 100644 --- a/frontend/src/Components/Page/PageContentBody.js +++ b/frontend/src/Components/Page/PageContentBody.js @@ -27,7 +27,7 @@ class PageContentBody extends Component { if (this.props.onScroll && !isLocked()) { onScroll(props); } - } + }; // // Render diff --git a/frontend/src/Components/Page/PageJumpBar.js b/frontend/src/Components/Page/PageJumpBar.js index bdf7dc28f..d6bf8516c 100644 --- a/frontend/src/Components/Page/PageJumpBar.js +++ b/frontend/src/Components/Page/PageJumpBar.js @@ -101,7 +101,7 @@ class PageJumpBar extends Component { onMeasure = ({ height }) => { this.setState({ height }); - } + }; // // Render diff --git a/frontend/src/Components/Page/PageJumpBarItem.js b/frontend/src/Components/Page/PageJumpBarItem.js index aeffe4ddd..daee9837a 100644 --- a/frontend/src/Components/Page/PageJumpBarItem.js +++ b/frontend/src/Components/Page/PageJumpBarItem.js @@ -15,7 +15,7 @@ class PageJumpBarItem extends Component { } = this.props; onItemPress(label); - } + }; // // Render diff --git a/frontend/src/Components/Page/Sidebar/Messages/MessageConnector.js b/frontend/src/Components/Page/Sidebar/Messages/MessageConnector.js index 06c545c27..e92722343 100644 --- a/frontend/src/Components/Page/Sidebar/Messages/MessageConnector.js +++ b/frontend/src/Components/Page/Sidebar/Messages/MessageConnector.js @@ -35,11 +35,11 @@ class MessageConnector extends Component { if (hideAfter) { this._hideTimeoutId = setTimeout(this.hideMessage, hideAfter * 1000); } - } + }; hideMessage = () => { this.props.hideMessage({ id: this.props.id }); - } + }; // // Render diff --git a/frontend/src/Components/Page/Sidebar/PageSidebar.js b/frontend/src/Components/Page/Sidebar/PageSidebar.js index 9de449f95..16657f59e 100644 --- a/frontend/src/Components/Page/Sidebar/PageSidebar.js +++ b/frontend/src/Components/Page/Sidebar/PageSidebar.js @@ -234,7 +234,7 @@ class PageSidebar extends Component { _setSidebarRef = (ref) => { this._sidebarRef = ref; - } + }; _setSidebarTransform(isSidebarVisible, transition, callback) { this.setState({ @@ -263,11 +263,11 @@ class PageSidebar extends Component { event.stopPropagation(); this.props.onSidebarVisibleChange(false); } - } + }; onWindowScroll = () => { this.setState(getPositioning()); - } + }; onTouchStart = (event) => { const touches = event.touches; @@ -287,7 +287,7 @@ class PageSidebar extends Component { this._touchStartX = touchStartX; this._touchStartY = touchStartY; - } + }; onTouchMove = (event) => { const touches = event.touches; @@ -324,7 +324,7 @@ class PageSidebar extends Component { transition: 'none', transform }); - } + }; onTouchEnd = (event) => { const touches = event.changedTouches; @@ -344,16 +344,16 @@ class PageSidebar extends Component { this._touchStartX = null; this._touchStartY = null; - } + }; onTouchCancel = (event) => { this._touchStartX = null; this._touchStartY = null; - } + }; onItemPress = () => { this.props.onSidebarVisibleChange(false); - } + }; // // Render diff --git a/frontend/src/Components/Page/Sidebar/PageSidebarItem.js b/frontend/src/Components/Page/Sidebar/PageSidebarItem.js index 59b95e524..9ad78db6b 100644 --- a/frontend/src/Components/Page/Sidebar/PageSidebarItem.js +++ b/frontend/src/Components/Page/Sidebar/PageSidebarItem.js @@ -21,7 +21,7 @@ class PageSidebarItem extends Component { if (isChildItem || !isParentItem) { onPress(); } - } + }; // // Render diff --git a/frontend/src/Components/Page/Toolbar/PageToolbarSection.js b/frontend/src/Components/Page/Toolbar/PageToolbarSection.js index c35383c9d..d64d11435 100644 --- a/frontend/src/Components/Page/Toolbar/PageToolbarSection.js +++ b/frontend/src/Components/Page/Toolbar/PageToolbarSection.js @@ -108,7 +108,7 @@ class PageToolbarSection extends Component { isMeasured: true, width }); - } + }; // // Render diff --git a/frontend/src/Components/Scroller/OverlayScroller.js b/frontend/src/Components/Scroller/OverlayScroller.js index 7f4272f61..6a7fa1701 100644 --- a/frontend/src/Components/Scroller/OverlayScroller.js +++ b/frontend/src/Components/Scroller/OverlayScroller.js @@ -41,7 +41,7 @@ class OverlayScroller extends Component { if (ref) { this.props.registerScroller(ref.view); } - } + }; _renderThumb = (props) => { return ( @@ -50,7 +50,7 @@ class OverlayScroller extends Component { {...props} /> ); - } + }; _renderTrackHorizontal = ({ style, props }) => { const finalStyle = { @@ -69,7 +69,7 @@ class OverlayScroller extends Component { {...props} /> ); - } + }; _renderTrackVertical = ({ style, props }) => { const finalStyle = { @@ -88,7 +88,7 @@ class OverlayScroller extends Component { {...props} /> ); - } + }; _renderView = (props) => { return ( @@ -97,18 +97,18 @@ class OverlayScroller extends Component { {...props} /> ); - } + }; // // Listers onScrollStart = () => { this._isScrolling = true; - } + }; onScrollStop = () => { this._isScrolling = false; - } + }; onScroll = (event) => { const { @@ -122,7 +122,7 @@ class OverlayScroller extends Component { if (onScroll) { onScroll({ scrollTop, scrollLeft }); } - } + }; // // Render diff --git a/frontend/src/Components/Scroller/Scroller.js b/frontend/src/Components/Scroller/Scroller.js index 454163b7e..0deff8808 100644 --- a/frontend/src/Components/Scroller/Scroller.js +++ b/frontend/src/Components/Scroller/Scroller.js @@ -38,7 +38,7 @@ class Scroller extends Component { this._scroller = ref; this.props.registerScroller(ref); - } + }; // // Render diff --git a/frontend/src/Components/SignalRConnector.js b/frontend/src/Components/SignalRConnector.js index 5e3265cdf..3c10c2754 100644 --- a/frontend/src/Components/SignalRConnector.js +++ b/frontend/src/Components/SignalRConnector.js @@ -139,7 +139,7 @@ class SignalRConnector extends Component { } console.error(`signalR: Unable to find handler for ${name}`); - } + }; handleCommand = (body) => { if (body.action === 'sync') { @@ -158,15 +158,15 @@ class SignalRConnector extends Component { } else { this.props.dispatchUpdateCommand(resource); } - } + }; handleHealth = () => { this.props.dispatchFetchHealth(); - } + }; handleIndexerstatus = () => { this.props.dispatchFetchIndexerStatus(); - } + }; handleIndexer = (body) => { const action = body.action; @@ -177,17 +177,17 @@ class SignalRConnector extends Component { } else if (action === 'deleted') { this.props.dispatchRemoveItem({ section, id: body.resource.id }); } - } + }; handleVersion = (body) => { const version = body.version; this.props.dispatchSetVersion({ version }); - } + }; handleSystemTask = () => { this.props.dispatchFetchCommands(); - } + }; handleTag = (body) => { if (body.action === 'sync') { @@ -195,7 +195,7 @@ class SignalRConnector extends Component { this.props.dispatchFetchTagDetails(); return; } - } + }; // // Listeners @@ -210,7 +210,7 @@ class SignalRConnector extends Component { isDisconnected: false, isRestarting: false }); - } + }; onStart = () => { console.debug('[signalR] connected'); @@ -221,11 +221,11 @@ class SignalRConnector extends Component { isDisconnected: false, isRestarting: false }); - } + }; onReconnecting = () => { this.props.dispatchSetAppValue({ isReconnecting: true }); - } + }; onReconnected = () => { @@ -247,17 +247,17 @@ class SignalRConnector extends Component { dispatchFetchIndexers(); dispatchFetchCommands(); repopulatePage(); - } + }; onClose = () => { console.debug('[signalR] connection closed'); - } + }; onReceiveMessage = (message) => { console.debug('[signalR] received', message.name, message.body); this.handleMessage(message); - } + }; // // Render diff --git a/frontend/src/Components/Table/Cells/TableSelectCell.js b/frontend/src/Components/Table/Cells/TableSelectCell.js index 9c10f4444..a2a297f2e 100644 --- a/frontend/src/Components/Table/Cells/TableSelectCell.js +++ b/frontend/src/Components/Table/Cells/TableSelectCell.js @@ -38,7 +38,7 @@ class TableSelectCell extends Component { } = this.props; onSelectedChange({ id, value, shiftKey }); - } + }; // // Render diff --git a/frontend/src/Components/Table/Cells/VirtualTableSelectCell.js b/frontend/src/Components/Table/Cells/VirtualTableSelectCell.js index a773aab58..66817d21b 100644 --- a/frontend/src/Components/Table/Cells/VirtualTableSelectCell.js +++ b/frontend/src/Components/Table/Cells/VirtualTableSelectCell.js @@ -35,7 +35,7 @@ class VirtualTableSelectCell extends Component { } = this.props; onSelectedChange({ id, value, shiftKey }); - } + }; // // Render diff --git a/frontend/src/Components/Table/TableHeaderCell.js b/frontend/src/Components/Table/TableHeaderCell.js index 78c9535e3..21766978b 100644 --- a/frontend/src/Components/Table/TableHeaderCell.js +++ b/frontend/src/Components/Table/TableHeaderCell.js @@ -21,7 +21,7 @@ class TableHeaderCell extends Component { } else { this.props.onSortPress(name); } - } + }; // // Render diff --git a/frontend/src/Components/Table/TableOptions/TableOptionsModal.js b/frontend/src/Components/Table/TableOptions/TableOptionsModal.js index 8c285ad68..7d6f4f2c1 100644 --- a/frontend/src/Components/Table/TableOptions/TableOptionsModal.js +++ b/frontend/src/Components/Table/TableOptions/TableOptionsModal.js @@ -62,7 +62,7 @@ class TableOptionsModal extends Component { pageSize: value, pageSizeError }); - } + }; onVisibleChange = ({ name, value }) => { const columns = _.cloneDeep(this.props.columns); @@ -71,7 +71,7 @@ class TableOptionsModal extends Component { column.isVisible = value; this.props.onTableOptionChange({ columns }); - } + }; onColumnDragMove = (dragIndex, dropIndex) => { if (this.state.dragIndex !== dragIndex || this.state.dropIndex !== dropIndex) { @@ -80,7 +80,7 @@ class TableOptionsModal extends Component { dropIndex }); } - } + }; onColumnDragEnd = ({ id }, didDrop) => { const { @@ -100,7 +100,7 @@ class TableOptionsModal extends Component { dragIndex: null, dropIndex: null }); - } + }; // // Render diff --git a/frontend/src/Components/Table/TableOptions/TableOptionsModalWrapper.js b/frontend/src/Components/Table/TableOptions/TableOptionsModalWrapper.js index ff2b8538b..6bc18bb82 100644 --- a/frontend/src/Components/Table/TableOptions/TableOptionsModalWrapper.js +++ b/frontend/src/Components/Table/TableOptions/TableOptionsModalWrapper.js @@ -20,11 +20,11 @@ class TableOptionsModalWrapper extends Component { onTableOptionsPress = () => { this.setState({ isTableOptionsModalOpen: true }); - } + }; onTableOptionsModalClose = () => { this.setState({ isTableOptionsModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/Components/Table/TablePager.js b/frontend/src/Components/Table/TablePager.js index df1090b0e..6f71ee5d2 100644 --- a/frontend/src/Components/Table/TablePager.js +++ b/frontend/src/Components/Table/TablePager.js @@ -26,16 +26,16 @@ class TablePager extends Component { onOpenPageSelectClick = () => { this.setState({ isShowingPageSelect: true }); - } + }; onPageSelect = ({ value: page }) => { this.setState({ isShowingPageSelect: false }); this.props.onPageSelect(parseInt(page)); - } + }; onPageSelectBlur = () => { this.setState({ isShowingPageSelect: false }); - } + }; // // Render diff --git a/frontend/src/Components/Table/VirtualTable.js b/frontend/src/Components/Table/VirtualTable.js index 7b70179c7..d877b8208 100644 --- a/frontend/src/Components/Table/VirtualTable.js +++ b/frontend/src/Components/Table/VirtualTable.js @@ -75,7 +75,7 @@ class VirtualTable extends Component { setGridRef = (ref) => { this._grid = ref; - } + }; // // Listeners @@ -84,7 +84,7 @@ class VirtualTable extends Component { this.setState({ width }); - } + }; // // Render diff --git a/frontend/src/Components/Table/VirtualTableHeaderCell.js b/frontend/src/Components/Table/VirtualTableHeaderCell.js index 727d6469d..b944014aa 100644 --- a/frontend/src/Components/Table/VirtualTableHeaderCell.js +++ b/frontend/src/Components/Table/VirtualTableHeaderCell.js @@ -38,7 +38,7 @@ class VirtualTableHeaderCell extends Component { } else { this.props.onSortPress(name); } - } + }; // // Render diff --git a/frontend/src/Components/Tooltip/Tooltip.js b/frontend/src/Components/Tooltip/Tooltip.js index 6a7cb9e3d..43a7b8b77 100644 --- a/frontend/src/Components/Tooltip/Tooltip.js +++ b/frontend/src/Components/Tooltip/Tooltip.js @@ -80,20 +80,20 @@ class Tooltip extends Component { } return data; - } + }; // // Listeners onMeasure = ({ width }) => { this.setState({ width }); - } + }; onClick = () => { if (isMobileUtil()) { this.setState({ isOpen: !this.state.isOpen }); } - } + }; onMouseEnter = () => { if (this._closeTimeout) { @@ -101,13 +101,13 @@ class Tooltip extends Component { } this.setState({ isOpen: true }); - } + }; onMouseLeave = () => { this._closeTimeout = setTimeout(() => { this.setState({ isOpen: false }); }, 100); - } + }; // // Render diff --git a/frontend/src/Components/keyboardShortcuts.js b/frontend/src/Components/keyboardShortcuts.js index 74d8cdf80..713f2bff4 100644 --- a/frontend/src/Components/keyboardShortcuts.js +++ b/frontend/src/Components/keyboardShortcuts.js @@ -64,12 +64,12 @@ function keyboardShortcuts(WrappedComponent) { bindShortcut = (key, callback, options = {}) => { this._mousetrap.bind(key, callback); this._mousetrapBindings[key] = options; - } + }; unbindShortcut = (key) => { delete this._mousetrapBindings[key]; this._mousetrap.unbind(key); - } + }; unbindAllShortcuts = () => { const keys = Object.keys(this._mousetrapBindings); @@ -83,7 +83,7 @@ function keyboardShortcuts(WrappedComponent) { }); this._mousetrapBindings = {}; - } + }; stopCallback = (event, element, combo) => { const binding = this._mousetrapBindings[combo]; @@ -98,7 +98,7 @@ function keyboardShortcuts(WrappedComponent) { element.tagName === 'TEXTAREA' || (element.contentEditable && element.contentEditable === 'true') ); - } + }; // // Render diff --git a/frontend/src/History/History.js b/frontend/src/History/History.js index c4fb34fe4..fa33beffc 100644 --- a/frontend/src/History/History.js +++ b/frontend/src/History/History.js @@ -35,16 +35,16 @@ class History extends Component { onClearHistoryPress = () => { this.setState({ isClearHistoryModalOpen: true }); - } + }; onClearHistoryModalClose = () => { this.setState({ isClearHistoryModalOpen: false }); - } + }; onConfirmClearHistory = () => { this.setState({ isClearHistoryModalOpen: false }); this.props.onClearHistoryPress(); - } + }; // // Render diff --git a/frontend/src/History/HistoryConnector.js b/frontend/src/History/HistoryConnector.js index cede42e57..cd634ca11 100644 --- a/frontend/src/History/HistoryConnector.js +++ b/frontend/src/History/HistoryConnector.js @@ -69,42 +69,42 @@ class HistoryConnector extends Component { repopulate = () => { this.props.fetchHistory(); - } + }; // // Listeners onFirstPagePress = () => { this.props.gotoHistoryFirstPage(); - } + }; onPreviousPagePress = () => { this.props.gotoHistoryPreviousPage(); - } + }; onNextPagePress = () => { this.props.gotoHistoryNextPage(); - } + }; onLastPagePress = () => { this.props.gotoHistoryLastPage(); - } + }; onPageSelect = (page) => { this.props.gotoHistoryPage({ page }); - } + }; onSortPress = (sortKey) => { this.props.setHistorySort({ sortKey }); - } + }; onFilterSelect = (selectedFilterKey) => { this.props.setHistoryFilter({ selectedFilterKey }); - } + }; onClearHistoryPress = () => { this.props.executeCommand({ name: commandNames.CLEAR_HISTORY }); - } + }; onTableOptionChange = (payload) => { this.props.setHistoryTableOption(payload); @@ -112,7 +112,7 @@ class HistoryConnector extends Component { if (payload.pageSize) { this.props.gotoHistoryFirstPage(); } - } + }; // // Render diff --git a/frontend/src/History/HistoryOptions.js b/frontend/src/History/HistoryOptions.js index 228e13678..1459320ee 100644 --- a/frontend/src/History/HistoryOptions.js +++ b/frontend/src/History/HistoryOptions.js @@ -43,7 +43,7 @@ class HistoryOptions extends Component { this.setState(setting, () => { dispatchSaveGeneralSettings(setting); }); - } + }; // // Render diff --git a/frontend/src/History/HistoryRow.js b/frontend/src/History/HistoryRow.js index 6da11287e..8b59a1152 100644 --- a/frontend/src/History/HistoryRow.js +++ b/frontend/src/History/HistoryRow.js @@ -52,15 +52,15 @@ class HistoryRow extends Component { } this.props.onSearchPress(data.query, indexer.id, categories); - } + }; onDetailsPress = () => { this.setState({ isDetailsModalOpen: true }); - } + }; onDetailsModalClose = () => { this.setState({ isDetailsModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/History/HistoryRowConnector.js b/frontend/src/History/HistoryRowConnector.js index 7dea5a730..2d01a2d19 100644 --- a/frontend/src/History/HistoryRowConnector.js +++ b/frontend/src/History/HistoryRowConnector.js @@ -51,11 +51,11 @@ class HistoryRowConnector extends Component { onSearchPress = (term, indexerId, categories) => { this.props.setSearchDefault({ searchQuery: term, searchIndexerIds: [indexerId], searchCategories: categories }); this.props.push(`${window.Prowlarr.urlBase}/search`); - } + }; onMarkAsFailedPress = () => { this.props.markAsFailed({ id: this.props.id }); - } + }; // // Render diff --git a/frontend/src/Indexer/Add/AddIndexerModalContent.js b/frontend/src/Indexer/Add/AddIndexerModalContent.js index 1c5e0f28a..78b0469c0 100644 --- a/frontend/src/Indexer/Add/AddIndexerModalContent.js +++ b/frontend/src/Indexer/Add/AddIndexerModalContent.js @@ -77,7 +77,7 @@ class AddIndexerModalContent extends Component { onFilterChange = ({ value }) => { this.setState({ filter: value }); - } + }; // // Render diff --git a/frontend/src/Indexer/Add/AddIndexerModalContentConnector.js b/frontend/src/Indexer/Add/AddIndexerModalContentConnector.js index 354c3a5c0..2d6ac9fef 100644 --- a/frontend/src/Indexer/Add/AddIndexerModalContentConnector.js +++ b/frontend/src/Indexer/Add/AddIndexerModalContentConnector.js @@ -52,11 +52,11 @@ class AddIndexerModalContentConnector extends Component { onIndexerSelect = ({ implementation, name }) => { this.props.selectIndexerSchema({ implementation, name }); this.props.onModalClose({ indexerSelected: true }); - } + }; onSortPress = (sortKey, sortDirection) => { this.props.setIndexerSchemaSort({ sortKey, sortDirection }); - } + }; // // Render diff --git a/frontend/src/Indexer/Add/AddIndexerPresetMenuItem.js b/frontend/src/Indexer/Add/AddIndexerPresetMenuItem.js index ddea8b043..03196e526 100644 --- a/frontend/src/Indexer/Add/AddIndexerPresetMenuItem.js +++ b/frontend/src/Indexer/Add/AddIndexerPresetMenuItem.js @@ -17,7 +17,7 @@ class AddIndexerPresetMenuItem extends Component { name, implementation }); - } + }; // // Render diff --git a/frontend/src/Indexer/Add/SelectIndexerRow.js b/frontend/src/Indexer/Add/SelectIndexerRow.js index 1526caf58..24acb2650 100644 --- a/frontend/src/Indexer/Add/SelectIndexerRow.js +++ b/frontend/src/Indexer/Add/SelectIndexerRow.js @@ -17,7 +17,7 @@ class SelectIndexerRow extends Component { } = this.props; this.props.onIndexerSelect({ implementation, name }); - } + }; // // Render diff --git a/frontend/src/Indexer/Delete/DeleteIndexerModalContent.js b/frontend/src/Indexer/Delete/DeleteIndexerModalContent.js index 5b4efe2b1..e3d46e108 100644 --- a/frontend/src/Indexer/Delete/DeleteIndexerModalContent.js +++ b/frontend/src/Indexer/Delete/DeleteIndexerModalContent.js @@ -27,11 +27,11 @@ class DeleteIndexerModalContent extends Component { onDeleteFilesChange = ({ value }) => { this.setState({ deleteFiles: value }); - } + }; onAddImportExclusionChange = ({ value }) => { this.setState({ addImportExclusion: value }); - } + }; onDeleteMovieConfirmed = () => { const deleteFiles = this.state.deleteFiles; @@ -39,7 +39,7 @@ class DeleteIndexerModalContent extends Component { this.setState({ deleteFiles: false, addImportExclusion: false }); this.props.onDeletePress(deleteFiles, addImportExclusion); - } + }; // // Render diff --git a/frontend/src/Indexer/Delete/DeleteIndexerModalContentConnector.js b/frontend/src/Indexer/Delete/DeleteIndexerModalContentConnector.js index be9d2b0a1..1e92eb845 100644 --- a/frontend/src/Indexer/Delete/DeleteIndexerModalContentConnector.js +++ b/frontend/src/Indexer/Delete/DeleteIndexerModalContentConnector.js @@ -32,7 +32,7 @@ class DeleteIndexerModalContentConnector extends Component { }); this.props.onModalClose(true); - } + }; // // Render diff --git a/frontend/src/Indexer/Edit/EditIndexerModalConnector.js b/frontend/src/Indexer/Edit/EditIndexerModalConnector.js index 27fc2d0fa..13cd47ae6 100644 --- a/frontend/src/Indexer/Edit/EditIndexerModalConnector.js +++ b/frontend/src/Indexer/Edit/EditIndexerModalConnector.js @@ -33,7 +33,7 @@ class EditIndexerModalConnector extends Component { this.props.dispatchCancelTestIndexer(); this.props.dispatchCancelSaveIndexer(); this.props.onModalClose(); - } + }; // // Render diff --git a/frontend/src/Indexer/Edit/EditIndexerModalContentConnector.js b/frontend/src/Indexer/Edit/EditIndexerModalContentConnector.js index 676457a12..c76dd5ce4 100644 --- a/frontend/src/Indexer/Edit/EditIndexerModalContentConnector.js +++ b/frontend/src/Indexer/Edit/EditIndexerModalContentConnector.js @@ -44,23 +44,23 @@ class EditIndexerModalContentConnector extends Component { onInputChange = ({ name, value }) => { this.props.setIndexerValue({ name, value }); - } + }; onFieldChange = ({ name, value }) => { this.props.setIndexerFieldValue({ name, value }); - } + }; onSavePress = () => { this.props.saveIndexer({ id: this.props.id }); - } + }; onTestPress = () => { this.props.testIndexer({ id: this.props.id }); - } + }; onAdvancedSettingsPress = () => { this.props.toggleAdvancedSettings(); - } + }; // // Render diff --git a/frontend/src/Indexer/Editor/Delete/DeleteIndexerModalContent.js b/frontend/src/Indexer/Editor/Delete/DeleteIndexerModalContent.js index dff05e52d..b4035a35c 100644 --- a/frontend/src/Indexer/Editor/Delete/DeleteIndexerModalContent.js +++ b/frontend/src/Indexer/Editor/Delete/DeleteIndexerModalContent.js @@ -12,7 +12,7 @@ import styles from './DeleteIndexerModalContent.css'; class DeleteIndexerModalContent extends Component { onDeleteMovieConfirmed = () => { this.props.onDeleteSelectedPress(); - } + }; // // Render diff --git a/frontend/src/Indexer/Editor/IndexerEditorFooter.js b/frontend/src/Indexer/Editor/IndexerEditorFooter.js index 5c59a1591..1818eae72 100644 --- a/frontend/src/Indexer/Editor/IndexerEditorFooter.js +++ b/frontend/src/Indexer/Editor/IndexerEditorFooter.js @@ -59,7 +59,7 @@ class IndexerEditorFooter extends Component { default: this.props.onSaveSelected({ [name]: value }); } - } + }; onApplyTagsPress = (tags, applyTags) => { this.setState({ @@ -71,23 +71,23 @@ class IndexerEditorFooter extends Component { tags, applyTags }); - } + }; onDeleteSelectedPress = () => { this.setState({ isDeleteMovieModalOpen: true }); - } + }; onDeleteMovieModalClose = () => { this.setState({ isDeleteMovieModalOpen: false }); - } + }; onTagsPress = () => { this.setState({ isTagsModalOpen: true }); - } + }; onTagsModalClose = () => { this.setState({ isTagsModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/Indexer/Editor/Tags/TagsModalContent.js b/frontend/src/Indexer/Editor/Tags/TagsModalContent.js index 0ea26e968..eaa9c5b6a 100644 --- a/frontend/src/Indexer/Editor/Tags/TagsModalContent.js +++ b/frontend/src/Indexer/Editor/Tags/TagsModalContent.js @@ -34,7 +34,7 @@ class TagsModalContent extends Component { onInputChange = ({ name, value }) => { this.setState({ [name]: value }); - } + }; onApplyTagsPress = () => { const { @@ -43,7 +43,7 @@ class TagsModalContent extends Component { } = this.state; this.props.onApplyTagsPress(tags, applyTags); - } + }; // // Render diff --git a/frontend/src/Indexer/Index/IndexerIndex.js b/frontend/src/Indexer/Index/IndexerIndex.js index 883a34f55..e895f3357 100644 --- a/frontend/src/Indexer/Index/IndexerIndex.js +++ b/frontend/src/Indexer/Index/IndexerIndex.js @@ -98,14 +98,14 @@ class IndexerIndex extends Component { setScrollerRef = (ref) => { this.setState({ scroller: ref }); - } + }; getSelectedIds = () => { if (this.state.allUnselected) { return []; } return getSelectedIds(this.state.selectedState); - } + }; setSelectedState() { const { @@ -191,18 +191,18 @@ class IndexerIndex extends Component { onAddIndexerPress = () => { this.setState({ isAddIndexerModalOpen: true }); - } + }; onAddIndexerModalClose = ({ indexerSelected = false } = {}) => { this.setState({ isAddIndexerModalOpen: false, isEditIndexerModalOpen: indexerSelected }); - } + }; onEditIndexerModalClose = () => { this.setState({ isEditIndexerModalOpen: false }); - } + }; onMovieEditorTogglePress = () => { if (this.state.isMovieEditorActive) { @@ -212,11 +212,11 @@ class IndexerIndex extends Component { newState.isMovieEditorActive = true; this.setState(newState); } - } + }; onJumpBarItemPress = (jumpToCharacter) => { this.setState({ jumpToCharacter }); - } + }; onKeyUp = (event) => { const jumpBarItems = this.state.jumpBarItems.order; @@ -228,28 +228,28 @@ class IndexerIndex extends Component { this.setState({ jumpToCharacter: jumpBarItems[jumpBarItems.length - 1] }); } } - } + }; onSelectAllChange = ({ value }) => { this.setState(selectAll(this.state.selectedState, value)); - } + }; onSelectAllPress = () => { this.onSelectAllChange({ value: !this.state.allSelected }); - } + }; onSelectedChange = ({ id, value, shiftKey = false }) => { this.setState((state) => { return toggleSelected(state, this.props.items, id, value, shiftKey); }); - } + }; onSaveSelected = (changes) => { this.props.onSaveSelected({ indexerIds: this.getSelectedIds(), ...changes }); - } + }; // // Render diff --git a/frontend/src/Indexer/Index/IndexerIndexConnector.js b/frontend/src/Indexer/Index/IndexerIndexConnector.js index ef3f0f091..e31041c66 100644 --- a/frontend/src/Indexer/Index/IndexerIndexConnector.js +++ b/frontend/src/Indexer/Index/IndexerIndexConnector.js @@ -57,11 +57,11 @@ class IndexerIndexConnector extends Component { onSaveSelected = (payload) => { this.props.dispatchSaveIndexerEditor(payload); - } + }; onScroll = ({ scrollTop }) => { scrollPositions.movieIndex = scrollTop; - } + }; // // Render diff --git a/frontend/src/Indexer/Index/Table/IndexerIndexActionsCell.js b/frontend/src/Indexer/Index/Table/IndexerIndexActionsCell.js index 1a649235f..3450b74a0 100644 --- a/frontend/src/Indexer/Index/Table/IndexerIndexActionsCell.js +++ b/frontend/src/Indexer/Index/Table/IndexerIndexActionsCell.js @@ -27,22 +27,22 @@ class IndexerIndexActionsCell extends Component { onEditMoviePress = () => { this.setState({ isEditMovieModalOpen: true }); - } + }; onEditMovieModalClose = () => { this.setState({ isEditMovieModalOpen: false }); - } + }; onDeleteMoviePress = () => { this.setState({ isEditMovieModalOpen: false, isDeleteMovieModalOpen: true }); - } + }; onDeleteMovieModalClose = () => { this.setState({ isDeleteMovieModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/Indexer/Index/Table/IndexerIndexHeader.js b/frontend/src/Indexer/Index/Table/IndexerIndexHeader.js index 5dacee870..557f1c4ca 100644 --- a/frontend/src/Indexer/Index/Table/IndexerIndexHeader.js +++ b/frontend/src/Indexer/Index/Table/IndexerIndexHeader.js @@ -27,11 +27,11 @@ class IndexerIndexHeader extends Component { onTableOptionsPress = () => { this.setState({ isTableOptionsModalOpen: true }); - } + }; onTableOptionsModalClose = () => { this.setState({ isTableOptionsModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/Indexer/Index/Table/IndexerIndexRow.js b/frontend/src/Indexer/Index/Table/IndexerIndexRow.js index 972289214..9233a10fa 100644 --- a/frontend/src/Indexer/Index/Table/IndexerIndexRow.js +++ b/frontend/src/Indexer/Index/Table/IndexerIndexRow.js @@ -34,35 +34,35 @@ class IndexerIndexRow extends Component { onEditIndexerPress = () => { this.setState({ isEditIndexerModalOpen: true }); - } + }; onIndexerInfoPress = () => { this.setState({ isIndexerInfoModalOpen: true }); - } + }; onEditIndexerModalClose = () => { this.setState({ isEditIndexerModalOpen: false }); - } + }; onIndexerInfoModalClose = () => { this.setState({ isIndexerInfoModalOpen: false }); - } + }; onDeleteMoviePress = () => { this.setState({ isEditIndexerModalOpen: false, isDeleteMovieModalOpen: true }); - } + }; onDeleteMovieModalClose = () => { this.setState({ isDeleteMovieModalOpen: false }); - } + }; onUseSceneNumberingChange = () => { // Mock handler to satisfy `onChange` being required for `CheckInput`. // - } + }; // // Render diff --git a/frontend/src/Indexer/Index/Table/IndexerIndexTable.js b/frontend/src/Indexer/Index/Table/IndexerIndexTable.js index 79e733b65..51701a8f3 100644 --- a/frontend/src/Indexer/Index/Table/IndexerIndexTable.js +++ b/frontend/src/Indexer/Index/Table/IndexerIndexTable.js @@ -70,7 +70,7 @@ class IndexerIndexTable extends Component { /> </VirtualTableRow> ); - } + }; // // Render diff --git a/frontend/src/Indexer/Index/Table/IndexerIndexTableOptions.js b/frontend/src/Indexer/Index/Table/IndexerIndexTableOptions.js index ee52f454f..ce75eeb86 100644 --- a/frontend/src/Indexer/Index/Table/IndexerIndexTableOptions.js +++ b/frontend/src/Indexer/Index/Table/IndexerIndexTableOptions.js @@ -43,7 +43,7 @@ class IndexerIndexTableOptions extends Component { } }); }); - } + }; // // Render diff --git a/frontend/src/Search/QueryParameterModal.js b/frontend/src/Search/QueryParameterModal.js index 237d5a6e6..aede4a251 100644 --- a/frontend/src/Search/QueryParameterModal.js +++ b/frontend/src/Search/QueryParameterModal.js @@ -68,7 +68,7 @@ class QueryParameterModal extends Component { onInputSelectionChange = (selectionStart, selectionEnd) => { this._selectionStart = selectionStart; this._selectionEnd = selectionEnd; - } + }; onOptionPress = ({ isFullFilename, tokenValue }) => { const { @@ -96,12 +96,12 @@ class QueryParameterModal extends Component { this._selectionStart = newValue.length - 1; this._selectionEnd = newValue.length - 1; } - } + }; onInputChange = ({ name, value }) => { this.props.onSearchInputChange({ value: '' }); this.props.onInputChange({ name, value }); - } + }; // // Render diff --git a/frontend/src/Search/QueryParameterOption.js b/frontend/src/Search/QueryParameterOption.js index 6a31a1efa..a0b4724a9 100644 --- a/frontend/src/Search/QueryParameterOption.js +++ b/frontend/src/Search/QueryParameterOption.js @@ -24,7 +24,7 @@ class QueryParameterOption extends Component { tokenValue = tokenValue.replace(/ /g, tokenSeparator); onPress({ isFullFilename, tokenValue }); - } + }; // // Render diff --git a/frontend/src/Search/SearchFooter.js b/frontend/src/Search/SearchFooter.js index f17fc8dca..cd3897f33 100644 --- a/frontend/src/Search/SearchFooter.js +++ b/frontend/src/Search/SearchFooter.js @@ -108,19 +108,19 @@ class SearchFooter extends Component { }, isQueryParameterModalOpen: true }); - } + }; onQueryParameterModalClose = () => { this.setState({ isQueryParameterModalOpen: false }); - } + }; onSearchPress = () => { this.props.onSearchPress(this.state.searchQuery, this.state.searchIndexerIds, this.state.searchCategories, this.state.searchType); - } + }; onSearchInputChange = ({ value }) => { this.setState({ searchQuery: value }); - } + }; // // Render diff --git a/frontend/src/Search/SearchFooterConnector.js b/frontend/src/Search/SearchFooterConnector.js index 0478ec329..efbe6b3c4 100644 --- a/frontend/src/Search/SearchFooterConnector.js +++ b/frontend/src/Search/SearchFooterConnector.js @@ -37,7 +37,7 @@ class SearchFooterConnector extends Component { onInputChange = ({ name, value }) => { this.props.setSearchDefault({ [name]: value }); - } + }; // // Render diff --git a/frontend/src/Search/SearchIndex.js b/frontend/src/Search/SearchIndex.js index d629224de..06479972b 100644 --- a/frontend/src/Search/SearchIndex.js +++ b/frontend/src/Search/SearchIndex.js @@ -86,14 +86,14 @@ class SearchIndex extends Component { setScrollerRef = (ref) => { this.setState({ scroller: ref }); - } + }; getSelectedIds = () => { if (this.state.allUnselected) { return []; } return getSelectedIds(this.state.selectedState, { parseIds: false }); - } + }; setSelectedState() { const { @@ -179,32 +179,32 @@ class SearchIndex extends Component { onAddIndexerPress = () => { this.setState({ isAddIndexerModalOpen: true }); - } + }; onAddIndexerModalClose = ({ indexerSelected = false } = {}) => { this.setState({ isAddIndexerModalOpen: false, isEditIndexerModalOpen: indexerSelected }); - } + }; onEditIndexerModalClose = () => { this.setState({ isEditIndexerModalOpen: false }); - } + }; onJumpBarItemPress = (jumpToCharacter) => { this.setState({ jumpToCharacter }); - } + }; onSearchPress = (query, indexerIds, categories, type) => { this.props.onSearchPress({ query, indexerIds, categories, type }); - } + }; onBulkGrabPress = () => { const selectedIds = this.getSelectedIds(); const result = _.filter(this.props.items, (release) => _.indexOf(selectedIds, release.guid) !== -1); this.props.onBulkGrabPress(result); - } + }; onKeyUp = (event) => { const jumpBarItems = this.state.jumpBarItems.order; @@ -216,21 +216,21 @@ class SearchIndex extends Component { this.setState({ jumpToCharacter: jumpBarItems[jumpBarItems.length - 1] }); } } - } + }; onSelectAllChange = ({ value }) => { this.setState(selectAll(this.state.selectedState, value)); - } + }; onSelectAllPress = () => { this.onSelectAllChange({ value: !this.state.allSelected }); - } + }; onSelectedChange = ({ id, value, shiftKey = false }) => { this.setState((state) => { return toggleSelected(state, this.props.items, id, value, shiftKey); }); - } + }; // // Render diff --git a/frontend/src/Search/SearchIndexConnector.js b/frontend/src/Search/SearchIndexConnector.js index a32dd47c0..efa0dc563 100644 --- a/frontend/src/Search/SearchIndexConnector.js +++ b/frontend/src/Search/SearchIndexConnector.js @@ -69,7 +69,7 @@ class SearchIndexConnector extends Component { onScroll = ({ scrollTop }) => { scrollPositions.movieIndex = scrollTop; - } + }; // // Render diff --git a/frontend/src/Search/Table/SearchIndexHeader.js b/frontend/src/Search/Table/SearchIndexHeader.js index f69cd5a48..6b91adb45 100644 --- a/frontend/src/Search/Table/SearchIndexHeader.js +++ b/frontend/src/Search/Table/SearchIndexHeader.js @@ -26,11 +26,11 @@ class SearchIndexHeader extends Component { onTableOptionsPress = () => { this.setState({ isTableOptionsModalOpen: true }); - } + }; onTableOptionsModalClose = () => { this.setState({ isTableOptionsModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/Search/Table/SearchIndexRow.js b/frontend/src/Search/Table/SearchIndexRow.js index bd508d2e5..f562bf8f3 100644 --- a/frontend/src/Search/Table/SearchIndexRow.js +++ b/frontend/src/Search/Table/SearchIndexRow.js @@ -69,7 +69,7 @@ class SearchIndexRow extends Component { guid, indexerId }); - } + }; // // Render diff --git a/frontend/src/Search/Table/SearchIndexTable.js b/frontend/src/Search/Table/SearchIndexTable.js index b2a6973fd..7f1f44118 100644 --- a/frontend/src/Search/Table/SearchIndexTable.js +++ b/frontend/src/Search/Table/SearchIndexTable.js @@ -74,7 +74,7 @@ class SearchIndexTable extends Component { /> </VirtualTableRow> ); - } + }; // // Render diff --git a/frontend/src/Settings/Applications/Applications/AddApplicationItem.js b/frontend/src/Settings/Applications/Applications/AddApplicationItem.js index ec4512f51..bb0053824 100644 --- a/frontend/src/Settings/Applications/Applications/AddApplicationItem.js +++ b/frontend/src/Settings/Applications/Applications/AddApplicationItem.js @@ -20,7 +20,7 @@ class AddApplicationItem extends Component { } = this.props; this.props.onApplicationSelect({ implementation }); - } + }; // // Render diff --git a/frontend/src/Settings/Applications/Applications/AddApplicationModalContentConnector.js b/frontend/src/Settings/Applications/Applications/AddApplicationModalContentConnector.js index a48ba8ac4..41076d4fe 100644 --- a/frontend/src/Settings/Applications/Applications/AddApplicationModalContentConnector.js +++ b/frontend/src/Settings/Applications/Applications/AddApplicationModalContentConnector.js @@ -46,7 +46,7 @@ class AddApplicationModalContentConnector extends Component { onApplicationSelect = ({ implementation, name }) => { this.props.selectApplicationSchema({ implementation, presetName: name }); this.props.onModalClose({ applicationSelected: true }); - } + }; // // Render diff --git a/frontend/src/Settings/Applications/Applications/AddApplicationPresetMenuItem.js b/frontend/src/Settings/Applications/Applications/AddApplicationPresetMenuItem.js index b4bad3014..9974f7132 100644 --- a/frontend/src/Settings/Applications/Applications/AddApplicationPresetMenuItem.js +++ b/frontend/src/Settings/Applications/Applications/AddApplicationPresetMenuItem.js @@ -17,7 +17,7 @@ class AddApplicationPresetMenuItem extends Component { name, implementation }); - } + }; // // Render diff --git a/frontend/src/Settings/Applications/Applications/Application.js b/frontend/src/Settings/Applications/Applications/Application.js index 2d8280617..d7ebd56e1 100644 --- a/frontend/src/Settings/Applications/Applications/Application.js +++ b/frontend/src/Settings/Applications/Applications/Application.js @@ -27,26 +27,26 @@ class Application extends Component { onEditApplicationPress = () => { this.setState({ isEditApplicationModalOpen: true }); - } + }; onEditApplicationModalClose = () => { this.setState({ isEditApplicationModalOpen: false }); - } + }; onDeleteApplicationPress = () => { this.setState({ isEditApplicationModalOpen: false, isDeleteApplicationModalOpen: true }); - } + }; onDeleteApplicationModalClose= () => { this.setState({ isDeleteApplicationModalOpen: false }); - } + }; onConfirmDeleteApplication = () => { this.props.onConfirmDeleteApplication(this.props.id); - } + }; // // Render diff --git a/frontend/src/Settings/Applications/Applications/Applications.js b/frontend/src/Settings/Applications/Applications/Applications.js index a4fc7d68e..83047f602 100644 --- a/frontend/src/Settings/Applications/Applications/Applications.js +++ b/frontend/src/Settings/Applications/Applications/Applications.js @@ -30,18 +30,18 @@ class Applications extends Component { onAddApplicationPress = () => { this.setState({ isAddApplicationModalOpen: true }); - } + }; onAddApplicationModalClose = ({ applicationSelected = false } = {}) => { this.setState({ isAddApplicationModalOpen: false, isEditApplicationModalOpen: applicationSelected }); - } + }; onEditApplicationModalClose = () => { this.setState({ isEditApplicationModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/Settings/Applications/Applications/ApplicationsConnector.js b/frontend/src/Settings/Applications/Applications/ApplicationsConnector.js index 062a7f8e8..a984299f0 100644 --- a/frontend/src/Settings/Applications/Applications/ApplicationsConnector.js +++ b/frontend/src/Settings/Applications/Applications/ApplicationsConnector.js @@ -33,7 +33,7 @@ class ApplicationsConnector extends Component { onConfirmDeleteApplication = (id) => { this.props.deleteApplication({ id }); - } + }; // // Render diff --git a/frontend/src/Settings/Applications/Applications/EditApplicationModalConnector.js b/frontend/src/Settings/Applications/Applications/EditApplicationModalConnector.js index 2a217398f..8858ba00b 100644 --- a/frontend/src/Settings/Applications/Applications/EditApplicationModalConnector.js +++ b/frontend/src/Settings/Applications/Applications/EditApplicationModalConnector.js @@ -33,7 +33,7 @@ class EditApplicationModalConnector extends Component { this.props.dispatchCancelTestApplication(); this.props.dispatchCancelSaveApplication(); this.props.onModalClose(); - } + }; // // Render diff --git a/frontend/src/Settings/Applications/Applications/EditApplicationModalContentConnector.js b/frontend/src/Settings/Applications/Applications/EditApplicationModalContentConnector.js index a3b3e6560..859afc1de 100644 --- a/frontend/src/Settings/Applications/Applications/EditApplicationModalContentConnector.js +++ b/frontend/src/Settings/Applications/Applications/EditApplicationModalContentConnector.js @@ -42,19 +42,19 @@ class EditApplicationModalContentConnector extends Component { onInputChange = ({ name, value }) => { this.props.setApplicationValue({ name, value }); - } + }; onFieldChange = ({ name, value }) => { this.props.setApplicationFieldValue({ name, value }); - } + }; onSavePress = () => { this.props.saveApplication({ id: this.props.id }); - } + }; onTestPress = () => { this.props.testApplication({ id: this.props.id }); - } + }; // // Render diff --git a/frontend/src/Settings/Development/DevelopmentSettingsConnector.js b/frontend/src/Settings/Development/DevelopmentSettingsConnector.js index 974cd446a..f93701e49 100644 --- a/frontend/src/Settings/Development/DevelopmentSettingsConnector.js +++ b/frontend/src/Settings/Development/DevelopmentSettingsConnector.js @@ -47,11 +47,11 @@ class DevelopmentSettingsConnector extends Component { onInputChange = ({ name, value }) => { this.props.setDevelopmentSettingsValue({ name, value }); - } + }; onSavePress = () => { this.props.saveDevelopmentSettings(); - } + }; // // Render diff --git a/frontend/src/Settings/DownloadClients/DownloadClientSettings.js b/frontend/src/Settings/DownloadClients/DownloadClientSettings.js index 8de472a6a..3e060aa5d 100644 --- a/frontend/src/Settings/DownloadClients/DownloadClientSettings.js +++ b/frontend/src/Settings/DownloadClients/DownloadClientSettings.js @@ -30,17 +30,17 @@ class DownloadClientSettings extends Component { onChildMounted = (saveCallback) => { this._saveCallback = saveCallback; - } + }; onChildStateChange = (payload) => { this.setState(payload); - } + }; onSavePress = () => { if (this._saveCallback) { this._saveCallback(); } - } + }; // // Render diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/AddDownloadClientItem.js b/frontend/src/Settings/DownloadClients/DownloadClients/AddDownloadClientItem.js index 235356a5f..0b1113022 100644 --- a/frontend/src/Settings/DownloadClients/DownloadClients/AddDownloadClientItem.js +++ b/frontend/src/Settings/DownloadClients/DownloadClients/AddDownloadClientItem.js @@ -20,7 +20,7 @@ class AddDownloadClientItem extends Component { } = this.props; this.props.onDownloadClientSelect({ implementation }); - } + }; // // Render diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/AddDownloadClientModalContentConnector.js b/frontend/src/Settings/DownloadClients/DownloadClients/AddDownloadClientModalContentConnector.js index 99d5c4f19..ffae3eee9 100644 --- a/frontend/src/Settings/DownloadClients/DownloadClients/AddDownloadClientModalContentConnector.js +++ b/frontend/src/Settings/DownloadClients/DownloadClients/AddDownloadClientModalContentConnector.js @@ -51,7 +51,7 @@ class AddDownloadClientModalContentConnector extends Component { onDownloadClientSelect = ({ implementation }) => { this.props.selectDownloadClientSchema({ implementation }); this.props.onModalClose({ downloadClientSelected: true }); - } + }; // // Render diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/AddDownloadClientPresetMenuItem.js b/frontend/src/Settings/DownloadClients/DownloadClients/AddDownloadClientPresetMenuItem.js index f356f8140..309c817b0 100644 --- a/frontend/src/Settings/DownloadClients/DownloadClients/AddDownloadClientPresetMenuItem.js +++ b/frontend/src/Settings/DownloadClients/DownloadClients/AddDownloadClientPresetMenuItem.js @@ -17,7 +17,7 @@ class AddDownloadClientPresetMenuItem extends Component { name, implementation }); - } + }; // // Render diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/DownloadClient.js b/frontend/src/Settings/DownloadClients/DownloadClients/DownloadClient.js index 98fce6319..8cea557a9 100644 --- a/frontend/src/Settings/DownloadClients/DownloadClients/DownloadClient.js +++ b/frontend/src/Settings/DownloadClients/DownloadClients/DownloadClient.js @@ -27,26 +27,26 @@ class DownloadClient extends Component { onEditDownloadClientPress = () => { this.setState({ isEditDownloadClientModalOpen: true }); - } + }; onEditDownloadClientModalClose = () => { this.setState({ isEditDownloadClientModalOpen: false }); - } + }; onDeleteDownloadClientPress = () => { this.setState({ isEditDownloadClientModalOpen: false, isDeleteDownloadClientModalOpen: true }); - } + }; onDeleteDownloadClientModalClose= () => { this.setState({ isDeleteDownloadClientModalOpen: false }); - } + }; onConfirmDeleteDownloadClient = () => { this.props.onConfirmDeleteDownloadClient(this.props.id); - } + }; // // Render diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/DownloadClients.js b/frontend/src/Settings/DownloadClients/DownloadClients/DownloadClients.js index 52f211f4a..640d56a89 100644 --- a/frontend/src/Settings/DownloadClients/DownloadClients/DownloadClients.js +++ b/frontend/src/Settings/DownloadClients/DownloadClients/DownloadClients.js @@ -30,18 +30,18 @@ class DownloadClients extends Component { onAddDownloadClientPress = () => { this.setState({ isAddDownloadClientModalOpen: true }); - } + }; onAddDownloadClientModalClose = ({ downloadClientSelected = false } = {}) => { this.setState({ isAddDownloadClientModalOpen: false, isEditDownloadClientModalOpen: downloadClientSelected }); - } + }; onEditDownloadClientModalClose = () => { this.setState({ isEditDownloadClientModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/DownloadClientsConnector.js b/frontend/src/Settings/DownloadClients/DownloadClients/DownloadClientsConnector.js index ed8ddffc9..9cba9c1cc 100644 --- a/frontend/src/Settings/DownloadClients/DownloadClients/DownloadClientsConnector.js +++ b/frontend/src/Settings/DownloadClients/DownloadClients/DownloadClientsConnector.js @@ -33,7 +33,7 @@ class DownloadClientsConnector extends Component { onConfirmDeleteDownloadClient = (id) => { this.props.deleteDownloadClient({ id }); - } + }; // // Render diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalConnector.js b/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalConnector.js index e6b06974d..7948ef120 100644 --- a/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalConnector.js +++ b/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalConnector.js @@ -33,7 +33,7 @@ class EditDownloadClientModalConnector extends Component { this.props.dispatchCancelTestDownloadClient(); this.props.dispatchCancelSaveDownloadClient(); this.props.onModalClose(); - } + }; // // Render diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContentConnector.js b/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContentConnector.js index 864d83cfe..f2d4ad6ff 100644 --- a/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContentConnector.js +++ b/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContentConnector.js @@ -42,19 +42,19 @@ class EditDownloadClientModalContentConnector extends Component { onInputChange = ({ name, value }) => { this.props.setDownloadClientValue({ name, value }); - } + }; onFieldChange = ({ name, value }) => { this.props.setDownloadClientFieldValue({ name, value }); - } + }; onSavePress = () => { this.props.saveDownloadClient({ id: this.props.id }); - } + }; onTestPress = () => { this.props.testDownloadClient({ id: this.props.id }); - } + }; // // Render diff --git a/frontend/src/Settings/General/GeneralSettings.js b/frontend/src/Settings/General/GeneralSettings.js index 546af3ac7..38bb08f75 100644 --- a/frontend/src/Settings/General/GeneralSettings.js +++ b/frontend/src/Settings/General/GeneralSettings.js @@ -82,11 +82,11 @@ class GeneralSettings extends Component { onConfirmRestart = () => { this.setState({ isRestartRequiredModalOpen: false }); this.props.onConfirmRestart(); - } + }; onCloseRestartRequiredModalOpen = () => { this.setState({ isRestartRequiredModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/Settings/General/GeneralSettingsConnector.js b/frontend/src/Settings/General/GeneralSettingsConnector.js index f1a688175..18b23a950 100644 --- a/frontend/src/Settings/General/GeneralSettingsConnector.js +++ b/frontend/src/Settings/General/GeneralSettingsConnector.js @@ -67,19 +67,19 @@ class GeneralSettingsConnector extends Component { onInputChange = ({ name, value }) => { this.props.setGeneralSettingsValue({ name, value }); - } + }; onSavePress = () => { this.props.saveGeneralSettings(); - } + }; onConfirmResetApiKey = () => { this.props.executeCommand({ name: commandNames.RESET_API_KEY }); - } + }; onConfirmRestart = () => { this.props.restart(); - } + }; // // Render diff --git a/frontend/src/Settings/General/SecuritySettings.js b/frontend/src/Settings/General/SecuritySettings.js index ecb4c9671..d2589b6b1 100644 --- a/frontend/src/Settings/General/SecuritySettings.js +++ b/frontend/src/Settings/General/SecuritySettings.js @@ -41,20 +41,20 @@ class SecuritySettings extends Component { onApikeyFocus = (event) => { event.target.select(); - } + }; onResetApiKeyPress = () => { this.setState({ isConfirmApiKeyResetModalOpen: true }); - } + }; onConfirmResetApiKey = () => { this.setState({ isConfirmApiKeyResetModalOpen: false }); this.props.onConfirmResetApiKey(); - } + }; onCloseResetApiKeyModal = () => { this.setState({ isConfirmApiKeyResetModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyItem.js b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyItem.js index 73e6454a9..ff238c915 100644 --- a/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyItem.js +++ b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyItem.js @@ -20,7 +20,7 @@ class AddIndexerProxyItem extends Component { } = this.props; this.props.onIndexerProxySelect({ implementation }); - } + }; // // Render diff --git a/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContentConnector.js b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContentConnector.js index cccafe922..1fac45c1d 100644 --- a/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContentConnector.js +++ b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyModalContentConnector.js @@ -46,7 +46,7 @@ class AddIndexerProxyModalContentConnector extends Component { onIndexerProxySelect = ({ implementation, name }) => { this.props.selectIndexerProxySchema({ implementation, presetName: name }); this.props.onModalClose({ indexerProxySelected: true }); - } + }; // // Render diff --git a/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyPresetMenuItem.js b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyPresetMenuItem.js index 52ee40c10..166457873 100644 --- a/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyPresetMenuItem.js +++ b/frontend/src/Settings/Indexers/IndexerProxies/AddIndexerProxyPresetMenuItem.js @@ -17,7 +17,7 @@ class AddIndexerProxyPresetMenuItem extends Component { name, implementation }); - } + }; // // Render diff --git a/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalConnector.js b/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalConnector.js index a1a6563e7..0df91cb83 100644 --- a/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalConnector.js +++ b/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalConnector.js @@ -33,7 +33,7 @@ class EditIndexerProxyModalConnector extends Component { this.props.dispatchCancelTestIndexerProxy(); this.props.dispatchCancelSaveIndexerProxy(); this.props.onModalClose(); - } + }; // // Render diff --git a/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalContentConnector.js b/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalContentConnector.js index 01db7709b..ca5bfd43f 100644 --- a/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalContentConnector.js +++ b/frontend/src/Settings/Indexers/IndexerProxies/EditIndexerProxyModalContentConnector.js @@ -42,19 +42,19 @@ class EditIndexerProxyModalContentConnector extends Component { onInputChange = ({ name, value }) => { this.props.setIndexerProxyValue({ name, value }); - } + }; onFieldChange = ({ name, value }) => { this.props.setIndexerProxyFieldValue({ name, value }); - } + }; onSavePress = () => { this.props.saveIndexerProxy({ id: this.props.id }); - } + }; onTestPress = () => { this.props.testIndexerProxy({ id: this.props.id }); - } + }; // // Render diff --git a/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.js b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.js index b51b8116f..7ae537da1 100644 --- a/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.js +++ b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.js @@ -30,18 +30,18 @@ class IndexerProxies extends Component { onAddIndexerProxyPress = () => { this.setState({ isAddIndexerProxyModalOpen: true }); - } + }; onAddIndexerProxyModalClose = ({ indexerProxySelected = false } = {}) => { this.setState({ isAddIndexerProxyModalOpen: false, isEditIndexerProxyModalOpen: indexerProxySelected }); - } + }; onEditIndexerProxyModalClose = () => { this.setState({ isEditIndexerProxyModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxiesConnector.js b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxiesConnector.js index 94258079a..9d2188a7c 100644 --- a/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxiesConnector.js +++ b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxiesConnector.js @@ -42,7 +42,7 @@ class IndexerProxiesConnector extends Component { onConfirmDeleteIndexerProxy = (id) => { this.props.deleteIndexerProxy({ id }); - } + }; // // Render diff --git a/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxy.js b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxy.js index 18c96144a..4ac3cfc61 100644 --- a/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxy.js +++ b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxy.js @@ -29,26 +29,26 @@ class IndexerProxy extends Component { onEditIndexerProxyPress = () => { this.setState({ isEditIndexerProxyModalOpen: true }); - } + }; onEditIndexerProxyModalClose = () => { this.setState({ isEditIndexerProxyModalOpen: false }); - } + }; onDeleteIndexerProxyPress = () => { this.setState({ isEditIndexerProxyModalOpen: false, isDeleteIndexerProxyModalOpen: true }); - } + }; onDeleteIndexerProxyModalClose= () => { this.setState({ isDeleteIndexerProxyModalOpen: false }); - } + }; onConfirmDeleteIndexerProxy = () => { this.props.onConfirmDeleteIndexerProxy(this.props.id); - } + }; // // Render diff --git a/frontend/src/Settings/Notifications/Notifications/AddNotificationItem.js b/frontend/src/Settings/Notifications/Notifications/AddNotificationItem.js index 0ac3d6634..f6e6affc0 100644 --- a/frontend/src/Settings/Notifications/Notifications/AddNotificationItem.js +++ b/frontend/src/Settings/Notifications/Notifications/AddNotificationItem.js @@ -20,7 +20,7 @@ class AddNotificationItem extends Component { } = this.props; this.props.onNotificationSelect({ implementation }); - } + }; // // Render diff --git a/frontend/src/Settings/Notifications/Notifications/AddNotificationModalContentConnector.js b/frontend/src/Settings/Notifications/Notifications/AddNotificationModalContentConnector.js index abeb5e2ac..749038688 100644 --- a/frontend/src/Settings/Notifications/Notifications/AddNotificationModalContentConnector.js +++ b/frontend/src/Settings/Notifications/Notifications/AddNotificationModalContentConnector.js @@ -46,7 +46,7 @@ class AddNotificationModalContentConnector extends Component { onNotificationSelect = ({ implementation, name }) => { this.props.selectNotificationSchema({ implementation, presetName: name }); this.props.onModalClose({ notificationSelected: true }); - } + }; // // Render diff --git a/frontend/src/Settings/Notifications/Notifications/AddNotificationPresetMenuItem.js b/frontend/src/Settings/Notifications/Notifications/AddNotificationPresetMenuItem.js index e4df85b8a..dd325906f 100644 --- a/frontend/src/Settings/Notifications/Notifications/AddNotificationPresetMenuItem.js +++ b/frontend/src/Settings/Notifications/Notifications/AddNotificationPresetMenuItem.js @@ -17,7 +17,7 @@ class AddNotificationPresetMenuItem extends Component { name, implementation }); - } + }; // // Render diff --git a/frontend/src/Settings/Notifications/Notifications/EditNotificationModalConnector.js b/frontend/src/Settings/Notifications/Notifications/EditNotificationModalConnector.js index 7a9042946..91070a979 100644 --- a/frontend/src/Settings/Notifications/Notifications/EditNotificationModalConnector.js +++ b/frontend/src/Settings/Notifications/Notifications/EditNotificationModalConnector.js @@ -33,7 +33,7 @@ class EditNotificationModalConnector extends Component { this.props.dispatchCancelTestNotification(); this.props.dispatchCancelSaveNotification(); this.props.onModalClose(); - } + }; // // Render diff --git a/frontend/src/Settings/Notifications/Notifications/EditNotificationModalContentConnector.js b/frontend/src/Settings/Notifications/Notifications/EditNotificationModalContentConnector.js index 504f18663..3d6e9378e 100644 --- a/frontend/src/Settings/Notifications/Notifications/EditNotificationModalContentConnector.js +++ b/frontend/src/Settings/Notifications/Notifications/EditNotificationModalContentConnector.js @@ -42,19 +42,19 @@ class EditNotificationModalContentConnector extends Component { onInputChange = ({ name, value }) => { this.props.setNotificationValue({ name, value }); - } + }; onFieldChange = ({ name, value }) => { this.props.setNotificationFieldValue({ name, value }); - } + }; onSavePress = () => { this.props.saveNotification({ id: this.props.id }); - } + }; onTestPress = () => { this.props.testNotification({ id: this.props.id }); - } + }; // // Render diff --git a/frontend/src/Settings/Notifications/Notifications/Notification.js b/frontend/src/Settings/Notifications/Notifications/Notification.js index eaca8b834..e356024c4 100644 --- a/frontend/src/Settings/Notifications/Notifications/Notification.js +++ b/frontend/src/Settings/Notifications/Notifications/Notification.js @@ -27,26 +27,26 @@ class Notification extends Component { onEditNotificationPress = () => { this.setState({ isEditNotificationModalOpen: true }); - } + }; onEditNotificationModalClose = () => { this.setState({ isEditNotificationModalOpen: false }); - } + }; onDeleteNotificationPress = () => { this.setState({ isEditNotificationModalOpen: false, isDeleteNotificationModalOpen: true }); - } + }; onDeleteNotificationModalClose= () => { this.setState({ isDeleteNotificationModalOpen: false }); - } + }; onConfirmDeleteNotification = () => { this.props.onConfirmDeleteNotification(this.props.id); - } + }; // // Render diff --git a/frontend/src/Settings/Notifications/Notifications/Notifications.js b/frontend/src/Settings/Notifications/Notifications/Notifications.js index d740cb647..8b3bfbb36 100644 --- a/frontend/src/Settings/Notifications/Notifications/Notifications.js +++ b/frontend/src/Settings/Notifications/Notifications/Notifications.js @@ -30,18 +30,18 @@ class Notifications extends Component { onAddNotificationPress = () => { this.setState({ isAddNotificationModalOpen: true }); - } + }; onAddNotificationModalClose = ({ notificationSelected = false } = {}) => { this.setState({ isAddNotificationModalOpen: false, isEditNotificationModalOpen: notificationSelected }); - } + }; onEditNotificationModalClose = () => { this.setState({ isEditNotificationModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/Settings/Notifications/Notifications/NotificationsConnector.js b/frontend/src/Settings/Notifications/Notifications/NotificationsConnector.js index 6191d76f8..83ee6c697 100644 --- a/frontend/src/Settings/Notifications/Notifications/NotificationsConnector.js +++ b/frontend/src/Settings/Notifications/Notifications/NotificationsConnector.js @@ -33,7 +33,7 @@ class NotificationsConnector extends Component { onConfirmDeleteNotification = (id) => { this.props.deleteNotification({ id }); - } + }; // // Render diff --git a/frontend/src/Settings/Profiles/App/AppProfile.js b/frontend/src/Settings/Profiles/App/AppProfile.js index e1146986d..546006ff5 100644 --- a/frontend/src/Settings/Profiles/App/AppProfile.js +++ b/frontend/src/Settings/Profiles/App/AppProfile.js @@ -28,26 +28,26 @@ class AppProfile extends Component { onEditAppProfilePress = () => { this.setState({ isEditAppProfileModalOpen: true }); - } + }; onEditAppProfileModalClose = () => { this.setState({ isEditAppProfileModalOpen: false }); - } + }; onDeleteAppProfilePress = () => { this.setState({ isEditAppProfileModalOpen: false, isDeleteAppProfileModalOpen: true }); - } + }; onDeleteAppProfileModalClose = () => { this.setState({ isDeleteAppProfileModalOpen: false }); - } + }; onConfirmDeleteAppProfile = () => { this.props.onConfirmDeleteAppProfile(this.props.id); - } + }; onCloneAppProfilePress = () => { const { @@ -56,7 +56,7 @@ class AppProfile extends Component { } = this.props; onCloneAppProfilePress(id); - } + }; // // Render diff --git a/frontend/src/Settings/Profiles/App/AppProfiles.js b/frontend/src/Settings/Profiles/App/AppProfiles.js index c4d46a96e..b93b0fe51 100644 --- a/frontend/src/Settings/Profiles/App/AppProfiles.js +++ b/frontend/src/Settings/Profiles/App/AppProfiles.js @@ -29,15 +29,15 @@ class AppProfiles extends Component { onCloneAppProfilePress = (id) => { this.props.onCloneAppProfilePress(id); this.setState({ isAppProfileModalOpen: true }); - } + }; onEditAppProfilePress = () => { this.setState({ isAppProfileModalOpen: true }); - } + }; onModalClose = () => { this.setState({ isAppProfileModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/Settings/Profiles/App/AppProfilesConnector.js b/frontend/src/Settings/Profiles/App/AppProfilesConnector.js index 3948fcdb7..a150655a6 100644 --- a/frontend/src/Settings/Profiles/App/AppProfilesConnector.js +++ b/frontend/src/Settings/Profiles/App/AppProfilesConnector.js @@ -34,11 +34,11 @@ class AppProfilesConnector extends Component { onConfirmDeleteAppProfile = (id) => { this.props.dispatchDeleteAppProfile({ id }); - } + }; onCloneAppProfilePress = (id) => { this.props.dispatchCloneAppProfile({ id }); - } + }; // // Render diff --git a/frontend/src/Settings/Profiles/App/EditAppProfileModalConnector.js b/frontend/src/Settings/Profiles/App/EditAppProfileModalConnector.js index c6e1f849e..de61a9b86 100644 --- a/frontend/src/Settings/Profiles/App/EditAppProfileModalConnector.js +++ b/frontend/src/Settings/Profiles/App/EditAppProfileModalConnector.js @@ -20,7 +20,7 @@ class EditAppProfileModalConnector extends Component { onModalClose = () => { this.props.clearPendingChanges({ section: 'settings.appProfiles' }); this.props.onModalClose(); - } + }; // // Render diff --git a/frontend/src/Settings/Profiles/App/EditAppProfileModalContentConnector.js b/frontend/src/Settings/Profiles/App/EditAppProfileModalContentConnector.js index 8e92f8204..80a1f9dfc 100644 --- a/frontend/src/Settings/Profiles/App/EditAppProfileModalContentConnector.js +++ b/frontend/src/Settings/Profiles/App/EditAppProfileModalContentConnector.js @@ -45,11 +45,11 @@ class EditAppProfileModalContentConnector extends Component { onInputChange = ({ name, value }) => { this.props.setAppProfileValue({ name, value }); - } + }; onSavePress = () => { this.props.saveAppProfile({ id: this.props.id }); - } + }; // // Render diff --git a/frontend/src/Settings/SettingsToolbar.js b/frontend/src/Settings/SettingsToolbar.js index 62692ca76..048dcc66e 100644 --- a/frontend/src/Settings/SettingsToolbar.js +++ b/frontend/src/Settings/SettingsToolbar.js @@ -32,7 +32,7 @@ class SettingsToolbar extends Component { if (hasPendingChanges) { onSavePress(); } - } + }; // // Render diff --git a/frontend/src/Settings/SettingsToolbarConnector.js b/frontend/src/Settings/SettingsToolbarConnector.js index 8bfb3dad5..1e6f7a589 100644 --- a/frontend/src/Settings/SettingsToolbarConnector.js +++ b/frontend/src/Settings/SettingsToolbarConnector.js @@ -66,14 +66,14 @@ class SettingsToolbarConnector extends Component { } return true; - } + }; // // Listeners onAdvancedSettingsPress = () => { this.props.toggleAdvancedSettings(); - } + }; onConfirmNavigation = () => { const { @@ -98,7 +98,7 @@ class SettingsToolbarConnector extends Component { history.goBack(); } }); - } + }; onCancelNavigation = () => { this.setState({ @@ -106,7 +106,7 @@ class SettingsToolbarConnector extends Component { nextLocationAction: null, confirmed: false }); - } + }; // // Render diff --git a/frontend/src/Settings/Tags/Tag.js b/frontend/src/Settings/Tags/Tag.js index 7842b878f..7e9aa0991 100644 --- a/frontend/src/Settings/Tags/Tag.js +++ b/frontend/src/Settings/Tags/Tag.js @@ -26,26 +26,26 @@ class Tag extends Component { onShowDetailsPress = () => { this.setState({ isDetailsModalOpen: true }); - } + }; onDetailsModalClose = () => { this.setState({ isDetailsModalOpen: false }); - } + }; onDeleteTagPress = () => { this.setState({ isDetailsModalOpen: false, isDeleteTagModalOpen: true }); - } + }; onDeleteTagModalClose= () => { this.setState({ isDeleteTagModalOpen: false }); - } + }; onConfirmDeleteTag = () => { this.props.onConfirmDeleteTag({ id: this.props.id }); - } + }; // // Render diff --git a/frontend/src/Settings/UI/UISettingsConnector.js b/frontend/src/Settings/UI/UISettingsConnector.js index 31d41f9e0..ea9194f8c 100644 --- a/frontend/src/Settings/UI/UISettingsConnector.js +++ b/frontend/src/Settings/UI/UISettingsConnector.js @@ -72,11 +72,11 @@ class UISettingsConnector extends Component { onInputChange = ({ name, value }) => { this.props.setUISettingsValue({ name, value }); - } + }; onSavePress = () => { this.props.saveUISettings(); - } + }; // // Render diff --git a/frontend/src/System/Backup/BackupRow.js b/frontend/src/System/Backup/BackupRow.js index 1e57c2f7b..8bbfaf172 100644 --- a/frontend/src/System/Backup/BackupRow.js +++ b/frontend/src/System/Backup/BackupRow.js @@ -31,19 +31,19 @@ class BackupRow extends Component { onRestorePress = () => { this.setState({ isRestoreModalOpen: true }); - } + }; onRestoreModalClose = () => { this.setState({ isRestoreModalOpen: false }); - } + }; onDeletePress = () => { this.setState({ isConfirmDeleteModalOpen: true }); - } + }; onConfirmDeleteModalClose = () => { this.setState({ isConfirmDeleteModalOpen: false }); - } + }; onConfirmDeletePress = () => { const { @@ -54,7 +54,7 @@ class BackupRow extends Component { this.setState({ isConfirmDeleteModalOpen: false }, () => { onDeleteBackupPress(id); }); - } + }; // // Render diff --git a/frontend/src/System/Backup/Backups.js b/frontend/src/System/Backup/Backups.js index f65010875..541c09253 100644 --- a/frontend/src/System/Backup/Backups.js +++ b/frontend/src/System/Backup/Backups.js @@ -52,11 +52,11 @@ class Backups extends Component { onRestorePress = () => { this.setState({ isRestoreModalOpen: true }); - } + }; onRestoreModalClose = () => { this.setState({ isRestoreModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/System/Backup/RestoreBackupModalContent.js b/frontend/src/System/Backup/RestoreBackupModalContent.js index 3c86ae0d4..150c46ad6 100644 --- a/frontend/src/System/Backup/RestoreBackupModalContent.js +++ b/frontend/src/System/Backup/RestoreBackupModalContent.js @@ -97,7 +97,7 @@ class RestoreBackupModalContent extends Component { file: files[0], path: value }); - } + }; onRestorePress = () => { const { @@ -109,7 +109,7 @@ class RestoreBackupModalContent extends Component { id, file: this.state.file }); - } + }; // // Render diff --git a/frontend/src/System/Events/LogsTableConnector.js b/frontend/src/System/Events/LogsTableConnector.js index 957e2a5e1..20e6eafbf 100644 --- a/frontend/src/System/Events/LogsTableConnector.js +++ b/frontend/src/System/Events/LogsTableConnector.js @@ -57,31 +57,31 @@ class LogsTableConnector extends Component { onFirstPagePress = () => { this.props.gotoLogsFirstPage(); - } + }; onPreviousPagePress = () => { this.props.gotoLogsPreviousPage(); - } + }; onNextPagePress = () => { this.props.gotoLogsNextPage(); - } + }; onLastPagePress = () => { this.props.gotoLogsLastPage(); - } + }; onPageSelect = (page) => { this.props.gotoLogsPage({ page }); - } + }; onSortPress = (sortKey) => { this.props.setLogsSort({ sortKey }); - } + }; onFilterSelect = (selectedFilterKey) => { this.props.setLogsFilter({ selectedFilterKey }); - } + }; onTableOptionChange = (payload) => { this.props.setLogsTableOption(payload); @@ -89,15 +89,15 @@ class LogsTableConnector extends Component { if (payload.pageSize) { this.props.gotoLogsFirstPage(); } - } + }; onRefreshPress = () => { this.props.gotoLogsFirstPage(); - } + }; onClearLogsPress = () => { this.props.executeCommand({ name: commandNames.CLEAR_LOGS }); - } + }; // // Render diff --git a/frontend/src/System/Events/LogsTableRow.js b/frontend/src/System/Events/LogsTableRow.js index bebf80184..2de54a189 100644 --- a/frontend/src/System/Events/LogsTableRow.js +++ b/frontend/src/System/Events/LogsTableRow.js @@ -46,11 +46,11 @@ class LogsTableRow extends Component { if (!this.state.isDetailsModalOpen) { this.setState({ isDetailsModalOpen: true }); } - } + }; onModalClose = () => { this.setState({ isDetailsModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/System/Logs/Files/LogFilesConnector.js b/frontend/src/System/Logs/Files/LogFilesConnector.js index b6d443f6a..03d958b33 100644 --- a/frontend/src/System/Logs/Files/LogFilesConnector.js +++ b/frontend/src/System/Logs/Files/LogFilesConnector.js @@ -61,11 +61,11 @@ class LogFilesConnector extends Component { onRefreshPress = () => { this.props.fetchLogFiles(); - } + }; onDeleteFilesPress = () => { this.props.executeCommand({ name: commandNames.DELETE_LOG_FILES }); - } + }; // // Render diff --git a/frontend/src/System/Logs/LogsNavMenu.js b/frontend/src/System/Logs/LogsNavMenu.js index b69630248..cc485f270 100644 --- a/frontend/src/System/Logs/LogsNavMenu.js +++ b/frontend/src/System/Logs/LogsNavMenu.js @@ -23,11 +23,11 @@ class LogsNavMenu extends Component { onMenuButtonPress = () => { this.setState({ isMenuOpen: !this.state.isMenuOpen }); - } + }; onMenuItemPress = () => { this.setState({ isMenuOpen: false }); - } + }; // // Render diff --git a/frontend/src/System/Logs/Updates/UpdateLogFilesConnector.js b/frontend/src/System/Logs/Updates/UpdateLogFilesConnector.js index 3563d58d8..537816014 100644 --- a/frontend/src/System/Logs/Updates/UpdateLogFilesConnector.js +++ b/frontend/src/System/Logs/Updates/UpdateLogFilesConnector.js @@ -61,11 +61,11 @@ class UpdateLogFilesConnector extends Component { onRefreshPress = () => { this.props.fetchUpdateLogFiles(); - } + }; onDeleteFilesPress = () => { this.props.executeCommand({ name: commandNames.DELETE_UPDATE_LOG_FILES }); - } + }; // // Render diff --git a/frontend/src/System/Status/About/StartTime.js b/frontend/src/System/Status/About/StartTime.js index 94b4322d5..08c820add 100644 --- a/frontend/src/System/Status/About/StartTime.js +++ b/frontend/src/System/Status/About/StartTime.js @@ -65,7 +65,7 @@ class StartTime extends Component { onTimeout = () => { this.setState({ uptime: getUptime(this.props.startTime) }); this._timeoutId = setTimeout(this.onTimeout, 1000); - } + }; // // Render diff --git a/frontend/src/System/Tasks/Queued/QueuedTaskRow.js b/frontend/src/System/Tasks/Queued/QueuedTaskRow.js index b19525326..5ccf0e5b8 100644 --- a/frontend/src/System/Tasks/Queued/QueuedTaskRow.js +++ b/frontend/src/System/Tasks/Queued/QueuedTaskRow.js @@ -136,13 +136,13 @@ class QueuedTaskRow extends Component { this.setState({ isCancelConfirmModalOpen: true }); - } + }; onAbortCancel = () => { this.setState({ isCancelConfirmModalOpen: false }); - } + }; // // Render diff --git a/frontend/src/System/Updates/UpdatesConnector.js b/frontend/src/System/Updates/UpdatesConnector.js index 343106d24..38873a990 100644 --- a/frontend/src/System/Updates/UpdatesConnector.js +++ b/frontend/src/System/Updates/UpdatesConnector.js @@ -77,7 +77,7 @@ class UpdatesConnector extends Component { onInstallLatestPress = () => { this.props.dispatchExecuteCommand({ name: commandNames.APPLICATION_UPDATE }); - } + }; // // Render From 4d021fe8dc66130e24f3d76100021be857125c2c Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 22 Nov 2021 08:09:32 -0600 Subject: [PATCH 0174/2320] Fixed: Default search type should be 'search' --- frontend/src/Store/Actions/releaseActions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Store/Actions/releaseActions.js b/frontend/src/Store/Actions/releaseActions.js index 89ea9ffda..7256f9d8d 100644 --- a/frontend/src/Store/Actions/releaseActions.js +++ b/frontend/src/Store/Actions/releaseActions.js @@ -36,7 +36,7 @@ export const defaultState = { secondarySortDirection: sortDirections.ASCENDING, defaults: { - searchType: 'basic', + searchType: 'search', searchQuery: '', searchIndexerIds: [], searchCategories: [] From 25bb5b642784e12bb8f8faf87cd8c9366d34f8ae Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 21 Nov 2021 19:07:47 -0600 Subject: [PATCH 0175/2320] Bump React-dnd to 14.0.4 --- package.json | 6 +++--- yarn.lock | 42 +++++++++++++++++++++--------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 72090b7ce..23ff8ebf4 100644 --- a/package.json +++ b/package.json @@ -55,10 +55,10 @@ "react-async-script": "1.2.0", "react-autosuggest": "10.1.0", "react-custom-scrollbars": "4.2.1", - "react-dnd": "14.0.2", - "react-dnd-html5-backend": "14.0.0", + "react-dnd": "14.0.4", + "react-dnd-html5-backend": "14.0.2", "react-dnd-multi-backend": "6.0.2", - "react-dnd-touch-backend": "14.0.0", + "react-dnd-touch-backend": "14.1.1", "react-document-title": "2.0.3", "react-dom": "17.0.2", "react-focus-lock": "2.5.0", diff --git a/yarn.lock b/yarn.lock index 0fc5ec714..c14096c64 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2621,14 +2621,14 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -dnd-core@14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-14.0.0.tgz#973ab3470d0a9ac5a0fa9021c4feba93ad12347d" - integrity sha512-wTDYKyjSqWuYw3ZG0GJ7k+UIfzxTNoZLjDrut37PbcPGNfwhlKYlPUqjAKUjOOv80izshUiqusaKgJPItXSevA== +dnd-core@14.0.1: + version "14.0.1" + resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-14.0.1.tgz#76d000e41c494983210fb20a48b835f81a203c2e" + integrity sha512-+PVS2VPTgKFPYWo3vAFEA8WPbTf7/xo43TifH9G8S1KqnrQu0o77A3unrF5yOugy4mIz7K5wAVFHUcha7wsz6A== dependencies: "@react-dnd/asap" "^4.0.0" "@react-dnd/invariant" "^2.0.0" - redux "^4.0.5" + redux "^4.1.1" dnd-multi-backend@^6.0.0: version "6.0.0" @@ -5480,12 +5480,12 @@ react-custom-scrollbars@4.2.1: prop-types "^15.5.10" raf "^3.1.0" -react-dnd-html5-backend@14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-14.0.0.tgz#28d660a2ad1e07447c34a65cd25f7de8f1657194" - integrity sha512-2wAQqRFC1hbRGmk6+dKhOXsyQQOn3cN8PSZyOUeOun9J8t3tjZ7PS2+aFu7CVu2ujMDwTJR3VTwZh8pj2kCv7g== +react-dnd-html5-backend@14.0.2: + version "14.0.2" + resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-14.0.2.tgz#25019388f6abdeeda3a6fea835dff155abb2085c" + integrity sha512-QgN6rYrOm4UUj6tIvN8ovImu6uP48xBXF2rzVsp6tvj6d5XQ7OjHI4SJ/ZgGobOneRAU3WCX4f8DGCYx0tuhlw== dependencies: - dnd-core "14.0.0" + dnd-core "14.0.1" react-dnd-multi-backend@6.0.2: version "6.0.2" @@ -5503,22 +5503,22 @@ react-dnd-preview@^6.0.2: dependencies: prop-types "^15.7.2" -react-dnd-touch-backend@14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/react-dnd-touch-backend/-/react-dnd-touch-backend-14.0.0.tgz#f7f144ca4af17946e20cdfd06a766ebadd170d4d" - integrity sha512-fNt3isf9h0xgjj86dIXhBi3dJ7OhC88vKUYdEvsOGypdp3LOFD+TobBAuBu00v26WmJ6II6xqbkhOx+KOcyHxQ== +react-dnd-touch-backend@14.1.1: + version "14.1.1" + resolved "https://registry.yarnpkg.com/react-dnd-touch-backend/-/react-dnd-touch-backend-14.1.1.tgz#d8875ef1cf8dcbf1741a4e03dd5b147c4fbda5e4" + integrity sha512-ITmfzn3fJrkUBiVLO6aJZcnu7T8C+GfwZitFryGsXKn5wYcUv+oQBeh9FYcMychmVbDdeUCfvEtTk9O+DKmAaw== dependencies: "@react-dnd/invariant" "^2.0.0" - dnd-core "14.0.0" + dnd-core "14.0.1" -react-dnd@14.0.2: - version "14.0.2" - resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-14.0.2.tgz#57266baec92b887301f81fa3b77f87168d159733" - integrity sha512-JoEL78sBCg8SzjOKMlkR70GWaPORudhWuTNqJ56lb2P8Vq0eM2+er3ZrMGiSDhOmzaRPuA9SNBz46nHCrjn11A== +react-dnd@14.0.4: + version "14.0.4" + resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-14.0.4.tgz#ffb4ea0e2a3a5532f9c6294d565742008a52b8b0" + integrity sha512-AFJJXzUIWp5WAhgvI85ESkDCawM0lhoVvfo/lrseLXwFdH3kEO3v8I2C81QPqBW2UEyJBIPStOhPMGYGFtq/bg== dependencies: "@react-dnd/invariant" "^2.0.0" "@react-dnd/shallowequal" "^2.0.0" - dnd-core "14.0.0" + dnd-core "14.0.1" fast-deep-equal "^3.1.3" hoist-non-react-statics "^3.3.2" @@ -5773,7 +5773,7 @@ redux@4.1.0: dependencies: "@babel/runtime" "^7.9.2" -redux@^4.0.0, redux@^4.0.5: +redux@^4.0.0, redux@^4.1.1: version "4.1.2" resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.2.tgz#140f35426d99bb4729af760afcf79eaaac407104" integrity sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw== From 5979c5f8febb64c5036d6b38c4f1c834ca68aa50 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 21 Nov 2021 20:32:12 -0600 Subject: [PATCH 0176/2320] Cleanup Config Options Fixes #610 --- frontend/src/Commands/commandNames.js | 2 - .../Page/Sidebar/Messages/Message.js | 12 -- .../Configuration/ConfigServiceFixture.cs | 14 +- .../Configuration/ConfigService.cs | 121 ------------------ .../Configuration/IConfigService.cs | 27 ---- .../Config/DownloadClientConfigResource.cs | 16 +-- .../Config/IndexerConfigController.cs | 32 ----- .../Config/IndexerConfigResource.cs | 35 ----- 8 files changed, 8 insertions(+), 251 deletions(-) delete mode 100644 src/Prowlarr.Api.V1/Config/IndexerConfigController.cs delete mode 100644 src/Prowlarr.Api.V1/Config/IndexerConfigResource.cs diff --git a/frontend/src/Commands/commandNames.js b/frontend/src/Commands/commandNames.js index 7028d46cd..9974bab12 100644 --- a/frontend/src/Commands/commandNames.js +++ b/frontend/src/Commands/commandNames.js @@ -4,7 +4,5 @@ export const CLEAR_HISTORY = 'ClearHistory'; export const CLEAR_LOGS = 'ClearLog'; export const DELETE_LOG_FILES = 'DeleteLogFiles'; export const DELETE_UPDATE_LOG_FILES = 'DeleteUpdateLogFiles'; -export const INTERACTIVE_IMPORT = 'ManualImport'; export const RESET_API_KEY = 'ResetApiKey'; -export const RSS_SYNC = 'RssSync'; export const APP_INDEXER_SYNC = 'ApplicationIndexerSync'; diff --git a/frontend/src/Components/Page/Sidebar/Messages/Message.js b/frontend/src/Components/Page/Sidebar/Messages/Message.js index be626c582..964f4ad0d 100644 --- a/frontend/src/Components/Page/Sidebar/Messages/Message.js +++ b/frontend/src/Components/Page/Sidebar/Messages/Message.js @@ -13,20 +13,8 @@ function getIconName(name) { return icons.BACKUP; case 'CheckHealth': return icons.HEALTH; - case 'EpisodeSearch': - return icons.SEARCH; case 'Housekeeping': return icons.HOUSEKEEPING; - case 'RefreshMovie': - return icons.REFRESH; - case 'RssSync': - return icons.RSS; - case 'SeasonSearch': - return icons.SEARCH; - case 'MovieSearch': - return icons.SEARCH; - case 'UpdateSceneMapping': - return icons.REFRESH; default: return icons.SPINNER; } diff --git a/src/NzbDrone.Core.Test/Configuration/ConfigServiceFixture.cs b/src/NzbDrone.Core.Test/Configuration/ConfigServiceFixture.cs index 2ed847f4e..906f4d611 100644 --- a/src/NzbDrone.Core.Test/Configuration/ConfigServiceFixture.cs +++ b/src/NzbDrone.Core.Test/Configuration/ConfigServiceFixture.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using FluentAssertions; @@ -20,10 +20,10 @@ namespace NzbDrone.Core.Test.Configuration [Test] public void Add_new_value_to_database() { - const string key = "RssSyncInterval"; - const int value = 12; + const string key = "HistoryCleanupDays"; + const int value = 20; - Subject.RssSyncInterval = value; + Subject.HistoryCleanupDays = value; AssertUpsert(key, value); } @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Test.Configuration [Test] public void Get_value_should_return_default_when_no_value() { - Subject.RssSyncInterval.Should().Be(60); + Subject.HistoryCleanupDays.Should().Be(365); } [Test] @@ -45,8 +45,8 @@ namespace NzbDrone.Core.Test.Configuration [Test] public void get_value_with_out_persist_should_not_store_default_value() { - var interval = Subject.RssSyncInterval; - interval.Should().Be(60); + var interval = Subject.HistoryCleanupDays; + interval.Should().Be(365); Mocker.GetMock<IConfigRepository>().Verify(c => c.Insert(It.IsAny<Config>()), Times.Never()); } diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index 4ca375459..9541c3d6a 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -77,77 +77,12 @@ namespace NzbDrone.Core.Configuration return _repository.Get(key.ToLower()) != null; } - public int Retention - { - get { return GetValueInt("Retention", 0); } - set { SetValue("Retention", value); } - } - public int HistoryCleanupDays { get { return GetValueInt("HistoryCleanupDays", 365); } set { SetValue("HistoryCleanupDays", value); } } - public int RssSyncInterval - { - get { return GetValueInt("RssSyncInterval", 60); } - - set { SetValue("RssSyncInterval", value); } - } - - public int AvailabilityDelay - { - get { return GetValueInt("AvailabilityDelay", 0); } - set { SetValue("AvailabilityDelay", value); } - } - - public int ImportListSyncInterval - { - get { return GetValueInt("ImportListSyncInterval", 240); } - - set { SetValue("ImportListSyncInterval", value); } - } - - public string ListSyncLevel - { - get { return GetValue("ListSyncLevel", "disabled"); } - set { SetValue("ListSyncLevel", value); } - } - - public string ImportExclusions - { - get { return GetValue("ImportExclusions", string.Empty); } - set { SetValue("ImportExclusions", value); } - } - - public int MaximumSize - { - get { return GetValueInt("MaximumSize", 0); } - set { SetValue("MaximumSize", value); } - } - - public int MinimumAge - { - get { return GetValueInt("MinimumAge", 0); } - - set { SetValue("MinimumAge", value); } - } - - public bool EnableCompletedDownloadHandling - { - get { return GetValueBoolean("EnableCompletedDownloadHandling", true); } - - set { SetValue("EnableCompletedDownloadHandling", value); } - } - - public bool PreferIndexerFlags - { - get { return GetValueBoolean("PreferIndexerFlags", false); } - - set { SetValue("PreferIndexerFlags", value); } - } - public bool LogIndexerResponse { get { return GetValueBoolean("LogIndexerResponse", false); } @@ -155,61 +90,12 @@ namespace NzbDrone.Core.Configuration set { SetValue("LogIndexerResponse", value); } } - public bool AllowHardcodedSubs - { - get { return GetValueBoolean("AllowHardcodedSubs", false); } - - set { SetValue("AllowHardcodedSubs", value); } - } - - public string WhitelistedHardcodedSubs - { - get { return GetValue("WhitelistedHardcodedSubs", ""); } - - set { SetValue("WhitelistedHardcodedSubs", value); } - } - - public bool RemoveCompletedDownloads - { - get { return GetValueBoolean("RemoveCompletedDownloads", false); } - - set { SetValue("RemoveCompletedDownloads", value); } - } - - public bool AutoRedownloadFailed - { - get { return GetValueBoolean("AutoRedownloadFailed", true); } - - set { SetValue("AutoRedownloadFailed", value); } - } - - public bool RemoveFailedDownloads - { - get { return GetValueBoolean("RemoveFailedDownloads", true); } - - set { SetValue("RemoveFailedDownloads", value); } - } - public string DownloadClientWorkingFolders { get { return GetValue("DownloadClientWorkingFolders", "_UNPACK_|_FAILED_"); } set { SetValue("DownloadClientWorkingFolders", value); } } - public int CheckForFinishedDownloadInterval - { - get { return GetValueInt("CheckForFinishedDownloadInterval", 1); } - - set { SetValue("CheckForFinishedDownloadInterval", value); } - } - - public int DownloadClientHistoryLimit - { - get { return GetValueInt("DownloadClientHistoryLimit", 30); } - - set { SetValue("DownloadClientHistoryLimit", value); } - } - public int FirstDayOfWeek { get { return GetValueInt("FirstDayOfWeek", (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek); } @@ -273,13 +159,6 @@ namespace NzbDrone.Core.Configuration set { SetValue("UILanguage", value); } } - public bool CleanupMetadataImages - { - get { return GetValueBoolean("CleanupMetadataImages", true); } - - set { SetValue("CleanupMetadataImages", value); } - } - public string PlexClientIdentifier => GetValue("PlexClientIdentifier", Guid.NewGuid().ToString(), true); public string RijndaelPassphrase => GetValue("RijndaelPassphrase", Guid.NewGuid().ToString(), true); diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index 78bd52664..d2556901d 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -12,36 +12,10 @@ namespace NzbDrone.Core.Configuration //Download Client string DownloadClientWorkingFolders { get; set; } - int DownloadClientHistoryLimit { get; set; } - int CheckForFinishedDownloadInterval { get; set; } - - //Completed/Failed Download Handling (Download client) - bool EnableCompletedDownloadHandling { get; set; } - bool RemoveCompletedDownloads { get; set; } - - bool AutoRedownloadFailed { get; set; } - bool RemoveFailedDownloads { get; set; } //History int HistoryCleanupDays { get; set; } - //Indexers - int Retention { get; set; } - int RssSyncInterval { get; set; } - int MaximumSize { get; set; } - int MinimumAge { get; set; } - - bool PreferIndexerFlags { get; set; } - - int AvailabilityDelay { get; set; } - - bool AllowHardcodedSubs { get; set; } - string WhitelistedHardcodedSubs { get; set; } - - int ImportListSyncInterval { get; set; } - string ListSyncLevel { get; set; } - string ImportExclusions { get; set; } - //UI int FirstDayOfWeek { get; set; } string CalendarWeekColumnHeader { get; set; } @@ -55,7 +29,6 @@ namespace NzbDrone.Core.Configuration int UILanguage { get; set; } //Internal - bool CleanupMetadataImages { get; set; } string PlexClientIdentifier { get; } //Forms Auth diff --git a/src/Prowlarr.Api.V1/Config/DownloadClientConfigResource.cs b/src/Prowlarr.Api.V1/Config/DownloadClientConfigResource.cs index cdc5cf048..b779340a1 100644 --- a/src/Prowlarr.Api.V1/Config/DownloadClientConfigResource.cs +++ b/src/Prowlarr.Api.V1/Config/DownloadClientConfigResource.cs @@ -6,13 +6,6 @@ namespace Prowlarr.Api.V1.Config public class DownloadClientConfigResource : RestResource { public string DownloadClientWorkingFolders { get; set; } - - public bool EnableCompletedDownloadHandling { get; set; } - public bool RemoveCompletedDownloads { get; set; } - public int CheckForFinishedDownloadInterval { get; set; } - - public bool AutoRedownloadFailed { get; set; } - public bool RemoveFailedDownloads { get; set; } } public static class DownloadClientConfigResourceMapper @@ -21,14 +14,7 @@ namespace Prowlarr.Api.V1.Config { return new DownloadClientConfigResource { - DownloadClientWorkingFolders = model.DownloadClientWorkingFolders, - - EnableCompletedDownloadHandling = model.EnableCompletedDownloadHandling, - RemoveCompletedDownloads = model.RemoveCompletedDownloads, - CheckForFinishedDownloadInterval = model.CheckForFinishedDownloadInterval, - - AutoRedownloadFailed = model.AutoRedownloadFailed, - RemoveFailedDownloads = model.RemoveFailedDownloads + DownloadClientWorkingFolders = model.DownloadClientWorkingFolders }; } } diff --git a/src/Prowlarr.Api.V1/Config/IndexerConfigController.cs b/src/Prowlarr.Api.V1/Config/IndexerConfigController.cs deleted file mode 100644 index 1c3dfd0a1..000000000 --- a/src/Prowlarr.Api.V1/Config/IndexerConfigController.cs +++ /dev/null @@ -1,32 +0,0 @@ -using FluentValidation; -using NzbDrone.Core.Configuration; -using Prowlarr.Http; -using Prowlarr.Http.Validation; - -namespace Prowlarr.Api.V1.Config -{ - [V1ApiController("config/indexer")] - public class IndexerConfigController : ConfigController<IndexerConfigResource> - { - public IndexerConfigController(IConfigService configService) - : base(configService) - { - SharedValidator.RuleFor(c => c.MinimumAge) - .GreaterThanOrEqualTo(0); - - SharedValidator.RuleFor(c => c.MaximumSize) - .GreaterThanOrEqualTo(0); - - SharedValidator.RuleFor(c => c.Retention) - .GreaterThanOrEqualTo(0); - - SharedValidator.RuleFor(c => c.RssSyncInterval) - .IsValidRssSyncInterval(); - } - - protected override IndexerConfigResource ToResource(IConfigService model) - { - return IndexerConfigResourceMapper.ToResource(model); - } - } -} diff --git a/src/Prowlarr.Api.V1/Config/IndexerConfigResource.cs b/src/Prowlarr.Api.V1/Config/IndexerConfigResource.cs deleted file mode 100644 index c3acc6c45..000000000 --- a/src/Prowlarr.Api.V1/Config/IndexerConfigResource.cs +++ /dev/null @@ -1,35 +0,0 @@ -using NzbDrone.Core.Configuration; -using Prowlarr.Http.REST; - -namespace Prowlarr.Api.V1.Config -{ - public class IndexerConfigResource : RestResource - { - public int MinimumAge { get; set; } - public int MaximumSize { get; set; } - public int Retention { get; set; } - public int RssSyncInterval { get; set; } - public bool PreferIndexerFlags { get; set; } - public int AvailabilityDelay { get; set; } - public bool AllowHardcodedSubs { get; set; } - public string WhitelistedHardcodedSubs { get; set; } - } - - public static class IndexerConfigResourceMapper - { - public static IndexerConfigResource ToResource(IConfigService model) - { - return new IndexerConfigResource - { - MinimumAge = model.MinimumAge, - MaximumSize = model.MaximumSize, - Retention = model.Retention, - RssSyncInterval = model.RssSyncInterval, - PreferIndexerFlags = model.PreferIndexerFlags, - AvailabilityDelay = model.AvailabilityDelay, - AllowHardcodedSubs = model.AllowHardcodedSubs, - WhitelistedHardcodedSubs = model.WhitelistedHardcodedSubs, - }; - } - } -} From 1183a0386d60829e0f7ad3ec4aea760d8cadd18c Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 22 Nov 2021 16:39:30 -0600 Subject: [PATCH 0177/2320] New: Grab Title column option in History Fixes #628 --- frontend/src/History/HistoryRow.js | 15 +++++++++++++++ frontend/src/Store/Actions/historyActions.js | 6 ++++++ 2 files changed, 21 insertions(+) diff --git a/frontend/src/History/HistoryRow.js b/frontend/src/History/HistoryRow.js index 8b59a1152..0ebe3deb4 100644 --- a/frontend/src/History/HistoryRow.js +++ b/frontend/src/History/HistoryRow.js @@ -247,6 +247,21 @@ class HistoryRow extends Component { ); } + if (name === 'grabTitle') { + return ( + <TableRowCell + key={name} + className={styles.indexer} + > + { + data.title ? + data.title : + null + } + </TableRowCell> + ); + } + if (name === 'categories') { return ( <TableRowCell diff --git a/frontend/src/Store/Actions/historyActions.js b/frontend/src/Store/Actions/historyActions.js index 4a04ef542..a94ff8c3a 100644 --- a/frontend/src/Store/Actions/historyActions.js +++ b/frontend/src/Store/Actions/historyActions.js @@ -52,6 +52,12 @@ export const defaultState = { isSortable: false, isVisible: false }, + { + name: 'grabTitle', + label: 'Grab Title', + isSortable: false, + isVisible: false + }, { name: 'categories', label: 'Categories', From 884aecf84678b84a8a1b4bb60bf9beb105e4a19a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 22 Nov 2021 17:14:52 -0600 Subject: [PATCH 0178/2320] New: Store call URL in History, Link in UI --- .../src/History/Details/HistoryDetails.js | 23 +++++++++++++++++-- src/NzbDrone.Core/Download/DownloadService.cs | 16 ++++++------- src/NzbDrone.Core/History/HistoryService.cs | 9 +++++--- .../IndexerSearch/ReleaseSearchService.cs | 4 ++-- .../Indexers/Events/IndexerDownloadEvent.cs | 4 +++- .../Indexers/Events/IndexerQueryEvent.cs | 10 +++----- src/NzbDrone.Core/Indexers/HttpIndexerBase.cs | 13 +++++------ .../Indexers/IndexerQueryResult.cs | 4 ++-- 8 files changed, 51 insertions(+), 32 deletions(-) diff --git a/frontend/src/History/Details/HistoryDetails.js b/frontend/src/History/Details/HistoryDetails.js index ad5504ba2..4d7887fab 100644 --- a/frontend/src/History/Details/HistoryDetails.js +++ b/frontend/src/History/Details/HistoryDetails.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import DescriptionList from 'Components/DescriptionList/DescriptionList'; import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem'; +import Link from 'Components/Link/Link'; import translate from 'Utilities/String/translate'; import styles from './HistoryDetails.css'; @@ -17,7 +18,8 @@ function HistoryDetails(props) { query, queryResults, categories, - source + source, + url } = data; return ( @@ -59,6 +61,14 @@ function HistoryDetails(props) { data={source} /> } + + { + !!data && + <DescriptionListItem + title={'Url'} + data={url ? <Link to={url}>{translate('Link')}</Link> : '-'} + /> + } </DescriptionList> ); } @@ -66,7 +76,8 @@ function HistoryDetails(props) { if (eventType === 'releaseGrabbed') { const { source, - title + title, + url } = data; return ( @@ -94,6 +105,14 @@ function HistoryDetails(props) { data={title ? title : '-'} /> } + + { + !!data && + <DescriptionListItem + title={'Url'} + data={url ? <Link to={url}>{translate('Link')}</Link> : '-'} + /> + } </DescriptionList> ); } diff --git a/src/NzbDrone.Core/Download/DownloadService.cs b/src/NzbDrone.Core/Download/DownloadService.cs index 6d5e5df7c..34a18e029 100644 --- a/src/NzbDrone.Core/Download/DownloadService.cs +++ b/src/NzbDrone.Core/Download/DownloadService.cs @@ -81,13 +81,13 @@ namespace NzbDrone.Core.Download catch (ReleaseUnavailableException) { _logger.Trace("Release {0} no longer available on indexer.", release); - _eventAggregator.PublishEvent(new IndexerDownloadEvent(release.IndexerId, false, source, host, release.Title, redirect)); + _eventAggregator.PublishEvent(new IndexerDownloadEvent(release.IndexerId, false, source, host, release.Title, release.DownloadUrl, redirect)); throw; } catch (DownloadClientRejectedReleaseException) { _logger.Trace("Release {0} rejected by download client, possible duplicate.", release); - _eventAggregator.PublishEvent(new IndexerDownloadEvent(release.IndexerId, false, source, host, release.Title, redirect)); + _eventAggregator.PublishEvent(new IndexerDownloadEvent(release.IndexerId, false, source, host, release.Title, release.DownloadUrl, redirect)); throw; } catch (ReleaseDownloadException ex) @@ -102,14 +102,14 @@ namespace NzbDrone.Core.Download _indexerStatusService.RecordFailure(release.IndexerId); } - _eventAggregator.PublishEvent(new IndexerDownloadEvent(release.IndexerId, false, source, host, release.Title, redirect)); + _eventAggregator.PublishEvent(new IndexerDownloadEvent(release.IndexerId, false, source, host, release.Title, release.DownloadUrl, redirect)); throw; } _logger.ProgressInfo("Report sent to {0}. {1}", downloadClient.Definition.Name, downloadTitle); - _eventAggregator.PublishEvent(new IndexerDownloadEvent(release.IndexerId, true, source, host, release.Title, redirect)); + _eventAggregator.PublishEvent(new IndexerDownloadEvent(release.IndexerId, true, source, host, release.Title, release.DownloadUrl, redirect)); } public async Task<byte[]> DownloadReport(string link, int indexerId, string source, string host, string title) @@ -135,7 +135,7 @@ namespace NzbDrone.Core.Download catch (ReleaseUnavailableException) { _logger.Trace("Release {0} no longer available on indexer.", link); - _eventAggregator.PublishEvent(new IndexerDownloadEvent(indexerId, success, source, host, title)); + _eventAggregator.PublishEvent(new IndexerDownloadEvent(indexerId, success, source, host, title, url.AbsoluteUri)); throw; } catch (ReleaseDownloadException ex) @@ -150,17 +150,17 @@ namespace NzbDrone.Core.Download _indexerStatusService.RecordFailure(indexerId); } - _eventAggregator.PublishEvent(new IndexerDownloadEvent(indexerId, success, source, host, title)); + _eventAggregator.PublishEvent(new IndexerDownloadEvent(indexerId, success, source, host, title, url.AbsoluteUri)); throw; } - _eventAggregator.PublishEvent(new IndexerDownloadEvent(indexerId, success, source, host, title)); + _eventAggregator.PublishEvent(new IndexerDownloadEvent(indexerId, success, source, host, title, url.AbsoluteUri)); return downloadedBytes; } public void RecordRedirect(string link, int indexerId, string source, string host, string title) { - _eventAggregator.PublishEvent(new IndexerDownloadEvent(indexerId, true, source, host, title, true)); + _eventAggregator.PublishEvent(new IndexerDownloadEvent(indexerId, true, source, host, title, link, true)); } } } diff --git a/src/NzbDrone.Core/History/HistoryService.cs b/src/NzbDrone.Core/History/HistoryService.cs index 72786e2e4..3187f1f20 100644 --- a/src/NzbDrone.Core/History/HistoryService.cs +++ b/src/NzbDrone.Core/History/HistoryService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; using NLog; using NzbDrone.Core.Configuration; using NzbDrone.Core.Datastore; @@ -115,7 +116,7 @@ namespace NzbDrone.Core.History Date = DateTime.UtcNow, IndexerId = message.IndexerId, EventType = message.Query.RssSearch ? HistoryEventType.IndexerRss : HistoryEventType.IndexerQuery, - Successful = message.Successful + Successful = message.QueryResult.Response?.StatusCode == HttpStatusCode.OK }; if (message.Query is MovieSearchCriteria) @@ -148,13 +149,14 @@ namespace NzbDrone.Core.History history.Data.Add("BookTitle", ((BookSearchCriteria)message.Query).Title ?? string.Empty); } - history.Data.Add("ElapsedTime", message.Time.ToString()); + history.Data.Add("ElapsedTime", message.QueryResult.Response?.ElapsedTime.ToString() ?? string.Empty); history.Data.Add("Query", message.Query.SearchTerm ?? string.Empty); history.Data.Add("QueryType", message.Query.SearchType ?? string.Empty); history.Data.Add("Categories", string.Join(",", message.Query.Categories) ?? string.Empty); history.Data.Add("Source", message.Query.Source ?? string.Empty); history.Data.Add("Host", message.Query.Host ?? string.Empty); - history.Data.Add("QueryResults", message.Results.HasValue ? message.Results.ToString() : null); + history.Data.Add("QueryResults", message.QueryResult.Releases?.Count().ToString() ?? string.Empty); + history.Data.Add("Url", message.QueryResult.Response?.Request.Url.FullUri ?? string.Empty); _historyRepository.Insert(history); } @@ -173,6 +175,7 @@ namespace NzbDrone.Core.History history.Data.Add("Host", message.Host ?? string.Empty); history.Data.Add("GrabMethod", message.Redirect ? "Redirect" : "Proxy"); history.Data.Add("Title", message.Title); + history.Data.Add("Url", message.Url ?? string.Empty); _historyRepository.Insert(history); } diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs index 4111cdd7d..4b49a4f23 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs @@ -188,14 +188,14 @@ namespace NzbDrone.Core.IndexerSearch foreach (var query in indexerReports.Queries) { - _eventAggregator.PublishEvent(new IndexerQueryEvent(indexer.Definition.Id, criteriaBase, query.ElapsedTime, query.StatusCode == 200, query.Releases.Count())); + _eventAggregator.PublishEvent(new IndexerQueryEvent(indexer.Definition.Id, criteriaBase, query)); } return releases; } catch (Exception e) { - _eventAggregator.PublishEvent(new IndexerQueryEvent(indexer.Definition.Id, criteriaBase, 0, false)); + _eventAggregator.PublishEvent(new IndexerQueryEvent(indexer.Definition.Id, criteriaBase, new IndexerQueryResult())); _logger.Error(e, "Error while searching for {0}", criteriaBase); } diff --git a/src/NzbDrone.Core/Indexers/Events/IndexerDownloadEvent.cs b/src/NzbDrone.Core/Indexers/Events/IndexerDownloadEvent.cs index 26f9572e2..ed895adf5 100644 --- a/src/NzbDrone.Core/Indexers/Events/IndexerDownloadEvent.cs +++ b/src/NzbDrone.Core/Indexers/Events/IndexerDownloadEvent.cs @@ -10,8 +10,9 @@ namespace NzbDrone.Core.Indexers.Events public string Host { get; set; } public string Title { get; set; } public bool Redirect { get; set; } + public string Url { get; set; } - public IndexerDownloadEvent(int indexerId, bool successful, string source, string host, string title, bool redirect = false) + public IndexerDownloadEvent(int indexerId, bool successful, string source, string host, string title, string url, bool redirect = false) { IndexerId = indexerId; Successful = successful; @@ -19,6 +20,7 @@ namespace NzbDrone.Core.Indexers.Events Host = host; Title = title; Redirect = redirect; + Url = url; } } } diff --git a/src/NzbDrone.Core/Indexers/Events/IndexerQueryEvent.cs b/src/NzbDrone.Core/Indexers/Events/IndexerQueryEvent.cs index e8c1477fd..aa834af77 100644 --- a/src/NzbDrone.Core/Indexers/Events/IndexerQueryEvent.cs +++ b/src/NzbDrone.Core/Indexers/Events/IndexerQueryEvent.cs @@ -7,17 +7,13 @@ namespace NzbDrone.Core.Indexers.Events { public int IndexerId { get; set; } public SearchCriteriaBase Query { get; set; } - public long Time { get; set; } - public bool Successful { get; set; } - public int? Results { get; set; } + public IndexerQueryResult QueryResult { get; set; } - public IndexerQueryEvent(int indexerId, SearchCriteriaBase query, long time, bool successful, int? results = null) + public IndexerQueryEvent(int indexerId, SearchCriteriaBase query, IndexerQueryResult result) { IndexerId = indexerId; Query = query; - Time = time; - Successful = successful; - Results = results; + QueryResult = result; } } } diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index c07af6852..f69755bc3 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -220,7 +220,7 @@ namespace NzbDrone.Core.Indexers } catch (TooManyRequestsException ex) { - result.Queries.Add(new IndexerQueryResult { ElapsedTime = ex.Response.ElapsedTime, StatusCode = (int)ex.Response.StatusCode }); + result.Queries.Add(new IndexerQueryResult { Response = ex.Response }); if (ex.RetryAfter != TimeSpan.Zero) { @@ -235,13 +235,13 @@ namespace NzbDrone.Core.Indexers } catch (HttpException ex) { - result.Queries.Add(new IndexerQueryResult { ElapsedTime = ex.Response.ElapsedTime, StatusCode = (int)ex.Response.StatusCode }); + result.Queries.Add(new IndexerQueryResult { Response = ex.Response }); _indexerStatusService.RecordFailure(Definition.Id); _logger.Warn("{0} {1}", this, ex.Message); } catch (RequestLimitReachedException ex) { - result.Queries.Add(new IndexerQueryResult { ElapsedTime = ex.Response.HttpResponse.ElapsedTime, StatusCode = (int)ex.Response.HttpResponse.StatusCode }); + result.Queries.Add(new IndexerQueryResult { Response = ex.Response.HttpResponse }); _indexerStatusService.RecordFailure(Definition.Id, TimeSpan.FromHours(1)); _logger.Warn("API Request Limit reached for {0}", this); } @@ -252,7 +252,7 @@ namespace NzbDrone.Core.Indexers } catch (CloudFlareCaptchaException ex) { - result.Queries.Add(new IndexerQueryResult { ElapsedTime = ex.Response.ElapsedTime, StatusCode = (int)ex.Response.StatusCode }); + result.Queries.Add(new IndexerQueryResult { Response = ex.Response }); _indexerStatusService.RecordFailure(Definition.Id); ex.WithData("FeedUrl", url); if (ex.IsExpired) @@ -266,7 +266,7 @@ namespace NzbDrone.Core.Indexers } catch (IndexerException ex) { - result.Queries.Add(new IndexerQueryResult { ElapsedTime = ex.Response.HttpResponse.ElapsedTime, StatusCode = (int)ex.Response.HttpResponse.StatusCode }); + result.Queries.Add(new IndexerQueryResult { Response = ex.Response.HttpResponse }); _indexerStatusService.RecordFailure(Definition.Id); _logger.Warn(ex, "{0}", url); } @@ -308,8 +308,7 @@ namespace NzbDrone.Core.Indexers return new IndexerQueryResult { Releases = releases, - ElapsedTime = response.HttpResponse.ElapsedTime, - StatusCode = (int)response.HttpResponse.StatusCode + Response = response.HttpResponse }; } catch (Exception ex) diff --git a/src/NzbDrone.Core/Indexers/IndexerQueryResult.cs b/src/NzbDrone.Core/Indexers/IndexerQueryResult.cs index f84a914b5..4bddb8f5d 100644 --- a/src/NzbDrone.Core/Indexers/IndexerQueryResult.cs +++ b/src/NzbDrone.Core/Indexers/IndexerQueryResult.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using NzbDrone.Common.Http; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers @@ -11,7 +12,6 @@ namespace NzbDrone.Core.Indexers } public IList<ReleaseInfo> Releases { get; set; } - public long ElapsedTime { get; set; } - public int StatusCode { get; set; } + public HttpResponse Response { get; set; } } } From 8bce43ac29b34b69723df2670f8b3092fb26edfe Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 22 Nov 2021 15:14:24 -0600 Subject: [PATCH 0179/2320] Fixed: (Cardigann) Poster & tmbid are Optional by default missed jackett commit f5802306fa1fe4edb4c7f997100a6caebe71e989 Fixes #629 --- .../Indexers/Definitions/Cardigann/CardigannBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index b7a4eb87c..8a4d0268b 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.Indexers.Cardigann protected readonly List<CategoryMapping> _categoryMapping = new List<CategoryMapping>(); protected readonly List<string> _defaultCategories = new List<string>(); - protected readonly string[] OptionalFields = new string[] { "imdb", "imdbid", "rageid", "tvdbid", "banner", "description" }; + protected readonly string[] OptionalFields = new string[] { "imdb", "imdbid", "rageid", "tmdbid", "tvdbid", "poster", "banner", "description" }; protected static readonly string[] _SupportedLogicFunctions = { From 51f8b1b5c43b3df94d025cd117ca976d69b8574c Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 23 Nov 2021 10:17:23 -0600 Subject: [PATCH 0180/2320] Fixed: (Nebulance) Handle null poster --- src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs index 71327650c..a3b1da8ab 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs @@ -242,7 +242,7 @@ namespace NzbDrone.Core.Indexers.Definitions Title = title, Guid = details, InfoUrl = details, - PosterUrl = poster.AbsoluteUri, + PosterUrl = poster?.AbsoluteUri ?? null, DownloadUrl = link, Categories = new List<IndexerCategory> { TvCategoryFromQualityParser.ParseTvShowQuality(title) }, Size = size, From 44f12d9569035ce2e5a2fcb156eabd8afae0665a Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 20 Nov 2021 12:38:18 -0600 Subject: [PATCH 0181/2320] Fixed: (RarBG) Do not cleanse get_token --- .../InstrumentationTests/CleanseLogMessageFixture.cs | 1 + src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs index 2ba4a776b..88e28acbc 100644 --- a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs +++ b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs @@ -119,6 +119,7 @@ namespace NzbDrone.Common.Test.InstrumentationTests } [TestCase(@"https://www.torrentleech.org/torrents/browse/list/imdbID/tt8005374/categories/29,2,26,27,32,44,7,34,35")] + [TestCase(@"https://torrentapi.org/pubapi_v2.php?get_token=get_token&app_id=Prowlarr")] public void should_not_clean_url(string message) { var cleansedMessage = CleanseLogMessage.Cleanse(message); diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index 8d79f2c97..3353b7f1d 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -12,7 +12,7 @@ namespace NzbDrone.Common.Instrumentation { // Url new Regex(@"(?<=[?&: ;])(apikey|(?:access[-_]?)?token|pass(?:key|wd)?|auth|authkey|user|u?id|api|[a-z_]*apikey|account|pwd)=(?<secret>[^&=]+?)(?= |&|$|<)", RegexOptions.Compiled | RegexOptions.IgnoreCase), - new Regex(@"(?<=[?& ])[^=]*?(_?(?<!use)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"(?<=[?& ])[^=]*?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"rss\.torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"rss\.torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), From cd7c73bad34a453aa8bf16175fbd845313322a5c Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 23 Nov 2021 18:18:00 -0600 Subject: [PATCH 0182/2320] Fixed: Indexer not removed in UI when deleted Indexer doesn't get removed because createAjaxReqest expects JSON type return, however after net6 provider delete event returns text/html type. --- frontend/src/Store/Actions/Creators/createRemoveItemHandler.js | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/Store/Actions/Creators/createRemoveItemHandler.js b/frontend/src/Store/Actions/Creators/createRemoveItemHandler.js index dfe29ace8..286469d57 100644 --- a/frontend/src/Store/Actions/Creators/createRemoveItemHandler.js +++ b/frontend/src/Store/Actions/Creators/createRemoveItemHandler.js @@ -14,6 +14,7 @@ function createRemoveItemHandler(section, url) { const ajaxOptions = { url: `${url}/${id}?${$.param(queryParams, true)}`, + dataType: 'text', method: 'DELETE' }; From 0fd411a37f7a0581d90abc2a3d67fd1786ee888a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 25 Nov 2021 09:08:51 -0600 Subject: [PATCH 0183/2320] Fixed: Default Cardigann to DownloadUrl GUID --- .../Indexers/Definitions/Cardigann/CardigannParser.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index bcf2bf5f2..e97ff8b75 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -385,6 +385,8 @@ namespace NzbDrone.Core.Indexers.Cardigann value = release.DownloadUrl; } + release.Guid = value; + break; case "magnet": var magnetUri = value; @@ -397,7 +399,6 @@ namespace NzbDrone.Core.Indexers.Cardigann case "details": var url = ResolvePath(value, searchUrlUri)?.AbsoluteUri; release.InfoUrl = url; - release.Guid = url; value = url.ToString(); break; case "comments": From 510ccf4bcef1ef2ca4a1556720f1cc6d6bbd1aa6 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 25 Nov 2021 09:10:16 -0600 Subject: [PATCH 0184/2320] New: Set GUID in IndexerBase if Indexer doesn't set it explicitly --- src/NzbDrone.Core/Indexers/IndexerBase.cs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/IndexerBase.cs b/src/NzbDrone.Core/Indexers/IndexerBase.cs index 2e9f3058a..75717c1b5 100644 --- a/src/NzbDrone.Core/Indexers/IndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/IndexerBase.cs @@ -105,10 +105,27 @@ namespace NzbDrone.Core.Indexers protected virtual IList<ReleaseInfo> CleanupReleases(IEnumerable<ReleaseInfo> releases) { - var result = releases.DistinctBy(v => v.Guid).ToList(); + var result = releases.ToList(); result.ForEach(c => { + //Set GUID if not set + if (c.Guid.IsNullOrWhiteSpace()) + { + if (c.DownloadUrl.IsNotNullOrWhiteSpace()) + { + c.Guid = c.DownloadUrl; + } + else if (Protocol == DownloadProtocol.Torrent && ((TorrentInfo)c).MagnetUrl.IsNotNullOrWhiteSpace()) + { + c.Guid = ((TorrentInfo)c).MagnetUrl; + } + else if (c.InfoUrl.IsNotNullOrWhiteSpace()) + { + c.Guid = c.InfoUrl; + } + } + //Set common props c.IndexerId = Definition.Id; c.Indexer = Definition.Name; @@ -122,7 +139,7 @@ namespace NzbDrone.Core.Indexers } }); - return result; + return result.DistinctBy(v => v.Guid).ToList(); } protected TSettings GetDefaultBaseUrl(TSettings settings) From cda373f195938b1a10bc6ae39001922993a3abac Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Thu, 25 Nov 2021 13:03:22 +0000 Subject: [PATCH 0185/2320] Translated using Weblate (Finnish) Currently translated at 99.5% (445 of 447 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (447 of 447 strings) Translated using Weblate (Finnish) Currently translated at 99.5% (445 of 447 strings) Translated using Weblate (German) Currently translated at 95.3% (426 of 447 strings) Co-authored-by: Csaba <csab0825@gmail.com> Co-authored-by: Don-Chris <Chr_Sch@t-online.de> Co-authored-by: Oskari Lavinto <olavinto@protonmail.com> Co-authored-by: Weblate <noreply@weblate.org> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/de.json | 6 +- src/NzbDrone.Core/Localization/Core/fi.json | 252 ++++++++++---------- src/NzbDrone.Core/Localization/Core/hu.json | 8 +- 3 files changed, 138 insertions(+), 128 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/de.json b/src/NzbDrone.Core/Localization/Core/de.json index 7e451b681..4941bc708 100644 --- a/src/NzbDrone.Core/Localization/Core/de.json +++ b/src/NzbDrone.Core/Localization/Core/de.json @@ -425,5 +425,9 @@ "IndexerProxyStatusCheckAllClientMessage": "Alle Indexer sind aufgrund von Fehlern nicht verfügbar", "IndexerProxyStatusCheckSingleClientMessage": "Listen aufgrund von Fehlern nicht verfügbar: {0}", "UnableToAddANewIndexerProxyPleaseTryAgain": "Der neue Indexer konnte nicht hinzugefügt werden, bitte erneut probieren.", - "DeleteIndexerProxyMessageText": "Tag '{0}' wirklich löschen?" + "DeleteIndexerProxyMessageText": "Tag '{0}' wirklich löschen?", + "AudioSearch": "Audio Suche", + "AddIndexerProxy": "Indexer Proxy hinzufügen", + "AppSettingsSummary": "Anwendungen und Einstellungen um zu konfigurieren, wie Prowlarr mit deinen PVR Programmen interagiert", + "DeleteIndexerProxy": "Indexer Proxy löschen" } diff --git a/src/NzbDrone.Core/Localization/Core/fi.json b/src/NzbDrone.Core/Localization/Core/fi.json index 70f21cc25..0e3e6719e 100644 --- a/src/NzbDrone.Core/Localization/Core/fi.json +++ b/src/NzbDrone.Core/Localization/Core/fi.json @@ -5,41 +5,41 @@ "MovieIndexScrollTop": "Elokuvahakemisto: Vieritä yläreunaan", "Apply": "Käytä", "ClientPriority": "Lataustyökalun painotus", - "EnabledHelpText": "Käytä tätä listaa Prowlarissa", - "IndexerPriorityHelpText": "Indeksoinnin painotus: 1 (korkein) - 50 (matalin). Oletusarvo on 25.", + "EnabledHelpText": "Käytä tätä tuontilistaa.", + "IndexerPriorityHelpText": "Tietolähteen painotus: 1 (korkein) - 50 (matalin). Oletusarvo on 25.", "Manual": "Manuaalinen", "Add": "Lisää", "Reload": "Lataa uudelleen", - "Indexers": "Indeksoinnit", + "Indexers": "Tietolähteet", "MovieIndexScrollBottom": "Elokuvahakemisto: Vieritä alareunaan", "Movies": "Elokuvat", - "PtpOldSettingsCheckMessage": "Seuraavat PassThePopcorn-indeksoinnit sisältävät vanhentuneita asetuksia, jotka olisi syytä päivittää: {0}", - "QualityDefinitions": "Laatumääritelmät", + "PtpOldSettingsCheckMessage": "Seuraavat PassThePopcorn-tietolähteet sisältävät vanhentuneita asetuksia, jotka olisi syytä päivittää: {0}", + "QualityDefinitions": "Laatumääritykset", "SSLCertPassword": "SSL-varmenteen salasana", "Style": "Tyyli", - "Tags": "Tagit", + "Tags": "Tunnisteet", "Today": "Tänään", "About": "Tietoja", "AcceptConfirmationModal": "Hyväksy vahvistus", "Actions": "Toiminnot", "ApplicationStatusCheckAllClientMessage": "Sovellukset eivät ole käytettävissä virheiden vuoksi", "ApplicationStatusCheckSingleClientMessage": "Sovellukset eivät ole käytettävissä virheiden vuoksi: {0}", - "Date": "Päivämäärä", + "Date": "Päiväys", "Dates": "Päiväykset", "SettingsTimeFormat": "Ajan esitystapa", "Message": "Viesti", "Seeders": "Jakajat", - "TestAll": "Koesta kaikki", + "TestAll": "Testaa kaikki", "AddDownloadClient": "Lisää lataustyökalu", - "CustomFilters": "Omat suodattimet", - "DeleteIndexer": "Poista indeksointi", - "DeleteTag": "Poista tagi", + "CustomFilters": "Mukautetut suodattimet", + "DeleteIndexer": "Poista tietolähde", + "DeleteTag": "Poista tunniste", "DownloadClientCheckNoneAvailableMessage": "Lataustyökaluja ei ole käytettävissä", - "EnableRss": "Käytä RSS-syötettä", + "EnableRss": "RSS-syöte", "Filter": "Suodata", - "Fixed": "Kiinteä", + "Fixed": "Korjattu", "FocusSearchBox": "Kohdista hakukenttä", - "ForMoreInformationOnTheIndividualDownloadClients": "Saat lisätietoja yksittäisestä lataustyökalusta painamalla lisätietopainikkeita.", + "ForMoreInformationOnTheIndividualDownloadClients": "Lue lisää lataustyökalusta painamalla 'Lisätietoja'.", "HideAdvanced": "Piilota lisäasetukset", "History": "Historia", "MIA": "Puuttuu", @@ -58,11 +58,11 @@ "Settings": "Asetukset", "SettingsLongDateFormat": "Päiväyksen pitkä esitystapa", "SettingsShortDateFormat": "Päiväyksen lyhyt esitystapa", - "UnselectAll": "Tyhjennä kaikki valinnat", + "UnselectAll": "Poista kaikkien valinta", "UpdateCheckStartupTranslocationMessage": "Päivitystä ei voi asentaa, koska käynnistyskansio '{0}' sijaitsee 'App Translocation' -kansiossa.", "UpdateCheckUINotWritableMessage": "Päivitystä ei voi asentaa, koska käyttäjällä '{1}' ei ole kirjoitusoikeutta käyttöliittymäkansioon '{0}'.", - "UpdateMechanismHelpText": "Käytä Prowlarrin sisäänrakennettua päivitystoimintoa tai omaa komentosarjaa", - "ApplyTagsHelpTexts3": "Poista: Poista syötetyt tagit", + "UpdateMechanismHelpText": "Käytä Prowlarrin sisäänrakennettua päivitystoimintoa tai omaa komentosarjaasi.", + "ApplyTagsHelpTexts3": "– 'Poista' ainoastaan syötetyt tunnisteet", "Enable": "Käytä", "UI": "Käyttöliittymä", "UrlBaseHelpText": "Käänteisen välityspalvelimen tuki (esim. 'http://[host]:[port]/[urlBase]'). Oletus on tyhjä.", @@ -77,13 +77,13 @@ "UseProxy": "Käytä välityspalvelinta", "Username": "Käyttäjätunnus", "YesCancel": "Kyllä, peruuta", - "NoTagsHaveBeenAddedYet": "Tageja ei ole vielä lisätty", - "ApplyTags": "Käytä tageja", + "NoTagsHaveBeenAddedYet": "Tunnisteita ei ole vielä lisätty", + "ApplyTags": "Toimenpide tunnisteille", "Authentication": "Todennus", "AuthenticationMethodHelpText": "Vaadi Prowlarrin käyttöön käyttäjätunnus ja salasana", "BindAddressHelpText": "Toimiva IPv4-osoite tai jokerimerkkinä '*' (tähti) kaikille yhteyksille.", "Close": "Sulje", - "DeleteNotification": "Poista ilmoitus", + "DeleteNotification": "Poista kytkentä", "Docker": "Docker", "DownloadClient": "Lataustyökalu", "EnableMediaInfoHelpText": "Pura videotiedostoista tietoja, kuten videon resoluutio, kesto ja koodekki. Tätä varten Prowlarrin on luettava tiedostoja osittain ja tämä saattaa aiheuttaa korkeampaa levyn ja/tai verkon kuormitusta tarkistusten aikana.", @@ -125,25 +125,25 @@ "ReleaseStatus": "Julkaisutila", "RemovedFromTaskQueue": "Poistettu tehtäväjonosta", "RemoveFilter": "Poista suodatin", - "RemovingTag": "Poistetaan tagia", + "RemovingTag": "Tunniste poistetaan", "Reset": "Uudista", "ResetAPIKey": "Uudista API-avain", "Restart": "Käynnistä uudelleen", "RestartNow": "Käynnistä uudelleen nyt", "Restore": "Palauta", "RSS": "RSS", - "RSSIsNotSupportedWithThisIndexer": "Tämä indeksointi ei tue RSS-syötteitä", + "RSSIsNotSupportedWithThisIndexer": "RSS-syötettä ei ole käytettävissä tälle tietolähteelle", "ScriptPath": "Komentosarjan sijainti", "Security": "Suojaus", "SuggestTranslationChange": "Ehdota käännösmuutosta", "System": "Järjestelmä", "SystemTimeCheckMessage": "Järjestelmän aika on heittä yli vuorokauden verran. Ajoitetut tehtävät eivät luultavasti toimi oikein ennen ajan korjausta.", - "TagCannotBeDeletedWhileInUse": "Tagia ei voi poistaa, koska se on käytössä", - "TagIsNotUsedAndCanBeDeleted": "Tagi ei ole käytössä, joten sen voi poistaa", - "TagsSettingsSummary": "Näytä kaikki tagit ja niiden käyttökohteet. Käyttämättömät tagit voi poistaa.", + "TagCannotBeDeletedWhileInUse": "Tunnistetta ei voi poistaa, koska se on käytössä", + "TagIsNotUsedAndCanBeDeleted": "Tunnistetta ei ole määritetty millekään kohteelle, joten sen voi poistaa.", + "TagsSettingsSummary": "Täältä näet kaikki tunnisteet käyttökohteineen ja voit poistaa sellaiset tunnisteet, joita ei ole määritetty millekään kohteelle.", "Tasks": "Tehtävät", - "Test": "Koesta", - "TestAllClients": "Koesta kaikki lataustyökalut", + "Test": "Kokeile", + "TestAllClients": "Testaa kaikki lataustyökalut", "Time": "Aika", "Title": "Nimi", "Tomorrow": "Huomenna", @@ -152,26 +152,26 @@ "Type": "Tyyppi", "UILanguage": "Käyttöliittymän kieli", "UnableToAddANewApplicationPleaseTryAgain": "Uuden sovelluksen lisäys epäonnistui. Yritä uudelleen.", - "UnableToAddANewIndexerPleaseTryAgain": "Uuden indeksoinnin lisäys epäonnistui. Yritä uudelleen.", - "UnableToAddANewIndexerProxyPleaseTryAgain": "Uuden indeksoinnin välityspalvelimen lisäys epäonnistui. Yritä uudelleen.", - "UnableToLoadBackups": "Varmuuskopioiden lataus epäonnistui", - "UnableToLoadDownloadClients": "Lataustyökalujen lataus epäonnistui", - "UnableToLoadGeneralSettings": "Yleisten asetusten lataus epäonnistui", + "UnableToAddANewIndexerPleaseTryAgain": "Uuden tietolähteen lisäys epäonnistui. Yritä uudelleen.", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Uuden tietolähdevälityspalvelimen lisäys epäonnistui. Yritä uudelleen.", + "UnableToLoadBackups": "Varmuuskopioiden lataus epäonnistui.", + "UnableToLoadDownloadClients": "Lataustyökalujen lataus epäonnistui.", + "UnableToLoadGeneralSettings": "Yleisten asetusten lataus epäonnistui.", "UpdateAutomaticallyHelpText": "Lataa ja asenna päivitykset automaattisesti. Voit silti asentaa ne myös lähteestä System:Updates.", "Added": "Lisätty", - "AddIndexer": "Lisää indeksointi", - "AddingTag": "Lisätään tagia", + "AddIndexer": "Lisää tietolähde", + "AddingTag": "Tunniste lisätään", "Age": "Ikä", "All": "Kaikki", - "AllIndexersHiddenDueToFilter": "Aktiivinen suodatin on piilottanut kaikki indeksoinnit.", + "AllIndexersHiddenDueToFilter": "Aktiivinen suodatin on piilottanut kaikki tietolähteet.", "Analytics": "Analytiikka", "AnalyticsEnabledHelpText": "Lähetä nimettömiä käyttö- ja virhetietoja Prowlarin palvelimille. Tämä sisältää tietoja selaimestasi, verkkokäyttöliittymän sivujen käytöstä, virheraportoinnista sekä käyttöjärjestelmästäsi ja versiosta. Käytämme näitä tietoja ominaisuuksien ja virhekorjauksien painotukseen.", "ApiKey": "API-avain", "AppDataDirectory": "AppData-kansio", "DBMigration": "Tietokannan siirto", "Delete": "Poista", - "DeleteIndexerProxyMessageText": "Haluatko varmasti poistaa välityspalvelimen \"{0}\"?", - "DeleteNotificationMessageText": "Haluatko varmasti poistaa ilmoituksen '{0}'?", + "DeleteIndexerProxyMessageText": "Haluatko varmasti poistaa välityspalvelimen '{0}'?", + "DeleteNotificationMessageText": "Haluatko varmasti poistaa kytkennän '{0}'?", "Disabled": "Ei käytössä", "DownloadClientCheckUnableToCommunicateMessage": "Lataustyökalun '{0}' kanssa ei voida viestiä.", "DownloadClients": "Lataustyökalut", @@ -184,45 +184,45 @@ "MoreInfo": "Lisätietoja", "SelectAll": "Valitse kaikki", "SendAnonymousUsageData": "Lähetä nimettömiä käyttötietoja", - "SetTags": "Määritä tageja", - "SettingsEnableColorImpairedMode": "Käytä heikentyneelle värinäölle sopivaa tilaa", + "SetTags": "Tunnisteiden määritys", + "SettingsEnableColorImpairedMode": "Heikentyneen värinäön tila", "ShowAdvanced": "Näytä lisäasetukset", - "ShowSearchHelpText": "Näytä hakupainike osoitettaessa", + "ShowSearchHelpText": "Näytä hakupainike osoitettaessa.", "Shutdown": "Sammuta", "Size": "Koko", "Sort": "Järjestä", "UnableToAddANewDownloadClientPleaseTryAgain": "Uuden lataustyökalun lisäys epäonnistui. Yitä uudelleen.", - "AppDataLocationHealthCheckMessage": "Päivitystä ei sallita, jotta voidaan estää AppData-kansion poisto päivityksen yhteydessä.", - "UnableToLoadHistory": "Historian lataus epäonnistui", - "UnableToLoadIndexers": "Indeksointien lataus epäonnistui", - "UnableToLoadNotifications": "Ilmoitusten lataus epäonnistui", - "UnableToLoadQualityDefinitions": "Laatumääritelmien lataus epäonnistui", - "UnableToLoadTags": "Tagien lataus epäonnistui", - "UnableToLoadUISettings": "Käyttöliittymän asetusten lataus epäonnistui", + "AppDataLocationHealthCheckMessage": "Päivitystä ei sallita, jotta AppData-kansion poisto päivityksen yhteydessä voidaan estää.", + "UnableToLoadHistory": "Historian lataus epäonnistui.", + "UnableToLoadIndexers": "Tietolähteiden lataus epäonnistui.", + "UnableToLoadNotifications": "Kytkentöjen lataus epäonnistui.", + "UnableToLoadQualityDefinitions": "Laatumäärityksien lataus epäonnistui.", + "UnableToLoadTags": "Tunnisteiden lataus epäonnistui.", + "UnableToLoadUISettings": "Käyttöliittymän asetuksien lataus epäonnistui.", "UnsavedChanges": "Tallentamattomia muutoksia", "Yesterday": "Eilen", "ConnectionLost": "Yhteys on katkennut", - "ConnectionLostAutomaticMessage": "Radarr pyrkii muodostamaan yhteyden automaattisesti tai voit painaa alta \"Lataa uudelleen\".", + "ConnectionLostAutomaticMessage": "Prowlarr pyrkii muodostamaan yhteyden automaattisesti tai voit painaa alta \"Lataa uudelleen\".", "DeleteDownloadClientMessageText": "Haluatko varmasti poistaa lataustyökalun '{0}'?", - "DeleteTagMessageText": "Haluatko varmasti poistaa tagin '{0}'?", + "DeleteTagMessageText": "Haluatko varmasti poistaa tunnisteen '{0}'?", "Discord": "Discord", "Donations": "Lahjoitukset", "DownloadClientUnavailable": "Lataustyökalu ei ole käytettävissä", "Downloading": "Ladataan", "Edit": "Muokkaa", - "EnableAutomaticSearchHelpText": "Käytetään, kun automaattiset haut suoritetaan käyttöliittymästä tai Prowlarin toimesta", - "EnableAutomaticSearchHelpTextWarning": "Käytetään vuorovaikutteisen haun yhteydessä", - "EnableColorImpairedModeHelpText": "Muokattu tyyli käyttäjille, joiden värinäkö on heikentynyt", + "EnableAutomaticSearchHelpText": "Profiilia käytetään automaattihaun yhteydessä, kun sellainen suoritetaan käyttöliittymästä tai Prowlarin toimesta.", + "EnableAutomaticSearchHelpTextWarning": "Profiilia käytetään vuorovaikutteisen haun yhteydessä.", + "EnableColorImpairedModeHelpText": "Muokattu tyyli käyttäjille, joiden värinäkö on heikentynyt. Auttaa erottamaan värikoodatun tiedon.", "Enabled": "Käytössä", - "EnableInteractiveSearchHelpTextWarning": "Hakua ei tueta tällä indeksoinnilla", + "EnableInteractiveSearchHelpTextWarning": "Tämä tietolähde ei tue hakua", "EventType": "Tapahtumatyyppi", "Exception": "Poikkeus", - "FeatureRequests": "Ominaisuusehdotukset", + "FeatureRequests": "Kehitysehdotukset", "Grabbed": "Siepattu", "IgnoredAddresses": "Ohitetut osoitteet", "IllRestartLater": "Käynnistän uudelleen myöhemmin", "Info": "Tiedot", - "LaunchBrowserHelpText": " Avaa Radarrin sivusto verkkoselaimeen sovelluksen käynnistyessä.", + "LaunchBrowserHelpText": " Avaa Prowlarrin verkkokäyttöliittymä verkkoselaimeen sovelluksen käynnistyksen yhteydessä.", "MinimumLimits": "Vähimmäismäärät", "NoChanges": "Ei muutoksia", "NoLeaveIt": "Ei, anna olla", @@ -232,7 +232,7 @@ "SaveChanges": "Tallenna muutokset", "SaveSettings": "Tallenna asetukset", "Scheduled": "Ajoitettu", - "SettingsEnableColorImpairedModeHelpText": "Mukautettu tyyli käyttäjille, joilla on heikentynyt värinäkö", + "SettingsEnableColorImpairedModeHelpText": "Muokattu tyyli käyttäjille, joiden värinäkö on heikentynyt. Auttaa erottamaan värikoodatun tiedon.", "SettingsShowRelativeDates": "Näytä suhteutetut päiväykset", "SettingsShowRelativeDatesHelpText": "Näytä suhteutetut (tänään/eilen/yms.) tai absoluuttiset päiväykset", "ShownClickToHide": "Näkyvissä, piilota painamalla", @@ -243,30 +243,30 @@ "StartupDirectory": "Käynnistyskansio", "TableOptions": "Taulukkoasetukset", "TableOptionsColumnsMessage": "Valitse näytettävät sarakkeet ja niiden järjestys", - "TagsHelpText": "Koskee indeksointeja, jotka on merkitty ainakin yhdellä täsmäävällä tagilla.", + "TagsHelpText": "Käytetään vähintään yhdellä täsmäävällä tunnisteella merkityille tietolähteille.", "UnableToAddANewAppProfilePleaseTryAgain": "Uuden sovellusprofiilin lisäys epäonnistui. Yritä uudelleen.", - "UnableToAddANewNotificationPleaseTryAgain": "Uuden ilmoituksen lisäys epäonnistui. Yritä uudelleen.", + "UnableToAddANewNotificationPleaseTryAgain": "Kytkennän lisäys epäonnistui. Yritä uudelleen.", "Version": "Versio", "View": "Näytä", "Warn": "Varoita", "Wiki": "Wiki", - "ApplyTagsHelpTexts1": "Miten tageja lisätään valituille indeksoinneille", - "ApplyTagsHelpTexts2": "Lisää: Lisää tagit olemassa olevaan tagilistaan", - "ApplyTagsHelpTexts4": "Korvaa: Korvaa tagit syötetyillä tageilla (jätä tyjäksi poistaaksesi kaikki tagit)", + "ApplyTagsHelpTexts1": "Tunnisteisiin kohdistettavat toimenpiteet:", + "ApplyTagsHelpTexts2": "– 'Lisää' syötetyt tunnisteet aiempiin tunnisteisiin", + "ApplyTagsHelpTexts4": "– 'Korvaa' kaikki aiemmat tunnisteet tai poista kaikki tunnisteet jättämällä tyhjäksi", "Importing": "Tuodaan", "Port": "Portti", "AreYouSureYouWantToResetYourAPIKey": "Haluatko varmasti uudistaa API-avaimesi?", "Automatic": "Automaattinen", - "AutomaticSearch": "Automaattinen haku", + "AutomaticSearch": "Automaattihaku", "Backup": "Varmuuskopio", "BackupFolderHelpText": "Suhteelliset polut sijaitsevat Prowlarrin AppData-kansiossa", "BackupIntervalHelpText": "Automaattisen varmuuskopioinnin aikaväli", - "BackupRetentionHelpText": "Säilytysjaksoa vanhemmat automaattiset varmuuskopiot poistetaan automaattisesti", + "BackupRetentionHelpText": "Säilytysjaksoa vanhemmat automaattiset varmuuskopiot poistetaan automaattisesti.", "Backups": "Varmuuskopiot", "BeforeUpdate": "Ennen päivitystä", "BindAddress": "Sidososoite", "Branch": "Kehityshaara", - "BranchUpdate": "Haara, jota käytetään Prowlarrin päivitykseen", + "BranchUpdate": "Kehityshaara, jota käytetään Prowlarrin päivityksille.", "BranchUpdateMechanism": "Ulkoisen päivittysmekanismin käyttämä kehityshaara", "BypassProxyForLocalAddresses": "Ohjaa paikalliset osoitteet välityspalvelimen ohi", "Cancel": "Peruuta", @@ -275,7 +275,7 @@ "CertificateValidationHelpText": "Aseta HTTPS-varmenteen vahvistuksen tiukkuus", "ChangeHasNotBeenSavedYet": "Muutosta ei ole vielä tallennettu", "Clear": "Tyhjennä", - "CloneIndexer": "Kloonaa indeksointi", + "CloneIndexer": "Kloonaa tietolähde", "CloneProfile": "Kloonaa profiili", "CloseCurrentModal": "Sulje nykyinen ikkuna", "Columns": "Sarakkeet", @@ -283,54 +283,54 @@ "Connections": "Kytkennät", "ConnectSettings": "Kytkentöjen asetukset", "CouldNotConnectSignalR": "SignalR-kirjastoa ei tavoitettu, eikä käyttöliittymää päivitetä", - "Custom": "Oma", + "Custom": "Mukautettu", "DelayProfile": "Viiveprofiili", "DeleteApplicationMessageText": "Haluatko varmasti poistaa sovelluksen \"{0}\"?", "DeleteBackup": "Poista varmuuskopio", "DeleteBackupMessageText": "Haluatko varmasti poistaa varmuuskopion '{0}'?", "DeleteDownloadClient": "Poista lataustyökalu", - "DeleteIndexerMessageText": "Haluatko varmasti poistaa indeksoinnin '{0}'?", + "DeleteIndexerMessageText": "Haluatko varmasti poistaa tietolähteen '{0}'?", "DownloadClientStatusCheckSingleClientMessage": "Lataustyökalut eivät ole virheiden vuoksi käytettävissä: {0}", - "EditIndexer": "Muokkaa indeksointia", - "EnableAutoHelpText": "Jos käytössä, lisätään tällä listalla olevat elokuvat automaattisesti Prowlariin", - "EnableAutomaticAdd": "Käytä automaattilisäystä", - "EnableAutomaticSearch": "Käytä automaattihakua", - "EnableColorImpairedMode": "Käytä heikentyneelle värinäölle sopivaa tilaa", - "EnableCompletedDownloadHandlingHelpText": "Tuo valmistuneet lataukset lataustyökalusta automaattisesti", - "EnableHelpText": "Käytä metatietotiedostojen luontia tälle metatietotyypille", - "EnableInteractiveSearch": "Käytä vuorovaikutteista hakua", - "EnableInteractiveSearchHelpText": "Käytetään vuorovaikutteisen haun yhteydessä", - "EnableSSL": "Käytä SSL-suojausta", + "EditIndexer": "Muokkaa tietolähdettä", + "EnableAutoHelpText": "Elokuvat tältä tuontilistalta lisätään Prowlarriin automaattisesti.", + "EnableAutomaticAdd": "Automaattilisäys", + "EnableAutomaticSearch": "Automaattihaku", + "EnableColorImpairedMode": "Heikentyneen värinäön tila", + "EnableCompletedDownloadHandlingHelpText": "Tuo valmistuneet lataukset lataustyökalusta automaattisesti.", + "EnableHelpText": "Luo tälle metatietotyypille metatietotiedostot.", + "EnableInteractiveSearch": "Vuorovaikutteinen haku", + "EnableInteractiveSearchHelpText": "Profiilia käytetään vuorovaikutteisen haun yhteydessä.", + "EnableSSL": "SSL-salaus", "EnableSslHelpText": " Käyttöönotto edellyttää uudelleenkäynnistystä järjestelmänvalvojan oikeuksilla", "Error": "Virhe", - "ErrorLoadingContents": "Sisältöä ladattaessa havaittiin virhe", + "ErrorLoadingContents": "Sisällönlatauksen virhe", "Events": "Tapahtumat", "ExistingMovies": "Olemassa olevat elokuva(t)", - "ExistingTag": "Olemassa oleva tagi", + "ExistingTag": "Olemassa oleva tunniste", "Failed": "Epäonnistui", "Filename": "Tiedostonimi", "Files": "Tiedostot", "Folder": "Kansio", "General": "Yleiset", "GeneralSettings": "Yleiset asetukset", - "GeneralSettingsSummary": "Portti, SSL-salaus, käyttäjätunnus/salasana, välityspalvelin, analytiikka ja päivitykset", + "GeneralSettingsSummary": "Portti, SSL-salaus, käyttäjänimi ja salasana, välityspalvelin, analytiikka ja päivitykset.", "Grabs": "Sieppaukset", "Health": "Kunto", "Level": "Taso", - "HealthNoIssues": "Kokoonpanossasi ei ole ongelmia", + "HealthNoIssues": "Kokoonpanossasi ei ole ongelmia.", "HiddenClickToShow": "Piilotettu, näytä painalla", "HomePage": "Verkkosivusto", "Host": "Osoite", "Hostname": "Osoite", "IncludeHealthWarningsHelpText": "Sisällytä kuntovaroitukset", - "Indexer": "Indeksointi", - "IndexerFlags": "Indeksoinnnin liput", - "IndexerLongTermStatusCheckAllClientMessage": "Indeksoinnint eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi", - "IndexerLongTermStatusCheckSingleClientMessage": "Indeksoinnit eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi: {0}", - "IndexerPriority": "Indeksointien painotus", + "Indexer": "Tietolähde", + "IndexerFlags": "Tietolähteen liput", + "IndexerLongTermStatusCheckAllClientMessage": "Tietolähteet eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi", + "IndexerLongTermStatusCheckSingleClientMessage": "Tietolähteet eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi: {0}", + "IndexerPriority": "Tietolähteiden painotus", "IndexerProxyStatusCheckAllClientMessage": "Välityspalvelimet eivät ole käytettävissä virheiden vuoksi", - "IndexerStatusCheckAllClientMessage": "Indeksoinnit eivät ole käytettävissä virheiden vuoksi", - "IndexerStatusCheckSingleClientMessage": "Indeksoinnit eivät ole käytettävissä virheiden vuoksi: {0}", + "IndexerStatusCheckAllClientMessage": "Tietolähteet eivät ole käytettävissä virheiden vuoksi", + "IndexerStatusCheckSingleClientMessage": "Tietolähteet eivät ole käytettävissä virheiden vuoksi: {0}", "NoChange": "Ei muutosta", "NoLimitForAnyRuntime": "Ei toistoajan rajoitusta", "NoLogFiles": "Ei lokitiedostoja", @@ -358,50 +358,50 @@ "UILanguageHelpText": "Prowlarin käyttöliittymä näytetään tällä kielellä", "UILanguageHelpTextWarning": "Selaimen sivupäivitys vaaditaan", "UISettings": "Käyttöliittymän asetukset", - "DownloadClientsSettingsSummary": "Lataustyökalujen asetukset Prowlarr-käyttöliittymästä suoritettavalle haulle", + "DownloadClientsSettingsSummary": "Prowlarrin käyttöliittymästä suoritettavien hakujen yhteydessä käytettävien lataustyökalujen määritykset.", "ProwlarrSupportsAnyDownloadClient": "Prowlarr tukee alla listatuja lataustyökaluja.", - "AddDownloadClientToProwlarr": "Lisäämällä lataustyökalun Prowlarr voi lähettää julkaisut suoraan käyttöliittymästä, kun sisältöä etsitään manuaalisesti.", - "RedirectHelpText": "Uudelleenohjaa indeksoinnin saapuvat latauspyynnöt ja ohjaa sieppaus suoraan sen sijaan, että se välitettäisiin Prowlarin kautta.", + "AddDownloadClientToProwlarr": "Lisäämällä lataustyökalun Prowlarr voi käynnistää lataukset suoraan käyttöliittymästä manuaalisen haun yhteydessä.", + "RedirectHelpText": "Uudelleenohjaa tietolähteeltä saapuvat latauspyynnöt ja ohjaa sieppaus suoraan sen sijaan, että se välitettäisiin Prowlarin kautta.", "FullSync": "Täysi synkronointi", "SyncLevelFull": "Täysi synkronointi: Pitää sovelluksen täysin synkronoituna. Prowlarissa tehdyt muutokset synkronoidaan etäsovellukseen ja kaikki etäsovelluksessa tehdyt muutokset korvataan seuraavan synkronoinnin yhteydessä.", "AppProfile": "Sovellusprofiili", - "EnableIndexer": "Käytä indeksointia", - "FilterPlaceHolder": "Hae indeksoinneista", - "IndexerHealthCheckNoIndexers": "Indeksointeja ei ole käytössä, eikä Prowlarr tuota hakutuloksia", - "IndexerObsoleteCheckMessage": "Indeksoinnit ovat vanhentuneita tai niitä on päivitetty: {0}. Poista ja/tai lisää ne Prowlariin uudelleen.", - "IndexerProxy": "Indeksoinnin välityspalvelin", - "IndexerSettingsSummary": "Määritä useita globaaleita indeksoinnin asetuksia, kuten välityspalvelimia.", - "IndexerVipCheckExpiringClientMessage": "Indeksoinnin VIP-edut erääntyvät pian: {0}", - "ProwlarrSupportsAnyIndexer": "Prowlarr tukee Newznab/Torznab-standardin mukaisten indeksointien lisäksi myös useita muita indeksointeja käyttäen \"Yleinen Newznab\" (usenetille) tai \"Yleinen Torznab\"(torrenteille) -määrityksiä.", - "SettingsIndexerLogging": "Tehostettu indeksointien valvonta", - "AddIndexerProxy": "Lisää indeksoinnin välityspalvelin", + "EnableIndexer": "Tietolähteen tila", + "FilterPlaceHolder": "Hae tietolähteestä", + "IndexerHealthCheckNoIndexers": "Yhtään tietolähdettä ei ole käytössä, eikä Prowlarr tämän vuoksi löydä tuloksia.", + "IndexerObsoleteCheckMessage": "Tietolähteet ovat vanhentuneita tai niitä on päivitetty: {0}. Poista ja/tai lisää ne Prowlariin uudelleen.", + "IndexerProxy": "Tietolähteen välityspalvelin", + "IndexerSettingsSummary": "Määritä useita globaaleita tietolähdeasetuksia, kuten välityspalvelimia.", + "IndexerVipCheckExpiringClientMessage": "Tietolähteen VIP-edut erääntyvät pian: {0}", + "ProwlarrSupportsAnyIndexer": "Prowlarr tukee Newznab- ja Torznab-yhteensopivien tietolähteiden ohella myös useita muita lähteitä vaihtoehdoilla \"Yleinen Newznab\" (Usenetille) ja 'Yleinen Torznab' (torrenteille).", + "SettingsIndexerLogging": "Tehostettu tietolähteiden valvonta", + "AddIndexerProxy": "Lisää tiedonhaun välityspalvelin", "UISettingsSummary": "Päiväyksen ja kielen sekä heikentyneen värinäön asetukset", - "SettingsIndexerLoggingHelpText": "Kirjaa tarkempia tietoja indeksoitien toiminnasta, mukaanlukien vastaukset", - "IndexerTagsHelpText": "Käytä tageja oletusarvoisten lataustyökalujen ja indeksoinnin välityspalvelimien määritykseen tai indeksointiesi organisointiin.", + "SettingsIndexerLoggingHelpText": "Kirjaa tarkempia tietoja tietolähteiden toiminnasta, mukaanlukien vastaukset", + "IndexerTagsHelpText": "Tunnisteiden avulla voit määrittää ensisijaiset lataustyökalut ja tiedonhaun välityspalvelimet sekä järjestellä tietolähteitäsi.", "UnableToLoadAppProfiles": "Sovellusprofiilien lataus epäonnistui", - "AppProfileSelectHelpText": "Sovellusprofiilien avulla voidaan hallinnoida sovellussynkronoinnin RSS-syötteiden sekä automaattihaun ja vuorovaikutteisen haun asetuksia.", + "AppProfileSelectHelpText": "Sovellusprofiilieilla määritetään tietolähteelle sovellussynkronoinnin yhteydessä aktivoitavat hakutavat (RSS/automaatti/vuorovaikutteinen).", "AddAppProfile": "Lisää sovelluksen synkronointiprofiili", "AppProfiles": "Sovellusprofiilit", - "IndexerQuery": "Indeksoinnin kysely", - "IndexerRss": "Indeksoinnin RSS-syöte", - "SearchIndexers": "Hae indeksointeja", + "IndexerQuery": "Tietolähteen kysely", + "IndexerRss": "Tietolähteen RSS-syöte", + "SearchIndexers": "Etsi tietolähteistä", "AddRemoveOnly": "Ainoastaan lisää/poista", - "IndexerVipCheckExpiredClientMessage": "Indeksoinnin VIP-edut ovat erääntyneet: {0}", + "IndexerVipCheckExpiredClientMessage": "Tietolähteen VIP-edut ovat erääntyneet: {0}", "MaintenanceRelease": "Huoltojulkaisu: Virhekorjauksia ja muita parannuksia. Lue lisää Githubin historiasta muutoshistoriasta.", "Query": "Kysely", "Redirect": "Uudelleenohjaus", "RestartProwlarr": "Käynnistä Prowlarr uudelleen", "SyncLevel": "Synkronoinnin laajuus", "SyncLevelAddRemove": "Ainoastaan lisää/poista: Etäsovellus päivitetään, kun sovellus lisätään tai poistetaan Prowlarista.", - "SyncAppIndexers": "Synkronoi sovellusten indeksoinnit", - "TestAllApps": "Koesta kaikki sovellukset", - "UnableToLoadIndexerProxies": "Indeksoinnin välityspalvelimien lataus epäonnistui", + "SyncAppIndexers": "Synkronoi tietolähteet", + "TestAllApps": "Testaa kaikki sovellukset", + "UnableToLoadIndexerProxies": "Tietolähdevälityspalvelinten lataus epäonnistui", "AddedToDownloadClient": "Julkaisu lisättiin lataustyökaluun", - "AddNewIndexer": "Lisää uusi indeksointi", + "AddNewIndexer": "Lisää uusi tietolähde", "AddToDownloadClient": "Lisää julkaisu lataustyökaluun", - "NoSearchResultsFound": "Ei hakutuloksia. Kokeile uutta hakua alta.", + "NoSearchResultsFound": "Tuloksia ei löytynyt. Yritä uutta hakua alta.", "Notification": "Ilmoitus", - "DeleteIndexerProxy": "Poista indeksoinnin välityspalvelin", + "DeleteIndexerProxy": "Poista tiedonhaun välityspalvelin", "Encoding": "Enkoodaus", "MonoNotNetCoreCheckMessage": "Päivitä Prowlar sen .NET Core -versioon", "SettingsLogRotateHelpText": "Lokien tallennuskansiossa säilytettävien lokitiedostojen enimmäismäärä", @@ -409,7 +409,7 @@ "SettingsLogSql": "Kirjaa SQL", "SettingsSqlLoggingHelpText": "Kirjaa kaikki Prowlarrin SQL-kyselyt", "ConnectionLostMessage": "Prowlarr on menettänyt yhteyden taustajärjestelmään ja sivu on päivitettävä toiminnallisuuden palauttamiseksi.", - "ConnectSettingsSummary": "Ilmoitukset ja omat komentosarjat", + "ConnectSettingsSummary": "Ilmoitukset ja omat komentosarjat.", "DevelopmentSettings": "Kehittäjäasetukset", "Description": "Kuvaus", "Id": "Tunniste", @@ -425,14 +425,14 @@ "Category": "Luokitus", "ClearHistory": "Tyhjennä historia", "ClearHistoryMessageText": "Haluatko varmasti tyhjentää kaiken Prowlarr-historian?", - "Connect": "Ilmoitukset", - "EnableRssHelpText": "Käytä indeksoinnille RSS-syötettä", + "Connect": "Kytkennät", + "EnableRssHelpText": "Tietolähde sisällytetään RSS-syötteeseen.", "DeleteApplication": "Poista sovellus", "DeleteAppProfile": "Poista sovellusprofiili", - "IndexerProxies": "Indeksoinnin välityspalvelimet", - "IndexerAuth": "Indeksoinnin todennus", - "IndexersSelectedInterp": "{0} indeksointia valittu", - "Notifications": "Ilmoitukset", + "IndexerProxies": "Tietolähteiden välityspalvelimet", + "IndexerAuth": "Tietolähteen todennus", + "IndexersSelectedInterp": "{0} valittua tietolähdettä", + "Notifications": "Kytkennät", "NotificationTriggersHelpText": "Valitse tapahtumat, jotka laukaisevat tämän ilmoituksen", "Stats": "Tilastot", "UnableToLoadDevelopmentSettings": "Kehittäjäasetusten lataus epäonnistui", @@ -440,10 +440,10 @@ "EditAppProfile": "Muokkaa sovellusprofiilia", "Privacy": "Yksityisyys", "NetCore": ".NET", - "BookSearch": "Kirjahaku", - "SearchType": "Hakutyyppi", - "AudioSearch": "Äänihaku", - "MovieSearch": "Elokuvahaku", + "BookSearch": "Etsi kirjoja", + "SearchType": "Mitä etsitään", + "AudioSearch": "Etsi ääniä", + "MovieSearch": "Etsi elokuvia", "QueryOptions": "Kyselyasetukset", - "TvSearch": "TV-sarjahaku" + "TvSearch": "Etsi televisiosarjoja" } diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index 7ec9c2b49..c3a8e3d52 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -439,5 +439,11 @@ "IndexerVipCheckExpiringClientMessage": "Az Indexer VIP előnyei hamarosan lejárnak: {0}", "IndexerProxy": "Indexelő Proxy", "NoLinks": "Nincsenek Linkek", - "Notification": "Értesítés" + "Notification": "Értesítés", + "BookSearch": "Könyv kereső", + "TvSearch": "TV keresés", + "AudioSearch": "Hang keresés", + "MovieSearch": "Film Kereső", + "QueryOptions": "Lekérdezési beállítások", + "SearchType": "Keresés típusa" } From 60f37de6afc7b2cf4fa59efe629e138c7f3a4ddd Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Thu, 25 Nov 2021 14:54:01 -0600 Subject: [PATCH 0186/2320] Fixed: (Orpheus) Try to actually use the token --- src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs index 5acab3183..2e1b96df5 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs @@ -75,7 +75,7 @@ namespace NzbDrone.Core.Indexers.Definitions // Orpheus fails to download if usetoken=0 so we need to only add if we will use one if (_settings.UseFreeleechToken) { - url = url.AddQueryParam("useToken", "1"); + url = url.AddQueryParam("usetoken", "1"); } return url.FullUri; From 01fe9904176aeaf71ced982c27517f5d2db63a78 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Thu, 11 Nov 2021 12:12:27 -0600 Subject: [PATCH 0187/2320] Update Github Templates [skip ci] (cherry picked from commit beb22844c960db8e0f42a32809ad74cffce06e09) --- .github/ISSUE_TEMPLATE/bug_report.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 5a1141815..ce79e928c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -63,12 +63,11 @@ body: required: true - type: textarea attributes: - label: Anything else? + label: Trace Logs? description: | Trace Logs (https://wiki.servarr.com/prowlarr/troubleshooting#logging-and-log-files) - Links? References? Anything that will give us more context about the issue you are encountering! ***Generally speaking, all bug reports must have trace logs provided.*** - Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. + Additionally, any additional info? Screenshots? References? Anything that will give us more context about the issue you are encountering! validations: required: true From eff8fdebf5fd22625f7b7c574463de78ca48ddcf Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 23 Nov 2021 21:01:04 -0600 Subject: [PATCH 0188/2320] cleanse postgres username/pass creds Fixes #632 --- .../InstrumentationTests/CleanseLogMessageFixture.cs | 3 +++ src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs index 88e28acbc..49da6364c 100644 --- a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs +++ b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs @@ -80,6 +80,9 @@ namespace NzbDrone.Common.Test.InstrumentationTests // RSS [TestCase(@"<atom:link href = ""https://api.nzb.su/api?t=search&extended=1&cat=3030&apikey=mySecret&q=Diggers"" rel=""self"" type=""application/rss+xml"" />")] + // Internal + [TestCase(@"[Info] MigrationController: *** Migrating Database=prowlarr-main;Host=postgres14;Username=mySecret;Password=mySecret;Port=5432;Enlist=False ***")] + public void should_clean_message(string message) { var cleansedMessage = CleanseLogMessage.Cleanse(message); diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index 3353b7f1d..f82cbadc2 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -12,7 +12,7 @@ namespace NzbDrone.Common.Instrumentation { // Url new Regex(@"(?<=[?&: ;])(apikey|(?:access[-_]?)?token|pass(?:key|wd)?|auth|authkey|user|u?id|api|[a-z_]*apikey|account|pwd)=(?<secret>[^&=]+?)(?= |&|$|<)", RegexOptions.Compiled | RegexOptions.IgnoreCase), - new Regex(@"(?<=[?& ])[^=]*?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"(?<=[?& ;])[^=]*?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"rss\.torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"rss\.torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), From d61ce3f27ca131d1c076f0570586a1246cd8e9b6 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 27 Nov 2021 20:50:58 -0600 Subject: [PATCH 0189/2320] Fixed: (Cardigann) Fails when Int variables used in requests --- .../Definitions/MovieSearchCriteria.cs | 6 ++++++ .../IndexerSearch/ReleaseSearchService.cs | 1 + .../Cardigann/CardigannRequestGenerator.cs | 20 +++++++++---------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/MovieSearchCriteria.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/MovieSearchCriteria.cs index 73b688427..c752c3a4b 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/MovieSearchCriteria.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/MovieSearchCriteria.cs @@ -9,6 +9,7 @@ namespace NzbDrone.Core.IndexerSearch.Definitions public string ImdbId { get; set; } public int? TmdbId { get; set; } public int? TraktId { get; set; } + public int? Year { get; set; } public override bool RssSearch { @@ -48,6 +49,11 @@ namespace NzbDrone.Core.IndexerSearch.Definitions builder = builder.Append($" IMDbId:[{ImdbId}]"); } + if (Year.HasValue) + { + builder = builder.Append($" Year:[{Year}]"); + } + if (TmdbId.HasValue) { builder = builder.Append($" TMDbId:[{TmdbId}]"); diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs index 4b49a4f23..14e4bba7c 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs @@ -59,6 +59,7 @@ namespace NzbDrone.Core.IndexerSearch searchSpec.ImdbId = request.imdbid; searchSpec.TmdbId = request.tmdbid; searchSpec.TraktId = request.traktid; + searchSpec.Year = request.year; return new NewznabResults { Releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) }; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 5e5526492..6a369db40 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -46,11 +46,11 @@ namespace NzbDrone.Core.Indexers.Cardigann var variables = GetQueryVariableDefaults(searchCriteria); variables[".Query.Movie"] = null; - variables[".Query.Year"] = null; + variables[".Query.Year"] = searchCriteria.Year?.ToString() ?? null; variables[".Query.IMDBID"] = searchCriteria.FullImdbId; variables[".Query.IMDBIDShort"] = searchCriteria.ImdbId; - variables[".Query.TMDBID"] = searchCriteria.TmdbId; - variables[".Query.TraktID"] = searchCriteria.TraktId; + variables[".Query.TMDBID"] = searchCriteria.TmdbId?.ToString() ?? null; + variables[".Query.TraktID"] = searchCriteria.TraktId?.ToString() ?? null; pageableRequests.Add(GetRequest(variables)); @@ -81,13 +81,13 @@ namespace NzbDrone.Core.Indexers.Cardigann variables[".Query.Series"] = null; variables[".Query.Ep"] = searchCriteria.Episode; - variables[".Query.Season"] = searchCriteria.Season; + variables[".Query.Season"] = searchCriteria.Season?.ToString() ?? null; variables[".Query.IMDBID"] = searchCriteria.FullImdbId; variables[".Query.IMDBIDShort"] = searchCriteria.ImdbId; - variables[".Query.TVDBID"] = searchCriteria.TvdbId; - variables[".Query.TVRageID"] = searchCriteria.RId; - variables[".Query.TVMazeID"] = searchCriteria.TvMazeId; - variables[".Query.TraktID"] = searchCriteria.TraktId; + variables[".Query.TVDBID"] = searchCriteria.TvdbId?.ToString() ?? null; + variables[".Query.TVRageID"] = searchCriteria.RId?.ToString() ?? null; + variables[".Query.TVMazeID"] = searchCriteria.TvMazeId?.ToString() ?? null; + variables[".Query.TraktID"] = searchCriteria.TraktId?.ToString() ?? null; variables[".Query.Episode"] = searchCriteria.EpisodeSearchString; pageableRequests.Add(GetRequest(variables)); @@ -127,8 +127,8 @@ namespace NzbDrone.Core.Indexers.Cardigann variables[".Query.Type"] = searchCriteria.SearchType; variables[".Query.Q"] = searchCriteria.SearchTerm; variables[".Query.Categories"] = searchCriteria.Categories; - variables[".Query.Limit"] = searchCriteria.Limit; - variables[".Query.Offset"] = searchCriteria.Offset; + variables[".Query.Limit"] = searchCriteria.Limit?.ToString() ?? null; + variables[".Query.Offset"] = searchCriteria.Offset?.ToString() ?? null; variables[".Query.Extended"] = null; variables[".Query.APIKey"] = null; From 387f8df0ff5be47765c9e44df1f2cad8e05bf633 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 27 Nov 2021 21:07:42 -0600 Subject: [PATCH 0190/2320] Rework some Cardigann exception handling --- .../Definitions/Cardigann/CardigannParser.cs | 9 +++--- .../Cardigann/CardigannRequestGenerator.cs | 15 +++++---- .../CardigannConfigException.cs | 4 +-- .../Exceptions/CardigannException.cs | 32 +++++++++++++++++++ 4 files changed, 47 insertions(+), 13 deletions(-) rename src/NzbDrone.Core/Indexers/Definitions/Cardigann/{ => Exceptions}/CardigannConfigException.cs (82%) create mode 100644 src/NzbDrone.Core/Indexers/Definitions/Cardigann/Exceptions/CardigannException.cs diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index e97ff8b75..55ac4f3bd 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -10,6 +10,7 @@ using Newtonsoft.Json.Linq; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Definitions.Cardigann.Exceptions; using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; @@ -67,7 +68,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var parsedJson = JToken.Parse(results); if (parsedJson == null) { - throw new Exception("Error Parsing Json Response"); + throw new IndexerException(indexerResponse, "Error Parsing Json Response"); } if (search.Rows.Count != null) @@ -85,7 +86,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var rowsObj = parsedJson.SelectToken(search.Rows.Selector); if (rowsObj == null) { - throw new Exception("Error Parsing Rows Selector"); + throw new IndexerException(indexerResponse, "Error Parsing Rows Selector"); } foreach (var row in rowsObj.Value<JArray>()) @@ -140,7 +141,7 @@ namespace NzbDrone.Core.Indexers.Cardigann continue; } - throw new Exception(string.Format("Error while parsing field={0}, selector={1}, value={2}: {3}", field.Key, field.Value.Selector, value ?? "<null>", ex.Message)); + throw new CardigannException(string.Format("Error while parsing field={0}, selector={1}, value={2}: {3}", field.Key, field.Value.Selector, value ?? "<null>", ex.Message)); } var filters = search.Rows.Filters; @@ -327,7 +328,7 @@ namespace NzbDrone.Core.Indexers.Cardigann if (value == null && dateHeaders.Optional == false) { - throw new Exception(string.Format("No date header row found for {0}", release.ToString())); + throw new CardigannException(string.Format("No date header row found for {0}", release.ToString())); } if (value != null) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 6a369db40..052407c92 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -12,6 +12,7 @@ using NLog; using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Definitions.Cardigann; +using NzbDrone.Core.Indexers.Definitions.Cardigann.Exceptions; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Parser; using NzbDrone.Core.ThingiProvider; @@ -288,7 +289,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } catch (Exception ex) { - throw new Exception(string.Format("Error while parsing selector input={0}, selector={1}, value={2}: {3}", selectorinput.Key, selectorinput.Value.Selector, value, ex.Message)); + throw new CardigannException(string.Format("Error while parsing selector input={0}, selector={1}, value={2}: {3}", selectorinput.Key, selectorinput.Value.Selector, value, ex.Message)); } } } @@ -306,7 +307,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } catch (Exception ex) { - throw new Exception(string.Format("Error while parsing get selector input={0}, selector={1}, value={2}: {3}", selectorinput.Key, selectorinput.Value.Selector, value, ex.Message)); + throw new CardigannException(string.Format("Error while parsing get selector input={0}, selector={1}, value={2}: {3}", selectorinput.Key, selectorinput.Value.Selector, value, ex.Message)); } } } @@ -763,13 +764,13 @@ namespace NzbDrone.Core.Indexers.Cardigann var hash = MatchSelector(response, download.Infohash.Hash, variables); if (hash == null) { - throw new Exception($"InfoHash selectors didn't match"); + throw new CardigannException($"InfoHash selectors didn't match"); } var title = MatchSelector(response, download.Infohash.Title, variables); if (title == null) { - throw new Exception($"InfoHash selectors didn't match"); + throw new CardigannException($"InfoHash selectors didn't match"); } var magnet = MagnetLinkBuilder.BuildPublicMagnetLink(hash, title); @@ -846,7 +847,7 @@ namespace NzbDrone.Core.Indexers.Cardigann { _logger.Error("{0} CardigannIndexer ({1}): An exception occurred while trying selector {2}, retrying with next available selector", e, _definition.Id, queryselector); - throw new Exception(string.Format("An exception occurred while trying selector {0}", queryselector)); + throw new CardigannException(string.Format("An exception occurred while trying selector {0}", queryselector)); } } } @@ -888,7 +889,7 @@ namespace NzbDrone.Core.Indexers.Cardigann val = element.GetAttribute(selector.Attribute); if (val == null) { - throw new Exception($"Attribute \"{selector.Attribute}\" is not set for element {element.ToHtmlPretty()}"); + throw new CardigannException($"Attribute \"{selector.Attribute}\" is not set for element {element.ToHtmlPretty()}"); } } else @@ -909,7 +910,7 @@ namespace NzbDrone.Core.Indexers.Cardigann { var errormessage = "Got redirected to another domain. Try changing the indexer URL to " + domainHint + "."; - throw new Exception(errormessage); + throw new CardigannException(errormessage); } return true; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannConfigException.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Exceptions/CardigannConfigException.cs similarity index 82% rename from src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannConfigException.cs rename to src/NzbDrone.Core/Indexers/Definitions/Cardigann/Exceptions/CardigannConfigException.cs index e8057e991..5986ec0fe 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannConfigException.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Exceptions/CardigannConfigException.cs @@ -1,9 +1,9 @@ using NzbDrone.Common.Exceptions; using NzbDrone.Core.Indexers.Cardigann; -namespace NzbDrone.Core.Indexers.Definitions.Cardigann +namespace NzbDrone.Core.Indexers.Definitions.Cardigann.Exceptions { - public class CardigannConfigException : NzbDroneException + public class CardigannConfigException : CardigannException { private readonly CardigannDefinition _configuration; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Exceptions/CardigannException.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Exceptions/CardigannException.cs new file mode 100644 index 000000000..18ee3644d --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Exceptions/CardigannException.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NzbDrone.Common.Exceptions; + +namespace NzbDrone.Core.Indexers.Definitions.Cardigann.Exceptions +{ + public class CardigannException : NzbDroneException + { + public CardigannException(string message) + : base(message) + { + } + + public CardigannException(string message, params object[] args) + : base(message, args) + { + } + + public CardigannException(string message, Exception innerException) + : base(message, innerException) + { + } + + public CardigannException(string message, Exception innerException, params object[] args) + : base(message, innerException, args) + { + } + } +} From 10aa3e43a2d68f9c07b5d8802d030c7f50a10911 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 27 Nov 2021 21:46:55 -0600 Subject: [PATCH 0191/2320] Fixed: (Cardigann) Use correct encoding for Auth and Download calls --- .../Http/HttpRequestBuilder.cs | 10 +++++++ .../Cardigann/CardigannRequestGenerator.cs | 30 +++++++++++++------ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/NzbDrone.Common/Http/HttpRequestBuilder.cs b/src/NzbDrone.Common/Http/HttpRequestBuilder.cs index 249a403e9..644d73908 100644 --- a/src/NzbDrone.Common/Http/HttpRequestBuilder.cs +++ b/src/NzbDrone.Common/Http/HttpRequestBuilder.cs @@ -14,6 +14,7 @@ namespace NzbDrone.Common.Http public HttpAccept HttpAccept { get; set; } public HttpUri BaseUrl { get; private set; } public string ResourceUrl { get; set; } + public Encoding Encoding { get; set; } public List<KeyValuePair<string, string>> QueryParams { get; private set; } public List<KeyValuePair<string, string>> SuffixQueryParams { get; private set; } public Dictionary<string, string> Segments { get; private set; } @@ -37,6 +38,7 @@ namespace NzbDrone.Common.Http BaseUrl = new HttpUri(baseUrl); ResourceUrl = string.Empty; Method = HttpMethod.GET; + Encoding = Encoding.UTF8; QueryParams = new List<KeyValuePair<string, string>>(); SuffixQueryParams = new List<KeyValuePair<string, string>>(); Segments = new Dictionary<string, string>(); @@ -101,6 +103,7 @@ namespace NzbDrone.Common.Http protected virtual void Apply(HttpRequest request) { request.Method = Method; + request.Encoding = Encoding; request.SuppressHttpError = SuppressHttpError; request.UseSimplifiedUserAgent = UseSimplifiedUserAgent; request.AllowAutoRedirect = AllowAutoRedirect; @@ -301,6 +304,13 @@ namespace NzbDrone.Common.Http return this; } + public virtual HttpRequestBuilder SetEncoding(Encoding encoding) + { + Encoding = encoding; + + return this; + } + public virtual HttpRequestBuilder AddPrefixQueryParam(string key, object value, bool replace = false) { if (replace) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 052407c92..5c1d631b4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -187,6 +187,7 @@ namespace NzbDrone.Core.Indexers.Cardigann Method = HttpMethod.POST, AllowAutoRedirect = true, SuppressHttpError = true, + Encoding = _encoding }; foreach (var pair in pairs) @@ -328,7 +329,8 @@ namespace NzbDrone.Core.Indexers.Cardigann var requestBuilder = new HttpRequestBuilder(captchaUrl.ToString()) { LogResponseContent = true, - Method = HttpMethod.GET + Method = HttpMethod.GET, + Encoding = _encoding }; requestBuilder.Headers.Add("Referer", loginUrl); @@ -393,7 +395,8 @@ namespace NzbDrone.Core.Indexers.Cardigann { LogResponseContent = true, Method = HttpMethod.POST, - AllowAutoRedirect = true + AllowAutoRedirect = true, + Encoding = _encoding }; requestBuilder.Headers.Add("Referer", SiteLink); @@ -422,7 +425,8 @@ namespace NzbDrone.Core.Indexers.Cardigann LogResponseContent = true, Method = HttpMethod.POST, AllowAutoRedirect = true, - SuppressHttpError = true + SuppressHttpError = true, + Encoding = _encoding }; requestBuilder.SetCookies(Cookies); @@ -463,7 +467,8 @@ namespace NzbDrone.Core.Indexers.Cardigann { LogResponseContent = true, Method = HttpMethod.GET, - SuppressHttpError = true + SuppressHttpError = true, + Encoding = _encoding }; requestBuilder.Headers.Add("Referer", SiteLink); @@ -487,7 +492,8 @@ namespace NzbDrone.Core.Indexers.Cardigann { LogResponseContent = true, Method = HttpMethod.GET, - SuppressHttpError = true + SuppressHttpError = true, + Encoding = _encoding }; requestBuilder.Headers.Add("Referer", SiteLink); @@ -559,7 +565,8 @@ namespace NzbDrone.Core.Indexers.Cardigann var requestBuilder = new HttpRequestBuilder(loginUrl.AbsoluteUri) { LogResponseContent = true, - Method = HttpMethod.GET + Method = HttpMethod.GET, + Encoding = _encoding }; requestBuilder.Headers.Add("Referer", SiteLink); @@ -613,6 +620,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var request = new HttpRequestBuilder(captchaUrl.ToString()) .SetCookies(landingResult.GetCookies()) .SetHeader("Referer", loginUrl.AbsoluteUri) + .SetEncoding(_encoding) .Build(); var response = await HttpClient.ExecuteProxiedAsync(request, Definition); @@ -693,6 +701,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var httpRequest = new HttpRequestBuilder(requestLinkStr) .SetCookies(Cookies ?? new Dictionary<string, string>()) + .SetEncoding(_encoding) .SetHeader("Referer", referer); httpRequest.Method = method; @@ -731,6 +740,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var request = new HttpRequestBuilder(link.ToString()) .SetCookies(Cookies ?? new Dictionary<string, string>()) .SetHeaders(headers ?? new Dictionary<string, string>()) + .SetEncoding(_encoding) .Build(); request.AllowAutoRedirect = true; @@ -779,6 +789,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var hashDownloadRequest = new HttpRequestBuilder(torrentLink.AbsoluteUri) .SetCookies(Cookies ?? new Dictionary<string, string>()) .SetHeaders(headers ?? new Dictionary<string, string>()) + .SetEncoding(_encoding) .Build(); hashDownloadRequest.Method = method; @@ -819,6 +830,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var testLinkRequest = new HttpRequestBuilder(torrentLink.ToString()) .SetCookies(Cookies ?? new Dictionary<string, string>()) .SetHeaders(headers ?? new Dictionary<string, string>()) + .SetEncoding(_encoding) .Build(); response = await HttpClient.ExecuteProxiedAsync(testLinkRequest, Definition); @@ -837,6 +849,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var selectorDownloadRequest = new HttpRequestBuilder(link.AbsoluteUri) .SetCookies(Cookies ?? new Dictionary<string, string>()) .SetHeaders(headers ?? new Dictionary<string, string>()) + .SetEncoding(_encoding) .Build(); selectorDownloadRequest.Method = method; @@ -856,6 +869,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var downloadRequest = new HttpRequestBuilder(link.AbsoluteUri) .SetCookies(Cookies ?? new Dictionary<string, string>()) .SetHeaders(headers ?? new Dictionary<string, string>()) + .SetEncoding(_encoding) .Build(); downloadRequest.Method = method; @@ -1080,9 +1094,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestbuilder.SetHeaders(headers ?? new Dictionary<string, string>()); } - var request = new CardigannRequest(requestbuilder.Build(), variables, searchPath); - - request.HttpRequest.Encoding = Encoding.GetEncoding(_definition.Encoding); + var request = new CardigannRequest(requestbuilder.SetEncoding(_encoding).Build(), variables, searchPath); yield return request; } From 7ce5df63d4a8b5bca33e4f87102a0105eaded34f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 27 Nov 2021 22:38:52 -0600 Subject: [PATCH 0192/2320] Fixed: (Cardigann) Number normalize to ignore non-digits --- src/NzbDrone.Core/Parser/ParseUtil.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/NzbDrone.Core/Parser/ParseUtil.cs b/src/NzbDrone.Core/Parser/ParseUtil.cs index b6ba7b53b..7868ba102 100644 --- a/src/NzbDrone.Core/Parser/ParseUtil.cs +++ b/src/NzbDrone.Core/Parser/ParseUtil.cs @@ -20,17 +20,19 @@ namespace NzbDrone.Core.Parser public static string NormalizeNumber(string s) { - s = (s.Length == 0) ? "0" : s.Replace(",", "."); + var valStr = new string(s.Where(c => char.IsDigit(c) || c == '.' || c == ',').ToArray()); - s = NormalizeSpace(s).Replace("-", "0"); + valStr = (valStr.Length == 0) ? "0" : valStr.Replace(",", "."); - if (s.Count(c => c == '.') > 1) + valStr = NormalizeSpace(valStr).Replace("-", "0"); + + if (valStr.Count(c => c == '.') > 1) { - var lastOcc = s.LastIndexOf('.'); - s = s.Substring(0, lastOcc).Replace(".", string.Empty) + s.Substring(lastOcc); + var lastOcc = valStr.LastIndexOf('.'); + valStr = valStr.Substring(0, lastOcc).Replace(".", string.Empty) + valStr.Substring(lastOcc); } - return s; + return valStr; } public static string RemoveInvalidXmlChars(string text) => string.IsNullOrEmpty(text) ? "" : InvalidXmlChars.Replace(text, ""); @@ -113,9 +115,8 @@ namespace NzbDrone.Core.Parser public static long GetBytes(string str) { - var valStr = new string(str.Where(c => char.IsDigit(c) || c == '.' || c == ',').ToArray()); var unit = new string(str.Where(char.IsLetter).ToArray()); - var val = CoerceFloat(valStr); + var val = CoerceFloat(str); return GetBytes(unit, val); } From f5d6fa91380c189a56fa82eddbcbb97bbc08bf22 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 27 Nov 2021 15:39:13 -0600 Subject: [PATCH 0193/2320] Fixed: (Cardigann) Blocklist depreciated definitions reverts 1abd14ee865033cf62fd6700829335a80d9e42f6 adds additional v3 definitions --- .../IndexerDefinitionUpdateService.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index 53c0249af..dc4c6f2e7 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -29,12 +29,21 @@ namespace NzbDrone.Core.IndexerVersions private const int DEFINITION_VERSION = 3; private readonly List<string> _defintionBlocklist = new List<string>() { + "aither", "animeworld", - "beyond-hd", "beyond-hd-oneurl", + "beyond-hd", + "blutopia", + "brsociety", "danishbytes", + "datascene", + "desitorrents", "hdbits", - "lat-team" + "lat-team", + "reelflix", + "shareisland", + "skipthecommercials", + "tellytorrent" }; private readonly IHttpClient _httpClient; From cb2e5953d577a72ab50810ad362f21cf9b9226d6 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 28 Nov 2021 01:57:32 -0600 Subject: [PATCH 0194/2320] Bump version to 0.1.5 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6d25219ef..933959b10 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,7 +7,7 @@ variables: outputFolder: './_output' artifactsFolder: './_artifacts' testsFolder: './_tests' - majorVersion: '0.1.4' + majorVersion: '0.1.5' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From dbf81a7c9ea603173afd84828b47e5a519e97a7c Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 28 Nov 2021 11:04:44 -0600 Subject: [PATCH 0195/2320] Fixed: Outdated Definition Healthcheck not using Definition Name --- src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs index 01f368951..5fd9ea81d 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs @@ -38,7 +38,7 @@ namespace NzbDrone.Core.HealthCheck.Checks return new HealthCheck(GetType(), HealthCheckResult.Warning, string.Format(_localizationService.GetLocalizedString("IndexerObsoleteCheckMessage"), - string.Join(", ", oldIndexers.Select(v => v.Name))), + string.Join(", ", oldIndexers.Select(v => v.Definition.Name))), "#indexers-are-obsolete"); } From 80b6821e46c31bbc3295670df9f89a6fab9815c7 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 28 Nov 2021 13:53:51 -0600 Subject: [PATCH 0196/2320] Fixed: (Xthor) Details Linking to API and not the site Fixes #577 --- src/NzbDrone.Core/Indexers/Definitions/Xthor/XthorParser.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Xthor/XthorParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Xthor/XthorParser.cs index 66dc4af51..07702e0b3 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Xthor/XthorParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Xthor/XthorParser.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; @@ -18,7 +18,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Xthor { _settings = settings; _categories = categories; - _torrentDetailsUrl = _settings.BaseUrl + "details.php?id={id}"; + _torrentDetailsUrl = _settings.BaseUrl.Replace("api.", "") + "details.php?id={id}"; } public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) From b80bfaeff0e911a47436eb93985237eb1424cee5 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 28 Nov 2021 15:03:23 -0600 Subject: [PATCH 0197/2320] Bump System.Data.SQLite.Core.Servar --- src/NzbDrone.Common/Prowlarr.Common.csproj | 2 +- src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj | 2 +- src/NzbDrone.Core/Prowlarr.Core.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index ea03b36c4..17259badd 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -12,7 +12,7 @@ <PackageReference Include="Sentry" Version="3.8.3" /> <PackageReference Include="SharpZipLib" Version="1.3.1" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" /> - <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-12" /> + <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> <PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" /> <PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" /> <PackageReference Include="System.Runtime.Loader" Version="4.3.0" /> diff --git a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj index a53ccde77..f00d67248 100644 --- a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj @@ -5,7 +5,7 @@ <ItemGroup> <PackageReference Include="Dapper" Version="2.0.90" /> <PackageReference Include="NBuilder" Version="6.1.0" /> - <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-12" /> + <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> <PackageReference Include="YamlDotNet" Version="11.2.1" /> </ItemGroup> <ItemGroup> diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index a71c71fbb..6d89467d0 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -17,7 +17,7 @@ <PackageReference Include="NLog" Version="4.7.9" /> <PackageReference Include="TinyTwitter" Version="1.1.2" /> <PackageReference Include="Kveer.XmlRPC" Version="1.1.1" /> - <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-12" /> + <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> <PackageReference Include="System.Text.Json" Version="6.0.0" /> <PackageReference Include="MonoTorrent" Version="1.0.29" /> <PackageReference Include="YamlDotNet" Version="11.2.1" /> From 9b9d2f2798159d6b980f1cf7da48d2255d70f343 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 28 Nov 2021 16:46:15 -0600 Subject: [PATCH 0198/2320] Fixed: Tray app restart Co-Authored-By: ta264 <ta264@users.noreply.github.com> --- src/NzbDrone.Console/Prowlarr.Console.csproj | 1 - src/NzbDrone.Console/app.config | 14 ----- src/NzbDrone.Console/app.manifest | 31 ----------- src/NzbDrone.Host/AppLifetime.cs | 3 -- src/NzbDrone.Host/Bootstrap.cs | 13 ++++- src/NzbDrone/Prowlarr.csproj | 1 - src/NzbDrone/SysTray/SysTrayApp.cs | 57 +++++--------------- src/NzbDrone/WindowsApp.cs | 11 ++-- src/NzbDrone/app.config | 14 ----- src/NzbDrone/app.manifest | 31 ----------- 10 files changed, 30 insertions(+), 146 deletions(-) delete mode 100644 src/NzbDrone.Console/app.config delete mode 100644 src/NzbDrone.Console/app.manifest delete mode 100644 src/NzbDrone/app.config delete mode 100644 src/NzbDrone/app.manifest diff --git a/src/NzbDrone.Console/Prowlarr.Console.csproj b/src/NzbDrone.Console/Prowlarr.Console.csproj index bbfa0a0fa..a1e85f4d6 100644 --- a/src/NzbDrone.Console/Prowlarr.Console.csproj +++ b/src/NzbDrone.Console/Prowlarr.Console.csproj @@ -4,7 +4,6 @@ <TargetFrameworks>net6.0</TargetFrameworks> <ApplicationIcon>..\NzbDrone.Host\Prowlarr.ico</ApplicationIcon> - <ApplicationManifest>app.manifest</ApplicationManifest> </PropertyGroup> <PropertyGroup Condition="!$(RuntimeIdentifier.StartsWith('win'))"> <AssemblyName>Prowlarr</AssemblyName> diff --git a/src/NzbDrone.Console/app.config b/src/NzbDrone.Console/app.config deleted file mode 100644 index ee76aa22d..000000000 --- a/src/NzbDrone.Console/app.config +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<configuration> - <system.net> - <connectionManagement> - <add address="*" maxconnection="100" /> - </connectionManagement> - </system.net> - <startup useLegacyV2RuntimeActivationPolicy="true"> - <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" /> - </startup> - <runtime> - <loadFromRemoteSources enabled="true" /> - </runtime> -</configuration> \ No newline at end of file diff --git a/src/NzbDrone.Console/app.manifest b/src/NzbDrone.Console/app.manifest deleted file mode 100644 index 7fc477bdf..000000000 --- a/src/NzbDrone.Console/app.manifest +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> - <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/> - <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> - <security> - <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> - <requestedExecutionLevel level="asInvoker" uiAccess="false" /> - </requestedPrivileges> - </security> - </trustInfo> - <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> - <application> - - <!-- Windows 8 --> - <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" /> - - <!-- Windows 8.1 --> - <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" /> - - <!-- Windows 10 --> - <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" /> - - </application> - </compatibility> - - <application xmlns="urn:schemas-microsoft-com:asm.v3"> - <windowsSettings> - <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware> - </windowsSettings> - </application> -</assembly> \ No newline at end of file diff --git a/src/NzbDrone.Host/AppLifetime.cs b/src/NzbDrone.Host/AppLifetime.cs index d0d0955ce..0a181a7db 100644 --- a/src/NzbDrone.Host/AppLifetime.cs +++ b/src/NzbDrone.Host/AppLifetime.cs @@ -19,7 +19,6 @@ namespace NzbDrone.Host private readonly IBrowserService _browserService; private readonly IProcessProvider _processProvider; private readonly IEventAggregator _eventAggregator; - private readonly IUtilityModeRouter _utilityModeRouter; private readonly Logger _logger; public AppLifetime(IHostApplicationLifetime appLifetime, @@ -29,7 +28,6 @@ namespace NzbDrone.Host IBrowserService browserService, IProcessProvider processProvider, IEventAggregator eventAggregator, - IUtilityModeRouter utilityModeRouter, Logger logger) { _appLifetime = appLifetime; @@ -39,7 +37,6 @@ namespace NzbDrone.Host _browserService = browserService; _processProvider = processProvider; _eventAggregator = eventAggregator; - _utilityModeRouter = utilityModeRouter; _logger = logger; appLifetime.ApplicationStarted.Register(OnAppStarted); diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index fd3c4bf76..b3b9341f6 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -171,7 +171,18 @@ namespace NzbDrone.Host return ApplicationModes.UninstallService; } - if (OsInfo.IsWindows && WindowsServiceHelpers.IsWindowsService()) + // IsWindowsService can throw sometimes, so wrap it + bool isWindowsService = false; + try + { + isWindowsService = WindowsServiceHelpers.IsWindowsService(); + } + catch + { + // don't care + } + + if (OsInfo.IsWindows && isWindowsService) { return ApplicationModes.Service; } diff --git a/src/NzbDrone/Prowlarr.csproj b/src/NzbDrone/Prowlarr.csproj index 3f990da36..ca6227e15 100644 --- a/src/NzbDrone/Prowlarr.csproj +++ b/src/NzbDrone/Prowlarr.csproj @@ -5,7 +5,6 @@ <RuntimeIdentifiers>win-x64;win-x86</RuntimeIdentifiers> <UseWindowsForms>true</UseWindowsForms> <ApplicationIcon>..\NzbDrone.Host\Prowlarr.ico</ApplicationIcon> - <ApplicationManifest>app.manifest</ApplicationManifest> <GenerateResourceUsePreserializedResources>true</GenerateResourceUsePreserializedResources> </PropertyGroup> <ItemGroup> diff --git a/src/NzbDrone/SysTray/SysTrayApp.cs b/src/NzbDrone/SysTray/SysTrayApp.cs index 649eb3d9e..06aa81b64 100644 --- a/src/NzbDrone/SysTray/SysTrayApp.cs +++ b/src/NzbDrone/SysTray/SysTrayApp.cs @@ -4,9 +4,8 @@ using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using Microsoft.Extensions.Hosting; -using NLog; using NzbDrone.Common.EnvironmentInfo; -using NzbDrone.Common.Processes; +using NzbDrone.Core.Lifecycle; using NzbDrone.Host; namespace NzbDrone.SysTray @@ -14,28 +13,19 @@ namespace NzbDrone.SysTray public class SystemTrayApp : Form, IHostedService { private readonly IBrowserService _browserService; - private readonly IRuntimeInfo _runtimeInfo; - private readonly IProcessProvider _processProvider; + private readonly ILifecycleService _lifecycle; private readonly NotifyIcon _trayIcon = new NotifyIcon(); private readonly ContextMenuStrip _trayMenu = new ContextMenuStrip(); - public SystemTrayApp(IBrowserService browserService, IRuntimeInfo runtimeInfo, IProcessProvider processProvider) + public SystemTrayApp(IBrowserService browserService, ILifecycleService lifecycle) { _browserService = browserService; - _runtimeInfo = runtimeInfo; - _processProvider = processProvider; + _lifecycle = lifecycle; } public void Start() { - Application.ThreadException += OnThreadException; - Application.ApplicationExit += OnApplicationExit; - - Application.SetHighDpiMode(HighDpiMode.PerMonitor); - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - _trayMenu.Items.Add(new ToolStripMenuItem("Launch Browser", null, LaunchBrowser)); _trayMenu.Items.Add(new ToolStripSeparator()); _trayMenu.Items.Add(new ToolStripMenuItem("Exit", null, OnExit)); @@ -69,12 +59,6 @@ namespace NzbDrone.SysTray DisposeTrayIcon(); } - protected override void OnClosed(EventArgs e) - { - Console.WriteLine("Closing"); - base.OnClosed(e); - } - protected override void OnLoad(EventArgs e) { Visible = false; @@ -102,8 +86,7 @@ namespace NzbDrone.SysTray private void OnExit(object sender, EventArgs e) { - LogManager.Configuration = null; - Environment.Exit(0); + _lifecycle.Shutdown(); } private void LaunchBrowser(object sender, EventArgs e) @@ -117,33 +100,17 @@ namespace NzbDrone.SysTray } } - private void OnApplicationExit(object sender, EventArgs e) - { - if (_runtimeInfo.RestartPending) - { - _processProvider.SpawnNewProcess(_runtimeInfo.ExecutingApplication, "--restart --nobrowser"); - } - - DisposeTrayIcon(); - } - - private void OnThreadException(object sender, EventArgs e) - { - DisposeTrayIcon(); - } - private void DisposeTrayIcon() { - try - { - _trayIcon.Visible = false; - _trayIcon.Icon = null; - _trayIcon.Visible = false; - _trayIcon.Dispose(); - } - catch (Exception) + if (_trayIcon == null) { + return; } + + _trayIcon.Visible = false; + _trayIcon.Icon = null; + _trayIcon.Visible = false; + _trayIcon.Dispose(); } } } diff --git a/src/NzbDrone/WindowsApp.cs b/src/NzbDrone/WindowsApp.cs index 0fdd6f40d..db2d34ddb 100644 --- a/src/NzbDrone/WindowsApp.cs +++ b/src/NzbDrone/WindowsApp.cs @@ -16,21 +16,22 @@ namespace NzbDrone public static void Main(string[] args) { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.SetHighDpiMode(HighDpiMode.SystemAware); + try { var startupArgs = new StartupContext(args); NzbDroneLogger.Register(startupArgs, false, true); - Bootstrap.Start(args, e => - { - e.ConfigureServices((_, s) => s.AddSingleton<IHostedService, SystemTrayApp>()); - }); + Bootstrap.Start(args, e => { e.ConfigureServices((_, s) => s.AddSingleton<IHostedService, SystemTrayApp>()); }); } catch (Exception e) { Logger.Fatal(e, "EPIC FAIL: " + e.Message); - var message = string.Format("{0}: {1}", e.GetType().Name, e.Message); + var message = string.Format("{0}: {1}", e.GetType().Name, e.ToString()); MessageBox.Show(text: message, buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error, caption: "Epic Fail!"); } } diff --git a/src/NzbDrone/app.config b/src/NzbDrone/app.config deleted file mode 100644 index ee76aa22d..000000000 --- a/src/NzbDrone/app.config +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<configuration> - <system.net> - <connectionManagement> - <add address="*" maxconnection="100" /> - </connectionManagement> - </system.net> - <startup useLegacyV2RuntimeActivationPolicy="true"> - <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" /> - </startup> - <runtime> - <loadFromRemoteSources enabled="true" /> - </runtime> -</configuration> \ No newline at end of file diff --git a/src/NzbDrone/app.manifest b/src/NzbDrone/app.manifest deleted file mode 100644 index dbf947ef8..000000000 --- a/src/NzbDrone/app.manifest +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> - <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/> - <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> - <security> - <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> - <requestedExecutionLevel level="asInvoker" uiAccess="false" /> - </requestedPrivileges> - </security> - </trustInfo> - <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> - <application> - - <!-- Windows 8 --> - <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" /> - - <!-- Windows 8.1 --> - <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" /> - - <!-- Windows 10 --> - <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" /> - - </application> - </compatibility> - - <application xmlns="urn:schemas-microsoft-com:asm.v3"> - <windowsSettings> - <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware> - </windowsSettings> - </application> -</assembly> \ No newline at end of file From 2e103d6dbaa5cfa16ffe2779f4d14b8fc148c6f8 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 28 Nov 2021 16:47:16 -0600 Subject: [PATCH 0199/2320] ParseUtil Cleanup --- .../ParserTests/ParseUtilFixture.cs | 14 ++++++++++++++ .../Definitions/Cardigann/CardigannBase.cs | 4 ++-- src/NzbDrone.Core/Parser/DateTimeUtil.cs | 4 ++-- src/NzbDrone.Core/Parser/ParseUtil.cs | 18 ++++++++---------- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/NzbDrone.Core.Test/ParserTests/ParseUtilFixture.cs b/src/NzbDrone.Core.Test/ParserTests/ParseUtilFixture.cs index 88ad41303..5766c0b40 100644 --- a/src/NzbDrone.Core.Test/ParserTests/ParseUtilFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/ParseUtilFixture.cs @@ -20,5 +20,19 @@ namespace NzbDrone.Core.Test.ParserTests { ParseUtil.GetBytes(stringSize).Should().Be(size); } + + [TestCase(" some string ", "some string")] + public void should_normalize_multiple_spaces(string original, string newString) + { + ParseUtil.NormalizeMultiSpaces(original).Should().Be(newString); + } + + [TestCase("1", 1)] + [TestCase("11", 11)] + [TestCase("1000 grabs", 1000)] + public void should_parse_int_from_string(string original, int parsedInt) + { + ParseUtil.CoerceInt(original).Should().Be(parsedInt); + } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index 8a4d0268b..9ea8a57d9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -220,7 +220,7 @@ namespace NzbDrone.Core.Indexers.Cardigann value = selection.TextContent; } - return ApplyFilters(ParseUtil.NormalizeSpace(value), selector.Filters, variables); + return ApplyFilters(value.Trim(), selector.Filters, variables); } protected string HandleJsonSelector(SelectorBlock selector, JToken parentObj, Dictionary<string, object> variables = null, bool required = true) @@ -271,7 +271,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } } - return ApplyFilters(ParseUtil.NormalizeSpace(value), selector.Filters, variables); + return ApplyFilters(value.Trim(), selector.Filters, variables); } protected Dictionary<string, object> GetBaseTemplateVariables() diff --git a/src/NzbDrone.Core/Parser/DateTimeUtil.cs b/src/NzbDrone.Core/Parser/DateTimeUtil.cs index 4d94c412a..a9fb063b9 100644 --- a/src/NzbDrone.Core/Parser/DateTimeUtil.cs +++ b/src/NzbDrone.Core/Parser/DateTimeUtil.cs @@ -121,7 +121,7 @@ namespace NzbDrone.Core.Parser { try { - str = ParseUtil.NormalizeSpace(str); + str = str.Trim(); if (str.ToLower().Contains("now")) { return DateTime.UtcNow; @@ -254,7 +254,7 @@ namespace NzbDrone.Core.Parser // converts a date/time string to a DateTime object using a GoLang layout public static DateTime ParseDateTimeGoLang(string date, string layout) { - date = ParseUtil.NormalizeSpace(date); + date = date.Trim(); var pattern = layout; // year diff --git a/src/NzbDrone.Core/Parser/ParseUtil.cs b/src/NzbDrone.Core/Parser/ParseUtil.cs index 7868ba102..e1f7fe8c6 100644 --- a/src/NzbDrone.Core/Parser/ParseUtil.cs +++ b/src/NzbDrone.Core/Parser/ParseUtil.cs @@ -13,18 +13,16 @@ namespace NzbDrone.Core.Parser RegexOptions.Compiled); private static readonly Regex ImdbId = new Regex(@"^(?:tt)?(\d{1,8})$", RegexOptions.Compiled); - public static string NormalizeSpace(string s) => s.Trim(); - public static string NormalizeMultiSpaces(string s) => - new Regex(@"\s+").Replace(NormalizeSpace(s), " "); + new Regex(@"\s+").Replace(s.Trim(), " "); - public static string NormalizeNumber(string s) + private static string NormalizeNumber(string s) { var valStr = new string(s.Where(c => char.IsDigit(c) || c == '.' || c == ',').ToArray()); valStr = (valStr.Length == 0) ? "0" : valStr.Replace(",", "."); - valStr = NormalizeSpace(valStr).Replace("-", "0"); + valStr = valStr.Trim().Replace("-", "0"); if (valStr.Count(c => c == '.') > 1) { @@ -120,7 +118,7 @@ namespace NzbDrone.Core.Parser return GetBytes(unit, val); } - public static long GetBytes(string unit, float value) + private static long GetBytes(string unit, float value) { unit = unit.Replace("i", "").ToLowerInvariant(); if (unit.Contains("kb")) @@ -146,12 +144,12 @@ namespace NzbDrone.Core.Parser return (long)value; } - public static long BytesFromTB(float tb) => BytesFromGB(tb * 1024f); + private static long BytesFromTB(float tb) => BytesFromGB(tb * 1024f); - public static long BytesFromGB(float gb) => BytesFromMB(gb * 1024f); + private static long BytesFromGB(float gb) => BytesFromMB(gb * 1024f); - public static long BytesFromMB(float mb) => BytesFromKB(mb * 1024f); + private static long BytesFromMB(float mb) => BytesFromKB(mb * 1024f); - public static long BytesFromKB(float kb) => (long)(kb * 1024f); + private static long BytesFromKB(float kb) => (long)(kb * 1024f); } } From 02ecc045262284cad22d61268eaddcea37e56961 Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Mon, 22 Nov 2021 21:14:29 +0000 Subject: [PATCH 0200/2320] Fixed: Restarting windows service from UI --- src/NzbDrone.Common.Test/ServiceFactoryFixture.cs | 13 +++++++++---- src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs | 11 ++++------- src/NzbDrone.Common/Prowlarr.Common.csproj | 1 + src/NzbDrone.Host.Test/ContainerFixture.cs | 8 ++++---- src/NzbDrone.Host/AppLifetime.cs | 2 +- src/NzbDrone.Host/Bootstrap.cs | 8 +++++--- 6 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/NzbDrone.Common.Test/ServiceFactoryFixture.cs b/src/NzbDrone.Common.Test/ServiceFactoryFixture.cs index ae6785780..560bf39ea 100644 --- a/src/NzbDrone.Common.Test/ServiceFactoryFixture.cs +++ b/src/NzbDrone.Common.Test/ServiceFactoryFixture.cs @@ -3,6 +3,8 @@ using DryIoc; using DryIoc.Microsoft.DependencyInjection; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Moq; using NUnit.Framework; using NzbDrone.Common.Composition.Extensions; using NzbDrone.Common.EnvironmentInfo; @@ -25,12 +27,15 @@ namespace NzbDrone.Common.Test .AddNzbDroneLogger() .AutoAddServices(Bootstrap.ASSEMBLIES) .AddDummyDatabase() - .AddStartupContext(new StartupContext("first", "second")) - .GetServiceProvider(); + .AddStartupContext(new StartupContext("first", "second")); - container.GetRequiredService<IAppFolderFactory>().Register(); + container.RegisterInstance<IHostLifetime>(new Mock<IHostLifetime>().Object); - Mocker.SetConstant<System.IServiceProvider>(container); + var serviceProvider = container.GetServiceProvider(); + + serviceProvider.GetRequiredService<IAppFolderFactory>().Register(); + + Mocker.SetConstant<System.IServiceProvider>(serviceProvider); var handlers = Subject.BuildAll<IHandle<ApplicationStartedEvent>>() .Select(c => c.GetType().FullName); diff --git a/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs index b5467c2e9..8ae7ad630 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs @@ -1,9 +1,9 @@ using System; using System.Diagnostics; using System.IO; -using System.Reflection; using System.Security.Principal; -using System.ServiceProcess; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Hosting.WindowsServices; using NLog; using NzbDrone.Common.Processes; @@ -14,14 +14,11 @@ namespace NzbDrone.Common.EnvironmentInfo private readonly Logger _logger; private readonly DateTime _startTime = DateTime.UtcNow; - public RuntimeInfo(IServiceProvider serviceProvider, Logger logger) + public RuntimeInfo(IHostLifetime hostLifetime, Logger logger) { _logger = logger; - IsWindowsService = !IsUserInteractive && - OsInfo.IsWindows && - serviceProvider.ServiceExist(ServiceProvider.SERVICE_NAME) && - serviceProvider.GetStatus(ServiceProvider.SERVICE_NAME) == ServiceControllerStatus.StartPending; + IsWindowsService = hostLifetime is WindowsServiceLifetime; // net6.0 will return Radarr.dll for entry assembly, we need the actual // executable name (Radarr on linux). On mono this will return the location of diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index 17259badd..aec3ac4ff 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -7,6 +7,7 @@ <PackageReference Include="DryIoc.dll" Version="4.8.1" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" /> <PackageReference Include="NLog.Extensions.Logging" Version="1.7.2" /> + <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="NLog" Version="4.7.9" /> <PackageReference Include="Sentry" Version="3.8.3" /> diff --git a/src/NzbDrone.Host.Test/ContainerFixture.cs b/src/NzbDrone.Host.Test/ContainerFixture.cs index 3771daf76..30774afbd 100644 --- a/src/NzbDrone.Host.Test/ContainerFixture.cs +++ b/src/NzbDrone.Host.Test/ContainerFixture.cs @@ -4,6 +4,7 @@ using DryIoc; using DryIoc.Microsoft.DependencyInjection; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Moq; using NUnit.Framework; using NzbDrone.Common; @@ -33,16 +34,15 @@ namespace NzbDrone.App.Test { var args = new StartupContext("first", "second"); - // set up a dummy broadcaster to allow tests to resolve - var mockBroadcaster = new Mock<IBroadcastSignalRMessage>(); - var container = new Container(rules => rules.WithNzbDroneRules()) .AutoAddServices(Bootstrap.ASSEMBLIES) .AddNzbDroneLogger() .AddDummyDatabase() .AddStartupContext(args); - container.RegisterInstance<IBroadcastSignalRMessage>(mockBroadcaster.Object); + // dummy lifetime and broadcaster so tests resolve + container.RegisterInstance<IHostLifetime>(new Mock<IHostLifetime>().Object); + container.RegisterInstance<IBroadcastSignalRMessage>(new Mock<IBroadcastSignalRMessage>().Object); _container = container.GetServiceProvider(); } diff --git a/src/NzbDrone.Host/AppLifetime.cs b/src/NzbDrone.Host/AppLifetime.cs index 0a181a7db..17f5bbcdc 100644 --- a/src/NzbDrone.Host/AppLifetime.cs +++ b/src/NzbDrone.Host/AppLifetime.cs @@ -68,7 +68,7 @@ namespace NzbDrone.Host private void OnAppStopped() { - if (_runtimeInfo.RestartPending) + if (_runtimeInfo.RestartPending && !_runtimeInfo.IsWindowsService) { var restartArgs = GetRestartArgs(); diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index b3b9341f6..beb73f276 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -171,15 +171,17 @@ namespace NzbDrone.Host return ApplicationModes.UninstallService; } + Logger.Debug("Getting windows service status"); + // IsWindowsService can throw sometimes, so wrap it - bool isWindowsService = false; + var isWindowsService = false; try { isWindowsService = WindowsServiceHelpers.IsWindowsService(); } - catch + catch (Exception e) { - // don't care + Logger.Error(e, "Failed to get service status"); } if (OsInfo.IsWindows && isWindowsService) From d3853c1a548ec5464c59e86c018f9720af9dd572 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 28 Nov 2021 22:15:09 -0600 Subject: [PATCH 0201/2320] Bump version to 0.1.6 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 933959b10..90cdd164e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,7 +7,7 @@ variables: outputFolder: './_output' artifactsFolder: './_artifacts' testsFolder: './_tests' - majorVersion: '0.1.5' + majorVersion: '0.1.6' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From 77e40e8e53d377cab04d1d7c0af78913d14c3aa4 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 29 Nov 2021 11:30:14 -0600 Subject: [PATCH 0202/2320] Fixed: (TorrentSyndikat) Download URL missing API --- src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs index 7378803fd..517ed183f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs @@ -244,7 +244,7 @@ namespace NzbDrone.Core.Indexers.Definitions UploadVolumeFactor = 1, Guid = details, InfoUrl = details, - DownloadUrl = _settings.BaseUrl + "download.php?id=" + id, + DownloadUrl = _settings.BaseUrl + "download.php?id=" + id + "&apikey=" + _settings.ApiKey, Title = row.Value<string>("name"), Categories = _categories.MapTrackerCatToNewznab(row.Value<int>("category").ToString()), PublishDate = dateTime.AddSeconds(row.Value<long>("added")).ToLocalTime(), From 5f5df99dab5696657aecf5c27d1b61d8ff8a6230 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 29 Nov 2021 21:00:11 -0600 Subject: [PATCH 0203/2320] Improved logging on bad date parse --- src/NzbDrone.Core/Parser/DateTimeUtil.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Parser/DateTimeUtil.cs b/src/NzbDrone.Core/Parser/DateTimeUtil.cs index a9fb063b9..9bccaabe1 100644 --- a/src/NzbDrone.Core/Parser/DateTimeUtil.cs +++ b/src/NzbDrone.Core/Parser/DateTimeUtil.cs @@ -114,7 +114,7 @@ namespace NzbDrone.Core.Parser return dateTimeParsed; } - throw new Exception("FromFuzzyTime parsing failed"); + throw new Exception($"FromFuzzyTime parsing failed for string {str}"); } public static DateTime FromUnknown(string str, string format = null) From 01e7e924c47a75db9f9183597e25db9df7e34e39 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 29 Nov 2021 21:00:38 -0600 Subject: [PATCH 0204/2320] Fixed: (Flaresolverr) Proxy Test Fixes #651 --- .../IndexerProxies/FlareSolverr/FlareSolverr.cs | 7 ++++--- src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs | 8 +------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index ca3f7691a..9b8b2140a 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -149,7 +149,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr { var failures = new List<ValidationFailure>(); - var request = PreRequest(_cloudRequestBuilder.Create() + var request = GenerateFlareSolverrRequest(_cloudRequestBuilder.Create() .Resource("/ping") .Build()); @@ -157,12 +157,13 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr { var response = _httpClient.Execute(request); - // We only care about 400 responses, other error codes can be ignored - if (response.StatusCode == HttpStatusCode.BadRequest) + if (response.StatusCode != HttpStatusCode.OK) { _logger.Error("Proxy Health Check failed: {0}", response.StatusCode); failures.Add(new NzbDroneValidationFailure("Host", string.Format(_localizationService.GetLocalizedString("ProxyCheckBadRequestMessage"), response.StatusCode))); } + + var result = JsonConvert.DeserializeObject<FlareSolverrResponse>(response.Content); } catch (Exception ex) { diff --git a/src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs b/src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs index 6ddc8b6bc..431ff53a9 100644 --- a/src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs +++ b/src/NzbDrone.Core/IndexerProxies/HttpIndexerProxyBase.cs @@ -31,12 +31,6 @@ namespace NzbDrone.Core.IndexerProxies { var failures = new List<ValidationFailure>(); - var addresses = Dns.GetHostAddresses(Settings.Host); - if (!addresses.Any()) - { - failures.Add(new NzbDroneValidationFailure("Host", string.Format(_localizationService.GetLocalizedString("ProxyCheckResolveIpMessage"), addresses))); - } - var request = PreRequest(_cloudRequestBuilder.Create() .Resource("/ping") .Build()); @@ -55,7 +49,7 @@ namespace NzbDrone.Core.IndexerProxies catch (Exception ex) { _logger.Error(ex, "Proxy Health Check failed"); - failures.Add(new NzbDroneValidationFailure("Host", string.Format("Failed to test proxy: {0}", request.Url))); + failures.Add(new NzbDroneValidationFailure("Host", string.Format("Failed to test proxy: {0}", ex.Message))); } return new ValidationResult(failures); From a61d4ab88cf4635025a0f0bdea11d7b0f29363f0 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 24 Jun 2021 00:12:37 -0400 Subject: [PATCH 0205/2320] New: Stats filters --- frontend/src/Indexer/Stats/Stats.js | 27 ++- frontend/src/Indexer/Stats/StatsConnector.js | 21 ++- frontend/src/Indexer/Stats/StatsFilterMenu.js | 37 ++++ .../Stats/StatsFilterModalConnector.js | 24 +++ .../src/Store/Actions/indexerStatsActions.js | 121 ++++++++++++- .../History/HistoryRepository.cs | 8 + src/NzbDrone.Core/History/HistoryService.cs | 6 + .../IndexerStats/IndexerStatistics.cs | 8 + .../IndexerStatisticsRepository.cs | 103 ----------- .../IndexerStats/IndexerStatisticsService.cs | 169 ++++++++++++++++-- .../Indexers/IndexerStatsController.cs | 12 +- 11 files changed, 397 insertions(+), 139 deletions(-) create mode 100644 frontend/src/Indexer/Stats/StatsFilterMenu.js create mode 100644 frontend/src/Indexer/Stats/StatsFilterModalConnector.js delete mode 100644 src/NzbDrone.Core/IndexerStats/IndexerStatisticsRepository.cs diff --git a/frontend/src/Indexer/Stats/Stats.js b/frontend/src/Indexer/Stats/Stats.js index b3b89974d..b063d638c 100644 --- a/frontend/src/Indexer/Stats/Stats.js +++ b/frontend/src/Indexer/Stats/Stats.js @@ -7,8 +7,10 @@ import LoadingIndicator from 'Components/Loading/LoadingIndicator'; import PageContent from 'Components/Page/PageContent'; import PageContentBody from 'Components/Page/PageContentBody'; import PageToolbar from 'Components/Page/Toolbar/PageToolbar'; -import { kinds } from 'Helpers/Props'; +import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection'; +import { align, kinds } from 'Helpers/Props'; import getErrorMessage from 'Utilities/Object/getErrorMessage'; +import StatsFilterMenu from './StatsFilterMenu'; import styles from './Stats.css'; function getAverageResponseTimeData(indexerStats) { @@ -144,14 +146,29 @@ function Stats(props) { item, isFetching, isPopulated, - error + error, + filters, + selectedFilterKey, + onFilterSelect } = props; const isLoaded = !!(!error && isPopulated); return ( <PageContent> - <PageToolbar /> + <PageToolbar> + <PageToolbarSection + alignContent={align.RIGHT} + collapseButtons={false} + > + <StatsFilterMenu + selectedFilterKey={selectedFilterKey} + filters={filters} + onFilterSelect={onFilterSelect} + isDisabled={false} + /> + </PageToolbarSection> + </PageToolbar> <PageContentBody> { isFetching && !isPopulated && @@ -232,6 +249,10 @@ Stats.propTypes = { item: PropTypes.object.isRequired, isFetching: PropTypes.bool.isRequired, isPopulated: PropTypes.bool.isRequired, + filters: PropTypes.arrayOf(PropTypes.object).isRequired, + selectedFilterKey: PropTypes.string.isRequired, + customFilters: PropTypes.arrayOf(PropTypes.object).isRequired, + onFilterSelect: PropTypes.func.isRequired, error: PropTypes.object, data: PropTypes.object }; diff --git a/frontend/src/Indexer/Stats/StatsConnector.js b/frontend/src/Indexer/Stats/StatsConnector.js index 4dbc8fbd2..006716953 100644 --- a/frontend/src/Indexer/Stats/StatsConnector.js +++ b/frontend/src/Indexer/Stats/StatsConnector.js @@ -2,7 +2,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { fetchIndexerStats } from 'Store/Actions/indexerStatsActions'; +import { fetchIndexerStats, setIndexerStatsFilter } from 'Store/Actions/indexerStatsActions'; import Stats from './Stats'; function createMapStateToProps() { @@ -12,9 +12,16 @@ function createMapStateToProps() { ); } -const mapDispatchToProps = { - dispatchFetchIndexers: fetchIndexerStats -}; +function createMapDispatchToProps(dispatch, props) { + return { + onFilterSelect(selectedFilterKey) { + dispatch(setIndexerStatsFilter({ selectedFilterKey })); + }, + dispatchFetchIndexerStats() { + dispatch(fetchIndexerStats()); + } + }; +} class StatsConnector extends Component { @@ -22,7 +29,7 @@ class StatsConnector extends Component { // Lifecycle componentDidMount() { - this.props.dispatchFetchIndexers(); + this.props.dispatchFetchIndexerStats(); } // @@ -38,7 +45,7 @@ class StatsConnector extends Component { } StatsConnector.propTypes = { - dispatchFetchIndexers: PropTypes.func.isRequired + dispatchFetchIndexerStats: PropTypes.func.isRequired }; -export default connect(createMapStateToProps, mapDispatchToProps)(StatsConnector); +export default connect(createMapStateToProps, createMapDispatchToProps)(StatsConnector); diff --git a/frontend/src/Indexer/Stats/StatsFilterMenu.js b/frontend/src/Indexer/Stats/StatsFilterMenu.js new file mode 100644 index 000000000..283159b7e --- /dev/null +++ b/frontend/src/Indexer/Stats/StatsFilterMenu.js @@ -0,0 +1,37 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import FilterMenu from 'Components/Menu/FilterMenu'; +import { align } from 'Helpers/Props'; + +function StatsFilterMenu(props) { + const { + selectedFilterKey, + filters, + isDisabled, + onFilterSelect + } = props; + + return ( + <FilterMenu + alignMenu={align.RIGHT} + isDisabled={isDisabled} + selectedFilterKey={selectedFilterKey} + filters={filters} + customFilters={[]} + onFilterSelect={onFilterSelect} + /> + ); +} + +StatsFilterMenu.propTypes = { + selectedFilterKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, + filters: PropTypes.arrayOf(PropTypes.object).isRequired, + isDisabled: PropTypes.bool.isRequired, + onFilterSelect: PropTypes.func.isRequired +}; + +StatsFilterMenu.defaultProps = { + showCustomFilters: false +}; + +export default StatsFilterMenu; diff --git a/frontend/src/Indexer/Stats/StatsFilterModalConnector.js b/frontend/src/Indexer/Stats/StatsFilterModalConnector.js new file mode 100644 index 000000000..53bf2ed3c --- /dev/null +++ b/frontend/src/Indexer/Stats/StatsFilterModalConnector.js @@ -0,0 +1,24 @@ +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import FilterModal from 'Components/Filter/FilterModal'; +import { setIndexerStatsFilter } from 'Store/Actions/indexerStatsActions'; + +function createMapStateToProps() { + return createSelector( + (state) => state.indexerStats.items, + (state) => state.indexerStats.filterBuilderProps, + (sectionItems, filterBuilderProps) => { + return { + sectionItems, + filterBuilderProps, + customFilterType: 'indexerStats' + }; + } + ); +} + +const mapDispatchToProps = { + dispatchSetFilter: setIndexerStatsFilter +}; + +export default connect(createMapStateToProps, mapDispatchToProps)(FilterModal); diff --git a/frontend/src/Store/Actions/indexerStatsActions.js b/frontend/src/Store/Actions/indexerStatsActions.js index ef2a7ccb0..e937cee93 100644 --- a/frontend/src/Store/Actions/indexerStatsActions.js +++ b/frontend/src/Store/Actions/indexerStatsActions.js @@ -1,5 +1,10 @@ +import moment from 'moment'; +import { batchActions } from 'redux-batched-actions'; +import { filterBuilderTypes, filterBuilderValueTypes } from 'Helpers/Props'; import { createThunk, handleThunks } from 'Store/thunks'; -import createFetchHandler from './Creators/createFetchHandler'; +import createAjaxRequest from 'Utilities/createAjaxRequest'; +import translate from 'Utilities/String/translate'; +import { set, update } from './baseActions'; import createHandleActions from './Creators/createHandleActions'; // @@ -15,30 +20,140 @@ export const defaultState = { isPopulated: false, error: null, item: {}, + start: null, + end: null, details: { isFetching: false, isPopulated: false, error: null, item: [] - } + }, + + filters: [ + { + key: 'all', + label: translate('All'), + filters: [] + }, + { + key: 'lastSeven', + label: 'Last 7 Days', + filters: [] + }, + { + key: 'lastThirty', + label: 'Last 30 Days', + filters: [] + }, + { + key: 'lastNinety', + label: 'Last 90 Days', + filters: [] + } + ], + + filterBuilderProps: [ + { + name: 'startDate', + label: 'Start Date', + type: filterBuilderTypes.EXACT, + valueType: filterBuilderValueTypes.DATE + }, + { + name: 'endDate', + label: 'End Date', + type: filterBuilderTypes.EXACT, + valueType: filterBuilderValueTypes.DATE + } + ], + selectedFilterKey: 'all' }; +export const persistState = [ + 'indexerStats.customFilters', + 'indexerStats.selectedFilterKey' +]; + // // Actions Types export const FETCH_INDEXER_STATS = 'indexerStats/fetchIndexerStats'; +export const SET_INDEXER_STATS_FILTER = 'indexerStats/setIndexerStatsFilter'; // // Action Creators export const fetchIndexerStats = createThunk(FETCH_INDEXER_STATS); +export const setIndexerStatsFilter = createThunk(SET_INDEXER_STATS_FILTER); // // Action Handlers export const actionHandlers = handleThunks({ - [FETCH_INDEXER_STATS]: createFetchHandler(section, '/indexerStats') + [FETCH_INDEXER_STATS]: function(getState, payload, dispatch) { + const state = getState(); + const indexerStats = state.indexerStats; + + const requestParams = { + endDate: moment().toISOString() + }; + + if (indexerStats.selectedFilterKey !== 'all') { + let dayCount = 7; + + if (indexerStats.selectedFilterKey === 'lastThirty') { + dayCount = 30; + } + + if (indexerStats.selectedFilterKey === 'lastNinety') { + dayCount = 90; + } + + requestParams.startDate = moment().add(-dayCount, 'days').endOf('day').toISOString(); + } + + const basesAttrs = { + section, + isFetching: true + }; + + const attrs = basesAttrs; + + dispatch(set(attrs)); + + const promise = createAjaxRequest({ + url: '/indexerStats', + data: requestParams + }).request; + + promise.done((data) => { + dispatch(batchActions([ + update({ section, data }), + + set({ + section, + isFetching: false, + isPopulated: true, + error: null + }) + ])); + }); + + promise.fail((xhr) => { + dispatch(set({ + section, + isFetching: false, + isPopulated: false, + error: xhr + })); + }); + }, + + [SET_INDEXER_STATS_FILTER]: function(getState, payload, dispatch) { + dispatch(set({ section, ...payload })); + dispatch(fetchIndexerStats()); + } }); // diff --git a/src/NzbDrone.Core/History/HistoryRepository.cs b/src/NzbDrone.Core/History/HistoryRepository.cs index 52bced1a7..e5e535fd8 100644 --- a/src/NzbDrone.Core/History/HistoryRepository.cs +++ b/src/NzbDrone.Core/History/HistoryRepository.cs @@ -15,6 +15,7 @@ namespace NzbDrone.Core.History List<History> GetByIndexerId(int indexerId, HistoryEventType? eventType); void DeleteForIndexers(List<int> indexerIds); History MostRecentForIndexer(int indexerId); + List<History> Between(DateTime start, DateTime end); List<History> Since(DateTime date, HistoryEventType? eventType); void Cleanup(int days); int CountSince(int indexerId, DateTime date, List<HistoryEventType> eventTypes); @@ -78,6 +79,13 @@ namespace NzbDrone.Core.History .FirstOrDefault(); } + public List<History> Between(DateTime start, DateTime end) + { + var builder = Builder().Where<History>(x => x.Date >= start && x.Date <= end); + + return Query(builder).OrderBy(h => h.Date).ToList(); + } + public List<History> Since(DateTime date, HistoryEventType? eventType) { var builder = Builder().Where<History>(x => x.Date >= date); diff --git a/src/NzbDrone.Core/History/HistoryService.cs b/src/NzbDrone.Core/History/HistoryService.cs index 3187f1f20..685a36882 100644 --- a/src/NzbDrone.Core/History/HistoryService.cs +++ b/src/NzbDrone.Core/History/HistoryService.cs @@ -24,6 +24,7 @@ namespace NzbDrone.Core.History List<History> FindByDownloadId(string downloadId); List<History> GetByIndexerId(int indexerId, HistoryEventType? eventType); void UpdateMany(List<History> toUpdate); + List<History> Between(DateTime start, DateTime end); List<History> Since(DateTime date, HistoryEventType? eventType); int CountSince(int indexerId, DateTime date, List<HistoryEventType> eventTypes); } @@ -87,6 +88,11 @@ namespace NzbDrone.Core.History _historyRepository.UpdateMany(toUpdate); } + public List<History> Between(DateTime start, DateTime end) + { + return _historyRepository.Between(start, end); + } + public List<History> Since(DateTime date, HistoryEventType? eventType) { return _historyRepository.Since(date, eventType); diff --git a/src/NzbDrone.Core/IndexerStats/IndexerStatistics.cs b/src/NzbDrone.Core/IndexerStats/IndexerStatistics.cs index b1e58a722..261d0052a 100644 --- a/src/NzbDrone.Core/IndexerStats/IndexerStatistics.cs +++ b/src/NzbDrone.Core/IndexerStats/IndexerStatistics.cs @@ -1,7 +1,15 @@ +using System.Collections.Generic; using NzbDrone.Core.Datastore; namespace NzbDrone.Core.IndexerStats { + public class CombinedStatistics + { + public List<IndexerStatistics> IndexerStatistics { get; set; } + public List<UserAgentStatistics> UserAgentStatistics { get; set; } + public List<HostStatistics> HostStatistics { get; set; } + } + public class IndexerStatistics : ResultSet { public int IndexerId { get; set; } diff --git a/src/NzbDrone.Core/IndexerStats/IndexerStatisticsRepository.cs b/src/NzbDrone.Core/IndexerStats/IndexerStatisticsRepository.cs deleted file mode 100644 index 0a11c0e16..000000000 --- a/src/NzbDrone.Core/IndexerStats/IndexerStatisticsRepository.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Dapper; -using NzbDrone.Core.Datastore; -using NzbDrone.Core.Indexers; - -namespace NzbDrone.Core.IndexerStats -{ - public interface IIndexerStatisticsRepository - { - List<IndexerStatistics> IndexerStatistics(); - List<UserAgentStatistics> UserAgentStatistics(); - List<HostStatistics> HostStatistics(); - } - - public class IndexerStatisticsRepository : IIndexerStatisticsRepository - { - private const string _selectTemplate = "SELECT /**select**/ FROM History /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/ /**orderby**/"; - - private readonly IMainDatabase _database; - - public IndexerStatisticsRepository(IMainDatabase database) - { - _database = database; - } - - public List<IndexerStatistics> IndexerStatistics() - { - var time = DateTime.UtcNow; - return Query(IndexerBuilder()); - } - - public List<UserAgentStatistics> UserAgentStatistics() - { - var time = DateTime.UtcNow; - return UserAgentQuery(UserAgentBuilder()); - } - - public List<HostStatistics> HostStatistics() - { - var time = DateTime.UtcNow; - return HostQuery(HostBuilder()); - } - - private List<IndexerStatistics> Query(SqlBuilder builder) - { - var sql = builder.AddTemplate(_selectTemplate).LogQuery(); - - using (var conn = _database.OpenConnection()) - { - return conn.Query<IndexerStatistics>(sql.RawSql, sql.Parameters).ToList(); - } - } - - private List<UserAgentStatistics> UserAgentQuery(SqlBuilder builder) - { - var sql = builder.AddTemplate(_selectTemplate).LogQuery(); - - using (var conn = _database.OpenConnection()) - { - return conn.Query<UserAgentStatistics>(sql.RawSql, sql.Parameters).ToList(); - } - } - - private List<HostStatistics> HostQuery(SqlBuilder builder) - { - var sql = builder.AddTemplate(_selectTemplate).LogQuery(); - - using (var conn = _database.OpenConnection()) - { - return conn.Query<HostStatistics>(sql.RawSql, sql.Parameters).ToList(); - } - } - - private SqlBuilder IndexerBuilder() => new SqlBuilder() - .Select(@"Indexers.Id AS IndexerId, - Indexers.Name AS IndexerName, - SUM(CASE WHEN EventType == 2 then 1 else 0 end) AS NumberOfQueries, - SUM(CASE WHEN EventType == 2 AND Successful == 0 then 1 else 0 end) AS NumberOfFailedQueries, - SUM(CASE WHEN EventType == 3 then 1 else 0 end) AS NumberOfRssQueries, - SUM(CASE WHEN EventType == 3 AND Successful == 0 then 1 else 0 end) AS NumberOfFailedRssQueries, - SUM(CASE WHEN EventType == 4 then 1 else 0 end) AS NumberOfAuthQueries, - SUM(CASE WHEN EventType == 4 AND Successful == 0 then 1 else 0 end) AS NumberOfFailedAuthQueries, - SUM(CASE WHEN EventType == 1 then 1 else 0 end) AS NumberOfGrabs, - SUM(CASE WHEN EventType == 1 AND Successful == 0 then 1 else 0 end) AS NumberOfFailedGrabs, - AVG(json_extract(History.Data,'$.elapsedTime')) AS AverageResponseTime") - .Join<History.History, IndexerDefinition>((t, r) => t.IndexerId == r.Id) - .GroupBy<IndexerDefinition>(x => x.Id); - - private SqlBuilder UserAgentBuilder() => new SqlBuilder() - .Select(@"json_extract(History.Data,'$.source') AS UserAgent, - SUM(CASE WHEN EventType == 2 OR EventType == 3 then 1 else 0 end) AS NumberOfQueries, - SUM(CASE WHEN EventType == 1 then 1 else 0 end) AS NumberOfGrabs") - .GroupBy("UserAgent"); - - private SqlBuilder HostBuilder() => new SqlBuilder() - .Select(@"json_extract(History.Data,'$.host') AS Host, - SUM(CASE WHEN EventType == 2 OR EventType == 3 then 1 else 0 end) AS NumberOfQueries, - SUM(CASE WHEN EventType == 1 then 1 else 0 end) AS NumberOfGrabs") - .GroupBy("Host"); - } -} diff --git a/src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs b/src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs index 0e3eb370f..7bd8cd075 100644 --- a/src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs +++ b/src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs @@ -1,43 +1,174 @@ +using System; using System.Collections.Generic; using System.Linq; +using NzbDrone.Core.History; +using NzbDrone.Core.Indexers; namespace NzbDrone.Core.IndexerStats { public interface IIndexerStatisticsService { - List<IndexerStatistics> IndexerStatistics(); - List<UserAgentStatistics> UserAgentStatistics(); - List<HostStatistics> HostStatistics(); + CombinedStatistics IndexerStatistics(DateTime start, DateTime end); } public class IndexerStatisticsService : IIndexerStatisticsService { - private readonly IIndexerStatisticsRepository _indexerStatisticsRepository; + private readonly IIndexerFactory _indexerFactory; + private readonly IHistoryService _historyService; - public IndexerStatisticsService(IIndexerStatisticsRepository indexerStatisticsRepository) + public IndexerStatisticsService(IHistoryService historyService, IIndexerFactory indexerFactory) { - _indexerStatisticsRepository = indexerStatisticsRepository; + _historyService = historyService; + _indexerFactory = indexerFactory; } - public List<IndexerStatistics> IndexerStatistics() + public CombinedStatistics IndexerStatistics(DateTime start, DateTime end) { - var indexerStatistics = _indexerStatisticsRepository.IndexerStatistics(); + var history = _historyService.Between(start, end); - return indexerStatistics.ToList(); - } + var groupedByIndexer = history.GroupBy(h => h.IndexerId); + var groupedByUserAgent = history.GroupBy(h => h.Data.GetValueOrDefault("source") ?? ""); + var groupedByHost = history.GroupBy(h => h.Data.GetValueOrDefault("host") ?? ""); - public List<UserAgentStatistics> UserAgentStatistics() - { - var userAgentStatistics = _indexerStatisticsRepository.UserAgentStatistics(); + var indexerStatsList = new List<IndexerStatistics>(); + var userAgentStatsList = new List<UserAgentStatistics>(); + var hostStatsList = new List<HostStatistics>(); - return userAgentStatistics.ToList(); - } + var indexers = _indexerFactory.All(); - public List<HostStatistics> HostStatistics() - { - var hostStatistics = _indexerStatisticsRepository.HostStatistics(); + foreach (var indexer in groupedByIndexer) + { + var indexerDef = indexers.SingleOrDefault(i => i.Id == indexer.Key); - return hostStatistics.ToList(); + if (indexerDef == null) + { + continue; + } + + var indexerStats = new IndexerStatistics + { + IndexerId = indexer.Key, + IndexerName = indexerDef.Name + }; + + var sortedEvents = indexer.OrderBy(v => v.Date) + .ThenBy(v => v.Id) + .ToArray(); + + indexerStats.AverageResponseTime = (int)sortedEvents.Where(h => h.Data.ContainsKey("elapsedTime")).Select(h => int.Parse(h.Data.GetValueOrDefault("elapsedTime"))).Average(); + + foreach (var historyEvent in sortedEvents) + { + var failed = !historyEvent.Successful; + switch (historyEvent.EventType) + { + case HistoryEventType.IndexerQuery: + indexerStats.NumberOfQueries++; + if (failed) + { + indexerStats.NumberOfFailedQueries++; + } + + break; + case HistoryEventType.IndexerAuth: + indexerStats.NumberOfAuthQueries++; + if (failed) + { + indexerStats.NumberOfFailedAuthQueries++; + } + + break; + case HistoryEventType.ReleaseGrabbed: + indexerStats.NumberOfGrabs++; + if (failed) + { + indexerStats.NumberOfFailedGrabs++; + } + + break; + case HistoryEventType.IndexerRss: + indexerStats.NumberOfRssQueries++; + if (failed) + { + indexerStats.NumberOfFailedRssQueries++; + } + + break; + default: + break; + } + } + + indexerStatsList.Add(indexerStats); + } + + foreach (var indexer in groupedByUserAgent) + { + var indexerStats = new UserAgentStatistics + { + UserAgent = indexer.Key + }; + + var sortedEvents = indexer.OrderBy(v => v.Date) + .ThenBy(v => v.Id) + .ToArray(); + + foreach (var historyEvent in sortedEvents) + { + switch (historyEvent.EventType) + { + case HistoryEventType.IndexerRss: + case HistoryEventType.IndexerQuery: + indexerStats.NumberOfQueries++; + + break; + case HistoryEventType.ReleaseGrabbed: + indexerStats.NumberOfGrabs++; + break; + default: + break; + } + } + + userAgentStatsList.Add(indexerStats); + } + + foreach (var indexer in groupedByHost) + { + var indexerStats = new HostStatistics + { + Host = indexer.Key + }; + + var sortedEvents = indexer.OrderBy(v => v.Date) + .ThenBy(v => v.Id) + .ToArray(); + + foreach (var historyEvent in sortedEvents) + { + switch (historyEvent.EventType) + { + case HistoryEventType.IndexerRss: + case HistoryEventType.IndexerQuery: + indexerStats.NumberOfQueries++; + break; + case HistoryEventType.ReleaseGrabbed: + indexerStats.NumberOfGrabs++; + break; + default: + break; + } + } + + hostStatsList.Add(indexerStats); + } + + return new CombinedStatistics + { + IndexerStatistics = indexerStatsList, + UserAgentStatistics = userAgentStatsList, + HostStatistics = hostStatsList + }; } } } diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerStatsController.cs b/src/Prowlarr.Api.V1/Indexers/IndexerStatsController.cs index 10c5519f7..e3a13d066 100644 --- a/src/Prowlarr.Api.V1/Indexers/IndexerStatsController.cs +++ b/src/Prowlarr.Api.V1/Indexers/IndexerStatsController.cs @@ -1,3 +1,4 @@ +using System; using Microsoft.AspNetCore.Mvc; using NzbDrone.Core.IndexerStats; using Prowlarr.Http; @@ -15,13 +16,16 @@ namespace Prowlarr.Api.V1.Indexers } [HttpGet] - public IndexerStatsResource GetAll() + public IndexerStatsResource GetAll(DateTime? startDate, DateTime? endDate) { + var statsStartDate = startDate ?? DateTime.Now.AddDays(-30); + var statsEndDate = endDate ?? DateTime.Now; + var indexerResource = new IndexerStatsResource { - Indexers = _indexerStatisticsService.IndexerStatistics(), - UserAgents = _indexerStatisticsService.UserAgentStatistics(), - Hosts = _indexerStatisticsService.HostStatistics() + Indexers = _indexerStatisticsService.IndexerStatistics(statsStartDate, statsEndDate).IndexerStatistics, + UserAgents = _indexerStatisticsService.IndexerStatistics(statsStartDate, statsEndDate).UserAgentStatistics, + Hosts = _indexerStatisticsService.IndexerStatistics(statsStartDate, statsEndDate).HostStatistics }; return indexerResource; From df764ce8b4ed5c065cb592067c994b375fe10c5e Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 26 Sep 2021 12:27:50 -0500 Subject: [PATCH 0206/2320] New: Postgres Support --- frontend/src/System/Status/About/About.js | 19 +++-- .../Configuration/ConfigFileProvider.cs | 12 +++ .../Datastore/BasicRepository.cs | 25 +++++-- .../Datastore/ConnectionStringFactory.cs | 29 ++++++- src/NzbDrone.Core/Datastore/Database.cs | 45 ++++++++++- src/NzbDrone.Core/Datastore/DbFactory.cs | 18 ++++- .../Datastore/Extensions/BuilderExtensions.cs | 2 +- src/NzbDrone.Core/Datastore/LogDatabase.cs | 6 +- src/NzbDrone.Core/Datastore/MainDatabase.cs | 6 +- .../Migration/005_update_notifiarr.cs | 2 +- .../Datastore/Migration/007_history_failed.cs | 3 +- .../Datastore/Migration/008_redacted_api.cs | 4 +- .../Migration/013_desi_gazelle_to_unit3d.cs | 2 +- .../Framework/MigrationController.cs | 16 +++- src/NzbDrone.Core/Datastore/TableMapper.cs | 75 +++++++++++++++++-- .../Housekeepers/CleanupAdditionalUsers.cs | 8 +- .../CleanupOrphanedDownloadClientStatus.cs | 14 ++-- .../CleanupOrphanedHistoryItems.cs | 12 +-- .../CleanupOrphanedIndexerStatus.cs | 12 +-- .../Housekeepers/CleanupUnusedTags.cs | 13 +++- .../FixFutureRunScheduledTasks.cs | 8 +- .../Instrumentation/DatabaseTarget.cs | 73 +++++++++++++----- .../Messaging/Commands/CommandRepository.cs | 2 +- src/NzbDrone.Core/Prowlarr.Core.csproj | 2 + .../System/SystemController.cs | 3 +- 25 files changed, 320 insertions(+), 91 deletions(-) diff --git a/frontend/src/System/Status/About/About.js b/frontend/src/System/Status/About/About.js index d69d0b5d0..43b0deb9b 100644 --- a/frontend/src/System/Status/About/About.js +++ b/frontend/src/System/Status/About/About.js @@ -20,10 +20,11 @@ class About extends Component { packageVersion, packageAuthor, isNetCore, - isMono, isDocker, runtimeVersion, migrationVersion, + databaseVersion, + databaseType, appData, startupPath, mode, @@ -48,14 +49,6 @@ class About extends Component { /> } - { - isMono && - <DescriptionListItem - title={translate('MonoVersion')} - data={runtimeVersion} - /> - } - { isNetCore && <DescriptionListItem @@ -77,6 +70,11 @@ class About extends Component { data={migrationVersion} /> + <DescriptionListItem + title={translate('Database')} + data={`${titleCase(databaseType)} ${databaseVersion}`} + /> + <DescriptionListItem title={translate('AppDataDirectory')} data={appData} @@ -114,9 +112,10 @@ About.propTypes = { packageVersion: PropTypes.string, packageAuthor: PropTypes.string, isNetCore: PropTypes.bool.isRequired, - isMono: PropTypes.bool.isRequired, runtimeVersion: PropTypes.string.isRequired, isDocker: PropTypes.bool.isRequired, + databaseType: PropTypes.string.isRequired, + databaseVersion: PropTypes.string.isRequired, migrationVersion: PropTypes.number.isRequired, appData: PropTypes.string.isRequired, startupPath: PropTypes.string.isRequired, diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index 28e5639cd..7f1490eec 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -47,6 +47,12 @@ namespace NzbDrone.Core.Configuration string UpdateScriptPath { get; } string SyslogServer { get; } int SyslogPort { get; } + string PostgresHost { get; } + int PostgresPort { get; } + string PostgresUser { get; } + string PostgresPassword { get; } + string PostgresMainDb { get; } + string PostgresLogDb { get; } } public class ConfigFileProvider : IConfigFileProvider @@ -186,6 +192,12 @@ namespace NzbDrone.Core.Configuration public string LogLevel => GetValue("LogLevel", "info").ToLowerInvariant(); public string ConsoleLogLevel => GetValue("ConsoleLogLevel", string.Empty, persist: false); + public string PostgresHost => GetValue("PostgresHost", string.Empty, persist: false); + public string PostgresUser => GetValue("PostgresUser", string.Empty, persist: false); + public string PostgresPassword => GetValue("PostgresPassword", string.Empty, persist: false); + public string PostgresMainDb => GetValue("PostgresMainDb", "prowlarr-main", persist: false); + public string PostgresLogDb => GetValue("PostgresLogDb", "prowlarr-log", persist: false); + public int PostgresPort => GetValueInt("PostgresPort", 5436, persist: false); public bool LogSql => GetValueBoolean("LogSql", false, persist: false); public int LogRotate => GetValueInt("LogRotate", 50, persist: false); public bool FilterSentryEvents => GetValueBoolean("FilterSentryEvents", true, persist: false); diff --git a/src/NzbDrone.Core/Datastore/BasicRepository.cs b/src/NzbDrone.Core/Datastore/BasicRepository.cs index 4bf0d0c83..c03ecae4b 100644 --- a/src/NzbDrone.Core/Datastore/BasicRepository.cs +++ b/src/NzbDrone.Core/Datastore/BasicRepository.cs @@ -78,7 +78,7 @@ namespace NzbDrone.Core.Datastore { using (var conn = _database.OpenConnection()) { - return conn.ExecuteScalar<int>($"SELECT COUNT(*) FROM {_table}"); + return conn.ExecuteScalar<int>($"SELECT COUNT(*) FROM \"{_table}\""); } } @@ -167,14 +167,22 @@ namespace NzbDrone.Core.Datastore } } - return $"INSERT INTO {_table} ({sbColumnList.ToString()}) VALUES ({sbParameterList.ToString()}); SELECT last_insert_rowid() id"; + if (_database.DatabaseType == DatabaseType.SQLite) + { + return $"INSERT INTO {_table} ({sbColumnList.ToString()}) VALUES ({sbParameterList.ToString()}); SELECT last_insert_rowid() id"; + } + else + { + return $"INSERT INTO \"{_table}\" ({sbColumnList.ToString()}) VALUES ({sbParameterList.ToString()}) RETURNING \"Id\""; + } } private TModel Insert(IDbConnection connection, IDbTransaction transaction, TModel model) { SqlBuilderExtensions.LogQuery(_insertSql, model); var multi = connection.QueryMultiple(_insertSql, model, transaction); - var id = (int)multi.Read().First().id; + var multiRead = multi.Read(); + var id = (int)(multiRead.First().id ?? multiRead.First().Id); _keyProperty.SetValue(model, id); _database.ApplyLazyLoad(model); @@ -287,7 +295,7 @@ namespace NzbDrone.Core.Datastore { using (var conn = _database.OpenConnection()) { - conn.Execute($"DELETE FROM [{_table}]"); + conn.Execute($"DELETE FROM \"{_table}\""); } if (vacuum) @@ -346,7 +354,7 @@ namespace NzbDrone.Core.Datastore private string GetUpdateSql(List<PropertyInfo> propertiesToUpdate) { var sb = new StringBuilder(); - sb.AppendFormat("UPDATE {0} SET ", _table); + sb.AppendFormat("UPDATE \"{0}\" SET ", _table); for (var i = 0; i < propertiesToUpdate.Count; i++) { @@ -414,9 +422,12 @@ namespace NzbDrone.Core.Datastore pagingSpec.SortKey = $"{_table}.{_keyProperty.Name}"; } + var sortKey = TableMapping.Mapper.GetSortKey(pagingSpec.SortKey); + var sortDirection = pagingSpec.SortDirection == SortDirection.Descending ? "DESC" : "ASC"; - var pagingOffset = (pagingSpec.Page - 1) * pagingSpec.PageSize; - builder.OrderBy($"{pagingSpec.SortKey} {sortDirection} LIMIT {pagingSpec.PageSize} OFFSET {pagingOffset}"); + + var pagingOffset = Math.Max(pagingSpec.Page - 1, 0) * pagingSpec.PageSize; + builder.OrderBy($"\"{sortKey}\" {sortDirection} LIMIT {pagingSpec.PageSize} OFFSET {pagingOffset}"); return queryFunc(builder).ToList(); } diff --git a/src/NzbDrone.Core/Datastore/ConnectionStringFactory.cs b/src/NzbDrone.Core/Datastore/ConnectionStringFactory.cs index 9bdd133f7..961d060f8 100644 --- a/src/NzbDrone.Core/Datastore/ConnectionStringFactory.cs +++ b/src/NzbDrone.Core/Datastore/ConnectionStringFactory.cs @@ -1,7 +1,9 @@ using System; using System.Data.SQLite; +using Npgsql; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Configuration; namespace NzbDrone.Core.Datastore { @@ -14,10 +16,17 @@ namespace NzbDrone.Core.Datastore public class ConnectionStringFactory : IConnectionStringFactory { - public ConnectionStringFactory(IAppFolderInfo appFolderInfo) + private readonly IConfigFileProvider _configFileProvider; + + public ConnectionStringFactory(IAppFolderInfo appFolderInfo, IConfigFileProvider configFileProvider) { - MainDbConnectionString = GetConnectionString(appFolderInfo.GetDatabase()); - LogDbConnectionString = GetConnectionString(appFolderInfo.GetLogDatabase()); + _configFileProvider = configFileProvider; + + MainDbConnectionString = _configFileProvider.PostgresHost.IsNotNullOrWhiteSpace() ? GetPostgresConnectionString(_configFileProvider.PostgresMainDb) : + GetConnectionString(appFolderInfo.GetDatabase()); + + LogDbConnectionString = _configFileProvider.PostgresHost.IsNotNullOrWhiteSpace() ? GetPostgresConnectionString(_configFileProvider.PostgresLogDb) : + GetConnectionString(appFolderInfo.GetLogDatabase()); } public string MainDbConnectionString { get; private set; } @@ -48,5 +57,19 @@ namespace NzbDrone.Core.Datastore return connectionBuilder.ConnectionString; } + + private string GetPostgresConnectionString(string dbName) + { + var connectionBuilder = new NpgsqlConnectionStringBuilder(); + + connectionBuilder.Database = dbName; + connectionBuilder.Host = _configFileProvider.PostgresHost; + connectionBuilder.Username = _configFileProvider.PostgresUser; + connectionBuilder.Password = _configFileProvider.PostgresPassword; + connectionBuilder.Port = _configFileProvider.PostgresPort; + connectionBuilder.Enlist = false; + + return connectionBuilder.ConnectionString; + } } } diff --git a/src/NzbDrone.Core/Datastore/Database.cs b/src/NzbDrone.Core/Datastore/Database.cs index a9b6e807f..fd262f90d 100644 --- a/src/NzbDrone.Core/Datastore/Database.cs +++ b/src/NzbDrone.Core/Datastore/Database.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.Data; +using System.Text.RegularExpressions; using Dapper; using NLog; using NzbDrone.Common.Instrumentation; @@ -11,6 +12,7 @@ namespace NzbDrone.Core.Datastore IDbConnection OpenConnection(); Version Version { get; } int Migration { get; } + DatabaseType DatabaseType { get; } void Vacuum(); } @@ -32,13 +34,44 @@ namespace NzbDrone.Core.Datastore return _datamapperFactory(); } + public DatabaseType DatabaseType + { + get + { + using (var db = _datamapperFactory()) + { + if (db.ConnectionString.Contains(".db")) + { + return DatabaseType.SQLite; + } + else + { + return DatabaseType.PostgreSQL; + } + } + } + } + public Version Version { get { using (var db = _datamapperFactory()) { - var version = db.QueryFirstOrDefault<string>("SELECT sqlite_version()"); + string version; + + try + { + version = db.QueryFirstOrDefault<string>("SHOW server_version"); + + //Postgres can return extra info about operating system on version call, ignore this + version = Regex.Replace(version, @"\(.*?\)", ""); + } + catch + { + version = db.QueryFirstOrDefault<string>("SELECT sqlite_version()"); + } + return new Version(version); } } @@ -50,7 +83,7 @@ namespace NzbDrone.Core.Datastore { using (var db = _datamapperFactory()) { - return db.QueryFirstOrDefault<int>("SELECT version from VersionInfo ORDER BY version DESC LIMIT 1"); + return db.QueryFirstOrDefault<int>("SELECT \"Version\" from \"VersionInfo\" ORDER BY \"Version\" DESC LIMIT 1"); } } } @@ -73,4 +106,10 @@ namespace NzbDrone.Core.Datastore } } } + + public enum DatabaseType + { + SQLite, + PostgreSQL + } } diff --git a/src/NzbDrone.Core/Datastore/DbFactory.cs b/src/NzbDrone.Core/Datastore/DbFactory.cs index bd115d6d8..c62442d1b 100644 --- a/src/NzbDrone.Core/Datastore/DbFactory.cs +++ b/src/NzbDrone.Core/Datastore/DbFactory.cs @@ -1,10 +1,13 @@ using System; +using System.Data.Common; using System.Data.SQLite; using NLog; +using Npgsql; using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Exceptions; using NzbDrone.Common.Instrumentation; +using NzbDrone.Core.Configuration; using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore @@ -85,10 +88,19 @@ namespace NzbDrone.Core.Datastore var db = new Database(migrationContext.MigrationType.ToString(), () => { - var conn = SQLiteFactory.Instance.CreateConnection(); - conn.ConnectionString = connectionString; - conn.Open(); + DbConnection conn; + if (connectionString.Contains(".db")) + { + conn = SQLiteFactory.Instance.CreateConnection(); + conn.ConnectionString = connectionString; + } + else + { + conn = new NpgsqlConnection(connectionString); + } + + conn.Open(); return conn; }); diff --git a/src/NzbDrone.Core/Datastore/Extensions/BuilderExtensions.cs b/src/NzbDrone.Core/Datastore/Extensions/BuilderExtensions.cs index 97ce5d731..dc3e442f2 100644 --- a/src/NzbDrone.Core/Datastore/Extensions/BuilderExtensions.cs +++ b/src/NzbDrone.Core/Datastore/Extensions/BuilderExtensions.cs @@ -20,7 +20,7 @@ namespace NzbDrone.Core.Datastore public static SqlBuilder Select(this SqlBuilder builder, params Type[] types) { - return builder.Select(types.Select(x => TableMapping.Mapper.TableNameMapping(x) + ".*").Join(", ")); + return builder.Select(types.Select(x => $"\"{TableMapping.Mapper.TableNameMapping(x)}\".*").Join(", ")); } public static SqlBuilder SelectDistinct(this SqlBuilder builder, params Type[] types) diff --git a/src/NzbDrone.Core/Datastore/LogDatabase.cs b/src/NzbDrone.Core/Datastore/LogDatabase.cs index f992c8bbe..e29252d2a 100644 --- a/src/NzbDrone.Core/Datastore/LogDatabase.cs +++ b/src/NzbDrone.Core/Datastore/LogDatabase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Data; namespace NzbDrone.Core.Datastore @@ -10,10 +10,12 @@ namespace NzbDrone.Core.Datastore public class LogDatabase : ILogDatabase { private readonly IDatabase _database; + private readonly DatabaseType _databaseType; public LogDatabase(IDatabase database) { _database = database; + _databaseType = _database == null ? DatabaseType.SQLite : _database.DatabaseType; } public IDbConnection OpenConnection() @@ -25,6 +27,8 @@ namespace NzbDrone.Core.Datastore public int Migration => _database.Migration; + public DatabaseType DatabaseType => _databaseType; + public void Vacuum() { _database.Vacuum(); diff --git a/src/NzbDrone.Core/Datastore/MainDatabase.cs b/src/NzbDrone.Core/Datastore/MainDatabase.cs index 4a9d3298c..e3e237441 100644 --- a/src/NzbDrone.Core/Datastore/MainDatabase.cs +++ b/src/NzbDrone.Core/Datastore/MainDatabase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Data; namespace NzbDrone.Core.Datastore @@ -10,10 +10,12 @@ namespace NzbDrone.Core.Datastore public class MainDatabase : IMainDatabase { private readonly IDatabase _database; + private readonly DatabaseType _databaseType; public MainDatabase(IDatabase database) { _database = database; + _databaseType = _database == null ? DatabaseType.SQLite : _database.DatabaseType; } public IDbConnection OpenConnection() @@ -25,6 +27,8 @@ namespace NzbDrone.Core.Datastore public int Migration => _database.Migration; + public DatabaseType DatabaseType => _databaseType; + public void Vacuum() { _database.Vacuum(); diff --git a/src/NzbDrone.Core/Datastore/Migration/005_update_notifiarr.cs b/src/NzbDrone.Core/Datastore/Migration/005_update_notifiarr.cs index 5f7606ba2..91a239d5f 100644 --- a/src/NzbDrone.Core/Datastore/Migration/005_update_notifiarr.cs +++ b/src/NzbDrone.Core/Datastore/Migration/005_update_notifiarr.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Execute.Sql("UPDATE Notifications SET Implementation = Replace(Implementation, 'DiscordNotifier', 'Notifiarr'),ConfigContract = Replace(ConfigContract, 'DiscordNotifierSettings', 'NotifiarrSettings') WHERE Implementation = 'DiscordNotifier';"); + Execute.Sql("UPDATE \"Notifications\" SET \"Implementation\" = Replace(\"Implementation\", 'DiscordNotifier', 'Notifiarr'),\"ConfigContract\" = Replace(\"ConfigContract\", 'DiscordNotifierSettings', 'NotifiarrSettings') WHERE \"Implementation\" = 'DiscordNotifier';"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/007_history_failed.cs b/src/NzbDrone.Core/Datastore/Migration/007_history_failed.cs index 287a6c18e..845da3ab9 100644 --- a/src/NzbDrone.Core/Datastore/Migration/007_history_failed.cs +++ b/src/NzbDrone.Core/Datastore/Migration/007_history_failed.cs @@ -11,7 +11,8 @@ namespace NzbDrone.Core.Datastore.Migration Alter.Table("History") .AddColumn("Successful").AsBoolean().NotNullable().WithDefaultValue(true); - Execute.Sql("UPDATE History SET Successful = (json_extract(History.Data,'$.successful') == 'True' );"); + // Postgres added after this, not needed + IfDatabase("sqlite").Execute.Sql("UPDATE \"History\" SET \"Successful\" = (json_extract(\"History\".\"Data\",'$.successful') == 'True' );"); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/008_redacted_api.cs b/src/NzbDrone.Core/Datastore/Migration/008_redacted_api.cs index ac6c4ba38..796e74d13 100644 --- a/src/NzbDrone.Core/Datastore/Migration/008_redacted_api.cs +++ b/src/NzbDrone.Core/Datastore/Migration/008_redacted_api.cs @@ -19,7 +19,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var cmd = conn.CreateCommand()) { cmd.Transaction = tran; - cmd.CommandText = "SELECT Id, Settings FROM Indexers WHERE Implementation = 'Redacted'"; + cmd.CommandText = "SELECT \"Id\", \"Settings\" FROM \"Indexers\" WHERE \"Implementation\" = 'Redacted'"; using (var reader = cmd.ExecuteReader()) { @@ -48,7 +48,7 @@ namespace NzbDrone.Core.Datastore.Migration using (var updateCmd = conn.CreateCommand()) { updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE Indexers SET Settings = ?, ConfigContract = ?, Enable = 0 WHERE Id = ?"; + updateCmd.CommandText = "UPDATE \"Indexers\" SET \"Settings\" = ?, \"ConfigContract\" = ?, \"Enable\" = 0 WHERE \"Id\" = ?"; updateCmd.AddParameter(settings); updateCmd.AddParameter("RedactedSettings"); updateCmd.AddParameter(id); diff --git a/src/NzbDrone.Core/Datastore/Migration/013_desi_gazelle_to_unit3d.cs b/src/NzbDrone.Core/Datastore/Migration/013_desi_gazelle_to_unit3d.cs index c066fa8a8..be02bcf1f 100644 --- a/src/NzbDrone.Core/Datastore/Migration/013_desi_gazelle_to_unit3d.cs +++ b/src/NzbDrone.Core/Datastore/Migration/013_desi_gazelle_to_unit3d.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Update.Table("Indexers").Set(new { ConfigContract = "Unit3dSettings", Enable = 0 }).Where(new { Implementation = "DesiTorrents" }); + Update.Table("Indexers").Set(new { ConfigContract = "Unit3dSettings", Enable = true }).Where(new { Implementation = "DesiTorrents" }); } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationController.cs b/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationController.cs index 35c5c6b59..1249dfd8b 100644 --- a/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationController.cs +++ b/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationController.cs @@ -2,6 +2,7 @@ using System; using System.Diagnostics; using System.Reflection; using FluentMigrator.Runner; +using FluentMigrator.Runner.Generators; using FluentMigrator.Runner.Initialization; using FluentMigrator.Runner.Processors; using Microsoft.Extensions.DependencyInjection; @@ -34,11 +35,16 @@ namespace NzbDrone.Core.Datastore.Migration.Framework _logger.Info("*** Migrating {0} ***", connectionString); - var serviceProvider = new ServiceCollection() + ServiceProvider serviceProvider; + + var db = connectionString.Contains(".db") ? "sqlite" : "postgres"; + + serviceProvider = new ServiceCollection() .AddLogging(b => b.AddNLog()) .AddFluentMigratorCore() .ConfigureRunner( builder => builder + .AddPostgres() .AddNzbDroneSQLite() .WithGlobalConnectionString(connectionString) .WithMigrationsIn(Assembly.GetExecutingAssembly())) @@ -48,6 +54,14 @@ namespace NzbDrone.Core.Datastore.Migration.Framework opt.PreviewOnly = false; opt.Timeout = TimeSpan.FromSeconds(60); }) + .Configure<SelectingProcessorAccessorOptions>(cfg => + { + cfg.ProcessorId = db; + }) + .Configure<SelectingGeneratorAccessorOptions>(cfg => + { + cfg.GeneratorId = db; + }) .BuildServiceProvider(); using (var scope = serviceProvider.CreateScope()) diff --git a/src/NzbDrone.Core/Datastore/TableMapper.cs b/src/NzbDrone.Core/Datastore/TableMapper.cs index 0dbfca678..bbb84b9cb 100644 --- a/src/NzbDrone.Core/Datastore/TableMapper.cs +++ b/src/NzbDrone.Core/Datastore/TableMapper.cs @@ -8,6 +8,8 @@ namespace NzbDrone.Core.Datastore { public class TableMapper { + private readonly HashSet<string> _allowedOrderBy = new HashSet<string>(StringComparer.OrdinalIgnoreCase); + public TableMapper() { IgnoreList = new Dictionary<Type, List<PropertyInfo>>(); @@ -27,12 +29,12 @@ namespace NzbDrone.Core.Datastore if (IgnoreList.TryGetValue(type, out var list)) { - return new ColumnMapper<TEntity>(list, LazyLoadList[type]); + return new ColumnMapper<TEntity>(list, LazyLoadList[type], _allowedOrderBy); } IgnoreList[type] = new List<PropertyInfo>(); LazyLoadList[type] = new List<LazyLoadedProperty>(); - return new ColumnMapper<TEntity>(IgnoreList[type], LazyLoadList[type]); + return new ColumnMapper<TEntity>(IgnoreList[type], LazyLoadList[type], _allowedOrderBy); } public List<PropertyInfo> ExcludeProperties(Type x) @@ -40,6 +42,64 @@ namespace NzbDrone.Core.Datastore return IgnoreList.ContainsKey(x) ? IgnoreList[x] : new List<PropertyInfo>(); } + public bool IsValidSortKey(string sortKey) + { + string table = null; + + if (sortKey.Contains('.')) + { + var split = sortKey.Split('.'); + if (split.Length != 2) + { + return false; + } + + table = split[0]; + sortKey = split[1]; + } + + if (table != null && !TableMap.Values.Contains(table, StringComparer.OrdinalIgnoreCase)) + { + return false; + } + + if (!_allowedOrderBy.Contains(sortKey)) + { + return false; + } + + return true; + } + + public string GetSortKey(string sortKey) + { + string table = null; + + if (sortKey.Contains('.')) + { + var split = sortKey.Split('.'); + if (split.Length != 2) + { + return sortKey; + } + + table = split[0]; + sortKey = split[1]; + } + + if (table != null && !TableMap.Values.Contains(table, StringComparer.OrdinalIgnoreCase)) + { + return sortKey; + } + + if (!_allowedOrderBy.Contains(sortKey)) + { + return sortKey; + } + + return _allowedOrderBy.First(x => x.Equals(sortKey, StringComparison.OrdinalIgnoreCase)); + } + public string TableNameMapping(Type x) { return TableMap.ContainsKey(x) ? TableMap[x] : null; @@ -47,17 +107,17 @@ namespace NzbDrone.Core.Datastore public string SelectTemplate(Type x) { - return $"SELECT /**select**/ FROM {TableMap[x]} /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/ /**orderby**/"; + return $"SELECT /**select**/ FROM \"{TableMap[x]}\" /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/ /**orderby**/"; } public string DeleteTemplate(Type x) { - return $"DELETE FROM {TableMap[x]} /**where**/"; + return $"DELETE FROM \"{TableMap[x]}\" /**where**/"; } public string PageCountTemplate(Type x) { - return $"SELECT /**select**/ FROM {TableMap[x]} /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/"; + return $"SELECT /**select**/ FROM \"{TableMap[x]}\" /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/"; } } @@ -72,17 +132,20 @@ namespace NzbDrone.Core.Datastore { private readonly List<PropertyInfo> _ignoreList; private readonly List<LazyLoadedProperty> _lazyLoadList; + private readonly HashSet<string> _allowedOrderBy; - public ColumnMapper(List<PropertyInfo> ignoreList, List<LazyLoadedProperty> lazyLoadList) + public ColumnMapper(List<PropertyInfo> ignoreList, List<LazyLoadedProperty> lazyLoadList, HashSet<string> allowedOrderBy) { _ignoreList = ignoreList; _lazyLoadList = lazyLoadList; + _allowedOrderBy = allowedOrderBy; } public ColumnMapper<T> AutoMapPropertiesWhere(Func<PropertyInfo, bool> predicate) { var properties = typeof(T).GetProperties(); _ignoreList.AddRange(properties.Where(x => !predicate(x))); + _allowedOrderBy.UnionWith(properties.Where(x => predicate(x)).Select(x => x.Name)); return this; } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupAdditionalUsers.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupAdditionalUsers.cs index 4460ac83c..8b36317ec 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupAdditionalUsers.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupAdditionalUsers.cs @@ -1,4 +1,4 @@ -using Dapper; +using Dapper; using NzbDrone.Core.Datastore; namespace NzbDrone.Core.Housekeeping.Housekeepers @@ -16,9 +16,9 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers { using (var mapper = _database.OpenConnection()) { - mapper.Execute(@"DELETE FROM Users - WHERE ID NOT IN ( - SELECT ID FROM Users + mapper.Execute(@"DELETE FROM ""Users"" + WHERE ""Id"" NOT IN ( + SELECT ""Id"" FROM ""Users"" LIMIT 1)"); } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedDownloadClientStatus.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedDownloadClientStatus.cs index a5f584797..5a6af9fd8 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedDownloadClientStatus.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedDownloadClientStatus.cs @@ -1,4 +1,4 @@ -using Dapper; +using Dapper; using NzbDrone.Core.Datastore; namespace NzbDrone.Core.Housekeeping.Housekeepers @@ -16,12 +16,12 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers { var mapper = _database.OpenConnection(); - mapper.Execute(@"DELETE FROM DownloadClientStatus - WHERE Id IN ( - SELECT DownloadClientStatus.Id FROM DownloadClientStatus - LEFT OUTER JOIN DownloadClients - ON DownloadClientStatus.ProviderId = DownloadClients.Id - WHERE DownloadClients.Id IS NULL)"); + mapper.Execute(@"DELETE FROM ""DownloadClientStatus"" + WHERE ""Id"" IN ( + SELECT ""DownloadClientStatus"".""Id"" FROM ""DownloadClientStatus"" + LEFT OUTER JOIN ""DownloadClients"" + ON ""DownloadClientStatus"".""ProviderId"" = ""DownloadClients"".""Id"" + WHERE ""DownloadClients"".""Id"" IS NULL)"); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedHistoryItems.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedHistoryItems.cs index ad5a8e8ab..e6d8d789d 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedHistoryItems.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedHistoryItems.cs @@ -21,12 +21,12 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers { using (var mapper = _database.OpenConnection()) { - mapper.Execute(@"DELETE FROM History - WHERE Id IN ( - SELECT History.Id FROM History - LEFT OUTER JOIN Indexers - ON History.IndexerId = Indexers.Id - WHERE Indexers.Id IS NULL)"); + mapper.Execute(@"DELETE FROM ""History"" + WHERE ""Id"" IN ( + SELECT ""History"".""Id"" FROM ""History"" + LEFT OUTER JOIN ""Indexers"" + ON ""History"".""IndexerId"" = ""Indexers"".""Id"" + WHERE ""Indexers"".""Id"" IS NULL)"); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedIndexerStatus.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedIndexerStatus.cs index 039db9b52..059f059e4 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedIndexerStatus.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedIndexerStatus.cs @@ -16,12 +16,12 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers { using (var mapper = _database.OpenConnection()) { - mapper.Execute(@"DELETE FROM IndexerStatus - WHERE Id IN ( - SELECT IndexerStatus.Id FROM IndexerStatus - LEFT OUTER JOIN Indexers - ON IndexerStatus.ProviderId = Indexers.Id - WHERE Indexers.Id IS NULL)"); + mapper.Execute(@"DELETE FROM ""IndexerStatus"" + WHERE ""Id"" IN ( + SELECT ""IndexerStatus"".""Id"" FROM ""IndexerStatus"" + LEFT OUTER JOIN ""Indexers"" + ON ""IndexerStatus"".""ProviderId"" = ""Indexers"".""Id"" + WHERE ""Indexers"".""Id"" IS NULL)"); } } } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs index 4ee4afd78..1df062918 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs @@ -24,15 +24,22 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers .Distinct() .ToArray(); - var usedTagsList = string.Join(",", usedTags.Select(d => d.ToString()).ToArray()); + if (usedTags.Length > 0) + { + var usedTagsList = string.Join(",", usedTags.Select(d => d.ToString()).ToArray()); - mapper.Execute($"DELETE FROM Tags WHERE NOT Id IN ({usedTagsList})"); + mapper.Execute($"DELETE FROM \"Tags\" WHERE NOT \"Id\" IN ({usedTagsList})"); + } + else + { + mapper.Execute($"DELETE FROM \"Tags\""); + } } } private int[] GetUsedTags(string table, IDbConnection mapper) { - return mapper.Query<List<int>>($"SELECT DISTINCT Tags FROM {table} WHERE NOT Tags = '[]'") + return mapper.Query<List<int>>($"SELECT DISTINCT \"Tags\" FROM \"{table}\" WHERE NOT \"Tags\" = '[]'") .SelectMany(x => x) .Distinct() .ToArray(); diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/FixFutureRunScheduledTasks.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/FixFutureRunScheduledTasks.cs index 82a7af7fa..6b45ed0c4 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/FixFutureRunScheduledTasks.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/FixFutureRunScheduledTasks.cs @@ -1,4 +1,4 @@ -using System; +using System; using Dapper; using NLog; using NzbDrone.Common.EnvironmentInfo; @@ -26,9 +26,9 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers using (var mapper = _database.OpenConnection()) { - mapper.Execute(@"UPDATE ScheduledTasks - SET LastExecution = @time - WHERE LastExecution > @time", + mapper.Execute(@"UPDATE ""ScheduledTasks"" + SET ""LastExecution"" = @time + WHERE ""LastExecution"" > @time", new { time = DateTime.UtcNow }); } } diff --git a/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs b/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs index f761f3f7c..72ca2da08 100644 --- a/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs +++ b/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs @@ -1,9 +1,11 @@ -using System.Data; +using System; +using System.Data; using System.Data.SQLite; using NLog; using NLog.Common; using NLog.Config; using NLog.Targets; +using Npgsql; using NzbDrone.Common.Instrumentation; using NzbDrone.Core.Datastore; using NzbDrone.Core.Lifecycle; @@ -13,7 +15,7 @@ namespace NzbDrone.Core.Instrumentation { public class DatabaseTarget : TargetWithLayout, IHandle<ApplicationShutdownRequested> { - private const string INSERT_COMMAND = "INSERT INTO [Logs]([Message],[Time],[Logger],[Exception],[ExceptionType],[Level]) " + + private const string INSERT_COMMAND = "INSERT INTO \"Logs\" (\"Message\",\"Time\",\"Logger\",\"Exception\",\"ExceptionType\",\"Level\") " + "VALUES(@Message,@Time,@Logger,@Exception,@ExceptionType,@Level)"; private readonly IConnectionStringFactory _connectionStringFactory; @@ -83,23 +85,16 @@ namespace NzbDrone.Core.Instrumentation log.Level = logEvent.Level.Name; - using (var connection = - SQLiteFactory.Instance.CreateConnection()) - { - connection.ConnectionString = _connectionStringFactory.LogDbConnectionString; - connection.Open(); - using (var sqlCommand = connection.CreateCommand()) - { - sqlCommand.CommandText = INSERT_COMMAND; - sqlCommand.Parameters.Add(new SQLiteParameter("Message", DbType.String) { Value = log.Message }); - sqlCommand.Parameters.Add(new SQLiteParameter("Time", DbType.DateTime) { Value = log.Time.ToUniversalTime() }); - sqlCommand.Parameters.Add(new SQLiteParameter("Logger", DbType.String) { Value = log.Logger }); - sqlCommand.Parameters.Add(new SQLiteParameter("Exception", DbType.String) { Value = log.Exception }); - sqlCommand.Parameters.Add(new SQLiteParameter("ExceptionType", DbType.String) { Value = log.ExceptionType }); - sqlCommand.Parameters.Add(new SQLiteParameter("Level", DbType.String) { Value = log.Level }); + var connectionString = _connectionStringFactory.LogDbConnectionString; - sqlCommand.ExecuteNonQuery(); - } + //TODO: Probably need more robust way to differentiate what's being used + if (connectionString.Contains(".db")) + { + WriteSqliteLog(log, connectionString); + } + else + { + WritePostgresLog(log, connectionString); } } catch (SQLiteException ex) @@ -109,6 +104,48 @@ namespace NzbDrone.Core.Instrumentation } } + private void WritePostgresLog(Log log, string connectionString) + { + using (var connection = + new NpgsqlConnection(connectionString)) + { + connection.Open(); + using (var sqlCommand = connection.CreateCommand()) + { + sqlCommand.CommandText = INSERT_COMMAND; + sqlCommand.Parameters.Add(new NpgsqlParameter("Message", DbType.String) { Value = log.Message }); + sqlCommand.Parameters.Add(new NpgsqlParameter("Time", DbType.DateTime) { Value = log.Time.ToUniversalTime() }); + sqlCommand.Parameters.Add(new NpgsqlParameter("Logger", DbType.String) { Value = log.Logger }); + sqlCommand.Parameters.Add(new NpgsqlParameter("Exception", DbType.String) { Value = log.Exception == null ? DBNull.Value : log.Exception }); + sqlCommand.Parameters.Add(new NpgsqlParameter("ExceptionType", DbType.String) { Value = log.ExceptionType == null ? DBNull.Value : log.ExceptionType }); + sqlCommand.Parameters.Add(new NpgsqlParameter("Level", DbType.String) { Value = log.Level }); + + sqlCommand.ExecuteNonQuery(); + } + } + } + + private void WriteSqliteLog(Log log, string connectionString) + { + using (var connection = + SQLiteFactory.Instance.CreateConnection()) + { + connection.ConnectionString = connectionString; + connection.Open(); + using (var sqlCommand = connection.CreateCommand()) + { + sqlCommand.CommandText = INSERT_COMMAND; + sqlCommand.Parameters.Add(new SQLiteParameter("Message", DbType.String) { Value = log.Message }); + sqlCommand.Parameters.Add(new SQLiteParameter("Time", DbType.DateTime) { Value = log.Time.ToUniversalTime() }); + sqlCommand.Parameters.Add(new SQLiteParameter("Logger", DbType.String) { Value = log.Logger }); + sqlCommand.Parameters.Add(new SQLiteParameter("Exception", DbType.String) { Value = log.Exception }); + sqlCommand.Parameters.Add(new SQLiteParameter("ExceptionType", DbType.String) { Value = log.ExceptionType }); + sqlCommand.Parameters.Add(new SQLiteParameter("Level", DbType.String) { Value = log.Level }); + sqlCommand.ExecuteNonQuery(); + } + } + } + public void Handle(ApplicationShutdownRequested message) { if (LogManager.Configuration?.LoggingRules?.Contains(Rule) == true) diff --git a/src/NzbDrone.Core/Messaging/Commands/CommandRepository.cs b/src/NzbDrone.Core/Messaging/Commands/CommandRepository.cs index 1bf894ecc..d41f2fbba 100644 --- a/src/NzbDrone.Core/Messaging/Commands/CommandRepository.cs +++ b/src/NzbDrone.Core/Messaging/Commands/CommandRepository.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Messaging.Commands public void OrphanStarted() { - var sql = @"UPDATE Commands SET Status = @Orphaned, EndedAt = @Ended WHERE Status = @Started"; + var sql = @"UPDATE ""Commands"" SET ""Status"" = @Orphaned, ""EndedAt"" = @Ended WHERE ""Status"" = @Started"; var args = new { Orphaned = (int)CommandStatus.Orphaned, diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index 6d89467d0..99a4adc4d 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -9,9 +9,11 @@ <PackageReference Include="MailKit" Version="2.14.0" /> <PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" /> <PackageReference Include="NLog.Targets.Syslog" Version="6.0.2" /> + <PackageReference Include="Npgsql" Version="5.0.11" /> <PackageReference Include="System.Memory" Version="4.5.4" /> <PackageReference Include="System.ServiceModel.Syndication" Version="6.0.0" /> <PackageReference Include="FluentMigrator.Runner.SQLite" Version="3.3.1" /> + <PackageReference Include="FluentMigrator.Runner.Postgres" Version="3.3.1" /> <PackageReference Include="FluentValidation" Version="8.6.2" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="NLog" Version="4.7.9" /> diff --git a/src/Prowlarr.Api.V1/System/SystemController.cs b/src/Prowlarr.Api.V1/System/SystemController.cs index ec5e2f28c..66d058b71 100644 --- a/src/Prowlarr.Api.V1/System/SystemController.cs +++ b/src/Prowlarr.Api.V1/System/SystemController.cs @@ -77,7 +77,8 @@ namespace Prowlarr.Api.V1.System Mode = _runtimeInfo.Mode, Branch = _configFileProvider.Branch, Authentication = _configFileProvider.AuthenticationMethod, - SqliteVersion = _database.Version, + DatabaseType = _database.DatabaseType, + DatabaseVersion = _database.Version, MigrationVersion = _database.Migration, UrlBase = _configFileProvider.UrlBase, RuntimeVersion = _platformInfo.Version, From bf0a627a4eb6b788702037fd5ec07ac9c8406999 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 29 Nov 2021 21:58:29 -0600 Subject: [PATCH 0207/2320] New: (Indexer) PornoLab --- .../Indexers/Definitions/PornoLab.cs | 459 ++++++++++++++++++ 1 file changed, 459 insertions(+) create mode 100644 src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs diff --git a/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs b/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs new file mode 100644 index 000000000..8c7f3e032 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs @@ -0,0 +1,459 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using AngleSharp.Html.Parser; +using FluentValidation; +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Indexers.Definitions +{ + public class PornoLab : TorrentIndexerBase<PornoLabSettings> + { + public override string Name => "PornoLab"; + public override string[] IndexerUrls => new string[] { "https://pornolab.net/" }; + private string LoginUrl => Settings.BaseUrl + "forum/login.php"; + public override string Description => "PornoLab is a Semi-Private Russian site for Adult content"; + public override string Language => "ru-ru"; + public override Encoding Encoding => Encoding.GetEncoding("windows-1251"); + public override DownloadProtocol Protocol => DownloadProtocol.Torrent; + public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + public override IndexerCapabilities Capabilities => SetCapabilities(); + + public PornoLab(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) + { + } + + public override IIndexerRequestGenerator GetRequestGenerator() + { + return new PornoLabRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; + } + + public override IParseIndexerResponse GetParser() + { + return new PornoLabParser(Settings, Capabilities.Categories, _logger); + } + + protected override async Task DoLogin() + { + var requestBuilder = new HttpRequestBuilder(LoginUrl) + { + LogResponseContent = true, + AllowAutoRedirect = true, + Method = HttpMethod.POST + }; + + var authLoginRequest = requestBuilder + .AddFormParameter("login_username", Settings.Username) + .AddFormParameter("login_password", Settings.Password) + .AddFormParameter("login", "Login") + .SetHeader("Content-Type", "multipart/form-data") + .Build(); + + var response = await ExecuteAuth(authLoginRequest); + + if (CheckIfLoginNeeded(response)) + { + var errorMessage = "Unknown error message, please report"; + var loginResultParser = new HtmlParser(); + var loginResultDocument = loginResultParser.ParseDocument(response.Content); + var errormsg = loginResultDocument.QuerySelector("h4[class=\"warnColor1 tCenter mrg_16\"]"); + if (errormsg != null) + { + errorMessage = errormsg.TextContent; + } + + throw new IndexerAuthException(errorMessage); + } + + UpdateCookies(response.GetCookies(), DateTime.Now + TimeSpan.FromDays(30)); + + _logger.Debug("PornoLab authentication succeeded"); + } + + protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) + { + if (!httpResponse.Content.Contains("Вы зашли как:")) + { + return true; + } + + return false; + } + + private IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities + { + }; + + caps.Categories.AddCategoryMapping(1768, NewznabStandardCategory.XXX, "Эротические фильмы / Erotic Movies"); + caps.Categories.AddCategoryMapping(60, NewznabStandardCategory.XXX, "Документальные фильмы / Documentary & Reality"); + caps.Categories.AddCategoryMapping(1644, NewznabStandardCategory.XXX, "Нудизм-Натуризм / Nudity"); + + caps.Categories.AddCategoryMapping(1111, NewznabStandardCategory.XXXPack, "Паки полных фильмов / Full Length Movies Packs"); + caps.Categories.AddCategoryMapping(508, NewznabStandardCategory.XXX, "Классические фильмы / Classic"); + caps.Categories.AddCategoryMapping(555, NewznabStandardCategory.XXX, "Фильмы с сюжетом / Feature & Vignettes"); + caps.Categories.AddCategoryMapping(1673, NewznabStandardCategory.XXX, "Гонзо-фильмы 2011-2021 / Gonzo 2011-2021"); + caps.Categories.AddCategoryMapping(1112, NewznabStandardCategory.XXX, "Фильмы без сюжета 1991-2010 / All Sex & Amateur 1991-2010"); + caps.Categories.AddCategoryMapping(1718, NewznabStandardCategory.XXX, "Фильмы без сюжета 2011-2021 / All Sex & Amateur 2011-2021"); + caps.Categories.AddCategoryMapping(553, NewznabStandardCategory.XXX, "Лесбо-фильмы / All Girl & Solo"); + caps.Categories.AddCategoryMapping(1143, NewznabStandardCategory.XXX, "Этнические фильмы / Ethnic-Themed"); + caps.Categories.AddCategoryMapping(1646, NewznabStandardCategory.XXX, "Видео для телефонов и КПК / Pocket РС & Phone Video"); + + caps.Categories.AddCategoryMapping(1712, NewznabStandardCategory.XXX, "Эротические и Документальные фильмы (DVD и HD) / EroticDocumentary & Reality (DVD & HD)"); + caps.Categories.AddCategoryMapping(1713, NewznabStandardCategory.XXXDVD, "Фильмы с сюжетомКлассические (DVD) / Feature & Vignettes, Classic (DVD)"); + caps.Categories.AddCategoryMapping(512, NewznabStandardCategory.XXXDVD, "ГонзоЛесбо и Фильмы без сюжета (DVD) / Gonzo, All Girl & Solo, All Sex (DVD)"); + caps.Categories.AddCategoryMapping(1775, NewznabStandardCategory.XXX, "Фильмы с сюжетом (HD Video) / Feature & Vignettes (HD Video)"); + caps.Categories.AddCategoryMapping(1450, NewznabStandardCategory.XXX, "ГонзоЛесбо и Фильмы без сюжета (HD Video) / Gonzo, All Girl & Solo, All Sex (HD Video)"); + + caps.Categories.AddCategoryMapping(902, NewznabStandardCategory.XXX, "Русские порнофильмы / Russian Full Length Movies"); + caps.Categories.AddCategoryMapping(1675, NewznabStandardCategory.XXXPack, "Паки русских порнороликов / Russian Clips Packs"); + caps.Categories.AddCategoryMapping(36, NewznabStandardCategory.XXX, "Сайтрипы с русскими актрисами 1991-2015 / Russian SiteRip's 1991-2015"); + caps.Categories.AddCategoryMapping(1830, NewznabStandardCategory.XXX, "Сайтрипы с русскими актрисами 1991-2015 (HD Video) / Russian SiteRip's 1991-2015 (HD Video)"); + caps.Categories.AddCategoryMapping(1803, NewznabStandardCategory.XXX, "Сайтрипы с русскими актрисами 2016-2021 / Russian SiteRip's 2016-2021"); + caps.Categories.AddCategoryMapping(1831, NewznabStandardCategory.XXX, "Сайтрипы с русскими актрисами 2016-2021 (HD Video) / Russian SiteRip's 2016-2021 (HD Video)"); + caps.Categories.AddCategoryMapping(1741, NewznabStandardCategory.XXX, "Русские Порноролики Разное / Russian Clips (various)"); + caps.Categories.AddCategoryMapping(1676, NewznabStandardCategory.XXX, "Русское любительское видео / Russian Amateur Video"); + + caps.Categories.AddCategoryMapping(1780, NewznabStandardCategory.XXXPack, "Паки сайтрипов (HD Video) / SiteRip's Packs (HD Video)"); + caps.Categories.AddCategoryMapping(1110, NewznabStandardCategory.XXXPack, "Паки сайтрипов / SiteRip's Packs"); + caps.Categories.AddCategoryMapping(1678, NewznabStandardCategory.XXXPack, "Паки порнороликов по актрисам / Actresses Clips Packs"); + caps.Categories.AddCategoryMapping(1124, NewznabStandardCategory.XXX, "Сайтрипы 1991-2010 (HD Video) / SiteRip's 1991-2010 (HD Video)"); + caps.Categories.AddCategoryMapping(1784, NewznabStandardCategory.XXX, "Сайтрипы 2011-2012 (HD Video) / SiteRip's 2011-2012 (HD Video)"); + caps.Categories.AddCategoryMapping(1769, NewznabStandardCategory.XXX, "Сайтрипы 2013 (HD Video) / SiteRip's 2013 (HD Video)"); + caps.Categories.AddCategoryMapping(1793, NewznabStandardCategory.XXX, "Сайтрипы 2014 (HD Video) / SiteRip's 2014 (HD Video)"); + caps.Categories.AddCategoryMapping(1797, NewznabStandardCategory.XXX, "Сайтрипы 2015 (HD Video) / SiteRip's 2015 (HD Video)"); + caps.Categories.AddCategoryMapping(1804, NewznabStandardCategory.XXX, "Сайтрипы 2016 (HD Video) / SiteRip's 2016 (HD Video)"); + caps.Categories.AddCategoryMapping(1819, NewznabStandardCategory.XXX, "Сайтрипы 2017 (HD Video) / SiteRip's 2017 (HD Video)"); + caps.Categories.AddCategoryMapping(1825, NewznabStandardCategory.XXX, "Сайтрипы 2018 (HD Video) / SiteRip's 2018 (HD Video)"); + caps.Categories.AddCategoryMapping(1836, NewznabStandardCategory.XXX, "Сайтрипы 2019 (HD Video) / SiteRip's 2019 (HD Video)"); + caps.Categories.AddCategoryMapping(1842, NewznabStandardCategory.XXX, "Сайтрипы 2020 (HD Video) / SiteRip's 2020 (HD Video)"); + caps.Categories.AddCategoryMapping(1846, NewznabStandardCategory.XXX, "Сайтрипы 2021 (HD Video) / SiteRip's 2021 (HD Video)"); + + caps.Categories.AddCategoryMapping(1451, NewznabStandardCategory.XXX, "Сайтрипы 1991-2010 / SiteRip's 1991-2010"); + caps.Categories.AddCategoryMapping(1788, NewznabStandardCategory.XXX, "Сайтрипы 2011-2012 / SiteRip's 2011-2012"); + caps.Categories.AddCategoryMapping(1789, NewznabStandardCategory.XXX, "Сайтрипы 2013 / SiteRip's 2013"); + caps.Categories.AddCategoryMapping(1792, NewznabStandardCategory.XXX, "Сайтрипы 2014 / SiteRip's 2014"); + caps.Categories.AddCategoryMapping(1798, NewznabStandardCategory.XXX, "Сайтрипы 2015 / SiteRip's 2015"); + caps.Categories.AddCategoryMapping(1805, NewznabStandardCategory.XXX, "Сайтрипы 2016 / SiteRip's 2016"); + caps.Categories.AddCategoryMapping(1820, NewznabStandardCategory.XXX, "Сайтрипы 2017 / SiteRip's 2017"); + caps.Categories.AddCategoryMapping(1826, NewznabStandardCategory.XXX, "Сайтрипы 2018 / SiteRip's 2018"); + caps.Categories.AddCategoryMapping(1837, NewznabStandardCategory.XXX, "Сайтрипы 2019 / SiteRip's 2019"); + caps.Categories.AddCategoryMapping(1843, NewznabStandardCategory.XXX, "Сайтрипы 2020 / SiteRip's 2020"); + caps.Categories.AddCategoryMapping(1847, NewznabStandardCategory.XXX, "Сайтрипы 2021 / SiteRip's 2021"); + + caps.Categories.AddCategoryMapping(1707, NewznabStandardCategory.XXX, "Сцены из фильмов / Movie Scenes"); + caps.Categories.AddCategoryMapping(284, NewznabStandardCategory.XXX, "Порноролики Разное / Clips (various)"); + caps.Categories.AddCategoryMapping(1823, NewznabStandardCategory.XXX, "Порноролики в 3D и Virtual Reality (VR) / 3D & Virtual Reality Videos"); + + caps.Categories.AddCategoryMapping(1801, NewznabStandardCategory.XXXPack, "Паки японских фильмов и сайтрипов / Full Length Japanese Movies Packs & SiteRip's Packs"); + caps.Categories.AddCategoryMapping(1719, NewznabStandardCategory.XXX, "Японские фильмы и сайтрипы (DVD и HD Video) / Japanese Movies & SiteRip's (DVD & HD Video)"); + caps.Categories.AddCategoryMapping(997, NewznabStandardCategory.XXX, "Японские фильмы и сайтрипы 1991-2014 / Japanese Movies & SiteRip's 1991-2014"); + caps.Categories.AddCategoryMapping(1818, NewznabStandardCategory.XXX, "Японские фильмы и сайтрипы 2015-2019 / Japanese Movies & SiteRip's 2015-2019"); + + caps.Categories.AddCategoryMapping(1671, NewznabStandardCategory.XXX, "Эротические студии (видео) / Erotic Video Library"); + caps.Categories.AddCategoryMapping(1726, NewznabStandardCategory.XXX, "Met-Art & MetModels"); + caps.Categories.AddCategoryMapping(883, NewznabStandardCategory.XXXImageSet, "Эротические студии Разное / Erotic Picture Gallery (various)"); + caps.Categories.AddCategoryMapping(1759, NewznabStandardCategory.XXXImageSet, "Паки сайтрипов эротических студий / Erotic Picture SiteRip's Packs"); + caps.Categories.AddCategoryMapping(1728, NewznabStandardCategory.XXXImageSet, "Любительское фото / Amateur Picture Gallery"); + caps.Categories.AddCategoryMapping(1729, NewznabStandardCategory.XXXPack, "Подборки по актрисам / Actresses Picture Packs"); + caps.Categories.AddCategoryMapping(38, NewznabStandardCategory.XXXImageSet, "Подборки сайтрипов / SiteRip's Picture Packs"); + caps.Categories.AddCategoryMapping(1757, NewznabStandardCategory.XXXImageSet, "Подборки сетов / Picture Sets Packs"); + caps.Categories.AddCategoryMapping(1735, NewznabStandardCategory.XXXImageSet, "Тематическое и нетрадиционное фото / Misc & Special Interest Picture Packs"); + caps.Categories.AddCategoryMapping(1731, NewznabStandardCategory.XXXImageSet, "Журналы / Magazines"); + + caps.Categories.AddCategoryMapping(1679, NewznabStandardCategory.XXX, "Хентай: основной подраздел / Hentai: main subsection"); + caps.Categories.AddCategoryMapping(1740, NewznabStandardCategory.XXX, "Хентай в высоком качестве (DVD и HD) / Hentai DVD & HD"); + caps.Categories.AddCategoryMapping(1834, NewznabStandardCategory.XXX, "Хентай: ролики 2D / Hentai: 2D video"); + caps.Categories.AddCategoryMapping(1752, NewznabStandardCategory.XXX, "Хентай: ролики 3D / Hentai: 3D video"); + caps.Categories.AddCategoryMapping(1760, NewznabStandardCategory.XXX, "Хентай: Манга / Hentai: Manga"); + caps.Categories.AddCategoryMapping(1781, NewznabStandardCategory.XXX, "Хентай: Арт и HCG / Hentai: Artwork & HCG"); + caps.Categories.AddCategoryMapping(1711, NewznabStandardCategory.XXX, "Мультфильмы / Cartoons"); + caps.Categories.AddCategoryMapping(1296, NewznabStandardCategory.XXX, "Комиксы и рисунки / Comics & Artwork"); + + caps.Categories.AddCategoryMapping(1750, NewznabStandardCategory.XXX, "Игры: основной подраздел / Games: main subsection"); + caps.Categories.AddCategoryMapping(1756, NewznabStandardCategory.XXX, "Игры: визуальные новеллы / Games: Visual Novels"); + caps.Categories.AddCategoryMapping(1785, NewznabStandardCategory.XXX, "Игры: ролевые / Games: role-playing (RPG Maker and WOLF RPG Editor)"); + caps.Categories.AddCategoryMapping(1790, NewznabStandardCategory.XXX, "Игры и Софт: Анимация / Software: Animation"); + caps.Categories.AddCategoryMapping(1827, NewznabStandardCategory.XXX, "Игры: В разработке и Демо (основной подраздел) / Games: In Progress and Demo (main subsection)"); + caps.Categories.AddCategoryMapping(1828, NewznabStandardCategory.XXX, "Игры: В разработке и Демо (ролевые) / Games: In Progress and Demo (role-playing - RPG Maker and WOLF RPG Editor)"); + + caps.Categories.AddCategoryMapping(1715, NewznabStandardCategory.XXX, "Транссексуалы (DVD и HD) / Transsexual (DVD & HD)"); + caps.Categories.AddCategoryMapping(1680, NewznabStandardCategory.XXX, "Транссексуалы / Transsexual"); + + caps.Categories.AddCategoryMapping(1758, NewznabStandardCategory.XXX, "Бисексуалы / Bisexual"); + caps.Categories.AddCategoryMapping(1682, NewznabStandardCategory.XXX, "БДСМ / BDSM"); + caps.Categories.AddCategoryMapping(1733, NewznabStandardCategory.XXX, "Женское доминирование и страпон / Femdom & Strapon"); + caps.Categories.AddCategoryMapping(1754, NewznabStandardCategory.XXX, "Подглядывание / Voyeur"); + caps.Categories.AddCategoryMapping(1734, NewznabStandardCategory.XXX, "Фистинг и дилдо / Fisting & Dildo"); + caps.Categories.AddCategoryMapping(1791, NewznabStandardCategory.XXX, "Беременные / Pregnant"); + caps.Categories.AddCategoryMapping(509, NewznabStandardCategory.XXX, "Буккаке / Bukkake"); + caps.Categories.AddCategoryMapping(1685, NewznabStandardCategory.XXX, "Мочеиспускание / Peeing"); + caps.Categories.AddCategoryMapping(1762, NewznabStandardCategory.XXX, "Фетиш / Fetish"); + + caps.Categories.AddCategoryMapping(903, NewznabStandardCategory.XXX, "Полнометражные гей-фильмы / Full Length Movies (Gay)"); + caps.Categories.AddCategoryMapping(1765, NewznabStandardCategory.XXX, "Полнометражные азиатские гей-фильмы / Full-length Asian Films (Gay)"); + caps.Categories.AddCategoryMapping(1767, NewznabStandardCategory.XXX, "Классические гей-фильмы (до 1990 года) / Classic Gay Films (Pre-1990's)"); + caps.Categories.AddCategoryMapping(1755, NewznabStandardCategory.XXX, "Гей-фильмы в высоком качестве (DVD и HD) / High-Quality Full Length Movies (Gay DVD & HD)"); + caps.Categories.AddCategoryMapping(1787, NewznabStandardCategory.XXX, "Азиатские гей-фильмы в высоком качестве (DVD и HD) / High-Quality Full Length Asian Movies (Gay DVD & HD)"); + caps.Categories.AddCategoryMapping(1763, NewznabStandardCategory.XXXPack, "ПАКи гей-роликов и сайтрипов / Clip's & SiteRip's Packs (Gay)"); + caps.Categories.AddCategoryMapping(1777, NewznabStandardCategory.XXX, "Гей-ролики в высоком качестве (HD Video) / Gay Clips (HD Video)"); + caps.Categories.AddCategoryMapping(1691, NewznabStandardCategory.XXX, "РоликиSiteRip'ы и сцены из гей-фильмов / Clips & Movie Scenes (Gay)"); + caps.Categories.AddCategoryMapping(1692, NewznabStandardCategory.XXXImageSet, "Гей-журналыфото, разное / Magazines, Photo, Rest (Gay)"); + + caps.Categories.AddCategoryMapping(1817, NewznabStandardCategory.XXX, "Обход блокировки"); + caps.Categories.AddCategoryMapping(1670, NewznabStandardCategory.XXX, "Эротическое видео / Erotic&Softcore"); + caps.Categories.AddCategoryMapping(1672, NewznabStandardCategory.XXX, "Зарубежные порнофильмы / Full Length Movies"); + caps.Categories.AddCategoryMapping(1717, NewznabStandardCategory.XXX, "Зарубежные фильмы в высоком качестве (DVD&HD) / Full Length .."); + caps.Categories.AddCategoryMapping(1674, NewznabStandardCategory.XXX, "Русское порно / Russian Video"); + caps.Categories.AddCategoryMapping(1677, NewznabStandardCategory.XXX, "Зарубежные порноролики / Clips"); + caps.Categories.AddCategoryMapping(1800, NewznabStandardCategory.XXX, "Японское порно / Japanese Adult Video (JAV)"); + caps.Categories.AddCategoryMapping(1815, NewznabStandardCategory.XXX, "Архив (Японское порно)"); + caps.Categories.AddCategoryMapping(1723, NewznabStandardCategory.XXX, "Эротические студиифото и журналы / Erotic Picture Gallery .."); + caps.Categories.AddCategoryMapping(1802, NewznabStandardCategory.XXX, "Архив (Фото)"); + caps.Categories.AddCategoryMapping(1745, NewznabStandardCategory.XXX, "Хентай и МангаМультфильмы и Комиксы, Рисунки / Hentai&Ma.."); + caps.Categories.AddCategoryMapping(1838, NewznabStandardCategory.XXX, "Игры / Games"); + caps.Categories.AddCategoryMapping(1829, NewznabStandardCategory.XXX, "Обсуждение игр / Games Discussion"); + caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.XXX, "Нетрадиционное порно / Special Interest Movies&Clips"); + caps.Categories.AddCategoryMapping(1681, NewznabStandardCategory.XXX, "Дефекация / Scat"); + caps.Categories.AddCategoryMapping(1683, NewznabStandardCategory.XXX, "Архив (общий)"); + caps.Categories.AddCategoryMapping(1688, NewznabStandardCategory.XXX, "Гей-порно / Gay Forum"); + caps.Categories.AddCategoryMapping(1720, NewznabStandardCategory.XXX, "Архив (Гей-порно)"); + + return caps; + } + } + + public class PornoLabRequestGenerator : IIndexerRequestGenerator + { + public PornoLabSettings Settings { get; set; } + public IndexerCapabilities Capabilities { get; set; } + + public PornoLabRequestGenerator() + { + } + + private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories) + { + var searchUrl = string.Format("{0}/forum/tracker.php", Settings.BaseUrl.TrimEnd('/')); + + var searchString = term; + + // NameValueCollection don't support cat[]=19&cat[]=6 + var qc = new List<KeyValuePair<string, string>> + { + { "o", "1" }, + { "s", "2" } + }; + + // if the search string is empty use the getnew view + if (string.IsNullOrWhiteSpace(searchString)) + { + qc.Add("nm", searchString); + } + else + { + // use the normal search + searchString = searchString.Replace("-", " "); + qc.Add("nm", searchString); + } + + foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories)) + { + qc.Add("f[]", cat); + } + + searchUrl = searchUrl + "?" + qc.GetQueryString(); + + var request = new IndexerRequest(searchUrl, HttpAccept.Html); + + yield return request; + } + + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public Func<IDictionary<string, string>> GetCookies { get; set; } + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + } + + public class PornoLabParser : IParseIndexerResponse + { + private readonly PornoLabSettings _settings; + private readonly IndexerCapabilitiesCategories _categories; + private readonly Logger _logger; + private static readonly Regex StripRussianRegex = new Regex(@"(\([А-Яа-яЁё\W]+\))|(^[А-Яа-яЁё\W\d]+\/ )|([а-яА-ЯЁё \-]+,+)|([а-яА-ЯЁё]+)"); + + public PornoLabParser(PornoLabSettings settings, IndexerCapabilitiesCategories categories, Logger logger) + { + _settings = settings; + _categories = categories; + _logger = logger; + } + + public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) + { + var torrentInfos = new List<ReleaseInfo>(); + + var rowsSelector = "table#tor-tbl > tbody > tr"; + + var searchResultParser = new HtmlParser(); + var searchResultDocument = searchResultParser.ParseDocument(indexerResponse.Content); + var rows = searchResultDocument.QuerySelectorAll(rowsSelector); + foreach (var row in rows) + { + try + { + var qDownloadLink = row.QuerySelector("a.tr-dl"); + + // Expects moderation + if (qDownloadLink == null) + { + continue; + } + + var qForumLink = row.QuerySelector("a.f"); + var qDetailsLink = row.QuerySelector("a.tLink"); + var qSize = row.QuerySelector("td:nth-child(6) u"); + var link = new Uri(_settings.BaseUrl + "forum/" + qDetailsLink.GetAttribute("href")); + var seederString = row.QuerySelector("td:nth-child(7) b").TextContent; + var seeders = string.IsNullOrWhiteSpace(seederString) ? 0 : ParseUtil.CoerceInt(seederString); + + var timestr = row.QuerySelector("td:nth-child(11) u").TextContent; + var forum = qForumLink; + var forumid = forum.GetAttribute("href").Split('=')[1]; + var title = _settings.StripRussianLetters + ? StripRussianRegex.Replace(qDetailsLink.TextContent, "") + : qDetailsLink.TextContent; + var size = ParseUtil.GetBytes(qSize.TextContent); + var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(8)").TextContent); + var grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(9)").TextContent); + var publishDate = DateTimeUtil.UnixTimestampToDateTime(long.Parse(timestr)); + var release = new TorrentInfo + { + MinimumRatio = 1, + MinimumSeedTime = 0, + Title = title, + InfoUrl = link.AbsoluteUri, + Description = qForumLink.TextContent, + DownloadUrl = link.AbsoluteUri, + Guid = link.AbsoluteUri, + Size = size, + Seeders = seeders, + Peers = leechers + seeders, + Grabs = grabs, + PublishDate = publishDate, + Categories = _categories.MapTrackerCatToNewznab(forumid), + DownloadVolumeFactor = 1, + UploadVolumeFactor = 1 + }; + + torrentInfos.Add(release); + } + catch (Exception ex) + { + _logger.Error(string.Format("Pornolab: Error while parsing row '{0}':\n\n{1}", row.OuterHtml, ex)); + } + } + + return torrentInfos.ToArray(); + } + + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + } + + public class PornoLabSettingsValidator : AbstractValidator<PornoLabSettings> + { + public PornoLabSettingsValidator() + { + RuleFor(c => c.Username).NotEmpty(); + RuleFor(c => c.Password).NotEmpty(); + } + } + + public class PornoLabSettings : IIndexerSettings + { + private static readonly PornoLabSettingsValidator Validator = new PornoLabSettingsValidator(); + + public PornoLabSettings() + { + Username = ""; + Password = ""; + } + + [FieldDefinition(1, Label = "Base Url", HelpText = "Select which baseurl Prowlarr will use for requests to the site", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls")] + public string BaseUrl { get; set; } + + [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] + public string Username { get; set; } + + [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] + public string Password { get; set; } + + [FieldDefinition(4, Label = "Strip Russian Letters", HelpLink = "Strip Cyrillic letters from release names", Type = FieldType.Checkbox)] + public bool StripRussianLetters { get; set; } + + [FieldDefinition(5)] + public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} From 1ffab661da7155d36d162a73b407d1082549ace1 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 30 Nov 2021 11:20:15 -0600 Subject: [PATCH 0208/2320] Don't fallback to different OS Yarn cache --- azure-pipelines.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 90cdd164e..8453d7ec8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -163,7 +163,6 @@ stages: key: 'yarn | "$(osName)" | yarn.lock' restoreKeys: | yarn | "$(osName)" - yarn path: $(yarnCacheFolder) displayName: Cache Yarn packages - bash: ./build.sh --frontend @@ -816,7 +815,6 @@ stages: key: 'yarn | "$(osName)" | yarn.lock' restoreKeys: | yarn | "$(osName)" - yarn path: $(yarnCacheFolder) displayName: Cache Yarn packages - bash: ./build.sh --lint From b5a2f68bde7bec066b05204028c08526cde7fff3 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 30 Nov 2021 21:47:44 -0600 Subject: [PATCH 0209/2320] Fixed: (Newznab) Parse Imdb, Tmdb, RageId, Tvdbid from indexer Fixes #656 --- .../IndexerSearch/NewznabResults.cs | 2 +- .../Definitions/Newznab/NewznabRssParser.cs | 46 +++++-------------- 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs index c979bff96..568183fb5 100644 --- a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs +++ b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs @@ -90,7 +90,7 @@ namespace NzbDrone.Core.IndexerSearch r.Categories == null ? null : from c in r.Categories select GetNabElement("category", c.Id, protocol), r.IndexerFlags == null ? null : from f in r.IndexerFlags select GetNabElement("tag", f.Name, protocol), GetNabElement("rageid", r.TvRageId, protocol), - GetNabElement("thetvdb", r.TvdbId, protocol), + GetNabElement("tvdbid", r.TvdbId, protocol), GetNabElement("imdb", r.ImdbId.ToString("D7"), protocol), GetNabElement("tmdb", r.TmdbId, protocol), GetNabElement("seeders", t.Seeders, protocol), diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs index 54c192eb4..b3792a47b 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Xml; using System.Xml.Linq; using NzbDrone.Common.Extensions; using NzbDrone.Core.Indexers.Exceptions; @@ -96,9 +95,12 @@ namespace NzbDrone.Core.Indexers.Newznab } releaseInfo = base.ProcessItem(item, releaseInfo); - releaseInfo.ImdbId = GetImdbId(item); - releaseInfo.Grabs = GetGrabs(item); - releaseInfo.Files = GetFiles(item); + releaseInfo.ImdbId = GetIntAttribute(item, "imdb"); + releaseInfo.TmdbId = GetIntAttribute(item, "tmdb"); + releaseInfo.TvdbId = GetIntAttribute(item, "tvdbid"); + releaseInfo.TvRageId = GetIntAttribute(item, "rageid"); + releaseInfo.Grabs = GetIntAttribute(item, "grabs"); + releaseInfo.Files = GetIntAttribute(item, "files"); releaseInfo.PosterUrl = GetPosterUrl(item); return releaseInfo; @@ -195,27 +197,14 @@ namespace NzbDrone.Core.Indexers.Newznab return url; } - protected virtual int GetImdbId(XElement item) + protected virtual int GetIntAttribute(XElement item, string attribute) { - var imdbIdString = TryGetNewznabAttribute(item, "imdb"); - int imdbId; + var idString = TryGetNewznabAttribute(item, attribute); + int idInt; - if (!imdbIdString.IsNullOrWhiteSpace() && int.TryParse(imdbIdString, out imdbId)) + if (!idString.IsNullOrWhiteSpace() && int.TryParse(idString, out idInt)) { - return imdbId; - } - - return 0; - } - - protected virtual int GetGrabs(XElement item) - { - var grabsString = TryGetNewznabAttribute(item, "grabs"); - int grabs; - - if (!grabsString.IsNullOrWhiteSpace() && int.TryParse(grabsString, out grabs)) - { - return grabs; + return idInt; } return 0; @@ -226,19 +215,6 @@ namespace NzbDrone.Core.Indexers.Newznab return ParseUrl(TryGetNewznabAttribute(item, "coverurl")); } - protected virtual int GetFiles(XElement item) - { - var filesString = TryGetNewznabAttribute(item, "files"); - int files; - - if (!filesString.IsNullOrWhiteSpace() && int.TryParse(filesString, out files)) - { - return files; - } - - return 0; - } - protected virtual int GetImdbYear(XElement item) { var imdbYearString = TryGetNewznabAttribute(item, "imdbyear"); From 89510c4a659e32d7a24764b18bb6686e4e273c21 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 1 Dec 2021 20:39:26 -0600 Subject: [PATCH 0210/2320] Fixed: Workaround net6 object serialization issues Co-Authored-By: ta264 <ta264@users.noreply.github.com> --- .../src/Store/Actions/Creators/createRemoveItemHandler.js | 1 - src/Prowlarr.Api.V1/Indexers/IndexerEditorController.cs | 2 +- src/Prowlarr.Api.V1/ProviderControllerBase.cs | 4 +++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/src/Store/Actions/Creators/createRemoveItemHandler.js b/frontend/src/Store/Actions/Creators/createRemoveItemHandler.js index 286469d57..dfe29ace8 100644 --- a/frontend/src/Store/Actions/Creators/createRemoveItemHandler.js +++ b/frontend/src/Store/Actions/Creators/createRemoveItemHandler.js @@ -14,7 +14,6 @@ function createRemoveItemHandler(section, url) { const ajaxOptions = { url: `${url}/${id}?${$.param(queryParams, true)}`, - dataType: 'text', method: 'DELETE' }; diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerEditorController.cs b/src/Prowlarr.Api.V1/Indexers/IndexerEditorController.cs index cdf6c2061..bde7f5282 100644 --- a/src/Prowlarr.Api.V1/Indexers/IndexerEditorController.cs +++ b/src/Prowlarr.Api.V1/Indexers/IndexerEditorController.cs @@ -76,7 +76,7 @@ namespace Prowlarr.Api.V1.Indexers { _indexerService.DeleteIndexers(resource.IndexerIds); - return new object(); + return new { }; } } } diff --git a/src/Prowlarr.Api.V1/ProviderControllerBase.cs b/src/Prowlarr.Api.V1/ProviderControllerBase.cs index 4784421db..993357745 100644 --- a/src/Prowlarr.Api.V1/ProviderControllerBase.cs +++ b/src/Prowlarr.Api.V1/ProviderControllerBase.cs @@ -102,9 +102,11 @@ namespace Prowlarr.Api.V1 } [RestDeleteById] - public void DeleteProvider(int id) + public object DeleteProvider(int id) { _providerFactory.Delete(id); + + return new { }; } [HttpGet("schema")] From a2df38b1ca253a74b432de2b48da7a221dd598e9 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 1 Dec 2021 21:46:33 -0600 Subject: [PATCH 0211/2320] Fixed: Windows installer and adding/removing services Co-Authored-By: ta264 <ta264@users.noreply.github.com> --- src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs | 2 +- src/NzbDrone.Host/UtilityModeRouter.cs | 3 --- src/Prowlarr.sln | 4 ++-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs index 8ae7ad630..42cb5d1be 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Common.EnvironmentInfo private readonly Logger _logger; private readonly DateTime _startTime = DateTime.UtcNow; - public RuntimeInfo(IHostLifetime hostLifetime, Logger logger) + public RuntimeInfo(Logger logger, IHostLifetime hostLifetime = null) { _logger = logger; diff --git a/src/NzbDrone.Host/UtilityModeRouter.cs b/src/NzbDrone.Host/UtilityModeRouter.cs index 744dc6a5d..66fad6f8b 100644 --- a/src/NzbDrone.Host/UtilityModeRouter.cs +++ b/src/NzbDrone.Host/UtilityModeRouter.cs @@ -16,21 +16,18 @@ namespace NzbDrone.Host { private readonly IServiceProvider _serviceProvider; private readonly IConsoleService _consoleService; - private readonly IRuntimeInfo _runtimeInfo; private readonly IProcessProvider _processProvider; private readonly IRemoteAccessAdapter _remoteAccessAdapter; private readonly Logger _logger; public UtilityModeRouter(IServiceProvider serviceProvider, IConsoleService consoleService, - IRuntimeInfo runtimeInfo, IProcessProvider processProvider, IRemoteAccessAdapter remoteAccessAdapter, Logger logger) { _serviceProvider = serviceProvider; _consoleService = consoleService; - _runtimeInfo = runtimeInfo; _processProvider = processProvider; _remoteAccessAdapter = remoteAccessAdapter; _logger = logger; diff --git a/src/Prowlarr.sln b/src/Prowlarr.sln index 753dff571..dc8fce3a3 100644 --- a/src/Prowlarr.sln +++ b/src/Prowlarr.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29418.71 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31912.275 MinimumVisualStudioVersion = 15.0.26124.0 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{57A04B72-8088-4F75-A582-1158CF8291F7}" EndProject From c83c8183808b225eda8f1292eafa40643bcc99a0 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 1 Dec 2021 21:50:28 -0600 Subject: [PATCH 0212/2320] Fixed: (Flaresolverr) Ignore http errors on initial request when using FS --- src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index 9b8b2140a..8751519b9 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -26,7 +26,9 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr public override HttpRequest PreRequest(HttpRequest request) { - //Try original request first, detect CF in post response + //Try original request first, ignore errors, detect CF in post response + request.SuppressHttpError = true; + return request; } From 574568e71d38dd98507abd7bf92ff3b5f3a7a57b Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 4 Dec 2021 12:09:23 -0600 Subject: [PATCH 0213/2320] Optimize HandleJsonSelector() to avoid needless throws --- .../Indexers/Definitions/Cardigann/CardigannBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index 9ea8a57d9..1b46b05e7 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -271,7 +271,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } } - return ApplyFilters(value.Trim(), selector.Filters, variables); + return ApplyFilters(value?.Trim(), selector.Filters, variables) ?? null; } protected Dictionary<string, object> GetBaseTemplateVariables() From 08c68e26c15b65ba834583893da474cabc58ed1d Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 4 Dec 2021 12:10:19 -0600 Subject: [PATCH 0214/2320] Fixed: Correctly return infohash in torznab response when available --- src/NzbDrone.Core/IndexerSearch/NewznabResults.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs index 568183fb5..8e97c2806 100644 --- a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs +++ b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs @@ -97,7 +97,7 @@ namespace NzbDrone.Core.IndexerSearch GetNabElement("files", r.Files, protocol), GetNabElement("grabs", r.Grabs, protocol), GetNabElement("peers", t.Peers, protocol), - GetNabElement("infohash", RemoveInvalidXMLChars(r.Guid), protocol), + GetNabElement("infohash", RemoveInvalidXMLChars(t.InfoHash), protocol), GetNabElement("minimumratio", t.MinimumRatio, protocol), GetNabElement("minimumseedtime", t.MinimumSeedTime, protocol), GetNabElement("downloadvolumefactor", t.DownloadVolumeFactor, protocol), From 6d62744667c9242807e30666e4ba729355f08b6c Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 4 Dec 2021 12:26:55 -0600 Subject: [PATCH 0215/2320] Fixed: (Cardigann) Magnet generation for public indexers with InfoHash Fixes #668 --- src/NzbDrone.Core/Indexers/IndexerBase.cs | 21 ++++++++++++++++--- .../Indexers/MagnetLinkBuilder.cs | 16 ++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/IndexerBase.cs b/src/NzbDrone.Core/Indexers/IndexerBase.cs index 75717c1b5..cd123f4ad 100644 --- a/src/NzbDrone.Core/Indexers/IndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/IndexerBase.cs @@ -132,10 +132,25 @@ namespace NzbDrone.Core.Indexers c.DownloadProtocol = Protocol; c.IndexerPriority = ((IndexerDefinition)Definition).Priority; - //Add common flags - if (Protocol == DownloadProtocol.Torrent && ((TorrentInfo)c).DownloadVolumeFactor == 0) + if (Protocol == DownloadProtocol.Torrent) { - c.IndexerFlags.Add(IndexerFlag.FreeLeech); + // generate magnet link from info hash (not allowed for private sites) + if (((TorrentInfo)c).MagnetUrl == null && !string.IsNullOrWhiteSpace(((TorrentInfo)c).InfoHash) && ((IndexerDefinition)Definition).Privacy != IndexerPrivacy.Private) + { + ((TorrentInfo)c).MagnetUrl = MagnetLinkBuilder.BuildPublicMagnetLink(((TorrentInfo)c).InfoHash, c.Title); + } + + // generate info hash from magnet link + if (((TorrentInfo)c).MagnetUrl != null && string.IsNullOrWhiteSpace(((TorrentInfo)c).InfoHash)) + { + ((TorrentInfo)c).InfoHash = MagnetLinkBuilder.GetInfoHashFromMagnet(((TorrentInfo)c).MagnetUrl); + } + + //Add common flags + if (((TorrentInfo)c).DownloadVolumeFactor == 0) + { + ((TorrentInfo)c).IndexerFlags.Add(IndexerFlag.FreeLeech); + } } }); diff --git a/src/NzbDrone.Core/Indexers/MagnetLinkBuilder.cs b/src/NzbDrone.Core/Indexers/MagnetLinkBuilder.cs index 5732c3dcf..a41d64b98 100644 --- a/src/NzbDrone.Core/Indexers/MagnetLinkBuilder.cs +++ b/src/NzbDrone.Core/Indexers/MagnetLinkBuilder.cs @@ -1,5 +1,8 @@ +using System; using System.Collections.Generic; +using System.Linq; using MonoTorrent; +using NzbDrone.Core.Parser; namespace NzbDrone.Core.Indexers { @@ -33,5 +36,18 @@ namespace NzbDrone.Core.Indexers { return new MagnetLink(InfoHash.FromHex(infoHash), releaseTitle, _trackers).ToV1String(); } + + public static string GetInfoHashFromMagnet(string magnet) + { + try + { + var xt = ParseUtil.GetArgumentFromQueryString(magnet.ToString(), "xt"); + return xt.Split(':').Last(); // remove prefix urn:btih: + } + catch (Exception) + { + return null; + } + } } } From ea8302071458ce1556e8b37bcac010fca32ca1bc Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 4 Dec 2021 17:17:47 -0600 Subject: [PATCH 0216/2320] Build Magnet on Cardigann separate --- .../Definitions/Cardigann/CardigannParser.cs | 15 +++++++++++++++ src/NzbDrone.Core/Indexers/IndexerBase.cs | 12 ------------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index 55ac4f3bd..a48cd760d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -358,6 +358,21 @@ namespace NzbDrone.Core.Indexers.Cardigann releases = releases.Take(query.Limit).ToList(); }*/ + releases.ForEach(c => + { + // generate magnet link from info hash (not allowed for private sites) + if (((TorrentInfo)c).MagnetUrl == null && !string.IsNullOrWhiteSpace(((TorrentInfo)c).InfoHash) && _definition.Type != "private") + { + ((TorrentInfo)c).MagnetUrl = MagnetLinkBuilder.BuildPublicMagnetLink(((TorrentInfo)c).InfoHash, c.Title); + } + + // generate info hash from magnet link + if (((TorrentInfo)c).MagnetUrl != null && string.IsNullOrWhiteSpace(((TorrentInfo)c).InfoHash)) + { + ((TorrentInfo)c).InfoHash = MagnetLinkBuilder.GetInfoHashFromMagnet(((TorrentInfo)c).MagnetUrl); + } + }); + _logger.Debug($"Got {releases.Count} releases"); return releases; diff --git a/src/NzbDrone.Core/Indexers/IndexerBase.cs b/src/NzbDrone.Core/Indexers/IndexerBase.cs index cd123f4ad..9f29f8bdd 100644 --- a/src/NzbDrone.Core/Indexers/IndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/IndexerBase.cs @@ -134,18 +134,6 @@ namespace NzbDrone.Core.Indexers if (Protocol == DownloadProtocol.Torrent) { - // generate magnet link from info hash (not allowed for private sites) - if (((TorrentInfo)c).MagnetUrl == null && !string.IsNullOrWhiteSpace(((TorrentInfo)c).InfoHash) && ((IndexerDefinition)Definition).Privacy != IndexerPrivacy.Private) - { - ((TorrentInfo)c).MagnetUrl = MagnetLinkBuilder.BuildPublicMagnetLink(((TorrentInfo)c).InfoHash, c.Title); - } - - // generate info hash from magnet link - if (((TorrentInfo)c).MagnetUrl != null && string.IsNullOrWhiteSpace(((TorrentInfo)c).InfoHash)) - { - ((TorrentInfo)c).InfoHash = MagnetLinkBuilder.GetInfoHashFromMagnet(((TorrentInfo)c).MagnetUrl); - } - //Add common flags if (((TorrentInfo)c).DownloadVolumeFactor == 0) { From 89e500edfdc490355b85499b88e0d70df349650d Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 4 Dec 2021 17:18:20 -0600 Subject: [PATCH 0217/2320] Fixed: (Stats) All filter not returning all --- src/Prowlarr.Api.V1/Indexers/IndexerStatsController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerStatsController.cs b/src/Prowlarr.Api.V1/Indexers/IndexerStatsController.cs index e3a13d066..cf1249b9b 100644 --- a/src/Prowlarr.Api.V1/Indexers/IndexerStatsController.cs +++ b/src/Prowlarr.Api.V1/Indexers/IndexerStatsController.cs @@ -18,7 +18,7 @@ namespace Prowlarr.Api.V1.Indexers [HttpGet] public IndexerStatsResource GetAll(DateTime? startDate, DateTime? endDate) { - var statsStartDate = startDate ?? DateTime.Now.AddDays(-30); + var statsStartDate = startDate ?? DateTime.MinValue; var statsEndDate = endDate ?? DateTime.Now; var indexerResource = new IndexerStatsResource From dcee9582bdaf4dfa10f9a0c4e9666284610df24a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 4 Dec 2021 17:24:20 -0600 Subject: [PATCH 0218/2320] Speedup Stats endpoint call X3 --- src/Prowlarr.Api.V1/Indexers/IndexerStatsController.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerStatsController.cs b/src/Prowlarr.Api.V1/Indexers/IndexerStatsController.cs index cf1249b9b..7bd3c47b7 100644 --- a/src/Prowlarr.Api.V1/Indexers/IndexerStatsController.cs +++ b/src/Prowlarr.Api.V1/Indexers/IndexerStatsController.cs @@ -21,11 +21,13 @@ namespace Prowlarr.Api.V1.Indexers var statsStartDate = startDate ?? DateTime.MinValue; var statsEndDate = endDate ?? DateTime.Now; + var indexerStats = _indexerStatisticsService.IndexerStatistics(statsStartDate, statsEndDate); + var indexerResource = new IndexerStatsResource { - Indexers = _indexerStatisticsService.IndexerStatistics(statsStartDate, statsEndDate).IndexerStatistics, - UserAgents = _indexerStatisticsService.IndexerStatistics(statsStartDate, statsEndDate).UserAgentStatistics, - Hosts = _indexerStatisticsService.IndexerStatistics(statsStartDate, statsEndDate).HostStatistics + Indexers = indexerStats.IndexerStatistics, + UserAgents = indexerStats.UserAgentStatistics, + Hosts = indexerStats.HostStatistics }; return indexerResource; From bd834fb4d715d47298de1ec06d0174ac5f95a97f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 4 Dec 2021 18:03:33 -0600 Subject: [PATCH 0219/2320] Fixed: Stats fails to load due to unparsable elapsedTime for history event Fixes #663 --- src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs b/src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs index 7bd8cd075..02bbbb143 100644 --- a/src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs +++ b/src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs @@ -54,8 +54,11 @@ namespace NzbDrone.Core.IndexerStats var sortedEvents = indexer.OrderBy(v => v.Date) .ThenBy(v => v.Id) .ToArray(); + int temp = 0; - indexerStats.AverageResponseTime = (int)sortedEvents.Where(h => h.Data.ContainsKey("elapsedTime")).Select(h => int.Parse(h.Data.GetValueOrDefault("elapsedTime"))).Average(); + indexerStats.AverageResponseTime = (int)sortedEvents.Where(h => int.TryParse(h.Data.GetValueOrDefault("elapsedTime"), out temp)) + .Select(h => temp) + .Average(); foreach (var historyEvent in sortedEvents) { From fab1304bcd0b758adc8e32cb0aa02230c1415422 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 4 Dec 2021 18:50:33 -0600 Subject: [PATCH 0220/2320] Skip DB backup on Postgres DB --- src/NzbDrone.Core/Backup/BackupService.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Backup/BackupService.cs b/src/NzbDrone.Core/Backup/BackupService.cs index 300461f80..a25f67e21 100644 --- a/src/NzbDrone.Core/Backup/BackupService.cs +++ b/src/NzbDrone.Core/Backup/BackupService.cs @@ -187,9 +187,12 @@ namespace NzbDrone.Core.Backup private void BackupDatabase() { - _logger.ProgressDebug("Backing up database"); + if (_maindDb.DatabaseType == DatabaseType.SQLite) + { + _logger.ProgressDebug("Backing up database"); - _makeDatabaseBackup.BackupDatabase(_maindDb, _backupTempFolder); + _makeDatabaseBackup.BackupDatabase(_maindDb, _backupTempFolder); + } } private void BackupConfigFile() From c64addb976d4ecfc41c43911eba59a6cdd8da533 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 29 Nov 2021 21:20:13 -0600 Subject: [PATCH 0221/2320] Fixed: (UNIT3D Indexers) Cleanse RID in Logs Fixes #652 --- .../InstrumentationTests/CleanseLogMessageFixture.cs | 10 +++++++--- .../Instrumentation/CleanseLogMessage.cs | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs index 49da6364c..013ead2c2 100644 --- a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs +++ b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs @@ -26,17 +26,21 @@ namespace NzbDrone.Common.Test.InstrumentationTests //Indexer Responses - // avistaz response + // avistaz response [TestCase(@"""download"":""https:\/\/avistaz.to\/rss\/download\/2b51db35e1910123321025a12b9933d2\/tb51db35e1910123321025a12b9933d2.torrent"",")] [TestCase(@",""info_hash"":""2b51db35e1910123321025a12b9933d2"",")] - // danish bytes response + // danish bytes response [TestCase(@",""rsskey"":""2b51db35e1910123321025a12b9933d2"",")] [TestCase(@",""passkey"":""2b51db35e1910123321025a12b9933d2"",")] - // nzbgeek & usenet response + // nzbgeek & usenet response [TestCase(@"<guid isPermaLink=""true"">https://api.nzbgeek.info/api?t=details&id=2b51db35e1910123321025a12b9933d2&apikey=2b51db35e1910123321025a12b9933d2</guid>")] + // UNIT3D Response + [TestCase(@"""download_link"":""https://blutopia.xyz/torrent/download/114592.2b51db35e1910123321025a12b9933d2"",")] + [TestCase(@"""download_link"":""https://desitorrents.tv/torrent/download/114592.2b51db35e1910123321025a12b9933d2"",")] + // NzbGet [TestCase(@"{ ""Name"" : ""ControlUsername"", ""Value"" : ""mySecret"" }, { ""Name"" : ""ControlPassword"", ""Value"" : ""mySecret"" }, ")] [TestCase(@"{ ""Name"" : ""Server1.Username"", ""Value"" : ""mySecret"" }, { ""Name"" : ""Server1.Password"", ""Value"" : ""mySecret"" }, ")] diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index f82cbadc2..a3f81b6b4 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -21,6 +21,9 @@ namespace NzbDrone.Common.Instrumentation new Regex(@"(?<=authkey = "")(?<secret>[^&=]+?)(?="")", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"(?<=beyond-hd\.[a-z]+/api/torrents/)(?<secret>[^&=][a-z0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + // UNIT3D + new Regex(@"(?<=[a-z0-9-]+\.[a-z]+/torrent/download/\d+\.)(?<secret>[^&=][a-z0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + // Path new Regex(@"""C:\\Users\\(?<secret>[^\""]+?)(\\|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"""/home/(?<secret>[^/""]+?)(/|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), From 8855b2846dd2c4198f551bd02ee554385e68d6c9 Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Sun, 5 Dec 2021 13:15:45 +0000 Subject: [PATCH 0222/2320] Fixed: Updated wording of Application Server URLs --- src/NzbDrone.Core/Applications/Lidarr/LidarrSettings.cs | 2 +- src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs | 2 +- src/NzbDrone.Core/Applications/Radarr/RadarrSettings.cs | 2 +- src/NzbDrone.Core/Applications/Readarr/ReadarrSettings.cs | 2 +- src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Core/Applications/Lidarr/LidarrSettings.cs b/src/NzbDrone.Core/Applications/Lidarr/LidarrSettings.cs index d1b341529..fe9ab208e 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/LidarrSettings.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/LidarrSettings.cs @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Applications.Lidarr [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Lidarr sees it, including http(s)://, port, and urlbase if needed")] public string ProwlarrUrl { get; set; } - [FieldDefinition(1, Label = "Lidarr Server", HelpText = "Lidarr server URL, including http(s):// and port if needed")] + [FieldDefinition(1, Label = "Lidarr Server", HelpText = "URL used to connect to Lidarr server, including http(s)://, port, and urlbase if required")] public string BaseUrl { get; set; } [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Lidarr in Settings/General")] diff --git a/src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs b/src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs index 1b2c38c36..50869c77f 100644 --- a/src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs +++ b/src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Applications.Mylar [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Mylar sees it, including http(s)://, port, and urlbase if needed")] public string ProwlarrUrl { get; set; } - [FieldDefinition(1, Label = "Mylar Server", HelpText = "Mylar server URL, including http(s):// and port if needed")] + [FieldDefinition(1, Label = "Mylar Server", HelpText = "URL used to connect to Mylar server, including http(s)://, port, and urlbase if required")] public string BaseUrl { get; set; } [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Mylar in Settings/Web Interface")] diff --git a/src/NzbDrone.Core/Applications/Radarr/RadarrSettings.cs b/src/NzbDrone.Core/Applications/Radarr/RadarrSettings.cs index 08e9f6a69..4bfa4709c 100644 --- a/src/NzbDrone.Core/Applications/Radarr/RadarrSettings.cs +++ b/src/NzbDrone.Core/Applications/Radarr/RadarrSettings.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Applications.Radarr [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Radarr sees it, including http(s)://, port, and urlbase if needed")] public string ProwlarrUrl { get; set; } - [FieldDefinition(1, Label = "Radarr Server", HelpText = "Radarr server URL, including http(s):// and port if needed")] + [FieldDefinition(1, Label = "Radarr Server", HelpText = "URL used to connect to Radarr server, including http(s)://, port, and urlbase if required")] public string BaseUrl { get; set; } [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Radarr in Settings/General")] diff --git a/src/NzbDrone.Core/Applications/Readarr/ReadarrSettings.cs b/src/NzbDrone.Core/Applications/Readarr/ReadarrSettings.cs index 7c97fa0d6..0554e78cb 100644 --- a/src/NzbDrone.Core/Applications/Readarr/ReadarrSettings.cs +++ b/src/NzbDrone.Core/Applications/Readarr/ReadarrSettings.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Applications.Readarr [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Readarr sees it, including http(s)://, port, and urlbase if needed")] public string ProwlarrUrl { get; set; } - [FieldDefinition(1, Label = "Readarr Server", HelpText = "Readarr server URL, including http(s):// and port if needed")] + [FieldDefinition(1, Label = "Readarr Server", HelpText = "URL used to connect to Readarr server, including http(s)://, port, and urlbase if required")] public string BaseUrl { get; set; } [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Readarr in Settings/General")] diff --git a/src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs b/src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs index 26c2b90df..9d15b1a5c 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Applications.Sonarr [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Sonarr sees it, including http(s)://, port, and urlbase if needed")] public string ProwlarrUrl { get; set; } - [FieldDefinition(1, Label = "Sonarr Server", HelpText = "Sonarr server URL, including http(s):// and port if needed")] + [FieldDefinition(1, Label = "Sonarr Server", HelpText = "URL used to connect to Sonarr server, including http(s)://, port, and urlbase if required")] public string BaseUrl { get; set; } [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Sonarr in Settings/General")] From 849b3de7d32c7ebd23ae82d82a97dc8e5460aeb5 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 27 Nov 2021 12:05:51 -0600 Subject: [PATCH 0223/2320] readme updates [skip ci] --- README.md | 64 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index e0e539918..7e1dd130d 100644 --- a/README.md +++ b/README.md @@ -4,74 +4,84 @@ [![Translated](https://translate.servarr.com/widgets/servarr/-/prowlarr/svg-badge.svg)](https://translate.servarr.com/engage/prowlarr/?utm_source=widget) [![Docker Pulls](https://img.shields.io/docker/pulls/hotio/prowlarr.svg)](https://wiki.servarr.com/prowlarr/installation#docker) ![Github Downloads](https://img.shields.io/github/downloads/Prowlarr/Prowlarr/total.svg) -[![Backers on Open Collective](https://opencollective.com/Prowlarr/backers/badge.svg)](#backers) +[![Backers on Open Collective](https://opencollective.com/Prowlarr/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Prowlarr/sponsors/badge.svg)](#sponsors) +[![Mega Sponsors on Open Collective](https://opencollective.com/Prowlarr/megasponsors/badge.svg)](#mega-sponsors) -Prowlarr is an indexer manager/proxy built on the popular arr .net/reactjs base stack to integrate with your various PVR apps. Prowlarr supports management of both Torrent Trackers and Usenet Indexers. It integrates seamlessly with Lidarr, Mylar3, Radarr, Readarr, and Sonarr offering complete management of your indexers with no per app Indexer setup required (we do it all). +Prowlarr is an indexer manager/proxy built on the popular \*arr .net/reactjs base stack to integrate with your various PVR apps. Prowlarr supports management of both Torrent Trackers and Usenet Indexers. It integrates seamlessly with Lidarr, Mylar3, Radarr, Readarr, and Sonarr offering complete management of your indexers with no per app Indexer setup required (we do it all). -## Major Features Include: -- Usenet support for 24 indexers natively, including Headphones VIP, and support for any Newznab compatible indexer via "Generic Newznab" +## Major Features Include + +- Usenet support for 24 indexers natively, including Headphones VIP +- Usenet support for any Newznab compatible indexer via "Generic Newznab" - Torrent support for over 500 trackers with more added all the time - Torrent support for any Torznab compatible tracker via "Generic Torznab" -- Indexer Sync to Sonarr/Radarr/Readarr/Lidarr/Mylar3, so no manual configuration of the other applications are required +- Support for custom YML definitions via Cardigann that includes JSON and XML parsing +- Indexer Sync to Lidarr/Mylar3/Radarr/Readarr/Sonarr, so no manual configuration of the other applications are required - Indexer history and statistics - Manual searching of Trackers & Indexers at a category level -- Support for pushing releases directly to your download clients from Prowlarr +- Parameter based manual searching +- Support for pushing multiple releases at once directly to your download clients from Prowlarr - Indexer health and status notifications - Per Indexer proxy support (SOCKS4, SOCKS5, HTTP, Flaresolverr) ## Support + Note: Prowlarr is currently early in life, thus bugs should be expected +[![Wiki](https://img.shields.io/badge/servarr-wiki-181717.svg?maxAge=60)](https://wiki.servarr.com/prowlarr) + [![Discord](https://img.shields.io/badge/discord-chat-7289DA.svg?maxAge=60)](https://prowlarr.com/discord) [![Reddit](https://img.shields.io/badge/reddit-discussion-FF4500.svg?maxAge=60)](https://www.reddit.com/r/Prowlarr) + +Note: GitHub Issues are for Bugs and Feature Requests Only + [![GitHub - Bugs and Feature Requests Only](https://img.shields.io/badge/github-issues-red.svg?maxAge=60)](https://github.com/Prowlarr/Prowlarr/issues) -[![Wiki](https://img.shields.io/badge/servarr-wiki-181717.svg?maxAge=60)](https://wiki.servarr.com/prowlarr) -## Indexers/Trackers +## Indexers & Trackers -[Supported Indexers](https://wiki.servarr.com/en/prowlarr/supported-indexers) +[![Supported Indexers](https://img.shields.io/badge/Supported%20Indexers-View%20all%20currently%20supported%20indexers%20%26%20trackers-important)](https://wiki.servarr.com/en/prowlarr/supported-indexers) -[Indexer Requests](https://requests.prowlarr.com) -- Request or vote on an existing request for a new tracker/indexer +[![Indexer Requests](https://img.shields.io/badge/Indexer%20Requests-Create%20and%20view%20existing%20requests%20for%20trackers%20and%20indexers-informational)](https://requests.prowlarr.com) ## Contributors & Developers +[API Documentation](https://prowlarr.com/docs/api/) + +This project exists thanks to all the people who contribute. + - [Contribute (GitHub)](CONTRIBUTING.md) - [Contribution (Wiki Article)](https://wiki.servarr.com/prowlarr/contributing) -- [YML Indexer Defintion (Wiki Article)](https://wiki.servarr.com/prowlarr/cardigann-yml-definition) +- [YML Indexer Definition (Wiki Article)](https://wiki.servarr.com/prowlarr/cardigann-yml-definition) -This project exists thanks to all the people who contribute. -<a href="https://github.com/Prowlarr/Prowlarr/graphs/contributors"><img src="https://opencollective.com/Prowlarr/contributors.svg?width=890&button=false" /></a> +[![Contributors List](https://opencollective.com/Prowlarr/contributors.svg?width=890&button=false)](https://github.com/Prowlarr/Prowlarr/graphs/contributors) ## Backers Thank you to all our backers! 🙏 [Become a backer](https://opencollective.com/Prowlarr#backer) - -<img src="https://opencollective.com/Prowlarr/backers.svg?width=890"></a> +![Backers List](https://opencollective.com/Prowlarr/backers.svg?width=890) ## Sponsors Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor](https://opencollective.com/Prowlarr#sponsor) - -<img src="https://opencollective.com/Prowlarr/sponsors.svg?width=890"></a> +![Sponsors List](https://opencollective.com/Prowlarr/sponsors.svg?width=890) ## Mega Sponsors -<img src="https://opencollective.com/Prowlarr/tiers/mega-sponsor.svg?width=890"></a> +![Mega Sponsors List](https://opencollective.com/Prowlarr/tiers/mega-sponsor.svg?width=890) ## JetBrains + Thank you to [<img src="/Logo/jetbrains.svg" alt="JetBrains" width="32"> JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools. -* [<img src="/Logo/resharper.svg" alt="ReSharper" width="32"> ReSharper](http://www.jetbrains.com/resharper/) -* [<img src="/Logo/webstorm.svg" alt="WebStorm" width="32"> WebStorm](http://www.jetbrains.com/webstorm/) -* [<img src="/Logo/rider.svg" alt="Rider" width="32"> Rider](http://www.jetbrains.com/rider/) -* [<img src="/Logo/dottrace.svg" alt="dotTrace" width="32"> dotTrace](http://www.jetbrains.com/dottrace/) +- [<img src="/Logo/resharper.svg" alt="ReSharper" width="32"> ReSharper](http://www.jetbrains.com/resharper/) +- [<img src="/Logo/webstorm.svg" alt="WebStorm" width="32"> WebStorm](http://www.jetbrains.com/webstorm/) +- [<img src="/Logo/rider.svg" alt="Rider" width="32"> Rider](http://www.jetbrains.com/rider/) +- [<img src="/Logo/dottrace.svg" alt="dotTrace" width="32"> dotTrace](http://www.jetbrains.com/dottrace/) ### License -* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html) -* Copyright 2010-2021 +- [GNU GPL v3](http://www.gnu.org/licenses/gpl.html) +- Copyright 2010-2022 -Icon Credit: -<a href="https://www.freepik.com/vectors/box">Box vector created by freepik - www.freepik.com</a> +Icon Credit - [Box vector created by freepik - www.freepik.com](https://www.freepik.com/vectors/box) From 579b8a3d3bdb293fdbf2dbbdbaf9eafdef4e40ef Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 5 Dec 2021 11:23:47 -0600 Subject: [PATCH 0224/2320] New: (Cardigann) More feed metadata for book and music --- .../IndexerSearch/NewznabResults.cs | 6 +++++- .../Definitions/Cardigann/CardigannParser.cs | 19 ++++++++++++------- src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs | 5 +++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs index 8e97c2806..da6d01c82 100644 --- a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs +++ b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs @@ -92,11 +92,15 @@ namespace NzbDrone.Core.IndexerSearch GetNabElement("rageid", r.TvRageId, protocol), GetNabElement("tvdbid", r.TvdbId, protocol), GetNabElement("imdb", r.ImdbId.ToString("D7"), protocol), - GetNabElement("tmdb", r.TmdbId, protocol), + GetNabElement("tmdbid", r.TmdbId, protocol), GetNabElement("seeders", t.Seeders, protocol), GetNabElement("files", r.Files, protocol), GetNabElement("grabs", r.Grabs, protocol), GetNabElement("peers", t.Peers, protocol), + GetNabElement("author", RemoveInvalidXMLChars(r.Author), protocol), + GetNabElement("booktitle", RemoveInvalidXMLChars(r.BookTitle), protocol), + GetNabElement("artist", RemoveInvalidXMLChars(r.Artist), protocol), + GetNabElement("album", RemoveInvalidXMLChars(r.Album), protocol), GetNabElement("infohash", RemoveInvalidXMLChars(t.InfoHash), protocol), GetNabElement("minimumratio", t.MinimumRatio, protocol), GetNabElement("minimumseedtime", t.MinimumSeedTime, protocol), diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index a48cd760d..5ad00524c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -561,13 +561,18 @@ namespace NzbDrone.Core.Indexers.Cardigann value = release.PosterUrl; break; - - //case "author": - // release.Author = value; - // break; - //case "booktitle": - // release.BookTitle = value; - // break; + case "author": + release.Author = value; + break; + case "booktitle": + release.BookTitle = value; + break; + case "artist": + release.Artist = value; + break; + case "album": + release.Album = value; + break; default: break; } diff --git a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs index c2f023b60..23ce03963 100644 --- a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs +++ b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs @@ -31,6 +31,10 @@ namespace NzbDrone.Core.Parser.Model public int TvRageId { get; set; } public int ImdbId { get; set; } public int TmdbId { get; set; } + public string Author { get; set; } + public string BookTitle { get; set; } + public string Artist { get; set; } + public string Album { get; set; } public DateTime PublishDate { get; set; } public string PosterUrl { get; set; } @@ -93,6 +97,7 @@ namespace NzbDrone.Core.Parser.Model stringBuilder.AppendLine("TvdbId: " + TvdbId ?? "Empty"); stringBuilder.AppendLine("TvRageId: " + TvRageId ?? "Empty"); stringBuilder.AppendLine("ImdbId: " + ImdbId ?? "Empty"); + stringBuilder.AppendLine("TmdbId: " + TmdbId ?? "Empty"); stringBuilder.AppendLine("PublishDate: " + PublishDate ?? "Empty"); return stringBuilder.ToString(); default: From 4eadd4cb2f354f5035d836f0f818e0fa5f28453c Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 5 Dec 2021 11:40:21 -0600 Subject: [PATCH 0225/2320] New: LazyLibrarian Sync Support Closes #469 Co-Authored-By: philborman <12158777+philborman@users.noreply.github.com> --- .../LazyLibrarian/LazyLibrarian.cs | 153 ++++++++++++++ .../LazyLibrarian/LazyLibrarianError.cs | 8 + .../LazyLibrarian/LazyLibrarianException.cs | 23 +++ .../LazyLibrarian/LazyLibrarianIndexer.cs | 49 +++++ .../LazyLibrarian/LazyLibrarianSettings.cs | 58 ++++++ .../LazyLibrarian/LazyLibrarianStatus.cs | 8 + .../LazyLibrarian/LazyLibrarianV1Proxy.cs | 187 ++++++++++++++++++ 7 files changed, 486 insertions(+) create mode 100644 src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarian.cs create mode 100644 src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianError.cs create mode 100644 src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianException.cs create mode 100644 src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianIndexer.cs create mode 100644 src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianSettings.cs create mode 100644 src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianStatus.cs create mode 100644 src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs diff --git a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarian.cs b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarian.cs new file mode 100644 index 000000000..763735d51 --- /dev/null +++ b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarian.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using FluentValidation.Results; +using NLog; +using NzbDrone.Common.Cache; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers; + +namespace NzbDrone.Core.Applications.LazyLibrarian +{ + public class LazyLibrarian : ApplicationBase<LazyLibrarianSettings> + { + public override string Name => "LazyLibrarian"; + + private readonly ILazyLibrarianV1Proxy _lazyLibrarianV1Proxy; + private readonly IConfigFileProvider _configFileProvider; + + public LazyLibrarian(ILazyLibrarianV1Proxy lazyLibrarianV1Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, Logger logger) + : base(appIndexerMapService, logger) + { + _lazyLibrarianV1Proxy = lazyLibrarianV1Proxy; + _configFileProvider = configFileProvider; + } + + public override ValidationResult Test() + { + var failures = new List<ValidationFailure>(); + + try + { + failures.AddIfNotNull(_lazyLibrarianV1Proxy.TestConnection(Settings)); + } + catch (WebException ex) + { + _logger.Error(ex, "Unable to send test message"); + failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Unable to complete application test, cannot connect to LazyLibrarian")); + } + + return new ValidationResult(failures); + } + + public override List<AppIndexerMap> GetIndexerMappings() + { + var indexers = _lazyLibrarianV1Proxy.GetIndexers(Settings); + + var mappings = new List<AppIndexerMap>(); + + foreach (var indexer in indexers) + { + if (indexer.Apikey == _configFileProvider.ApiKey) + { + var match = AppIndexerRegex.Match(indexer.Host); + + if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId)) + { + //Add parsed mapping if it's mapped to a Indexer in this Prowlarr instance + mappings.Add(new AppIndexerMap { RemoteIndexerName = $"{indexer.Type},{indexer.Name}", IndexerId = indexerId }); + } + } + } + + return mappings; + } + + public override void AddIndexer(IndexerDefinition indexer) + { + if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) + { + var lazyLibrarianIndexer = BuildLazyLibrarianIndexer(indexer, indexer.Protocol); + + var remoteIndexer = _lazyLibrarianV1Proxy.AddIndexer(lazyLibrarianIndexer, Settings); + _appIndexerMapService.Insert(new AppIndexerMap { AppId = Definition.Id, IndexerId = indexer.Id, RemoteIndexerName = $"{remoteIndexer.Type},{remoteIndexer.Name}" }); + } + } + + public override void RemoveIndexer(int indexerId) + { + var appMappings = _appIndexerMapService.GetMappingsForApp(Definition.Id); + + var indexerMapping = appMappings.FirstOrDefault(m => m.IndexerId == indexerId); + + if (indexerMapping != null) + { + //Remove Indexer remotely and then remove the mapping + var indexerProps = indexerMapping.RemoteIndexerName.Split(","); + _lazyLibrarianV1Proxy.RemoveIndexer(indexerProps[1], (LazyLibrarianProviderType)Enum.Parse(typeof(LazyLibrarianProviderType), indexerProps[0]), Settings); + _appIndexerMapService.Delete(indexerMapping.Id); + } + } + + public override void UpdateIndexer(IndexerDefinition indexer) + { + _logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id); + + var appMappings = _appIndexerMapService.GetMappingsForApp(Definition.Id); + var indexerMapping = appMappings.FirstOrDefault(m => m.IndexerId == indexer.Id); + var indexerProps = indexerMapping.RemoteIndexerName.Split(","); + + var lazyLibrarianIndexer = BuildLazyLibrarianIndexer(indexer, indexer.Protocol, indexerProps[1]); + + //Use the old remote id to find the indexer on LazyLibrarian incase the update was from a name change in Prowlarr + var remoteIndexer = _lazyLibrarianV1Proxy.GetIndexer(indexerProps[1], lazyLibrarianIndexer.Type, Settings); + + if (remoteIndexer != null) + { + _logger.Debug("Remote indexer found, syncing with current settings"); + + if (!lazyLibrarianIndexer.Equals(remoteIndexer)) + { + _lazyLibrarianV1Proxy.UpdateIndexer(lazyLibrarianIndexer, Settings); + indexerMapping.RemoteIndexerName = $"{lazyLibrarianIndexer.Type},{lazyLibrarianIndexer.Altername}"; + _appIndexerMapService.Update(indexerMapping); + } + } + else + { + _appIndexerMapService.Delete(indexerMapping.Id); + + if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) + { + _logger.Debug("Remote indexer not found, re-adding {0} to LazyLibrarian", indexer.Name); + var newRemoteIndexer = _lazyLibrarianV1Proxy.AddIndexer(lazyLibrarianIndexer, Settings); + _appIndexerMapService.Insert(new AppIndexerMap { AppId = Definition.Id, IndexerId = indexer.Id, RemoteIndexerName = $"{newRemoteIndexer.Type},{newRemoteIndexer.Name}" }); + } + else + { + _logger.Debug("Remote indexer not found for {0}, skipping re-add to LazyLibrarian due to indexer capabilities", indexer.Name); + } + } + } + + private LazyLibrarianIndexer BuildLazyLibrarianIndexer(IndexerDefinition indexer, DownloadProtocol protocol, string originalName = null) + { + var schema = protocol == DownloadProtocol.Usenet ? LazyLibrarianProviderType.Newznab : LazyLibrarianProviderType.Torznab; + + var lazyLibrarianIndexer = new LazyLibrarianIndexer + { + Name = originalName ?? $"{indexer.Name} (Prowlarr)", + Altername = $"{indexer.Name} (Prowlarr)", + Host = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/api", + Apikey = _configFileProvider.ApiKey, + Categories = string.Join(",", indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray())), + Enabled = indexer.Enable, + Type = schema, + }; + + return lazyLibrarianIndexer; + } + } +} diff --git a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianError.cs b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianError.cs new file mode 100644 index 000000000..65338ae92 --- /dev/null +++ b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianError.cs @@ -0,0 +1,8 @@ +namespace NzbDrone.Core.Applications.LazyLibrarian +{ + public class LazyLibrarianError + { + public int Code { get; set; } + public string Message { get; set; } + } +} diff --git a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianException.cs b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianException.cs new file mode 100644 index 000000000..ab0d32749 --- /dev/null +++ b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianException.cs @@ -0,0 +1,23 @@ +using System; +using NzbDrone.Common.Exceptions; + +namespace NzbDrone.Core.Applications.LazyLibrarian +{ + public class LazyLibrarianException : NzbDroneException + { + public LazyLibrarianException(string message) + : base(message) + { + } + + public LazyLibrarianException(string message, params object[] args) + : base(message, args) + { + } + + public LazyLibrarianException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} diff --git a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianIndexer.cs b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianIndexer.cs new file mode 100644 index 000000000..ff77f47b7 --- /dev/null +++ b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianIndexer.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; + +namespace NzbDrone.Core.Applications.LazyLibrarian +{ + public class LazyLibrarianIndexerResponse + { + public bool Success { get; set; } + public LazyLibrarianIndexerData Data { get; set; } + public LazyLibrarianError Error { get; set; } + } + + public class LazyLibrarianIndexerData + { + public List<LazyLibrarianIndexer> Torznabs { get; set; } + public List<LazyLibrarianIndexer> Newznabs { get; set; } + } + + public enum LazyLibrarianProviderType + { + Newznab, + Torznab + } + + public class LazyLibrarianIndexer + { + public string Name { get; set; } + public string Host { get; set; } + public string Apikey { get; set; } + public string Categories { get; set; } + public bool Enabled { get; set; } + public string Altername { get; set; } + public LazyLibrarianProviderType Type { get; set; } + + public bool Equals(LazyLibrarianIndexer other) + { + if (ReferenceEquals(null, other)) + { + return false; + } + + return other.Host == Host && + other.Apikey == Apikey && + other.Name == Name && + other.Categories == Categories && + other.Enabled == Enabled && + other.Altername == Altername; + } + } +} diff --git a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianSettings.cs b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianSettings.cs new file mode 100644 index 000000000..e6c8df3dd --- /dev/null +++ b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianSettings.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Applications.LazyLibrarian +{ + public class LazyLibrarianSettingsValidator : AbstractValidator<LazyLibrarianSettings> + { + public LazyLibrarianSettingsValidator() + { + RuleFor(c => c.BaseUrl).IsValidUrl(); + RuleFor(c => c.ProwlarrUrl).IsValidUrl(); + RuleFor(c => c.ApiKey).NotEmpty(); + RuleFor(c => c.SyncCategories).NotEmpty(); + } + } + + public class LazyLibrarianSettings : IApplicationSettings + { + private static readonly LazyLibrarianSettingsValidator Validator = new LazyLibrarianSettingsValidator(); + + public LazyLibrarianSettings() + { + ProwlarrUrl = "http://localhost:9696"; + BaseUrl = "http://localhost:5299"; + SyncCategories = new[] + { + NewznabStandardCategory.AudioAudiobook.Id, + NewznabStandardCategory.Books.Id, + NewznabStandardCategory.BooksComics.Id, + NewznabStandardCategory.BooksEBook.Id, + NewznabStandardCategory.BooksForeign.Id, + NewznabStandardCategory.BooksMags.Id, + NewznabStandardCategory.BooksOther.Id, + NewznabStandardCategory.BooksTechnical.Id, + }; + } + + [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as LazyLibrarian sees it, including http(s)://, port, and urlbase if needed")] + public string ProwlarrUrl { get; set; } + + [FieldDefinition(1, Label = "LazyLibrarian Server", HelpText = "URL used to connect to LazyLibrarian server, including http(s)://, port, and urlbase if required")] + public string BaseUrl { get; set; } + + [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by LazyLibrarian in Settings/Web Interface")] + public string ApiKey { get; set; } + + [FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")] + public IEnumerable<int> SyncCategories { get; set; } + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} diff --git a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianStatus.cs b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianStatus.cs new file mode 100644 index 000000000..869bd50dd --- /dev/null +++ b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianStatus.cs @@ -0,0 +1,8 @@ +namespace NzbDrone.Core.Applications.LazyLibrarian +{ + public class LazyLibrarianStatus + { + public bool Success { get; set; } + public LazyLibrarianError Error { get; set; } + } +} diff --git a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs new file mode 100644 index 000000000..13cc2aa85 --- /dev/null +++ b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using FluentValidation.Results; +using Newtonsoft.Json; +using NLog; +using NzbDrone.Common.Http; + +namespace NzbDrone.Core.Applications.LazyLibrarian +{ + public interface ILazyLibrarianV1Proxy + { + LazyLibrarianIndexer AddIndexer(LazyLibrarianIndexer indexer, LazyLibrarianSettings settings); + List<LazyLibrarianIndexer> GetIndexers(LazyLibrarianSettings settings); + LazyLibrarianIndexer GetIndexer(string indexerName, LazyLibrarianProviderType indexerType, LazyLibrarianSettings settings); + void RemoveIndexer(string indexerName, LazyLibrarianProviderType indexerType, LazyLibrarianSettings settings); + LazyLibrarianIndexer UpdateIndexer(LazyLibrarianIndexer indexer, LazyLibrarianSettings settings); + ValidationFailure TestConnection(LazyLibrarianSettings settings); + } + + public class LazyLibrarianV1Proxy : ILazyLibrarianV1Proxy + { + private readonly IHttpClient _httpClient; + private readonly Logger _logger; + + public LazyLibrarianV1Proxy(IHttpClient httpClient, Logger logger) + { + _httpClient = httpClient; + _logger = logger; + } + + public LazyLibrarianStatus GetStatus(LazyLibrarianSettings settings) + { + var request = BuildRequest(settings, "/api", "getVersion", HttpMethod.GET); + return Execute<LazyLibrarianStatus>(request); + } + + public List<LazyLibrarianIndexer> GetIndexers(LazyLibrarianSettings settings) + { + var request = BuildRequest(settings, "/api", "listProviders", HttpMethod.GET); + + var response = Execute<LazyLibrarianIndexerResponse>(request); + + if (!response.Success) + { + throw new LazyLibrarianException(string.Format("LazyLibrarian Error - Code {0}: {1}", response.Error.Code, response.Error.Message)); + } + + var indexers = new List<LazyLibrarianIndexer>(); + + var torIndexers = response.Data.Torznabs; + torIndexers.ForEach(i => i.Type = LazyLibrarianProviderType.Torznab); + + var nzbIndexers = response.Data.Newznabs; + nzbIndexers.ForEach(i => i.Type = LazyLibrarianProviderType.Newznab); + + indexers.AddRange(torIndexers); + indexers.AddRange(nzbIndexers); + indexers.ForEach(i => i.Altername = i.Name); + + return indexers; + } + + public LazyLibrarianIndexer GetIndexer(string indexerName, LazyLibrarianProviderType indexerType, LazyLibrarianSettings settings) + { + var indexers = GetIndexers(settings); + + return indexers.SingleOrDefault(i => i.Name == indexerName && i.Type == indexerType); + } + + public void RemoveIndexer(string indexerName, LazyLibrarianProviderType indexerType, LazyLibrarianSettings settings) + { + var parameters = new Dictionary<string, string> + { + { "name", indexerName }, + { "providertype", indexerType.ToString().ToLower() } + }; + + var request = BuildRequest(settings, "/api", "delProvider", HttpMethod.GET, parameters); + CheckForError(Execute<LazyLibrarianStatus>(request)); + } + + public LazyLibrarianIndexer AddIndexer(LazyLibrarianIndexer indexer, LazyLibrarianSettings settings) + { + var parameters = new Dictionary<string, string> + { + { "name", indexer.Name }, + { "providertype", indexer.Type.ToString().ToLower() }, + { "host", indexer.Host }, + { "prov_apikey", indexer.Apikey }, + { "enabled", indexer.Enabled.ToString().ToLower() }, + { "categories", indexer.Categories } + }; + + var request = BuildRequest(settings, "/api", "addProvider", HttpMethod.GET, parameters); + CheckForError(Execute<LazyLibrarianStatus>(request)); + return indexer; + } + + public LazyLibrarianIndexer UpdateIndexer(LazyLibrarianIndexer indexer, LazyLibrarianSettings settings) + { + var parameters = new Dictionary<string, string> + { + { "name", indexer.Name }, + { "providertype", indexer.Type.ToString().ToLower() }, + { "host", indexer.Host }, + { "prov_apikey", indexer.Apikey }, + { "enabled", indexer.Enabled.ToString().ToLower() }, + { "categories", indexer.Categories }, + { "altername", indexer.Altername } + }; + + var request = BuildRequest(settings, "/api", "changeProvider", HttpMethod.GET, parameters); + CheckForError(Execute<LazyLibrarianStatus>(request)); + return indexer; + } + + private void CheckForError(LazyLibrarianStatus response) + { + if (!response.Success) + { + throw new LazyLibrarianException(string.Format("LazyLibrarian Error - Code {0}: {1}", response.Error.Code, response.Error.Message)); + } + } + + public ValidationFailure TestConnection(LazyLibrarianSettings settings) + { + try + { + var status = GetStatus(settings); + + if (!status.Success) + { + return new ValidationFailure("ApiKey", status.Error.Message); + } + } + catch (HttpException ex) + { + _logger.Error(ex, "Unable to send test message"); + return new ValidationFailure("BaseUrl", "Unable to complete application test"); + } + catch (Exception ex) + { + _logger.Error(ex, "Unable to send test message"); + return new ValidationFailure("", "Unable to send test message"); + } + + return null; + } + + private HttpRequest BuildRequest(LazyLibrarianSettings settings, string resource, string command, HttpMethod method, Dictionary<string, string> parameters = null) + { + var baseUrl = settings.BaseUrl.TrimEnd('/'); + + var requestBuilder = new HttpRequestBuilder(baseUrl).Resource(resource) + .AddQueryParam("cmd", command) + .AddQueryParam("apikey", settings.ApiKey); + + if (parameters != null) + { + foreach (var param in parameters) + { + requestBuilder.AddQueryParam(param.Key, param.Value); + } + } + + var request = requestBuilder.Build(); + + request.Headers.ContentType = "application/json"; + + request.Method = method; + request.AllowAutoRedirect = true; + + return request; + } + + private TResource Execute<TResource>(HttpRequest request) + where TResource : new() + { + var response = _httpClient.Execute(request); + + var results = JsonConvert.DeserializeObject<TResource>(response.Content); + + return results; + } + } +} From 0f52258d53258081f26887e60fa61bd48f40d2bc Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 5 Dec 2021 17:26:58 -0600 Subject: [PATCH 0226/2320] Fixed: (Flaresolverr) YggCookie and YggTorrent Issues --- .../Http/Dispatchers/ManagedHttpDispatcher.cs | 3 +- src/NzbDrone.Common/Http/HttpHeader.cs | 14 +++++- .../FlareSolverr/FlareSolverr.cs | 48 +++++++++++++++---- 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs index e20341305..e5bcb6432 100644 --- a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs +++ b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs @@ -254,7 +254,8 @@ namespace NzbDrone.Common.Http.Dispatchers webRequest.TransferEncoding = header.Value; break; case "User-Agent": - throw new NotSupportedException("User-Agent other than Prowlarr not allowed."); + webRequest.UserAgent = header.Value; + break; case "Proxy-Connection": throw new NotImplementedException(); default: diff --git a/src/NzbDrone.Common/Http/HttpHeader.cs b/src/NzbDrone.Common/Http/HttpHeader.cs index 2794f6dc4..b78e27460 100644 --- a/src/NzbDrone.Common/Http/HttpHeader.cs +++ b/src/NzbDrone.Common/Http/HttpHeader.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; @@ -107,6 +107,18 @@ namespace NzbDrone.Common.Http } } + public string UserAgent + { + get + { + return GetSingleValue("User-Agent"); + } + set + { + SetSingleValue("User-Agent", value); + } + } + public string Accept { get diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index 8751519b9..3215c0a39 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -5,7 +5,9 @@ using System.Net; using FluentValidation.Results; using Newtonsoft.Json; using NLog; +using NzbDrone.Common.Cache; using NzbDrone.Common.Cloud; +using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Common.Serializer; using NzbDrone.Core.Localization; @@ -16,10 +18,12 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr public class FlareSolverr : HttpIndexerProxyBase<FlareSolverrSettings> { private static readonly HashSet<string> CloudflareServerNames = new HashSet<string> { "cloudflare", "cloudflare-nginx" }; + private readonly ICached<string> _cache; - public FlareSolverr(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger, ILocalizationService localizationService) + public FlareSolverr(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger, ILocalizationService localizationService, ICacheManager cacheManager) : base(cloudRequestBuilder, httpClient, logger, localizationService) { + _cache = cacheManager.GetCache<string>(typeof(string), "UserAgent"); } public override string Name => "FlareSolverr"; @@ -29,6 +33,12 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr //Try original request first, ignore errors, detect CF in post response request.SuppressHttpError = true; + //Inject UA if not present + if (_cache.Find(request.Url.Host).IsNotNullOrWhiteSpace() && request.Headers.UserAgent.IsNullOrWhiteSpace()) + { + request.Headers.UserAgent = _cache.Find(request.Url.Host); + } + return request; } @@ -51,18 +61,18 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr result = JsonConvert.DeserializeObject<FlareSolverrResponse>(flaresolverrResponse.Content); - var cookieCollection = new CookieCollection(); - var responseHeader = new HttpHeader(); + var newRequest = response.Request; - foreach (var cookie in result.Solution.Cookies) - { - cookieCollection.Add(cookie.ToCookieObj()); - } + //Cache the user-agent so we can inject it in next request to avoid re-solve + _cache.Set(response.Request.Url.Host, result.Solution.UserAgent); + newRequest.Headers.UserAgent = result.Solution.UserAgent; - //Build new response with FS Cookie and Site Response - var newResponse = new HttpResponse(response.Request, responseHeader, cookieCollection, result.Solution.Response); + InjectCookies(newRequest, result); - return newResponse; + //Request again with User-Agent and Cookies from Flaresolvrr + var finalResponse = _httpClient.Execute(newRequest); + + return finalResponse; } private static bool IsCloudflareProtected(HttpResponse response) @@ -79,6 +89,24 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr return false; } + private void InjectCookies(HttpRequest request, FlareSolverrResponse flareSolverrResponse) + { + var rCookies = flareSolverrResponse.Solution.Cookies; + + if (!rCookies.Any()) + { + return; + } + + var rCookiesList = rCookies.Select(x => x.Name).ToList(); + + foreach (var rCookie in rCookies) + { + request.Cookies.Remove(rCookie.Name); + request.Cookies.Add(rCookie.Name, rCookie.Value); + } + } + private HttpRequest GenerateFlareSolverrRequest(HttpRequest request) { FlareSolverrRequest req; From 4e69b80a98170aa605b7dacdeb29cbdc6543af70 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 5 Dec 2021 17:29:22 -0600 Subject: [PATCH 0227/2320] Bump to 0.1.7 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8453d7ec8..822852b41 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,7 +7,7 @@ variables: outputFolder: './_output' artifactsFolder: './_artifacts' testsFolder: './_tests' - majorVersion: '0.1.6' + majorVersion: '0.1.7' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From 3b7b72d4e1439b91470e08335172ab54a8228cfe Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 5 Dec 2021 17:42:40 -0600 Subject: [PATCH 0228/2320] Fixed: (Cardigann) Always use search headers for download if defined --- .../Definitions/Cardigann/CardigannRequestGenerator.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 5c1d631b4..1bd0a6c76 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -727,14 +727,14 @@ namespace NzbDrone.Core.Indexers.Cardigann var method = HttpMethod.GET; var headers = new Dictionary<string, string>(); + var variables = GetBaseTemplateVariables(); + AddTemplateVariablesFromUri(variables, link, ".DownloadUri"); + headers = ParseCustomHeaders(_definition.Search?.Headers, variables); + if (_definition.Download != null) { var download = _definition.Download; - var variables = GetBaseTemplateVariables(); - AddTemplateVariablesFromUri(variables, link, ".DownloadUri"); - - headers = ParseCustomHeaders(_definition.Search?.Headers, variables); HttpResponse response = null; var request = new HttpRequestBuilder(link.ToString()) From d2cf060473e11f04b9d1debeac48923b925064a9 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 6 Dec 2021 16:37:16 -0600 Subject: [PATCH 0229/2320] Fixed: (LazyLibrarian) Use listNabProviders instead of listProviders --- .../Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs index 13cc2aa85..df397d678 100644 --- a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs +++ b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs @@ -37,7 +37,7 @@ namespace NzbDrone.Core.Applications.LazyLibrarian public List<LazyLibrarianIndexer> GetIndexers(LazyLibrarianSettings settings) { - var request = BuildRequest(settings, "/api", "listProviders", HttpMethod.GET); + var request = BuildRequest(settings, "/api", "listNabProviders", HttpMethod.GET); var response = Execute<LazyLibrarianIndexerResponse>(request); From 88677ce236e4327364b5c8d0ab13f82cf80c8bfc Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 6 Dec 2021 17:19:04 -0600 Subject: [PATCH 0230/2320] Bump to 0.1.8 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 822852b41..c9135039d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,7 +7,7 @@ variables: outputFolder: './_output' artifactsFolder: './_artifacts' testsFolder: './_tests' - majorVersion: '0.1.7' + majorVersion: '0.1.8' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From 7fcd320e23cbfb05af45a37e20b036d8bf1aa7a0 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 29 Nov 2021 21:05:35 -0600 Subject: [PATCH 0231/2320] Fixed: (PrivateHD) Drop support for IMDB search imdb search does not support S/E params this matches the behavior for TorrentLeech Fixes #119 --- src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs b/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs index bb1fac39e..61e918986 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Core.Indexers.Definitions { TvSearchParams = new List<TvSearchParam> { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep }, MovieSearchParams = new List<MovieSearchParam> { From 4a7bf39723f40681c6dbf905f62f6b49e24c6362 Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Mon, 6 Dec 2021 21:57:22 +0000 Subject: [PATCH 0232/2320] Fixed: Speed up parsing DateTime --- src/NzbDrone.Core/Parser/DateTimeUtil.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/NzbDrone.Core/Parser/DateTimeUtil.cs b/src/NzbDrone.Core/Parser/DateTimeUtil.cs index 9bccaabe1..2e1422da8 100644 --- a/src/NzbDrone.Core/Parser/DateTimeUtil.cs +++ b/src/NzbDrone.Core/Parser/DateTimeUtil.cs @@ -214,16 +214,13 @@ namespace NzbDrone.Core.Parser return dt; } - try + // try parsing the str as an unix timestamp + if (long.TryParse(str, out var unixTimeStamp)) { - // try parsing the str as an unix timestamp - var unixTimeStamp = long.Parse(str); return UnixTimestampToDateTime(unixTimeStamp); } - catch (FormatException) - { - // it wasn't a timestamp, continue.... - } + + // it wasn't a timestamp, continue.... // add missing year match = _MissingYearRegexp.Match(str); From 6b886b938c08801c2854a55e7e257045e12b9e06 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 7 Dec 2021 18:42:38 -0600 Subject: [PATCH 0233/2320] New: Better Fuzzy DateTime Parse --- .../Definitions/Cardigann/CardigannBase.cs | 2 +- src/NzbDrone.Core/Parser/DateTimeRoutines.cs | 352 ++++++++++++++++++ src/NzbDrone.Core/Parser/DateTimeUtil.cs | 22 +- 3 files changed, 363 insertions(+), 13 deletions(-) create mode 100644 src/NzbDrone.Core/Parser/DateTimeRoutines.cs diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index 1b46b05e7..05fdeda25 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -633,7 +633,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var date = DateTimeUtil.ParseDateTimeGoLang(data, layout); data = date.ToString(DateTimeUtil.Rfc1123ZPattern); } - catch (FormatException ex) + catch (InvalidDateException ex) { _logger.Debug(ex.Message); } diff --git a/src/NzbDrone.Core/Parser/DateTimeRoutines.cs b/src/NzbDrone.Core/Parser/DateTimeRoutines.cs new file mode 100644 index 000000000..27cdcc17b --- /dev/null +++ b/src/NzbDrone.Core/Parser/DateTimeRoutines.cs @@ -0,0 +1,352 @@ +//******************************************************************************************** +//Author: Sergey Stoyan, CliverSoft.com +// http://cliversoft.com +// stoyan@cliversoft.com +// sergey.stoyan@gmail.com +// 27 February 2007 +//******************************************************************************************** +using System; +using System.Text.RegularExpressions; + +namespace NzbDrone.Core.Parser +{ + public static class DateTimeRoutines + { + public class ParsedDateTime + { + public readonly int IndexOfDate = -1; + public readonly int LengthOfDate = -1; + public readonly int IndexOfTime = -1; + public readonly int LengthOfTime = -1; + public readonly DateTime DateTime; + public readonly bool IsDateFound; + public readonly bool IsTimeFound; + + internal ParsedDateTime(int index_of_date, int length_of_date, int index_of_time, int length_of_time, DateTime date_time) + { + IndexOfDate = index_of_date; + LengthOfDate = length_of_date; + IndexOfTime = index_of_time; + LengthOfTime = length_of_time; + DateTime = date_time; + IsDateFound = index_of_date > -1; + IsTimeFound = index_of_time > -1; + } + } + + public static DateTime DefaultDate + { + get + { + if (DefaultDateIsNow) + { + return DateTime.Now; + } + else + { + return _DefaultDate; + } + } + set + { + _DefaultDate = value; + DefaultDateIsNow = false; + } + } + + private static DateTime _DefaultDate = DateTime.Now; + + public static bool DefaultDateIsNow = true; + + public enum DateTimeFormat + { + USDate, + UKDate, + } + + public static bool TryParseDateOrTime(this string str, DateTimeFormat default_format, out ParsedDateTime parsed_date_time) + { + parsed_date_time = null; + + ParsedDateTime parsed_date; + ParsedDateTime parsed_time; + if (!TryParseDate(str, default_format, out parsed_date)) + { + if (!TryParseTime(str, default_format, out parsed_time, null)) + { + return false; + } + + var date_time = new DateTime(DefaultDate.Year, DefaultDate.Month, DefaultDate.Day, parsed_time.DateTime.Hour, parsed_time.DateTime.Minute, parsed_time.DateTime.Second); + parsed_date_time = new ParsedDateTime(-1, -1, parsed_time.IndexOfTime, parsed_time.LengthOfTime, date_time); + } + else + { + if (!TryParseTime(str, default_format, out parsed_time, parsed_date)) + { + var date_time = new DateTime(parsed_date.DateTime.Year, parsed_date.DateTime.Month, parsed_date.DateTime.Day, 0, 0, 0); + parsed_date_time = new ParsedDateTime(parsed_date.IndexOfDate, parsed_date.LengthOfDate, -1, -1, date_time); + } + else + { + var date_time = new DateTime(parsed_date.DateTime.Year, parsed_date.DateTime.Month, parsed_date.DateTime.Day, parsed_time.DateTime.Hour, parsed_time.DateTime.Minute, parsed_time.DateTime.Second); + parsed_date_time = new ParsedDateTime(parsed_date.IndexOfDate, parsed_date.LengthOfDate, parsed_time.IndexOfTime, parsed_time.LengthOfTime, date_time); + } + } + + return true; + } + + public static bool TryParseTime(this string str, DateTimeFormat default_format, out ParsedDateTime parsed_time, ParsedDateTime parsed_date) + { + parsed_time = null; + + Match m; + if (parsed_date != null && parsed_date.IndexOfDate > -1) + { + //look around the found date + //look for <date> [h]h:mm[:ss] [PM/AM] + m = Regex.Match(str.Substring(parsed_date.IndexOfDate + parsed_date.LengthOfDate), @"(?<=^\s*,?\s+|^\s*at\s*|^\s*[T\-]\s*)(?'hour'\d{1,2})\s*:\s*(?'minute'\d{2})\s*(?::\s*(?'second'\d{2}))?(?:\s*(?'ampm'AM|am|PM|pm))?(?=$|[^\d\w])", RegexOptions.Compiled); + if (!m.Success) + { + //look for [h]h:mm:ss <date> + m = Regex.Match(str.Substring(0, parsed_date.IndexOfDate), @"(?<=^|[^\d])(?'hour'\d{1,2})\s*:\s*(?'minute'\d{2})\s*(?::\s*(?'second'\d{2}))?(?:\s*(?'ampm'AM|am|PM|pm))?(?=$|[\s,]+)", RegexOptions.Compiled); + } + } + else + { + //look anywere within string + //look for [h]h:mm[:ss] [PM/AM] + m = Regex.Match(str, @"(?<=^|\s+|\s*T\s*)(?'hour'\d{1,2})\s*:\s*(?'minute'\d{2})\s*(?::\s*(?'second'\d{2}))?(?:\s*(?'ampm'AM|am|PM|pm))?(?=$|[^\d\w])", RegexOptions.Compiled); + } + + if (m.Success) + { + try + { + var hour = int.Parse(m.Groups["hour"].Value); + if (hour < 0 || hour > 23) + { + return false; + } + + var minute = int.Parse(m.Groups["minute"].Value); + if (minute < 0 || minute > 59) + { + return false; + } + + var second = 0; + if (!string.IsNullOrEmpty(m.Groups["second"].Value)) + { + second = int.Parse(m.Groups["second"].Value); + if (second < 0 || second > 59) + { + return false; + } + } + + if (string.Compare(m.Groups["ampm"].Value, "PM", true) == 0 && hour < 12) + { + hour += 12; + } + else if (string.Compare(m.Groups["ampm"].Value, "AM", true) == 0 && hour == 12) + { + hour -= 12; + } + + var date_time = new DateTime(1, 1, 1, hour, minute, second); + parsed_time = new ParsedDateTime(-1, -1, m.Index, m.Length, date_time); + } + catch + { + return false; + } + + return true; + } + + return false; + } + + public static bool TryParseDate(this string str, DateTimeFormat default_format, out ParsedDateTime parsed_date) + { + parsed_date = null; + + if (string.IsNullOrEmpty(str)) + { + return false; + } + + //look for dd/mm/yy + var m = Regex.Match(str, @"(?<=^|[^\d])(?'day'\d{1,2})\s*(?'separator'[\\/\.])+\s*(?'month'\d{1,2})\s*\'separator'+\s*(?'year'\d{2}|\d{4})(?=$|[^\d])", RegexOptions.Compiled | RegexOptions.IgnoreCase); + if (m.Success) + { + DateTime date; + if ((default_format ^ DateTimeFormat.USDate) == DateTimeFormat.USDate) + { + if (!ConvertToDate(int.Parse(m.Groups["year"].Value), int.Parse(m.Groups["day"].Value), int.Parse(m.Groups["month"].Value), out date)) + { + return false; + } + } + else + { + if (!ConvertToDate(int.Parse(m.Groups["year"].Value), int.Parse(m.Groups["month"].Value), int.Parse(m.Groups["day"].Value), out date)) + { + return false; + } + } + + parsed_date = new ParsedDateTime(m.Index, m.Length, -1, -1, date); + return true; + } + + //look for [yy]yy-mm-dd + m = Regex.Match(str, @"(?<=^|[^\d])(?'year'\d{2}|\d{4})\s*(?'separator'[\-])\s*(?'month'\d{1,2})\s*\'separator'+\s*(?'day'\d{1,2})(?=$|[^\d])", RegexOptions.Compiled | RegexOptions.IgnoreCase); + if (m.Success) + { + DateTime date; + if (!ConvertToDate(int.Parse(m.Groups["year"].Value), int.Parse(m.Groups["month"].Value), int.Parse(m.Groups["day"].Value), out date)) + { + return false; + } + + parsed_date = new ParsedDateTime(m.Index, m.Length, -1, -1, date); + return true; + } + + //look for month dd yyyy + m = Regex.Match(str, @"(?:^|[^\d\w])(?'month'Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[uarychilestmbro]*\s+(?'day'\d{1,2})(?:-?st|-?th|-?rd|-?nd)?\s*,?\s*(?'year'\d{4})(?=$|[^\d\w])", RegexOptions.Compiled | RegexOptions.IgnoreCase); + if (!m.Success) + { + //look for dd month [yy]yy + m = Regex.Match(str, @"(?:^|[^\d\w:])(?'day'\d{1,2})(?:-?st\s+|-?th\s+|-?rd\s+|-?nd\s+|-|\s+)(?'month'Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[uarychilestmbro]*(?:\s*,?\s*|-)'?(?'year'\d{2}|\d{4})(?=$|[^\d\w])", RegexOptions.Compiled | RegexOptions.IgnoreCase); + } + + if (!m.Success) + { + //look for yyyy month dd + m = Regex.Match(str, @"(?:^|[^\d\w])(?'year'\d{4})\s+(?'month'Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[uarychilestmbro]*\s+(?'day'\d{1,2})(?:-?st|-?th|-?rd|-?nd)?(?=$|[^\d\w])", RegexOptions.Compiled | RegexOptions.IgnoreCase); + } + + if (!m.Success) + { + //look for month dd [yyyy] + m = Regex.Match(str, @"(?:^|[^\d\w])(?'month'Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[uarychilestmbro]*\s+(?'day'\d{1,2})(?:-?st|-?th|-?rd|-?nd)?(?:\s*,?\s*(?'year'\d{4}))?(?=$|[^\d\w])", RegexOptions.Compiled | RegexOptions.IgnoreCase); + } + + if (m.Success) + { + var month = -1; + var index_of_date = m.Index; + var length_of_date = m.Length; + + switch (m.Groups["month"].Value) + { + case "Jan": + case "JAN": + month = 1; + break; + case "Feb": + case "FEB": + month = 2; + break; + case "Mar": + case "MAR": + month = 3; + break; + case "Apr": + case "APR": + month = 4; + break; + case "May": + case "MAY": + month = 5; + break; + case "Jun": + case "JUN": + month = 6; + break; + case "Jul": + month = 7; + break; + case "Aug": + case "AUG": + month = 8; + break; + case "Sep": + case "SEP": + month = 9; + break; + case "Oct": + case "OCT": + month = 10; + break; + case "Nov": + case "NOV": + month = 11; + break; + case "Dec": + case "DEC": + month = 12; + break; + } + + int year; + if (!string.IsNullOrEmpty(m.Groups["year"].Value)) + { + year = int.Parse(m.Groups["year"].Value); + } + else + { + year = DefaultDate.Year; + } + + DateTime date; + if (!ConvertToDate(year, month, int.Parse(m.Groups["day"].Value), out date)) + { + return false; + } + + parsed_date = new ParsedDateTime(index_of_date, length_of_date, -1, -1, date); + return true; + } + + return false; + } + + private static bool ConvertToDate(int year, int month, int day, out DateTime date) + { + if (year >= 100) + { + if (year < 1000) + { + date = new DateTime(1, 1, 1); + return false; + } + } + else + if (year > 30) + { + year += 1900; + } + else + { + year += 2000; + } + + try + { + date = new DateTime(year, month, day); + } + catch + { + date = new DateTime(1, 1, 1); + return false; + } + + return true; + } + } +} diff --git a/src/NzbDrone.Core/Parser/DateTimeUtil.cs b/src/NzbDrone.Core/Parser/DateTimeUtil.cs index 2e1422da8..2f6596350 100644 --- a/src/NzbDrone.Core/Parser/DateTimeUtil.cs +++ b/src/NzbDrone.Core/Parser/DateTimeUtil.cs @@ -91,7 +91,7 @@ namespace NzbDrone.Core.Parser } else { - throw new Exception("TimeAgo parsing failed, unknown unit: " + unit); + throw new InvalidDateException("TimeAgo parsing failed, unknown unit: " + unit); } } @@ -102,19 +102,17 @@ namespace NzbDrone.Core.Parser // http://www.codeproject.com/Articles/33298/C-Date-Time-Parser public static DateTime FromFuzzyTime(string str, string format = null) { - //var dtFormat = format == "UK" ? - // DateTimeRoutines.DateTimeRoutines.DateTimeFormat.UkDate : - // DateTimeRoutines.DateTimeRoutines.DateTimeFormat.UsaDate; + var dtFormat = format == "UK" ? + DateTimeRoutines.DateTimeFormat.UKDate : + DateTimeRoutines.DateTimeFormat.UKDate; - //if (DateTimeRoutines.DateTimeRoutines.TryParseDateOrTime( - // str, dtFormat, out DateTimeRoutines.DateTimeRoutines.ParsedDateTime dt)) - // return dt.DateTime; - if (DateTime.TryParse(str, out var dateTimeParsed)) + if (DateTimeRoutines.TryParseDateOrTime( + str, dtFormat, out var dt)) { - return dateTimeParsed; + return dt.DateTime; } - throw new Exception($"FromFuzzyTime parsing failed for string {str}"); + throw new InvalidDateException($"FromFuzzyTime parsing failed for string {str}"); } public static DateTime FromUnknown(string str, string format = null) @@ -244,7 +242,7 @@ namespace NzbDrone.Core.Parser } catch (Exception ex) { - throw new Exception($"DateTime parsing failed for \"{str}\": {ex}"); + throw new InvalidDateException($"DateTime parsing failed for \"{str}\": {ex}"); } } @@ -314,7 +312,7 @@ namespace NzbDrone.Core.Parser } catch (FormatException ex) { - throw new FormatException($"Error while parsing DateTime \"{date}\", using layout \"{layout}\" ({pattern}): {ex.Message}"); + throw new InvalidDateException($"Error while parsing DateTime \"{date}\", using layout \"{layout}\" ({pattern}): {ex.Message}"); } } From b05d8c930dddb41ad1ed8efe6bb93c17f216fdb7 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 7 Dec 2021 20:19:05 -0600 Subject: [PATCH 0234/2320] Date Routines Test Cases --- .../ParserTests/DateTimeRoutinesFixture.cs | 54 +++++ src/NzbDrone.Core/Parser/DateTimeRoutines.cs | 204 ++++++++++++++---- src/NzbDrone.Core/Parser/DateTimeUtil.cs | 4 +- 3 files changed, 215 insertions(+), 47 deletions(-) create mode 100644 src/NzbDrone.Core.Test/ParserTests/DateTimeRoutinesFixture.cs diff --git a/src/NzbDrone.Core.Test/ParserTests/DateTimeRoutinesFixture.cs b/src/NzbDrone.Core.Test/ParserTests/DateTimeRoutinesFixture.cs new file mode 100644 index 000000000..7de34424e --- /dev/null +++ b/src/NzbDrone.Core.Test/ParserTests/DateTimeRoutinesFixture.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections; +using NUnit.Framework; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.ParserTests +{ + [TestFixture] + public class DateTimeRoutinesFixture : CoreTest + { + public static IEnumerable DateTimeTestCases + { + get + { + yield return new TestCaseData(@"Member since: 10-Feb-2008").Returns(new DateTime(2008, 2, 10, 0, 0, 0)); + yield return new TestCaseData(@"Last Update: 18:16 11 Feb '08 ").Returns(new DateTime(2008, 2, 11, 18, 16, 0)); + yield return new TestCaseData(@"date Tue, Feb 10, 2008 at 11:06 AM").Returns(new DateTime(2008, 2, 10, 11, 06, 0)); + yield return new TestCaseData(@"see at 12/31/2007 14:16:32").Returns(new DateTime(2007, 12, 31, 14, 16, 32)); + yield return new TestCaseData(@"sack finish 14:16:32 November 15 2008, 1-144 app").Returns(new DateTime(2008, 11, 15, 14, 16, 32)); + yield return new TestCaseData(@"Genesis Message - Wed 04 Feb 08 - 19:40").Returns(new DateTime(2008, 2, 4, 19, 40, 0)); + yield return new TestCaseData(@"The day 07/31/07 14:16:32 is ").Returns(new DateTime(2007, 7, 31, 14, 16, 32)); + yield return new TestCaseData(@"Shipping is on us until December 24, 2008 within the U.S. ").Returns(new DateTime(2008, 12, 24, 0, 0, 0)); + yield return new TestCaseData(@" 2008 within the U.S. at 14:16:32").Returns(new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 14, 16, 32)); + yield return new TestCaseData(@"5th November, 1994, 8:15:30 pm").Returns(new DateTime(1994, 11, 5, 20, 15, 30)); + yield return new TestCaseData(@"7 boxes January 31 , 14:16:32.").Returns(new DateTime(DateTime.Now.Year, 1, 31, 14, 16, 32)); + yield return new TestCaseData(@"the blue sky of Sept 30th 2008 14:16:32").Returns(new DateTime(2008, 9, 30, 14, 16, 32)); + yield return new TestCaseData(@" e.g. 1997-07-16T19:20:30+01:00").Returns(new DateTime(1997, 7, 16, 19, 20, 30)); + yield return new TestCaseData(@"Apr 1st, 2008 14:16:32 tufa 6767").Returns(new DateTime(2008, 4, 1, 14, 16, 32)); + yield return new TestCaseData(@"wait for 07/31/07 14:16:32").Returns(new DateTime(2007, 7, 31, 14, 16, 32)); + yield return new TestCaseData(@"later 12.31.08 and before 1.01.09").Returns(new DateTime(2008, 12, 31, 0, 0, 0)); + yield return new TestCaseData(@"Expires: Sept 30th 2008 14:16:32").Returns(new DateTime(2008, 9, 30, 14, 16, 32)); + yield return new TestCaseData(@"Offer expires Apr 1st, 2007, 14:16:32").Returns(new DateTime(2007, 4, 1, 14, 16, 32)); + yield return new TestCaseData(@"Expires 14:16:32 January 31.").Returns(new DateTime(DateTime.Now.Year, 1, 31, 14, 16, 32)); + yield return new TestCaseData(@"Expires 14:16:32 January 31-st.").Returns(new DateTime(DateTime.Now.Year, 1, 31, 14, 16, 32)); + yield return new TestCaseData(@"Expires 23rd January 2010.").Returns(new DateTime(2010, 1, 23, 0, 0, 0)); + yield return new TestCaseData(@"Expires January 22nd, 2010.").Returns(new DateTime(2010, 1, 22, 0, 0, 0)); + yield return new TestCaseData(@"Expires DEC 22, 2010.").Returns(new DateTime(2010, 12, 22, 0, 0, 0)); + yield return new TestCaseData(@"Version: 1.0.0.692 6/1/2010 2:28:04 AM ").Returns(new DateTime(2010, 6, 1, 2, 28, 4)); + yield return new TestCaseData(@"Version: 1.0.0.692 04/21/11 12:30am ").Returns(new DateTime(2011, 4, 21, 00, 30, 00)); + yield return new TestCaseData(@"Version: 1.0.0.692 04/21/11 12:30pm ").Returns(new DateTime(2011, 4, 21, 12, 30, 00)); + yield return new TestCaseData(@"Version: Thu Aug 06 22:32:15 MDT 2009 ").Returns(new DateTime(2009, 8, 6, 22, 32, 15)); + } + } + + [TestCaseSource("DateTimeTestCases")] + public DateTime should_parse_date(string date) + { + DateTimeRoutines.TryParseDateOrTime(date, DateTimeRoutines.DateTimeFormat.USDate, out var parsedDateTime); + + return parsedDateTime.DateTime; + } + } +} diff --git a/src/NzbDrone.Core/Parser/DateTimeRoutines.cs b/src/NzbDrone.Core/Parser/DateTimeRoutines.cs index 27cdcc17b..0592ed222 100644 --- a/src/NzbDrone.Core/Parser/DateTimeRoutines.cs +++ b/src/NzbDrone.Core/Parser/DateTimeRoutines.cs @@ -21,6 +21,9 @@ namespace NzbDrone.Core.Parser public readonly DateTime DateTime; public readonly bool IsDateFound; public readonly bool IsTimeFound; + public readonly TimeSpan UtcOffset; + public readonly bool IsUtcOffsetFound; + public DateTime UtcDateTime; internal ParsedDateTime(int index_of_date, int length_of_date, int index_of_time, int length_of_time, DateTime date_time) { @@ -31,6 +34,46 @@ namespace NzbDrone.Core.Parser DateTime = date_time; IsDateFound = index_of_date > -1; IsTimeFound = index_of_time > -1; + UtcOffset = new TimeSpan(25, 0, 0); + IsUtcOffsetFound = false; + UtcDateTime = new DateTime(1, 1, 1); + } + + internal ParsedDateTime(int index_of_date, int length_of_date, int index_of_time, int length_of_time, DateTime date_time, TimeSpan utc_offset) + { + IndexOfDate = index_of_date; + LengthOfDate = length_of_date; + IndexOfTime = index_of_time; + LengthOfTime = length_of_time; + DateTime = date_time; + IsDateFound = index_of_date > -1; + IsTimeFound = index_of_time > -1; + UtcOffset = utc_offset; + IsUtcOffsetFound = Math.Abs(utc_offset.TotalHours) < 12; + if (!IsUtcOffsetFound) + { + UtcDateTime = new DateTime(1, 1, 1); + } + else + { + if (index_of_date < 0) + { + //to avoid negative date exception when date is undefined + var ts = date_time.TimeOfDay + utc_offset; + if (ts < new TimeSpan(0)) + { + UtcDateTime = new DateTime(1, 1, 2) + ts; + } + else + { + UtcDateTime = new DateTime(1, 1, 1) + ts; + } + } + else + { + UtcDateTime = date_time + utc_offset; + } + } } } @@ -78,7 +121,7 @@ namespace NzbDrone.Core.Parser } var date_time = new DateTime(DefaultDate.Year, DefaultDate.Month, DefaultDate.Day, parsed_time.DateTime.Hour, parsed_time.DateTime.Minute, parsed_time.DateTime.Second); - parsed_date_time = new ParsedDateTime(-1, -1, parsed_time.IndexOfTime, parsed_time.LengthOfTime, date_time); + parsed_date_time = new ParsedDateTime(-1, -1, parsed_time.IndexOfTime, parsed_time.LengthOfTime, date_time, parsed_time.UtcOffset); } else { @@ -90,7 +133,7 @@ namespace NzbDrone.Core.Parser else { var date_time = new DateTime(parsed_date.DateTime.Year, parsed_date.DateTime.Month, parsed_date.DateTime.Day, parsed_time.DateTime.Hour, parsed_time.DateTime.Minute, parsed_time.DateTime.Second); - parsed_date_time = new ParsedDateTime(parsed_date.IndexOfDate, parsed_date.LengthOfDate, parsed_time.IndexOfTime, parsed_time.LengthOfTime, date_time); + parsed_date_time = new ParsedDateTime(parsed_date.IndexOfDate, parsed_date.LengthOfDate, parsed_time.IndexOfTime, parsed_time.LengthOfTime, date_time, parsed_time.UtcOffset); } } @@ -101,72 +144,137 @@ namespace NzbDrone.Core.Parser { parsed_time = null; + string time_zone_r; + if (default_format == DateTimeFormat.USDate) + { + time_zone_r = @"(?:\s*(?'time_zone'UTC|GMT|CST|EST))?"; + } + else + { + time_zone_r = @"(?:\s*(?'time_zone'UTC|GMT))?"; + } + Match m; if (parsed_date != null && parsed_date.IndexOfDate > -1) { //look around the found date - //look for <date> [h]h:mm[:ss] [PM/AM] - m = Regex.Match(str.Substring(parsed_date.IndexOfDate + parsed_date.LengthOfDate), @"(?<=^\s*,?\s+|^\s*at\s*|^\s*[T\-]\s*)(?'hour'\d{1,2})\s*:\s*(?'minute'\d{2})\s*(?::\s*(?'second'\d{2}))?(?:\s*(?'ampm'AM|am|PM|pm))?(?=$|[^\d\w])", RegexOptions.Compiled); + //look for <date> hh:mm:ss <UTC offset> + m = Regex.Match(str.Substring(parsed_date.IndexOfDate + parsed_date.LengthOfDate), @"(?<=^\s*,?\s+|^\s*at\s*|^\s*[T\-]\s*)(?'hour'\d{2})\s*:\s*(?'minute'\d{2})\s*:\s*(?'second'\d{2})\s+(?'offset_sign'[\+\-])(?'offset_hh'\d{2}):?(?'offset_mm'\d{2})(?=$|[^\d\w])", RegexOptions.Compiled); if (!m.Success) { - //look for [h]h:mm:ss <date> - m = Regex.Match(str.Substring(0, parsed_date.IndexOfDate), @"(?<=^|[^\d])(?'hour'\d{1,2})\s*:\s*(?'minute'\d{2})\s*(?::\s*(?'second'\d{2}))?(?:\s*(?'ampm'AM|am|PM|pm))?(?=$|[\s,]+)", RegexOptions.Compiled); + //look for <date> [h]h:mm[:ss] [PM/AM] [UTC/GMT] + m = Regex.Match(str.Substring(parsed_date.IndexOfDate + parsed_date.LengthOfDate), @"(?<=^\s*,?\s+|^\s*at\s*|^\s*[T\-]\s*)(?'hour'\d{1,2})\s*:\s*(?'minute'\d{2})\s*(?::\s*(?'second'\d{2}))?(?:\s*(?'ampm'AM|am|PM|pm))?" + time_zone_r + @"(?=$|[^\d\w])", RegexOptions.Compiled); + } + + if (!m.Success) + { + //look for [h]h:mm:ss [PM/AM] [UTC/GMT] <date> + m = Regex.Match(str.Substring(0, parsed_date.IndexOfDate), @"(?<=^|[^\d])(?'hour'\d{1,2})\s*:\s*(?'minute'\d{2})\s*(?::\s*(?'second'\d{2}))?(?:\s*(?'ampm'AM|am|PM|pm))?" + time_zone_r + @"(?=$|[\s,]+)", RegexOptions.Compiled); + } + + if (!m.Success) + { + //look for [h]h:mm:ss [PM/AM] [UTC/GMT] within <date> + m = Regex.Match(str.Substring(parsed_date.IndexOfDate, parsed_date.LengthOfDate), @"(?<=^|[^\d])(?'hour'\d{1,2})\s*:\s*(?'minute'\d{2})\s*(?::\s*(?'second'\d{2}))?(?:\s*(?'ampm'AM|am|PM|pm))?" + time_zone_r + @"(?=$|[\s,]+)", RegexOptions.Compiled); } } else { - //look anywere within string - //look for [h]h:mm[:ss] [PM/AM] - m = Regex.Match(str, @"(?<=^|\s+|\s*T\s*)(?'hour'\d{1,2})\s*:\s*(?'minute'\d{2})\s*(?::\s*(?'second'\d{2}))?(?:\s*(?'ampm'AM|am|PM|pm))?(?=$|[^\d\w])", RegexOptions.Compiled); + //look anywhere within string + //look for hh:mm:ss <UTC offset> + m = Regex.Match(str, @"(?<=^|\s+|\s*T\s*)(?'hour'\d{2})\s*:\s*(?'minute'\d{2})\s*:\s*(?'second'\d{2})\s+(?'offset_sign'[\+\-])(?'offset_hh'\d{2}):?(?'offset_mm'\d{2})?(?=$|[^\d\w])", RegexOptions.Compiled); + if (!m.Success) + { + //look for [h]h:mm[:ss] [PM/AM] [UTC/GMT] + m = Regex.Match(str, @"(?<=^|\s+|\s*T\s*)(?'hour'\d{1,2})\s*:\s*(?'minute'\d{2})\s*(?::\s*(?'second'\d{2}))?(?:\s*(?'ampm'AM|am|PM|pm))?" + time_zone_r + @"(?=$|[^\d\w])", RegexOptions.Compiled); + } } - if (m.Success) + if (!m.Success) { - try - { - var hour = int.Parse(m.Groups["hour"].Value); - if (hour < 0 || hour > 23) - { - return false; - } + return false; + } - var minute = int.Parse(m.Groups["minute"].Value); - if (minute < 0 || minute > 59) - { - return false; - } + //try + //{ + var hour = int.Parse(m.Groups["hour"].Value); + if (hour < 0 || hour > 23) + { + return false; + } - var second = 0; - if (!string.IsNullOrEmpty(m.Groups["second"].Value)) - { - second = int.Parse(m.Groups["second"].Value); - if (second < 0 || second > 59) - { - return false; - } - } + var minute = int.Parse(m.Groups["minute"].Value); + if (minute < 0 || minute > 59) + { + return false; + } - if (string.Compare(m.Groups["ampm"].Value, "PM", true) == 0 && hour < 12) - { - hour += 12; - } - else if (string.Compare(m.Groups["ampm"].Value, "AM", true) == 0 && hour == 12) - { - hour -= 12; - } - - var date_time = new DateTime(1, 1, 1, hour, minute, second); - parsed_time = new ParsedDateTime(-1, -1, m.Index, m.Length, date_time); - } - catch + var second = 0; + if (!string.IsNullOrEmpty(m.Groups["second"].Value)) + { + second = int.Parse(m.Groups["second"].Value); + if (second < 0 || second > 59) { return false; } + } + if (string.Compare(m.Groups["ampm"].Value, "PM", true) == 0 && hour < 12) + { + hour += 12; + } + else if (string.Compare(m.Groups["ampm"].Value, "AM", true) == 0 && hour == 12) + { + hour -= 12; + } + + var date_time = new DateTime(1, 1, 1, hour, minute, second); + + if (m.Groups["offset_hh"].Success) + { + var offset_hh = int.Parse(m.Groups["offset_hh"].Value); + var offset_mm = 0; + if (m.Groups["offset_mm"].Success) + { + offset_mm = int.Parse(m.Groups["offset_mm"].Value); + } + + var utc_offset = new TimeSpan(offset_hh, offset_mm, 0); + if (m.Groups["offset_sign"].Value == "-") + { + utc_offset = -utc_offset; + } + + parsed_time = new ParsedDateTime(-1, -1, m.Index, m.Length, date_time, utc_offset); return true; } - return false; + if (m.Groups["time_zone"].Success) + { + TimeSpan utc_offset; + switch (m.Groups["time_zone"].Value) + { + case "UTC": + case "GMT": + utc_offset = new TimeSpan(0, 0, 0); + break; + case "CST": + utc_offset = new TimeSpan(-6, 0, 0); + break; + case "EST": + utc_offset = new TimeSpan(-5, 0, 0); + break; + default: + throw new Exception("Time zone: " + m.Groups["time_zone"].Value + " is not defined."); + } + + parsed_time = new ParsedDateTime(-1, -1, m.Index, m.Length, date_time, utc_offset); + return true; + } + + parsed_time = new ParsedDateTime(-1, -1, m.Index, m.Length, date_time); + + return true; } public static bool TryParseDate(this string str, DateTimeFormat default_format, out ParsedDateTime parsed_date) @@ -230,6 +338,12 @@ namespace NzbDrone.Core.Parser m = Regex.Match(str, @"(?:^|[^\d\w])(?'year'\d{4})\s+(?'month'Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[uarychilestmbro]*\s+(?'day'\d{1,2})(?:-?st|-?th|-?rd|-?nd)?(?=$|[^\d\w])", RegexOptions.Compiled | RegexOptions.IgnoreCase); } + if (!m.Success) + { + //look for month dd hh:mm:ss MDT|UTC yyyy + m = Regex.Match(str, @"(?:^|[^\d\w])(?'month'Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[uarychilestmbro]*\s+(?'day'\d{1,2})\s+\d{2}\:\d{2}\:\d{2}\s+(?:MDT|UTC)\s+(?'year'\d{4})(?=$|[^\d\w])", RegexOptions.Compiled | RegexOptions.IgnoreCase); + } + if (!m.Success) { //look for month dd [yyyy] diff --git a/src/NzbDrone.Core/Parser/DateTimeUtil.cs b/src/NzbDrone.Core/Parser/DateTimeUtil.cs index 2f6596350..3e05f60a7 100644 --- a/src/NzbDrone.Core/Parser/DateTimeUtil.cs +++ b/src/NzbDrone.Core/Parser/DateTimeUtil.cs @@ -104,10 +104,10 @@ namespace NzbDrone.Core.Parser { var dtFormat = format == "UK" ? DateTimeRoutines.DateTimeFormat.UKDate : - DateTimeRoutines.DateTimeFormat.UKDate; + DateTimeRoutines.DateTimeFormat.USDate; if (DateTimeRoutines.TryParseDateOrTime( - str, dtFormat, out var dt)) + str, dtFormat, out DateTimeRoutines.ParsedDateTime dt)) { return dt.DateTime; } From 9e7af8369e165c19a2f181071e63bef6961cd64e Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Tue, 7 Dec 2021 21:33:45 +0000 Subject: [PATCH 0235/2320] Fixed: Support older glibc in libMonoPosixHelper --- src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj | 2 +- src/NzbDrone.Mono/Prowlarr.Mono.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj b/src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj index 3ca751434..a79b0aadc 100644 --- a/src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj +++ b/src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj @@ -3,7 +3,7 @@ <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> - <PackageReference Include="Mono.Posix.NETStandard" Version="5.20.1.34-servarr17" /> + <PackageReference Include="Mono.Posix.NETStandard" Version="5.20.1.34-servarr18" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Common.Test\Prowlarr.Common.Test.csproj" /> diff --git a/src/NzbDrone.Mono/Prowlarr.Mono.csproj b/src/NzbDrone.Mono/Prowlarr.Mono.csproj index 0c7cb60ec..a5038be86 100644 --- a/src/NzbDrone.Mono/Prowlarr.Mono.csproj +++ b/src/NzbDrone.Mono/Prowlarr.Mono.csproj @@ -3,7 +3,7 @@ <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> - <PackageReference Include="Mono.Posix.NETStandard" Version="5.20.1.34-servarr17" /> + <PackageReference Include="Mono.Posix.NETStandard" Version="5.20.1.34-servarr18" /> <PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" /> </ItemGroup> <ItemGroup> From 6ca708f5232b6bb643f3f006123c6e98654f171f Mon Sep 17 00:00:00 2001 From: PearsonFlyer <john@theediguy.com> Date: Wed, 8 Dec 2021 15:26:46 -0500 Subject: [PATCH 0236/2320] Fixed: (HDTorrents) Remove . from searches --- src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs index f206e3a3e..d1764d26d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs @@ -158,7 +158,7 @@ namespace NzbDrone.Core.Indexers.Definitions }; // manually url encode parenthesis to prevent "hacking" detection - searchUrl += queryCollection.GetQueryString().Replace("(", "%28").Replace(")", "%29"); + searchUrl += queryCollection.GetQueryString().Replace("(", "%28").Replace(")", "%29").Replace(".", " "); var request = new IndexerRequest(searchUrl, HttpAccept.Rss); From 69f5963f6f1e80e3f598bdb13792b7413fcc13b1 Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Sun, 14 Nov 2021 21:49:21 +0000 Subject: [PATCH 0237/2320] New: Frontend Placeholders from the Backend --- frontend/src/Components/Form/ProviderFieldFormGroup.js | 3 +++ src/NzbDrone.Core/Annotations/FieldDefinitionAttribute.cs | 1 + src/Prowlarr.Http/ClientSchema/Field.cs | 1 + src/Prowlarr.Http/ClientSchema/SchemaBuilder.cs | 3 ++- 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/src/Components/Form/ProviderFieldFormGroup.js b/frontend/src/Components/Form/ProviderFieldFormGroup.js index 89b54369b..2b32e0e38 100644 --- a/frontend/src/Components/Form/ProviderFieldFormGroup.js +++ b/frontend/src/Components/Form/ProviderFieldFormGroup.js @@ -68,6 +68,7 @@ function ProviderFieldFormGroup(props) { label, helpText, helpLink, + placeholder, value, type, advanced, @@ -100,6 +101,7 @@ function ProviderFieldFormGroup(props) { label={label} helpText={helpText} helpLink={helpLink} + placeholder={placeholder} value={value} values={getSelectValues(selectOptions)} errors={errors} @@ -125,6 +127,7 @@ ProviderFieldFormGroup.propTypes = { label: PropTypes.string, helpText: PropTypes.string, helpLink: PropTypes.string, + placeholder: PropTypes.string, value: PropTypes.any, type: PropTypes.string.isRequired, advanced: PropTypes.bool.isRequired, diff --git a/src/NzbDrone.Core/Annotations/FieldDefinitionAttribute.cs b/src/NzbDrone.Core/Annotations/FieldDefinitionAttribute.cs index e68db5a2c..bb56e1a02 100644 --- a/src/NzbDrone.Core/Annotations/FieldDefinitionAttribute.cs +++ b/src/NzbDrone.Core/Annotations/FieldDefinitionAttribute.cs @@ -23,6 +23,7 @@ namespace NzbDrone.Core.Annotations public string Section { get; set; } public HiddenType Hidden { get; set; } public PrivacyLevel Privacy { get; set; } + public string Placeholder { get; set; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] diff --git a/src/Prowlarr.Http/ClientSchema/Field.cs b/src/Prowlarr.Http/ClientSchema/Field.cs index 61db3cfc2..1e6f58ff4 100644 --- a/src/Prowlarr.Http/ClientSchema/Field.cs +++ b/src/Prowlarr.Http/ClientSchema/Field.cs @@ -19,6 +19,7 @@ namespace Prowlarr.Http.ClientSchema public string SelectOptionsProviderAction { get; set; } public string Section { get; set; } public string Hidden { get; set; } + public string Placeholder { get; set; } public Field Clone() { diff --git a/src/Prowlarr.Http/ClientSchema/SchemaBuilder.cs b/src/Prowlarr.Http/ClientSchema/SchemaBuilder.cs index 0874ec7d6..f370d7762 100644 --- a/src/Prowlarr.Http/ClientSchema/SchemaBuilder.cs +++ b/src/Prowlarr.Http/ClientSchema/SchemaBuilder.cs @@ -101,7 +101,8 @@ namespace Prowlarr.Http.ClientSchema Order = fieldAttribute.Order, Advanced = fieldAttribute.Advanced, Type = fieldAttribute.Type.ToString().FirstCharToLower(), - Section = fieldAttribute.Section + Section = fieldAttribute.Section, + Placeholder = fieldAttribute.Placeholder }; if (fieldAttribute.Type == FieldType.Select || fieldAttribute.Type == FieldType.TagSelect) From 0e6ec58a83130cc4056b1797b29e13bc4c9d4ddf Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Sun, 14 Nov 2021 21:49:49 +0000 Subject: [PATCH 0238/2320] New: Placeholders in notification fields --- .../Notifications/Email/EmailSettings.cs | 12 +++++------- .../Notifications/PushBullet/PushBulletSettings.cs | 4 ++-- .../Notifications/Pushover/PushoverSettings.cs | 5 +++-- .../Notifications/SendGrid/SendGridSettings.cs | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/NzbDrone.Core/Notifications/Email/EmailSettings.cs b/src/NzbDrone.Core/Notifications/Email/EmailSettings.cs index acd42e99a..3601f3e01 100644 --- a/src/NzbDrone.Core/Notifications/Email/EmailSettings.cs +++ b/src/NzbDrone.Core/Notifications/Email/EmailSettings.cs @@ -32,15 +32,13 @@ namespace NzbDrone.Core.Notifications.Email public EmailSettings() { - Server = "smtp.gmail.com"; Port = 587; - To = Array.Empty<string>(); CC = Array.Empty<string>(); Bcc = Array.Empty<string>(); } - [FieldDefinition(0, Label = "Server", HelpText = "Hostname or IP of Email server")] + [FieldDefinition(0, Label = "Server", HelpText = "Hostname or IP of Email server", Placeholder = "smtp.gmail.com")] public string Server { get; set; } [FieldDefinition(1, Label = "Port")] @@ -55,16 +53,16 @@ namespace NzbDrone.Core.Notifications.Email [FieldDefinition(4, Label = "Password", HelpText = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] public string Password { get; set; } - [FieldDefinition(5, Label = "From Address")] + [FieldDefinition(5, Label = "From Address", Placeholder = "example@email.com")] public string From { get; set; } - [FieldDefinition(6, Label = "Recipient Address(es)", HelpText = "Comma separated list of email recipients")] + [FieldDefinition(6, Label = "Recipient Address(es)", HelpText = "Comma separated list of email recipients", Placeholder = "example@email.com,example1@email.com")] public IEnumerable<string> To { get; set; } - [FieldDefinition(7, Label = "CC Address(es)", HelpText = "Comma separated list of email cc recipients", Advanced = true)] + [FieldDefinition(7, Label = "CC Address(es)", HelpText = "Comma separated list of email cc recipients", Placeholder = "example@email.com,example1@email.com", Advanced = true)] public IEnumerable<string> CC { get; set; } - [FieldDefinition(8, Label = "BCC Address(es)", HelpText = "Comma separated list of email bcc recipients", Advanced = true)] + [FieldDefinition(8, Label = "BCC Address(es)", HelpText = "Comma separated list of email bcc recipients", Placeholder = "example@email.com,example1@email.com", Advanced = true)] public IEnumerable<string> Bcc { get; set; } public NzbDroneValidationResult Validate() diff --git a/src/NzbDrone.Core/Notifications/PushBullet/PushBulletSettings.cs b/src/NzbDrone.Core/Notifications/PushBullet/PushBulletSettings.cs index d4e9d0661..93ec03a38 100644 --- a/src/NzbDrone.Core/Notifications/PushBullet/PushBulletSettings.cs +++ b/src/NzbDrone.Core/Notifications/PushBullet/PushBulletSettings.cs @@ -28,10 +28,10 @@ namespace NzbDrone.Core.Notifications.PushBullet [FieldDefinition(0, Label = "Access Token", Privacy = PrivacyLevel.ApiKey, HelpLink = "https://www.pushbullet.com/#settings/account")] public string ApiKey { get; set; } - [FieldDefinition(1, Label = "Device IDs", HelpText = "List of device IDs (leave blank to send to all devices)", Type = FieldType.Device)] + [FieldDefinition(1, Label = "Device IDs", HelpText = "List of device IDs (leave blank to send to all devices)", Type = FieldType.Device, Placeholder = "123456789,987654321")] public IEnumerable<string> DeviceIds { get; set; } - [FieldDefinition(2, Label = "Channel Tags", HelpText = "List of Channel Tags to send notifications to", Type = FieldType.Tag)] + [FieldDefinition(2, Label = "Channel Tags", HelpText = "List of Channel Tags to send notifications to", Type = FieldType.Tag, Placeholder = "Channel1234,Channel4321")] public IEnumerable<string> ChannelTags { get; set; } [FieldDefinition(3, Label = "Sender ID", HelpText = "The device ID to send notifications from, use device_iden in the device's URL on pushbullet.com (leave blank to send from yourself)")] diff --git a/src/NzbDrone.Core/Notifications/Pushover/PushoverSettings.cs b/src/NzbDrone.Core/Notifications/Pushover/PushoverSettings.cs index dcfa5bcfd..3d573be78 100644 --- a/src/NzbDrone.Core/Notifications/Pushover/PushoverSettings.cs +++ b/src/NzbDrone.Core/Notifications/Pushover/PushoverSettings.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using FluentValidation; using NzbDrone.Core.Annotations; @@ -23,7 +24,7 @@ namespace NzbDrone.Core.Notifications.Pushover public PushoverSettings() { Priority = 0; - Devices = System.Array.Empty<string>(); + Devices = Array.Empty<string>(); } //TODO: Get Pushover to change our app name (or create a new app) when we have a new logo @@ -33,7 +34,7 @@ namespace NzbDrone.Core.Notifications.Pushover [FieldDefinition(1, Label = "User Key", Privacy = PrivacyLevel.UserName, HelpLink = "https://pushover.net/")] public string UserKey { get; set; } - [FieldDefinition(2, Label = "Devices", HelpText = "List of device names (leave blank to send to all devices)", Type = FieldType.Tag)] + [FieldDefinition(2, Label = "Devices", HelpText = "List of device names (leave blank to send to all devices)", Type = FieldType.Tag, Placeholder = "device1")] public IEnumerable<string> Devices { get; set; } [FieldDefinition(3, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(PushoverPriority))] diff --git a/src/NzbDrone.Core/Notifications/SendGrid/SendGridSettings.cs b/src/NzbDrone.Core/Notifications/SendGrid/SendGridSettings.cs index 63f30d4ec..fa9ef39ae 100644 --- a/src/NzbDrone.Core/Notifications/SendGrid/SendGridSettings.cs +++ b/src/NzbDrone.Core/Notifications/SendGrid/SendGridSettings.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Core.Notifications.SendGrid [FieldDefinition(2, Label = "From Address")] public string From { get; set; } - [FieldDefinition(3, Label = "Recipient Address(es)", Type = FieldType.Tag)] + [FieldDefinition(3, Label = "Recipient Address(es)", Type = FieldType.Tag, Placeholder = "example@email.com,example1@email.com")] public IEnumerable<string> Recipients { get; set; } public NzbDroneValidationResult Validate() From 32fd0911a288d8c8da1dc5342bafa8dbaa342057 Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Tue, 7 Dec 2021 11:01:02 +0000 Subject: [PATCH 0239/2320] New: Application Placeholders instead of default values --- .../Applications/LazyLibrarian/LazyLibrarianSettings.cs | 6 ++---- src/NzbDrone.Core/Applications/Lidarr/LidarrSettings.cs | 6 ++---- src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs | 6 ++---- src/NzbDrone.Core/Applications/Radarr/RadarrSettings.cs | 6 ++---- src/NzbDrone.Core/Applications/Readarr/ReadarrSettings.cs | 6 ++---- src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs | 6 ++---- 6 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianSettings.cs b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianSettings.cs index e6c8df3dd..94b0e2ca1 100644 --- a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianSettings.cs +++ b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianSettings.cs @@ -23,8 +23,6 @@ namespace NzbDrone.Core.Applications.LazyLibrarian public LazyLibrarianSettings() { - ProwlarrUrl = "http://localhost:9696"; - BaseUrl = "http://localhost:5299"; SyncCategories = new[] { NewznabStandardCategory.AudioAudiobook.Id, @@ -38,10 +36,10 @@ namespace NzbDrone.Core.Applications.LazyLibrarian }; } - [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as LazyLibrarian sees it, including http(s)://, port, and urlbase if needed")] + [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as LazyLibrarian sees it, including http(s)://, port, and urlbase if needed", Placeholder = "http://localhost:9696")] public string ProwlarrUrl { get; set; } - [FieldDefinition(1, Label = "LazyLibrarian Server", HelpText = "URL used to connect to LazyLibrarian server, including http(s)://, port, and urlbase if required")] + [FieldDefinition(1, Label = "LazyLibrarian Server", HelpText = "URL used to connect to LazyLibrarian server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:5299")] public string BaseUrl { get; set; } [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by LazyLibrarian in Settings/Web Interface")] diff --git a/src/NzbDrone.Core/Applications/Lidarr/LidarrSettings.cs b/src/NzbDrone.Core/Applications/Lidarr/LidarrSettings.cs index fe9ab208e..5d66671a7 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/LidarrSettings.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/LidarrSettings.cs @@ -22,15 +22,13 @@ namespace NzbDrone.Core.Applications.Lidarr public LidarrSettings() { - ProwlarrUrl = "http://localhost:9696"; - BaseUrl = "http://localhost:8686"; SyncCategories = new[] { 3000, 3010, 3030, 3040, 3050, 3060 }; } - [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Lidarr sees it, including http(s)://, port, and urlbase if needed")] + [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Lidarr sees it, including http(s)://, port, and urlbase if needed", Placeholder = "http://localhost:9696")] public string ProwlarrUrl { get; set; } - [FieldDefinition(1, Label = "Lidarr Server", HelpText = "URL used to connect to Lidarr server, including http(s)://, port, and urlbase if required")] + [FieldDefinition(1, Label = "Lidarr Server", HelpText = "URL used to connect to Lidarr server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:8686")] public string BaseUrl { get; set; } [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Lidarr in Settings/General")] diff --git a/src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs b/src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs index 50869c77f..2f3380bbc 100644 --- a/src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs +++ b/src/NzbDrone.Core/Applications/Mylar/MylarSettings.cs @@ -23,15 +23,13 @@ namespace NzbDrone.Core.Applications.Mylar public MylarSettings() { - ProwlarrUrl = "http://localhost:9696"; - BaseUrl = "http://localhost:8090"; SyncCategories = new[] { NewznabStandardCategory.BooksComics.Id }; } - [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Mylar sees it, including http(s)://, port, and urlbase if needed")] + [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Mylar sees it, including http(s)://, port, and urlbase if needed", Placeholder = "http://localhost:9696")] public string ProwlarrUrl { get; set; } - [FieldDefinition(1, Label = "Mylar Server", HelpText = "URL used to connect to Mylar server, including http(s)://, port, and urlbase if required")] + [FieldDefinition(1, Label = "Mylar Server", HelpText = "URL used to connect to Mylar server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:8090")] public string BaseUrl { get; set; } [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Mylar in Settings/Web Interface")] diff --git a/src/NzbDrone.Core/Applications/Radarr/RadarrSettings.cs b/src/NzbDrone.Core/Applications/Radarr/RadarrSettings.cs index 4bfa4709c..bb744e511 100644 --- a/src/NzbDrone.Core/Applications/Radarr/RadarrSettings.cs +++ b/src/NzbDrone.Core/Applications/Radarr/RadarrSettings.cs @@ -23,15 +23,13 @@ namespace NzbDrone.Core.Applications.Radarr public RadarrSettings() { - ProwlarrUrl = "http://localhost:9696"; - BaseUrl = "http://localhost:7878"; SyncCategories = new[] { 2000, 2010, 2020, 2030, 2040, 2045, 2050, 2060, 2070, 2080 }; } - [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Radarr sees it, including http(s)://, port, and urlbase if needed")] + [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Radarr sees it, including http(s)://, port, and urlbase if needed", Placeholder = "http://localhost:9696")] public string ProwlarrUrl { get; set; } - [FieldDefinition(1, Label = "Radarr Server", HelpText = "URL used to connect to Radarr server, including http(s)://, port, and urlbase if required")] + [FieldDefinition(1, Label = "Radarr Server", HelpText = "URL used to connect to Radarr server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:7878")] public string BaseUrl { get; set; } [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Radarr in Settings/General")] diff --git a/src/NzbDrone.Core/Applications/Readarr/ReadarrSettings.cs b/src/NzbDrone.Core/Applications/Readarr/ReadarrSettings.cs index 0554e78cb..f88203af0 100644 --- a/src/NzbDrone.Core/Applications/Readarr/ReadarrSettings.cs +++ b/src/NzbDrone.Core/Applications/Readarr/ReadarrSettings.cs @@ -23,15 +23,13 @@ namespace NzbDrone.Core.Applications.Readarr public ReadarrSettings() { - ProwlarrUrl = "http://localhost:9696"; - BaseUrl = "http://localhost:8787"; SyncCategories = new[] { 3030, 7000, 7010, 7020, 7030, 7040, 7050, 7060 }; } - [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Readarr sees it, including http(s)://, port, and urlbase if needed")] + [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Readarr sees it, including http(s)://, port, and urlbase if needed", Placeholder = "http://localhost:9696")] public string ProwlarrUrl { get; set; } - [FieldDefinition(1, Label = "Readarr Server", HelpText = "URL used to connect to Readarr server, including http(s)://, port, and urlbase if required")] + [FieldDefinition(1, Label = "Readarr Server", HelpText = "URL used to connect to Readarr server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:8787")] public string BaseUrl { get; set; } [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Readarr in Settings/General")] diff --git a/src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs b/src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs index 9d15b1a5c..0acbafd3e 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/SonarrSettings.cs @@ -22,16 +22,14 @@ namespace NzbDrone.Core.Applications.Sonarr public SonarrSettings() { - ProwlarrUrl = "http://localhost:9696"; - BaseUrl = "http://localhost:8989"; SyncCategories = new[] { 5000, 5010, 5020, 5030, 5040, 5045, 5050 }; AnimeSyncCategories = new[] { 5070 }; } - [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Sonarr sees it, including http(s)://, port, and urlbase if needed")] + [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Sonarr sees it, including http(s)://, port, and urlbase if needed", Placeholder = "http://localhost:9696")] public string ProwlarrUrl { get; set; } - [FieldDefinition(1, Label = "Sonarr Server", HelpText = "URL used to connect to Sonarr server, including http(s)://, port, and urlbase if required")] + [FieldDefinition(1, Label = "Sonarr Server", HelpText = "URL used to connect to Sonarr server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:8989")] public string BaseUrl { get; set; } [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Sonarr in Settings/General")] From dd27d69e97b2db6694a3e8ba696c2ef7d0bfd566 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Thu, 9 Dec 2021 11:46:32 -0600 Subject: [PATCH 0240/2320] fix erroneous logging for windows service on non-windows --- src/NzbDrone.Host/Bootstrap.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index beb73f276..a8edd0f95 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -171,8 +171,6 @@ namespace NzbDrone.Host return ApplicationModes.UninstallService; } - Logger.Debug("Getting windows service status"); - // IsWindowsService can throw sometimes, so wrap it var isWindowsService = false; try From 147cdf2cce49c8e2924d115fb8efdc6fa6f7afbd Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Mon, 1 Nov 2021 21:28:20 +0000 Subject: [PATCH 0241/2320] Fixed: Forms login persists across restarts in docker (cherry picked from commit a219b4a1b869863b2ef47d4bdf33d308cb261ba3) Fixes #409 --- src/NzbDrone.Common/Extensions/PathExtensions.cs | 5 +++++ src/NzbDrone.Host/Bootstrap.cs | 4 ++++ src/NzbDrone.Host/Startup.cs | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/src/NzbDrone.Common/Extensions/PathExtensions.cs b/src/NzbDrone.Common/Extensions/PathExtensions.cs index 80a54ac7d..0633b391f 100644 --- a/src/NzbDrone.Common/Extensions/PathExtensions.cs +++ b/src/NzbDrone.Common/Extensions/PathExtensions.cs @@ -258,6 +258,11 @@ namespace NzbDrone.Common.Extensions return appFolderInfo.AppDataFolder; } + public static string GetDataProtectionPath(this IAppFolderInfo appFolderInfo) + { + return Path.Combine(GetAppDataPath(appFolderInfo), "asp"); + } + public static string GetLogFolder(this IAppFolderInfo appFolderInfo) { return Path.Combine(GetAppDataPath(appFolderInfo), "logs"); diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index a8edd0f95..27c129fb7 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -8,8 +8,10 @@ using System.Security.Cryptography.X509Certificates; using System.Text; using DryIoc; using DryIoc.Microsoft.DependencyInjection; +using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting.WindowsServices; using NLog; @@ -129,6 +131,7 @@ namespace NzbDrone.Host }) .ConfigureWebHost(builder => { + builder.UseConfiguration(config); builder.UseUrls(urls.ToArray()); builder.UseKestrel(options => { @@ -195,6 +198,7 @@ namespace NzbDrone.Host var appFolder = new AppFolderInfo(context); return new ConfigurationBuilder() .AddXmlFile(appFolder.GetConfigPath(), optional: true, reloadOnChange: false) + .AddInMemoryCollection(new List<KeyValuePair<string, string>> { new ("dataProtectionFolder", appFolder.GetDataProtectionPath()) }) .Build(); } diff --git a/src/NzbDrone.Host/Startup.cs b/src/NzbDrone.Host/Startup.cs index 722a0ef30..8a63849ac 100644 --- a/src/NzbDrone.Host/Startup.cs +++ b/src/NzbDrone.Host/Startup.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.IO; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.Configuration; @@ -45,6 +47,7 @@ namespace NzbDrone.Host b.SetMinimumLevel(LogLevel.Trace); b.AddFilter("Microsoft.AspNetCore", LogLevel.Warning); b.AddFilter("Prowlarr.Http.Authentication", LogLevel.Information); + b.AddFilter("Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager", LogLevel.Error); b.AddNLog(); }); @@ -94,6 +97,9 @@ namespace NzbDrone.Host options.PayloadSerializerOptions = STJson.GetSerializerSettings(); }); + services.AddDataProtection() + .PersistKeysToFileSystem(new DirectoryInfo(Configuration["dataProtectionFolder"])); + services.AddSingleton<IAuthorizationPolicyProvider, UiAuthorizationPolicyProvider>(); services.AddAuthorization(options => { From 62d15536dfe0933cee1d057b5bd2abe8d6a9bba4 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 11 Dec 2021 13:38:25 -0600 Subject: [PATCH 0242/2320] Fixed: NullRef in SchemaBuilder when sending payload without optional Provider.Settings fields --- src/Prowlarr.Http/ClientSchema/SchemaBuilder.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Prowlarr.Http/ClientSchema/SchemaBuilder.cs b/src/Prowlarr.Http/ClientSchema/SchemaBuilder.cs index f370d7762..e955d35b1 100644 --- a/src/Prowlarr.Http/ClientSchema/SchemaBuilder.cs +++ b/src/Prowlarr.Http/ClientSchema/SchemaBuilder.cs @@ -47,7 +47,10 @@ namespace Prowlarr.Http.ClientSchema var propertyType = mapping.PropertyType; var field = fields.Find(f => f.Name == mapping.Field.Name); - mapping.SetterFunc(target, field.Value); + if (field != null) + { + mapping.SetterFunc(target, field.Value); + } } return target; From 383d5464b7bc6a4b64ee8352e2374a60dd2dbc23 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 11 Dec 2021 15:51:45 -0600 Subject: [PATCH 0243/2320] New: (FlareSolverr Proxy) Configurable Request Timeout Closes #696 --- .../IndexerProxies/FlareSolverr/FlareSolverr.cs | 2 +- .../IndexerProxies/FlareSolverr/FlareSolverrSettings.cs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index 3215c0a39..47c4c0634 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -113,7 +113,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr var url = request.Url.ToString(); var userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"; - var maxTimeout = 60000; + var maxTimeout = Settings.RequestTimeout * 1000; if (request.Method == HttpMethod.GET) { diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverrSettings.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverrSettings.cs index 0af09fc82..9ea860ba3 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverrSettings.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverrSettings.cs @@ -1,4 +1,5 @@ using FluentValidation; +using NLog.Config; using NzbDrone.Core.Annotations; using NzbDrone.Core.Validation; @@ -9,6 +10,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr public FlareSolverrSettingsValidator() { RuleFor(c => c.Host).NotEmpty(); + RuleFor(c => c.RequestTimeout).InclusiveBetween(1, 180); } } @@ -19,11 +21,15 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr public FlareSolverrSettings() { Host = "http://localhost:8191/"; + RequestTimeout = 60; } [FieldDefinition(0, Label = "Host")] public string Host { get; set; } + [FieldDefinition(2, Label = "Request Timeout", Advanced = true, HelpText = "FlareSolverr maxTimeout Request Parameter", Unit = "seconds")] + public int RequestTimeout { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); From d0d1f4012802426f0d9d30d474ccbdc9c245942f Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 12 Dec 2021 17:19:34 -0600 Subject: [PATCH 0244/2320] Fixed: (Anilibria) Duplicate entries Mark C# Anilibria as obsolete --- src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs b/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs index eaa0487a0..a76e15f48 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs @@ -17,6 +17,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete("Moved to YML for Cardigann v3")] public class Anilibria : TorrentIndexerBase<AnilibriaSettings> { public override string Name => "Anilibria"; From 06d9c157d894ad4b3808461c004cf728f90bdc13 Mon Sep 17 00:00:00 2001 From: Davo1624 <85573606+Davo1624@users.noreply.github.com> Date: Wed, 15 Dec 2021 17:27:50 -0500 Subject: [PATCH 0245/2320] Fixed: (Orpheus) Map Categories Comedy & E-Learning Videos to 'Other' indexer does not actually have movies and tv --- src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs index 2e1b96df5..f09a81a50 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs @@ -45,8 +45,8 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.PC, "Applications"); caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Books, "E-Books"); caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.AudioAudiobook, "Audiobooks"); - caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Movies, "E-Learning Videos"); - caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.TV, "Comedy"); + caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Other, "E-Learning Videos"); + caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.Other, "Comedy"); caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.Books, "Comics"); return caps; From 3610becc64bd1d14be208402824905110822b9eb Mon Sep 17 00:00:00 2001 From: Davo1624 <85573606+Davo1624@users.noreply.github.com> Date: Wed, 15 Dec 2021 17:30:26 -0500 Subject: [PATCH 0246/2320] Fixed: (Orpheus) Drop Caps Support for Movie & TV Search Drop TV and Movie search as no Movie/TV categories (#713) e-learning results are how to play guitar videos, etc comedy are comedy/standup recordings --- src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs index f09a81a50..cd7286542 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs @@ -23,14 +23,6 @@ namespace NzbDrone.Core.Indexers.Definitions { var caps = new IndexerCapabilities { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q - }, MusicSearchParams = new List<MusicSearchParam> { MusicSearchParam.Q, MusicSearchParam.Album, MusicSearchParam.Artist, MusicSearchParam.Label, MusicSearchParam.Year From 46401ee187a46baf27fdc73313a4e4862aa1bafe Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 13 Dec 2021 11:30:13 -0600 Subject: [PATCH 0247/2320] Fixed: (BB) Remove '.' from Search String based on jackett fbb1f15d7014b2d8c23c6ee94c2bcf37612066db --- src/NzbDrone.Core/Indexers/Definitions/BB.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BB.cs b/src/NzbDrone.Core/Indexers/Definitions/BB.cs index 4950814a6..4c44c5b6c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BB.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BB.cs @@ -178,7 +178,7 @@ namespace NzbDrone.Core.Indexers.Definitions { "searchtags", "" }, { "tags_type", "0" }, { "action", "basic" }, - { "searchstr", term } + { "searchstr", term.Replace(".", " ") } }; var catList = Capabilities.Categories.MapTorznabCapsToTrackers(categories); From 80c31e8660c805d106f184eabd088f971bc9526a Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 11 Dec 2021 22:38:40 -0600 Subject: [PATCH 0248/2320] fixup add rationale for Obsolete of C# Indexer Implementations --- src/NzbDrone.Core/Indexers/Definitions/Aither.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Milkie.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/YTS.cs | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Aither.cs b/src/NzbDrone.Core/Indexers/Definitions/Aither.cs index a3324507a..c84b177dd 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Aither.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Aither.cs @@ -8,7 +8,7 @@ using NzbDrone.Core.Messaging.Events; namespace NzbDrone.Core.Indexers.Definitions { - [Obsolete] + [Obsolete("Moved to YML for Cardigann v3")] public class Aither : Unit3dBase { public override string Name => "Aither"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs index 709a4b118..cd747a5dd 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs @@ -8,7 +8,7 @@ using NzbDrone.Core.Messaging.Events; namespace NzbDrone.Core.Indexers.Definitions { - [Obsolete] + [Obsolete("Moved to YML for Cardigann v3")] public class AnimeWorld : Unit3dBase { public override string Name => "AnimeWorld"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs b/src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs index c46c8e97d..e854ed96b 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs @@ -8,7 +8,7 @@ using NzbDrone.Core.Messaging.Events; namespace NzbDrone.Core.Indexers.Definitions { - [Obsolete] + [Obsolete("Moved to YML for Cardigann v3")] public class Blutopia : Unit3dBase { public override string Name => "Blutopia"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs index ed906e6dc..571d3e904 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs @@ -9,7 +9,7 @@ using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers.Definitions { - [Obsolete] + [Obsolete("Moved to YML for Cardigann v3")] public class DesiTorrents : Unit3dBase { public override string Name => "DesiTorrents"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs b/src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs index 12a26587a..e14dce86e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs @@ -20,7 +20,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - [Obsolete] + [Obsolete("Moved to YML for Cardigann v3")] public class DigitalCore : TorrentIndexerBase<DigitalCoreSettings> { public override string Name => "DigitalCore"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs b/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs index b5385f479..f59b52f35 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs @@ -17,7 +17,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - [Obsolete] + [Obsolete("Moved to YML for Cardigann v3")] public class InternetArchive : TorrentIndexerBase<InternetArchiveSettings> { public override string Name => "Internet Archive"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Milkie.cs b/src/NzbDrone.Core/Indexers/Definitions/Milkie.cs index d1baf4cc8..89cbf2bad 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Milkie.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Milkie.cs @@ -15,7 +15,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - [Obsolete] + [Obsolete("Moved to YML for Cardigann v3")] public class Milkie : TorrentIndexerBase<MilkieSettings> { public override string Name => "Milkie"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs b/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs index 9fbeae9fb..1a289e8b6 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs @@ -8,7 +8,7 @@ using NzbDrone.Core.Messaging.Events; namespace NzbDrone.Core.Indexers.Definitions { - [Obsolete] + [Obsolete("Moved to YML for Cardigann v3")] public class ShareIsland : Unit3dBase { public override string Name => "ShareIsland"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs b/src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs index 1ae39db67..46fc865a1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs @@ -18,7 +18,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - [Obsolete] + [Obsolete("Moved to YML for Cardigann v3")] public class SuperBits : TorrentIndexerBase<SuperBitsSettings> { public override string Name => "SuperBits"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs b/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs index c88fb943c..7f937a98a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs @@ -16,7 +16,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - [Obsolete] + [Obsolete("Moved to YML for Cardigann v3")] public class ThePirateBay : TorrentIndexerBase<ThePirateBaySettings> { public override string Name => "ThePirateBay"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs index b4e256c5e..3e4867382 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs @@ -20,7 +20,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - [Obsolete] + [Obsolete("Moved to YML for Cardigann v3")] public class TorrentLeech : TorrentIndexerBase<TorrentLeechSettings> { public override string Name => "TorrentLeech"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs index 7546ac313..00a052014 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs @@ -18,7 +18,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - [Obsolete] + [Obsolete("Moved to YML for Cardigann v3")] public class TorrentParadiseMl : TorrentIndexerBase<TorrentParadiseMlSettings> { public override string Name => "TorrentParadiseMl"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/YTS.cs b/src/NzbDrone.Core/Indexers/Definitions/YTS.cs index 530c976e1..73c00416a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/YTS.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/YTS.cs @@ -18,7 +18,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - [Obsolete] + [Obsolete("Moved to YML for Cardigann v3")] public class YTS : TorrentIndexerBase<YTSSettings> { public override string Name => "YTS"; From 5e3322c5382b0349d70fb27189a6b326e01eb6cd Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 22 Dec 2021 17:38:42 -0600 Subject: [PATCH 0249/2320] New: OnApplicationUpdate Notifications (based on Radarr Commits 9e175e28efcfc6ac3e414649b955a10fb0e951e7 4f5f9ff77ee4de05ba04cc677eb7baf4df726af5 4ebcbc28aa3e3268ecc37c5fc2b5565da8f13305 ) Fixes #723 Co-authored-by: Qstick <qstick@gmail.com> --- .../Notifications/Notification.js | 35 +++++--- .../Notifications/NotificationEventItems.js | 15 +++- .../Store/Actions/Settings/notifications.js | 1 + .../NotificationBaseFixture.cs | 90 +++++++++++++++++++ .../014_add_on_update_to_notifications.cs | 14 +++ src/NzbDrone.Core/Datastore/TableMapping.cs | 3 +- src/NzbDrone.Core/Localization/Core/en.json | 3 + .../Notifications/ApplicationUpdateMessage.cs | 16 ++++ .../Notifications/Boxcar/Boxcar.cs | 5 ++ .../CustomScript/CustomScript.cs | 12 +++ .../Notifications/Discord/Discord.cs | 35 ++++++++ .../Notifications/Email/Email.cs | 7 ++ .../Notifications/Gotify/Gotify.cs | 5 ++ .../Notifications/INotification.cs | 2 + src/NzbDrone.Core/Notifications/Join/Join.cs | 5 ++ .../Notifications/Notifiarr/Notifiarr.cs | 12 +++ .../Notifications/NotificationBase.cs | 7 ++ .../Notifications/NotificationDefinition.cs | 4 +- .../Notifications/NotificationFactory.cs | 7 ++ .../Notifications/NotificationService.cs | 24 ++++- .../Notifications/Prowl/Prowl.cs | 5 ++ .../Notifications/PushBullet/PushBullet.cs | 5 ++ .../Notifications/Pushover/Pushover.cs | 5 ++ .../Notifications/SendGrid/SendGrid.cs | 5 ++ .../Notifications/Slack/Slack.cs | 17 ++++ .../Notifications/Telegram/Telegram.cs | 5 ++ .../Notifications/Twitter/Twitter.cs | 5 ++ .../Notifications/Webhook/Webhook.cs | 27 ++++-- .../WebhookApplicationUpdatePayload.cs | 11 +++ .../Notifications/Webhook/WebhookEventType.cs | 3 +- .../Notifications/NotificationResource.cs | 6 ++ 31 files changed, 373 insertions(+), 23 deletions(-) create mode 100644 src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs create mode 100644 src/NzbDrone.Core/Datastore/Migration/014_add_on_update_to_notifications.cs create mode 100644 src/NzbDrone.Core/Notifications/ApplicationUpdateMessage.cs create mode 100644 src/NzbDrone.Core/Notifications/Webhook/WebhookApplicationUpdatePayload.cs diff --git a/frontend/src/Settings/Notifications/Notifications/Notification.js b/frontend/src/Settings/Notifications/Notifications/Notification.js index e356024c4..e4a2847d9 100644 --- a/frontend/src/Settings/Notifications/Notifications/Notification.js +++ b/frontend/src/Settings/Notifications/Notifications/Notification.js @@ -40,7 +40,7 @@ class Notification extends Component { }); }; - onDeleteNotificationModalClose= () => { + onDeleteNotificationModalClose = () => { this.setState({ isDeleteNotificationModalOpen: false }); }; @@ -61,12 +61,14 @@ class Notification extends Component { onRename, onDelete, onHealthIssue, + onApplicationUpdate, supportsOnGrab, supportsOnDownload, supportsOnUpgrade, supportsOnRename, supportsOnDelete, - supportsOnHealthIssue + supportsOnHealthIssue, + supportsOnApplicationUpdate } = this.props; return ( @@ -82,53 +84,62 @@ class Notification extends Component { { supportsOnGrab && onGrab && <Label kind={kinds.SUCCESS}> - On Grab + {translate('OnGrab')} </Label> } { supportsOnDelete && onDelete && <Label kind={kinds.SUCCESS}> - On Delete + {translate('OnDelete')} </Label> } { supportsOnDownload && onDownload && <Label kind={kinds.SUCCESS}> - On Import + {translate('OnImport')} </Label> } { supportsOnUpgrade && onDownload && onUpgrade && <Label kind={kinds.SUCCESS}> - On Upgrade + {translate('OnUpgrade')} </Label> } { supportsOnRename && onRename && <Label kind={kinds.SUCCESS}> - On Rename + {translate('OnRename')} </Label> } { supportsOnHealthIssue && onHealthIssue && <Label kind={kinds.SUCCESS}> - On Health Issue + {translate('OnHealthIssue')} </Label> } { - !onGrab && !onDownload && !onRename && !onHealthIssue && !onDelete && + supportsOnApplicationUpdate && onApplicationUpdate ? + <Label kind={kinds.SUCCESS}> + {translate('OnApplicationUpdate')} + </Label> : + null + } + + { + !onGrab && !onDownload && !onRename && !onHealthIssue && !onDelete && !onApplicationUpdate ? <Label kind={kinds.DISABLED} outline={true} > - Disabled - </Label> + {translate('Disabled')} + </Label> : + null } <EditNotificationModalConnector @@ -161,12 +172,14 @@ Notification.propTypes = { onRename: PropTypes.bool.isRequired, onDelete: PropTypes.bool.isRequired, onHealthIssue: PropTypes.bool.isRequired, + onApplicationUpdate: PropTypes.bool.isRequired, supportsOnGrab: PropTypes.bool.isRequired, supportsOnDownload: PropTypes.bool.isRequired, supportsOnDelete: PropTypes.bool.isRequired, supportsOnUpgrade: PropTypes.bool.isRequired, supportsOnRename: PropTypes.bool.isRequired, supportsOnHealthIssue: PropTypes.bool.isRequired, + supportsOnApplicationUpdate: PropTypes.bool.isRequired, onConfirmDeleteNotification: PropTypes.func.isRequired }; diff --git a/frontend/src/Settings/Notifications/Notifications/NotificationEventItems.js b/frontend/src/Settings/Notifications/Notifications/NotificationEventItems.js index 1b4711fca..711fd8fbb 100644 --- a/frontend/src/Settings/Notifications/Notifications/NotificationEventItems.js +++ b/frontend/src/Settings/Notifications/Notifications/NotificationEventItems.js @@ -16,8 +16,10 @@ function NotificationEventItems(props) { const { onHealthIssue, + onApplicationUpdate, supportsOnHealthIssue, - includeHealthWarnings + includeHealthWarnings, + supportsOnApplicationUpdate } = item; return ( @@ -53,6 +55,17 @@ function NotificationEventItems(props) { /> </div> } + + <div> + <FormInputGroup + type={inputTypes.CHECK} + name="onApplicationUpdate" + helpText={translate('OnApplicationUpdateHelpText')} + isDisabled={!supportsOnApplicationUpdate.value} + {...onApplicationUpdate} + onChange={onInputChange} + /> + </div> </div> </div> </FormGroup> diff --git a/frontend/src/Store/Actions/Settings/notifications.js b/frontend/src/Store/Actions/Settings/notifications.js index 062fe4d9e..c9c86a2a8 100644 --- a/frontend/src/Store/Actions/Settings/notifications.js +++ b/frontend/src/Store/Actions/Settings/notifications.js @@ -106,6 +106,7 @@ export default { selectedSchema.onDownload = selectedSchema.supportsOnDownload; selectedSchema.onUpgrade = selectedSchema.supportsOnUpgrade; selectedSchema.onRename = selectedSchema.supportsOnRename; + selectedSchema.onApplicationUpdate = selectedSchema.supportsOnApplicationUpdate; return selectedSchema; }); diff --git a/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs b/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs new file mode 100644 index 000000000..35fe385e8 --- /dev/null +++ b/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using FluentAssertions; +using FluentValidation.Results; +using NUnit.Framework; +using NzbDrone.Core.Notifications; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.Validation; +using NzbDrone.Test.Common; + +namespace NzbDrone.Core.Test.NotificationTests +{ + [TestFixture] + public class NotificationBaseFixture : TestBase + { + private class TestSetting : IProviderConfig + { + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(); + } + } + + private class TestNotificationWithApplicationUpdate : NotificationBase<TestSetting> + { + public override string Name => "TestNotification"; + public override string Link => ""; + + public override ValidationResult Test() + { + throw new NotImplementedException(); + } + + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) + { + TestLogger.Info("OnApplicationUpdate was called"); + } + } + + private class TestNotificationWithAllEvents : NotificationBase<TestSetting> + { + public override string Name => "TestNotification"; + public override string Link => ""; + + public override ValidationResult Test() + { + throw new NotImplementedException(); + } + + public override void OnHealthIssue(NzbDrone.Core.HealthCheck.HealthCheck artist) + { + TestLogger.Info("OnHealthIssue was called"); + } + + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) + { + TestLogger.Info("OnApplicationUpdate was called"); + } + } + + private class TestNotificationWithNoEvents : NotificationBase<TestSetting> + { + public override string Name => "TestNotification"; + public override string Link => ""; + + public override ValidationResult Test() + { + throw new NotImplementedException(); + } + } + + [Test] + public void should_support_all_if_implemented() + { + var notification = new TestNotificationWithAllEvents(); + + notification.SupportsOnHealthIssue.Should().BeTrue(); + notification.SupportsOnApplicationUpdate.Should().BeTrue(); + } + + [Test] + public void should_support_none_if_none_are_implemented() + { + var notification = new TestNotificationWithNoEvents(); + + notification.SupportsOnHealthIssue.Should().BeFalse(); + notification.SupportsOnApplicationUpdate.Should().BeFalse(); + } + } +} diff --git a/src/NzbDrone.Core/Datastore/Migration/014_add_on_update_to_notifications.cs b/src/NzbDrone.Core/Datastore/Migration/014_add_on_update_to_notifications.cs new file mode 100644 index 000000000..3fc05561a --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/014_add_on_update_to_notifications.cs @@ -0,0 +1,14 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(014)] + public class add_on_update_to_notifications : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Alter.Table("Notifications").AddColumn("OnApplicationUpdate").AsBoolean().WithDefaultValue(0); + } + } +} diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index 74e6c6b28..7942732d6 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -63,7 +63,8 @@ namespace NzbDrone.Core.Datastore Mapper.Entity<NotificationDefinition>("Notifications").RegisterModel() .Ignore(x => x.ImplementationName) - .Ignore(i => i.SupportsOnHealthIssue); + .Ignore(i => i.SupportsOnHealthIssue) + .Ignore(i => i.SupportsOnApplicationUpdate); Mapper.Entity<IndexerProxyDefinition>("IndexerProxies").RegisterModel() .Ignore(x => x.ImplementationName); diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 16f81c7b7..f8b175d7d 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -262,6 +262,9 @@ "NoUpdatesAreAvailable": "No updates are available", "OAuthPopupMessage": "Pop-ups are being blocked by your browser", "Ok": "Ok", + "OnApplicationUpdate": "On Application Update", + "OnApplicationUpdateHelpText": "On Application Update", + "OnHealthIssue": "On Health Issue", "OnHealthIssueHelpText": "On Health Issue", "OpenBrowserOnStart": "Open browser on start", "OpenThisModal": "Open This Modal", diff --git a/src/NzbDrone.Core/Notifications/ApplicationUpdateMessage.cs b/src/NzbDrone.Core/Notifications/ApplicationUpdateMessage.cs new file mode 100644 index 000000000..1819ad423 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/ApplicationUpdateMessage.cs @@ -0,0 +1,16 @@ +using System; + +namespace NzbDrone.Core.Notifications +{ + public class ApplicationUpdateMessage + { + public string Message { get; set; } + public Version PreviousVersion { get; set; } + public Version NewVersion { get; set; } + + public override string ToString() + { + return NewVersion.ToString(); + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs b/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs index dedf30421..db6908019 100644 --- a/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs +++ b/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs @@ -20,6 +20,11 @@ namespace NzbDrone.Core.Notifications.Boxcar _proxy.SendNotification(HEALTH_ISSUE_TITLE, message.Message, Settings); } + public override void OnApplicationUpdate(ApplicationUpdateMessage message) + { + _proxy.SendNotification(APPLICATION_UPDATE_TITLE, message.Message, Settings); + } + public override ValidationResult Test() { var failures = new List<ValidationFailure>(); diff --git a/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs b/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs index 83130cd53..f7d728ca3 100755 --- a/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs +++ b/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs @@ -44,6 +44,18 @@ namespace NzbDrone.Core.Notifications.CustomScript ExecuteScript(environmentVariables); } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) + { + var environmentVariables = new StringDictionary(); + + environmentVariables.Add("Prowlarr_EventType", "ApplicationUpdate"); + environmentVariables.Add("Prowlarr_Update_Message", updateMessage.Message); + environmentVariables.Add("Prowlarr_Update_NewVersion", updateMessage.NewVersion.ToString()); + environmentVariables.Add("Prowlarr_Update_PreviousVersion", updateMessage.PreviousVersion.ToString()); + + ExecuteScript(environmentVariables); + } + public override ValidationResult Test() { var failures = new List<ValidationFailure>(); diff --git a/src/NzbDrone.Core/Notifications/Discord/Discord.cs b/src/NzbDrone.Core/Notifications/Discord/Discord.cs index 414d784fe..2985af45a 100644 --- a/src/NzbDrone.Core/Notifications/Discord/Discord.cs +++ b/src/NzbDrone.Core/Notifications/Discord/Discord.cs @@ -42,6 +42,41 @@ namespace NzbDrone.Core.Notifications.Discord _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 payload = CreatePayload(null, attachments); + + _proxy.SendPayload(payload, Settings); + } + public override ValidationResult Test() { var failures = new List<ValidationFailure>(); diff --git a/src/NzbDrone.Core/Notifications/Email/Email.cs b/src/NzbDrone.Core/Notifications/Email/Email.cs index 56b58b7ad..f40c20da6 100644 --- a/src/NzbDrone.Core/Notifications/Email/Email.cs +++ b/src/NzbDrone.Core/Notifications/Email/Email.cs @@ -28,6 +28,13 @@ namespace NzbDrone.Core.Notifications.Email SendEmail(Settings, HEALTH_ISSUE_TITLE_BRANDED, message.Message); } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) + { + var body = $"{updateMessage.Message}"; + + SendEmail(Settings, APPLICATION_UPDATE_TITLE_BRANDED, body); + } + public override ValidationResult Test() { var failures = new List<ValidationFailure>(); diff --git a/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs b/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs index f58b947ac..a8c631a95 100644 --- a/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs +++ b/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs @@ -24,6 +24,11 @@ namespace NzbDrone.Core.Notifications.Gotify _proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings); } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) + { + _proxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings); + } + public override ValidationResult Test() { var failures = new List<ValidationFailure>(); diff --git a/src/NzbDrone.Core/Notifications/INotification.cs b/src/NzbDrone.Core/Notifications/INotification.cs index e2ef5dfca..de71139d6 100644 --- a/src/NzbDrone.Core/Notifications/INotification.cs +++ b/src/NzbDrone.Core/Notifications/INotification.cs @@ -7,7 +7,9 @@ namespace NzbDrone.Core.Notifications string Link { get; } void OnHealthIssue(HealthCheck.HealthCheck healthCheck); + void OnApplicationUpdate(ApplicationUpdateMessage updateMessage); void ProcessQueue(); bool SupportsOnHealthIssue { get; } + bool SupportsOnApplicationUpdate { get; } } } diff --git a/src/NzbDrone.Core/Notifications/Join/Join.cs b/src/NzbDrone.Core/Notifications/Join/Join.cs index e5da40e0e..cb9243429 100644 --- a/src/NzbDrone.Core/Notifications/Join/Join.cs +++ b/src/NzbDrone.Core/Notifications/Join/Join.cs @@ -22,6 +22,11 @@ namespace NzbDrone.Core.Notifications.Join _proxy.SendNotification(HEALTH_ISSUE_TITLE_BRANDED, message.Message, Settings); } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) + { + _proxy.SendNotification(APPLICATION_UPDATE_TITLE_BRANDED, updateMessage.Message, Settings); + } + public override ValidationResult Test() { var failures = new List<ValidationFailure>(); diff --git a/src/NzbDrone.Core/Notifications/Notifiarr/Notifiarr.cs b/src/NzbDrone.Core/Notifications/Notifiarr/Notifiarr.cs index 5956e17f1..255567784 100644 --- a/src/NzbDrone.Core/Notifications/Notifiarr/Notifiarr.cs +++ b/src/NzbDrone.Core/Notifications/Notifiarr/Notifiarr.cs @@ -29,6 +29,18 @@ namespace NzbDrone.Core.Notifications.Notifiarr _proxy.SendNotification(variables, Settings); } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) + { + var variables = new StringDictionary(); + + variables.Add("Prowlarr_EventType", "ApplicationUpdate"); + variables.Add("Prowlarr_Update_Message", updateMessage.Message); + variables.Add("Prowlarr_Update_NewVersion", updateMessage.NewVersion.ToString()); + variables.Add("Prowlarr_Update_PreviousVersion", updateMessage.PreviousVersion.ToString()); + + _proxy.SendNotification(variables, Settings); + } + public override ValidationResult Test() { var failures = new List<ValidationFailure>(); diff --git a/src/NzbDrone.Core/Notifications/NotificationBase.cs b/src/NzbDrone.Core/Notifications/NotificationBase.cs index 9de1f34f3..67eee85ef 100644 --- a/src/NzbDrone.Core/Notifications/NotificationBase.cs +++ b/src/NzbDrone.Core/Notifications/NotificationBase.cs @@ -9,8 +9,10 @@ namespace NzbDrone.Core.Notifications where TSettings : IProviderConfig, new() { protected const string HEALTH_ISSUE_TITLE = "Health Check Failure"; + protected const string APPLICATION_UPDATE_TITLE = "Application Updated"; protected const string HEALTH_ISSUE_TITLE_BRANDED = "Prowlarr - " + HEALTH_ISSUE_TITLE; + protected const string APPLICATION_UPDATE_TITLE_BRANDED = "Prowlarr - " + APPLICATION_UPDATE_TITLE; public abstract string Name { get; } @@ -29,11 +31,16 @@ namespace NzbDrone.Core.Notifications { } + public virtual void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) + { + } + public virtual void ProcessQueue() { } public bool SupportsOnHealthIssue => HasConcreteImplementation("OnHealthIssue"); + public bool SupportsOnApplicationUpdate => HasConcreteImplementation("OnApplicationUpdate"); protected TSettings Settings => (TSettings)Definition.Settings; diff --git a/src/NzbDrone.Core/Notifications/NotificationDefinition.cs b/src/NzbDrone.Core/Notifications/NotificationDefinition.cs index 7bc58d689..0d94f377f 100644 --- a/src/NzbDrone.Core/Notifications/NotificationDefinition.cs +++ b/src/NzbDrone.Core/Notifications/NotificationDefinition.cs @@ -5,9 +5,11 @@ namespace NzbDrone.Core.Notifications public class NotificationDefinition : ProviderDefinition { public bool OnHealthIssue { get; set; } + public bool OnApplicationUpdate { get; set; } public bool SupportsOnHealthIssue { get; set; } public bool IncludeHealthWarnings { get; set; } + public bool SupportsOnApplicationUpdate { get; set; } - public override bool Enable => OnHealthIssue; + public override bool Enable => OnHealthIssue || OnApplicationUpdate; } } diff --git a/src/NzbDrone.Core/Notifications/NotificationFactory.cs b/src/NzbDrone.Core/Notifications/NotificationFactory.cs index 05da34cf5..1c111d4c8 100644 --- a/src/NzbDrone.Core/Notifications/NotificationFactory.cs +++ b/src/NzbDrone.Core/Notifications/NotificationFactory.cs @@ -10,6 +10,7 @@ namespace NzbDrone.Core.Notifications public interface INotificationFactory : IProviderFactory<INotification, NotificationDefinition> { List<INotification> OnHealthIssueEnabled(); + List<INotification> OnApplicationUpdateEnabled(); } public class NotificationFactory : ProviderFactory<INotification, NotificationDefinition>, INotificationFactory @@ -24,11 +25,17 @@ namespace NzbDrone.Core.Notifications return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnHealthIssue).ToList(); } + public List<INotification> OnApplicationUpdateEnabled() + { + return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnApplicationUpdate).ToList(); + } + public override void SetProviderCharacteristics(INotification provider, NotificationDefinition definition) { base.SetProviderCharacteristics(provider, definition); definition.SupportsOnHealthIssue = provider.SupportsOnHealthIssue; + definition.SupportsOnApplicationUpdate = provider.SupportsOnApplicationUpdate; } } } diff --git a/src/NzbDrone.Core/Notifications/NotificationService.cs b/src/NzbDrone.Core/Notifications/NotificationService.cs index 9f820a035..aa17b2a28 100644 --- a/src/NzbDrone.Core/Notifications/NotificationService.cs +++ b/src/NzbDrone.Core/Notifications/NotificationService.cs @@ -2,12 +2,14 @@ using System; using NLog; using NzbDrone.Core.HealthCheck; using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Update.History.Events; namespace NzbDrone.Core.Notifications { public class NotificationService : IHandle<HealthCheckFailedEvent>, - IHandleAsync<HealthCheckCompleteEvent> + IHandleAsync<HealthCheckCompleteEvent>, + IHandle<UpdateInstalledEvent> { private readonly INotificationFactory _notificationFactory; private readonly Logger _logger; @@ -56,6 +58,26 @@ namespace NzbDrone.Core.Notifications ProcessQueue(); } + public void Handle(UpdateInstalledEvent message) + { + var updateMessage = new ApplicationUpdateMessage(); + updateMessage.Message = $"Prowlarr updated from {message.PreviousVerison.ToString()} to {message.NewVersion.ToString()}"; + updateMessage.PreviousVersion = message.PreviousVerison; + updateMessage.NewVersion = message.NewVersion; + + foreach (var notification in _notificationFactory.OnApplicationUpdateEnabled()) + { + try + { + notification.OnApplicationUpdate(updateMessage); + } + catch (Exception ex) + { + _logger.Warn(ex, "Unable to send OnApplicationUpdate notification to: " + notification.Definition.Name); + } + } + } + private void ProcessQueue() { foreach (var notification in _notificationFactory.GetAvailableProviders()) diff --git a/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs b/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs index c30209f19..3e1ace185 100644 --- a/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs +++ b/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs @@ -21,6 +21,11 @@ namespace NzbDrone.Core.Notifications.Prowl _prowlProxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings); } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) + { + _prowlProxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings); + } + public override ValidationResult Test() { var failures = new List<ValidationFailure>(); diff --git a/src/NzbDrone.Core/Notifications/PushBullet/PushBullet.cs b/src/NzbDrone.Core/Notifications/PushBullet/PushBullet.cs index 209b536eb..6b2c4616c 100644 --- a/src/NzbDrone.Core/Notifications/PushBullet/PushBullet.cs +++ b/src/NzbDrone.Core/Notifications/PushBullet/PushBullet.cs @@ -24,6 +24,11 @@ namespace NzbDrone.Core.Notifications.PushBullet _proxy.SendNotification(HEALTH_ISSUE_TITLE_BRANDED, healthCheck.Message, Settings); } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) + { + _proxy.SendNotification(APPLICATION_UPDATE_TITLE_BRANDED, updateMessage.Message, Settings); + } + public override ValidationResult Test() { var failures = new List<ValidationFailure>(); diff --git a/src/NzbDrone.Core/Notifications/Pushover/Pushover.cs b/src/NzbDrone.Core/Notifications/Pushover/Pushover.cs index c31bd4ceb..0d8aa43d1 100644 --- a/src/NzbDrone.Core/Notifications/Pushover/Pushover.cs +++ b/src/NzbDrone.Core/Notifications/Pushover/Pushover.cs @@ -21,6 +21,11 @@ namespace NzbDrone.Core.Notifications.Pushover _proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings); } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) + { + _proxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings); + } + public override ValidationResult Test() { var failures = new List<ValidationFailure>(); diff --git a/src/NzbDrone.Core/Notifications/SendGrid/SendGrid.cs b/src/NzbDrone.Core/Notifications/SendGrid/SendGrid.cs index d834cfab4..9d25e57d6 100644 --- a/src/NzbDrone.Core/Notifications/SendGrid/SendGrid.cs +++ b/src/NzbDrone.Core/Notifications/SendGrid/SendGrid.cs @@ -24,6 +24,11 @@ namespace NzbDrone.Core.Notifications.SendGrid _proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings); } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) + { + _proxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings); + } + public override ValidationResult Test() { var failures = new List<ValidationFailure>(); diff --git a/src/NzbDrone.Core/Notifications/Slack/Slack.cs b/src/NzbDrone.Core/Notifications/Slack/Slack.cs index e9c9a23ed..6737443f5 100644 --- a/src/NzbDrone.Core/Notifications/Slack/Slack.cs +++ b/src/NzbDrone.Core/Notifications/Slack/Slack.cs @@ -36,6 +36,23 @@ namespace NzbDrone.Core.Notifications.Slack _proxy.SendPayload(payload, Settings); } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) + { + var attachments = new List<Attachment> + { + new Attachment + { + Title = Environment.MachineName, + Text = updateMessage.Message, + Color = "good" + } + }; + + var payload = CreatePayload("Application Updated", attachments); + + _proxy.SendPayload(payload, Settings); + } + public override ValidationResult Test() { var failures = new List<ValidationFailure>(); diff --git a/src/NzbDrone.Core/Notifications/Telegram/Telegram.cs b/src/NzbDrone.Core/Notifications/Telegram/Telegram.cs index 93a919fea..d052ce73d 100644 --- a/src/NzbDrone.Core/Notifications/Telegram/Telegram.cs +++ b/src/NzbDrone.Core/Notifications/Telegram/Telegram.cs @@ -21,6 +21,11 @@ namespace NzbDrone.Core.Notifications.Telegram _proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings); } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) + { + _proxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings); + } + public override ValidationResult Test() { var failures = new List<ValidationFailure>(); diff --git a/src/NzbDrone.Core/Notifications/Twitter/Twitter.cs b/src/NzbDrone.Core/Notifications/Twitter/Twitter.cs index 9d788e733..b33bfada9 100644 --- a/src/NzbDrone.Core/Notifications/Twitter/Twitter.cs +++ b/src/NzbDrone.Core/Notifications/Twitter/Twitter.cs @@ -23,6 +23,11 @@ namespace NzbDrone.Core.Notifications.Twitter _twitterService.SendNotification($"Health Issue: {healthCheck.Message}", Settings); } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) + { + _twitterService.SendNotification($"Application Updated: {updateMessage.Message}", Settings); + } + public override object RequestAction(string action, IDictionary<string, string> query) { if (action == "startOAuth") diff --git a/src/NzbDrone.Core/Notifications/Webhook/Webhook.cs b/src/NzbDrone.Core/Notifications/Webhook/Webhook.cs index 0c36baf59..16c5e9983 100755 --- a/src/NzbDrone.Core/Notifications/Webhook/Webhook.cs +++ b/src/NzbDrone.Core/Notifications/Webhook/Webhook.cs @@ -19,13 +19,26 @@ namespace NzbDrone.Core.Notifications.Webhook public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck) { var payload = new WebhookHealthPayload - { - EventType = WebhookEventType.Health, - Level = healthCheck.Type, - Message = healthCheck.Message, - Type = healthCheck.Source.Name, - WikiUrl = healthCheck.WikiUrl?.ToString() - }; + { + EventType = WebhookEventType.Health, + Level = healthCheck.Type, + Message = healthCheck.Message, + Type = healthCheck.Source.Name, + WikiUrl = healthCheck.WikiUrl?.ToString() + }; + + _proxy.SendWebhook(payload, Settings); + } + + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) + { + var payload = new WebhookApplicationUpdatePayload + { + EventType = WebhookEventType.ApplicationUpdate, + Message = updateMessage.Message, + PreviousVersion = updateMessage.PreviousVersion.ToString(), + NewVersion = updateMessage.NewVersion.ToString() + }; _proxy.SendWebhook(payload, Settings); } diff --git a/src/NzbDrone.Core/Notifications/Webhook/WebhookApplicationUpdatePayload.cs b/src/NzbDrone.Core/Notifications/Webhook/WebhookApplicationUpdatePayload.cs new file mode 100644 index 000000000..e05be69bc --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Webhook/WebhookApplicationUpdatePayload.cs @@ -0,0 +1,11 @@ +using NzbDrone.Core.HealthCheck; + +namespace NzbDrone.Core.Notifications.Webhook +{ + public class WebhookApplicationUpdatePayload : WebhookPayload + { + public string Message { get; set; } + public string PreviousVersion { get; set; } + public string NewVersion { get; set; } + } +} diff --git a/src/NzbDrone.Core/Notifications/Webhook/WebhookEventType.cs b/src/NzbDrone.Core/Notifications/Webhook/WebhookEventType.cs index 8c7036d92..fdc765877 100644 --- a/src/NzbDrone.Core/Notifications/Webhook/WebhookEventType.cs +++ b/src/NzbDrone.Core/Notifications/Webhook/WebhookEventType.cs @@ -12,6 +12,7 @@ namespace NzbDrone.Core.Notifications.Webhook Grab, Download, Rename, - Health + Health, + ApplicationUpdate } } diff --git a/src/Prowlarr.Api.V1/Notifications/NotificationResource.cs b/src/Prowlarr.Api.V1/Notifications/NotificationResource.cs index 290610e3a..d1b751df1 100644 --- a/src/Prowlarr.Api.V1/Notifications/NotificationResource.cs +++ b/src/Prowlarr.Api.V1/Notifications/NotificationResource.cs @@ -6,8 +6,10 @@ namespace Prowlarr.Api.V1.Notifications { public string Link { get; set; } public bool OnHealthIssue { get; set; } + public bool OnApplicationUpdate { get; set; } public bool SupportsOnHealthIssue { get; set; } public bool IncludeHealthWarnings { get; set; } + public bool SupportsOnApplicationUpdate { get; set; } public string TestCommand { get; set; } } @@ -25,6 +27,8 @@ namespace Prowlarr.Api.V1.Notifications resource.OnHealthIssue = definition.OnHealthIssue; resource.SupportsOnHealthIssue = definition.SupportsOnHealthIssue; resource.IncludeHealthWarnings = definition.IncludeHealthWarnings; + resource.OnApplicationUpdate = definition.OnApplicationUpdate; + resource.SupportsOnApplicationUpdate = definition.SupportsOnApplicationUpdate; return resource; } @@ -41,6 +45,8 @@ namespace Prowlarr.Api.V1.Notifications definition.OnHealthIssue = resource.OnHealthIssue; definition.SupportsOnHealthIssue = resource.SupportsOnHealthIssue; definition.IncludeHealthWarnings = resource.IncludeHealthWarnings; + definition.OnApplicationUpdate = resource.OnApplicationUpdate; + definition.SupportsOnApplicationUpdate = resource.SupportsOnApplicationUpdate; return definition; } From 27898aa3b58cfde0f6a83da2998910460a22bff5 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Thu, 23 Dec 2021 23:29:22 -0600 Subject: [PATCH 0250/2320] Fixed: (DanishBytes) Update Domain to .club Based on Jackett f890ddd119a35eb4ba40b407aa65461c713b5e5d --- src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs index b3a420854..3527a05fe 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs @@ -22,7 +22,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class DanishBytes : TorrentIndexerBase<DanishBytesSettings> { public override string Name => "DanishBytes"; - public override string[] IndexerUrls => new string[] { "https://danishbytes.org/" }; + public override string[] IndexerUrls => new string[] { "https://danishbytes.club/" }; public override string Description => "DanishBytes is a Private Danish Tracker"; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; From 5928eea83e4a71a555e711d7f5d318e9adde5471 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Thu, 23 Dec 2021 23:31:29 -0600 Subject: [PATCH 0251/2320] Fixed: (PornoLab) Add new 2022 Categories Based on Jackett f61a2b47400e68422ba6620a5ef2f5b4d0a929a3 --- src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs b/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs index 8c7f3e032..f5a7092a9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs @@ -142,6 +142,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1836, NewznabStandardCategory.XXX, "Сайтрипы 2019 (HD Video) / SiteRip's 2019 (HD Video)"); caps.Categories.AddCategoryMapping(1842, NewznabStandardCategory.XXX, "Сайтрипы 2020 (HD Video) / SiteRip's 2020 (HD Video)"); caps.Categories.AddCategoryMapping(1846, NewznabStandardCategory.XXX, "Сайтрипы 2021 (HD Video) / SiteRip's 2021 (HD Video)"); + caps.Categories.AddCategoryMapping(1857, NewznabStandardCategory.XXX, "Сайтрипы 2022 (HD Video) / SiteRip's 2022 (HD Video)"); caps.Categories.AddCategoryMapping(1451, NewznabStandardCategory.XXX, "Сайтрипы 1991-2010 / SiteRip's 1991-2010"); caps.Categories.AddCategoryMapping(1788, NewznabStandardCategory.XXX, "Сайтрипы 2011-2012 / SiteRip's 2011-2012"); @@ -154,6 +155,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1837, NewznabStandardCategory.XXX, "Сайтрипы 2019 / SiteRip's 2019"); caps.Categories.AddCategoryMapping(1843, NewznabStandardCategory.XXX, "Сайтрипы 2020 / SiteRip's 2020"); caps.Categories.AddCategoryMapping(1847, NewznabStandardCategory.XXX, "Сайтрипы 2021 / SiteRip's 2021"); + caps.Categories.AddCategoryMapping(1856, NewznabStandardCategory.XXX, "Сайтрипы 2022 / SiteRip's 2022"); caps.Categories.AddCategoryMapping(1707, NewznabStandardCategory.XXX, "Сцены из фильмов / Movie Scenes"); caps.Categories.AddCategoryMapping(284, NewznabStandardCategory.XXX, "Порноролики Разное / Clips (various)"); From d108ab0339cc3c94c4ed3a68a7405871e56f8929 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 22 Dec 2021 18:50:05 -0600 Subject: [PATCH 0252/2320] Fix misleading Tags helptext [skip ci] --- src/NzbDrone.Core/Localization/Core/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index f8b175d7d..312b07bc5 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -203,7 +203,7 @@ "IndexersSelectedInterp": "{0} Indexer(s) Selected", "IndexerStatusCheckAllClientMessage": "All indexers are unavailable due to failures", "IndexerStatusCheckSingleClientMessage": "Indexers unavailable due to failures: {0}", - "IndexerTagsHelpText": "Use tags to specify default clients, specify Indexer Proxies, or just to organize your indexers.", + "IndexerTagsHelpText": "Use tags to specify Indexer Proxies or just to organize your indexers.", "IndexerVipCheckExpiredClientMessage": "Indexer VIP benefits have expired: {0}", "IndexerVipCheckExpiringClientMessage": "Indexer VIP benefits expiring soon: {0}", "Info": "Info", @@ -449,4 +449,4 @@ "Wiki": "Wiki", "YesCancel": "Yes, Cancel", "Yesterday": "Yesterday" -} \ No newline at end of file +} From 55788ac04dea7adfd3b678b6df9e4631abd037be Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Fri, 17 Dec 2021 23:56:18 -0600 Subject: [PATCH 0253/2320] Fixed: (Usenet) (DrunkenSlug) Update URL https://api.drunkenslug.com gives a 301 --- src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs index d27b1df4d..045a4a7ef 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs @@ -88,7 +88,7 @@ namespace NzbDrone.Core.Indexers.Newznab yield return GetDefinition("altHUB", GetSettings("https://althub.co.za")); yield return GetDefinition("AnimeTosho (Usenet)", GetSettings("https://feed.animetosho.org")); yield return GetDefinition("DOGnzb", GetSettings("https://api.dognzb.cr")); - yield return GetDefinition("DrunkenSlug", GetSettings("https://api.drunkenslug.com")); + yield return GetDefinition("DrunkenSlug", GetSettings("https://drunkenslug.com")); yield return GetDefinition("GingaDADDY", GetSettings("https://www.gingadaddy.com")); yield return GetDefinition("Miatrix", GetSettings("https://www.miatrix.com")); yield return GetDefinition("Newz-Complex", GetSettings("https://newz-complex.org/www")); From 1c737d77fb87e7d3aa9bae6cbbd44e66252be9d2 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 11 Dec 2021 22:32:38 -0600 Subject: [PATCH 0254/2320] Bump to 0.1.9 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c9135039d..2794e0b85 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,7 +7,7 @@ variables: outputFolder: './_output' artifactsFolder: './_artifacts' testsFolder: './_tests' - majorVersion: '0.1.8' + majorVersion: '0.1.9' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From 735be4f467fa321a5f113f6e9d761087d4b66e2a Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 11 Dec 2021 22:11:48 -0600 Subject: [PATCH 0255/2320] New: (TvVault) Mark as Obsolete per Site Bot Ban Closes #573 --- src/NzbDrone.Core/Indexers/Definitions/TVVault.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs b/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs index 25ef8fd83..5fc618a90 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs @@ -22,6 +22,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete("Remove per Site Request Prowlarr Issue 573")] public class TVVault : TorrentIndexerBase<TVVaultSettings> { public override string Name => "TVVault"; From 34597e6ecb6261ac6b88ef5400513fe630aed29e Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 24 Dec 2021 14:23:09 -0600 Subject: [PATCH 0256/2320] Boolean default should be a boolean Fixes #729 --- .../Datastore/Migration/014_add_on_update_to_notifications.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Datastore/Migration/014_add_on_update_to_notifications.cs b/src/NzbDrone.Core/Datastore/Migration/014_add_on_update_to_notifications.cs index 3fc05561a..0dbe6ffbe 100644 --- a/src/NzbDrone.Core/Datastore/Migration/014_add_on_update_to_notifications.cs +++ b/src/NzbDrone.Core/Datastore/Migration/014_add_on_update_to_notifications.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Datastore.Migration { protected override void MainDbUpgrade() { - Alter.Table("Notifications").AddColumn("OnApplicationUpdate").AsBoolean().WithDefaultValue(0); + Alter.Table("Notifications").AddColumn("OnApplicationUpdate").AsBoolean().WithDefaultValue(false); } } } From 4c7b5a47d3f21b7cd9e9f9e4a81bd683cb951eb9 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 29 Aug 2021 23:33:32 -0400 Subject: [PATCH 0257/2320] Autogenerated API docs --- .gitignore | 4 + azure-pipelines.yml | 44 + docs.sh | 38 + src/NzbDrone.Host/Prowlarr.Host.csproj | 1 + src/NzbDrone.Host/Startup.cs | 72 + .../Profiles/App/AppProfileController.cs | 8 + src/Prowlarr.Api.V1/swagger.json | 6900 ----------------- 7 files changed, 167 insertions(+), 6900 deletions(-) create mode 100644 docs.sh delete mode 100644 src/Prowlarr.Api.V1/swagger.json diff --git a/.gitignore b/.gitignore index 45e6b1a39..d903078ef 100644 --- a/.gitignore +++ b/.gitignore @@ -188,6 +188,10 @@ packages.config.md5sum **/.idea/**/*.iml **/.idea/**/contentModel.xml **/.idea/**/modules.xml + # ignore node_modules symlink node_modules node_modules.nosync + +# API doc generation +.config/ diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2794e0b85..14749108f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -823,6 +823,50 @@ stages: FORCE_COLOR: 0 YARN_CACHE_FOLDER: $(yarnCacheFolder) + - job: Api_Docs + displayName: API Docs + dependsOn: Prepare + condition: | + and + ( + and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/develop')), + and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0')) + ) + + pool: + vmImage: windows-2019 + + steps: + - task: UseDotNet@2 + displayName: 'Install .net core' + inputs: + version: $(dotnetVersion) + - checkout: self # Need history for Sonar analysis + submodules: true + - bash: ./docs.sh Windows + displayName: Create Openapi.json + - bash: git commit -am 'Automated API Docs update' + displayName: Commit APIDoc Change + - task: CreatePullRequest@1 + inputs: + repoType: 'GitHub' + githubEndpoint: 'github release' + githubRepository: '$(Build.Repository.Name)' + sourceBranch: 'api-docs' + targetBranch: 'develop' + title: 'Update API Docs' + - task: CopyFiles@2 + displayName: 'Copy openapi.json to: $(Build.ArtifactStagingDirectory)' + inputs: + SourceFolder: '$(Build.SourcesDirectory)' + Contents: | + **/*openapi.json + TargetFolder: '$(Build.ArtifactStagingDirectory)/api_docs' + - publish: $(Build.ArtifactStagingDirectory)/api_docs + artifact: 'APIDocs' + displayName: Publish API Docs Bundle + condition: and(succeeded(), eq(variables['System.JobAttempt'], '1')) + - job: Analyze_Backend displayName: Backend dependsOn: Prepare diff --git a/docs.sh b/docs.sh new file mode 100644 index 000000000..bc9a94ff0 --- /dev/null +++ b/docs.sh @@ -0,0 +1,38 @@ +PLATFORM=$1 + +if [ "$PLATFORM" = "Windows" ]; then + RUNTIME="win-x64" +elif [ "$PLATFORM" = "Linux" ]; then + WHERE="linux-x64" +elif [ "$PLATFORM" = "Mac" ]; then + WHERE="osx-x64" +else + echo "Platform must be provided as first arguement: Windows, Linux or Mac" + exit 1 +fi + +outputFolder='_output' +testPackageFolder='_tests' + +rm -rf $outputFolder +rm -rf $testPackageFolder + +slnFile=src/Prowlarr.sln + +platform=Posix + +dotnet clean $slnFile -c Debug +dotnet clean $slnFile -c Release + +dotnet msbuild -restore $slnFile -p:Configuration=Debug -p:Platform=$platform -p:RuntimeIdentifiers=$RUNTIME -t:PublishAllRids + +dotnet new tool-manifest +dotnet tool install --version 6.2.3 Swashbuckle.AspNetCore.Cli + +dotnet tool run swagger tofile --output ./src/Prowlarr.Api.V1/openapi.json "$outputFolder/net6.0/$RUNTIME/prowlarr.console.dll" v1 & + +sleep 10 + +kill %1 + +exit 0 \ No newline at end of file diff --git a/src/NzbDrone.Host/Prowlarr.Host.csproj b/src/NzbDrone.Host/Prowlarr.Host.csproj index 204117551..0b6b294e2 100644 --- a/src/NzbDrone.Host/Prowlarr.Host.csproj +++ b/src/NzbDrone.Host/Prowlarr.Host.csproj @@ -7,6 +7,7 @@ <PackageReference Include="NLog.Extensions.Logging" Version="1.7.2" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> + <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.2.3" /> <PackageReference Include="DryIoc.dll" Version="4.8.1" /> <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="5.1.0" /> </ItemGroup> diff --git a/src/NzbDrone.Host/Startup.cs b/src/NzbDrone.Host/Startup.cs index 8a63849ac..bd3a0ad7b 100644 --- a/src/NzbDrone.Host/Startup.cs +++ b/src/NzbDrone.Host/Startup.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.OpenApi.Models; using NLog.Extensions.Logging; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Instrumentation; @@ -90,6 +91,63 @@ namespace NzbDrone.Host }) .AddControllersAsServices(); + services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo + { + Version = "1.0.0", + Title = "Prowlarr", + Description = "Prowlarr API docs", + License = new OpenApiLicense + { + Name = "GPL-3.0", + Url = new Uri("https://github.com/Prowlarr/Prowlarr/blob/develop/LICENSE") + } + }); + + var apiKeyHeader = new OpenApiSecurityScheme + { + Name = "X-Api-Key", + Type = SecuritySchemeType.ApiKey, + Scheme = "apiKey", + Description = "Apikey passed as header", + In = ParameterLocation.Header, + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "X-Api-Key" + }, + }; + + c.AddSecurityDefinition("X-Api-Key", apiKeyHeader); + + c.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { apiKeyHeader, new string[] { } } + }); + + var apikeyQuery = new OpenApiSecurityScheme + { + Name = "apikey", + Type = SecuritySchemeType.ApiKey, + Scheme = "apiKey", + Description = "Apikey passed as header", + In = ParameterLocation.Query, + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "apikey" + }, + }; + + c.AddSecurityDefinition("apikey", apikeyQuery); + + c.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { apikeyQuery, new string[] { } } + }); + }); + services .AddSignalR() .AddJsonProtocol(options => @@ -181,6 +239,20 @@ namespace NzbDrone.Host app.UseWebSockets(); + // Enable middleware to serve generated Swagger as a JSON endpoint. + if (BuildInfo.IsDebug) + { + app.UseSwagger(c => + { + c.PreSerializeFilters.Add((swagger, httpReq) => + { + swagger.Servers = new List<OpenApiServer> { new OpenApiServer { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}" } }; + }); + + c.RouteTemplate = "docs/{documentName}/openapi.json"; + }); + } + app.UseEndpoints(x => { x.MapHub<MessageHub>("/signalr/messages").RequireAuthorization("SignalR"); diff --git a/src/Prowlarr.Api.V1/Profiles/App/AppProfileController.cs b/src/Prowlarr.Api.V1/Profiles/App/AppProfileController.cs index b3bc82a09..2225ace22 100644 --- a/src/Prowlarr.Api.V1/Profiles/App/AppProfileController.cs +++ b/src/Prowlarr.Api.V1/Profiles/App/AppProfileController.cs @@ -20,6 +20,7 @@ namespace Prowlarr.Api.V1.Profiles.App } [RestPostById] + [Produces("application/json")] public ActionResult<AppProfileResource> Create(AppProfileResource resource) { var model = resource.ToModel(); @@ -28,12 +29,14 @@ namespace Prowlarr.Api.V1.Profiles.App } [RestDeleteById] + [Produces("application/json")] public void DeleteProfile(int id) { _profileService.Delete(id); } [RestPutById] + [Produces("application/json")] public ActionResult<AppProfileResource> Update(AppProfileResource resource) { var model = resource.ToModel(); @@ -43,12 +46,17 @@ namespace Prowlarr.Api.V1.Profiles.App return Accepted(model.Id); } + [Produces("application/json")] + [ProducesResponseType(typeof(AppProfileResource), 200)] + [ProducesResponseType(typeof(IDictionary<string, string>), 404)] + [ProducesResponseType(500)] public override AppProfileResource GetResourceById(int id) { return _profileService.Get(id).ToResource(); } [HttpGet] + [Produces("application/json")] public List<AppProfileResource> GetAll() { return _profileService.All().ToResource(); diff --git a/src/Prowlarr.Api.V1/swagger.json b/src/Prowlarr.Api.V1/swagger.json deleted file mode 100644 index d739dd2cf..000000000 --- a/src/Prowlarr.Api.V1/swagger.json +++ /dev/null @@ -1,6900 +0,0 @@ -{ - "openapi": "3.0.1", - "info": { - "title": "Prowlarr", - "version": "1.0.0" - }, - "paths": { - "/api/v1/applications/{id}": { - "get": { - "tags": [ - "Application" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - } - } - } - } - }, - "put": { - "tags": [ - "Application" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Application" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/applications": { - "get": { - "tags": [ - "Application" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApplicationResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApplicationResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApplicationResource" - } - } - } - } - } - } - }, - "post": { - "tags": [ - "Application" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - } - } - } - } - } - }, - "/api/v1/applications/schema": { - "get": { - "tags": [ - "Application" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApplicationResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApplicationResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApplicationResource" - } - } - } - } - } - } - } - }, - "/api/v1/applications/test": { - "post": { - "tags": [ - "Application" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/applications/testall": { - "post": { - "tags": [ - "Application" - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/applications/action/{name}": { - "post": { - "tags": [ - "Application" - ], - "parameters": [ - { - "name": "name", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/appprofile": { - "post": { - "tags": [ - "AppProfile" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - } - } - } - } - }, - "get": { - "tags": [ - "AppProfile" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/AppProfileResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/AppProfileResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/AppProfileResource" - } - } - } - } - } - } - } - }, - "/api/v1/appprofile/{id}": { - "delete": { - "tags": [ - "AppProfile" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - }, - "put": { - "tags": [ - "AppProfile" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - } - } - } - } - }, - "get": { - "tags": [ - "AppProfile" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - } - } - } - } - } - }, - "/login": { - "post": { - "tags": [ - "Authentication" - ], - "parameters": [ - { - "name": "returnUrl", - "in": "query", - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "type": "object", - "properties": { - "Username": { - "type": "string" - }, - "Password": { - "type": "string" - }, - "RememberMe": { - "type": "string" - } - } - }, - "encoding": { - "Username": { - "style": "form" - }, - "Password": { - "style": "form" - }, - "RememberMe": { - "style": "form" - } - } - } - } - }, - "responses": { - "200": { - "description": "Success" - } - } - }, - "get": { - "tags": [ - "StaticResource" - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/logout": { - "get": { - "tags": [ - "Authentication" - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/system/backup": { - "get": { - "tags": [ - "Backup" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BackupResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BackupResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BackupResource" - } - } - } - } - } - } - } - }, - "/api/v1/system/backup/{id}": { - "delete": { - "tags": [ - "Backup" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/system/backup/restore/{id}": { - "post": { - "tags": [ - "Backup" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/system/backup/restore/upload": { - "post": { - "tags": [ - "Backup" - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/command/{id}": { - "get": { - "tags": [ - "Command" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/CommandResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CommandResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CommandResource" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Command" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/command": { - "post": { - "tags": [ - "Command" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CommandResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CommandResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CommandResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/CommandResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CommandResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CommandResource" - } - } - } - } - } - }, - "get": { - "tags": [ - "Command" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CommandResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CommandResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CommandResource" - } - } - } - } - } - } - } - }, - "/api/v1/customfilter/{id}": { - "get": { - "tags": [ - "CustomFilter" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - } - } - } - } - }, - "put": { - "tags": [ - "CustomFilter" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - } - } - } - } - }, - "delete": { - "tags": [ - "CustomFilter" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/customfilter": { - "get": { - "tags": [ - "CustomFilter" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CustomFilterResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CustomFilterResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CustomFilterResource" - } - } - } - } - } - } - }, - "post": { - "tags": [ - "CustomFilter" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - } - } - } - } - } - }, - "/api/v1/config/development/{id}": { - "put": { - "tags": [ - "DevelopmentConfig" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DevelopmentConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DevelopmentConfigResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/DevelopmentConfigResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/DevelopmentConfigResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DevelopmentConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DevelopmentConfigResource" - } - } - } - } - } - }, - "get": { - "tags": [ - "DevelopmentConfig" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/DevelopmentConfigResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DevelopmentConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DevelopmentConfigResource" - } - } - } - } - } - } - }, - "/api/v1/config/development": { - "get": { - "tags": [ - "DevelopmentConfig" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/DevelopmentConfigResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DevelopmentConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DevelopmentConfigResource" - } - } - } - } - } - } - }, - "/api/v1/downloadclient/{id}": { - "get": { - "tags": [ - "DownloadClient" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } - } - } - } - }, - "put": { - "tags": [ - "DownloadClient" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } - } - } - } - }, - "delete": { - "tags": [ - "DownloadClient" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/downloadclient": { - "get": { - "tags": [ - "DownloadClient" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } - } - } - } - } - }, - "post": { - "tags": [ - "DownloadClient" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } - } - } - } - } - }, - "/api/v1/downloadclient/schema": { - "get": { - "tags": [ - "DownloadClient" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } - } - } - } - } - } - }, - "/api/v1/downloadclient/test": { - "post": { - "tags": [ - "DownloadClient" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/downloadclient/testall": { - "post": { - "tags": [ - "DownloadClient" - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/downloadclient/action/{name}": { - "post": { - "tags": [ - "DownloadClient" - ], - "parameters": [ - { - "name": "name", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/config/downloadclient/{id}": { - "get": { - "tags": [ - "DownloadClientConfig" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/DownloadClientConfigResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientConfigResource" - } - } - } - } - } - }, - "put": { - "tags": [ - "DownloadClientConfig" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientConfigResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientConfigResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/DownloadClientConfigResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientConfigResource" - } - } - } - } - } - } - }, - "/api/v1/config/downloadclient": { - "get": { - "tags": [ - "DownloadClientConfig" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/DownloadClientConfigResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientConfigResource" - } - } - } - } - } - } - }, - "/api/v1/filesystem": { - "get": { - "tags": [ - "FileSystem" - ], - "parameters": [ - { - "name": "path", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "includeFiles", - "in": "query", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "name": "allowFoldersWithoutTrailingSlashes", - "in": "query", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/filesystem/type": { - "get": { - "tags": [ - "FileSystem" - ], - "parameters": [ - { - "name": "path", - "in": "query", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/health/{id}": { - "get": { - "tags": [ - "Health" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/HealthResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/HealthResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/HealthResource" - } - } - } - } - } - } - }, - "/api/v1/health": { - "get": { - "tags": [ - "Health" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HealthResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HealthResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HealthResource" - } - } - } - } - } - } - } - }, - "/api/v1/history": { - "get": { - "tags": [ - "History" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/HistoryResourcePagingResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/HistoryResourcePagingResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/HistoryResourcePagingResource" - } - } - } - } - } - } - }, - "/api/v1/history/since": { - "get": { - "tags": [ - "History" - ], - "parameters": [ - { - "name": "date", - "in": "query", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "eventType", - "in": "query", - "schema": { - "$ref": "#/components/schemas/HistoryEventType" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HistoryResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HistoryResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HistoryResource" - } - } - } - } - } - } - } - }, - "/api/v1/history/indexer": { - "get": { - "tags": [ - "History" - ], - "parameters": [ - { - "name": "indexerId", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "eventType", - "in": "query", - "schema": { - "$ref": "#/components/schemas/HistoryEventType" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HistoryResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HistoryResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HistoryResource" - } - } - } - } - } - } - } - }, - "/api/v1/config/host/{id}": { - "get": { - "tags": [ - "HostConfig" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/HostConfigResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/HostConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/HostConfigResource" - } - } - } - } - } - }, - "put": { - "tags": [ - "HostConfig" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HostConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/HostConfigResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/HostConfigResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/HostConfigResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/HostConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/HostConfigResource" - } - } - } - } - } - } - }, - "/api/v1/config/host": { - "get": { - "tags": [ - "HostConfig" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/HostConfigResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/HostConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/HostConfigResource" - } - } - } - } - } - } - }, - "/api/v1/indexer/{id}": { - "get": { - "tags": [ - "Indexer" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - } - } - } - } - }, - "put": { - "tags": [ - "Indexer" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Indexer" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/indexer": { - "get": { - "tags": [ - "Indexer" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerResource" - } - } - } - } - } - } - }, - "post": { - "tags": [ - "Indexer" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - } - } - } - } - } - }, - "/api/v1/indexer/schema": { - "get": { - "tags": [ - "Indexer" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerResource" - } - } - } - } - } - } - } - }, - "/api/v1/indexer/test": { - "post": { - "tags": [ - "Indexer" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/indexer/testall": { - "post": { - "tags": [ - "Indexer" - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/indexer/action/{name}": { - "post": { - "tags": [ - "Indexer" - ], - "parameters": [ - { - "name": "name", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/config/indexer/{id}": { - "get": { - "tags": [ - "IndexerConfig" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/IndexerConfigResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerConfigResource" - } - } - } - } - } - }, - "put": { - "tags": [ - "IndexerConfig" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerConfigResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/IndexerConfigResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/IndexerConfigResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerConfigResource" - } - } - } - } - } - } - }, - "/api/v1/config/indexer": { - "get": { - "tags": [ - "IndexerConfig" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/IndexerConfigResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerConfigResource" - } - } - } - } - } - } - }, - "/api/v1/indexer/categories": { - "get": { - "tags": [ - "IndexerDefaultCategories" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerCategory" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerCategory" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerCategory" - } - } - } - } - } - } - } - }, - "/api/v1/indexer/editor": { - "put": { - "tags": [ - "IndexerEditor" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerEditorResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerEditorResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/IndexerEditorResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success" - } - } - }, - "delete": { - "tags": [ - "IndexerEditor" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerEditorResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerEditorResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/IndexerEditorResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/indexerproxy/{id}": { - "get": { - "tags": [ - "IndexerProxy" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } - } - } - } - }, - "put": { - "tags": [ - "IndexerProxy" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } - } - } - } - }, - "delete": { - "tags": [ - "IndexerProxy" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/indexerproxy": { - "get": { - "tags": [ - "IndexerProxy" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } - } - } - } - } - }, - "post": { - "tags": [ - "IndexerProxy" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } - } - } - } - } - }, - "/api/v1/indexerproxy/schema": { - "get": { - "tags": [ - "IndexerProxy" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } - } - } - } - } - } - }, - "/api/v1/indexerproxy/test": { - "post": { - "tags": [ - "IndexerProxy" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/indexerproxy/testall": { - "post": { - "tags": [ - "IndexerProxy" - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/indexerproxy/action/{name}": { - "post": { - "tags": [ - "IndexerProxy" - ], - "parameters": [ - { - "name": "name", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/indexerstats": { - "get": { - "tags": [ - "IndexerStats" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/IndexerStatsResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerStatsResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerStatsResource" - } - } - } - } - } - } - }, - "/api/v1/indexerstatus/{id}": { - "get": { - "tags": [ - "IndexerStatus" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/IndexerStatusResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexerStatusResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerStatusResource" - } - } - } - } - } - } - }, - "/api/v1/indexerstatus": { - "get": { - "tags": [ - "IndexerStatus" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerStatusResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerStatusResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerStatusResource" - } - } - } - } - } - } - } - }, - "/initialize.js": { - "get": { - "tags": [ - "InitializeJs" - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/language/{id}": { - "get": { - "tags": [ - "Language" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/LanguageResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/LanguageResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/LanguageResource" - } - } - } - } - } - } - }, - "/api/v1/language": { - "get": { - "tags": [ - "Language" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/LanguageResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/LanguageResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/LanguageResource" - } - } - } - } - } - } - } - }, - "/api/v1/localization": { - "get": { - "tags": [ - "Localization" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - }, - "application/json": { - "schema": { - "type": "string" - } - }, - "text/json": { - "schema": { - "type": "string" - } - } - } - } - } - } - }, - "/api/v1/log": { - "get": { - "tags": [ - "Log" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/LogResourcePagingResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/LogResourcePagingResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/LogResourcePagingResource" - } - } - } - } - } - } - }, - "/api/v1/log/file": { - "get": { - "tags": [ - "LogFile" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/LogFileResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/LogFileResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/LogFileResource" - } - } - } - } - } - } - } - }, - "/api/v1/log/file/{filename}": { - "get": { - "tags": [ - "LogFile" - ], - "parameters": [ - { - "name": "filename", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/indexer/{id}/newznab": { - "get": { - "tags": [ - "Newznab" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "t", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "q", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "cat", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "imdbid", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "tmdbid", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "extended", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "limit", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "offset", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "rid", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "tvmazeid", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "traktid", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "tvdbid", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "season", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "ep", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "album", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "artist", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "label", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "track", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "year", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "genre", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "author", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "title", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "configured", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "source", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "host", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "server", - "in": "query", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/{id}/api": { - "get": { - "tags": [ - "Newznab" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "t", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "q", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "cat", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "imdbid", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "tmdbid", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "extended", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "limit", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "offset", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "rid", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "tvmazeid", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "traktid", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "tvdbid", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "season", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "ep", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "album", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "artist", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "label", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "track", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "year", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "genre", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "author", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "title", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "configured", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "source", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "host", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "server", - "in": "query", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/indexer/{id}/download": { - "get": { - "tags": [ - "Newznab" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "link", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "file", - "in": "query", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/{id}/download": { - "get": { - "tags": [ - "Newznab" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "link", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "file", - "in": "query", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/notification/{id}": { - "get": { - "tags": [ - "Notification" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - } - } - } - } - }, - "put": { - "tags": [ - "Notification" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Notification" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/notification": { - "get": { - "tags": [ - "Notification" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NotificationResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NotificationResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NotificationResource" - } - } - } - } - } - } - }, - "post": { - "tags": [ - "Notification" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - } - } - } - } - } - }, - "/api/v1/notification/schema": { - "get": { - "tags": [ - "Notification" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NotificationResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NotificationResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NotificationResource" - } - } - } - } - } - } - } - }, - "/api/v1/notification/test": { - "post": { - "tags": [ - "Notification" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/notification/testall": { - "post": { - "tags": [ - "Notification" - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/notification/action/{name}": { - "post": { - "tags": [ - "Notification" - ], - "parameters": [ - { - "name": "name", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/appprofile/schema": { - "get": { - "tags": [ - "QualityProfileSchema" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/AppProfileResource" - } - } - } - } - } - } - }, - "/api/v1/search/{id}": { - "get": { - "tags": [ - "Search" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/SearchResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SearchResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SearchResource" - } - } - } - } - } - } - }, - "/api/v1/search": { - "post": { - "tags": [ - "Search" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SearchResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SearchResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/SearchResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/SearchResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SearchResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SearchResource" - } - } - } - } - } - }, - "get": { - "tags": [ - "Search" - ], - "parameters": [ - { - "name": "query", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "indexerIds", - "in": "query", - "schema": { - "type": "array", - "items": { - "type": "integer", - "format": "int32" - } - } - }, - { - "name": "categories", - "in": "query", - "schema": { - "type": "array", - "items": { - "type": "integer", - "format": "int32" - } - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SearchResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SearchResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SearchResource" - } - } - } - } - } - } - } - }, - "/content/{path}": { - "get": { - "tags": [ - "StaticResource" - ], - "parameters": [ - { - "name": "path", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/": { - "get": { - "tags": [ - "StaticResource" - ], - "parameters": [ - { - "name": "path", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/{path}": { - "get": { - "tags": [ - "StaticResource" - ], - "parameters": [ - { - "name": "path", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/system/status": { - "get": { - "tags": [ - "System" - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/system/routes": { - "get": { - "tags": [ - "System" - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/system/routes/duplicate": { - "get": { - "tags": [ - "System" - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/system/shutdown": { - "post": { - "tags": [ - "System" - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/system/restart": { - "post": { - "tags": [ - "System" - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/tag/{id}": { - "get": { - "tags": [ - "Tag" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/TagResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/TagResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TagResource" - } - } - } - } - } - }, - "put": { - "tags": [ - "Tag" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TagResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TagResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/TagResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/TagResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/TagResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TagResource" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Tag" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/api/v1/tag": { - "get": { - "tags": [ - "Tag" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TagResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TagResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TagResource" - } - } - } - } - } - } - }, - "post": { - "tags": [ - "Tag" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TagResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TagResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/TagResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/TagResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/TagResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TagResource" - } - } - } - } - } - } - }, - "/api/v1/tag/detail/{id}": { - "get": { - "tags": [ - "TagDetails" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/TagDetailsResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/TagDetailsResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TagDetailsResource" - } - } - } - } - } - } - }, - "/api/v1/tag/detail": { - "get": { - "tags": [ - "TagDetails" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TagDetailsResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TagDetailsResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TagDetailsResource" - } - } - } - } - } - } - } - }, - "/api/v1/system/task": { - "get": { - "tags": [ - "Task" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TaskResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TaskResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TaskResource" - } - } - } - } - } - } - } - }, - "/api/v1/system/task/{id}": { - "get": { - "tags": [ - "Task" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/TaskResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/TaskResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TaskResource" - } - } - } - } - } - } - }, - "/api/v1/config/ui/{id}": { - "get": { - "tags": [ - "UiConfig" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - } - } - } - } - }, - "put": { - "tags": [ - "UiConfig" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - } - } - } - } - } - }, - "/api/v1/config/ui": { - "get": { - "tags": [ - "UiConfig" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - } - } - } - } - } - }, - "/api/v1/update": { - "get": { - "tags": [ - "Update" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UpdateResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UpdateResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UpdateResource" - } - } - } - } - } - } - } - }, - "/api/v1/log/file/update": { - "get": { - "tags": [ - "UpdateLogFile" - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/LogFileResource" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/LogFileResource" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/LogFileResource" - } - } - } - } - } - } - } - }, - "/api/v1/log/file/update/{filename}": { - "get": { - "tags": [ - "UpdateLogFile" - ], - "parameters": [ - { - "name": "filename", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - } - }, - "components": { - "schemas": { - "ApplicationResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string", - "nullable": true - }, - "fields": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Field" - }, - "nullable": true - }, - "implementationName": { - "type": "string", - "nullable": true - }, - "implementation": { - "type": "string", - "nullable": true - }, - "configContract": { - "type": "string", - "nullable": true - }, - "infoLink": { - "type": "string", - "nullable": true - }, - "message": { - "$ref": "#/components/schemas/ProviderMessage" - }, - "tags": { - "uniqueItems": true, - "type": "array", - "items": { - "type": "integer", - "format": "int32" - }, - "nullable": true - }, - "presets": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApplicationResource" - }, - "nullable": true - }, - "syncLevel": { - "$ref": "#/components/schemas/ApplicationSyncLevel" - }, - "testCommand": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "ApplicationSyncLevel": { - "enum": [ - "disabled", - "addOnly", - "fullSync" - ], - "type": "string" - }, - "ApplyTags": { - "enum": [ - "add", - "remove", - "replace" - ], - "type": "string" - }, - "AppProfileResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string", - "nullable": true - }, - "enableRss": { - "type": "boolean" - }, - "enableInteractiveSearch": { - "type": "boolean" - }, - "enableAutomaticSearch": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "AuthenticationType": { - "enum": [ - "none", - "basic", - "forms" - ], - "type": "string" - }, - "BackupResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string", - "nullable": true - }, - "path": { - "type": "string", - "nullable": true - }, - "type": { - "$ref": "#/components/schemas/BackupType" - }, - "time": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "BackupType": { - "enum": [ - "scheduled", - "manual", - "update" - ], - "type": "string" - }, - "CertificateValidationType": { - "enum": [ - "enabled", - "disabledForLocalAddresses", - "disabled" - ], - "type": "string" - }, - "Command": { - "type": "object", - "properties": { - "sendUpdatesToClient": { - "type": "boolean" - }, - "updateScheduledTask": { - "type": "boolean", - "readOnly": true - }, - "completionMessage": { - "type": "string", - "nullable": true, - "readOnly": true - }, - "requiresDiskAccess": { - "type": "boolean", - "readOnly": true - }, - "isExclusive": { - "type": "boolean", - "readOnly": true - }, - "isTypeExclusive": { - "type": "boolean", - "readOnly": true - }, - "name": { - "type": "string", - "nullable": true, - "readOnly": true - }, - "lastExecutionTime": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "lastStartTime": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "trigger": { - "$ref": "#/components/schemas/CommandTrigger" - }, - "suppressMessages": { - "type": "boolean" - }, - "clientUserAgent": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "CommandPriority": { - "enum": [ - "normal", - "high", - "low" - ], - "type": "string" - }, - "CommandResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string", - "nullable": true - }, - "commandName": { - "type": "string", - "nullable": true - }, - "message": { - "type": "string", - "nullable": true - }, - "body": { - "$ref": "#/components/schemas/Command" - }, - "priority": { - "$ref": "#/components/schemas/CommandPriority" - }, - "status": { - "$ref": "#/components/schemas/CommandStatus" - }, - "queued": { - "type": "string", - "format": "date-time" - }, - "started": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "ended": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "duration": { - "$ref": "#/components/schemas/TimeSpan" - }, - "exception": { - "type": "string", - "nullable": true - }, - "trigger": { - "$ref": "#/components/schemas/CommandTrigger" - }, - "clientUserAgent": { - "type": "string", - "nullable": true - }, - "stateChangeTime": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "sendUpdatesToClient": { - "type": "boolean" - }, - "updateScheduledTask": { - "type": "boolean" - }, - "lastExecutionTime": { - "type": "string", - "format": "date-time", - "nullable": true - } - }, - "additionalProperties": false - }, - "CommandStatus": { - "enum": [ - "queued", - "started", - "completed", - "failed", - "aborted", - "cancelled", - "orphaned" - ], - "type": "string" - }, - "CommandTrigger": { - "enum": [ - "unspecified", - "manual", - "scheduled" - ], - "type": "string" - }, - "CustomFilterResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "type": { - "type": "string", - "nullable": true - }, - "label": { - "type": "string", - "nullable": true - }, - "filters": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { } - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "DevelopmentConfigResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "consoleLogLevel": { - "type": "string", - "nullable": true - }, - "logSql": { - "type": "boolean" - }, - "logIndexerResponse": { - "type": "boolean" - }, - "logRotate": { - "type": "integer", - "format": "int32" - }, - "filterSentryEvents": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "DownloadClientConfigResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "downloadClientWorkingFolders": { - "type": "string", - "nullable": true - }, - "enableCompletedDownloadHandling": { - "type": "boolean" - }, - "removeCompletedDownloads": { - "type": "boolean" - }, - "checkForFinishedDownloadInterval": { - "type": "integer", - "format": "int32" - }, - "autoRedownloadFailed": { - "type": "boolean" - }, - "removeFailedDownloads": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "DownloadClientResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string", - "nullable": true - }, - "fields": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Field" - }, - "nullable": true - }, - "implementationName": { - "type": "string", - "nullable": true - }, - "implementation": { - "type": "string", - "nullable": true - }, - "configContract": { - "type": "string", - "nullable": true - }, - "infoLink": { - "type": "string", - "nullable": true - }, - "message": { - "$ref": "#/components/schemas/ProviderMessage" - }, - "tags": { - "uniqueItems": true, - "type": "array", - "items": { - "type": "integer", - "format": "int32" - }, - "nullable": true - }, - "presets": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DownloadClientResource" - }, - "nullable": true - }, - "enable": { - "type": "boolean" - }, - "protocol": { - "$ref": "#/components/schemas/DownloadProtocol" - }, - "priority": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "DownloadProtocol": { - "enum": [ - "unknown", - "usenet", - "torrent" - ], - "type": "string" - }, - "Field": { - "type": "object", - "properties": { - "order": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string", - "nullable": true - }, - "label": { - "type": "string", - "nullable": true - }, - "unit": { - "type": "string", - "nullable": true - }, - "helpText": { - "type": "string", - "nullable": true - }, - "helpLink": { - "type": "string", - "nullable": true - }, - "value": { - "nullable": true - }, - "type": { - "type": "string", - "nullable": true - }, - "advanced": { - "type": "boolean" - }, - "selectOptions": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SelectOption" - }, - "nullable": true - }, - "selectOptionsProviderAction": { - "type": "string", - "nullable": true - }, - "section": { - "type": "string", - "nullable": true - }, - "hidden": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "HealthCheckResult": { - "enum": [ - "ok", - "notice", - "warning", - "error" - ], - "type": "string" - }, - "HealthResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "source": { - "type": "string", - "nullable": true - }, - "type": { - "$ref": "#/components/schemas/HealthCheckResult" - }, - "message": { - "type": "string", - "nullable": true - }, - "wikiUrl": { - "$ref": "#/components/schemas/HttpUri" - } - }, - "additionalProperties": false - }, - "HistoryEventType": { - "enum": [ - "unknown", - "releaseGrabbed", - "indexerQuery", - "indexerRss", - "indexerAuth", - "indexerInfo" - ], - "type": "string" - }, - "HistoryResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "indexerId": { - "type": "integer", - "format": "int32" - }, - "date": { - "type": "string", - "format": "date-time" - }, - "downloadId": { - "type": "string", - "nullable": true - }, - "successful": { - "type": "boolean" - }, - "eventType": { - "$ref": "#/components/schemas/HistoryEventType" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "HistoryResourcePagingResource": { - "type": "object", - "properties": { - "page": { - "type": "integer", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "format": "int32" - }, - "sortKey": { - "type": "string", - "nullable": true - }, - "sortDirection": { - "$ref": "#/components/schemas/SortDirection" - }, - "filters": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PagingResourceFilter" - }, - "nullable": true - }, - "totalRecords": { - "type": "integer", - "format": "int32" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HistoryResource" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "HostConfigResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "bindAddress": { - "type": "string", - "nullable": true - }, - "port": { - "type": "integer", - "format": "int32" - }, - "sslPort": { - "type": "integer", - "format": "int32" - }, - "enableSsl": { - "type": "boolean" - }, - "launchBrowser": { - "type": "boolean" - }, - "authenticationMethod": { - "$ref": "#/components/schemas/AuthenticationType" - }, - "analyticsEnabled": { - "type": "boolean" - }, - "username": { - "type": "string", - "nullable": true - }, - "password": { - "type": "string", - "nullable": true - }, - "logLevel": { - "type": "string", - "nullable": true - }, - "consoleLogLevel": { - "type": "string", - "nullable": true - }, - "branch": { - "type": "string", - "nullable": true - }, - "apiKey": { - "type": "string", - "nullable": true - }, - "sslCertPath": { - "type": "string", - "nullable": true - }, - "sslCertPassword": { - "type": "string", - "nullable": true - }, - "urlBase": { - "type": "string", - "nullable": true - }, - "updateAutomatically": { - "type": "boolean" - }, - "updateMechanism": { - "$ref": "#/components/schemas/UpdateMechanism" - }, - "updateScriptPath": { - "type": "string", - "nullable": true - }, - "proxyEnabled": { - "type": "boolean" - }, - "proxyType": { - "$ref": "#/components/schemas/ProxyType" - }, - "proxyHostname": { - "type": "string", - "nullable": true - }, - "proxyPort": { - "type": "integer", - "format": "int32" - }, - "proxyUsername": { - "type": "string", - "nullable": true - }, - "proxyPassword": { - "type": "string", - "nullable": true - }, - "proxyBypassFilter": { - "type": "string", - "nullable": true - }, - "proxyBypassLocalAddresses": { - "type": "boolean" - }, - "certificateValidation": { - "$ref": "#/components/schemas/CertificateValidationType" - }, - "backupFolder": { - "type": "string", - "nullable": true - }, - "backupInterval": { - "type": "integer", - "format": "int32" - }, - "backupRetention": { - "type": "integer", - "format": "int32" - }, - "historyCleanupDays": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "HostStatistics": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true - }, - "numberOfQueries": { - "type": "integer", - "format": "int32" - }, - "numberOfGrabs": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "HttpUri": { - "type": "object", - "properties": { - "fullUri": { - "type": "string", - "nullable": true, - "readOnly": true - }, - "scheme": { - "type": "string", - "nullable": true, - "readOnly": true - }, - "host": { - "type": "string", - "nullable": true, - "readOnly": true - }, - "port": { - "type": "integer", - "format": "int32", - "nullable": true, - "readOnly": true - }, - "path": { - "type": "string", - "nullable": true, - "readOnly": true - }, - "query": { - "type": "string", - "nullable": true, - "readOnly": true - }, - "fragment": { - "type": "string", - "nullable": true, - "readOnly": true - } - }, - "additionalProperties": false - }, - "IndexerCapabilityResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "limitsMax": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "limitsDefault": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "categories": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerCategory" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "IndexerCategory": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "subCategories": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerCategory" - }, - "nullable": true, - "readOnly": true - } - }, - "additionalProperties": false - }, - "IndexerConfigResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "minimumAge": { - "type": "integer", - "format": "int32" - }, - "maximumSize": { - "type": "integer", - "format": "int32" - }, - "retention": { - "type": "integer", - "format": "int32" - }, - "rssSyncInterval": { - "type": "integer", - "format": "int32" - }, - "preferIndexerFlags": { - "type": "boolean" - }, - "availabilityDelay": { - "type": "integer", - "format": "int32" - }, - "allowHardcodedSubs": { - "type": "boolean" - }, - "whitelistedHardcodedSubs": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "IndexerEditorResource": { - "type": "object", - "properties": { - "indexerIds": { - "type": "array", - "items": { - "type": "integer", - "format": "int32" - }, - "nullable": true - }, - "enable": { - "type": "string", - "nullable": true - }, - "appProfileId": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "tags": { - "type": "array", - "items": { - "type": "integer", - "format": "int32" - }, - "nullable": true - }, - "applyTags": { - "$ref": "#/components/schemas/ApplyTags" - } - }, - "additionalProperties": false - }, - "IndexerPrivacy": { - "enum": [ - "public", - "semiPublic", - "private" - ], - "type": "string" - }, - "IndexerProxyResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string", - "nullable": true - }, - "fields": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Field" - }, - "nullable": true - }, - "implementationName": { - "type": "string", - "nullable": true - }, - "implementation": { - "type": "string", - "nullable": true - }, - "configContract": { - "type": "string", - "nullable": true - }, - "infoLink": { - "type": "string", - "nullable": true - }, - "message": { - "$ref": "#/components/schemas/ProviderMessage" - }, - "tags": { - "uniqueItems": true, - "type": "array", - "items": { - "type": "integer", - "format": "int32" - }, - "nullable": true - }, - "presets": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerProxyResource" - }, - "nullable": true - }, - "link": { - "type": "string", - "nullable": true - }, - "onHealthIssue": { - "type": "boolean" - }, - "supportsOnHealthIssue": { - "type": "boolean" - }, - "includeHealthWarnings": { - "type": "boolean" - }, - "testCommand": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "IndexerResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string", - "nullable": true - }, - "fields": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Field" - }, - "nullable": true - }, - "implementationName": { - "type": "string", - "nullable": true - }, - "implementation": { - "type": "string", - "nullable": true - }, - "configContract": { - "type": "string", - "nullable": true - }, - "infoLink": { - "type": "string", - "nullable": true - }, - "message": { - "$ref": "#/components/schemas/ProviderMessage" - }, - "tags": { - "uniqueItems": true, - "type": "array", - "items": { - "type": "integer", - "format": "int32" - }, - "nullable": true - }, - "presets": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerResource" - }, - "nullable": true - }, - "indexerUrls": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "language": { - "type": "string", - "nullable": true - }, - "encoding": { - "type": "string", - "nullable": true - }, - "enable": { - "type": "boolean" - }, - "redirect": { - "type": "boolean" - }, - "supportsRss": { - "type": "boolean" - }, - "supportsSearch": { - "type": "boolean" - }, - "supportsRedirect": { - "type": "boolean" - }, - "appProfileId": { - "type": "integer", - "format": "int32" - }, - "protocol": { - "$ref": "#/components/schemas/DownloadProtocol" - }, - "privacy": { - "$ref": "#/components/schemas/IndexerPrivacy" - }, - "capabilities": { - "$ref": "#/components/schemas/IndexerCapabilityResource" - }, - "priority": { - "type": "integer", - "format": "int32" - }, - "added": { - "type": "string", - "format": "date-time" - }, - "status": { - "$ref": "#/components/schemas/IndexerStatusResource" - }, - "sortName": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "IndexerStatistics": { - "type": "object", - "properties": { - "indexerId": { - "type": "integer", - "format": "int32" - }, - "indexerName": { - "type": "string", - "nullable": true - }, - "averageResponseTime": { - "type": "integer", - "format": "int32" - }, - "numberOfQueries": { - "type": "integer", - "format": "int32" - }, - "numberOfGrabs": { - "type": "integer", - "format": "int32" - }, - "numberOfRssQueries": { - "type": "integer", - "format": "int32" - }, - "numberOfAuthQueries": { - "type": "integer", - "format": "int32" - }, - "numberOfFailedQueries": { - "type": "integer", - "format": "int32" - }, - "numberOfFailedGrabs": { - "type": "integer", - "format": "int32" - }, - "numberOfFailedRssQueries": { - "type": "integer", - "format": "int32" - }, - "numberOfFailedAuthQueries": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "IndexerStatsResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "indexers": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerStatistics" - }, - "nullable": true - }, - "userAgents": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserAgentStatistics" - }, - "nullable": true - }, - "hosts": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HostStatistics" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "IndexerStatusResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "indexerId": { - "type": "integer", - "format": "int32" - }, - "disabledTill": { - "type": "string", - "format": "date-time", - "nullable": true - } - }, - "additionalProperties": false - }, - "LanguageResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string", - "nullable": true - }, - "nameLower": { - "type": "string", - "nullable": true, - "readOnly": true - } - }, - "additionalProperties": false - }, - "LogFileResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "filename": { - "type": "string", - "nullable": true - }, - "lastWriteTime": { - "type": "string", - "format": "date-time" - }, - "contentsUrl": { - "type": "string", - "nullable": true - }, - "downloadUrl": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "LogResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "time": { - "type": "string", - "format": "date-time" - }, - "exception": { - "type": "string", - "nullable": true - }, - "exceptionType": { - "type": "string", - "nullable": true - }, - "level": { - "type": "string", - "nullable": true - }, - "logger": { - "type": "string", - "nullable": true - }, - "message": { - "type": "string", - "nullable": true - }, - "method": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "LogResourcePagingResource": { - "type": "object", - "properties": { - "page": { - "type": "integer", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "format": "int32" - }, - "sortKey": { - "type": "string", - "nullable": true - }, - "sortDirection": { - "$ref": "#/components/schemas/SortDirection" - }, - "filters": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PagingResourceFilter" - }, - "nullable": true - }, - "totalRecords": { - "type": "integer", - "format": "int32" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/LogResource" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "NotificationResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string", - "nullable": true - }, - "fields": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Field" - }, - "nullable": true - }, - "implementationName": { - "type": "string", - "nullable": true - }, - "implementation": { - "type": "string", - "nullable": true - }, - "configContract": { - "type": "string", - "nullable": true - }, - "infoLink": { - "type": "string", - "nullable": true - }, - "message": { - "$ref": "#/components/schemas/ProviderMessage" - }, - "tags": { - "uniqueItems": true, - "type": "array", - "items": { - "type": "integer", - "format": "int32" - }, - "nullable": true - }, - "presets": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NotificationResource" - }, - "nullable": true - }, - "link": { - "type": "string", - "nullable": true - }, - "onHealthIssue": { - "type": "boolean" - }, - "supportsOnHealthIssue": { - "type": "boolean" - }, - "includeHealthWarnings": { - "type": "boolean" - }, - "testCommand": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "PagingResourceFilter": { - "type": "object", - "properties": { - "key": { - "type": "string", - "nullable": true - }, - "value": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "ProviderMessage": { - "type": "object", - "properties": { - "message": { - "type": "string", - "nullable": true - }, - "type": { - "$ref": "#/components/schemas/ProviderMessageType" - } - }, - "additionalProperties": false - }, - "ProviderMessageType": { - "enum": [ - "info", - "warning", - "error" - ], - "type": "string" - }, - "ProxyType": { - "enum": [ - "http", - "socks4", - "socks5" - ], - "type": "string" - }, - "SearchResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "guid": { - "type": "string", - "nullable": true - }, - "age": { - "type": "integer", - "format": "int32" - }, - "ageHours": { - "type": "number", - "format": "double" - }, - "ageMinutes": { - "type": "number", - "format": "double" - }, - "size": { - "type": "integer", - "format": "int64" - }, - "files": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "grabs": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "indexerId": { - "type": "integer", - "format": "int32" - }, - "indexer": { - "type": "string", - "nullable": true - }, - "subGroup": { - "type": "string", - "nullable": true - }, - "releaseHash": { - "type": "string", - "nullable": true - }, - "title": { - "type": "string", - "nullable": true - }, - "approved": { - "type": "boolean" - }, - "imdbId": { - "type": "integer", - "format": "int32" - }, - "publishDate": { - "type": "string", - "format": "date-time" - }, - "commentUrl": { - "type": "string", - "nullable": true - }, - "downloadUrl": { - "type": "string", - "nullable": true - }, - "infoUrl": { - "type": "string", - "nullable": true - }, - "posterUrl": { - "type": "string", - "nullable": true - }, - "indexerFlags": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "categories": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerCategory" - }, - "nullable": true - }, - "magnetUrl": { - "type": "string", - "nullable": true - }, - "infoHash": { - "type": "string", - "nullable": true - }, - "seeders": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "leechers": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "protocol": { - "$ref": "#/components/schemas/DownloadProtocol" - } - }, - "additionalProperties": false - }, - "SelectOption": { - "type": "object", - "properties": { - "value": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string", - "nullable": true - }, - "order": { - "type": "integer", - "format": "int32" - }, - "hint": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "SortDirection": { - "enum": [ - "default", - "ascending", - "descending" - ], - "type": "string" - }, - "TagDetailsResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "label": { - "type": "string", - "nullable": true - }, - "notificationIds": { - "type": "array", - "items": { - "type": "integer", - "format": "int32" - }, - "nullable": true - }, - "indexerIds": { - "type": "array", - "items": { - "type": "integer", - "format": "int32" - }, - "nullable": true - }, - "indexerProxyIds": { - "type": "array", - "items": { - "type": "integer", - "format": "int32" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "TagResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "label": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "TaskResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string", - "nullable": true - }, - "taskName": { - "type": "string", - "nullable": true - }, - "interval": { - "type": "integer", - "format": "int32" - }, - "lastExecution": { - "type": "string", - "format": "date-time" - }, - "lastStartTime": { - "type": "string", - "format": "date-time" - }, - "nextExecution": { - "type": "string", - "format": "date-time" - }, - "lastDuration": { - "$ref": "#/components/schemas/TimeSpan" - } - }, - "additionalProperties": false - }, - "TimeSpan": { - "type": "object", - "properties": { - "ticks": { - "type": "integer", - "format": "int64", - "readOnly": true - }, - "days": { - "type": "integer", - "format": "int32", - "readOnly": true - }, - "hours": { - "type": "integer", - "format": "int32", - "readOnly": true - }, - "milliseconds": { - "type": "integer", - "format": "int32", - "readOnly": true - }, - "minutes": { - "type": "integer", - "format": "int32", - "readOnly": true - }, - "seconds": { - "type": "integer", - "format": "int32", - "readOnly": true - }, - "totalDays": { - "type": "number", - "format": "double", - "readOnly": true - }, - "totalHours": { - "type": "number", - "format": "double", - "readOnly": true - }, - "totalMilliseconds": { - "type": "number", - "format": "double", - "readOnly": true - }, - "totalMinutes": { - "type": "number", - "format": "double", - "readOnly": true - }, - "totalSeconds": { - "type": "number", - "format": "double", - "readOnly": true - } - }, - "additionalProperties": false - }, - "UiConfigResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "firstDayOfWeek": { - "type": "integer", - "format": "int32" - }, - "calendarWeekColumnHeader": { - "type": "string", - "nullable": true - }, - "shortDateFormat": { - "type": "string", - "nullable": true - }, - "longDateFormat": { - "type": "string", - "nullable": true - }, - "timeFormat": { - "type": "string", - "nullable": true - }, - "showRelativeDates": { - "type": "boolean" - }, - "enableColorImpairedMode": { - "type": "boolean" - }, - "movieInfoLanguage": { - "type": "integer", - "format": "int32" - }, - "uiLanguage": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "UpdateChanges": { - "type": "object", - "properties": { - "new": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "fixed": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "UpdateMechanism": { - "enum": [ - "builtIn", - "script", - "external", - "apt", - "docker" - ], - "type": "string" - }, - "UpdateResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "version": { - "$ref": "#/components/schemas/Version" - }, - "branch": { - "type": "string", - "nullable": true - }, - "releaseDate": { - "type": "string", - "format": "date-time" - }, - "fileName": { - "type": "string", - "nullable": true - }, - "url": { - "type": "string", - "nullable": true - }, - "installed": { - "type": "boolean" - }, - "installedOn": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "installable": { - "type": "boolean" - }, - "latest": { - "type": "boolean" - }, - "changes": { - "$ref": "#/components/schemas/UpdateChanges" - }, - "hash": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "UserAgentStatistics": { - "type": "object", - "properties": { - "userAgent": { - "type": "string", - "nullable": true - }, - "numberOfQueries": { - "type": "integer", - "format": "int32" - }, - "numberOfGrabs": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "Version": { - "type": "object", - "properties": { - "major": { - "type": "integer", - "format": "int32", - "readOnly": true - }, - "minor": { - "type": "integer", - "format": "int32", - "readOnly": true - }, - "build": { - "type": "integer", - "format": "int32", - "readOnly": true - }, - "revision": { - "type": "integer", - "format": "int32", - "readOnly": true - }, - "majorRevision": { - "type": "integer", - "format": "int32", - "readOnly": true - }, - "minorRevision": { - "type": "integer", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false - } - } - } -} \ No newline at end of file From 38fcffe871ed86693e6f2549404ed5c159099aa8 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 28 Dec 2021 13:58:57 -0600 Subject: [PATCH 0258/2320] Identify user for git --- azure-pipelines.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 14749108f..e9ea6e4e8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -844,10 +844,15 @@ stages: - checkout: self # Need history for Sonar analysis submodules: true - bash: ./docs.sh Windows - displayName: Create Openapi.json - - bash: git commit -am 'Automated API Docs update' - displayName: Commit APIDoc Change + displayName: Create openapi.json + - bash: | + git config --global user.email "development@lidarr.audio" + git config --global user.name "Servarr" + git add . + git commit -m 'Automated API Docs update' + displayName: Commit API Doc Change - task: CreatePullRequest@1 + displayName: PR Change to Github inputs: repoType: 'GitHub' githubEndpoint: 'github release' From 8a38e124fd160013c4b7c27dd6c35b69e9b83423 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 28 Dec 2021 14:45:28 -0600 Subject: [PATCH 0259/2320] Speed up Checkout for Docs job --- azure-pipelines.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e9ea6e4e8..393bc4bf7 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -841,8 +841,9 @@ stages: displayName: 'Install .net core' inputs: version: $(dotnetVersion) - - checkout: self # Need history for Sonar analysis - submodules: true + - checkout: self + submodules: true + fetchDepth: 1 - bash: ./docs.sh Windows displayName: Create openapi.json - bash: | From 97956ce951ffc1428ab73376f04d65b794c84d5b Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 28 Dec 2021 15:10:56 -0600 Subject: [PATCH 0260/2320] Branch and push prior to PR --- azure-pipelines.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 393bc4bf7..ef4be60b2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -843,14 +843,17 @@ stages: version: $(dotnetVersion) - checkout: self submodules: true + persistCredentials: true fetchDepth: 1 - bash: ./docs.sh Windows displayName: Create openapi.json - bash: | git config --global user.email "development@lidarr.audio" git config --global user.name "Servarr" + git checkout -b api-docs git add . git commit -m 'Automated API Docs update' + git push -f displayName: Commit API Doc Change - task: CreatePullRequest@1 displayName: PR Change to Github From de7505bbe6787a26742de440cfe49bf78badbef4 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 28 Dec 2021 15:19:34 -0600 Subject: [PATCH 0261/2320] correctly push upstream --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ef4be60b2..4049f9885 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -853,7 +853,7 @@ stages: git checkout -b api-docs git add . git commit -m 'Automated API Docs update' - git push -f + git push --set-upstream origin api-docs displayName: Commit API Doc Change - task: CreatePullRequest@1 displayName: PR Change to Github From ca67a40c729eff34c015d0656ea54528fa8bd082 Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Tue, 28 Dec 2021 21:32:38 +0000 Subject: [PATCH 0262/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 6798 ++++++++++++++++++++++++++++++ 1 file changed, 6798 insertions(+) create mode 100644 src/Prowlarr.Api.V1/openapi.json diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json new file mode 100644 index 000000000..96956d868 --- /dev/null +++ b/src/Prowlarr.Api.V1/openapi.json @@ -0,0 +1,6798 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "Prowlarr", + "description": "Prowlarr API docs", + "license": { + "name": "GPL-3.0", + "url": "https://github.com/Prowlarr/Prowlarr/blob/develop/LICENSE" + }, + "version": "1.0.0" + }, + "paths": { + "/api/v1/applications/{id}": { + "get": { + "tags": [ + "Application" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "Application" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Application" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/applications": { + "get": { + "tags": [ + "Application" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Application" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + } + } + } + }, + "/api/v1/applications/schema": { + "get": { + "tags": [ + "Application" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + } + } + } + } + }, + "/api/v1/applications/test": { + "post": { + "tags": [ + "Application" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/applications/testall": { + "post": { + "tags": [ + "Application" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/applications/action/{name}": { + "post": { + "tags": [ + "Application" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ApplicationResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/appprofile": { + "post": { + "tags": [ + "AppProfile" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "AppProfile" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + } + } + } + } + }, + "/api/v1/appprofile/{id}": { + "delete": { + "tags": [ + "AppProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "put": { + "tags": [ + "AppProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "AppProfile" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + }, + "500": { + "description": "Server Error" + } + } + } + }, + "/login": { + "post": { + "tags": [ + "Authentication" + ], + "parameters": [ + { + "name": "returnUrl", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "Username": { + "type": "string" + }, + "Password": { + "type": "string" + }, + "RememberMe": { + "type": "string" + } + } + }, + "encoding": { + "Username": { + "style": "form" + }, + "Password": { + "style": "form" + }, + "RememberMe": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + }, + "get": { + "tags": [ + "StaticResource" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/logout": { + "get": { + "tags": [ + "Authentication" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/system/backup": { + "get": { + "tags": [ + "Backup" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackupResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackupResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackupResource" + } + } + } + } + } + } + } + }, + "/api/v1/system/backup/{id}": { + "delete": { + "tags": [ + "Backup" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/system/backup/restore/{id}": { + "post": { + "tags": [ + "Backup" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/system/backup/restore/upload": { + "post": { + "tags": [ + "Backup" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/command/{id}": { + "get": { + "tags": [ + "Command" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Command" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/command": { + "post": { + "tags": [ + "Command" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CommandResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "Command" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommandResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommandResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommandResource" + } + } + } + } + } + } + } + }, + "/api/v1/customfilter/{id}": { + "get": { + "tags": [ + "CustomFilter" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "CustomFilter" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "CustomFilter" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/customfilter": { + "get": { + "tags": [ + "CustomFilter" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "CustomFilter" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomFilterResource" + } + } + } + } + } + } + }, + "/api/v1/config/development/{id}": { + "put": { + "tags": [ + "DevelopmentConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "DevelopmentConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/development": { + "get": { + "tags": [ + "DevelopmentConfig" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DevelopmentConfigResource" + } + } + } + } + } + } + }, + "/api/v1/downloadclient/{id}": { + "get": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/downloadclient": { + "get": { + "tags": [ + "DownloadClient" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "DownloadClient" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + } + }, + "/api/v1/downloadclient/schema": { + "get": { + "tags": [ + "DownloadClient" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + } + } + } + } + }, + "/api/v1/downloadclient/test": { + "post": { + "tags": [ + "DownloadClient" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/downloadclient/testall": { + "post": { + "tags": [ + "DownloadClient" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/downloadclient/action/{name}": { + "post": { + "tags": [ + "DownloadClient" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/config/downloadclient/{id}": { + "get": { + "tags": [ + "DownloadClientConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "DownloadClientConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/downloadclient": { + "get": { + "tags": [ + "DownloadClientConfig" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DownloadClientConfigResource" + } + } + } + } + } + } + }, + "/api/v1/filesystem": { + "get": { + "tags": [ + "FileSystem" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "includeFiles", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "allowFoldersWithoutTrailingSlashes", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/filesystem/type": { + "get": { + "tags": [ + "FileSystem" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/health/{id}": { + "get": { + "tags": [ + "Health" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/HealthResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/HealthResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HealthResource" + } + } + } + } + } + } + }, + "/api/v1/health": { + "get": { + "tags": [ + "Health" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HealthResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HealthResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HealthResource" + } + } + } + } + } + } + } + }, + "/api/v1/history": { + "get": { + "tags": [ + "History" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/HistoryResourcePagingResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/HistoryResourcePagingResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HistoryResourcePagingResource" + } + } + } + } + } + } + }, + "/api/v1/history/since": { + "get": { + "tags": [ + "History" + ], + "parameters": [ + { + "name": "date", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "eventType", + "in": "query", + "schema": { + "$ref": "#/components/schemas/HistoryEventType" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + } + } + } + } + } + }, + "/api/v1/history/indexer": { + "get": { + "tags": [ + "History" + ], + "parameters": [ + { + "name": "indexerId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "eventType", + "in": "query", + "schema": { + "$ref": "#/components/schemas/HistoryEventType" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + } + } + } + } + } + } + } + }, + "/api/v1/config/host/{id}": { + "get": { + "tags": [ + "HostConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "HostConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/host": { + "get": { + "tags": [ + "HostConfig" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HostConfigResource" + } + } + } + } + } + } + }, + "/api/v1/indexer/{id}": { + "get": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexer": { + "get": { + "tags": [ + "Indexer" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Indexer" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + } + }, + "/api/v1/indexer/schema": { + "get": { + "tags": [ + "Indexer" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + } + } + } + } + }, + "/api/v1/indexer/test": { + "post": { + "tags": [ + "Indexer" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexer/testall": { + "post": { + "tags": [ + "Indexer" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexer/action/{name}": { + "post": { + "tags": [ + "Indexer" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexer/categories": { + "get": { + "tags": [ + "IndexerDefaultCategories" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerCategory" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerCategory" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerCategory" + } + } + } + } + } + } + } + }, + "/api/v1/indexer/editor": { + "put": { + "tags": [ + "IndexerEditor" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerEditorResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerEditorResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerEditorResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "IndexerEditor" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerEditorResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerEditorResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerEditorResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexerproxy/{id}": { + "get": { + "tags": [ + "IndexerProxy" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "IndexerProxy" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "IndexerProxy" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexerproxy": { + "get": { + "tags": [ + "IndexerProxy" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "IndexerProxy" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + } + } + } + }, + "/api/v1/indexerproxy/schema": { + "get": { + "tags": [ + "IndexerProxy" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + } + } + } + } + }, + "/api/v1/indexerproxy/test": { + "post": { + "tags": [ + "IndexerProxy" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexerproxy/testall": { + "post": { + "tags": [ + "IndexerProxy" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexerproxy/action/{name}": { + "post": { + "tags": [ + "IndexerProxy" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/IndexerProxyResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexerstats": { + "get": { + "tags": [ + "IndexerStats" + ], + "parameters": [ + { + "name": "startDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "endDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerStatsResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerStatsResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerStatsResource" + } + } + } + } + } + } + }, + "/api/v1/indexerstatus/{id}": { + "get": { + "tags": [ + "IndexerStatus" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/IndexerStatusResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexerStatusResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/IndexerStatusResource" + } + } + } + } + } + } + }, + "/api/v1/indexerstatus": { + "get": { + "tags": [ + "IndexerStatus" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerStatusResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerStatusResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerStatusResource" + } + } + } + } + } + } + } + }, + "/initialize.js": { + "get": { + "tags": [ + "InitializeJs" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/language/{id}": { + "get": { + "tags": [ + "Language" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/LanguageResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/LanguageResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/LanguageResource" + } + } + } + } + } + } + }, + "/api/v1/language": { + "get": { + "tags": [ + "Language" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LanguageResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LanguageResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LanguageResource" + } + } + } + } + } + } + } + }, + "/api/v1/localization": { + "get": { + "tags": [ + "Localization" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + }, + "application/json": { + "schema": { + "type": "string" + } + }, + "text/json": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/api/v1/log": { + "get": { + "tags": [ + "Log" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/LogResourcePagingResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/LogResourcePagingResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/LogResourcePagingResource" + } + } + } + } + } + } + }, + "/api/v1/log/file": { + "get": { + "tags": [ + "LogFile" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + } + } + } + } + } + }, + "/api/v1/log/file/{filename}": { + "get": { + "tags": [ + "LogFile" + ], + "parameters": [ + { + "name": "filename", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexer/{id}/newznab": { + "get": { + "tags": [ + "Newznab" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "t", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "q", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "cat", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "imdbid", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "tmdbid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "extended", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "offset", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "rid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tvmazeid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "traktid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tvdbid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "season", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "ep", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "album", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "artist", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "label", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "track", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "year", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "genre", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "author", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "title", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "configured", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "source", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "host", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "server", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/{id}/api": { + "get": { + "tags": [ + "Newznab" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "t", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "q", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "cat", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "imdbid", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "tmdbid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "extended", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "offset", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "rid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tvmazeid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "traktid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tvdbid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "season", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "ep", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "album", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "artist", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "label", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "track", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "year", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "genre", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "author", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "title", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "configured", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "source", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "host", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "server", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/indexer/{id}/download": { + "get": { + "tags": [ + "Newznab" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "link", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "file", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/{id}/download": { + "get": { + "tags": [ + "Newznab" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "link", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "file", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/notification/{id}": { + "get": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/notification": { + "get": { + "tags": [ + "Notification" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Notification" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + } + }, + "/api/v1/notification/schema": { + "get": { + "tags": [ + "Notification" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + } + } + } + } + }, + "/api/v1/notification/test": { + "post": { + "tags": [ + "Notification" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/notification/testall": { + "post": { + "tags": [ + "Notification" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/notification/action/{name}": { + "post": { + "tags": [ + "Notification" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/NotificationResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/appprofile/schema": { + "get": { + "tags": [ + "QualityProfileSchema" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AppProfileResource" + } + } + } + } + } + } + }, + "/api/v1/search/{id}": { + "get": { + "tags": [ + "Search" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + } + } + } + } + } + }, + "/api/v1/search": { + "post": { + "tags": [ + "Search" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "Search" + ], + "parameters": [ + { + "name": "query", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "indexerIds", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "categories", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "type", + "in": "query", + "schema": { + "type": "string", + "default": "search" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchResource" + } + } + } + } + } + } + } + }, + "/api/v1/search/bulk": { + "post": { + "tags": [ + "Search" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchResource" + } + } + }, + "application/*+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchResource" + } + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/SearchResource" + } + } + } + } + } + } + }, + "/content/{path}": { + "get": { + "tags": [ + "StaticResource" + ], + "parameters": [ + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/": { + "get": { + "tags": [ + "StaticResource" + ], + "parameters": [ + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/{path}": { + "get": { + "tags": [ + "StaticResource" + ], + "parameters": [ + { + "name": "path", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/system/status": { + "get": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/system/routes": { + "get": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/system/routes/duplicate": { + "get": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/system/shutdown": { + "post": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/system/restart": { + "post": { + "tags": [ + "System" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/tag/{id}": { + "get": { + "tags": [ + "Tag" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "Tag" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Tag" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/v1/tag": { + "get": { + "tags": [ + "Tag" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagResource" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "Tag" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TagResource" + } + } + } + } + } + } + }, + "/api/v1/tag/detail/{id}": { + "get": { + "tags": [ + "TagDetails" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/TagDetailsResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagDetailsResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TagDetailsResource" + } + } + } + } + } + } + }, + "/api/v1/tag/detail": { + "get": { + "tags": [ + "TagDetails" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDetailsResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDetailsResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagDetailsResource" + } + } + } + } + } + } + } + }, + "/api/v1/system/task": { + "get": { + "tags": [ + "Task" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskResource" + } + } + } + } + } + } + } + }, + "/api/v1/system/task/{id}": { + "get": { + "tags": [ + "Task" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/TaskResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TaskResource" + } + } + } + } + } + } + }, + "/api/v1/config/ui/{id}": { + "get": { + "tags": [ + "UiConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "UiConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + } + } + } + }, + "/api/v1/config/ui": { + "get": { + "tags": [ + "UiConfig" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + } + } + } + }, + "/api/v1/update": { + "get": { + "tags": [ + "Update" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateResource" + } + } + } + } + } + } + } + }, + "/api/v1/log/file/update": { + "get": { + "tags": [ + "UpdateLogFile" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogFileResource" + } + } + } + } + } + } + } + }, + "/api/v1/log/file/update/{filename}": { + "get": { + "tags": [ + "UpdateLogFile" + ], + "parameters": [ + { + "name": "filename", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + }, + "components": { + "schemas": { + "ApplicationResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationResource" + }, + "nullable": true + }, + "syncLevel": { + "$ref": "#/components/schemas/ApplicationSyncLevel" + }, + "testCommand": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "ApplicationSyncLevel": { + "enum": [ + "disabled", + "addOnly", + "fullSync" + ], + "type": "string" + }, + "ApplyTags": { + "enum": [ + "add", + "remove", + "replace" + ], + "type": "string" + }, + "AppProfileResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "enableRss": { + "type": "boolean" + }, + "enableInteractiveSearch": { + "type": "boolean" + }, + "enableAutomaticSearch": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "AuthenticationType": { + "enum": [ + "none", + "basic", + "forms" + ], + "type": "string" + }, + "BackupResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "path": { + "type": "string", + "nullable": true + }, + "type": { + "$ref": "#/components/schemas/BackupType" + }, + "time": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "BackupType": { + "enum": [ + "scheduled", + "manual", + "update" + ], + "type": "string" + }, + "CertificateValidationType": { + "enum": [ + "enabled", + "disabledForLocalAddresses", + "disabled" + ], + "type": "string" + }, + "Command": { + "type": "object", + "properties": { + "sendUpdatesToClient": { + "type": "boolean" + }, + "updateScheduledTask": { + "type": "boolean", + "readOnly": true + }, + "completionMessage": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "requiresDiskAccess": { + "type": "boolean", + "readOnly": true + }, + "isExclusive": { + "type": "boolean", + "readOnly": true + }, + "isTypeExclusive": { + "type": "boolean", + "readOnly": true + }, + "name": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "lastExecutionTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "lastStartTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "trigger": { + "$ref": "#/components/schemas/CommandTrigger" + }, + "suppressMessages": { + "type": "boolean" + }, + "clientUserAgent": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "CommandPriority": { + "enum": [ + "normal", + "high", + "low" + ], + "type": "string" + }, + "CommandResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "commandName": { + "type": "string", + "nullable": true + }, + "message": { + "type": "string", + "nullable": true + }, + "body": { + "$ref": "#/components/schemas/Command" + }, + "priority": { + "$ref": "#/components/schemas/CommandPriority" + }, + "status": { + "$ref": "#/components/schemas/CommandStatus" + }, + "queued": { + "type": "string", + "format": "date-time" + }, + "started": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "ended": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "duration": { + "$ref": "#/components/schemas/TimeSpan" + }, + "exception": { + "type": "string", + "nullable": true + }, + "trigger": { + "$ref": "#/components/schemas/CommandTrigger" + }, + "clientUserAgent": { + "type": "string", + "nullable": true + }, + "stateChangeTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "sendUpdatesToClient": { + "type": "boolean" + }, + "updateScheduledTask": { + "type": "boolean" + }, + "lastExecutionTime": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false + }, + "CommandStatus": { + "enum": [ + "queued", + "started", + "completed", + "failed", + "aborted", + "cancelled", + "orphaned" + ], + "type": "string" + }, + "CommandTrigger": { + "enum": [ + "unspecified", + "manual", + "scheduled" + ], + "type": "string" + }, + "CustomFilterResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "type": { + "type": "string", + "nullable": true + }, + "label": { + "type": "string", + "nullable": true + }, + "filters": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { } + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "DevelopmentConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "consoleLogLevel": { + "type": "string", + "nullable": true + }, + "logSql": { + "type": "boolean" + }, + "logIndexerResponse": { + "type": "boolean" + }, + "logRotate": { + "type": "integer", + "format": "int32" + }, + "filterSentryEvents": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "DownloadClientConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "downloadClientWorkingFolders": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "DownloadClientResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientResource" + }, + "nullable": true + }, + "enable": { + "type": "boolean" + }, + "protocol": { + "$ref": "#/components/schemas/DownloadProtocol" + }, + "priority": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "DownloadProtocol": { + "enum": [ + "unknown", + "usenet", + "torrent" + ], + "type": "string" + }, + "Field": { + "type": "object", + "properties": { + "order": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "label": { + "type": "string", + "nullable": true + }, + "unit": { + "type": "string", + "nullable": true + }, + "helpText": { + "type": "string", + "nullable": true + }, + "helpLink": { + "type": "string", + "nullable": true + }, + "value": { + "nullable": true + }, + "type": { + "type": "string", + "nullable": true + }, + "advanced": { + "type": "boolean" + }, + "selectOptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SelectOption" + }, + "nullable": true + }, + "selectOptionsProviderAction": { + "type": "string", + "nullable": true + }, + "section": { + "type": "string", + "nullable": true + }, + "hidden": { + "type": "string", + "nullable": true + }, + "placeholder": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "HealthCheckResult": { + "enum": [ + "ok", + "notice", + "warning", + "error" + ], + "type": "string" + }, + "HealthResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "source": { + "type": "string", + "nullable": true + }, + "type": { + "$ref": "#/components/schemas/HealthCheckResult" + }, + "message": { + "type": "string", + "nullable": true + }, + "wikiUrl": { + "$ref": "#/components/schemas/HttpUri" + } + }, + "additionalProperties": false + }, + "HistoryEventType": { + "enum": [ + "unknown", + "releaseGrabbed", + "indexerQuery", + "indexerRss", + "indexerAuth", + "indexerInfo" + ], + "type": "string" + }, + "HistoryResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "indexerId": { + "type": "integer", + "format": "int32" + }, + "date": { + "type": "string", + "format": "date-time" + }, + "downloadId": { + "type": "string", + "nullable": true + }, + "successful": { + "type": "boolean" + }, + "eventType": { + "$ref": "#/components/schemas/HistoryEventType" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "HistoryResourcePagingResource": { + "type": "object", + "properties": { + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "sortKey": { + "type": "string", + "nullable": true + }, + "sortDirection": { + "$ref": "#/components/schemas/SortDirection" + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PagingResourceFilter" + }, + "nullable": true + }, + "totalRecords": { + "type": "integer", + "format": "int32" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryResource" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "HostConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "bindAddress": { + "type": "string", + "nullable": true + }, + "port": { + "type": "integer", + "format": "int32" + }, + "sslPort": { + "type": "integer", + "format": "int32" + }, + "enableSsl": { + "type": "boolean" + }, + "launchBrowser": { + "type": "boolean" + }, + "authenticationMethod": { + "$ref": "#/components/schemas/AuthenticationType" + }, + "analyticsEnabled": { + "type": "boolean" + }, + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "logLevel": { + "type": "string", + "nullable": true + }, + "consoleLogLevel": { + "type": "string", + "nullable": true + }, + "branch": { + "type": "string", + "nullable": true + }, + "apiKey": { + "type": "string", + "nullable": true + }, + "sslCertPath": { + "type": "string", + "nullable": true + }, + "sslCertPassword": { + "type": "string", + "nullable": true + }, + "urlBase": { + "type": "string", + "nullable": true + }, + "updateAutomatically": { + "type": "boolean" + }, + "updateMechanism": { + "$ref": "#/components/schemas/UpdateMechanism" + }, + "updateScriptPath": { + "type": "string", + "nullable": true + }, + "proxyEnabled": { + "type": "boolean" + }, + "proxyType": { + "$ref": "#/components/schemas/ProxyType" + }, + "proxyHostname": { + "type": "string", + "nullable": true + }, + "proxyPort": { + "type": "integer", + "format": "int32" + }, + "proxyUsername": { + "type": "string", + "nullable": true + }, + "proxyPassword": { + "type": "string", + "nullable": true + }, + "proxyBypassFilter": { + "type": "string", + "nullable": true + }, + "proxyBypassLocalAddresses": { + "type": "boolean" + }, + "certificateValidation": { + "$ref": "#/components/schemas/CertificateValidationType" + }, + "backupFolder": { + "type": "string", + "nullable": true + }, + "backupInterval": { + "type": "integer", + "format": "int32" + }, + "backupRetention": { + "type": "integer", + "format": "int32" + }, + "historyCleanupDays": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "HostStatistics": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true + }, + "numberOfQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfGrabs": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "HttpUri": { + "type": "object", + "properties": { + "fullUri": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "scheme": { + "type": "string", + "nullable": true + }, + "host": { + "type": "string", + "nullable": true + }, + "port": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "path": { + "type": "string", + "nullable": true + }, + "query": { + "type": "string", + "nullable": true + }, + "fragment": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "IndexerCapabilityResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "limitsMax": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "limitsDefault": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "categories": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerCategory" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "IndexerCategory": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "description": { + "type": "string", + "nullable": true + }, + "subCategories": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerCategory" + }, + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "IndexerEditorResource": { + "type": "object", + "properties": { + "indexerIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "enable": { + "type": "string", + "nullable": true + }, + "appProfileId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "tags": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "applyTags": { + "$ref": "#/components/schemas/ApplyTags" + } + }, + "additionalProperties": false + }, + "IndexerPrivacy": { + "enum": [ + "public", + "semiPublic", + "private" + ], + "type": "string" + }, + "IndexerProxyResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerProxyResource" + }, + "nullable": true + }, + "link": { + "type": "string", + "nullable": true + }, + "onHealthIssue": { + "type": "boolean" + }, + "supportsOnHealthIssue": { + "type": "boolean" + }, + "includeHealthWarnings": { + "type": "boolean" + }, + "testCommand": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "IndexerResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerResource" + }, + "nullable": true + }, + "indexerUrls": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "description": { + "type": "string", + "nullable": true + }, + "language": { + "type": "string", + "nullable": true + }, + "encoding": { + "type": "string", + "nullable": true + }, + "enable": { + "type": "boolean" + }, + "redirect": { + "type": "boolean" + }, + "supportsRss": { + "type": "boolean" + }, + "supportsSearch": { + "type": "boolean" + }, + "supportsRedirect": { + "type": "boolean" + }, + "appProfileId": { + "type": "integer", + "format": "int32" + }, + "protocol": { + "$ref": "#/components/schemas/DownloadProtocol" + }, + "privacy": { + "$ref": "#/components/schemas/IndexerPrivacy" + }, + "capabilities": { + "$ref": "#/components/schemas/IndexerCapabilityResource" + }, + "priority": { + "type": "integer", + "format": "int32" + }, + "added": { + "type": "string", + "format": "date-time" + }, + "status": { + "$ref": "#/components/schemas/IndexerStatusResource" + }, + "sortName": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "IndexerStatistics": { + "type": "object", + "properties": { + "indexerId": { + "type": "integer", + "format": "int32" + }, + "indexerName": { + "type": "string", + "nullable": true + }, + "averageResponseTime": { + "type": "integer", + "format": "int32" + }, + "numberOfQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfGrabs": { + "type": "integer", + "format": "int32" + }, + "numberOfRssQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfAuthQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfFailedQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfFailedGrabs": { + "type": "integer", + "format": "int32" + }, + "numberOfFailedRssQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfFailedAuthQueries": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "IndexerStatsResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "indexers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerStatistics" + }, + "nullable": true + }, + "userAgents": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserAgentStatistics" + }, + "nullable": true + }, + "hosts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HostStatistics" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "IndexerStatusResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "indexerId": { + "type": "integer", + "format": "int32" + }, + "disabledTill": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false + }, + "LanguageResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "nameLower": { + "type": "string", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "LogFileResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "filename": { + "type": "string", + "nullable": true + }, + "lastWriteTime": { + "type": "string", + "format": "date-time" + }, + "contentsUrl": { + "type": "string", + "nullable": true + }, + "downloadUrl": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LogResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "time": { + "type": "string", + "format": "date-time" + }, + "exception": { + "type": "string", + "nullable": true + }, + "exceptionType": { + "type": "string", + "nullable": true + }, + "level": { + "type": "string", + "nullable": true + }, + "logger": { + "type": "string", + "nullable": true + }, + "message": { + "type": "string", + "nullable": true + }, + "method": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LogResourcePagingResource": { + "type": "object", + "properties": { + "page": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "sortKey": { + "type": "string", + "nullable": true + }, + "sortDirection": { + "$ref": "#/components/schemas/SortDirection" + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PagingResourceFilter" + }, + "nullable": true + }, + "totalRecords": { + "type": "integer", + "format": "int32" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LogResource" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "NotificationResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Field" + }, + "nullable": true + }, + "implementationName": { + "type": "string", + "nullable": true + }, + "implementation": { + "type": "string", + "nullable": true + }, + "configContract": { + "type": "string", + "nullable": true + }, + "infoLink": { + "type": "string", + "nullable": true + }, + "message": { + "$ref": "#/components/schemas/ProviderMessage" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "presets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationResource" + }, + "nullable": true + }, + "link": { + "type": "string", + "nullable": true + }, + "onHealthIssue": { + "type": "boolean" + }, + "onApplicationUpdate": { + "type": "boolean" + }, + "supportsOnHealthIssue": { + "type": "boolean" + }, + "includeHealthWarnings": { + "type": "boolean" + }, + "supportsOnApplicationUpdate": { + "type": "boolean" + }, + "testCommand": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "PagingResourceFilter": { + "type": "object", + "properties": { + "key": { + "type": "string", + "nullable": true + }, + "value": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "ProviderMessage": { + "type": "object", + "properties": { + "message": { + "type": "string", + "nullable": true + }, + "type": { + "$ref": "#/components/schemas/ProviderMessageType" + } + }, + "additionalProperties": false + }, + "ProviderMessageType": { + "enum": [ + "info", + "warning", + "error" + ], + "type": "string" + }, + "ProxyType": { + "enum": [ + "http", + "socks4", + "socks5" + ], + "type": "string" + }, + "SearchResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "guid": { + "type": "string", + "nullable": true + }, + "age": { + "type": "integer", + "format": "int32" + }, + "ageHours": { + "type": "number", + "format": "double" + }, + "ageMinutes": { + "type": "number", + "format": "double" + }, + "size": { + "type": "integer", + "format": "int64" + }, + "files": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "grabs": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "indexerId": { + "type": "integer", + "format": "int32" + }, + "indexer": { + "type": "string", + "nullable": true + }, + "subGroup": { + "type": "string", + "nullable": true + }, + "releaseHash": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "approved": { + "type": "boolean" + }, + "imdbId": { + "type": "integer", + "format": "int32" + }, + "publishDate": { + "type": "string", + "format": "date-time" + }, + "commentUrl": { + "type": "string", + "nullable": true + }, + "downloadUrl": { + "type": "string", + "nullable": true + }, + "infoUrl": { + "type": "string", + "nullable": true + }, + "posterUrl": { + "type": "string", + "nullable": true + }, + "indexerFlags": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "categories": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexerCategory" + }, + "nullable": true + }, + "magnetUrl": { + "type": "string", + "nullable": true + }, + "infoHash": { + "type": "string", + "nullable": true + }, + "seeders": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "leechers": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "protocol": { + "$ref": "#/components/schemas/DownloadProtocol" + } + }, + "additionalProperties": false + }, + "SelectOption": { + "type": "object", + "properties": { + "value": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "order": { + "type": "integer", + "format": "int32" + }, + "hint": { + "type": "string", + "nullable": true + }, + "parentValue": { + "type": "integer", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false + }, + "SortDirection": { + "enum": [ + "default", + "ascending", + "descending" + ], + "type": "string" + }, + "TagDetailsResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "label": { + "type": "string", + "nullable": true + }, + "notificationIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "indexerIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "indexerProxyIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "TagResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "label": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "TaskResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "taskName": { + "type": "string", + "nullable": true + }, + "interval": { + "type": "integer", + "format": "int32" + }, + "lastExecution": { + "type": "string", + "format": "date-time" + }, + "lastStartTime": { + "type": "string", + "format": "date-time" + }, + "nextExecution": { + "type": "string", + "format": "date-time" + }, + "lastDuration": { + "$ref": "#/components/schemas/TimeSpan" + } + }, + "additionalProperties": false + }, + "TimeSpan": { + "type": "object", + "properties": { + "ticks": { + "type": "integer", + "format": "int64" + }, + "days": { + "type": "integer", + "format": "int32" + }, + "hours": { + "type": "integer", + "format": "int32" + }, + "milliseconds": { + "type": "integer", + "format": "int32" + }, + "minutes": { + "type": "integer", + "format": "int32" + }, + "seconds": { + "type": "integer", + "format": "int32" + }, + "totalDays": { + "type": "number", + "format": "double", + "readOnly": true + }, + "totalHours": { + "type": "number", + "format": "double", + "readOnly": true + }, + "totalMilliseconds": { + "type": "number", + "format": "double", + "readOnly": true + }, + "totalMinutes": { + "type": "number", + "format": "double", + "readOnly": true + }, + "totalSeconds": { + "type": "number", + "format": "double", + "readOnly": true + } + }, + "additionalProperties": false + }, + "UiConfigResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "firstDayOfWeek": { + "type": "integer", + "format": "int32" + }, + "calendarWeekColumnHeader": { + "type": "string", + "nullable": true + }, + "shortDateFormat": { + "type": "string", + "nullable": true + }, + "longDateFormat": { + "type": "string", + "nullable": true + }, + "timeFormat": { + "type": "string", + "nullable": true + }, + "showRelativeDates": { + "type": "boolean" + }, + "enableColorImpairedMode": { + "type": "boolean" + }, + "movieInfoLanguage": { + "type": "integer", + "format": "int32" + }, + "uiLanguage": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "UpdateChanges": { + "type": "object", + "properties": { + "new": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "fixed": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "UpdateMechanism": { + "enum": [ + "builtIn", + "script", + "external", + "apt", + "docker" + ], + "type": "string" + }, + "UpdateResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "version": { + "$ref": "#/components/schemas/Version" + }, + "branch": { + "type": "string", + "nullable": true + }, + "releaseDate": { + "type": "string", + "format": "date-time" + }, + "fileName": { + "type": "string", + "nullable": true + }, + "url": { + "type": "string", + "nullable": true + }, + "installed": { + "type": "boolean" + }, + "installedOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "installable": { + "type": "boolean" + }, + "latest": { + "type": "boolean" + }, + "changes": { + "$ref": "#/components/schemas/UpdateChanges" + }, + "hash": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "UserAgentStatistics": { + "type": "object", + "properties": { + "userAgent": { + "type": "string", + "nullable": true + }, + "numberOfQueries": { + "type": "integer", + "format": "int32" + }, + "numberOfGrabs": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "Version": { + "type": "object", + "properties": { + "major": { + "type": "integer", + "format": "int32" + }, + "minor": { + "type": "integer", + "format": "int32" + }, + "build": { + "type": "integer", + "format": "int32" + }, + "revision": { + "type": "integer", + "format": "int32" + }, + "majorRevision": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "minorRevision": { + "type": "integer", + "format": "int32", + "readOnly": true + } + }, + "additionalProperties": false + } + }, + "securitySchemes": { + "X-Api-Key": { + "type": "apiKey", + "description": "Apikey passed as header", + "name": "X-Api-Key", + "in": "header" + }, + "apikey": { + "type": "apiKey", + "description": "Apikey passed as header", + "name": "apikey", + "in": "query" + } + } + }, + "security": [ + { + "X-Api-Key": [ ] + }, + { + "apikey": [ ] + } + ] +} \ No newline at end of file From c57a91bc64e6d1a95eab584ec7529b25bd2c6002 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 28 Dec 2021 17:01:23 -0600 Subject: [PATCH 0263/2320] Skip build of doc only change, ignore PR errors for docs --- azure-pipelines.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 4049f9885..8df9eb651 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -29,6 +29,7 @@ pr: paths: exclude: - src/NzbDrone.Core/Localization/Core + - src/Prowlarr.API.*/openapi.json stages: - stage: Setup @@ -857,6 +858,7 @@ stages: displayName: Commit API Doc Change - task: CreatePullRequest@1 displayName: PR Change to Github + continueOnError: true inputs: repoType: 'GitHub' githubEndpoint: 'github release' From 177084fe8b7f5e413c752cf16f6e08c048ab4bdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Sj=C3=B6berg?= <ga22be@live.se> Date: Mon, 27 Dec 2021 23:20:49 +0100 Subject: [PATCH 0264/2320] Fixed: (Indexer) Update RARBG API query options * Added app_id to captcha check to avoid 403 forbidden error * Migrated app_id from hard coded to BuildInfo.AppName --- src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs | 3 ++- src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs | 3 ++- src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs | 3 ++- .../Indexers/Definitions/Rarbg/RarbgTokenProvider.cs | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs index 89e3eafb7..c9649ee52 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using FluentAssertions; using Moq; using NUnit.Framework; +using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Http; using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers.Rarbg; @@ -51,7 +52,7 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests torrentInfo.Title.Should().Be("Sense8.S01E01.WEBRip.x264-FGT"); torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent); torrentInfo.DownloadUrl.Should().Be("magnet:?xt=urn:btih:d8bde635f573acb390c7d7e7efc1556965fdc802&dn=Sense8.S01E01.WEBRip.x264-FGT&tr=http%3A%2F%2Ftracker.trackerfix.com%3A80%2Fannounce&tr=udp%3A%2F%2F9.rarbg.me%3A2710&tr=udp%3A%2F%2F9.rarbg.to%3A2710&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce"); - torrentInfo.InfoUrl.Should().Be("https://torrentapi.org/redirect_to_info.php?token=i5cx7b9agd&p=8_6_4_4_5_6__d8bde635f5&app_id=Prowlarr"); + torrentInfo.InfoUrl.Should().Be($"https://torrentapi.org/redirect_to_info.php?token=i5cx7b9agd&p=8_6_4_4_5_6__d8bde635f5&app_id={BuildInfo.AppName}"); torrentInfo.Indexer.Should().Be(Subject.Definition.Name); torrentInfo.PublishDate.Should().Be(DateTime.Parse("2015-06-05 16:58:11 +0000").ToUniversalTime()); torrentInfo.Size.Should().Be(564198371); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs index a0fb1ab53..4bb424ec9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using NLog; +using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; @@ -103,7 +104,7 @@ namespace NzbDrone.Core.Indexers.Rarbg try { var request = new HttpRequestBuilder(Settings.BaseUrl.Trim('/')) - .Resource("/pubapi_v2.php?get_token=get_token") + .Resource($"/pubapi_v2.php?get_token=get_token&app_id={BuildInfo.AppName}") .Accept(HttpAccept.Json) .Build(); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs index 41d1a5226..667e532a4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Net; using System.Text.RegularExpressions; +using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Http; using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Parser.Model; @@ -62,7 +63,7 @@ namespace NzbDrone.Core.Indexers.Rarbg torrentInfo.Title = torrent.title; torrentInfo.Size = torrent.size; torrentInfo.DownloadUrl = torrent.download; - torrentInfo.InfoUrl = torrent.info_page + "&app_id=Prowlarr"; + torrentInfo.InfoUrl = $"{torrent.info_page}&app_id={BuildInfo.AppName}"; torrentInfo.PublishDate = torrent.pubdate.ToUniversalTime(); torrentInfo.Seeders = torrent.seeders; torrentInfo.Peers = torrent.leechers + torrent.seeders; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs index 2319105a4..613aa1f39 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs @@ -2,6 +2,7 @@ using System; using Newtonsoft.Json.Linq; using NLog; using NzbDrone.Common.Cache; +using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; @@ -32,7 +33,7 @@ namespace NzbDrone.Core.Indexers.Rarbg { var requestBuilder = new HttpRequestBuilder(baseUrl.Trim('/')) .WithRateLimit(3.0) - .Resource("/pubapi_v2.php?get_token=get_token&app_id=Prowlarr") + .Resource($"/pubapi_v2.php?get_token=get_token&app_id={BuildInfo.AppName}") .Accept(HttpAccept.Json); if (settings.CaptchaToken.IsNotNullOrWhiteSpace()) From 9859b4a3d91a50100ceb19068f29473cd4c4b438 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 28 Dec 2021 17:37:30 -0600 Subject: [PATCH 0265/2320] force it --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8df9eb651..97efe7f01 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -854,7 +854,7 @@ stages: git checkout -b api-docs git add . git commit -m 'Automated API Docs update' - git push --set-upstream origin api-docs + git push -f --set-upstream origin api-docs displayName: Commit API Doc Change - task: CreatePullRequest@1 displayName: PR Change to Github From 01c7a0584168fc1d0d4fd64956858953b57b52cd Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 28 Dec 2021 17:49:12 -0600 Subject: [PATCH 0266/2320] Only push to api-docs when changes --- azure-pipelines.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 97efe7f01..be2d21e59 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -853,8 +853,13 @@ stages: git config --global user.name "Servarr" git checkout -b api-docs git add . - git commit -m 'Automated API Docs update' - git push -f --set-upstream origin api-docs + if git status | grep -q modified + then + git commit -am 'Automated API Docs update' + git push -f --set-upstream origin api-docs + else + echo "No changes since last run" + fi displayName: Commit API Doc Change - task: CreatePullRequest@1 displayName: PR Change to Github From 9bad31af8493dba9c3ec15242121514de56da665 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 28 Dec 2021 18:26:51 -0600 Subject: [PATCH 0267/2320] Eliminate PR Extension from pipeline --- azure-pipelines.yml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index be2d21e59..802b77ff9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -857,20 +857,14 @@ stages: then git commit -am 'Automated API Docs update' git push -f --set-upstream origin api-docs + curl -X POST -H 'Authorization: token $GITHUB_TOKEN' -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/prowlarr/prowlarr/pulls -d '{"head":"api-docs","base":"develop","title":"Update API docs"}' else echo "No changes since last run" fi - displayName: Commit API Doc Change - - task: CreatePullRequest@1 - displayName: PR Change to Github + displayName: Commit API Doc Change continueOnError: true - inputs: - repoType: 'GitHub' - githubEndpoint: 'github release' - githubRepository: '$(Build.Repository.Name)' - sourceBranch: 'api-docs' - targetBranch: 'develop' - title: 'Update API Docs' + env: + GITHUB_TOKEN: $(githubToken) - task: CopyFiles@2 displayName: 'Copy openapi.json to: $(Build.ArtifactStagingDirectory)' inputs: From 7f28f64cbee676ce289a8c00c37b23c73fc68e29 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 28 Dec 2021 18:47:44 -0600 Subject: [PATCH 0268/2320] Fix server settings on API docs --- src/NzbDrone.Host/Startup.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Host/Startup.cs b/src/NzbDrone.Host/Startup.cs index bd3a0ad7b..40b375ada 100644 --- a/src/NzbDrone.Host/Startup.cs +++ b/src/NzbDrone.Host/Startup.cs @@ -140,6 +140,16 @@ namespace NzbDrone.Host }, }; + c.AddServer(new OpenApiServer + { + Url = "{protocol}://{hostpath}", + Variables = new Dictionary<string, OpenApiServerVariable> + { + { "protocol", new OpenApiServerVariable { Default = "http", Enum = new List<string> { "http", "https" } } }, + { "hostpath", new OpenApiServerVariable { Default = "localhost:9696" } } + } + }); + c.AddSecurityDefinition("apikey", apikeyQuery); c.AddSecurityRequirement(new OpenApiSecurityRequirement @@ -244,11 +254,6 @@ namespace NzbDrone.Host { app.UseSwagger(c => { - c.PreSerializeFilters.Add((swagger, httpReq) => - { - swagger.Servers = new List<OpenApiServer> { new OpenApiServer { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}" } }; - }); - c.RouteTemplate = "docs/{documentName}/openapi.json"; }); } From 548db6a5cd63792fbf365b727614a69d3e65ad1b Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Wed, 29 Dec 2021 00:52:05 +0000 Subject: [PATCH 0269/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index 96956d868..69ddaebc2 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -9,6 +9,23 @@ }, "version": "1.0.0" }, + "servers": [ + { + "url": "{protocol}://{hostpath}", + "variables": { + "protocol": { + "default": "http", + "enum": [ + "http", + "https" + ] + }, + "hostpath": { + "default": "localhost:9696" + } + } + } + ], "paths": { "/api/v1/applications/{id}": { "get": { From 5b804e8f3ae5b362ac3b9b03fd478d4e837111df Mon Sep 17 00:00:00 2001 From: Mouton99 <66394380+Mouton99@users.noreply.github.com> Date: Wed, 29 Dec 2021 19:14:22 -0500 Subject: [PATCH 0270/2320] New: (TorrentSeeds) Migrate to API & YML --- src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs index c164c8d28..6fdf85976 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs @@ -21,6 +21,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete("Moved to YML for Cardigann v3")] public class TorrentSeeds : TorrentIndexerBase<TorrentSeedsSettings> { public override string Name => "TorrentSeeds"; From 25620e8670f7ebce5d8ddc4243f46bc3d3bcfe2e Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 29 Dec 2021 18:16:36 -0600 Subject: [PATCH 0271/2320] Fix GitHub token variable usage --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 802b77ff9..b45d4e1c2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -857,7 +857,7 @@ stages: then git commit -am 'Automated API Docs update' git push -f --set-upstream origin api-docs - curl -X POST -H 'Authorization: token $GITHUB_TOKEN' -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/prowlarr/prowlarr/pulls -d '{"head":"api-docs","base":"develop","title":"Update API docs"}' + curl -X POST -H 'Authorization: token ${GITHUB_TOKEN}' -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/prowlarr/prowlarr/pulls -d '{"head":"api-docs","base":"develop","title":"Update API docs"}' else echo "No changes since last run" fi From c9e6a0339e743be5e6cf523959524cbe8a506f21 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 29 Dec 2021 18:18:09 -0600 Subject: [PATCH 0272/2320] Fixed: (Cardigann) Indexer privacy tweaks, Semi-Public fixes Fixes #744 --- .../src/Indexer/Add/AddIndexerModalContent.js | 19 +++++++++++++++---- frontend/src/Indexer/Add/SelectIndexerRow.js | 4 +++- .../Definitions/Cardigann/Cardigann.cs | 7 ++++++- src/NzbDrone.Core/Indexers/IndexerFactory.cs | 7 ++++++- src/NzbDrone.Core/Localization/Core/en.json | 3 +++ 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/frontend/src/Indexer/Add/AddIndexerModalContent.js b/frontend/src/Indexer/Add/AddIndexerModalContent.js index 78b0469c0..ddc7e4a3a 100644 --- a/frontend/src/Indexer/Add/AddIndexerModalContent.js +++ b/frontend/src/Indexer/Add/AddIndexerModalContent.js @@ -56,6 +56,21 @@ const protocols = [ } ]; +const privacyLevels = [ + { + key: 'private', + value: translate('Private') + }, + { + key: 'semiPublic', + value: translate('SemiPublic') + }, + { + key: 'public', + value: translate('Public') + } +]; + class AddIndexerModalContent extends Component { // @@ -99,10 +114,6 @@ class AddIndexerModalContent extends Component { .sort((a, b) => a.localeCompare(b)) .map((language) => ({ key: language, value: language })); - const privacyLevels = Array.from(new Set(indexers.map(({ privacy }) => privacy))) - .sort((a, b) => a.localeCompare(b)) - .map((privacy) => ({ key: privacy, value: privacy })); - const filteredIndexers = indexers.filter((indexer) => { const { filter, filterProtocols, filterLanguages, filterPrivacyLevels } = this.state; diff --git a/frontend/src/Indexer/Add/SelectIndexerRow.js b/frontend/src/Indexer/Add/SelectIndexerRow.js index 24acb2650..fbf05e927 100644 --- a/frontend/src/Indexer/Add/SelectIndexerRow.js +++ b/frontend/src/Indexer/Add/SelectIndexerRow.js @@ -3,6 +3,8 @@ import React, { Component } from 'react'; import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableRowButton from 'Components/Table/TableRowButton'; import ProtocolLabel from 'Indexer/Index/Table/ProtocolLabel'; +import firstCharToUpper from 'Utilities/String/firstCharToUpper'; +import translate from 'Utilities/String/translate'; import styles from './SelectIndexerRow.css'; class SelectIndexerRow extends Component { @@ -47,7 +49,7 @@ class SelectIndexerRow extends Component { </TableRowCell> <TableRowCell> - {privacy} + {translate(firstCharToUpper(privacy))} </TableRowCell> </TableRowButton> ); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs index f2759f848..75435c570 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs @@ -128,7 +128,12 @@ namespace NzbDrone.Core.Indexers.Cardigann IndexerUrls = definition.Links.ToArray(), Settings = new CardigannSettings { DefinitionFile = definition.File }, Protocol = DownloadProtocol.Torrent, - Privacy = definition.Type == "private" ? IndexerPrivacy.Private : IndexerPrivacy.Public, + Privacy = definition.Type switch + { + "private" => IndexerPrivacy.Private, + "public" => IndexerPrivacy.Public, + _ => IndexerPrivacy.SemiPublic + }, SupportsRss = SupportsRss, SupportsSearch = SupportsSearch, SupportsRedirect = SupportsRedirect, diff --git a/src/NzbDrone.Core/Indexers/IndexerFactory.cs b/src/NzbDrone.Core/Indexers/IndexerFactory.cs index d23306583..7a583c6a6 100644 --- a/src/NzbDrone.Core/Indexers/IndexerFactory.cs +++ b/src/NzbDrone.Core/Indexers/IndexerFactory.cs @@ -94,7 +94,12 @@ namespace NzbDrone.Core.Indexers definition.Description = defFile.Description; definition.Language = defFile.Language; definition.Encoding = Encoding.GetEncoding(defFile.Encoding); - definition.Privacy = defFile.Type == "private" ? IndexerPrivacy.Private : IndexerPrivacy.Public; + definition.Privacy = defFile.Type switch + { + "private" => IndexerPrivacy.Private, + "public" => IndexerPrivacy.Public, + _ => IndexerPrivacy.SemiPublic + }; definition.Capabilities = new IndexerCapabilities(); definition.Capabilities.ParseCardigannSearchModes(defFile.Caps.Modes); definition.Capabilities.SupportsRawSearch = defFile.Caps.Allowrawsearch; diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 312b07bc5..1f07a2501 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -286,6 +286,7 @@ "PriorityHelpText": "Prioritize multiple Download Clients. Round-Robin is used for clients with the same priority.", "PrioritySettings": "Priority", "Privacy": "Privacy", + "Private": "Private", "Protocol": "Protocol", "ProwlarrSupportsAnyDownloadClient": "Prowlarr supports any of the download clients listed below.", "ProwlarrSupportsAnyIndexer": "Prowlarr supports many indexers in addition to any indexer that uses the Newznab/Torznab standard using 'Generic Newznab' (for usenet) or 'Generic Torznab' (for torrents). Search & Select your indexer from below.", @@ -298,6 +299,7 @@ "ProxyType": "Proxy Type", "ProxyUsernameHelpText": "You only need to enter a username and password if one is required. Leave them blank otherwise.", "PtpOldSettingsCheckMessage": "The following PassThePopcorn indexers have deprecated settings and should be updated: {0}", + "Public": "Public", "QualityDefinitions": "Quality Definitions", "QualitySettings": "Quality Settings", "Query": "Query", @@ -340,6 +342,7 @@ "Security": "Security", "Seeders": "Seeders", "SelectAll": "Select All", + "SemiPublic": "Semi-Public", "SendAnonymousUsageData": "Send Anonymous Usage Data", "SetTags": "Set Tags", "Settings": "Settings", From 642848d331b24d5a4066df8f6cccce8df39174a4 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 30 Dec 2021 15:51:51 -0600 Subject: [PATCH 0273/2320] API Annotations --- src/Prowlarr.Api.V1/Commands/CommandController.cs | 2 ++ src/Prowlarr.Api.V1/Config/ConfigController.cs | 2 ++ src/Prowlarr.Api.V1/CustomFilters/CustomFilterController.cs | 3 +++ src/Prowlarr.Api.V1/Health/HealthController.cs | 1 + src/Prowlarr.Api.V1/History/HistoryController.cs | 3 +++ src/Prowlarr.Api.V1/Languages/LanguageController.cs | 1 + src/Prowlarr.Api.V1/Localization/LocalizationController.cs | 1 + src/Prowlarr.Api.V1/ProviderControllerBase.cs | 4 ++++ 8 files changed, 17 insertions(+) diff --git a/src/Prowlarr.Api.V1/Commands/CommandController.cs b/src/Prowlarr.Api.V1/Commands/CommandController.cs index a375b7966..eb9ee70cf 100644 --- a/src/Prowlarr.Api.V1/Commands/CommandController.cs +++ b/src/Prowlarr.Api.V1/Commands/CommandController.cs @@ -46,6 +46,7 @@ namespace Prowlarr.Api.V1.Commands } [RestPostById] + [Produces("application/json")] public ActionResult<CommandResource> StartCommand(CommandResource commandResource) { var commandType = @@ -69,6 +70,7 @@ namespace Prowlarr.Api.V1.Commands } [HttpGet] + [Produces("application/json")] public List<CommandResource> GetStartedCommands() { return _commandQueueManager.All().ToResource(); diff --git a/src/Prowlarr.Api.V1/Config/ConfigController.cs b/src/Prowlarr.Api.V1/Config/ConfigController.cs index e56f5e3e5..f6a001e10 100644 --- a/src/Prowlarr.Api.V1/Config/ConfigController.cs +++ b/src/Prowlarr.Api.V1/Config/ConfigController.cs @@ -23,6 +23,7 @@ namespace Prowlarr.Api.V1.Config } [HttpGet] + [Produces("application/json")] public TResource GetConfig() { var resource = ToResource(_configService); @@ -32,6 +33,7 @@ namespace Prowlarr.Api.V1.Config } [RestPutById] + [Produces("application/json")] public virtual ActionResult<TResource> SaveConfig(TResource resource) { var dictionary = resource.GetType() diff --git a/src/Prowlarr.Api.V1/CustomFilters/CustomFilterController.cs b/src/Prowlarr.Api.V1/CustomFilters/CustomFilterController.cs index c60318885..018a3cc9f 100644 --- a/src/Prowlarr.Api.V1/CustomFilters/CustomFilterController.cs +++ b/src/Prowlarr.Api.V1/CustomFilters/CustomFilterController.cs @@ -23,12 +23,14 @@ namespace Prowlarr.Api.V1.CustomFilters } [HttpGet] + [Produces("application/json")] public List<CustomFilterResource> GetCustomFilters() { return _customFilterService.All().ToResource(); } [RestPostById] + [Produces("application/json")] public ActionResult<CustomFilterResource> AddCustomFilter(CustomFilterResource resource) { var customFilter = _customFilterService.Add(resource.ToModel()); @@ -37,6 +39,7 @@ namespace Prowlarr.Api.V1.CustomFilters } [RestPutById] + [Produces("application/json")] public ActionResult<CustomFilterResource> UpdateCustomFilter(CustomFilterResource resource) { _customFilterService.Update(resource.ToModel()); diff --git a/src/Prowlarr.Api.V1/Health/HealthController.cs b/src/Prowlarr.Api.V1/Health/HealthController.cs index 8f13ca598..9c562214d 100644 --- a/src/Prowlarr.Api.V1/Health/HealthController.cs +++ b/src/Prowlarr.Api.V1/Health/HealthController.cs @@ -28,6 +28,7 @@ namespace Prowlarr.Api.V1.Health } [HttpGet] + [Produces("application/json")] public List<HealthResource> GetHealth() { return _healthCheckService.Results().ToResource(); diff --git a/src/Prowlarr.Api.V1/History/HistoryController.cs b/src/Prowlarr.Api.V1/History/HistoryController.cs index 2bf7f9774..aee0eb84d 100644 --- a/src/Prowlarr.Api.V1/History/HistoryController.cs +++ b/src/Prowlarr.Api.V1/History/HistoryController.cs @@ -27,6 +27,7 @@ namespace Prowlarr.Api.V1.History } [HttpGet] + [Produces("application/json")] public PagingResource<HistoryResource> GetHistory() { var pagingResource = Request.ReadPagingResourceFromRequest<HistoryResource>(); @@ -58,12 +59,14 @@ namespace Prowlarr.Api.V1.History } [HttpGet("since")] + [Produces("application/json")] public List<HistoryResource> GetHistorySince(DateTime date, HistoryEventType? eventType = null) { return _historyService.Since(date, eventType).Select(h => MapToResource(h)).ToList(); } [HttpGet("indexer")] + [Produces("application/json")] public List<HistoryResource> GetIndexerHistory(int indexerId, HistoryEventType? eventType = null) { return _historyService.GetByIndexerId(indexerId, eventType).Select(h => MapToResource(h)).ToList(); diff --git a/src/Prowlarr.Api.V1/Languages/LanguageController.cs b/src/Prowlarr.Api.V1/Languages/LanguageController.cs index 33622aea9..de7a2c4e7 100644 --- a/src/Prowlarr.Api.V1/Languages/LanguageController.cs +++ b/src/Prowlarr.Api.V1/Languages/LanguageController.cs @@ -22,6 +22,7 @@ namespace Prowlarr.Api.V1.Languages } [HttpGet] + [Produces("application/json")] public List<LanguageResource> GetAll() { return Language.All.Select(l => new LanguageResource diff --git a/src/Prowlarr.Api.V1/Localization/LocalizationController.cs b/src/Prowlarr.Api.V1/Localization/LocalizationController.cs index ea1a6b7c5..845b4666b 100644 --- a/src/Prowlarr.Api.V1/Localization/LocalizationController.cs +++ b/src/Prowlarr.Api.V1/Localization/LocalizationController.cs @@ -21,6 +21,7 @@ namespace Prowlarr.Api.V1.Localization } [HttpGet] + [Produces("application/json")] public string GetLocalizationDictionary() { return JsonSerializer.Serialize(_localizationService.GetLocalizationDictionary().ToResource(), _serializerSettings); diff --git a/src/Prowlarr.Api.V1/ProviderControllerBase.cs b/src/Prowlarr.Api.V1/ProviderControllerBase.cs index 993357745..0be76531b 100644 --- a/src/Prowlarr.Api.V1/ProviderControllerBase.cs +++ b/src/Prowlarr.Api.V1/ProviderControllerBase.cs @@ -41,6 +41,7 @@ namespace Prowlarr.Api.V1 } [HttpGet] + [Produces("application/json")] public List<TProviderResource> GetAll() { var providerDefinitions = _providerFactory.All().OrderBy(p => p.ImplementationName); @@ -58,6 +59,7 @@ namespace Prowlarr.Api.V1 } [RestPostById] + [Produces("application/json")] public ActionResult<TProviderResource> CreateProvider(TProviderResource providerResource) { var providerDefinition = GetDefinition(providerResource, false); @@ -73,6 +75,7 @@ namespace Prowlarr.Api.V1 } [RestPutById] + [Produces("application/json")] public ActionResult<TProviderResource> UpdateProvider(TProviderResource providerResource) { var providerDefinition = GetDefinition(providerResource, false); @@ -110,6 +113,7 @@ namespace Prowlarr.Api.V1 } [HttpGet("schema")] + [Produces("application/json")] public virtual List<TProviderResource> GetTemplates() { var defaultDefinitions = _providerFactory.GetDefaultDefinitions().OrderBy(p => p.ImplementationName).ToList(); From 8ec7a4898dffcc80e7169de31bcb5e37cb2715a7 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 21 Dec 2021 17:45:00 -0600 Subject: [PATCH 0274/2320] Maintain PrimaryKey and AutoIncrement on some schemas [common] --- .../SqliteSchemaDumperFixture.cs | 3 ++- .../Migration/Framework/SqliteSchemaDumper.cs | 21 ++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core.Test/Datastore/SqliteSchemaDumperTests/SqliteSchemaDumperFixture.cs b/src/NzbDrone.Core.Test/Datastore/SqliteSchemaDumperTests/SqliteSchemaDumperFixture.cs index b1ecba40f..a59bbf5a4 100644 --- a/src/NzbDrone.Core.Test/Datastore/SqliteSchemaDumperTests/SqliteSchemaDumperFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/SqliteSchemaDumperTests/SqliteSchemaDumperFixture.cs @@ -1,4 +1,4 @@ -using System.Data; +using System.Data; using System.Linq; using FluentAssertions; using NUnit.Framework; @@ -38,6 +38,7 @@ namespace NzbDrone.Core.Test.Datastore.SqliteSchemaDumperTests result.Name.Should().Be(tableName); result.Columns.Count.Should().Be(1); result.Columns.First().Name.Should().Be(columnName); + result.Columns.First().IsIdentity.Should().BeTrue(); } [TestCase(@"CREATE INDEX TestIndex ON TestTable (MyId)", "TestIndex", "TestTable", "MyId")] diff --git a/src/NzbDrone.Core/Datastore/Migration/Framework/SqliteSchemaDumper.cs b/src/NzbDrone.Core/Datastore/Migration/Framework/SqliteSchemaDumper.cs index 57b984c5a..4ae4e6e68 100644 --- a/src/NzbDrone.Core/Datastore/Migration/Framework/SqliteSchemaDumper.cs +++ b/src/NzbDrone.Core/Datastore/Migration/Framework/SqliteSchemaDumper.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Data; +using System.Linq; using FluentMigrator.Model; using FluentMigrator.Runner.Processors.SQLite; @@ -66,6 +67,24 @@ namespace NzbDrone.Core.Datastore.Migration.Framework if (columnReader.Read() == SqliteSyntaxReader.TokenType.StringToken) { + if (columnReader.ValueToUpper == "PRIMARY") + { + columnReader.SkipTillToken(SqliteSyntaxReader.TokenType.ListStart); + if (columnReader.Read() == SqliteSyntaxReader.TokenType.Identifier) + { + var pk = table.Columns.First(v => v.Name == columnReader.Value); + pk.IsPrimaryKey = true; + pk.IsNullable = true; + pk.IsUnique = true; + if (columnReader.Buffer.ToUpperInvariant().Contains("AUTOINCREMENT")) + { + pk.IsIdentity = true; + } + + continue; + } + } + if (columnReader.ValueToUpper == "CONSTRAINT" || columnReader.ValueToUpper == "PRIMARY" || columnReader.ValueToUpper == "UNIQUE" || columnReader.ValueToUpper == "CHECK" || columnReader.ValueToUpper == "FOREIGN") From 6e8fb22c715434857ee99a25ccfc211012ec57e4 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 23 Dec 2021 13:47:01 -0600 Subject: [PATCH 0275/2320] New: Additional logging for InvalidModel BadRequest API calls [common] --- src/NzbDrone.Host/Startup.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/NzbDrone.Host/Startup.cs b/src/NzbDrone.Host/Startup.cs index 40b375ada..730f16dea 100644 --- a/src/NzbDrone.Host/Startup.cs +++ b/src/NzbDrone.Host/Startup.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -184,6 +185,21 @@ namespace NzbDrone.Host }); services.AddAppAuthentication(); + + services.PostConfigure<ApiBehaviorOptions>(options => + { + var builtInFactory = options.InvalidModelStateResponseFactory; + + options.InvalidModelStateResponseFactory = context => + { + var loggerFactory = context.HttpContext.RequestServices.GetRequiredService<ILoggerFactory>(); + var logger = loggerFactory.CreateLogger(context.ActionDescriptor.DisplayName); + + logger.LogError(STJson.ToJson(context.ModelState)); + + return builtInFactory(context); + }; + }); } public void Configure(IApplicationBuilder app, From 3fce120578a422864b7600a682c82ca79b85dc68 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 30 Dec 2021 18:30:58 -0600 Subject: [PATCH 0276/2320] Fixed: (SpeedApp) Map Categories instead of building Fixes #574 --- src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs index 43d23d709..bc4078427 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs @@ -61,7 +61,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IParseIndexerResponse GetParser() { - return new SpeedAppParser(Settings); + return new SpeedAppParser(Settings, Capabilities.Categories); } protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) @@ -347,13 +347,15 @@ namespace NzbDrone.Core.Indexers.Definitions public class SpeedAppParser : IParseIndexerResponse { - public SpeedAppSettings Settings { get; set; } + private readonly SpeedAppSettings _settings; + private readonly IndexerCapabilitiesCategories _categories; public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - public SpeedAppParser(SpeedAppSettings settings) + public SpeedAppParser(SpeedAppSettings settings, IndexerCapabilitiesCategories categories) { - Settings = settings; + _settings = settings; + _categories = categories; } public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) @@ -377,12 +379,12 @@ namespace NzbDrone.Core.Indexers.Definitions Description = torrent.ShortDescription, Size = torrent.Size, ImdbId = ParseUtil.GetImdbID(torrent.ImdbId).GetValueOrDefault(), - DownloadUrl = $"{Settings.BaseUrl}/api/torrent/{torrent.Id}/download", + DownloadUrl = $"{_settings.BaseUrl}/api/torrent/{torrent.Id}/download", PosterUrl = torrent.Poster, InfoUrl = torrent.Url, Grabs = torrent.TimesCompleted, PublishDate = torrent.CreatedAt, - Categories = new List<IndexerCategory> { new (torrent.Category.Id, torrent.Category.Name), }, + Categories = _categories.MapTrackerCatToNewznab(torrent.Category.Id.ToString()), InfoHash = null, Seeders = torrent.Seeders, Peers = torrent.Leechers + torrent.Seeders, From 75984e954ee1cae4202e95487d775a14c6db2924 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 30 Dec 2021 18:41:56 -0600 Subject: [PATCH 0277/2320] Update LocalizationController.cs --- src/Prowlarr.Api.V1/Localization/LocalizationController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Prowlarr.Api.V1/Localization/LocalizationController.cs b/src/Prowlarr.Api.V1/Localization/LocalizationController.cs index 845b4666b..67d3f53b5 100644 --- a/src/Prowlarr.Api.V1/Localization/LocalizationController.cs +++ b/src/Prowlarr.Api.V1/Localization/LocalizationController.cs @@ -22,9 +22,9 @@ namespace Prowlarr.Api.V1.Localization [HttpGet] [Produces("application/json")] - public string GetLocalizationDictionary() + public IActionResult GetLocalizationDictionary() { - return JsonSerializer.Serialize(_localizationService.GetLocalizationDictionary().ToResource(), _serializerSettings); + return Json(_localizationService.GetLocalizationDictionary().ToResource(), _serializerSettings); } } } From fd55a624a795a55a5df33e4adfc640938ed07266 Mon Sep 17 00:00:00 2001 From: Yukine <devyukine@gmx.de> Date: Thu, 30 Dec 2021 05:06:45 +0100 Subject: [PATCH 0278/2320] Fixed: (AnimeBytes) Do not Page requests --- .../Indexers/Definitions/AnimeBytes.cs | 77 ++++++++----------- 1 file changed, 31 insertions(+), 46 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs index 90a50d753..15219662e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs @@ -106,7 +106,37 @@ namespace NzbDrone.Core.Indexers.Definitions { } - private IEnumerable<IndexerRequest> GetPagedRequests(string searchType, string term, int[] categories) + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + => GetRequestWithSearchType(searchCriteria, "anime"); + + public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) + => GetRequestWithSearchType(searchCriteria, "music"); + + public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) + => GetRequestWithSearchType(searchCriteria, "anime"); + + public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + => GetRequestWithSearchType(searchCriteria, "anime"); + + public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) + => GetRequestWithSearchType(searchCriteria, "anime"); + + private IndexerPageableRequestChain GetRequestWithSearchType(SearchCriteriaBase searchCriteria, string searchType) + { + var pageableRequests = new IndexerPageableRequestChain(); + + // TODO: Remove this once Prowlarr has proper support for non Pageable Indexers and can tell Sonarr that indexer doesn't support pagination in a proper way, for now just return empty release list on all request containing an offset + if (searchCriteria.Offset is > 0) + { + return pageableRequests; + } + + pageableRequests.Add(GetRequest(searchType, searchCriteria.SanitizedSearchTerm, searchCriteria.Categories)); + + return pageableRequests; + } + + private IEnumerable<IndexerRequest> GetRequest(string searchType, string term, int[] categories) { var searchUrl = string.Format("{0}/scrape.php", Settings.BaseUrl.TrimEnd('/')); @@ -135,51 +165,6 @@ namespace NzbDrone.Core.Indexers.Definitions yield return request; } - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests("anime", searchCriteria.SanitizedSearchTerm, searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests("music", searchCriteria.SanitizedSearchTerm, searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests("anime", searchCriteria.SanitizedSearchTerm, searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests("anime", searchCriteria.SanitizedSearchTerm, searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests("anime", searchCriteria.SanitizedSearchTerm, searchCriteria.Categories)); - - return pageableRequests; - } - public Func<IDictionary<string, string>> GetCookies { get; set; } public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } From 22cbd01c5796caacab1da5be488cf2a312cefe1e Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 30 Dec 2021 19:03:04 -0600 Subject: [PATCH 0279/2320] Bump to 0.1.10 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b45d4e1c2..079c77b80 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,7 +7,7 @@ variables: outputFolder: './_output' artifactsFolder: './_artifacts' testsFolder: './_tests' - majorVersion: '0.1.9' + majorVersion: '0.1.10' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From 77724a50a4841ecbe20963bdb4e8deed0fbed0fd Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 30 Dec 2021 21:42:46 -0600 Subject: [PATCH 0280/2320] Really fix Github token for API PR --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 079c77b80..aa3e7e5b9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -857,14 +857,14 @@ stages: then git commit -am 'Automated API Docs update' git push -f --set-upstream origin api-docs - curl -X POST -H 'Authorization: token ${GITHUB_TOKEN}' -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/prowlarr/prowlarr/pulls -d '{"head":"api-docs","base":"develop","title":"Update API docs"}' + curl -X POST -H "Authorization: token ${GITHUBTOKEN}" -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/prowlarr/prowlarr/pulls -d '{"head":"api-docs","base":"develop","title":"Update API docs"}' else echo "No changes since last run" fi displayName: Commit API Doc Change continueOnError: true env: - GITHUB_TOKEN: $(githubToken) + GITHUBTOKEN: $(githubToken) - task: CopyFiles@2 displayName: 'Copy openapi.json to: $(Build.ArtifactStagingDirectory)' inputs: From c5b111530c2fe35eb7ebc144799125a47dbe256d Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Fri, 31 Dec 2021 03:47:20 +0000 Subject: [PATCH 0281/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 475 +------------------------------ 1 file changed, 1 insertion(+), 474 deletions(-) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index 69ddaebc2..d3edebdc9 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -103,20 +103,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } } } } @@ -153,14 +143,6 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApplicationResource" - } - } - }, "application/json": { "schema": { "type": "array", @@ -168,14 +150,6 @@ "$ref": "#/components/schemas/ApplicationResource" } } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApplicationResource" - } - } } } } @@ -208,20 +182,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ApplicationResource" - } } } } @@ -237,14 +201,6 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApplicationResource" - } - } - }, "application/json": { "schema": { "type": "array", @@ -252,14 +208,6 @@ "$ref": "#/components/schemas/ApplicationResource" } } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApplicationResource" - } - } } } } @@ -780,20 +728,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/CommandResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/CommandResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CommandResource" - } } } } @@ -807,14 +745,6 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CommandResource" - } - } - }, "application/json": { "schema": { "type": "array", @@ -822,14 +752,6 @@ "$ref": "#/components/schemas/CommandResource" } } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CommandResource" - } - } } } } @@ -912,20 +834,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/CustomFilterResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } } } } @@ -962,14 +874,6 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CustomFilterResource" - } - } - }, "application/json": { "schema": { "type": "array", @@ -977,14 +881,6 @@ "$ref": "#/components/schemas/CustomFilterResource" } } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CustomFilterResource" - } - } } } } @@ -1017,20 +913,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/CustomFilterResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CustomFilterResource" - } } } } @@ -1075,20 +961,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/DevelopmentConfigResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/DevelopmentConfigResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DevelopmentConfigResource" - } } } } @@ -1142,20 +1018,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/DevelopmentConfigResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/DevelopmentConfigResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DevelopmentConfigResource" - } } } } @@ -1238,20 +1104,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/DownloadClientResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } } } } @@ -1288,14 +1144,6 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } - }, "application/json": { "schema": { "type": "array", @@ -1303,14 +1151,6 @@ "$ref": "#/components/schemas/DownloadClientResource" } } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } } } } @@ -1343,20 +1183,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/DownloadClientResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientResource" - } } } } @@ -1372,14 +1202,6 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } - }, "application/json": { "schema": { "type": "array", @@ -1387,14 +1209,6 @@ "$ref": "#/components/schemas/DownloadClientResource" } } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DownloadClientResource" - } - } } } } @@ -1561,20 +1375,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/DownloadClientConfigResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/DownloadClientConfigResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientConfigResource" - } } } } @@ -1590,20 +1394,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/DownloadClientConfigResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/DownloadClientConfigResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DownloadClientConfigResource" - } } } } @@ -1717,14 +1511,6 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HealthResource" - } - } - }, "application/json": { "schema": { "type": "array", @@ -1732,14 +1518,6 @@ "$ref": "#/components/schemas/HealthResource" } } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HealthResource" - } - } } } } @@ -1755,20 +1533,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/HistoryResourcePagingResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/HistoryResourcePagingResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/HistoryResourcePagingResource" - } } } } @@ -1801,14 +1569,6 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HistoryResource" - } - } - }, "application/json": { "schema": { "type": "array", @@ -1816,14 +1576,6 @@ "$ref": "#/components/schemas/HistoryResource" } } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HistoryResource" - } - } } } } @@ -1856,14 +1608,6 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HistoryResource" - } - } - }, "application/json": { "schema": { "type": "array", @@ -1871,14 +1615,6 @@ "$ref": "#/components/schemas/HistoryResource" } } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HistoryResource" - } - } } } } @@ -2086,20 +1822,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/IndexerResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } } } } @@ -2136,14 +1862,6 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerResource" - } - } - }, "application/json": { "schema": { "type": "array", @@ -2151,14 +1869,6 @@ "$ref": "#/components/schemas/IndexerResource" } } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerResource" - } - } } } } @@ -2191,20 +1901,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/IndexerResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerResource" - } } } } @@ -2220,14 +1920,6 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerResource" - } - } - }, "application/json": { "schema": { "type": "array", @@ -2235,14 +1927,6 @@ "$ref": "#/components/schemas/IndexerResource" } } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerResource" - } - } } } } @@ -2507,20 +2191,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/IndexerProxyResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } } } } @@ -2557,14 +2231,6 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } - }, "application/json": { "schema": { "type": "array", @@ -2572,14 +2238,6 @@ "$ref": "#/components/schemas/IndexerProxyResource" } } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } } } } @@ -2612,20 +2270,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/IndexerProxyResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/IndexerProxyResource" - } } } } @@ -2641,14 +2289,6 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } - }, "application/json": { "schema": { "type": "array", @@ -2656,14 +2296,6 @@ "$ref": "#/components/schemas/IndexerProxyResource" } } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexerProxyResource" - } - } } } } @@ -2940,14 +2572,6 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/LanguageResource" - } - } - }, "application/json": { "schema": { "type": "array", @@ -2955,14 +2579,6 @@ "$ref": "#/components/schemas/LanguageResource" } } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/LanguageResource" - } - } } } } @@ -2976,24 +2592,7 @@ ], "responses": { "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - }, - "application/json": { - "schema": { - "type": "string" - } - }, - "text/json": { - "schema": { - "type": "string" - } - } - } + "description": "Success" } } } @@ -3665,20 +3264,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/NotificationResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } } } } @@ -3715,14 +3304,6 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NotificationResource" - } - } - }, "application/json": { "schema": { "type": "array", @@ -3730,14 +3311,6 @@ "$ref": "#/components/schemas/NotificationResource" } } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NotificationResource" - } - } } } } @@ -3770,20 +3343,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/NotificationResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResource" - } } } } @@ -3799,14 +3362,6 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NotificationResource" - } - } - }, "application/json": { "schema": { "type": "array", @@ -3814,14 +3369,6 @@ "$ref": "#/components/schemas/NotificationResource" } } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NotificationResource" - } - } } } } @@ -4720,20 +4267,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/UiConfigResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } } } } @@ -4749,20 +4286,10 @@ "200": { "description": "Success", "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - }, "application/json": { "schema": { "$ref": "#/components/schemas/UiConfigResource" } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } } } } From 66a6311dcc8d69aef6cecfcbd4c72b74546619d6 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Thu, 30 Dec 2021 21:44:59 -0600 Subject: [PATCH 0282/2320] Fixed: SemiPublic => SemiPrivate --- frontend/src/Indexer/Add/AddIndexerModalContent.js | 4 ++-- src/NzbDrone.Core/Indexers/Definitions/Anidub.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs | 2 +- src/NzbDrone.Core/Indexers/IndexerFactory.cs | 2 +- src/NzbDrone.Core/Indexers/IndexerPrivacy.cs | 2 +- src/NzbDrone.Core/Localization/Core/en.json | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/src/Indexer/Add/AddIndexerModalContent.js b/frontend/src/Indexer/Add/AddIndexerModalContent.js index ddc7e4a3a..5255a4e7c 100644 --- a/frontend/src/Indexer/Add/AddIndexerModalContent.js +++ b/frontend/src/Indexer/Add/AddIndexerModalContent.js @@ -62,8 +62,8 @@ const privacyLevels = [ value: translate('Private') }, { - key: 'semiPublic', - value: translate('SemiPublic') + key: 'semiPrivate', + value: translate('SemiPrivate') }, { key: 'public', diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs b/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs index d656f9ce4..6e1fe3ead 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Language => "ru-RU"; public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPublic; + public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPrivate; public override IndexerCapabilities Capabilities => SetCapabilities(); public Anidub(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs index 75435c570..9012983f1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs @@ -132,7 +132,7 @@ namespace NzbDrone.Core.Indexers.Cardigann { "private" => IndexerPrivacy.Private, "public" => IndexerPrivacy.Public, - _ => IndexerPrivacy.SemiPublic + _ => IndexerPrivacy.SemiPrivate }, SupportsRss = SupportsRss, SupportsSearch = SupportsSearch, diff --git a/src/NzbDrone.Core/Indexers/IndexerFactory.cs b/src/NzbDrone.Core/Indexers/IndexerFactory.cs index 7a583c6a6..be4fd0af5 100644 --- a/src/NzbDrone.Core/Indexers/IndexerFactory.cs +++ b/src/NzbDrone.Core/Indexers/IndexerFactory.cs @@ -98,7 +98,7 @@ namespace NzbDrone.Core.Indexers { "private" => IndexerPrivacy.Private, "public" => IndexerPrivacy.Public, - _ => IndexerPrivacy.SemiPublic + _ => IndexerPrivacy.SemiPrivate }; definition.Capabilities = new IndexerCapabilities(); definition.Capabilities.ParseCardigannSearchModes(defFile.Caps.Modes); diff --git a/src/NzbDrone.Core/Indexers/IndexerPrivacy.cs b/src/NzbDrone.Core/Indexers/IndexerPrivacy.cs index 0e467063e..bebaa3690 100644 --- a/src/NzbDrone.Core/Indexers/IndexerPrivacy.cs +++ b/src/NzbDrone.Core/Indexers/IndexerPrivacy.cs @@ -3,7 +3,7 @@ namespace NzbDrone.Core.Indexers public enum IndexerPrivacy { Public, - SemiPublic, + SemiPrivate, Private } } diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 1f07a2501..f5f39d2e3 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -342,7 +342,7 @@ "Security": "Security", "Seeders": "Seeders", "SelectAll": "Select All", - "SemiPublic": "Semi-Public", + "SemiPrivate": "Semi-Private", "SendAnonymousUsageData": "Send Anonymous Usage Data", "SetTags": "Set Tags", "Settings": "Settings", From 0dbd23c52bba836b0e824a68e4f1f0b188c74b10 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Thu, 30 Dec 2021 23:34:48 -0600 Subject: [PATCH 0283/2320] Fixed: Various Translations --- frontend/src/App/AppUpdatedModalContent.js | 4 +- .../Builder/FilterBuilderModalContent.js | 4 +- .../src/History/Details/HistoryDetails.js | 14 ++--- frontend/src/History/HistoryOptions.js | 7 ++- .../Indexer/Edit/EditIndexerModalContent.js | 2 +- frontend/src/Indexer/Index/IndexerIndex.js | 8 +-- .../Indexer/Index/Table/IndexerIndexRow.js | 4 +- frontend/src/Search/Table/SearchIndexRow.js | 2 +- .../Applications/Applications/Applications.js | 2 +- .../Indexers/IndexerProxies/IndexerProxies.js | 2 +- .../Tags/Details/TagDetailsModalContent.js | 2 +- .../src/System/Tasks/Queued/QueuedTaskRow.js | 2 +- src/NzbDrone.Core/Localization/Core/en.json | 60 +++++-------------- 13 files changed, 45 insertions(+), 68 deletions(-) diff --git a/frontend/src/App/AppUpdatedModalContent.js b/frontend/src/App/AppUpdatedModalContent.js index efd847575..d03609a69 100644 --- a/frontend/src/App/AppUpdatedModalContent.js +++ b/frontend/src/App/AppUpdatedModalContent.js @@ -77,7 +77,9 @@ function AppUpdatedModalContent(props) { <div> { !update.changes && - <div className={styles.maintenance}>Maintenance release</div> + <div className={styles.maintenance}> + {translate('MaintenanceRelease')} + </div> } { diff --git a/frontend/src/Components/Filter/Builder/FilterBuilderModalContent.js b/frontend/src/Components/Filter/Builder/FilterBuilderModalContent.js index d5a8c65b8..033b9a69a 100644 --- a/frontend/src/Components/Filter/Builder/FilterBuilderModalContent.js +++ b/frontend/src/Components/Filter/Builder/FilterBuilderModalContent.js @@ -166,7 +166,9 @@ class FilterBuilderModalContent extends Component { </div> </div> - <div className={styles.label}>Filters</div> + <div className={styles.label}> + {translate('Filters')} + </div> <div className={styles.rows}> { diff --git a/frontend/src/History/Details/HistoryDetails.js b/frontend/src/History/Details/HistoryDetails.js index 4d7887fab..63543f040 100644 --- a/frontend/src/History/Details/HistoryDetails.js +++ b/frontend/src/History/Details/HistoryDetails.js @@ -41,7 +41,7 @@ function HistoryDetails(props) { { !!data && <DescriptionListItem - title={'Query Results'} + title={translate('QueryResults')} data={queryResults ? queryResults : '-'} /> } @@ -49,7 +49,7 @@ function HistoryDetails(props) { { !!data && <DescriptionListItem - title={'Categories'} + title={translate('Categories')} data={categories ? categories : '-'} /> } @@ -57,7 +57,7 @@ function HistoryDetails(props) { { !!data && <DescriptionListItem - title={'Source'} + title={translate('Source')} data={source} /> } @@ -65,7 +65,7 @@ function HistoryDetails(props) { { !!data && <DescriptionListItem - title={'Url'} + title={translate('Url')} data={url ? <Link to={url}>{translate('Link')}</Link> : '-'} /> } @@ -93,7 +93,7 @@ function HistoryDetails(props) { { !!data && <DescriptionListItem - title={'Source'} + title={translate('Source')} data={source ? source : '-'} /> } @@ -101,7 +101,7 @@ function HistoryDetails(props) { { !!data && <DescriptionListItem - title={'Title'} + title={translate('Title')} data={title ? title : '-'} /> } @@ -109,7 +109,7 @@ function HistoryDetails(props) { { !!data && <DescriptionListItem - title={'Url'} + title={translate('Url')} data={url ? <Link to={url}>{translate('Link')}</Link> : '-'} /> } diff --git a/frontend/src/History/HistoryOptions.js b/frontend/src/History/HistoryOptions.js index 1459320ee..40fc5c727 100644 --- a/frontend/src/History/HistoryOptions.js +++ b/frontend/src/History/HistoryOptions.js @@ -4,6 +4,7 @@ import FormGroup from 'Components/Form/FormGroup'; import FormInputGroup from 'Components/Form/FormInputGroup'; import FormLabel from 'Components/Form/FormLabel'; import { inputTypes } from 'Helpers/Props'; +import translate from 'Utilities/String/translate'; class HistoryOptions extends Component { @@ -56,14 +57,14 @@ class HistoryOptions extends Component { return ( <Fragment> <FormGroup> - <FormLabel>History Cleanup</FormLabel> + <FormLabel>{translate('HistoryCleanup')}</FormLabel> <FormInputGroup type={inputTypes.NUMBER} name="historyCleanupDays" value={historyCleanupDays} - helpText="Set to 0 to disable automatic cleanup" - helpTextWarning="History items older than the selected number of days will be cleaned up automatically" + helpText={translate('HistoryCleanupDaysHelpText')} + helpTextWarning={translate('HistoryCleanupDaysHelpTextWarning')} onChange={this.onGlobalInputChange} /> </FormGroup> diff --git a/frontend/src/Indexer/Edit/EditIndexerModalContent.js b/frontend/src/Indexer/Edit/EditIndexerModalContent.js index 2cc55b8a2..a17c5a040 100644 --- a/frontend/src/Indexer/Edit/EditIndexerModalContent.js +++ b/frontend/src/Indexer/Edit/EditIndexerModalContent.js @@ -159,7 +159,7 @@ function EditIndexerModalContent(props) { <FormInputGroup type={inputTypes.TAG} name="tags" - helpText="Use tags to specify default clients, specify Indexer Proxies, or just to organize your indexers." + helpText={translate('IndexerTagsHelpText')} {...tags} onChange={onInputChange} /> diff --git a/frontend/src/Indexer/Index/IndexerIndex.js b/frontend/src/Indexer/Index/IndexerIndex.js index e895f3357..db56c9793 100644 --- a/frontend/src/Indexer/Index/IndexerIndex.js +++ b/frontend/src/Indexer/Index/IndexerIndex.js @@ -302,14 +302,14 @@ class IndexerIndex extends Component { <PageToolbar> <PageToolbarSection> <PageToolbarButton - label={'Add Indexer'} + label={translate('AddIndexer')} iconName={icons.ADD} spinningName={icons.ADD} onPress={this.onAddIndexerPress} /> <PageToolbarButton - label={'Test All Indexers'} + label={translate('TestAllIndexers')} iconName={icons.TEST} isSpinning={isTestingAll} isDisabled={hasNoIndexer} @@ -321,13 +321,13 @@ class IndexerIndex extends Component { { isMovieEditorActive ? <PageToolbarButton - label={'Indexers'} + label={translate('Indexers')} iconName={icons.MOVIE_CONTINUING} isDisabled={hasNoIndexer} onPress={this.onMovieEditorTogglePress} /> : <PageToolbarButton - label={'Mass Editor'} + label={translate('MassEditor')} iconName={icons.EDIT} isDisabled={hasNoIndexer} onPress={this.onMovieEditorTogglePress} diff --git a/frontend/src/Indexer/Index/Table/IndexerIndexRow.js b/frontend/src/Indexer/Index/Table/IndexerIndexRow.js index 9233a10fa..fa802e254 100644 --- a/frontend/src/Indexer/Index/Table/IndexerIndexRow.js +++ b/frontend/src/Indexer/Index/Table/IndexerIndexRow.js @@ -240,14 +240,14 @@ class IndexerIndexRow extends Component { > <IconButton name={icons.INFO} - title={'Indexer info'} + title={translate('IndexerInfo')} onPress={this.onIndexerInfoPress} /> <IconButton className={styles.externalLink} name={icons.EXTERNAL_LINK} - title={'Website'} + title={translate('Website')} to={indexerUrls[0].replace('api.', '')} /> diff --git a/frontend/src/Search/Table/SearchIndexRow.js b/frontend/src/Search/Table/SearchIndexRow.js index f562bf8f3..a54876c8f 100644 --- a/frontend/src/Search/Table/SearchIndexRow.js +++ b/frontend/src/Search/Table/SearchIndexRow.js @@ -299,7 +299,7 @@ class SearchIndexRow extends Component { <IconButton className={styles.downloadLink} name={icons.SAVE} - title={'Save'} + title={translate('Save')} to={downloadUrl} /> </VirtualTableRowCell> diff --git a/frontend/src/Settings/Applications/Applications/Applications.js b/frontend/src/Settings/Applications/Applications/Applications.js index 83047f602..9e679f0e7 100644 --- a/frontend/src/Settings/Applications/Applications/Applications.js +++ b/frontend/src/Settings/Applications/Applications/Applications.js @@ -61,7 +61,7 @@ class Applications extends Component { return ( <FieldSet legend={translate('Applications')}> <PageSectionContent - errorMessage="Unable to load application list" + errorMessage={translate('UnableToLoadApplicationList')} {...otherProps} > <div className={styles.applications}> diff --git a/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.js b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.js index 7ae537da1..5501354c9 100644 --- a/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.js +++ b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.js @@ -61,7 +61,7 @@ class IndexerProxies extends Component { } = this.state; return ( - <FieldSet legend={translate('Indexer Proxies')}> + <FieldSet legend={translate('IndexerProxies')}> <PageSectionContent errorMessage={translate('UnableToLoadIndexerProxies')} {...otherProps} diff --git a/frontend/src/Settings/Tags/Details/TagDetailsModalContent.js b/frontend/src/Settings/Tags/Details/TagDetailsModalContent.js index c65f46974..dfe24646d 100644 --- a/frontend/src/Settings/Tags/Details/TagDetailsModalContent.js +++ b/frontend/src/Settings/Tags/Details/TagDetailsModalContent.js @@ -67,7 +67,7 @@ function TagDetailsModalContent(props) { { !!indexerProxies.length && - <FieldSet legend={translate('Indexer Proxies')}> + <FieldSet legend={translate('IndexerProxies')}> { indexerProxies.map((item) => { return ( diff --git a/frontend/src/System/Tasks/Queued/QueuedTaskRow.js b/frontend/src/System/Tasks/Queued/QueuedTaskRow.js index 5ccf0e5b8..917bfa11a 100644 --- a/frontend/src/System/Tasks/Queued/QueuedTaskRow.js +++ b/frontend/src/System/Tasks/Queued/QueuedTaskRow.js @@ -199,7 +199,7 @@ class QueuedTaskRow extends Component { </span> { clientUserAgent ? - <span className={styles.userAgent} title="User-Agent provided by the app that called the API"> + <span className={styles.userAgent} title={translate('UserAgentProvidedByTheAppThatCalledTheAPI')}> from: {clientUserAgent} </span> : null diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index f5f39d2e3..3e09bea17 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -61,6 +61,7 @@ "BypassProxyForLocalAddresses": "Bypass Proxy for Local Addresses", "Cancel": "Cancel", "CancelPendingTask": "Are you sure you want to cancel this pending task?", + "Categories": "Categories", "Category": "Category", "CertificateValidation": "Certificate Validation", "CertificateValidationHelpText": "Change how strict HTTPS certification validation is", @@ -69,7 +70,6 @@ "ClearHistory": "Clear History", "ClearHistoryMessageText": "Are you sure you want to clear all Prowlarr history?", "ClientPriority": "Client Priority", - "CloneIndexer": "Clone Indexer", "CloneProfile": "Clone Profile", "Close": "Close", "CloseCurrentModal": "Close Current Modal", @@ -88,7 +88,6 @@ "Date": "Date", "Dates": "Dates", "DBMigration": "DB Migration", - "DelayProfile": "Delay Profile", "Delete": "Delete", "DeleteApplication": "Delete Application", "DeleteApplicationMessageText": "Are you sure you want to delete the application '{0}'?", @@ -97,8 +96,6 @@ "DeleteBackupMessageText": "Are you sure you want to delete the backup '{0}'?", "DeleteDownloadClient": "Delete Download Client", "DeleteDownloadClientMessageText": "Are you sure you want to delete the download client '{0}'?", - "DeleteIndexer": "Delete Indexer", - "DeleteIndexerMessageText": "Are you sure you want to delete the indexer '{0}'?", "DeleteIndexerProxy": "Delete Indexer Proxy", "DeleteIndexerProxyMessageText": "Are you sure you want to delete the proxy '{0}'?", "DeleteNotification": "Delete Notification", @@ -113,35 +110,21 @@ "Docker": "Docker", "Donations": "Donations", "DownloadClient": "Download Client", - "DownloadClientCheckNoneAvailableMessage": "No download client is available", - "DownloadClientCheckUnableToCommunicateMessage": "Unable to communicate with {0}.", "DownloadClients": "Download Clients", "DownloadClientSettings": "Download Client Settings", "DownloadClientsSettingsSummary": "Download clients configuration for integration into Prowlarr UI search", "DownloadClientStatusCheckAllClientMessage": "All download clients are unavailable due to failures", "DownloadClientStatusCheckSingleClientMessage": "Download clients unavailable due to failures: {0}", - "DownloadClientUnavailable": "Download client is unavailable", - "Downloading": "Downloading", "Edit": "Edit", "EditAppProfile": "Edit App Profile", "EditIndexer": "Edit Indexer", "Enable": "Enable", - "EnableAutoHelpText": "If enabled, Movies will be automatically added to Prowlarr from this list", - "EnableAutomaticAdd": "Enable Automatic Add", "EnableAutomaticSearch": "Enable Automatic Search", "EnableAutomaticSearchHelpText": "Will be used when automatic searches are performed via the UI or by Prowlarr", - "EnableAutomaticSearchHelpTextWarning": "Will be used when interactive search is used", - "EnableColorImpairedMode": "Enable Color-Impaired Mode", - "EnableColorImpairedModeHelpText": "Altered style to allow color-impaired users to better distinguish color coded information", - "EnableCompletedDownloadHandlingHelpText": "Automatically import completed downloads from download client", "Enabled": "Enabled", - "EnabledHelpText": "Enable this list for use in Prowlarr", - "EnableHelpText": "Enable metadata file creation for this metadata type", "EnableIndexer": "Enable Indexer", "EnableInteractiveSearch": "Enable Interactive Search", "EnableInteractiveSearchHelpText": "Will be used when interactive search is used", - "EnableInteractiveSearchHelpTextWarning": "Search is not supported with this indexer", - "EnableMediaInfoHelpText": "Extract video information such as resolution, runtime and codec information from files. This requires Prowlarr to read parts of the file which may cause high disk or network activity during scans.", "EnableRss": "Enable RSS", "EnableRssHelpText": "Enable Rss feed for Indexer", "EnableSSL": "Enable SSL", @@ -152,7 +135,6 @@ "Events": "Events", "EventType": "Event Type", "Exception": "Exception", - "ExistingMovies": "Existing Movie(s)", "ExistingTag": "Existing tag", "Failed": "Failed", "FeatureRequests": "Feature Requests", @@ -160,6 +142,7 @@ "Files": "Files", "Filter": "Filter", "FilterPlaceHolder": "Search indexers", + "Filters": "Filters", "Fixed": "Fixed", "FocusSearchBox": "Focus Search Box", "Folder": "Folder", @@ -175,18 +158,21 @@ "HiddenClickToShow": "Hidden, click to show", "HideAdvanced": "Hide Advanced", "History": "History", + "HistoryCleanup": "History Cleanup", + "HistoryCleanupDaysHelpText": "Set to 0 to disable automatic cleanup", + "HistoryCleanupDaysHelpTextWarning": "History items older than the selected number of days will be cleaned up automatically", "HomePage": "Home Page", "Host": "Host", "Hostname": "Hostname", "Id": "Id", "IgnoredAddresses": "Ignored Addresses", "IllRestartLater": "I'll restart later", - "Importing": "Importing", "IncludeHealthWarningsHelpText": "Include Health Warnings", "Indexer": "Indexer", "IndexerAuth": "Indexer Auth", "IndexerFlags": "Indexer Flags", "IndexerHealthCheckNoIndexers": "No indexers enabled, Prowlarr will not return search results", + "IndexerInfo": "Indexer Info", "IndexerLongTermStatusCheckAllClientMessage": "All indexers are unavailable due to failures for more than 6 hours", "IndexerLongTermStatusCheckSingleClientMessage": "Indexers unavailable due to failures for more than 6 hours: {0}", "IndexerObsoleteCheckMessage": "Indexers are obsolete or have been updated: {0}. Please remove and (or) re-add to Prowlarr", @@ -211,7 +197,6 @@ "Interval": "Interval", "KeyboardShortcuts": "Keyboard Shortcuts", "Language": "Language", - "Languages": "Languages", "LastWriteTime": "Last Write Time", "LaunchBrowserHelpText": " Open a web browser and navigate to the Prowlarr homepage on app start.", "Level": "Level", @@ -220,27 +205,16 @@ "LogLevel": "Log Level", "LogLevelTraceHelpTextWarning": "Trace logging should only be enabled temporarily", "Logs": "Logs", - "MaintenanceRelease": "Maintenance release", + "MaintenanceRelease": "Maintenance Release: bug fixes and other improvements. See Github Commit History for more details", "Manual": "Manual", - "MaximumLimits": "Maximum Limits", + "MassEditor": "Mass Editor", "Mechanism": "Mechanism", "Message": "Message", "MIA": "MIA", - "MinimumLimits": "Minimum Limits", - "MinutesHundredTwenty": "120 Minutes: {0}", - "MinutesNinety": "90 Minutes: {0}", - "MinutesSixty": "60 Minutes: {0}", "Mode": "Mode", - "MonoNotNetCoreCheckMessage": "Please upgrade to the .NET Core version of Prowlarr", - "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls workaround still enabled, consider removing MONO_TLS_PROVIDER=legacy environment option", - "MonoVersion": "Mono Version", - "MonoVersionCheckUpgradeRecommendedMessage": "Currently installed Mono version {0} is supported but upgrading to {1} is recommended.", "MoreInfo": "More Info", - "MovieDetailsNextMovie": "Movie Details: Next Movie", - "MovieDetailsPreviousMovie": "Movie Details: Previous Movie", "MovieIndexScrollBottom": "Movie Index: Scroll Bottom", "MovieIndexScrollTop": "Movie Index: Scroll Top", - "Movies": "Movies", "MovieSearch": "Movie Search", "Name": "Name", "NetCore": ".NET", @@ -249,10 +223,8 @@ "NoChange": "No Change", "NoChanges": "No Changes", "NoLeaveIt": "No, Leave It", - "NoLimitForAnyRuntime": "No limit for any runtime", "NoLinks": "No Links", "NoLogFiles": "No log files", - "NoMinimumForAnyRuntime": "No minimum for any runtime", "NoSearchResultsFound": "No search results found, try performing a new search below.", "NoTagsHaveBeenAddedYet": "No tags have been added yet", "Notification": "Notification", @@ -264,6 +236,7 @@ "Ok": "Ok", "OnApplicationUpdate": "On Application Update", "OnApplicationUpdateHelpText": "On Application Update", + "OnGrab": "On Grab", "OnHealthIssue": "On Health Issue", "OnHealthIssueHelpText": "On Health Issue", "OpenBrowserOnStart": "Open browser on start", @@ -274,13 +247,11 @@ "PageSizeHelpText": "Number of items to show on each page", "Password": "Password", "Peers": "Peers", - "Pending": "Pending", "PendingChangesDiscardChanges": "Discard changes and leave", "PendingChangesMessage": "You have unsaved changes, are you sure you want to leave this page?", "PendingChangesStayReview": "Stay and review changes", "Port": "Port", "PortNumber": "Port Number", - "PreferredSize": "Preferred Size", "Presets": "Presets", "Priority": "Priority", "PriorityHelpText": "Prioritize multiple Download Clients. Round-Robin is used for clients with the same priority.", @@ -290,6 +261,7 @@ "Protocol": "Protocol", "ProwlarrSupportsAnyDownloadClient": "Prowlarr supports any of the download clients listed below.", "ProwlarrSupportsAnyIndexer": "Prowlarr supports many indexers in addition to any indexer that uses the Newznab/Torznab standard using 'Generic Newznab' (for usenet) or 'Generic Torznab' (for torrents). Search & Select your indexer from below.", + "Proxies": "Proxies", "Proxy": "Proxy", "ProxyBypassFilterHelpText": "Use ',' as a separator, and '*.' as a wildcard for subdomains", "ProxyCheckBadRequestMessage": "Failed to test proxy. StatusCode: {0}", @@ -300,10 +272,9 @@ "ProxyUsernameHelpText": "You only need to enter a username and password if one is required. Leave them blank otherwise.", "PtpOldSettingsCheckMessage": "The following PassThePopcorn indexers have deprecated settings and should be updated: {0}", "Public": "Public", - "QualityDefinitions": "Quality Definitions", - "QualitySettings": "Quality Settings", "Query": "Query", "QueryOptions": "Query Options", + "QueryResults": "Query Results", "Queue": "Queue", "ReadTheWikiForMoreInformation": "Read the Wiki for more information", "Reddit": "Reddit", @@ -312,7 +283,6 @@ "Refresh": "Refresh", "RefreshMovie": "Refresh movie", "ReleaseBranchCheckOfficialBranchMessage": "Branch {0} is not a valid Prowlarr release branch, you will not receive updates", - "ReleaseBranchCheckPreviousVersionMessage": "Branch {0} is for a previous version of Prowlarr, set branch to 'Nightly' for further updates", "ReleaseStatus": "Release Status", "Reload": "Reload", "RemovedFromTaskQueue": "Removed from task queue", @@ -326,7 +296,6 @@ "RestartRequiredHelpTextWarning": "Requires restart to take effect", "Restore": "Restore", "RestoreBackup": "Restore Backup", - "Restrictions": "Restrictions", "Result": "Result", "Retention": "Retention", "RSS": "RSS", @@ -399,6 +368,7 @@ "TestAll": "Test All", "TestAllApps": "Test All Apps", "TestAllClients": "Test All Clients", + "TestAllIndexers": "Test All Indexers", "Time": "Time", "Title": "Title", "Today": "Today", @@ -419,6 +389,7 @@ "UnableToAddANewIndexerPleaseTryAgain": "Unable to add a new indexer, please try again.", "UnableToAddANewIndexerProxyPleaseTryAgain": "Unable to add a new indexer proxy, please try again.", "UnableToAddANewNotificationPleaseTryAgain": "Unable to add a new notification, please try again.", + "UnableToLoadApplicationList": "Unable to load application list", "UnableToLoadAppProfiles": "Unable to load app profiles", "UnableToLoadBackups": "Unable to load backups", "UnableToLoadDevelopmentSettings": "Unable to load Development settings", @@ -426,9 +397,7 @@ "UnableToLoadGeneralSettings": "Unable to load General settings", "UnableToLoadHistory": "Unable to load history", "UnableToLoadIndexerProxies": "Unable To Load Indexer Proxies", - "UnableToLoadIndexers": "Unable to load Indexers", "UnableToLoadNotifications": "Unable to load Notifications", - "UnableToLoadQualityDefinitions": "Unable to load Quality Definitions", "UnableToLoadTags": "Unable to load Tags", "UnableToLoadUISettings": "Unable to load UI settings", "UnsavedChanges": "Unsaved Changes", @@ -441,14 +410,17 @@ "Updates": "Updates", "UpdateScriptPathHelpText": "Path to a custom script that takes an extracted update package and handle the remainder of the update process", "Uptime": "Uptime", + "Url": "Url", "URLBase": "URL Base", "UrlBaseHelpText": "For reverse proxy support, default is empty", "Usenet": "Usenet", "UseProxy": "Use Proxy", + "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent provided by the app that called the API", "Username": "Username", "Version": "Version", "View": "View", "Warn": "Warn", + "Website": "Website", "Wiki": "Wiki", "YesCancel": "Yes, Cancel", "Yesterday": "Yesterday" From 2bae37d0c54dc2b5b3c4226d245f403ad39b7533 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Fri, 31 Dec 2021 10:19:05 -0600 Subject: [PATCH 0284/2320] Fixed: (TorrentLeech) Calculating Incorrect Age Closes #720 --- src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs index 3e4867382..3152fc1eb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs @@ -281,7 +281,7 @@ namespace NzbDrone.Core.Indexers.Definitions var torrentId = row.fid.ToString(); var details = new Uri(_settings.BaseUrl + "torrent/" + torrentId); var link = new Uri(_settings.BaseUrl + "download/" + torrentId + "/" + row.filename); - var publishDate = DateTime.ParseExact(row.addedTimestamp.ToString(), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + var publishDate = DateTime.ParseExact(row.addedTimestamp.ToString(), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); var seeders = (int)row.seeders; var leechers = (int)row.leechers; var grabs = (int)row.completed; From 9cb04466c15ca3080d6e2b121d141d3a0442a0cc Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 31 Dec 2021 13:19:22 -0600 Subject: [PATCH 0285/2320] DbType param on update check --- src/NzbDrone.Core/Update/UpdatePackageProvider.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Update/UpdatePackageProvider.cs b/src/NzbDrone.Core/Update/UpdatePackageProvider.cs index f441d2901..8b7a5be43 100644 --- a/src/NzbDrone.Core/Update/UpdatePackageProvider.cs +++ b/src/NzbDrone.Core/Update/UpdatePackageProvider.cs @@ -5,6 +5,7 @@ using NzbDrone.Common.Cloud; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Http; using NzbDrone.Core.Analytics; +using NzbDrone.Core.Datastore; namespace NzbDrone.Core.Update { @@ -20,13 +21,15 @@ namespace NzbDrone.Core.Update private readonly IHttpRequestBuilderFactory _requestBuilder; private readonly IPlatformInfo _platformInfo; private readonly IAnalyticsService _analyticsService; + private readonly IMainDatabase _mainDatabase; - public UpdatePackageProvider(IHttpClient httpClient, IProwlarrCloudRequestBuilder requestBuilder, IAnalyticsService analyticsService, IPlatformInfo platformInfo) + public UpdatePackageProvider(IHttpClient httpClient, IProwlarrCloudRequestBuilder requestBuilder, IAnalyticsService analyticsService, IPlatformInfo platformInfo, IMainDatabase mainDatabase) { _platformInfo = platformInfo; _analyticsService = analyticsService; _requestBuilder = requestBuilder.Services; _httpClient = httpClient; + _mainDatabase = mainDatabase; } public UpdatePackage GetLatestUpdate(string branch, Version currentVersion) @@ -38,6 +41,7 @@ namespace NzbDrone.Core.Update .AddQueryParam("arch", RuntimeInformation.OSArchitecture) .AddQueryParam("runtime", PlatformInfo.Platform.ToString().ToLowerInvariant()) .AddQueryParam("runtimeVer", _platformInfo.Version) + .AddQueryParam("dbType", _mainDatabase.DatabaseType) .SetSegment("branch", branch); if (_analyticsService.IsEnabled) @@ -65,6 +69,7 @@ namespace NzbDrone.Core.Update .AddQueryParam("arch", RuntimeInformation.OSArchitecture) .AddQueryParam("runtime", PlatformInfo.Platform.ToString().ToLowerInvariant()) .AddQueryParam("runtimeVer", _platformInfo.Version) + .AddQueryParam("dbType", _mainDatabase.DatabaseType) .SetSegment("branch", branch); if (previousVersion != null && previousVersion != currentVersion) From 03db7a9bbd1da8b9e736206b5ee96806aa23e51b Mon Sep 17 00:00:00 2001 From: Yukine <devyukine@gmx.de> Date: Fri, 31 Dec 2021 20:55:47 +0100 Subject: [PATCH 0286/2320] Fixed: (SpeedApp) correct categories in query string of requests --- src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs index bc4078427..f9dd987fa 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs @@ -335,7 +335,7 @@ namespace NzbDrone.Core.Indexers.Definitions } } - var searchUrl = Settings.BaseUrl + "/api/torrent?" + qc.GetQueryString(); + var searchUrl = Settings.BaseUrl + "/api/torrent?" + qc.GetQueryString(duplicateKeysIfMulti: true); var request = new IndexerRequest(searchUrl, HttpAccept.Json); From ecca6e9f492e890a70c3bfe98cf3550797b8678d Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 31 Dec 2021 15:25:56 -0600 Subject: [PATCH 0287/2320] New: TVDB and TMDB Search for AvistaZ Ref #717 --- src/NzbDrone.Core/Indexers/Definitions/AvistaZ.cs | 4 ++-- .../Definitions/Avistaz/AvistazRequestGenerator.cs | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/AvistaZ.cs b/src/NzbDrone.Core/Indexers/Definitions/AvistaZ.cs index 97dda7e42..69721505c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AvistaZ.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AvistaZ.cs @@ -36,11 +36,11 @@ namespace NzbDrone.Core.Indexers.Definitions { TvSearchParams = new List<TvSearchParam> { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId }, MovieSearchParams = new List<MovieSearchParam> { - MovieSearchParam.Q, MovieSearchParam.ImdbId + MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId } }; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs index ab8d086b7..424b5def3 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs @@ -77,6 +77,10 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz { parameters.Add("imdb", searchCriteria.FullImdbId); } + else if (searchCriteria.TmdbId.HasValue) + { + parameters.Add("tmdb", searchCriteria.TmdbId.Value.ToString()); + } else { parameters.Add("search", GetSearchTerm(searchCriteria.SanitizedSearchTerm).Trim()); @@ -105,6 +109,12 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace()) { parameters.Add("imdb", searchCriteria.FullImdbId); + parameters.Add("search", GetSearchTerm(searchCriteria.EpisodeSearchString).Trim()); + } + else if (searchCriteria.TvdbId.HasValue) + { + parameters.Add("tvdb", searchCriteria.TvdbId.Value.ToString()); + parameters.Add("search", GetSearchTerm(searchCriteria.EpisodeSearchString).Trim()); } else { From a366bec6849d384676aef51945779a9a00186b57 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 31 Dec 2021 15:26:56 -0600 Subject: [PATCH 0288/2320] New: Reenable TV Id search for PrivateHD --- src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs b/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs index 61e918986..b8fd39c10 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using NLog; -using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Definitions.Avistaz; using NzbDrone.Core.Messaging.Events; @@ -36,11 +35,11 @@ namespace NzbDrone.Core.Indexers.Definitions { TvSearchParams = new List<TvSearchParam> { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId }, MovieSearchParams = new List<MovieSearchParam> { - MovieSearchParam.Q, MovieSearchParam.ImdbId + MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId }, MusicSearchParams = new List<MusicSearchParam> { From 1dc00eb4455868fee73d8e11ea567c79bbc09a99 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 31 Dec 2021 19:32:44 -0600 Subject: [PATCH 0289/2320] More powerful label actions --- .github/label-actions.yml | 16 ++++++++++++++++ .github/workflows/label-actions.yml | 23 +++++++++++++++++++++++ .github/workflows/support.yml | 21 --------------------- 3 files changed, 39 insertions(+), 21 deletions(-) create mode 100644 .github/label-actions.yml create mode 100644 .github/workflows/label-actions.yml delete mode 100644 .github/workflows/support.yml diff --git a/.github/label-actions.yml b/.github/label-actions.yml new file mode 100644 index 000000000..a5f466a16 --- /dev/null +++ b/.github/label-actions.yml @@ -0,0 +1,16 @@ +# Configuration for Label Actions - https://github.com/dessant/label-actions + +'Type: Support': + comment: > + :wave: @{issue-author}, we use the issue tracker exclusively + for bug reports and feature requests. However, this issue appears + to be a support request. Please hop over onto our [Discord](https://prowlarr.com/discord) + or [Subreddit](https://reddit.com/r/prowlarr) + close: true + +'Type: Indexer Request': + comment: > + :wave: @{issue-author}, we use the issue tracker exclusively + for bug reports and feature requests. However, this issue appears + to be a indexer request. Please use our Indexer request [site](https://requests.prowlarr.com/) + close: true \ No newline at end of file diff --git a/.github/workflows/label-actions.yml b/.github/workflows/label-actions.yml new file mode 100644 index 000000000..1bccc0238 --- /dev/null +++ b/.github/workflows/label-actions.yml @@ -0,0 +1,23 @@ +name: 'Label Actions' + +on: + issues: + types: [labeled, unlabeled] + pull_request: + types: [labeled, unlabeled] + discussion: + types: [labeled, unlabeled] + +permissions: + contents: read + issues: write + pull-requests: write + discussions: write + +jobs: + action: + runs-on: ubuntu-latest + steps: + - uses: dessant/label-actions@v2 + with: + process-only: 'issues, prs' \ No newline at end of file diff --git a/.github/workflows/support.yml b/.github/workflows/support.yml deleted file mode 100644 index 46ce76c8b..000000000 --- a/.github/workflows/support.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: 'Support requests' - -on: - issues: - types: [labeled, unlabeled, reopened] - -jobs: - support: - runs-on: ubuntu-latest - steps: - - uses: dessant/support-requests@v2 - with: - github-token: ${{ github.token }} - support-label: 'Type: Support' - issue-comment: > - :wave: @{issue-author}, we use the issue tracker exclusively - for bug reports and feature requests. However, this issue appears - to be a support request. Please hop over onto our [Discord](https://prowlarr.com/discord) - or [Subreddit](https://reddit.com/r/prowlarr) - close-issue: true - lock-issue: false \ No newline at end of file From 1373ab255dfd9eeab4f75561dda5b90f63b6f92d Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Sat, 1 Jan 2022 01:40:36 +0000 Subject: [PATCH 0290/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index d3edebdc9..5978cc42a 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -5300,7 +5300,7 @@ "IndexerPrivacy": { "enum": [ "public", - "semiPublic", + "semiPrivate", "private" ], "type": "string" From 480a76c290386c5f1622f80a24e88650669f7169 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 1 Jan 2022 14:23:44 -0600 Subject: [PATCH 0291/2320] New: Support for language metadata --- src/NzbDrone.Core/IndexerSearch/NewznabResults.cs | 2 ++ src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs index da6d01c82..ec3f6965b 100644 --- a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs +++ b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs @@ -89,6 +89,8 @@ namespace NzbDrone.Core.IndexerSearch new XAttribute("type", protocol == DownloadProtocol.Torrent ? "application/x-bittorrent" : "application/x-nzb")), r.Categories == null ? null : from c in r.Categories select GetNabElement("category", c.Id, protocol), r.IndexerFlags == null ? null : from f in r.IndexerFlags select GetNabElement("tag", f.Name, protocol), + r.Languages == null ? null : from c in r.Languages select GetNabElement("language", c.Id, protocol), + r.Subs == null ? null : from c in r.Subs select GetNabElement("subs", c.Id, protocol), GetNabElement("rageid", r.TvRageId, protocol), GetNabElement("tvdbid", r.TvdbId, protocol), GetNabElement("imdb", r.ImdbId.ToString("D7"), protocol), diff --git a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs index 23ce03963..5a67933d5 100644 --- a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs +++ b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using NzbDrone.Core.Indexers; +using NzbDrone.Core.Languages; namespace NzbDrone.Core.Parser.Model { @@ -44,8 +45,9 @@ namespace NzbDrone.Core.Parser.Model public string Container { get; set; } public string Codec { get; set; } public string Resolution { get; set; } + public ICollection<Language> Languages { get; set; } + public ICollection<Language> Subs { get; set; } public ICollection<IndexerCategory> Categories { get; set; } - public ICollection<IndexerFlag> IndexerFlags { get; set; } public int Age From 66b4c7891de20908717a4ec2cf13d0804ad13231 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 1 Jan 2022 14:43:49 -0600 Subject: [PATCH 0292/2320] New: TmdbId Parameter for TV Search --- .../Definitions/TvSearchCriteria.cs | 6 ++++++ .../IndexerSearch/ReleaseSearchService.cs | 1 + .../Indexers/IndexerCapabilities.cs | 16 +++++++++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/TvSearchCriteria.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/TvSearchCriteria.cs index a52361fb6..4a1303d28 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/TvSearchCriteria.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/TvSearchCriteria.cs @@ -16,6 +16,7 @@ namespace NzbDrone.Core.IndexerSearch.Definitions public int? RId { get; set; } public int? TvMazeId { get; set; } public int? TraktId { get; set; } + public int? TmdbId { get; set; } public string SanitizedTvSearchString => (SanitizedSearchTerm + " " + EpisodeSearchString).Trim(); public string EpisodeSearchString => GetEpisodeSearchString(); @@ -74,6 +75,11 @@ namespace NzbDrone.Core.IndexerSearch.Definitions builder.Append($" TraktId:[{TraktId}]"); } + if (TmdbId.HasValue) + { + builder.Append($" TmdbId:[{TmdbId}]"); + } + builder = builder.Append(searchEpisodeTerm); return builder.ToString().Trim(); } diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs index 14e4bba7c..863432e4a 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs @@ -84,6 +84,7 @@ namespace NzbDrone.Core.IndexerSearch searchSpec.TvdbId = request.tvdbid; searchSpec.ImdbId = request.imdbid; searchSpec.TraktId = request.traktid; + searchSpec.TmdbId = request.tmdbid; searchSpec.RId = request.rid; searchSpec.TvMazeId = request.tvmazeid; diff --git a/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs b/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs index 92f66de27..6a455b96c 100644 --- a/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs +++ b/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs @@ -13,7 +13,9 @@ namespace NzbDrone.Core.Indexers ImdbId, TvdbId, RId, - TvMazeId + TvMazeId, + TraktId, + TmdbId } public enum MovieSearchParam @@ -65,6 +67,8 @@ namespace NzbDrone.Core.Indexers public bool TvSearchTvdbAvailable => TvSearchParams.Contains(TvSearchParam.TvdbId); public bool TvSearchTvRageAvailable => TvSearchParams.Contains(TvSearchParam.RId); public bool TvSearchTvMazeAvailable => TvSearchParams.Contains(TvSearchParam.TvMazeId); + public bool TvSearchTraktAvailable => TvSearchParams.Contains(TvSearchParam.TraktId); + public bool TvSearchTmdbAvailable => TvSearchParams.Contains(TvSearchParam.TmdbId); public List<MovieSearchParam> MovieSearchParams; public bool MovieSearchAvailable => MovieSearchParams.Count > 0; @@ -284,6 +288,16 @@ namespace NzbDrone.Core.Indexers parameters.Add("tvmazeid"); } + if (TvSearchTraktAvailable) + { + parameters.Add("traktid"); + } + + if (TvSearchTmdbAvailable) + { + parameters.Add("tmdbid"); + } + return string.Join(",", parameters); } From e2ddfbff9ce0a011c7efbdf6a08ff1768c94501f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 1 Jan 2022 14:49:01 -0600 Subject: [PATCH 0293/2320] New: Genre parameter for Movie search --- .../IndexerSearch/Definitions/MovieSearchCriteria.cs | 6 ++++++ .../IndexerSearch/ReleaseSearchService.cs | 1 + src/NzbDrone.Core/Indexers/IndexerCapabilities.cs | 12 ++++++++++++ 3 files changed, 19 insertions(+) diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/MovieSearchCriteria.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/MovieSearchCriteria.cs index c752c3a4b..e576d8eee 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/MovieSearchCriteria.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/MovieSearchCriteria.cs @@ -10,6 +10,7 @@ namespace NzbDrone.Core.IndexerSearch.Definitions public int? TmdbId { get; set; } public int? TraktId { get; set; } public int? Year { get; set; } + public string Genre { get; set; } public override bool RssSearch { @@ -64,6 +65,11 @@ namespace NzbDrone.Core.IndexerSearch.Definitions builder = builder.Append($" TraktId:[{TraktId}]"); } + if (Genre.IsNotNullOrWhiteSpace()) + { + builder = builder.Append($" Genre:[{Genre}]"); + } + return builder.ToString().Trim(); } } diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs index 863432e4a..c274e95f2 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs @@ -60,6 +60,7 @@ namespace NzbDrone.Core.IndexerSearch searchSpec.TmdbId = request.tmdbid; searchSpec.TraktId = request.traktid; searchSpec.Year = request.year; + searchSpec.Genre = request.genre; return new NewznabResults { Releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) }; } diff --git a/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs b/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs index 6a455b96c..3d58c2739 100644 --- a/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs +++ b/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs @@ -26,6 +26,7 @@ namespace NzbDrone.Core.Indexers ImdbTitle, ImdbYear, TraktId, + Genre } public enum MusicSearchParam @@ -75,6 +76,7 @@ namespace NzbDrone.Core.Indexers public bool MovieSearchImdbAvailable => MovieSearchParams.Contains(MovieSearchParam.ImdbId); public bool MovieSearchTmdbAvailable => MovieSearchParams.Contains(MovieSearchParam.TmdbId); public bool MovieSearchTraktAvailable => MovieSearchParams.Contains(MovieSearchParam.TraktId); + public bool MovieSearchGenreAvailable => MovieSearchParams.Contains(MovieSearchParam.Genre); public List<MusicSearchParam> MusicSearchParams; public bool MusicSearchAvailable => MusicSearchParams.Count > 0; @@ -321,6 +323,16 @@ namespace NzbDrone.Core.Indexers parameters.Add("tmdbid"); } + if (MovieSearchTraktAvailable) + { + parameters.Add("traktid"); + } + + if (MovieSearchGenreAvailable) + { + parameters.Add("genre"); + } + return string.Join(",", parameters); } From a5e13ca776b629a432a389981235e77f350a915d Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 1 Jan 2022 15:04:05 -0600 Subject: [PATCH 0294/2320] New: Genre parameter for Music search --- .../IndexerSearch/Definitions/MusicSearchCriteria.cs | 2 ++ src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs | 2 ++ src/NzbDrone.Core/Indexers/IndexerCapabilities.cs | 9 ++++++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/MusicSearchCriteria.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/MusicSearchCriteria.cs index 337c06fa5..d75e3a0db 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/MusicSearchCriteria.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/MusicSearchCriteria.cs @@ -7,6 +7,8 @@ namespace NzbDrone.Core.IndexerSearch.Definitions public string Album { get; set; } public string Artist { get; set; } public string Label { get; set; } + public string Genre { get; set; } + public int? Year { get; set; } public override bool RssSearch { diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs index c274e95f2..ac05628f5 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs @@ -72,6 +72,8 @@ namespace NzbDrone.Core.IndexerSearch searchSpec.Artist = request.artist; searchSpec.Album = request.album; searchSpec.Label = request.label; + searchSpec.Genre = request.genre; + searchSpec.Year = request.year; return new NewznabResults { Releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) }; } diff --git a/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs b/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs index 3d58c2739..e0e26593b 100644 --- a/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs +++ b/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs @@ -35,7 +35,8 @@ namespace NzbDrone.Core.Indexers Album, Artist, Label, - Year + Year, + Genre } public enum SearchParam @@ -84,6 +85,7 @@ namespace NzbDrone.Core.Indexers public bool MusicSearchArtistAvailable => MusicSearchParams.Contains(MusicSearchParam.Artist); public bool MusicSearchLabelAvailable => MusicSearchParams.Contains(MusicSearchParam.Label); public bool MusicSearchYearAvailable => MusicSearchParams.Contains(MusicSearchParam.Year); + public bool MusicSearchGenreAvailable => MusicSearchParams.Contains(MusicSearchParam.Genre); public List<BookSearchParam> BookSearchParams; public bool BookSearchAvailable => BookSearchParams.Count > 0; @@ -359,6 +361,11 @@ namespace NzbDrone.Core.Indexers parameters.Add("year"); } + if (MusicSearchGenreAvailable) + { + parameters.Add("genre"); + } + return string.Join(",", parameters); } From b9dfe5e35918211e02e61db1a7fe8416117ea356 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 1 Jan 2022 20:01:40 -0600 Subject: [PATCH 0295/2320] Fixed: (Gazelle) Use InfoUrl for GUID to avoid global duplicates --- .../Definitions/Gazelle/GazelleParser.cs | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs index 48be951d2..3aa5ec297 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs @@ -52,6 +52,8 @@ namespace NzbDrone.Core.Indexers.Gazelle foreach (var result in jsonResponse.Resource.Response.Results) { + var posterUrl = GetPosterUrl(result.Cover); + if (result.Torrents != null) { foreach (var torrent in result.Torrents) @@ -66,9 +68,11 @@ namespace NzbDrone.Core.Indexers.Gazelle title += " [Cue]"; } + var infoUrl = GetInfoUrl(result.GroupId, id); + var release = new GazelleInfo() { - Guid = string.Format("Gazelle-{0}", id), + Guid = infoUrl, Title = WebUtility.HtmlDecode(title), Container = torrent.Encoding, Files = torrent.FileCount, @@ -76,11 +80,12 @@ namespace NzbDrone.Core.Indexers.Gazelle Codec = torrent.Format, Size = long.Parse(torrent.Size), DownloadUrl = GetDownloadUrl(id), - InfoUrl = GetInfoUrl(result.GroupId, id), + InfoUrl = infoUrl, Seeders = int.Parse(torrent.Seeders), Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders), PublishDate = torrent.Time.ToUniversalTime(), Scene = torrent.Scene, + PosterUrl = posterUrl }; var category = torrent.Category; @@ -100,19 +105,21 @@ namespace NzbDrone.Core.Indexers.Gazelle { var id = result.TorrentId; var groupName = WebUtility.HtmlDecode(result.GroupName); + var infoUrl = GetInfoUrl(result.GroupId, id); var release = new GazelleInfo() { - Guid = string.Format("Gazelle-{0}", id), + Guid = infoUrl, Title = groupName, Size = long.Parse(result.Size), DownloadUrl = GetDownloadUrl(id), - InfoUrl = GetInfoUrl(result.GroupId, id), + InfoUrl = infoUrl, Seeders = int.Parse(result.Seeders), Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders), Files = result.FileCount, Grabs = result.Snatches, PublishDate = DateTimeOffset.FromUnixTimeSeconds(result.GroupTime).UtcDateTime, + PosterUrl = posterUrl }; var category = result.Category; @@ -147,7 +154,19 @@ namespace NzbDrone.Core.Indexers.Gazelle return url.FullUri; } - private string GetInfoUrl(string groupId, int torrentId) + protected virtual string GetPosterUrl(string cover) + { + if (!string.IsNullOrEmpty(cover)) + { + return cover.StartsWith("http") ? + new HttpUri(cover).FullUri : + new HttpUri(_settings.BaseUrl).CombinePath(cover).FullUri; + } + + return null; + } + + protected virtual string GetInfoUrl(string groupId, int torrentId) { var url = new HttpUri(_settings.BaseUrl) .CombinePath("/torrents.php") From 76982c598861d57556960d8eecce261db5bc6d99 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 1 Jan 2022 20:08:59 -0600 Subject: [PATCH 0296/2320] Fixed: (Gazelle) Freeleech detection for releases --- .../Indexers/Definitions/Gazelle/GazelleParser.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs index 3aa5ec297..04daef331 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs @@ -85,7 +85,9 @@ namespace NzbDrone.Core.Indexers.Gazelle Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders), PublishDate = torrent.Time.ToUniversalTime(), Scene = torrent.Scene, - PosterUrl = posterUrl + PosterUrl = posterUrl, + DownloadVolumeFactor = torrent.IsFreeLeech || torrent.IsNeutralLeech || torrent.IsPersonalFreeLeech ? 0 : 1, + UploadVolumeFactor = torrent.IsNeutralLeech ? 0 : 1 }; var category = torrent.Category; @@ -119,7 +121,9 @@ namespace NzbDrone.Core.Indexers.Gazelle Files = result.FileCount, Grabs = result.Snatches, PublishDate = DateTimeOffset.FromUnixTimeSeconds(result.GroupTime).UtcDateTime, - PosterUrl = posterUrl + PosterUrl = posterUrl, + DownloadVolumeFactor = result.IsFreeLeech || result.IsNeutralLeech || result.IsPersonalFreeLeech ? 0 : 1, + UploadVolumeFactor = result.IsNeutralLeech ? 0 : 1 }; var category = result.Category; From 8a73cf72c2c7386f36b9b25211f1500decf9979c Mon Sep 17 00:00:00 2001 From: Agneev Mukherjee <19761269+agneevX@users.noreply.github.com> Date: Sun, 2 Jan 2022 22:35:13 +0530 Subject: [PATCH 0297/2320] Set login.html theme-color to color of logo --- frontend/src/login.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/login.html b/frontend/src/login.html index 6ec2c81d6..dcfb23140 100644 --- a/frontend/src/login.html +++ b/frontend/src/login.html @@ -6,8 +6,8 @@ <meta name="mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-capable" content="yes" /> - <!-- Chrome, Opera, and Firefox OS --> - <meta name="theme-color" content="#464b51" /> + <!-- Chrome, Safari, Opera, and Firefox OS --> + <meta name="theme-color" content="#e66001" /> <!-- Windows Phone --> <meta name="msapplication-navbutton-color" content="#464b51" /> From 8a5194e604e7560cbe74fe53b32c5796a871afd6 Mon Sep 17 00:00:00 2001 From: Agneev Mukherjee <19761269+agneevX@users.noreply.github.com> Date: Sun, 2 Jan 2022 22:36:39 +0530 Subject: [PATCH 0298/2320] Update index.ejs --- frontend/src/index.ejs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/index.ejs b/frontend/src/index.ejs index 99218503c..2df008f31 100644 --- a/frontend/src/index.ejs +++ b/frontend/src/index.ejs @@ -6,8 +6,8 @@ <meta name="mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-capable" content="yes" /> - <!-- Chrome, Opera, and Firefox OS --> - <meta name="theme-color" content="#3a3f51" /> + <!-- Chrome, Safari, Opera, and Firefox OS --> + <meta name="theme-color" content="#e66001" /> <!-- Windows Phone --> <meta name="msapplication-navbutton-color" content="#3a3f51" /> From 1e532624af153f812f6b001deba88a9145c2fd1e Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 2 Jan 2022 16:45:34 -0600 Subject: [PATCH 0299/2320] Fixed: (Redacted) Guid and FL Parsing in line with Gazelle --- .../Indexers/Definitions/Redacted.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs b/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs index 445e90170..4aef85308 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs @@ -221,9 +221,11 @@ namespace NzbDrone.Core.Indexers.Definitions title += " [Cue]"; } + var infoUrl = GetInfoUrl(result.GroupId, id); + GazelleInfo release = new GazelleInfo() { - Guid = string.Format("Redacted-{0}", id), + Guid = infoUrl, // Splice Title from info to avoid calling API again for every torrent. Title = WebUtility.HtmlDecode(title), @@ -232,7 +234,7 @@ namespace NzbDrone.Core.Indexers.Definitions Codec = torrent.Format, Size = long.Parse(torrent.Size), DownloadUrl = GetDownloadUrl(id, torrent.CanUseToken), - InfoUrl = GetInfoUrl(result.GroupId, id), + InfoUrl = infoUrl, Seeders = int.Parse(torrent.Seeders), Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders), PublishDate = torrent.Time.ToUniversalTime(), @@ -240,6 +242,8 @@ namespace NzbDrone.Core.Indexers.Definitions Freeleech = torrent.IsFreeLeech || torrent.IsPersonalFreeLeech, Files = torrent.FileCount, Grabs = torrent.Snatches, + DownloadVolumeFactor = torrent.IsFreeLeech || torrent.IsNeutralLeech || torrent.IsPersonalFreeLeech ? 0 : 1, + UploadVolumeFactor = torrent.IsNeutralLeech ? 0 : 1 }; var category = torrent.Category; @@ -260,19 +264,23 @@ namespace NzbDrone.Core.Indexers.Definitions else { var id = result.TorrentId; + var infoUrl = GetInfoUrl(result.GroupId, id); + GazelleInfo release = new GazelleInfo() { - Guid = string.Format("Redacted-{0}", id), + Guid = infoUrl, Title = WebUtility.HtmlDecode(result.GroupName), Size = long.Parse(result.Size), DownloadUrl = GetDownloadUrl(id, result.CanUseToken), - InfoUrl = GetInfoUrl(result.GroupId, id), + InfoUrl = infoUrl, Seeders = int.Parse(result.Seeders), Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders), PublishDate = DateTimeOffset.FromUnixTimeSeconds(result.GroupTime).UtcDateTime, Freeleech = result.IsFreeLeech || result.IsPersonalFreeLeech, Files = result.FileCount, Grabs = result.Snatches, + DownloadVolumeFactor = result.IsFreeLeech || result.IsNeutralLeech || result.IsPersonalFreeLeech ? 0 : 1, + UploadVolumeFactor = result.IsNeutralLeech ? 0 : 1 }; var category = result.Category; From 3ecc926298016e326d1f7f77e556d281ec9ced7a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 2 Jan 2022 19:43:46 -0600 Subject: [PATCH 0300/2320] Fixed: (HDTorrents) Use Sanitized search string on all search types --- src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs index d1764d26d..a7f59e159 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs @@ -178,7 +178,7 @@ namespace NzbDrone.Core.Indexers.Definitions { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories)); + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); return pageableRequests; } @@ -187,7 +187,7 @@ namespace NzbDrone.Core.Indexers.Definitions { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId)); + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId)); return pageableRequests; } @@ -196,7 +196,7 @@ namespace NzbDrone.Core.Indexers.Definitions { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories)); + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); return pageableRequests; } @@ -205,7 +205,7 @@ namespace NzbDrone.Core.Indexers.Definitions { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories)); + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); return pageableRequests; } From 8e7acd894630eae5062c0f1b8276c647ee9216e1 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 2 Jan 2022 21:37:02 -0600 Subject: [PATCH 0301/2320] Fixed: (Mylar) Test indexer pull on setup to validate Mylar functionality --- src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs b/src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs index ba271b53e..c571d189b 100644 --- a/src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs +++ b/src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs @@ -133,12 +133,19 @@ namespace NzbDrone.Core.Applications.Mylar { return new ValidationFailure("ApiKey", status.Error.Message); } + + var indexers = GetIndexers(settings); } catch (HttpException ex) { _logger.Error(ex, "Unable to send test message"); return new ValidationFailure("BaseUrl", "Unable to complete application test"); } + catch (MylarException ex) + { + _logger.Error(ex, "Connection test failed"); + return new ValidationFailure("", ex.Message); + } catch (Exception ex) { _logger.Error(ex, "Unable to send test message"); From 07575ae239858c6d2d1baebc7b9f1892d552df79 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 2 Jan 2022 21:50:12 -0600 Subject: [PATCH 0302/2320] Fixed: (LazyLibrarian) Test indexer pull on setup to validate --- .../Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs index df397d678..abb1c0338 100644 --- a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs +++ b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs @@ -133,12 +133,19 @@ namespace NzbDrone.Core.Applications.LazyLibrarian { return new ValidationFailure("ApiKey", status.Error.Message); } + + var indexers = GetIndexers(settings); } catch (HttpException ex) { _logger.Error(ex, "Unable to send test message"); return new ValidationFailure("BaseUrl", "Unable to complete application test"); } + catch (LazyLibrarianException ex) + { + _logger.Error(ex, "Connection test failed"); + return new ValidationFailure("", ex.Message); + } catch (Exception ex) { _logger.Error(ex, "Unable to send test message"); From e04133d34a926584f2cf5074423d24cc238d6cf5 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 2 Jan 2022 23:19:47 -0600 Subject: [PATCH 0303/2320] More Mono Cleaning --- .../Http/HttpClientFixture.cs | 5 ---- .../Http/Dispatchers/ManagedHttpDispatcher.cs | 30 +++---------------- .../GlobalExceptionHandlers.cs | 10 ------- .../Instrumentation/Sentry/SentryTarget.cs | 9 +----- .../Processes/ProcessProvider.cs | 5 ---- src/NzbDrone.Test.Common/NzbDroneRunner.cs | 4 --- 6 files changed, 5 insertions(+), 58 deletions(-) diff --git a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs index f0e84583d..23f08adbe 100644 --- a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs +++ b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs @@ -229,11 +229,6 @@ namespace NzbDrone.Common.Test.Http [Test] public void should_follow_redirects_to_https() { - if (typeof(TDispatcher) == typeof(ManagedHttpDispatcher) && PlatformInfo.IsMono) - { - Assert.Ignore("Will fail on tls1.2 via managed dispatcher, ignore."); - } - var request = new HttpRequestBuilder($"https://{_httpBinHost}/redirect-to") .AddQueryParam("url", $"https://radarr.video/") .Build(); diff --git a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs index e5bcb6432..3fa5657c1 100644 --- a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs +++ b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs @@ -34,19 +34,10 @@ namespace NzbDrone.Common.Http.Dispatchers { var webRequest = (HttpWebRequest)WebRequest.Create((Uri)request.Url); - if (PlatformInfo.IsMono) - { - // On Mono GZipStream/DeflateStream leaks memory if an exception is thrown, use an intermediate buffer in that case. - webRequest.AutomaticDecompression = DecompressionMethods.None; - webRequest.Headers.Add("Accept-Encoding", "gzip"); - } - else - { - // Deflate is not a standard and could break depending on implementation. - // we should just stick with the more compatible Gzip - //http://stackoverflow.com/questions/8490718/how-to-decompress-stream-deflated-with-java-util-zip-deflater-in-net - webRequest.AutomaticDecompression = DecompressionMethods.GZip; - } + // Deflate is not a standard and could break depending on implementation. + // we should just stick with the more compatible Gzip + //http://stackoverflow.com/questions/8490718/how-to-decompress-stream-deflated-with-java-util-zip-deflater-in-net + webRequest.AutomaticDecompression = DecompressionMethods.GZip; webRequest.Method = request.Method.ToString(); webRequest.UserAgent = _userAgentBuilder.GetUserAgent(request.UseSimplifiedUserAgent); @@ -127,19 +118,6 @@ namespace NzbDrone.Common.Http.Dispatchers try { data = await responseStream.ToBytes(); - - if (PlatformInfo.IsMono && httpWebResponse.ContentEncoding == "gzip") - { - using (var compressedStream = new MemoryStream(data)) - using (var gzip = new GZipStream(compressedStream, CompressionMode.Decompress)) - using (var decompressedStream = new MemoryStream()) - { - gzip.CopyTo(decompressedStream); - data = decompressedStream.ToArray(); - } - - httpWebResponse.Headers.Remove("Content-Encoding"); - } } catch (Exception ex) { diff --git a/src/NzbDrone.Common/Instrumentation/GlobalExceptionHandlers.cs b/src/NzbDrone.Common/Instrumentation/GlobalExceptionHandlers.cs index 6f778d7de..50ede78a5 100644 --- a/src/NzbDrone.Common/Instrumentation/GlobalExceptionHandlers.cs +++ b/src/NzbDrone.Common/Instrumentation/GlobalExceptionHandlers.cs @@ -38,16 +38,6 @@ namespace NzbDrone.Common.Instrumentation return; } - if (PlatformInfo.IsMono) - { - if ((exception is TypeInitializationException && exception.InnerException is DllNotFoundException) || - exception is DllNotFoundException) - { - Logger.Debug(exception, "Minor Fail: " + exception.Message); - return; - } - } - Console.WriteLine("EPIC FAIL: {0}", exception); Logger.Fatal(exception, "EPIC FAIL."); } diff --git a/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs b/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs index 823d051ab..8832b6251 100644 --- a/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs +++ b/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs @@ -106,13 +106,6 @@ namespace NzbDrone.Common.Instrumentation.Sentry o.Debug = false; o.DiagnosticLevel = SentryLevel.Debug; o.Release = BuildInfo.Release; - if (PlatformInfo.IsMono) - { - // Mono 6.0 broke GzipStream.WriteAsync - // TODO: Check specific version - o.RequestBodyCompressionLevel = System.IO.Compression.CompressionLevel.NoCompression; - } - o.BeforeSend = x => SentryCleanser.CleanseEvent(x); o.BeforeBreadcrumb = x => SentryCleanser.CleanseBreadcrumb(x); o.Environment = BuildInfo.Branch; @@ -155,7 +148,7 @@ namespace NzbDrone.Common.Instrumentation.Sentry { scope.SetTag("is_docker", $"{osInfo.IsDocker}"); - if (osInfo.Name != null && PlatformInfo.IsMono) + if (osInfo.Name != null && !OsInfo.IsWindows) { // Sentry auto-detection of non-Windows platforms isn't that accurate on certain devices. scope.Contexts.OperatingSystem.Name = osInfo.Name.FirstCharToUpper(); diff --git a/src/NzbDrone.Common/Processes/ProcessProvider.cs b/src/NzbDrone.Common/Processes/ProcessProvider.cs index b55668200..953450aaa 100644 --- a/src/NzbDrone.Common/Processes/ProcessProvider.cs +++ b/src/NzbDrone.Common/Processes/ProcessProvider.cs @@ -366,11 +366,6 @@ namespace NzbDrone.Common.Processes private (string Path, string Args) GetPathAndArgs(string path, string args) { - if (PlatformInfo.IsMono && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase)) - { - return ("mono", $"--debug {path} {args}"); - } - if (OsInfo.IsWindows && path.EndsWith(".bat", StringComparison.InvariantCultureIgnoreCase)) { return ("cmd.exe", $"/c {path} {args}"); diff --git a/src/NzbDrone.Test.Common/NzbDroneRunner.cs b/src/NzbDrone.Test.Common/NzbDroneRunner.cs index 0a7251fc9..8ea3dd5ce 100644 --- a/src/NzbDrone.Test.Common/NzbDroneRunner.cs +++ b/src/NzbDrone.Test.Common/NzbDroneRunner.cs @@ -44,10 +44,6 @@ namespace NzbDrone.Test.Common { consoleExe = "Prowlarr.Console.exe"; } - else if (PlatformInfo.IsMono) - { - consoleExe = "Prowlarr.exe"; - } else { consoleExe = "Prowlarr"; From 76b6b0deadde599bf9eb313dd288309a765a03ad Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 3 Jan 2022 00:28:20 -0600 Subject: [PATCH 0304/2320] Use native HttpMethod --- src/NzbDrone.Common/Http/HttpClient.cs | 9 +++-- src/NzbDrone.Common/Http/HttpMethod.cs | 14 ------- src/NzbDrone.Common/Http/HttpRequest.cs | 1 + .../Http/HttpRequestBuilder.cs | 9 +++-- .../Http/JsonRpcRequestBuilder.cs | 7 ++-- .../AvistazTests/AvistazFixture.cs | 3 +- .../AvistazTests/PrivateHDFixture.cs | 3 +- .../FileListTests/FileListFixture.cs | 3 +- .../IndexerTests/HDBitsTests/HDBitsFixture.cs | 3 +- .../NewznabTests/NewznabFixture.cs | 3 +- .../IndexerTests/PTPTests/PTPFixture.cs | 5 ++- .../IndexerTests/RarbgTests/RarbgFixture.cs | 7 ++-- .../TorznabTests/TorznabFixture.cs | 7 ++-- .../LazyLibrarian/LazyLibrarianV1Proxy.cs | 11 +++--- .../Applications/Lidarr/LidarrV1Proxy.cs | 17 +++++---- .../Applications/Mylar/MylarV3Proxy.cs | 11 +++--- .../Applications/Radarr/RadarrV3Proxy.cs | 17 +++++---- .../Applications/Readarr/ReadarrV1Proxy.cs | 17 +++++---- .../Applications/Sonarr/SonarrV3Proxy.cs | 17 +++++---- .../Proxies/DiskStationProxyBase.cs | 13 +++++-- .../Proxies/DownloadStationTaskProxy.cs | 5 ++- .../Download/Clients/Flood/FloodProxy.cs | 9 +++-- .../FlareSolverr/FlareSolverr.cs | 7 ++-- .../Indexers/Definitions/Anidub.cs | 4 +- .../Indexers/Definitions/AnimeTorrents.cs | 3 +- .../Indexers/Definitions/Anthelion.cs | 3 +- .../Definitions/Avistaz/AvistazBase.cs | 3 +- src/NzbDrone.Core/Indexers/Definitions/BB.cs | 3 +- .../Indexers/Definitions/BakaBT.cs | 3 +- .../Indexers/Definitions/BeyondHD.cs | 3 +- .../Cardigann/CardigannRequestGenerator.cs | 37 ++++++++++--------- .../Indexers/Definitions/Gazelle/Gazelle.cs | 3 +- .../HDBits/HDBitsRequestGenerator.cs | 3 +- .../Indexers/Definitions/HDSpace.cs | 3 +- .../Indexers/Definitions/HDTorrents.cs | 3 +- .../Indexers/Definitions/ImmortalSeed.cs | 3 +- .../Indexers/Definitions/Nebulance.cs | 3 +- .../Newznab/NewznabCapabilitiesProvider.cs | 3 +- .../Indexers/Definitions/NorBits.cs | 3 +- .../Indexers/Definitions/PornoLab.cs | 3 +- .../Indexers/Definitions/PreToMe.cs | 3 +- .../Indexers/Definitions/RevolutionTT.cs | 3 +- .../Indexers/Definitions/RuTracker.cs | 3 +- .../Indexers/Definitions/SpeedApp.cs | 3 +- .../Indexers/Definitions/SpeedCD.cs | 5 ++- .../Indexers/Definitions/TVVault.cs | 3 +- .../Indexers/Definitions/TorrentLeech.cs | 3 +- .../Indexers/Definitions/TorrentSeeds.cs | 3 +- .../Indexers/Definitions/ZonaQ.cs | 5 ++- .../Notifications/Discord/DiscordProxy.cs | 3 +- .../Notifications/Join/JoinProxy.cs | 3 +- .../PushBullet/PushBulletProxy.cs | 3 +- .../Notifications/SendGrid/SendGridProxy.cs | 3 +- .../Notifications/Slack/SlackProxy.cs | 3 +- .../Notifications/Webhook/WebhookMethod.cs | 5 ++- .../Notifications/Webhook/WebhookProxy.cs | 10 ++++- 56 files changed, 198 insertions(+), 147 deletions(-) delete mode 100644 src/NzbDrone.Common/Http/HttpMethod.cs diff --git a/src/NzbDrone.Common/Http/HttpClient.cs b/src/NzbDrone.Common/Http/HttpClient.cs index 47286b3b0..9c1e2221c 100644 --- a/src/NzbDrone.Common/Http/HttpClient.cs +++ b/src/NzbDrone.Common/Http/HttpClient.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading.Tasks; using NLog; using NzbDrone.Common.Cache; @@ -87,7 +88,7 @@ namespace NzbDrone.Common.Http // 302 or 303 should default to GET on redirect even if POST on original if (response.StatusCode == HttpStatusCode.Redirect || response.StatusCode == HttpStatusCode.RedirectMethod) { - request.Method = HttpMethod.GET; + request.Method = HttpMethod.Get; request.ContentData = null; } @@ -263,7 +264,7 @@ namespace NzbDrone.Common.Http public Task<HttpResponse> GetAsync(HttpRequest request) { - request.Method = HttpMethod.GET; + request.Method = HttpMethod.Get; return ExecuteAsync(request); } @@ -288,7 +289,7 @@ namespace NzbDrone.Common.Http public Task<HttpResponse> HeadAsync(HttpRequest request) { - request.Method = HttpMethod.HEAD; + request.Method = HttpMethod.Head; return ExecuteAsync(request); } @@ -299,7 +300,7 @@ namespace NzbDrone.Common.Http public Task<HttpResponse> PostAsync(HttpRequest request) { - request.Method = HttpMethod.POST; + request.Method = HttpMethod.Post; return ExecuteAsync(request); } diff --git a/src/NzbDrone.Common/Http/HttpMethod.cs b/src/NzbDrone.Common/Http/HttpMethod.cs deleted file mode 100644 index 8964bbef6..000000000 --- a/src/NzbDrone.Common/Http/HttpMethod.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace NzbDrone.Common.Http -{ - public enum HttpMethod - { - GET, - POST, - PUT, - DELETE, - HEAD, - OPTIONS, - PATCH, - MERGE - } -} diff --git a/src/NzbDrone.Common/Http/HttpRequest.cs b/src/NzbDrone.Common/Http/HttpRequest.cs index 9f2aab320..769712386 100644 --- a/src/NzbDrone.Common/Http/HttpRequest.cs +++ b/src/NzbDrone.Common/Http/HttpRequest.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Net; +using System.Net.Http; using System.Text; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; diff --git a/src/NzbDrone.Common/Http/HttpRequestBuilder.cs b/src/NzbDrone.Common/Http/HttpRequestBuilder.cs index 644d73908..86b40b319 100644 --- a/src/NzbDrone.Common/Http/HttpRequestBuilder.cs +++ b/src/NzbDrone.Common/Http/HttpRequestBuilder.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; +using System.Net.Http; using System.Text; using NzbDrone.Common.Extensions; @@ -37,7 +38,7 @@ namespace NzbDrone.Common.Http { BaseUrl = new HttpUri(baseUrl); ResourceUrl = string.Empty; - Method = HttpMethod.GET; + Method = HttpMethod.Get; Encoding = Encoding.UTF8; QueryParams = new List<KeyValuePair<string, string>>(); SuffixQueryParams = new List<KeyValuePair<string, string>>(); @@ -275,7 +276,7 @@ namespace NzbDrone.Common.Http public virtual HttpRequestBuilder Post() { - Method = HttpMethod.POST; + Method = HttpMethod.Post; return this; } @@ -397,7 +398,7 @@ namespace NzbDrone.Common.Http public virtual HttpRequestBuilder AddFormParameter(string key, object value) { - if (Method != HttpMethod.POST) + if (Method != HttpMethod.Post) { throw new NotSupportedException("HttpRequest Method must be POST to add FormParameter."); } @@ -413,7 +414,7 @@ namespace NzbDrone.Common.Http public virtual HttpRequestBuilder AddFormUpload(string name, string fileName, byte[] data, string contentType = "application/octet-stream") { - if (Method != HttpMethod.POST) + if (Method != HttpMethod.Post) { throw new NotSupportedException("HttpRequest Method must be POST to add FormUpload."); } diff --git a/src/NzbDrone.Common/Http/JsonRpcRequestBuilder.cs b/src/NzbDrone.Common/Http/JsonRpcRequestBuilder.cs index ae987a23d..06b113e54 100644 --- a/src/NzbDrone.Common/Http/JsonRpcRequestBuilder.cs +++ b/src/NzbDrone.Common/Http/JsonRpcRequestBuilder.cs @@ -1,6 +1,7 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using Newtonsoft.Json; using NzbDrone.Common.Serializer; @@ -17,14 +18,14 @@ namespace NzbDrone.Common.Http public JsonRpcRequestBuilder(string baseUrl) : base(baseUrl) { - Method = HttpMethod.POST; + Method = HttpMethod.Post; JsonParameters = new List<object>(); } public JsonRpcRequestBuilder(string baseUrl, string method, IEnumerable<object> parameters) : base(baseUrl) { - Method = HttpMethod.POST; + Method = HttpMethod.Post; JsonMethod = method; JsonParameters = parameters.ToList(); } diff --git a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/AvistazFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/AvistazFixture.cs index 50443ac8f..230512265 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/AvistazFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/AvistazFixture.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading.Tasks; using FluentAssertions; using Moq; @@ -34,7 +35,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AvistazTests var recentFeed = ReadAllText(@"Files/Indexers/Avistaz/recentfeed.json"); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader { { "Content-Type", "application/json" } }, new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/PrivateHDFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/PrivateHDFixture.cs index 377fdd968..e259a928c 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/PrivateHDFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/PrivateHDFixture.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading.Tasks; using FluentAssertions; using Moq; @@ -34,7 +35,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AvistazTests var recentFeed = ReadAllText(@"Files/Indexers/PrivateHD/recentfeed.json"); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader { { "Content-Type", "application/json" } }, new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/FileListTests/FileListFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/FileListTests/FileListFixture.cs index 12f12c095..55a9c47b6 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/FileListTests/FileListFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/FileListTests/FileListFixture.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading.Tasks; using FluentAssertions; using Moq; @@ -33,7 +34,7 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests var recentFeed = ReadAllText(@"Files/Indexers/FileList/recentfeed.json"); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/HDBitsTests/HDBitsFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/HDBitsTests/HDBitsFixture.cs index 91e3efcf0..2592d6874 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/HDBitsTests/HDBitsFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/HDBitsTests/HDBitsFixture.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Net; +using System.Net.Http; using System.Text; using System.Threading.Tasks; using FluentAssertions; @@ -45,7 +46,7 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests var responseJson = ReadAllText(fileName); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Post), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), responseJson))); var torrents = (await Subject.Fetch(_movieSearchCriteria)).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabFixture.cs index 75ba1038c..231c4bb56 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabFixture.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading.Tasks; using FluentAssertions; using Moq; @@ -43,7 +44,7 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests var recentFeed = ReadAllText(@"Files/Indexers/Newznab/newznab_nzb_su.xml"); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 }, Limit = 100, Offset = 0 })).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs index b9827e838..2f606c420 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Net; +using System.Net.Http; using System.Threading.Tasks; using FluentAssertions; using Moq; @@ -37,11 +38,11 @@ namespace NzbDrone.Core.Test.IndexerTests.PTPTests var responseJson = ReadAllText(fileName); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Post), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), authStream.ToString()))); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader { ContentType = HttpAccept.Json.Value }, new CookieCollection(), responseJson))); var torrents = (await Subject.Fetch(new MovieSearchCriteria())).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs index c9649ee52..e8da2e1b3 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading.Tasks; using FluentAssertions; using Moq; @@ -39,7 +40,7 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests var recentFeed = ReadAllText(@"Files/Indexers/Rarbg/RecentFeed_v2.json"); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; @@ -66,7 +67,7 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests public async Task should_parse_error_20_as_empty_results() { Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), "{ error_code: 20, error: \"some message\" }"))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; @@ -78,7 +79,7 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests public async Task should_warn_on_unknown_error() { Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), "{ error_code: 25, error: \"some message\" }"))); var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; diff --git a/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs index 588a41349..2c96236fc 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading.Tasks; using FluentAssertions; using Moq; @@ -44,7 +45,7 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_hdaccess_net.xml"); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria())).Releases; @@ -73,7 +74,7 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_tpb.xml"); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria())).Releases; @@ -103,7 +104,7 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_animetosho.xml"); Mocker.GetMock<IIndexerHttpClient>() - .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET), Subject.Definition)) + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition)) .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); var releases = (await Subject.Fetch(new MovieSearchCriteria())).Releases; diff --git a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs index abb1c0338..dbf435f65 100644 --- a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs +++ b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarianV1Proxy.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using FluentValidation.Results; using Newtonsoft.Json; using NLog; @@ -31,13 +32,13 @@ namespace NzbDrone.Core.Applications.LazyLibrarian public LazyLibrarianStatus GetStatus(LazyLibrarianSettings settings) { - var request = BuildRequest(settings, "/api", "getVersion", HttpMethod.GET); + var request = BuildRequest(settings, "/api", "getVersion", HttpMethod.Get); return Execute<LazyLibrarianStatus>(request); } public List<LazyLibrarianIndexer> GetIndexers(LazyLibrarianSettings settings) { - var request = BuildRequest(settings, "/api", "listNabProviders", HttpMethod.GET); + var request = BuildRequest(settings, "/api", "listNabProviders", HttpMethod.Get); var response = Execute<LazyLibrarianIndexerResponse>(request); @@ -76,7 +77,7 @@ namespace NzbDrone.Core.Applications.LazyLibrarian { "providertype", indexerType.ToString().ToLower() } }; - var request = BuildRequest(settings, "/api", "delProvider", HttpMethod.GET, parameters); + var request = BuildRequest(settings, "/api", "delProvider", HttpMethod.Get, parameters); CheckForError(Execute<LazyLibrarianStatus>(request)); } @@ -92,7 +93,7 @@ namespace NzbDrone.Core.Applications.LazyLibrarian { "categories", indexer.Categories } }; - var request = BuildRequest(settings, "/api", "addProvider", HttpMethod.GET, parameters); + var request = BuildRequest(settings, "/api", "addProvider", HttpMethod.Get, parameters); CheckForError(Execute<LazyLibrarianStatus>(request)); return indexer; } @@ -110,7 +111,7 @@ namespace NzbDrone.Core.Applications.LazyLibrarian { "altername", indexer.Altername } }; - var request = BuildRequest(settings, "/api", "changeProvider", HttpMethod.GET, parameters); + var request = BuildRequest(settings, "/api", "changeProvider", HttpMethod.Get, parameters); CheckForError(Execute<LazyLibrarianStatus>(request)); return indexer; } diff --git a/src/NzbDrone.Core/Applications/Lidarr/LidarrV1Proxy.cs b/src/NzbDrone.Core/Applications/Lidarr/LidarrV1Proxy.cs index 6eff2a1a6..449ce6236 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/LidarrV1Proxy.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/LidarrV1Proxy.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Net; +using System.Net.Http; using FluentValidation.Results; using Newtonsoft.Json; using NLog; @@ -33,13 +34,13 @@ namespace NzbDrone.Core.Applications.Lidarr public LidarrStatus GetStatus(LidarrSettings settings) { - var request = BuildRequest(settings, "/api/v1/system/status", HttpMethod.GET); + var request = BuildRequest(settings, "/api/v1/system/status", HttpMethod.Get); return Execute<LidarrStatus>(request); } public List<LidarrIndexer> GetIndexers(LidarrSettings settings) { - var request = BuildRequest(settings, "/api/v1/indexer", HttpMethod.GET); + var request = BuildRequest(settings, "/api/v1/indexer", HttpMethod.Get); return Execute<List<LidarrIndexer>>(request); } @@ -47,7 +48,7 @@ namespace NzbDrone.Core.Applications.Lidarr { try { - var request = BuildRequest(settings, $"/api/v1/indexer/{indexerId}", HttpMethod.GET); + var request = BuildRequest(settings, $"/api/v1/indexer/{indexerId}", HttpMethod.Get); return Execute<LidarrIndexer>(request); } catch (HttpException ex) @@ -63,19 +64,19 @@ namespace NzbDrone.Core.Applications.Lidarr public void RemoveIndexer(int indexerId, LidarrSettings settings) { - var request = BuildRequest(settings, $"/api/v1/indexer/{indexerId}", HttpMethod.DELETE); + var request = BuildRequest(settings, $"/api/v1/indexer/{indexerId}", HttpMethod.Delete); _httpClient.Execute(request); } public List<LidarrIndexer> GetIndexerSchema(LidarrSettings settings) { - var request = BuildRequest(settings, "/api/v1/indexer/schema", HttpMethod.GET); + var request = BuildRequest(settings, "/api/v1/indexer/schema", HttpMethod.Get); return Execute<List<LidarrIndexer>>(request); } public LidarrIndexer AddIndexer(LidarrIndexer indexer, LidarrSettings settings) { - var request = BuildRequest(settings, "/api/v1/indexer", HttpMethod.POST); + var request = BuildRequest(settings, "/api/v1/indexer", HttpMethod.Post); request.SetContent(indexer.ToJson()); @@ -84,7 +85,7 @@ namespace NzbDrone.Core.Applications.Lidarr public LidarrIndexer UpdateIndexer(LidarrIndexer indexer, LidarrSettings settings) { - var request = BuildRequest(settings, $"/api/v1/indexer/{indexer.Id}", HttpMethod.PUT); + var request = BuildRequest(settings, $"/api/v1/indexer/{indexer.Id}", HttpMethod.Put); request.SetContent(indexer.ToJson()); @@ -93,7 +94,7 @@ namespace NzbDrone.Core.Applications.Lidarr public ValidationFailure TestConnection(LidarrIndexer indexer, LidarrSettings settings) { - var request = BuildRequest(settings, $"/api/v1/indexer/test", HttpMethod.POST); + var request = BuildRequest(settings, $"/api/v1/indexer/test", HttpMethod.Post); request.SetContent(indexer.ToJson()); diff --git a/src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs b/src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs index c571d189b..4c72160e9 100644 --- a/src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs +++ b/src/NzbDrone.Core/Applications/Mylar/MylarV3Proxy.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using FluentValidation.Results; using Newtonsoft.Json; using NLog; @@ -31,13 +32,13 @@ namespace NzbDrone.Core.Applications.Mylar public MylarStatus GetStatus(MylarSettings settings) { - var request = BuildRequest(settings, "/api", "getVersion", HttpMethod.GET); + var request = BuildRequest(settings, "/api", "getVersion", HttpMethod.Get); return Execute<MylarStatus>(request); } public List<MylarIndexer> GetIndexers(MylarSettings settings) { - var request = BuildRequest(settings, "/api", "listProviders", HttpMethod.GET); + var request = BuildRequest(settings, "/api", "listProviders", HttpMethod.Get); var response = Execute<MylarIndexerResponse>(request); @@ -76,7 +77,7 @@ namespace NzbDrone.Core.Applications.Mylar { "providertype", indexerType.ToString().ToLower() } }; - var request = BuildRequest(settings, "/api", "delProvider", HttpMethod.GET, parameters); + var request = BuildRequest(settings, "/api", "delProvider", HttpMethod.Get, parameters); CheckForError(Execute<MylarStatus>(request)); } @@ -92,7 +93,7 @@ namespace NzbDrone.Core.Applications.Mylar { "categories", indexer.Categories } }; - var request = BuildRequest(settings, "/api", "addProvider", HttpMethod.GET, parameters); + var request = BuildRequest(settings, "/api", "addProvider", HttpMethod.Get, parameters); CheckForError(Execute<MylarStatus>(request)); return indexer; } @@ -110,7 +111,7 @@ namespace NzbDrone.Core.Applications.Mylar { "altername", indexer.Altername } }; - var request = BuildRequest(settings, "/api", "changeProvider", HttpMethod.GET, parameters); + var request = BuildRequest(settings, "/api", "changeProvider", HttpMethod.Get, parameters); CheckForError(Execute<MylarStatus>(request)); return indexer; } diff --git a/src/NzbDrone.Core/Applications/Radarr/RadarrV3Proxy.cs b/src/NzbDrone.Core/Applications/Radarr/RadarrV3Proxy.cs index 2277f9d0e..fc1fd76c4 100644 --- a/src/NzbDrone.Core/Applications/Radarr/RadarrV3Proxy.cs +++ b/src/NzbDrone.Core/Applications/Radarr/RadarrV3Proxy.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Net; +using System.Net.Http; using FluentValidation.Results; using Newtonsoft.Json; using NLog; @@ -33,13 +34,13 @@ namespace NzbDrone.Core.Applications.Radarr public RadarrStatus GetStatus(RadarrSettings settings) { - var request = BuildRequest(settings, "/api/v3/system/status", HttpMethod.GET); + var request = BuildRequest(settings, "/api/v3/system/status", HttpMethod.Get); return Execute<RadarrStatus>(request); } public List<RadarrIndexer> GetIndexers(RadarrSettings settings) { - var request = BuildRequest(settings, "/api/v3/indexer", HttpMethod.GET); + var request = BuildRequest(settings, "/api/v3/indexer", HttpMethod.Get); return Execute<List<RadarrIndexer>>(request); } @@ -47,7 +48,7 @@ namespace NzbDrone.Core.Applications.Radarr { try { - var request = BuildRequest(settings, $"/api/v3/indexer/{indexerId}", HttpMethod.GET); + var request = BuildRequest(settings, $"/api/v3/indexer/{indexerId}", HttpMethod.Get); return Execute<RadarrIndexer>(request); } catch (HttpException ex) @@ -63,19 +64,19 @@ namespace NzbDrone.Core.Applications.Radarr public void RemoveIndexer(int indexerId, RadarrSettings settings) { - var request = BuildRequest(settings, $"/api/v3/indexer/{indexerId}", HttpMethod.DELETE); + var request = BuildRequest(settings, $"/api/v3/indexer/{indexerId}", HttpMethod.Delete); _httpClient.Execute(request); } public List<RadarrIndexer> GetIndexerSchema(RadarrSettings settings) { - var request = BuildRequest(settings, "/api/v3/indexer/schema", HttpMethod.GET); + var request = BuildRequest(settings, "/api/v3/indexer/schema", HttpMethod.Get); return Execute<List<RadarrIndexer>>(request); } public RadarrIndexer AddIndexer(RadarrIndexer indexer, RadarrSettings settings) { - var request = BuildRequest(settings, "/api/v3/indexer", HttpMethod.POST); + var request = BuildRequest(settings, "/api/v3/indexer", HttpMethod.Post); request.SetContent(indexer.ToJson()); @@ -84,7 +85,7 @@ namespace NzbDrone.Core.Applications.Radarr public RadarrIndexer UpdateIndexer(RadarrIndexer indexer, RadarrSettings settings) { - var request = BuildRequest(settings, $"/api/v3/indexer/{indexer.Id}", HttpMethod.PUT); + var request = BuildRequest(settings, $"/api/v3/indexer/{indexer.Id}", HttpMethod.Put); request.SetContent(indexer.ToJson()); @@ -93,7 +94,7 @@ namespace NzbDrone.Core.Applications.Radarr public ValidationFailure TestConnection(RadarrIndexer indexer, RadarrSettings settings) { - var request = BuildRequest(settings, $"/api/v3/indexer/test", HttpMethod.POST); + var request = BuildRequest(settings, $"/api/v3/indexer/test", HttpMethod.Post); request.SetContent(indexer.ToJson()); diff --git a/src/NzbDrone.Core/Applications/Readarr/ReadarrV1Proxy.cs b/src/NzbDrone.Core/Applications/Readarr/ReadarrV1Proxy.cs index 64319e21d..11c764d4a 100644 --- a/src/NzbDrone.Core/Applications/Readarr/ReadarrV1Proxy.cs +++ b/src/NzbDrone.Core/Applications/Readarr/ReadarrV1Proxy.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Net; +using System.Net.Http; using FluentValidation.Results; using Newtonsoft.Json; using NLog; @@ -33,13 +34,13 @@ namespace NzbDrone.Core.Applications.Readarr public ReadarrStatus GetStatus(ReadarrSettings settings) { - var request = BuildRequest(settings, "/api/v1/system/status", HttpMethod.GET); + var request = BuildRequest(settings, "/api/v1/system/status", HttpMethod.Get); return Execute<ReadarrStatus>(request); } public List<ReadarrIndexer> GetIndexers(ReadarrSettings settings) { - var request = BuildRequest(settings, "/api/v1/indexer", HttpMethod.GET); + var request = BuildRequest(settings, "/api/v1/indexer", HttpMethod.Get); return Execute<List<ReadarrIndexer>>(request); } @@ -47,7 +48,7 @@ namespace NzbDrone.Core.Applications.Readarr { try { - var request = BuildRequest(settings, $"/api/v1/indexer/{indexerId}", HttpMethod.GET); + var request = BuildRequest(settings, $"/api/v1/indexer/{indexerId}", HttpMethod.Get); return Execute<ReadarrIndexer>(request); } catch (HttpException ex) @@ -63,19 +64,19 @@ namespace NzbDrone.Core.Applications.Readarr public void RemoveIndexer(int indexerId, ReadarrSettings settings) { - var request = BuildRequest(settings, $"/api/v1/indexer/{indexerId}", HttpMethod.DELETE); + var request = BuildRequest(settings, $"/api/v1/indexer/{indexerId}", HttpMethod.Delete); _httpClient.Execute(request); } public List<ReadarrIndexer> GetIndexerSchema(ReadarrSettings settings) { - var request = BuildRequest(settings, "/api/v1/indexer/schema", HttpMethod.GET); + var request = BuildRequest(settings, "/api/v1/indexer/schema", HttpMethod.Get); return Execute<List<ReadarrIndexer>>(request); } public ReadarrIndexer AddIndexer(ReadarrIndexer indexer, ReadarrSettings settings) { - var request = BuildRequest(settings, "/api/v1/indexer", HttpMethod.POST); + var request = BuildRequest(settings, "/api/v1/indexer", HttpMethod.Post); request.SetContent(indexer.ToJson()); @@ -84,7 +85,7 @@ namespace NzbDrone.Core.Applications.Readarr public ReadarrIndexer UpdateIndexer(ReadarrIndexer indexer, ReadarrSettings settings) { - var request = BuildRequest(settings, $"/api/v1/indexer/{indexer.Id}", HttpMethod.PUT); + var request = BuildRequest(settings, $"/api/v1/indexer/{indexer.Id}", HttpMethod.Put); request.SetContent(indexer.ToJson()); @@ -93,7 +94,7 @@ namespace NzbDrone.Core.Applications.Readarr public ValidationFailure TestConnection(ReadarrIndexer indexer, ReadarrSettings settings) { - var request = BuildRequest(settings, $"/api/v1/indexer/test", HttpMethod.POST); + var request = BuildRequest(settings, $"/api/v1/indexer/test", HttpMethod.Post); request.SetContent(indexer.ToJson()); diff --git a/src/NzbDrone.Core/Applications/Sonarr/SonarrV3Proxy.cs b/src/NzbDrone.Core/Applications/Sonarr/SonarrV3Proxy.cs index a42ec5a2c..47c06f71a 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/SonarrV3Proxy.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/SonarrV3Proxy.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Net; +using System.Net.Http; using FluentValidation.Results; using Newtonsoft.Json; using NLog; @@ -33,13 +34,13 @@ namespace NzbDrone.Core.Applications.Sonarr public SonarrStatus GetStatus(SonarrSettings settings) { - var request = BuildRequest(settings, "/api/v3/system/status", HttpMethod.GET); + var request = BuildRequest(settings, "/api/v3/system/status", HttpMethod.Get); return Execute<SonarrStatus>(request); } public List<SonarrIndexer> GetIndexers(SonarrSettings settings) { - var request = BuildRequest(settings, "/api/v3/indexer", HttpMethod.GET); + var request = BuildRequest(settings, "/api/v3/indexer", HttpMethod.Get); return Execute<List<SonarrIndexer>>(request); } @@ -47,7 +48,7 @@ namespace NzbDrone.Core.Applications.Sonarr { try { - var request = BuildRequest(settings, $"/api/v3/indexer/{indexerId}", HttpMethod.GET); + var request = BuildRequest(settings, $"/api/v3/indexer/{indexerId}", HttpMethod.Get); return Execute<SonarrIndexer>(request); } catch (HttpException ex) @@ -63,19 +64,19 @@ namespace NzbDrone.Core.Applications.Sonarr public void RemoveIndexer(int indexerId, SonarrSettings settings) { - var request = BuildRequest(settings, $"/api/v3/indexer/{indexerId}", HttpMethod.DELETE); + var request = BuildRequest(settings, $"/api/v3/indexer/{indexerId}", HttpMethod.Delete); _httpClient.Execute(request); } public List<SonarrIndexer> GetIndexerSchema(SonarrSettings settings) { - var request = BuildRequest(settings, "/api/v3/indexer/schema", HttpMethod.GET); + var request = BuildRequest(settings, "/api/v3/indexer/schema", HttpMethod.Get); return Execute<List<SonarrIndexer>>(request); } public SonarrIndexer AddIndexer(SonarrIndexer indexer, SonarrSettings settings) { - var request = BuildRequest(settings, "/api/v3/indexer", HttpMethod.POST); + var request = BuildRequest(settings, "/api/v3/indexer", HttpMethod.Post); request.SetContent(indexer.ToJson()); @@ -84,7 +85,7 @@ namespace NzbDrone.Core.Applications.Sonarr public SonarrIndexer UpdateIndexer(SonarrIndexer indexer, SonarrSettings settings) { - var request = BuildRequest(settings, $"/api/v3/indexer/{indexer.Id}", HttpMethod.PUT); + var request = BuildRequest(settings, $"/api/v3/indexer/{indexer.Id}", HttpMethod.Put); request.SetContent(indexer.ToJson()); @@ -93,7 +94,7 @@ namespace NzbDrone.Core.Applications.Sonarr public ValidationFailure TestConnection(SonarrIndexer indexer, SonarrSettings settings) { - var request = BuildRequest(settings, $"/api/v3/indexer/test", HttpMethod.POST); + var request = BuildRequest(settings, $"/api/v3/indexer/test", HttpMethod.Post); request.SetContent(indexer.ToJson()); diff --git a/src/NzbDrone.Core/Download/Clients/DownloadStation/Proxies/DiskStationProxyBase.cs b/src/NzbDrone.Core/Download/Clients/DownloadStation/Proxies/DiskStationProxyBase.cs index fc0837f55..213b3e505 100644 --- a/src/NzbDrone.Core/Download/Clients/DownloadStation/Proxies/DiskStationProxyBase.cs +++ b/src/NzbDrone.Core/Download/Clients/DownloadStation/Proxies/DiskStationProxyBase.cs @@ -1,6 +1,7 @@ -using System; +using System; using System.Collections.Generic; using System.Net; +using System.Net.Http; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Http; @@ -142,15 +143,19 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies return authResponse.Data.SId; } - protected HttpRequestBuilder BuildRequest(DownloadStationSettings settings, string methodName, int apiVersion, HttpMethod httpVerb = HttpMethod.GET) + protected HttpRequestBuilder BuildRequest(DownloadStationSettings settings, string methodName, int apiVersion, HttpMethod httpVerb = null) { + httpVerb ??= HttpMethod.Get; + var info = GetApiInfo(_apiType, settings); return BuildRequest(settings, info, methodName, apiVersion, httpVerb); } - private HttpRequestBuilder BuildRequest(DownloadStationSettings settings, DiskStationApiInfo apiInfo, string methodName, int apiVersion, HttpMethod httpVerb = HttpMethod.GET) + private HttpRequestBuilder BuildRequest(DownloadStationSettings settings, DiskStationApiInfo apiInfo, string methodName, int apiVersion, HttpMethod httpVerb = null) { + httpVerb ??= HttpMethod.Get; + var requestBuilder = new HttpRequestBuilder(settings.UseSsl, settings.Host, settings.Port).Resource($"webapi/{apiInfo.Path}"); requestBuilder.Method = httpVerb; requestBuilder.LogResponseContent = true; @@ -163,7 +168,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies throw new ArgumentOutOfRangeException(nameof(apiVersion)); } - if (httpVerb == HttpMethod.POST) + if (httpVerb == HttpMethod.Post) { if (apiInfo.NeedsAuthentication) { diff --git a/src/NzbDrone.Core/Download/Clients/DownloadStation/Proxies/DownloadStationTaskProxy.cs b/src/NzbDrone.Core/Download/Clients/DownloadStation/Proxies/DownloadStationTaskProxy.cs index 1e6849dac..4b5637a5c 100644 --- a/src/NzbDrone.Core/Download/Clients/DownloadStation/Proxies/DownloadStationTaskProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/DownloadStation/Proxies/DownloadStationTaskProxy.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System.Collections.Generic; +using System.Net.Http; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; @@ -24,7 +25,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation.Proxies public void AddTaskFromData(byte[] data, string filename, string downloadDirectory, DownloadStationSettings settings) { - var requestBuilder = BuildRequest(settings, "create", 2, HttpMethod.POST); + var requestBuilder = BuildRequest(settings, "create", 2, HttpMethod.Post); if (downloadDirectory.IsNotNullOrWhiteSpace()) { diff --git a/src/NzbDrone.Core/Download/Clients/Flood/FloodProxy.cs b/src/NzbDrone.Core/Download/Clients/Flood/FloodProxy.cs index ddebdbfff..06bca878f 100644 --- a/src/NzbDrone.Core/Download/Clients/Flood/FloodProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/Flood/FloodProxy.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; +using System.Net.Http; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Http; @@ -107,7 +108,7 @@ namespace NzbDrone.Core.Download.Clients.Flood { var verifyRequest = BuildRequest(settings).Resource("/auth/verify").Build(); - verifyRequest.Method = HttpMethod.GET; + verifyRequest.Method = HttpMethod.Get; HandleRequest(verifyRequest, settings); } @@ -180,7 +181,7 @@ namespace NzbDrone.Core.Download.Clients.Flood { var getTorrentsRequest = BuildRequest(settings).Resource("/torrents").Build(); - getTorrentsRequest.Method = HttpMethod.GET; + getTorrentsRequest.Method = HttpMethod.Get; return Json.Deserialize<TorrentListSummary>(HandleRequest(getTorrentsRequest, settings).Content).Torrents; } @@ -189,7 +190,7 @@ namespace NzbDrone.Core.Download.Clients.Flood { var contentsRequest = BuildRequest(settings).Resource($"/torrents/{hash}/contents").Build(); - contentsRequest.Method = HttpMethod.GET; + contentsRequest.Method = HttpMethod.Get; return Json.Deserialize<List<TorrentContent>>(HandleRequest(contentsRequest, settings).Content).ConvertAll(content => content.Path); } @@ -198,7 +199,7 @@ namespace NzbDrone.Core.Download.Clients.Flood { var tagsRequest = BuildRequest(settings).Resource("/torrents/tags").Build(); - tagsRequest.Method = HttpMethod.PATCH; + tagsRequest.Method = HttpMethod.Patch; var body = new Dictionary<string, object> { diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index 47c4c0634..23e682715 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Net; +using System.Net.Http; using FluentValidation.Results; using Newtonsoft.Json; using NLog; @@ -115,7 +116,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr var userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"; var maxTimeout = Settings.RequestTimeout * 1000; - if (request.Method == HttpMethod.GET) + if (request.Method == HttpMethod.Get) { req = new FlareSolverrRequestGet { @@ -125,7 +126,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr UserAgent = userAgent }; } - else if (request.Method == HttpMethod.POST) + else if (request.Method == HttpMethod.Post) { var contentTypeType = request.Headers.ContentType; @@ -167,7 +168,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr var newRequest = new HttpRequest(apiUrl, HttpAccept.Json); newRequest.Headers.ContentType = "application/json"; - newRequest.Method = HttpMethod.POST; + newRequest.Method = HttpMethod.Post; newRequest.SetContent(req.ToJson()); _logger.Debug("Applying FlareSolverr Proxy {0} to request {1}", Name, request.Url); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs b/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs index 6e1fe3ead..ab7aff29c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs @@ -60,7 +60,7 @@ namespace NzbDrone.Core.Indexers.Definitions var mainPage = await ExecuteAuth(new HttpRequest(Settings.BaseUrl)); - requestBuilder.Method = Common.Http.HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); requestBuilder.SetCookies(mainPage.GetCookies()); @@ -167,7 +167,7 @@ namespace NzbDrone.Core.Indexers.Definitions if (isSearch) { - request.HttpRequest.Method = NzbDrone.Common.Http.HttpMethod.POST; + request.HttpRequest.Method = HttpMethod.Post; var postData = new NameValueCollection { { "do", "search" }, diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs index 0e0b59de6..87c92d73a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Globalization; using System.Linq; +using System.Net.Http; using System.Text.RegularExpressions; using System.Threading.Tasks; using AngleSharp.Html.Parser; @@ -57,7 +58,7 @@ namespace NzbDrone.Core.Indexers.Definitions }; var loginPage = await ExecuteAuth(new HttpRequest(LoginUrl)); - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); requestBuilder.SetCookies(loginPage.GetCookies()); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs b/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs index b52b49a14..e4d2597fe 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; +using System.Net.Http; using System.Text; using System.Threading.Tasks; using AngleSharp.Html.Parser; @@ -56,7 +57,7 @@ namespace NzbDrone.Core.Indexers.Definitions AllowAutoRedirect = true }; - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); var cookies = Cookies; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazBase.cs index f231fae7c..3663f1250 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazBase.cs @@ -1,5 +1,6 @@ using System; using System.Net; +using System.Net.Http; using System.Threading.Tasks; using FluentValidation.Results; using NLog; @@ -105,7 +106,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz LogResponseContent = true }; - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); var authLoginRequest = requestBuilder diff --git a/src/NzbDrone.Core/Indexers/Definitions/BB.cs b/src/NzbDrone.Core/Indexers/Definitions/BB.cs index 4c44c5b6c..e849cfade 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BB.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BB.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.Net.Http; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -55,7 +56,7 @@ namespace NzbDrone.Core.Indexers.Definitions AllowAutoRedirect = true }; - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); var cookies = Cookies; diff --git a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs index eb964df8c..8595a16d1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; +using System.Net.Http; using System.Text.RegularExpressions; using System.Threading.Tasks; using AngleSharp.Dom; @@ -79,7 +80,7 @@ namespace NzbDrone.Core.Indexers.Definitions var loginPage = await ExecuteAuth(new HttpRequest(LoginUrl)); - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); requestBuilder.SetCookies(loginPage.GetCookies()); diff --git a/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs b/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs index acda788be..e3c0fc054 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; +using System.Net.Http; using FluentValidation; using Newtonsoft.Json; using NLog; @@ -110,7 +111,7 @@ namespace NzbDrone.Core.Indexers.Definitions var request = new HttpRequest(searchUrl, HttpAccept.Json); request.Headers.Add("Content-type", "application/json"); - request.Method = HttpMethod.POST; + request.Method = HttpMethod.Post; request.SetContent(body.ToJson()); var indexerRequest = new IndexerRequest(request); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 1bd0a6c76..2622142cd 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Net; +using System.Net.Http; using System.Text; using System.Threading.Tasks; using AngleSharp.Html.Dom; @@ -184,7 +185,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var requestBuilder = new HttpRequestBuilder(loginUrl) { LogResponseContent = true, - Method = HttpMethod.POST, + Method = HttpMethod.Post, AllowAutoRedirect = true, SuppressHttpError = true, Encoding = _encoding @@ -329,7 +330,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var requestBuilder = new HttpRequestBuilder(captchaUrl.ToString()) { LogResponseContent = true, - Method = HttpMethod.GET, + Method = HttpMethod.Get, Encoding = _encoding }; @@ -394,7 +395,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var requestBuilder = new HttpRequestBuilder(submitUrl.ToString()) { LogResponseContent = true, - Method = HttpMethod.POST, + Method = HttpMethod.Post, AllowAutoRedirect = true, Encoding = _encoding }; @@ -423,7 +424,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var requestBuilder = new HttpRequestBuilder(submitUrl.ToString()) { LogResponseContent = true, - Method = HttpMethod.POST, + Method = HttpMethod.Post, AllowAutoRedirect = true, SuppressHttpError = true, Encoding = _encoding @@ -466,7 +467,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var requestBuilder = new HttpRequestBuilder(loginUrl) { LogResponseContent = true, - Method = HttpMethod.GET, + Method = HttpMethod.Get, SuppressHttpError = true, Encoding = _encoding }; @@ -491,7 +492,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var requestBuilder = new HttpRequestBuilder(loginUrl) { LogResponseContent = true, - Method = HttpMethod.GET, + Method = HttpMethod.Get, SuppressHttpError = true, Encoding = _encoding }; @@ -565,7 +566,7 @@ namespace NzbDrone.Core.Indexers.Cardigann var requestBuilder = new HttpRequestBuilder(loginUrl.AbsoluteUri) { LogResponseContent = true, - Method = HttpMethod.GET, + Method = HttpMethod.Get, Encoding = _encoding }; @@ -666,21 +667,21 @@ namespace NzbDrone.Core.Indexers.Cardigann Dictionary<string, string> pairs = null; var queryCollection = new NameValueCollection(); - var method = HttpMethod.GET; + var method = HttpMethod.Get; if (string.Equals(request.Method, "post", StringComparison.OrdinalIgnoreCase)) { - method = HttpMethod.POST; + method = HttpMethod.Post; pairs = new Dictionary<string, string>(); } foreach (var input in request.Inputs) { var value = ApplyGoTemplateText(input.Value, variables); - if (method == HttpMethod.GET) + if (method == HttpMethod.Get) { queryCollection.Add(input.Key, value); } - else if (method == HttpMethod.POST) + else if (method == HttpMethod.Post) { pairs.Add(input.Key, value); } @@ -707,7 +708,7 @@ namespace NzbDrone.Core.Indexers.Cardigann httpRequest.Method = method; // Add form data for POST requests - if (method == HttpMethod.POST) + if (method == HttpMethod.Post) { foreach (var param in pairs) { @@ -724,7 +725,7 @@ namespace NzbDrone.Core.Indexers.Cardigann public async Task<HttpRequest> DownloadRequest(Uri link) { Cookies = GetCookies(); - var method = HttpMethod.GET; + var method = HttpMethod.Get; var headers = new Dictionary<string, string>(); var variables = GetBaseTemplateVariables(); @@ -759,7 +760,7 @@ namespace NzbDrone.Core.Indexers.Cardigann if (download.Method == "post") { - method = HttpMethod.POST; + method = HttpMethod.Post; } if (download.Infohash != null) @@ -1014,11 +1015,11 @@ namespace NzbDrone.Core.Indexers.Cardigann // HttpUtility.UrlPathEncode seems to only encode spaces, we use UrlEncode and replace + with %20 as a workaround var searchUrl = ResolvePath(ApplyGoTemplateText(searchPath.Path, variables, WebUtility.UrlEncode).Replace("+", "%20")).AbsoluteUri; var queryCollection = new List<KeyValuePair<string, string>>(); - var method = HttpMethod.GET; + var method = HttpMethod.Get; if (string.Equals(searchPath.Method, "post", StringComparison.OrdinalIgnoreCase)) { - method = HttpMethod.POST; + method = HttpMethod.Post; } var inputsList = new List<Dictionary<string, string>>(); @@ -1064,7 +1065,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } } - if (method == HttpMethod.GET) + if (method == HttpMethod.Get) { if (queryCollection.Count > 0) { @@ -1079,7 +1080,7 @@ namespace NzbDrone.Core.Indexers.Cardigann requestbuilder.Method = method; // Add FormData for searchs that POST - if (method == HttpMethod.POST) + if (method == HttpMethod.Post) { foreach (var param in queryCollection) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs index bf316f438..a30436849 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs @@ -1,4 +1,5 @@ using System; +using System.Net.Http; using System.Threading.Tasks; using NLog; using NzbDrone.Common.Http; @@ -56,7 +57,7 @@ namespace NzbDrone.Core.Indexers.Gazelle LogResponseContent = true }; - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); var cookies = Cookies; diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsRequestGenerator.cs index 8c486c673..807ee5b75 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsRequestGenerator.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Common.Serializer; @@ -50,7 +51,7 @@ namespace NzbDrone.Core.Indexers.HDBits .Resource("/api/torrents") .Build(); - request.Method = HttpMethod.POST; + request.Method = HttpMethod.Post; const string appJson = "application/json"; request.Headers.Accept = appJson; request.Headers.ContentType = appJson; diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs b/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs index e4742cc0e..9bae17112 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; +using System.Net.Http; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -57,7 +58,7 @@ namespace NzbDrone.Core.Indexers.Definitions AllowAutoRedirect = true }; - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); var cookies = Cookies; diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs index a7f59e159..e7957c0ea 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Globalization; using System.Linq; +using System.Net.Http; using System.Text.RegularExpressions; using System.Threading.Tasks; using AngleSharp.Html.Parser; @@ -52,7 +53,7 @@ namespace NzbDrone.Core.Indexers.Definitions LogResponseContent = true }; - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); var cookies = Cookies; diff --git a/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs b/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs index 29224d5a6..59d3bb07d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading.Tasks; using AngleSharp.Html.Parser; using FluentValidation; @@ -54,7 +55,7 @@ namespace NzbDrone.Core.Indexers.Definitions LogResponseContent = true }; - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); var cookies = Cookies; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs index a3b1da8ab..4d6d231c6 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Globalization; +using System.Net.Http; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -53,7 +54,7 @@ namespace NzbDrone.Core.Indexers.Definitions LogResponseContent = true }; - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); var cookies = Cookies; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs index 29911e7db..155ec309a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Net.Http; using System.Xml; using System.Xml.Linq; using NLog; @@ -50,7 +51,7 @@ namespace NzbDrone.Core.Indexers.Newznab var request = new HttpRequest(url, HttpAccept.Rss); request.AllowAutoRedirect = true; - request.Method = HttpMethod.GET; + request.Method = HttpMethod.Get; HttpResponse response; diff --git a/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs b/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs index 2ab60205e..392fedc67 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Globalization; using System.Linq; +using System.Net.Http; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -79,7 +80,7 @@ namespace NzbDrone.Core.Indexers.Definitions { LogResponseContent = true, AllowAutoRedirect = true, - Method = HttpMethod.POST + Method = HttpMethod.Post }; var authLoginCheckRequest = requestBuilder3 diff --git a/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs b/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs index f5a7092a9..dfb3f0a35 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Net.Http; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -52,7 +53,7 @@ namespace NzbDrone.Core.Indexers.Definitions { LogResponseContent = true, AllowAutoRedirect = true, - Method = HttpMethod.POST + Method = HttpMethod.Post }; var authLoginRequest = requestBuilder diff --git a/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs b/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs index 4033a23f2..e80dbad09 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -59,7 +60,7 @@ namespace NzbDrone.Core.Indexers.Definitions var loginPage = await ExecuteAuth(new HttpRequest(Settings.BaseUrl + "login.php")); - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); requestBuilder.SetCookies(loginPage.GetCookies()); diff --git a/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs b/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs index d7de77b4a..7c48ab38f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Globalization; using System.Linq; +using System.Net.Http; using System.Threading.Tasks; using AngleSharp.Html.Parser; using FluentValidation; @@ -58,7 +59,7 @@ namespace NzbDrone.Core.Indexers.Definitions var loginPage = await ExecuteAuth(new HttpRequest(Settings.BaseUrl + "login.php")); - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); requestBuilder.SetCookies(loginPage.GetCookies()); diff --git a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs index c45cd1b8d..bcd4084e7 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; +using System.Net.Http; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -57,7 +58,7 @@ namespace NzbDrone.Core.Indexers.Definitions AllowAutoRedirect = true }; - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); var cookies = Cookies; diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs index f9dd987fa..67e393e39 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Net; +using System.Net.Http; using System.Net.Mime; using System.Text; using System.Threading.Tasks; @@ -75,7 +76,7 @@ namespace NzbDrone.Core.Indexers.Definitions { LogResponseContent = true, AllowAutoRedirect = true, - Method = HttpMethod.POST, + Method = HttpMethod.Post, }; var request = requestBuilder.Build(); diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs index ef253a5eb..04b176a0a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Net.Http; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -57,7 +58,7 @@ namespace NzbDrone.Core.Indexers.Definitions { var requestBuilder = new HttpRequestBuilder(string.Format("{0}/{1}", Settings.BaseUrl.TrimEnd('/'), "checkpoint/API")) { - Method = HttpMethod.POST, + Method = HttpMethod.Post, LogResponseContent = true, AllowAutoRedirect = true }; @@ -77,7 +78,7 @@ namespace NzbDrone.Core.Indexers.Definitions var requestBuilder2 = new HttpRequestBuilder(string.Format("{0}/{1}", Settings.BaseUrl.TrimEnd('/'), "checkpoint/")) { - Method = HttpMethod.POST, + Method = HttpMethod.Post, LogResponseContent = true, AllowAutoRedirect = true }; diff --git a/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs b/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs index 5fc618a90..1d56f6110 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; +using System.Net.Http; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -59,7 +60,7 @@ namespace NzbDrone.Core.Indexers.Definitions AllowAutoRedirect = true }; - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; var cookies = Cookies; diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs index 3152fc1eb..065ab7481 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; +using System.Net.Http; using System.Text.RegularExpressions; using System.Threading.Tasks; using FluentValidation; @@ -54,7 +55,7 @@ namespace NzbDrone.Core.Indexers.Definitions LogResponseContent = true }; - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); var cookies = Cookies; diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs index 6fdf85976..87cca4876 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Net; +using System.Net.Http; using System.Text.RegularExpressions; using System.Threading.Tasks; using AngleSharp.Html.Parser; @@ -63,7 +64,7 @@ namespace NzbDrone.Core.Indexers.Definitions var json1 = JObject.Parse(loginPage.Content); var captchaSelection = json1["images"][0]["hash"]; - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); requestBuilder.SetCookies(loginPage.GetCookies()); diff --git a/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs b/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs index 6e1233841..48497b75a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Globalization; using System.Linq; +using System.Net.Http; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; @@ -79,7 +80,7 @@ namespace NzbDrone.Core.Indexers.Definitions LogResponseContent = true }; - requestBuilder.Method = HttpMethod.POST; + requestBuilder.Method = HttpMethod.Post; requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); requestBuilder.SetCookies(loginPage.GetCookies()); @@ -102,7 +103,7 @@ namespace NzbDrone.Core.Indexers.Definitions LogResponseContent = true }; - requestBuilder2.Method = HttpMethod.POST; + requestBuilder2.Method = HttpMethod.Post; requestBuilder2.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); requestBuilder2.SetCookies(response.GetCookies()); diff --git a/src/NzbDrone.Core/Notifications/Discord/DiscordProxy.cs b/src/NzbDrone.Core/Notifications/Discord/DiscordProxy.cs index f3a6be3d2..c066da569 100644 --- a/src/NzbDrone.Core/Notifications/Discord/DiscordProxy.cs +++ b/src/NzbDrone.Core/Notifications/Discord/DiscordProxy.cs @@ -1,3 +1,4 @@ +using System.Net.Http; using NLog; using NzbDrone.Common.Http; using NzbDrone.Common.Serializer; @@ -29,7 +30,7 @@ namespace NzbDrone.Core.Notifications.Discord .Accept(HttpAccept.Json) .Build(); - request.Method = HttpMethod.POST; + request.Method = HttpMethod.Post; request.Headers.ContentType = "application/json"; request.SetContent(payload.ToJson()); diff --git a/src/NzbDrone.Core/Notifications/Join/JoinProxy.cs b/src/NzbDrone.Core/Notifications/Join/JoinProxy.cs index 7c901100e..aa477fbdd 100644 --- a/src/NzbDrone.Core/Notifications/Join/JoinProxy.cs +++ b/src/NzbDrone.Core/Notifications/Join/JoinProxy.cs @@ -1,4 +1,5 @@ using System; +using System.Net.Http; using FluentValidation.Results; using NLog; using NzbDrone.Common.Extensions; @@ -27,7 +28,7 @@ namespace NzbDrone.Core.Notifications.Join public void SendNotification(string title, string message, JoinSettings settings) { - var method = HttpMethod.GET; + var method = HttpMethod.Get; try { diff --git a/src/NzbDrone.Core/Notifications/PushBullet/PushBulletProxy.cs b/src/NzbDrone.Core/Notifications/PushBullet/PushBulletProxy.cs index 074d5578f..f39382ae8 100644 --- a/src/NzbDrone.Core/Notifications/PushBullet/PushBulletProxy.cs +++ b/src/NzbDrone.Core/Notifications/PushBullet/PushBulletProxy.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Net; +using System.Net.Http; using FluentValidation.Results; using NLog; using NzbDrone.Common.Extensions; @@ -100,7 +101,7 @@ namespace NzbDrone.Core.Notifications.PushBullet var request = requestBuilder.Build(); - request.Method = HttpMethod.GET; + request.Method = HttpMethod.Get; request.AddBasicAuthentication(settings.ApiKey, string.Empty); var response = _httpClient.Execute(request); diff --git a/src/NzbDrone.Core/Notifications/SendGrid/SendGridProxy.cs b/src/NzbDrone.Core/Notifications/SendGrid/SendGridProxy.cs index a8a44ef11..6a3b41ca9 100644 --- a/src/NzbDrone.Core/Notifications/SendGrid/SendGridProxy.cs +++ b/src/NzbDrone.Core/Notifications/SendGrid/SendGridProxy.cs @@ -1,4 +1,5 @@ using System.Net; +using System.Net.Http; using NzbDrone.Common.Http; using NzbDrone.Common.Serializer; @@ -22,7 +23,7 @@ namespace NzbDrone.Core.Notifications.SendGrid { try { - var request = BuildRequest(settings, "mail/send", HttpMethod.POST); + var request = BuildRequest(settings, "mail/send", HttpMethod.Post); var payload = new SendGridPayload { diff --git a/src/NzbDrone.Core/Notifications/Slack/SlackProxy.cs b/src/NzbDrone.Core/Notifications/Slack/SlackProxy.cs index 02075dad9..c8dd12f53 100644 --- a/src/NzbDrone.Core/Notifications/Slack/SlackProxy.cs +++ b/src/NzbDrone.Core/Notifications/Slack/SlackProxy.cs @@ -1,3 +1,4 @@ +using System.Net.Http; using NLog; using NzbDrone.Common.Http; using NzbDrone.Common.Serializer; @@ -29,7 +30,7 @@ namespace NzbDrone.Core.Notifications.Slack .Accept(HttpAccept.Json) .Build(); - request.Method = HttpMethod.POST; + request.Method = HttpMethod.Post; request.Headers.ContentType = "application/json"; request.SetContent(payload.ToJson()); diff --git a/src/NzbDrone.Core/Notifications/Webhook/WebhookMethod.cs b/src/NzbDrone.Core/Notifications/Webhook/WebhookMethod.cs index 5d6e859a6..a3f594bf7 100755 --- a/src/NzbDrone.Core/Notifications/Webhook/WebhookMethod.cs +++ b/src/NzbDrone.Core/Notifications/Webhook/WebhookMethod.cs @@ -1,10 +1,11 @@ +using System.Net.Http; using NzbDrone.Common.Http; namespace NzbDrone.Core.Notifications.Webhook { public enum WebhookMethod { - POST = HttpMethod.POST, - PUT = HttpMethod.PUT + POST = 1, + PUT = 2 } } diff --git a/src/NzbDrone.Core/Notifications/Webhook/WebhookProxy.cs b/src/NzbDrone.Core/Notifications/Webhook/WebhookProxy.cs index 489eeb41f..d196b5579 100755 --- a/src/NzbDrone.Core/Notifications/Webhook/WebhookProxy.cs +++ b/src/NzbDrone.Core/Notifications/Webhook/WebhookProxy.cs @@ -1,3 +1,5 @@ +using System; +using System.Net.Http; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Common.Serializer; @@ -26,7 +28,13 @@ namespace NzbDrone.Core.Notifications.Webhook .Accept(HttpAccept.Json) .Build(); - request.Method = (HttpMethod)settings.Method; + request.Method = settings.Method switch + { + (int)WebhookMethod.POST => HttpMethod.Post, + (int)WebhookMethod.PUT => HttpMethod.Put, + _ => throw new ArgumentOutOfRangeException($"Invalid Webhook method {settings.Method}") + }; + request.Headers.ContentType = "application/json"; request.SetContent(body.ToJson()); From 08d112a96f4ae19c244252484c5b2cb77d80bc2a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 3 Jan 2022 12:35:05 -0600 Subject: [PATCH 0305/2320] New: Privacy custom filter option Fixes #759 --- .../Filter/Builder/FilterBuilderRow.js | 4 ++++ .../Builder/PrivacyFilterBuilderRowValue.js | 20 +++++++++++++++++++ .../Helpers/Props/filterBuilderValueTypes.js | 1 + .../src/Store/Actions/indexerIndexActions.js | 15 ++++++++++---- 4 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 frontend/src/Components/Filter/Builder/PrivacyFilterBuilderRowValue.js diff --git a/frontend/src/Components/Filter/Builder/FilterBuilderRow.js b/frontend/src/Components/Filter/Builder/FilterBuilderRow.js index 9365ee04c..ed375b745 100644 --- a/frontend/src/Components/Filter/Builder/FilterBuilderRow.js +++ b/frontend/src/Components/Filter/Builder/FilterBuilderRow.js @@ -8,6 +8,7 @@ import BoolFilterBuilderRowValue from './BoolFilterBuilderRowValue'; import DateFilterBuilderRowValue from './DateFilterBuilderRowValue'; import FilterBuilderRowValueConnector from './FilterBuilderRowValueConnector'; import IndexerFilterBuilderRowValueConnector from './IndexerFilterBuilderRowValueConnector'; +import PrivacyFilterBuilderRowValue from './PrivacyFilterBuilderRowValue'; import ProtocolFilterBuilderRowValue from './ProtocolFilterBuilderRowValue'; import TagFilterBuilderRowValueConnector from './TagFilterBuilderRowValueConnector'; import styles from './FilterBuilderRow.css'; @@ -63,6 +64,9 @@ function getRowValueConnector(selectedFilterBuilderProp) { case filterBuilderValueTypes.PROTOCOL: return ProtocolFilterBuilderRowValue; + case filterBuilderValueTypes.PRIVACY: + return PrivacyFilterBuilderRowValue; + case filterBuilderValueTypes.TAG: return TagFilterBuilderRowValueConnector; diff --git a/frontend/src/Components/Filter/Builder/PrivacyFilterBuilderRowValue.js b/frontend/src/Components/Filter/Builder/PrivacyFilterBuilderRowValue.js new file mode 100644 index 000000000..4004f0ced --- /dev/null +++ b/frontend/src/Components/Filter/Builder/PrivacyFilterBuilderRowValue.js @@ -0,0 +1,20 @@ +import React from 'react'; +import translate from 'Utilities/String/translate'; +import FilterBuilderRowValue from './FilterBuilderRowValue'; + +const privacyTypes = [ + { id: 'public', name: translate('Public') }, + { id: 'private', name: translate('Private') }, + { id: 'semiPrivate', name: translate('SemiPrivate') } +]; + +function PrivacyFilterBuilderRowValue(props) { + return ( + <FilterBuilderRowValue + tagList={privacyTypes} + {...props} + /> + ); +} + +export default PrivacyFilterBuilderRowValue; diff --git a/frontend/src/Helpers/Props/filterBuilderValueTypes.js b/frontend/src/Helpers/Props/filterBuilderValueTypes.js index b31bd5043..7fed535f2 100644 --- a/frontend/src/Helpers/Props/filterBuilderValueTypes.js +++ b/frontend/src/Helpers/Props/filterBuilderValueTypes.js @@ -4,6 +4,7 @@ export const DATE = 'date'; export const DEFAULT = 'default'; export const INDEXER = 'indexer'; export const PROTOCOL = 'protocol'; +export const PRIVACY = 'privacy'; export const APP_PROFILE = 'appProfile'; export const MOVIE_STATUS = 'movieStatus'; export const TAG = 'tag'; diff --git a/frontend/src/Store/Actions/indexerIndexActions.js b/frontend/src/Store/Actions/indexerIndexActions.js index f0da8b23b..8efc9fb08 100644 --- a/frontend/src/Store/Actions/indexerIndexActions.js +++ b/frontend/src/Store/Actions/indexerIndexActions.js @@ -2,6 +2,7 @@ import { createAction } from 'redux-actions'; import { batchActions } from 'redux-batched-actions'; import { filterBuilderTypes, filterBuilderValueTypes, sortDirections } from 'Helpers/Props'; import { createThunk, handleThunks } from 'Store/thunks'; +import sortByName from 'Utilities/Array/sortByName'; import createAjaxRequest from 'Utilities/createAjaxRequest'; import translate from 'Utilities/String/translate'; import { removeItem, set, updateItem } from './baseActions'; @@ -118,12 +119,12 @@ export const defaultState = { filterBuilderProps: [ { name: 'name', - label: 'Indexer Name', + label: translate('IndexerName'), type: filterBuilderTypes.STRING }, { name: 'enable', - label: 'Enabled', + label: translate('Enabled'), type: filterBuilderTypes.EXACT, valueType: filterBuilderValueTypes.BOOL }, @@ -135,15 +136,21 @@ export const defaultState = { }, { name: 'priority', - label: 'Priority', + label: translate('Priority'), type: filterBuilderTypes.NUMBER }, { name: 'protocol', - label: 'Protocol', + label: translate('Protocol'), type: filterBuilderTypes.EXACT, valueType: filterBuilderValueTypes.PROTOCOL }, + { + name: 'privacy', + label: translate('Privacy'), + type: filterBuilderTypes.EXACT, + valueType: filterBuilderValueTypes.PRIVACY + }, { name: 'appProfileId', label: translate('AppProfile'), From 573dde97e56cd95d5890657f55961f81d2b33d1f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 3 Jan 2022 14:13:29 -0600 Subject: [PATCH 0306/2320] Default Method in HttpRequest to HttpMethod.Get --- src/NzbDrone.Common/Http/HttpRequest.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NzbDrone.Common/Http/HttpRequest.cs b/src/NzbDrone.Common/Http/HttpRequest.cs index 769712386..4a0b7a85a 100644 --- a/src/NzbDrone.Common/Http/HttpRequest.cs +++ b/src/NzbDrone.Common/Http/HttpRequest.cs @@ -14,6 +14,7 @@ namespace NzbDrone.Common.Http { Url = new HttpUri(url); Headers = new HttpHeader(); + Method = HttpMethod.Get; ConnectionKeepAlive = true; AllowAutoRedirect = true; Cookies = new Dictionary<string, string>(); From 0af8e84d2d161d5b511e059a45c85ecddce7363c Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 3 Jan 2022 16:43:22 -0600 Subject: [PATCH 0307/2320] Remove unused sortByName import from indexerIndexActions --- frontend/src/Store/Actions/indexerIndexActions.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/Store/Actions/indexerIndexActions.js b/frontend/src/Store/Actions/indexerIndexActions.js index 8efc9fb08..fb5cd8c43 100644 --- a/frontend/src/Store/Actions/indexerIndexActions.js +++ b/frontend/src/Store/Actions/indexerIndexActions.js @@ -2,7 +2,6 @@ import { createAction } from 'redux-actions'; import { batchActions } from 'redux-batched-actions'; import { filterBuilderTypes, filterBuilderValueTypes, sortDirections } from 'Helpers/Props'; import { createThunk, handleThunks } from 'Store/thunks'; -import sortByName from 'Utilities/Array/sortByName'; import createAjaxRequest from 'Utilities/createAjaxRequest'; import translate from 'Utilities/String/translate'; import { removeItem, set, updateItem } from './baseActions'; From 79e3e31028ef7f7e8ba74219c237efebc1682263 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 3 Jan 2022 17:23:21 -0600 Subject: [PATCH 0308/2320] Only dispatch search to enabled, non-failed, indexers Fixes #712 --- src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs index ac05628f5..75d87e73a 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs @@ -142,7 +142,7 @@ namespace NzbDrone.Core.IndexerSearch private async Task<List<ReleaseInfo>> Dispatch(Func<IIndexer, Task<IndexerPageableQueryResult>> searchAction, SearchCriteriaBase criteriaBase) { - var indexers = _indexerFactory.GetAvailableProviders(); + var indexers = _indexerFactory.Enabled(); if (criteriaBase.IndexerIds != null && criteriaBase.IndexerIds.Count > 0) { From 9dadb35b98620cf8328c9c41af00f358b7206461 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 3 Jan 2022 18:02:41 -0600 Subject: [PATCH 0309/2320] Fixed: Don't die when definition doesn't exist Fixes #596 --- src/NzbDrone.Core/Indexers/IndexerFactory.cs | 25 +++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/IndexerFactory.cs b/src/NzbDrone.Core/Indexers/IndexerFactory.cs index be4fd0af5..0140eb289 100644 --- a/src/NzbDrone.Core/Indexers/IndexerFactory.cs +++ b/src/NzbDrone.Core/Indexers/IndexerFactory.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using FluentValidation.Results; using NLog; +using NzbDrone.Core.Datastore; using NzbDrone.Core.Indexers.Cardigann; using NzbDrone.Core.Indexers.Newznab; using NzbDrone.Core.IndexerVersions; @@ -45,16 +46,27 @@ namespace NzbDrone.Core.Indexers public override List<IndexerDefinition> All() { var definitions = base.All(); + var filteredDefinitions = new List<IndexerDefinition>(); foreach (var definition in definitions) { if (definition.Implementation == typeof(Cardigann.Cardigann).Name) { - MapCardigannDefinition(definition); + try + { + MapCardigannDefinition(definition); + } + catch + { + // Skip indexer if we fail in Cardigann mapping + continue; + } } + + filteredDefinitions.Add(definition); } - return definitions; + return filteredDefinitions; } public override IndexerDefinition Get(int id) @@ -63,7 +75,14 @@ namespace NzbDrone.Core.Indexers if (definition.Implementation == typeof(Cardigann.Cardigann).Name) { - MapCardigannDefinition(definition); + try + { + MapCardigannDefinition(definition); + } + catch + { + throw new ModelNotFoundException(typeof(IndexerDefinition), id); + } } return definition; From d925b37066469de4d0c3a166f10f5af05b32a726 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 8 Jan 2022 15:12:07 -0600 Subject: [PATCH 0310/2320] Update createSentryMiddleware.js --- frontend/src/Store/Middleware/createSentryMiddleware.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/Store/Middleware/createSentryMiddleware.js b/frontend/src/Store/Middleware/createSentryMiddleware.js index 441caa959..e4dba73d8 100644 --- a/frontend/src/Store/Middleware/createSentryMiddleware.js +++ b/frontend/src/Store/Middleware/createSentryMiddleware.js @@ -80,8 +80,8 @@ export default function createSentryMiddleware() { return; } - const dsn = isProduction ? 'https://b0fb75c38ef4487dbf742f79c4ba62d2@sentry.servarr.com/12' : - 'https://da610619280249f891ec3ee306906793@sentry.servarr.com/13'; + const dsn = isProduction ? 'https://b233094711fe4430a0b0c5da2e01df93@sentry.servarr.com/28' : + 'https://116efebd253a4dff9df9475a31510001@sentry.servarr.com/37'; sentry.init({ dsn, From 8d23cbf52b35e0be982f72e518710a6a1e20458f Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 8 Jan 2022 09:35:51 -0600 Subject: [PATCH 0311/2320] New: (DanishBytes) Add .org Alt Link based on jackett bac28c030295bddeb2cc7934da6257dd013d8f60 --- src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs index 3527a05fe..c5def10a7 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs @@ -22,7 +22,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class DanishBytes : TorrentIndexerBase<DanishBytesSettings> { public override string Name => "DanishBytes"; - public override string[] IndexerUrls => new string[] { "https://danishbytes.club/" }; + public override string[] IndexerUrls => new string[] { "https://danishbytes.club/", "https://danishbytes2.org/" }; public override string Description => "DanishBytes is a Private Danish Tracker"; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; From 9e9e6662049af375841ae40c158a474c0d0a716d Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Sat, 8 Jan 2022 23:16:48 +0000 Subject: [PATCH 0312/2320] Fixed: Postgres default port --- src/NzbDrone.Core/Configuration/ConfigFileProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index 7f1490eec..9570aa2fc 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -197,7 +197,7 @@ namespace NzbDrone.Core.Configuration public string PostgresPassword => GetValue("PostgresPassword", string.Empty, persist: false); public string PostgresMainDb => GetValue("PostgresMainDb", "prowlarr-main", persist: false); public string PostgresLogDb => GetValue("PostgresLogDb", "prowlarr-log", persist: false); - public int PostgresPort => GetValueInt("PostgresPort", 5436, persist: false); + public int PostgresPort => GetValueInt("PostgresPort", 5432, persist: false); public bool LogSql => GetValueBoolean("LogSql", false, persist: false); public int LogRotate => GetValueInt("LogRotate", 50, persist: false); public bool FilterSentryEvents => GetValueBoolean("FilterSentryEvents", true, persist: false); From a62a4360e3c125c7f151b104127927024916f41a Mon Sep 17 00:00:00 2001 From: Yukine <DevYukine@gmx.de> Date: Sun, 16 Jan 2022 04:29:17 +0100 Subject: [PATCH 0313/2320] New: (MoreThanTV) Add MoreThanTV (#771) * New: (MoreThanTV) Add MoreThanTV * fix(ParseUtil): revert change since its already implemented elsewhere * docs: clarify how to get cookies * fix: set correct FieldDefinition order in Settings --- .../Indexers/Definitions/MoreThanTV.cs | 341 ++++++++++++++++++ 1 file changed, 341 insertions(+) create mode 100644 src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs diff --git a/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs b/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs new file mode 100644 index 000000000..2c1e5dffc --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs @@ -0,0 +1,341 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Web; +using AngleSharp.Dom; +using AngleSharp.Html.Dom; +using AngleSharp.Html.Parser; +using FluentValidation; +using NLog; +using NzbDrone.Common.Http; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Indexers.Definitions; + +public class MoreThanTV : TorrentIndexerBase<MoreThanTVSettings> +{ + public override string Name => "MoreThanTV"; + public override string[] IndexerUrls => new[] { "https://morethantv.me/" }; + public override string Description => "Private torrent tracker for TV / MOVIES"; + public override DownloadProtocol Protocol => DownloadProtocol.Torrent; + public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + public override IndexerCapabilities Capabilities => SetCapabilities(); + public override bool FollowRedirect => true; + + public MoreThanTV(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) + { + } + + public override IIndexerRequestGenerator GetRequestGenerator() + => new MoreThanTVRequestGenerator(Settings, Capabilities); + + public override IParseIndexerResponse GetParser() + => new MoreThanTVParser + { + Settings = Settings + }; + + private IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities + { + TvSearchParams = new List<TvSearchParam> + { + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep + }, + MovieSearchParams = new List<MovieSearchParam> + { + MovieSearchParam.Q + } + }; + + caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movies"); + caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "TV"); + + return caps; + } + + protected override IDictionary<string, string> GetCookies() + { + return CookieUtil.CookieHeaderToDictionary(Settings.Cookie); + } +} + +public class MoreThanTVRequestGenerator : IIndexerRequestGenerator +{ + private MoreThanTVSettings Settings { get; } + private IndexerCapabilities Capabilities { get; } + + private NameValueCollection BrowserHeaders { get; } + + public MoreThanTVRequestGenerator(MoreThanTVSettings settings, IndexerCapabilities capabilities) + { + Settings = settings; + Capabilities = capabilities; + BrowserHeaders = new NameValueCollection() + { + { "referer", settings.BaseUrl }, + { "Upgrade-Insecure-Requests", "1" }, + { "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.72 Safari/537.36" } + }; + } + + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + => PerformRequest(searchCriteria); + + public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) + => PerformRequest(searchCriteria); + + public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) + => PerformRequest(searchCriteria); + + public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + => PerformRequest(searchCriteria); + + public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) + => PerformRequest(searchCriteria); + + public Func<IDictionary<string, string>> GetCookies { get; set; } + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + + private IndexerPageableRequestChain PerformRequest(SearchCriteriaBase query) + { + var chain = new IndexerPageableRequestChain(); + + var requests = new List<IndexerRequest> { new (new HttpRequest(GetTorrentSearchUrl(query)) { Headers = new HttpHeader(BrowserHeaders), AllowAutoRedirect = true }) }; + + if (query is TvSearchCriteria tvSearchCriteria) + { + // Always search for torrent groups (complete seasons) too + var seasonRegex = new Regex(@".*\s[Ss]{1}\d{2}([Ee]{1}\d{2,3})?$", RegexOptions.Compiled); + var seasonMatch = seasonRegex.Match(query.SanitizedSearchTerm); + if (seasonMatch.Success) + { + var seasonReplaceRegex = new Regex(@"[Ss]{1}\d{2}([Ee]{1}\d{2,3})?", RegexOptions.Compiled); + var newSearchQuery = seasonReplaceRegex.Replace(query.SanitizedSearchTerm, $"Season {tvSearchCriteria.Season}"); + requests.Add(new IndexerRequest(new HttpRequest(GetTorrentSearchUrl(query, newSearchQuery)) { Headers = new HttpHeader(BrowserHeaders), AllowAutoRedirect = true })); + } + } + + chain.Add(requests); + + return chain; + } + + private string GetTorrentSearchUrl(SearchCriteriaBase query, string overrideSearchTerm = null) + { + var qc = new NameValueCollection + { + { "action", "advanced" }, + { "sizetype", "gb" }, + { "sizerange", "0.01" }, + { "title", overrideSearchTerm ?? GetSearchString(query.SanitizedSearchTerm) } + }; + + switch (query) + { + case MovieSearchCriteria: + qc.Add("filter_cat[1]", "1"); // HD Movies + qc.Add("filter_cat[2]", "1"); // SD Movies + break; + case TvSearchCriteria: + qc.Add("filter_cat[3]", "1"); // HD EPISODE + qc.Add("filter_cat[4]", "1"); // SD Episode + qc.Add("filter_cat[5]", "1"); // HD Season + qc.Add("filter_cat[6]", "1"); // SD Season + break; + } + + return $"{Settings.BaseUrl}torrents.php?{qc.GetQueryString()}"; + } + + private string GetSearchString(string input) + { + input = input.Replace("Marvels", "Marvel"); // strip 's for better results + var regex = new Regex(@"(S\d{2})$", RegexOptions.Compiled); + return regex.Replace(input, "$1*"); // If we're just seaching for a season (no episode) append an * to include all episodes of that season. + } +} + +public class MoreThanTVParser : IParseIndexerResponse +{ + public MoreThanTVSettings Settings { get; init; } + + public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) + { + var releases = new List<ReleaseInfo>(); + + try + { + var parser = new HtmlParser(); + var document = parser.ParseDocument(indexerResponse.Content); + var torrents = document.QuerySelectorAll("#torrent_table > tbody > tr.torrent"); + var movies = new[] { "movie" }; + var tv = new[] { "season", "episode" }; + + // Loop through all torrents checking for groups + foreach (var torrent in torrents) + { + // Parse required data + var torrentGroup = torrent.QuerySelectorAll("table a[href^=\"/torrents.php?action=download\"]"); + foreach (var downloadAnchor in torrentGroup) + { + var title = downloadAnchor.ParentElement.ParentElement.ParentElement.TextContent.Trim(); + title = CleanUpTitle(title); + + var category = torrent.QuerySelector(".cats_col div").GetAttribute("title"); + + // default to Other + var indexerCategory = NewznabStandardCategory.Other; + + if (movies.Any(category.Contains)) + { + indexerCategory = NewznabStandardCategory.Movies; + } + else if (tv.Any(category.Contains)) + { + indexerCategory = NewznabStandardCategory.TV; + } + + releases.Add(GetReleaseInfo(torrent, downloadAnchor, title, indexerCategory)); + } + } + + return releases; + } + catch (Exception ex) + { + throw new Exception("Error while parsing torrent response", ex); + } + } + + /// <summary> + /// Gather Release info from torrent table. Target using css + /// </summary> + /// <param name="row"></param> + /// <param name="downloadAnchor"></param> + /// <param name="title"></param> + /// <param name="category"></param> + /// <returns></returns> + private ReleaseInfo GetReleaseInfo(IElement row, IElement downloadAnchor, string title, IndexerCategory category) + { + // count from bottom + const int FILES_COL = 8; + /*const int COMMENTS_COL = 7;*/ + const int DATE_COL = 6; + const int FILESIZE_COL = 5; + const int SNATCHED_COL = 4; + const int SEEDS_COL = 3; + const int LEECHERS_COL = 2; + /*const int USER_COL = 1;*/ + + var downloadAnchorHref = (downloadAnchor as IHtmlAnchorElement).Href; + var queryParams = HttpUtility.ParseQueryString(downloadAnchorHref, Encoding.UTF8); + var torrentId = queryParams["id"]; + + var qFiles = row.QuerySelector("td:nth-last-child(" + FILES_COL + ")").TextContent; + + var fileCount = ParseUtil.CoerceInt(qFiles); + var qPublishDate = row.QuerySelector("td:nth-last-child(" + DATE_COL + ") .time").Attributes["title"].Value; + var publishDate = DateTime.ParseExact(qPublishDate, "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime(); + var qPoster = row.QuerySelector("div.tp-banner img")?.GetAttribute("src"); + var poster = (qPoster != null && !qPoster.Contains("caticons")) ? qPoster : null; + var description = row.QuerySelector("div.tags")?.TextContent.Trim(); + var fileSize = row.QuerySelector("td:nth-last-child(" + FILESIZE_COL + ")").TextContent.Trim(); + var snatched = row.QuerySelector("td:nth-last-child(" + SNATCHED_COL + ")").TextContent.Trim(); + var seeds = row.QuerySelector("td:nth-last-child(" + SEEDS_COL + ")").TextContent.Trim(); + var leechs = row.QuerySelector("td:nth-last-child(" + LEECHERS_COL + ")").TextContent.Trim(); + + if (fileSize.Length <= 0 || snatched.Length <= 0 || seeds.Length <= 0 || leechs.Length <= 0) + { + // Size (xx.xx GB[ (Max)]) Snatches (xx) Seeders (xx) Leechers (xx) + throw new Exception($"We expected 4 torrent datas."); + } + + var detailUrl = $"{Settings.BaseUrl}details.php"; + + var size = ParseUtil.GetBytes(fileSize); + var grabs = int.Parse(snatched, NumberStyles.AllowThousands, CultureInfo.InvariantCulture); + var seeders = int.Parse(seeds, NumberStyles.AllowThousands, CultureInfo.InvariantCulture); + var leechers = int.Parse(leechs, NumberStyles.AllowThousands, CultureInfo.InvariantCulture); + var detailsUrl = $"{detailUrl}?torrentid={torrentId}"; + var downloadUrl = $"{detailUrl}?action=download&id={torrentId}"; + var categories = new List<IndexerCategory> { category }; + + return new TorrentInfo + { + Title = title, + Categories = categories, + DownloadUrl = downloadUrl, + PublishDate = publishDate, + PosterUrl = poster, + Description = description, + Seeders = seeders, + Peers = seeders + leechers, + Files = fileCount, + Size = size, + Grabs = grabs, + Guid = downloadUrl, + InfoUrl = detailsUrl, + DownloadVolumeFactor = 0, // ratioless tracker + UploadVolumeFactor = 1 + }; + } + + /// <summary> + /// Clean Up any title stuff + /// </summary> + /// <param name="title"></param> + /// <returns></returns> + private string CleanUpTitle(string title) + { + return title + .Replace(".", " ") + .Replace("4K", "2160p"); // sonarr cleanup + } + + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } +} + +public class MoreThanTVSettingsValidator : AbstractValidator<MoreThanTVSettings> +{ + public MoreThanTVSettingsValidator() + { + RuleFor(c => c.Cookie).NotEmpty(); + } +} + +public class MoreThanTVSettings : IIndexerSettings +{ + private static readonly MoreThanTVSettingsValidator Validator = new (); + + public MoreThanTVSettings() + { + Cookie = ""; + } + + [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] + public string BaseUrl { get; set; } + + [FieldDefinition(2, Label = "Cookie", HelpText = "Enter the cookies for the site, just copy everything after 'cookie:' from the request headers to the site", HelpLink = "https://wiki.servarr.com/prowlarr/faq#finding-cookies")] + public string Cookie { get; set; } + + [FieldDefinition(3)] + public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } +} From aa59da2f2247f404298c2ee0cce8417f7ce15ddc Mon Sep 17 00:00:00 2001 From: Yukine <devyukine@gmx.de> Date: Sun, 16 Jan 2022 08:15:47 +0100 Subject: [PATCH 0314/2320] Fixed: (MoreThanTV) use www url to fix cookie/redirect issues --- src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs b/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs index 2c1e5dffc..63069e75c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs @@ -25,7 +25,7 @@ namespace NzbDrone.Core.Indexers.Definitions; public class MoreThanTV : TorrentIndexerBase<MoreThanTVSettings> { public override string Name => "MoreThanTV"; - public override string[] IndexerUrls => new[] { "https://morethantv.me/" }; + public override string[] IndexerUrls => new[] { "https://www.morethantv.me/" }; public override string Description => "Private torrent tracker for TV / MOVIES"; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; From a7b1ef19f57b8182c2ec3b105fe17d770add33d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Payet?= <fx.payet@tfdn.org> Date: Sat, 15 Jan 2022 21:17:17 +0100 Subject: [PATCH 0315/2320] Replace WebUtility.UrlEncode to Uri.EscapeDataString --- src/NzbDrone.Core/Download/DownloadMappingService.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs | 2 +- .../Definitions/Cardigann/CardigannRequestGenerator.cs | 4 ++-- src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Download/DownloadMappingService.cs b/src/NzbDrone.Core/Download/DownloadMappingService.cs index a3dbcc539..812087c47 100644 --- a/src/NzbDrone.Core/Download/DownloadMappingService.cs +++ b/src/NzbDrone.Core/Download/DownloadMappingService.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Core.Download var encryptedLink = _protectionService.Protect(link.ToString()); var encodedLink = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(encryptedLink)); - var urlEncodedFile = WebUtility.UrlEncode(file); + var urlEncodedFile = Uri.EscapeDataString(file); var proxyLink = $"{serverUrl}{urlBase}/{indexerId}/download?apikey={_configFileProvider.ApiKey}&link={encodedLink}&file={urlEncodedFile}"; return new Uri(proxyLink); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs index 8595a16d1..20824838d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs @@ -184,7 +184,7 @@ namespace NzbDrone.Core.Indexers.Definitions searchString = match.Value; } - var episodeSearchUrl = searchUrl + WebUtility.UrlEncode(searchString); + var episodeSearchUrl = searchUrl + Uri.EscapeDataString(searchString); var request = new IndexerRequest(episodeSearchUrl, null); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 2622142cd..0ca06a2d4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -1013,7 +1013,7 @@ namespace NzbDrone.Core.Indexers.Cardigann // build search URL // HttpUtility.UrlPathEncode seems to only encode spaces, we use UrlEncode and replace + with %20 as a workaround - var searchUrl = ResolvePath(ApplyGoTemplateText(searchPath.Path, variables, WebUtility.UrlEncode).Replace("+", "%20")).AbsoluteUri; + var searchUrl = ResolvePath(ApplyGoTemplateText(searchPath.Path, variables, Uri.EscapeDataString).Replace("+", "%20")).AbsoluteUri; var queryCollection = new List<KeyValuePair<string, string>>(); var method = HttpMethod.Get; @@ -1038,7 +1038,7 @@ namespace NzbDrone.Core.Indexers.Cardigann { if (input.Key == "$raw") { - var rawStr = ApplyGoTemplateText(input.Value, variables, WebUtility.UrlEncode); + var rawStr = ApplyGoTemplateText(input.Value, variables, Uri.EscapeDataString); foreach (var part in rawStr.Split('&')) { var parts = part.Split(new char[] { '=' }, 2); diff --git a/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs b/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs index 59d3bb07d..c8a8cb0ab 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs @@ -174,7 +174,7 @@ namespace NzbDrone.Core.Indexers.Definitions if (term.IsNotNullOrWhiteSpace()) { - searchUrl += string.Format("?do=search&keywords={0}&search_type=t_name&category=0&include_dead_torrents=no", WebUtility.UrlEncode(term)); + searchUrl += string.Format("?do=search&keywords={0}&search_type=t_name&category=0&include_dead_torrents=no", Uri.EscapeDataString(term)); } if (categories != null && categories.Length > 0) diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs index 065ab7481..8da22b1a8 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs @@ -192,7 +192,7 @@ namespace NzbDrone.Core.Indexers.Definitions } else if (!string.IsNullOrWhiteSpace(searchString)) { - searchUrl += "exact/1/query/" + WebUtility.UrlEncode(searchString) + "/"; + searchUrl += "exact/1/query/" + Uri.EscapeDataString(searchString) + "/"; } var cats = Capabilities.Categories.MapTorznabCapsToTrackers(categories); From 6880f3863593244249bb0763ccf0d55d4240ed73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Payet?= <fx.payet@tfdn.org> Date: Sat, 15 Jan 2022 21:29:44 +0100 Subject: [PATCH 0316/2320] Remove extra replacing (already done by Uri.EscapeDataString) --- .../Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 0ca06a2d4..3b141f36a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -1013,7 +1013,7 @@ namespace NzbDrone.Core.Indexers.Cardigann // build search URL // HttpUtility.UrlPathEncode seems to only encode spaces, we use UrlEncode and replace + with %20 as a workaround - var searchUrl = ResolvePath(ApplyGoTemplateText(searchPath.Path, variables, Uri.EscapeDataString).Replace("+", "%20")).AbsoluteUri; + var searchUrl = ResolvePath(ApplyGoTemplateText(searchPath.Path, variables, Uri.EscapeDataString)).AbsoluteUri; var queryCollection = new List<KeyValuePair<string, string>>(); var method = HttpMethod.Get; From 2f22e7295cf705201bc74d371d3473426424f2d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Payet?= <fx.payet@tfdn.org> Date: Sat, 15 Jan 2022 22:10:15 +0100 Subject: [PATCH 0317/2320] Changes Uri.ToString() to Uri.AbsoluteUri to prevent unescaping characters --- src/Prowlarr.Api.V1/Indexers/NewznabController.cs | 2 +- src/Prowlarr.Api.V1/Search/SearchController.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Prowlarr.Api.V1/Indexers/NewznabController.cs b/src/Prowlarr.Api.V1/Indexers/NewznabController.cs index 6acaf9fd8..6160ed0a7 100644 --- a/src/Prowlarr.Api.V1/Indexers/NewznabController.cs +++ b/src/Prowlarr.Api.V1/Indexers/NewznabController.cs @@ -148,7 +148,7 @@ namespace NzbDrone.Api.V1.Indexers foreach (var result in results.Releases) { - result.DownloadUrl = result.DownloadUrl.IsNotNullOrWhiteSpace() ? _downloadMappingService.ConvertToProxyLink(new Uri(result.DownloadUrl), request.server, indexerDef.Id, result.Title).ToString() : null; + result.DownloadUrl = result.DownloadUrl.IsNotNullOrWhiteSpace() ? _downloadMappingService.ConvertToProxyLink(new Uri(result.DownloadUrl), request.server, indexerDef.Id, result.Title).AbsoluteUri : null; if (result.DownloadProtocol == DownloadProtocol.Torrent) { diff --git a/src/Prowlarr.Api.V1/Search/SearchController.cs b/src/Prowlarr.Api.V1/Search/SearchController.cs index f9f515901..dfa2fcc80 100644 --- a/src/Prowlarr.Api.V1/Search/SearchController.cs +++ b/src/Prowlarr.Api.V1/Search/SearchController.cs @@ -162,7 +162,7 @@ namespace Prowlarr.Api.V1.Search var release = downloadDecision.ToResource(); _remoteReleaseCache.Set(GetCacheKey(release), downloadDecision, TimeSpan.FromMinutes(30)); - release.DownloadUrl = release.DownloadUrl.IsNotNullOrWhiteSpace() ? _downloadMappingService.ConvertToProxyLink(new Uri(release.DownloadUrl), serverUrl, release.IndexerId, release.Title).ToString() : null; + release.DownloadUrl = release.DownloadUrl.IsNotNullOrWhiteSpace() ? _downloadMappingService.ConvertToProxyLink(new Uri(release.DownloadUrl), serverUrl, release.IndexerId, release.Title).AbsoluteUri : null; release.MagnetUrl = release.MagnetUrl.IsNotNullOrWhiteSpace() ? _downloadMappingService.ConvertToProxyLink(new Uri(release.MagnetUrl), serverUrl, release.IndexerId, release.Title).ToString() : null; result.Add(release); From dad16f2c57163c0942b2489a6ec2d6b4ae984291 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 16 Jan 2022 14:22:32 -0600 Subject: [PATCH 0318/2320] Bump version to 0.2 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index aa3e7e5b9..40b05d1da 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,7 +7,7 @@ variables: outputFolder: './_output' artifactsFolder: './_artifacts' testsFolder: './_tests' - majorVersion: '0.1.10' + majorVersion: '0.2.0' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From 06913a2975d126032e5d80816f6e16807c99a9f9 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 17 Jan 2022 12:52:33 -0600 Subject: [PATCH 0319/2320] Fixed: (PornoLab) Update Privacy to Semi-Private --- src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs b/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs index dfb3f0a35..8ec32e9b0 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Language => "ru-ru"; public override Encoding Encoding => Encoding.GetEncoding("windows-1251"); public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPrivate; public override IndexerCapabilities Capabilities => SetCapabilities(); public PornoLab(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) From de17ae9969b6a6fcd1b14be8626cecbdbca26952 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 17 Jan 2022 12:52:29 -0600 Subject: [PATCH 0320/2320] Fixed: (RuTracker org) Update Privacy to Semi-Private --- src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs index bcd4084e7..26dd1525e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Language => "ru-org"; public override Encoding Encoding => Encoding.GetEncoding("windows-1251"); public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPrivate; public override IndexerCapabilities Capabilities => SetCapabilities(); public RuTracker(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) From 34e57f27ff342847f024910feacfee367d1121ea Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 17 Jan 2022 18:45:40 -0600 Subject: [PATCH 0321/2320] New: Don't close Indexer add list when adding Indexers --- frontend/src/Indexer/Add/AddIndexerModal.js | 6 ++++-- .../Indexer/Add/AddIndexerModalContentConnector.js | 5 +++-- frontend/src/Indexer/Index/IndexerIndex.js | 12 +++++++----- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/frontend/src/Indexer/Add/AddIndexerModal.js b/frontend/src/Indexer/Add/AddIndexerModal.js index 75cba5a17..4c4db24b9 100644 --- a/frontend/src/Indexer/Add/AddIndexerModal.js +++ b/frontend/src/Indexer/Add/AddIndexerModal.js @@ -4,7 +4,7 @@ import Modal from 'Components/Modal/Modal'; import AddIndexerModalContentConnector from './AddIndexerModalContentConnector'; import styles from './AddIndexerModal.css'; -function AddIndexerModal({ isOpen, onModalClose, ...otherProps }) { +function AddIndexerModal({ isOpen, onModalClose, onSelectIndexer, ...otherProps }) { return ( <Modal isOpen={isOpen} @@ -14,6 +14,7 @@ function AddIndexerModal({ isOpen, onModalClose, ...otherProps }) { <AddIndexerModalContentConnector {...otherProps} onModalClose={onModalClose} + onSelectIndexer={onSelectIndexer} /> </Modal> ); @@ -21,7 +22,8 @@ function AddIndexerModal({ isOpen, onModalClose, ...otherProps }) { AddIndexerModal.propTypes = { isOpen: PropTypes.bool.isRequired, - onModalClose: PropTypes.func.isRequired + onModalClose: PropTypes.func.isRequired, + onSelectIndexer: PropTypes.func.isRequired }; export default AddIndexerModal; diff --git a/frontend/src/Indexer/Add/AddIndexerModalContentConnector.js b/frontend/src/Indexer/Add/AddIndexerModalContentConnector.js index 2d6ac9fef..0dc810608 100644 --- a/frontend/src/Indexer/Add/AddIndexerModalContentConnector.js +++ b/frontend/src/Indexer/Add/AddIndexerModalContentConnector.js @@ -51,7 +51,7 @@ class AddIndexerModalContentConnector extends Component { onIndexerSelect = ({ implementation, name }) => { this.props.selectIndexerSchema({ implementation, name }); - this.props.onModalClose({ indexerSelected: true }); + this.props.onSelectIndexer(); }; onSortPress = (sortKey, sortDirection) => { @@ -76,7 +76,8 @@ AddIndexerModalContentConnector.propTypes = { fetchIndexerSchema: PropTypes.func.isRequired, selectIndexerSchema: PropTypes.func.isRequired, setIndexerSchemaSort: PropTypes.func.isRequired, - onModalClose: PropTypes.func.isRequired + onModalClose: PropTypes.func.isRequired, + onSelectIndexer: PropTypes.func.isRequired }; export default connect(createMapStateToProps, mapDispatchToProps)(AddIndexerModalContentConnector); diff --git a/frontend/src/Indexer/Index/IndexerIndex.js b/frontend/src/Indexer/Index/IndexerIndex.js index db56c9793..841bc1c00 100644 --- a/frontend/src/Indexer/Index/IndexerIndex.js +++ b/frontend/src/Indexer/Index/IndexerIndex.js @@ -193,11 +193,12 @@ class IndexerIndex extends Component { this.setState({ isAddIndexerModalOpen: true }); }; - onAddIndexerModalClose = ({ indexerSelected = false } = {}) => { - this.setState({ - isAddIndexerModalOpen: false, - isEditIndexerModalOpen: indexerSelected - }); + onAddIndexerModalClose = () => { + this.setState({ isAddIndexerModalOpen: false }); + }; + + onAddIndexerSelectIndexer = () => { + this.setState({ isEditIndexerModalOpen: true }); }; onEditIndexerModalClose = () => { @@ -463,6 +464,7 @@ class IndexerIndex extends Component { <AddIndexerModal isOpen={isAddIndexerModalOpen} onModalClose={this.onAddIndexerModalClose} + onSelectIndexer={this.onAddIndexerSelectIndexer} /> <EditIndexerModalConnector From 1cbf61f4dbd56b2f863d4b77b31f93a000d98ac4 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 17 Jan 2022 19:23:08 -0600 Subject: [PATCH 0322/2320] New: Show definition name on add/edit screen for Cardigann --- frontend/src/Indexer/Edit/EditIndexerModalContent.js | 5 ++++- frontend/src/Store/Selectors/selectSettings.js | 6 ++++++ src/Prowlarr.Api.V1/Indexers/IndexerResource.cs | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/frontend/src/Indexer/Edit/EditIndexerModalContent.js b/frontend/src/Indexer/Edit/EditIndexerModalContent.js index a17c5a040..08a097127 100644 --- a/frontend/src/Indexer/Edit/EditIndexerModalContent.js +++ b/frontend/src/Indexer/Edit/EditIndexerModalContent.js @@ -39,6 +39,7 @@ function EditIndexerModalContent(props) { const { id, implementationName, + definitionName, name, enable, redirect, @@ -50,10 +51,12 @@ function EditIndexerModalContent(props) { priority } = item; + const indexerDisplayName = implementationName === definitionName ? implementationName : `${implementationName} (${definitionName})`; + return ( <ModalContent onModalClose={onModalClose}> <ModalHeader> - {`${id ? translate('EditIndexer') : translate('AddIndexer')} - ${implementationName}`} + {`${id ? translate('EditIndexer') : translate('AddIndexer')} - ${indexerDisplayName}`} </ModalHeader> <ModalBody> diff --git a/frontend/src/Store/Selectors/selectSettings.js b/frontend/src/Store/Selectors/selectSettings.js index 3e30478b7..94eea8e55 100644 --- a/frontend/src/Store/Selectors/selectSettings.js +++ b/frontend/src/Store/Selectors/selectSettings.js @@ -36,6 +36,12 @@ function selectSettings(item, pendingChanges, saveError) { return result; } + if (key === 'definitionName') { + result.definitionName = item[key]; + + return result; + } + const setting = { value: item[key], errors: _.map(_.remove(validationFailures, (failure) => { diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs b/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs index 15808253e..3cd433e29 100644 --- a/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs +++ b/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs @@ -15,6 +15,7 @@ namespace Prowlarr.Api.V1.Indexers public class IndexerResource : ProviderResource<IndexerResource> { public string[] IndexerUrls { get; set; } + public string DefinitionName { get; set; } public string Description { get; set; } public string Language { get; set; } public string Encoding { get; set; } @@ -51,6 +52,8 @@ namespace Prowlarr.Api.V1.Indexers var resource = base.ToResource(definition); + resource.DefinitionName = definition.ImplementationName; + var infoLinkName = definition.ImplementationName; if (definition.Implementation == typeof(Cardigann).Name) @@ -71,6 +74,7 @@ namespace Prowlarr.Api.V1.Indexers } } + resource.DefinitionName = settings.DefinitionFile; infoLinkName = settings.DefinitionFile; } From 76daee3a1b864f461a90b7e494a2e7239976c140 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 17 Jan 2022 19:24:52 -0600 Subject: [PATCH 0323/2320] New: Identify indexers that are already setup in add list --- .../src/Indexer/Add/AddIndexerModalContent.js | 4 ++-- frontend/src/Indexer/Add/SelectIndexerRow.css | 6 ++++++ frontend/src/Indexer/Add/SelectIndexerRow.js | 18 ++++++++++++++++-- .../Indexer/Add/SelectIndexerRowConnector.js | 18 ++++++++++++++++++ .../Selectors/createExclusionMovieSelector.js | 14 -------------- .../Selectors/createExistingIndexerSelector.js | 15 +++++++++++++++ src/NzbDrone.Core/Localization/Core/en.json | 1 + 7 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 frontend/src/Indexer/Add/SelectIndexerRowConnector.js delete mode 100644 frontend/src/Store/Selectors/createExclusionMovieSelector.js create mode 100644 frontend/src/Store/Selectors/createExistingIndexerSelector.js diff --git a/frontend/src/Indexer/Add/AddIndexerModalContent.js b/frontend/src/Indexer/Add/AddIndexerModalContent.js index 5255a4e7c..253703d5d 100644 --- a/frontend/src/Indexer/Add/AddIndexerModalContent.js +++ b/frontend/src/Indexer/Add/AddIndexerModalContent.js @@ -15,7 +15,7 @@ import TableBody from 'Components/Table/TableBody'; import { kinds, scrollDirections } from 'Helpers/Props'; import getErrorMessage from 'Utilities/Object/getErrorMessage'; import translate from 'Utilities/String/translate'; -import SelectIndexerRow from './SelectIndexerRow'; +import SelectIndexerRowConnector from './SelectIndexerRowConnector'; import styles from './AddIndexerModalContent.css'; const columns = [ @@ -219,7 +219,7 @@ class AddIndexerModalContent extends Component { <TableBody> { filteredIndexers.map((indexer) => ( - <SelectIndexerRow + <SelectIndexerRowConnector key={indexer.name} implementation={indexer.implementation} {...indexer} diff --git a/frontend/src/Indexer/Add/SelectIndexerRow.css b/frontend/src/Indexer/Add/SelectIndexerRow.css index b5e99d910..071e264c9 100644 --- a/frontend/src/Indexer/Add/SelectIndexerRow.css +++ b/frontend/src/Indexer/Add/SelectIndexerRow.css @@ -3,3 +3,9 @@ width: 32px; } + +.alreadyExistsIcon { + margin-left: 10px; + color: #37bc9b; + pointer-events: all; +} diff --git a/frontend/src/Indexer/Add/SelectIndexerRow.js b/frontend/src/Indexer/Add/SelectIndexerRow.js index fbf05e927..481f21016 100644 --- a/frontend/src/Indexer/Add/SelectIndexerRow.js +++ b/frontend/src/Indexer/Add/SelectIndexerRow.js @@ -1,7 +1,9 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; +import Icon from 'Components/Icon'; import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableRowButton from 'Components/Table/TableRowButton'; +import { icons } from 'Helpers/Props'; import ProtocolLabel from 'Indexer/Index/Table/ProtocolLabel'; import firstCharToUpper from 'Utilities/String/firstCharToUpper'; import translate from 'Utilities/String/translate'; @@ -29,7 +31,8 @@ class SelectIndexerRow extends Component { protocol, privacy, name, - language + language, + isExistingIndexer } = this.props; return ( @@ -42,6 +45,16 @@ class SelectIndexerRow extends Component { <TableRowCell> {name} + { + isExistingIndexer ? + <Icon + className={styles.alreadyExistsIcon} + name={icons.CHECK_CIRCLE} + size={15} + title={translate('IndexerAlreadySetup')} + /> : + null + } </TableRowCell> <TableRowCell> @@ -62,7 +75,8 @@ SelectIndexerRow.propTypes = { privacy: PropTypes.string.isRequired, language: PropTypes.string.isRequired, implementation: PropTypes.string.isRequired, - onIndexerSelect: PropTypes.func.isRequired + onIndexerSelect: PropTypes.func.isRequired, + isExistingIndexer: PropTypes.bool.isRequired }; export default SelectIndexerRow; diff --git a/frontend/src/Indexer/Add/SelectIndexerRowConnector.js b/frontend/src/Indexer/Add/SelectIndexerRowConnector.js new file mode 100644 index 000000000..f507689c8 --- /dev/null +++ b/frontend/src/Indexer/Add/SelectIndexerRowConnector.js @@ -0,0 +1,18 @@ + +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import createExistingIndexerSelector from 'Store/Selectors/createExistingIndexerSelector'; +import SelectIndexerRow from './SelectIndexerRow'; + +function createMapStateToProps() { + return createSelector( + createExistingIndexerSelector(), + (isExistingIndexer, dimensions) => { + return { + isExistingIndexer + }; + } + ); +} + +export default connect(createMapStateToProps)(SelectIndexerRow); diff --git a/frontend/src/Store/Selectors/createExclusionMovieSelector.js b/frontend/src/Store/Selectors/createExclusionMovieSelector.js deleted file mode 100644 index 20365e9b5..000000000 --- a/frontend/src/Store/Selectors/createExclusionMovieSelector.js +++ /dev/null @@ -1,14 +0,0 @@ -import _ from 'lodash'; -import { createSelector } from 'reselect'; - -function createExclusionMovieSelector() { - return createSelector( - (state, { tmdbId }) => tmdbId, - (state) => state.settings.importExclusions, - (tmdbId, importExclusions) => { - return _.some(importExclusions.items, { tmdbId }); - } - ); -} - -export default createExclusionMovieSelector; diff --git a/frontend/src/Store/Selectors/createExistingIndexerSelector.js b/frontend/src/Store/Selectors/createExistingIndexerSelector.js new file mode 100644 index 000000000..af16973b7 --- /dev/null +++ b/frontend/src/Store/Selectors/createExistingIndexerSelector.js @@ -0,0 +1,15 @@ +import _ from 'lodash'; +import { createSelector } from 'reselect'; +import createAllIndexersSelector from './createAllIndexersSelector'; + +function createExistingIndexerSelector() { + return createSelector( + (state, { definitionName }) => definitionName, + createAllIndexersSelector(), + (definitionName, indexers) => { + return _.some(indexers, { definitionName }); + } + ); +} + +export default createExistingIndexerSelector; diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 3e09bea17..2360e55a5 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -169,6 +169,7 @@ "IllRestartLater": "I'll restart later", "IncludeHealthWarningsHelpText": "Include Health Warnings", "Indexer": "Indexer", + "IndexerAlreadySetup": "At least one instace of indexer is already setup", "IndexerAuth": "Indexer Auth", "IndexerFlags": "Indexer Flags", "IndexerHealthCheckNoIndexers": "No indexers enabled, Prowlarr will not return search results", From fa626a53e6f3db04d2aab05f85b4a4586379a5e7 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 17 Jan 2022 21:27:22 -0600 Subject: [PATCH 0324/2320] Fixed: Smarter Int normalization Fixes #787 --- .../ParserTests/ParseUtilFixture.cs | 18 +++++++++++++ src/NzbDrone.Core/Parser/ParseUtil.cs | 26 ++++++++++++++----- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/NzbDrone.Core.Test/ParserTests/ParseUtilFixture.cs b/src/NzbDrone.Core.Test/ParserTests/ParseUtilFixture.cs index 5766c0b40..24449ed7d 100644 --- a/src/NzbDrone.Core.Test/ParserTests/ParseUtilFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/ParseUtilFixture.cs @@ -30,9 +30,27 @@ namespace NzbDrone.Core.Test.ParserTests [TestCase("1", 1)] [TestCase("11", 11)] [TestCase("1000 grabs", 1000)] + [TestCase("2.222", 2222)] + [TestCase("2,222", 2222)] + [TestCase("2 222", 2222)] + [TestCase("2,22", 222)] public void should_parse_int_from_string(string original, int parsedInt) { ParseUtil.CoerceInt(original).Should().Be(parsedInt); } + + [TestCase("1.0", 1.0)] + [TestCase("1.1", 1.1)] + [TestCase("1000 grabs", 1000.0)] + [TestCase("2.222", 2.222)] + [TestCase("2,222", 2.222)] + [TestCase("2.222,22", 2222.22)] + [TestCase("2,222.22", 2222.22)] + [TestCase("2 222", 2222.0)] + [TestCase("2,22", 2.22)] + public void should_parse_double_from_string(string original, double parsedInt) + { + ParseUtil.CoerceDouble(original).Should().Be(parsedInt); + } } } diff --git a/src/NzbDrone.Core/Parser/ParseUtil.cs b/src/NzbDrone.Core/Parser/ParseUtil.cs index e1f7fe8c6..f8cbc7bbc 100644 --- a/src/NzbDrone.Core/Parser/ParseUtil.cs +++ b/src/NzbDrone.Core/Parser/ParseUtil.cs @@ -16,14 +16,26 @@ namespace NzbDrone.Core.Parser public static string NormalizeMultiSpaces(string s) => new Regex(@"\s+").Replace(s.Trim(), " "); - private static string NormalizeNumber(string s) + private static string NormalizeNumber(string s, bool isInt = false) { var valStr = new string(s.Where(c => char.IsDigit(c) || c == '.' || c == ',').ToArray()); - valStr = (valStr.Length == 0) ? "0" : valStr.Replace(",", "."); - valStr = valStr.Trim().Replace("-", "0"); + if (isInt) + { + if (valStr.Contains(',') && valStr.Contains('.')) + { + return valStr; + } + + valStr = (valStr.Length == 0) ? "0" : valStr.Replace(".", ","); + + return valStr; + } + + valStr = (valStr.Length == 0) ? "0" : valStr.Replace(",", "."); + if (valStr.Count(c => c == '.') > 1) { var lastOcc = valStr.LastIndexOf('.'); @@ -39,17 +51,17 @@ namespace NzbDrone.Core.Parser public static float CoerceFloat(string str) => float.Parse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture); - public static int CoerceInt(string str) => int.Parse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture); + public static int CoerceInt(string str) => int.Parse(NormalizeNumber(str, true), NumberStyles.Any, CultureInfo.InvariantCulture); - public static long CoerceLong(string str) => long.Parse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture); + public static long CoerceLong(string str) => long.Parse(NormalizeNumber(str, true), NumberStyles.Any, CultureInfo.InvariantCulture); public static bool TryCoerceDouble(string str, out double result) => double.TryParse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture, out result); public static bool TryCoerceFloat(string str, out float result) => float.TryParse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture, out result); - public static bool TryCoerceInt(string str, out int result) => int.TryParse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture, out result); + public static bool TryCoerceInt(string str, out int result) => int.TryParse(NormalizeNumber(str, true), NumberStyles.Any, CultureInfo.InvariantCulture, out result); - public static bool TryCoerceLong(string str, out long result) => long.TryParse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture, out result); + public static bool TryCoerceLong(string str, out long result) => long.TryParse(NormalizeNumber(str, true), NumberStyles.Any, CultureInfo.InvariantCulture, out result); public static long? GetLongFromString(string str) { From 3c3272cb251ee9db891fea244456d4b1fa7bedf4 Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Tue, 18 Jan 2022 03:33:19 +0000 Subject: [PATCH 0325/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index 5978cc42a..019947d3c 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -5438,6 +5438,10 @@ }, "nullable": true }, + "definitionName": { + "type": "string", + "nullable": true + }, "description": { "type": "string", "nullable": true From 97f4a2e651b2f716e282cd5b6da85fae6e999615 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 18 Jan 2022 19:56:17 -0600 Subject: [PATCH 0326/2320] Fixed: Use rolling 24 hours for indexer limits Fixes #789 --- src/NzbDrone.Core/Indexers/IndexerLimitService.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/IndexerLimitService.cs b/src/NzbDrone.Core/Indexers/IndexerLimitService.cs index 4fa742612..35cb5d6f8 100644 --- a/src/NzbDrone.Core/Indexers/IndexerLimitService.cs +++ b/src/NzbDrone.Core/Indexers/IndexerLimitService.cs @@ -28,17 +28,17 @@ namespace NzbDrone.Core.Indexers { if (indexer.Id > 0 && ((IIndexerSettings)indexer.Settings).BaseSettings.GrabLimit.HasValue) { - var grabCount = _historyService.CountSince(indexer.Id, DateTime.Now.StartOfDay(), new List<HistoryEventType> { HistoryEventType.ReleaseGrabbed }); + var grabCount = _historyService.CountSince(indexer.Id, DateTime.Now.AddHours(-24), new List<HistoryEventType> { HistoryEventType.ReleaseGrabbed }); var grabLimit = ((IIndexerSettings)indexer.Settings).BaseSettings.QueryLimit; if (grabCount > grabLimit) { - _logger.Info("Indexer {0} has exceeded maximum grab limit for today", indexer.Name); + _logger.Info("Indexer {0} has exceeded maximum grab limit for last 24 hours", indexer.Name); return true; } - _logger.Debug("Indexer {0} has performed {1} of possible {2} grabs for today, proceeding", indexer.Name, grabCount, grabLimit); + _logger.Debug("Indexer {0} has performed {1} of possible {2} grabs in last 24 hours, proceeding", indexer.Name, grabCount, grabLimit); } return false; @@ -48,17 +48,17 @@ namespace NzbDrone.Core.Indexers { if (indexer.Id > 0 && ((IIndexerSettings)indexer.Settings).BaseSettings.QueryLimit.HasValue) { - var queryCount = _historyService.CountSince(indexer.Id, DateTime.Now.StartOfDay(), new List<HistoryEventType> { HistoryEventType.IndexerQuery, HistoryEventType.IndexerRss }); + var queryCount = _historyService.CountSince(indexer.Id, DateTime.Now.AddHours(-24), new List<HistoryEventType> { HistoryEventType.IndexerQuery, HistoryEventType.IndexerRss }); var queryLimit = ((IIndexerSettings)indexer.Settings).BaseSettings.QueryLimit; if (queryCount > queryLimit) { - _logger.Info("Indexer {0} has exceeded maximum query limit for today", indexer.Name); + _logger.Info("Indexer {0} has exceeded maximum query limit for last 24 hours", indexer.Name); return true; } - _logger.Debug("Indexer {0} has performed {1} of possible {2} queries for today, proceeding", indexer.Name, queryCount, queryLimit); + _logger.Debug("Indexer {0} has performed {1} of possible {2} queries in last 24 hours, proceeding", indexer.Name, queryCount, queryLimit); } return false; From 8701e67b1e09c252c43b9b3e8cf4ba5d9798a980 Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Sun, 16 Jan 2022 22:00:47 +0000 Subject: [PATCH 0327/2320] Fixed: Close all database connections on shutdown --- src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs | 2 +- src/NzbDrone.Host/AppLifetime.cs | 3 +++ src/NzbDrone.Host/Bootstrap.cs | 6 ++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs b/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs index 72ca2da08..04e08cf81 100644 --- a/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs +++ b/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs @@ -128,7 +128,7 @@ namespace NzbDrone.Core.Instrumentation private void WriteSqliteLog(Log log, string connectionString) { using (var connection = - SQLiteFactory.Instance.CreateConnection()) + new SQLiteConnection(_connectionStringFactory.LogDbConnectionString).OpenAndReturn()) { connection.ConnectionString = connectionString; connection.Open(); diff --git a/src/NzbDrone.Host/AppLifetime.cs b/src/NzbDrone.Host/AppLifetime.cs index 17f5bbcdc..c1a56242d 100644 --- a/src/NzbDrone.Host/AppLifetime.cs +++ b/src/NzbDrone.Host/AppLifetime.cs @@ -1,3 +1,4 @@ +using System.Data.SQLite; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; @@ -6,6 +7,7 @@ using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Processes; using NzbDrone.Core.Configuration; using NzbDrone.Core.Lifecycle; +using NzbDrone.Core.Messaging; using NzbDrone.Core.Messaging.Events; namespace NzbDrone.Host @@ -99,6 +101,7 @@ namespace NzbDrone.Host return args; } + [EventHandleOrder(EventHandleOrder.Last)] public void Handle(ApplicationShutdownRequested message) { if (!_runtimeInfo.IsWindowsService) diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index 27c129fb7..4b3717c11 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data.SQLite; using System.Diagnostics; using System.IO; using System.Reflection; @@ -99,6 +100,11 @@ namespace NzbDrone.Host Logger.Info(e.Message); LogManager.Configuration = null; } + + // Make sure there are no lingering database connections + GC.Collect(); + GC.WaitForPendingFinalizers(); + SQLiteConnection.ClearAllPools(); } public static IHostBuilder CreateConsoleHostBuilder(string[] args, StartupContext context) From e480f53f7f0f22df0b19904dae938d3f850c9ee5 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 18 Jan 2022 20:17:01 -0600 Subject: [PATCH 0328/2320] More mono cleaning --- .../Http/Dispatchers/ManagedHttpDispatcher.cs | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs index 3fa5657c1..1be10eb56 100644 --- a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs +++ b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs @@ -82,9 +82,6 @@ namespace NzbDrone.Common.Http.Dispatchers if (httpWebResponse == null) { - // Workaround for mono not closing connections properly in certain situations. - AbortWebRequest(webRequest); - // The default messages for WebException on mono are pretty horrible. if (e.Status == WebExceptionStatus.NameResolutionFailure) { @@ -242,36 +239,5 @@ namespace NzbDrone.Common.Http.Dispatchers } } } - - // Workaround for mono not closing connections properly on timeouts - private void AbortWebRequest(HttpWebRequest webRequest) - { - // First affected version was mono 5.16 - if (OsInfo.IsNotWindows && _platformInfo.Version >= new Version(5, 16)) - { - try - { - var currentOperationInfo = webRequest.GetType().GetField("currentOperation", BindingFlags.NonPublic | BindingFlags.Instance); - var currentOperation = currentOperationInfo.GetValue(webRequest); - - if (currentOperation != null) - { - var responseStreamInfo = currentOperation.GetType().GetField("responseStream", BindingFlags.NonPublic | BindingFlags.Instance); - var responseStream = responseStreamInfo.GetValue(currentOperation) as Stream; - - // Note that responseStream will likely be null once mono fixes it. - responseStream?.Dispose(); - } - } - catch (Exception ex) - { - // This can fail randomly on future mono versions that have been changed/fixed. Log to sentry and ignore. - _logger.Trace() - .Exception(ex) - .Message("Unable to dispose responseStream on mono {0}", _platformInfo.Version) - .Write(); - } - } - } } } From 2da22c08b0d1ec8e5d46ab12f8498245f6463034 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 18 Jan 2022 21:06:12 -0600 Subject: [PATCH 0329/2320] Fixed: Log DB write connection opening --- src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs b/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs index 04e08cf81..ecd41cceb 100644 --- a/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs +++ b/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs @@ -128,10 +128,8 @@ namespace NzbDrone.Core.Instrumentation private void WriteSqliteLog(Log log, string connectionString) { using (var connection = - new SQLiteConnection(_connectionStringFactory.LogDbConnectionString).OpenAndReturn()) + new SQLiteConnection(connectionString).OpenAndReturn()) { - connection.ConnectionString = connectionString; - connection.Open(); using (var sqlCommand = connection.CreateCommand()) { sqlCommand.CommandText = INSERT_COMMAND; From c9951e7eba3a70d1a9203410f6fcdeaf18dcb883 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 18 Jan 2022 23:29:30 -0600 Subject: [PATCH 0330/2320] New: Add AppName to system status response --- src/Prowlarr.Api.V1/System/SystemController.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Prowlarr.Api.V1/System/SystemController.cs b/src/Prowlarr.Api.V1/System/SystemController.cs index 66d058b71..387ffd5c6 100644 --- a/src/Prowlarr.Api.V1/System/SystemController.cs +++ b/src/Prowlarr.Api.V1/System/SystemController.cs @@ -58,6 +58,7 @@ namespace Prowlarr.Api.V1.System { return new { + AppName = BuildInfo.AppName, Version = BuildInfo.Version.ToString(), BuildTime = BuildInfo.BuildDateTime, IsDebug = BuildInfo.IsDebug, From 62f6670a212b282a42beab2aa6ec407473d9bf1e Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 20 Jan 2022 23:19:58 -0600 Subject: [PATCH 0331/2320] Optimize Indexer updates --- .../IndexerDefinitionUpdateService.cs | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index dc4c6f2e7..be38c301b 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.Linq; using NLog; using NzbDrone.Common.Cache; @@ -26,6 +27,7 @@ namespace NzbDrone.Core.IndexerVersions { /* Update Service will fall back if version # does not exist for an indexer per Ta */ + private const string DEFINITION_BRANCH = "master"; private const int DEFINITION_VERSION = 3; private readonly List<string> _defintionBlocklist = new List<string>() { @@ -76,7 +78,7 @@ namespace NzbDrone.Core.IndexerVersions try { - var request = new HttpRequest($"https://indexers.prowlarr.com/master/{DEFINITION_VERSION}"); + var request = new HttpRequest($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}"); var response = _httpClient.Get<List<CardigannMetaDefinition>>(request); indexerList = response.Resource.Where(i => !_defintionBlocklist.Contains(i.File)).ToList(); @@ -141,7 +143,7 @@ namespace NzbDrone.Core.IndexerVersions private CardigannDefinition GetHttpDefinition(string id) { - var req = new HttpRequest($"https://indexers.prowlarr.com/master/{DEFINITION_VERSION}/{id}"); + var req = new HttpRequest($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}/{id}"); var response = _httpClient.Get(req); var definition = _deserializer.Deserialize<CardigannDefinition>(response.Content); return CleanIndexerDefinition(definition); @@ -238,29 +240,31 @@ namespace NzbDrone.Core.IndexerVersions private void UpdateLocalDefinitions() { - var request = new HttpRequest($"https://indexers.prowlarr.com/master/{DEFINITION_VERSION}"); - var response = _httpClient.Get<List<CardigannMetaDefinition>>(request); + var startupFolder = _appFolderInfo.AppDataFolder; - foreach (var def in response.Resource) + try { - try + EnsureDefinitionsFolder(); + + var definitionsFolder = Path.Combine(startupFolder, "Definitions"); + var saveFile = Path.Combine(startupFolder, "Definitions", $"indexers.zip"); + + _httpClient.DownloadFile($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}/package.zip", saveFile); + + using (ZipArchive archive = ZipFile.OpenRead(saveFile)) { - var startupFolder = _appFolderInfo.AppDataFolder; - - EnsureDefinitionsFolder(); - - var saveFile = Path.Combine(startupFolder, "Definitions", $"{def.File}.yml"); - - _httpClient.DownloadFile($"https://indexers.prowlarr.com/master/{DEFINITION_VERSION}/{def.File}", saveFile); - - _cache.Remove(def.File); - - _logger.Debug("Updated definition: {0}", def.File); - } - catch (Exception ex) - { - _logger.Error("Definition download failed: {0}, {1}", def.File, ex.Message); + archive.ExtractToDirectory(definitionsFolder, true); } + + _diskProvider.DeleteFile(saveFile); + + _cache.Clear(); + + _logger.Debug("Updated indexer definitions"); + } + catch (Exception ex) + { + _logger.Error(ex, "Definition update failed"); } } } From ae5d93d6dd4a0b1771466582af2c15d3451b95c4 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 23 Jan 2022 19:34:54 -0600 Subject: [PATCH 0332/2320] Revert "Remove extra replacing (already done by Uri.EscapeDataString)" This reverts commit 6880f3863593244249bb0763ccf0d55d4240ed73. --- .../Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 3b141f36a..0ca06a2d4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -1013,7 +1013,7 @@ namespace NzbDrone.Core.Indexers.Cardigann // build search URL // HttpUtility.UrlPathEncode seems to only encode spaces, we use UrlEncode and replace + with %20 as a workaround - var searchUrl = ResolvePath(ApplyGoTemplateText(searchPath.Path, variables, Uri.EscapeDataString)).AbsoluteUri; + var searchUrl = ResolvePath(ApplyGoTemplateText(searchPath.Path, variables, Uri.EscapeDataString).Replace("+", "%20")).AbsoluteUri; var queryCollection = new List<KeyValuePair<string, string>>(); var method = HttpMethod.Get; From 5b5c186d0ce640d1c3dd829b4f7ca153faa81943 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 23 Jan 2022 19:34:59 -0600 Subject: [PATCH 0333/2320] Revert "Replace WebUtility.UrlEncode to Uri.EscapeDataString " This reverts commit a7b1ef19f57b8182c2ec3b105fe17d770add33d3. --- src/NzbDrone.Core/Download/DownloadMappingService.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs | 2 +- .../Definitions/Cardigann/CardigannRequestGenerator.cs | 4 ++-- src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Download/DownloadMappingService.cs b/src/NzbDrone.Core/Download/DownloadMappingService.cs index 812087c47..a3dbcc539 100644 --- a/src/NzbDrone.Core/Download/DownloadMappingService.cs +++ b/src/NzbDrone.Core/Download/DownloadMappingService.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Core.Download var encryptedLink = _protectionService.Protect(link.ToString()); var encodedLink = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(encryptedLink)); - var urlEncodedFile = Uri.EscapeDataString(file); + var urlEncodedFile = WebUtility.UrlEncode(file); var proxyLink = $"{serverUrl}{urlBase}/{indexerId}/download?apikey={_configFileProvider.ApiKey}&link={encodedLink}&file={urlEncodedFile}"; return new Uri(proxyLink); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs index 20824838d..8595a16d1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs @@ -184,7 +184,7 @@ namespace NzbDrone.Core.Indexers.Definitions searchString = match.Value; } - var episodeSearchUrl = searchUrl + Uri.EscapeDataString(searchString); + var episodeSearchUrl = searchUrl + WebUtility.UrlEncode(searchString); var request = new IndexerRequest(episodeSearchUrl, null); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 0ca06a2d4..2622142cd 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -1013,7 +1013,7 @@ namespace NzbDrone.Core.Indexers.Cardigann // build search URL // HttpUtility.UrlPathEncode seems to only encode spaces, we use UrlEncode and replace + with %20 as a workaround - var searchUrl = ResolvePath(ApplyGoTemplateText(searchPath.Path, variables, Uri.EscapeDataString).Replace("+", "%20")).AbsoluteUri; + var searchUrl = ResolvePath(ApplyGoTemplateText(searchPath.Path, variables, WebUtility.UrlEncode).Replace("+", "%20")).AbsoluteUri; var queryCollection = new List<KeyValuePair<string, string>>(); var method = HttpMethod.Get; @@ -1038,7 +1038,7 @@ namespace NzbDrone.Core.Indexers.Cardigann { if (input.Key == "$raw") { - var rawStr = ApplyGoTemplateText(input.Value, variables, Uri.EscapeDataString); + var rawStr = ApplyGoTemplateText(input.Value, variables, WebUtility.UrlEncode); foreach (var part in rawStr.Split('&')) { var parts = part.Split(new char[] { '=' }, 2); diff --git a/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs b/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs index c8a8cb0ab..59d3bb07d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs @@ -174,7 +174,7 @@ namespace NzbDrone.Core.Indexers.Definitions if (term.IsNotNullOrWhiteSpace()) { - searchUrl += string.Format("?do=search&keywords={0}&search_type=t_name&category=0&include_dead_torrents=no", Uri.EscapeDataString(term)); + searchUrl += string.Format("?do=search&keywords={0}&search_type=t_name&category=0&include_dead_torrents=no", WebUtility.UrlEncode(term)); } if (categories != null && categories.Length > 0) diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs index 8da22b1a8..065ab7481 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs @@ -192,7 +192,7 @@ namespace NzbDrone.Core.Indexers.Definitions } else if (!string.IsNullOrWhiteSpace(searchString)) { - searchUrl += "exact/1/query/" + Uri.EscapeDataString(searchString) + "/"; + searchUrl += "exact/1/query/" + WebUtility.UrlEncode(searchString) + "/"; } var cats = Capabilities.Categories.MapTorznabCapsToTrackers(categories); From 7388655e6d6667dcc1d9dfaf56bcd9cbed2d6e54 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 23 Jan 2022 19:41:20 -0600 Subject: [PATCH 0334/2320] Fixed: ToString() to AbsoluteUri for MagnetUrls as well --- src/Prowlarr.Api.V1/Indexers/NewznabController.cs | 2 +- src/Prowlarr.Api.V1/Search/SearchController.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Prowlarr.Api.V1/Indexers/NewznabController.cs b/src/Prowlarr.Api.V1/Indexers/NewznabController.cs index 6160ed0a7..f2c111c75 100644 --- a/src/Prowlarr.Api.V1/Indexers/NewznabController.cs +++ b/src/Prowlarr.Api.V1/Indexers/NewznabController.cs @@ -152,7 +152,7 @@ namespace NzbDrone.Api.V1.Indexers if (result.DownloadProtocol == DownloadProtocol.Torrent) { - ((TorrentInfo)result).MagnetUrl = ((TorrentInfo)result).MagnetUrl.IsNotNullOrWhiteSpace() ? _downloadMappingService.ConvertToProxyLink(new Uri(((TorrentInfo)result).MagnetUrl), request.server, indexerDef.Id, result.Title).ToString() : null; + ((TorrentInfo)result).MagnetUrl = ((TorrentInfo)result).MagnetUrl.IsNotNullOrWhiteSpace() ? _downloadMappingService.ConvertToProxyLink(new Uri(((TorrentInfo)result).MagnetUrl), request.server, indexerDef.Id, result.Title).AbsoluteUri : null; } } diff --git a/src/Prowlarr.Api.V1/Search/SearchController.cs b/src/Prowlarr.Api.V1/Search/SearchController.cs index dfa2fcc80..836bfdaca 100644 --- a/src/Prowlarr.Api.V1/Search/SearchController.cs +++ b/src/Prowlarr.Api.V1/Search/SearchController.cs @@ -163,7 +163,7 @@ namespace Prowlarr.Api.V1.Search _remoteReleaseCache.Set(GetCacheKey(release), downloadDecision, TimeSpan.FromMinutes(30)); release.DownloadUrl = release.DownloadUrl.IsNotNullOrWhiteSpace() ? _downloadMappingService.ConvertToProxyLink(new Uri(release.DownloadUrl), serverUrl, release.IndexerId, release.Title).AbsoluteUri : null; - release.MagnetUrl = release.MagnetUrl.IsNotNullOrWhiteSpace() ? _downloadMappingService.ConvertToProxyLink(new Uri(release.MagnetUrl), serverUrl, release.IndexerId, release.Title).ToString() : null; + release.MagnetUrl = release.MagnetUrl.IsNotNullOrWhiteSpace() ? _downloadMappingService.ConvertToProxyLink(new Uri(release.MagnetUrl), serverUrl, release.IndexerId, release.Title).AbsoluteUri : null; result.Add(release); } From c46ed33544310dec3ada35eff6cf156a040287a7 Mon Sep 17 00:00:00 2001 From: Zippy79 <paul+github@paulthomas.jp> Date: Tue, 25 Jan 2022 20:36:24 +0900 Subject: [PATCH 0335/2320] Fixed: Download limit check was using the query limit instead of the grab limit. --- src/NzbDrone.Core/Indexers/IndexerLimitService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/IndexerLimitService.cs b/src/NzbDrone.Core/Indexers/IndexerLimitService.cs index 35cb5d6f8..9c3087d18 100644 --- a/src/NzbDrone.Core/Indexers/IndexerLimitService.cs +++ b/src/NzbDrone.Core/Indexers/IndexerLimitService.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Indexers if (indexer.Id > 0 && ((IIndexerSettings)indexer.Settings).BaseSettings.GrabLimit.HasValue) { var grabCount = _historyService.CountSince(indexer.Id, DateTime.Now.AddHours(-24), new List<HistoryEventType> { HistoryEventType.ReleaseGrabbed }); - var grabLimit = ((IIndexerSettings)indexer.Settings).BaseSettings.QueryLimit; + var grabLimit = ((IIndexerSettings)indexer.Settings).BaseSettings.GrabLimit; if (grabCount > grabLimit) { From 22161e6d57ed2c98340e9a07f8dcf9db5c97c7f4 Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Tue, 25 Jan 2022 23:03:15 +0000 Subject: [PATCH 0336/2320] Fixed: Added missing translate for Database --- src/NzbDrone.Core/Localization/Core/en.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 2360e55a5..202f4b46e 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -85,6 +85,7 @@ "CouldNotConnectSignalR": "Could not connect to SignalR, UI won't update", "Custom": "Custom", "CustomFilters": "Custom Filters", + "Database": "Database", "Date": "Date", "Dates": "Dates", "DBMigration": "DB Migration", From a3de574de5faad53b8792a5aab48bd2d2c11c3c2 Mon Sep 17 00:00:00 2001 From: PearsonFlyer <PearsonFlyer@github.com> Date: Wed, 26 Jan 2022 10:50:25 -0500 Subject: [PATCH 0337/2320] Fixed: Updated ruTorrent stopped state helptext --- src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentSettings.cs b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentSettings.cs index 0fad0741e..73fbd43bf 100644 --- a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentSettings.cs +++ b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentSettings.cs @@ -57,7 +57,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent [FieldDefinition(8, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(RTorrentPriority), HelpText = "Priority to use when grabbing items")] public int Priority { get; set; } - [FieldDefinition(9, Label = "Add Stopped", Type = FieldType.Checkbox, HelpText = "Enabling will prevent magnets from downloading before downloading")] + [FieldDefinition(9, Label = "Add Stopped", Type = FieldType.Checkbox, HelpText = "Enabling will add torrents and magnets to ruTorrent in a stopped state")] public bool AddStopped { get; set; } public NzbDroneValidationResult Validate() From 17608cf91558db05b0f529fb09ad62f4dfe6ca1d Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 30 Jan 2022 18:49:58 -0600 Subject: [PATCH 0338/2320] Misc definition handling improvements --- .../Indexer/Index/Table/IndexerIndexRow.js | 19 +- .../Migration/015_indexer_versions.cs | 18 ++ src/NzbDrone.Core/Datastore/TableMapping.cs | 2 + .../HealthCheck/Checks/NoDefinitionCheck.cs | 48 +++++ .../Checks/OutdatedDefinitionCheck.cs | 9 +- .../IndexerDefinitionUpdateService.cs | 169 +++++++++++------- .../IndexerDefinitionVersion.cs | 13 ++ .../IndexerDefinitionVersionRepository.cs | 25 +++ .../IndexerDefinitionVersionService.cs | 66 +++++++ .../Definitions/Cardigann/Cardigann.cs | 4 +- src/NzbDrone.Core/Indexers/IndexerFactory.cs | 4 +- src/NzbDrone.Core/Localization/Core/en.json | 1 + .../Indexers/IndexerResource.cs | 2 +- 13 files changed, 302 insertions(+), 78 deletions(-) create mode 100644 src/NzbDrone.Core/Datastore/Migration/015_indexer_versions.cs create mode 100644 src/NzbDrone.Core/HealthCheck/Checks/NoDefinitionCheck.cs create mode 100644 src/NzbDrone.Core/IndexerVersions/IndexerDefinitionVersion.cs create mode 100644 src/NzbDrone.Core/IndexerVersions/IndexerDefinitionVersionRepository.cs create mode 100644 src/NzbDrone.Core/IndexerVersions/IndexerDefinitionVersionService.cs diff --git a/frontend/src/Indexer/Index/Table/IndexerIndexRow.js b/frontend/src/Indexer/Index/Table/IndexerIndexRow.js index fa802e254..fda726182 100644 --- a/frontend/src/Indexer/Index/Table/IndexerIndexRow.js +++ b/frontend/src/Indexer/Index/Table/IndexerIndexRow.js @@ -244,12 +244,15 @@ class IndexerIndexRow extends Component { onPress={this.onIndexerInfoPress} /> - <IconButton - className={styles.externalLink} - name={icons.EXTERNAL_LINK} - title={translate('Website')} - to={indexerUrls[0].replace('api.', '')} - /> + { + indexerUrls ? + <IconButton + className={styles.externalLink} + name={icons.EXTERNAL_LINK} + title={translate('Website')} + to={indexerUrls[0].replace('api.', '')} + /> : null + } <IconButton name={icons.EDIT} @@ -289,7 +292,7 @@ class IndexerIndexRow extends Component { IndexerIndexRow.propTypes = { id: PropTypes.number.isRequired, - indexerUrls: PropTypes.arrayOf(PropTypes.string).isRequired, + indexerUrls: PropTypes.arrayOf(PropTypes.string), protocol: PropTypes.string.isRequired, privacy: PropTypes.string.isRequired, priority: PropTypes.number.isRequired, @@ -298,7 +301,7 @@ IndexerIndexRow.propTypes = { redirect: PropTypes.bool.isRequired, appProfile: PropTypes.object.isRequired, status: PropTypes.object, - capabilities: PropTypes.object.isRequired, + capabilities: PropTypes.object, added: PropTypes.string.isRequired, tags: PropTypes.arrayOf(PropTypes.number).isRequired, columns: PropTypes.arrayOf(PropTypes.object).isRequired, diff --git a/src/NzbDrone.Core/Datastore/Migration/015_indexer_versions.cs b/src/NzbDrone.Core/Datastore/Migration/015_indexer_versions.cs new file mode 100644 index 000000000..d75d7f05d --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/015_indexer_versions.cs @@ -0,0 +1,18 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(15)] + public class IndexerVersions : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Create.TableForModel("IndexerDefinitionVersions") + .WithColumn("DefinitionId").AsString().NotNullable().Unique() + .WithColumn("File").AsString().NotNullable().Unique() + .WithColumn("Sha").AsString().Nullable() + .WithColumn("LastUpdated").AsDateTime().Nullable(); + } + } +} diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index 7942732d6..685b7fb22 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -11,6 +11,7 @@ using NzbDrone.Core.Datastore.Converters; using NzbDrone.Core.Download; using NzbDrone.Core.IndexerProxies; using NzbDrone.Core.Indexers; +using NzbDrone.Core.IndexerVersions; using NzbDrone.Core.Instrumentation; using NzbDrone.Core.Jobs; using NzbDrone.Core.Languages; @@ -94,6 +95,7 @@ namespace NzbDrone.Core.Datastore Mapper.Entity<UpdateHistory>("UpdateHistory").RegisterModel(); Mapper.Entity<AppSyncProfile>("AppSyncProfiles").RegisterModel(); + Mapper.Entity<IndexerDefinitionVersion>("IndexerDefinitionVersions").RegisterModel(); } private static void RegisterMappers() diff --git a/src/NzbDrone.Core/HealthCheck/Checks/NoDefinitionCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/NoDefinitionCheck.cs new file mode 100644 index 000000000..24c49c41d --- /dev/null +++ b/src/NzbDrone.Core/HealthCheck/Checks/NoDefinitionCheck.cs @@ -0,0 +1,48 @@ +using System.Linq; +using NLog; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Indexers.Cardigann; +using NzbDrone.Core.IndexerVersions; +using NzbDrone.Core.Localization; +using NzbDrone.Core.ThingiProvider.Events; + +namespace NzbDrone.Core.HealthCheck.Checks +{ + [CheckOn(typeof(ProviderDeletedEvent<IIndexer>))] + public class NoDefinitionCheck : HealthCheckBase + { + private readonly IIndexerDefinitionUpdateService _indexerDefinitionUpdateService; + private readonly IIndexerFactory _indexerFactory; + + public NoDefinitionCheck(IIndexerDefinitionUpdateService indexerDefinitionUpdateService, IIndexerFactory indexerFactory, ILocalizationService localizationService) + : base(localizationService) + { + _indexerDefinitionUpdateService = indexerDefinitionUpdateService; + _indexerFactory = indexerFactory; + } + + public override HealthCheck Check() + { + var currentDefs = _indexerDefinitionUpdateService.All(); + + var noDefIndexers = _indexerFactory.AllProviders(false) + .Where(i => i.Definition.Implementation == "Cardigann" && !currentDefs.Any(d => d.File == ((CardigannSettings)i.Definition.Settings).DefinitionFile)).ToList(); + + if (noDefIndexers.Count == 0) + { + return new HealthCheck(GetType()); + } + + var healthType = HealthCheckResult.Error; + var healthMessage = string.Format(_localizationService.GetLocalizedString("IndexerNoDefCheckMessage"), + string.Join(", ", noDefIndexers.Select(v => v.Definition.Name))); + + return new HealthCheck(GetType(), + healthType, + healthMessage, + "#indexers-have-no-definition"); + } + + public override bool CheckOnSchedule => false; + } +} diff --git a/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs index 5fd9ea81d..c45c37db6 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs @@ -35,10 +35,13 @@ namespace NzbDrone.Core.HealthCheck.Checks return new HealthCheck(GetType()); } + var healthType = HealthCheckResult.Warning; + var healthMessage = string.Format(_localizationService.GetLocalizedString("IndexerObsoleteCheckMessage"), + string.Join(", ", oldIndexers.Select(v => v.Definition.Name))); + return new HealthCheck(GetType(), - HealthCheckResult.Warning, - string.Format(_localizationService.GetLocalizedString("IndexerObsoleteCheckMessage"), - string.Join(", ", oldIndexers.Select(v => v.Definition.Name))), + healthType, + healthMessage, "#indexers-are-obsolete"); } diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index be38c301b..72cd5f817 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -1,13 +1,11 @@ using System; using System.Collections.Generic; using System.IO; -using System.IO.Compression; using System.Linq; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; -using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Indexers.Cardigann; using NzbDrone.Core.Messaging.Commands; @@ -19,7 +17,7 @@ namespace NzbDrone.Core.IndexerVersions public interface IIndexerDefinitionUpdateService { List<CardigannMetaDefinition> All(); - CardigannDefinition GetDefinition(string fileKey); + CardigannDefinition GetCachedDefinition(string fileKey); List<string> GetBlocklist(); } @@ -29,6 +27,8 @@ namespace NzbDrone.Core.IndexerVersions private const string DEFINITION_BRANCH = "master"; private const int DEFINITION_VERSION = 3; + + //Used when moving yml to C# private readonly List<string> _defintionBlocklist = new List<string>() { "aither", @@ -51,6 +51,7 @@ namespace NzbDrone.Core.IndexerVersions private readonly IHttpClient _httpClient; private readonly IAppFolderInfo _appFolderInfo; private readonly IDiskProvider _diskProvider; + private readonly IIndexerDefinitionVersionService _versionService; private readonly ICached<CardigannDefinition> _cache; private readonly Logger _logger; @@ -62,11 +63,13 @@ namespace NzbDrone.Core.IndexerVersions public IndexerDefinitionUpdateService(IHttpClient httpClient, IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, + IIndexerDefinitionVersionService versionService, ICacheManager cacheManager, Logger logger) { _appFolderInfo = appFolderInfo; _diskProvider = diskProvider; + _versionService = versionService; _cache = cacheManager.GetCache<CardigannDefinition>(typeof(CardigannDefinition), "definitions"); _httpClient = httpClient; _logger = logger; @@ -78,43 +81,24 @@ namespace NzbDrone.Core.IndexerVersions try { - var request = new HttpRequest($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}"); - var response = _httpClient.Get<List<CardigannMetaDefinition>>(request); - indexerList = response.Resource.Where(i => !_defintionBlocklist.Contains(i.File)).ToList(); - - var definitionFolder = Path.Combine(_appFolderInfo.AppDataFolder, "Definitions", "Custom"); - - var directoryInfo = new DirectoryInfo(definitionFolder); - - if (directoryInfo.Exists) + // Grab latest def list from server or fallback to disk + try { - var files = directoryInfo.GetFiles($"*.yml"); - - foreach (var file in files) - { - _logger.Debug("Loading Custom Cardigann definition " + file.FullName); - - try - { - var definitionString = File.ReadAllText(file.FullName); - var definition = _deserializer.Deserialize<CardigannMetaDefinition>(definitionString); - - definition.File = Path.GetFileNameWithoutExtension(file.Name); - - if (indexerList.Any(i => i.File == definition.File || i.Name == definition.Name)) - { - _logger.Warn("Custom Cardigann definition {0} does not have unique file name or Indexer name", file.FullName); - continue; - } - - indexerList.Add(definition); - } - catch (Exception e) - { - _logger.Error($"Error while parsing custom Cardigann definition {file.FullName}\n{e}"); - } - } + var request = new HttpRequest($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}"); + var response = _httpClient.Get<List<CardigannMetaDefinition>>(request); + indexerList = response.Resource.Where(i => !_defintionBlocklist.Contains(i.File)).ToList(); } + catch + { + var definitionFolder = Path.Combine(_appFolderInfo.AppDataFolder, "Definitions"); + + indexerList = ReadDefinitionsFromDisk(indexerList, definitionFolder); + } + + //Check for custom definitions + var customDefinitionFolder = Path.Combine(_appFolderInfo.AppDataFolder, "Definitions", "Custom"); + + indexerList = ReadDefinitionsFromDisk(indexerList, customDefinitionFolder); } catch { @@ -124,14 +108,14 @@ namespace NzbDrone.Core.IndexerVersions return indexerList; } - public CardigannDefinition GetDefinition(string file) + public CardigannDefinition GetCachedDefinition(string fileKey) { - if (string.IsNullOrEmpty(file)) + if (string.IsNullOrEmpty(fileKey)) { - throw new ArgumentNullException(nameof(file)); + throw new ArgumentNullException(nameof(fileKey)); } - var definition = _cache.Get(file, () => LoadIndexerDef(file)); + var definition = _cache.Get(fileKey, () => GetUncachedDefinition(fileKey)); return definition; } @@ -141,15 +125,46 @@ namespace NzbDrone.Core.IndexerVersions return _defintionBlocklist; } - private CardigannDefinition GetHttpDefinition(string id) + private List<CardigannMetaDefinition> ReadDefinitionsFromDisk(List<CardigannMetaDefinition> defs, string path, SearchOption options = SearchOption.TopDirectoryOnly) { - var req = new HttpRequest($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}/{id}"); - var response = _httpClient.Get(req); - var definition = _deserializer.Deserialize<CardigannDefinition>(response.Content); - return CleanIndexerDefinition(definition); + var indexerList = defs; + + var directoryInfo = new DirectoryInfo(path); + + if (directoryInfo.Exists) + { + var files = directoryInfo.GetFiles($"*.yml", options); + + foreach (var file in files) + { + _logger.Debug("Loading definition " + file.FullName); + + try + { + var definitionString = File.ReadAllText(file.FullName); + var definition = _deserializer.Deserialize<CardigannMetaDefinition>(definitionString); + + definition.File = Path.GetFileNameWithoutExtension(file.Name); + + if (indexerList.Any(i => i.File == definition.File || i.Name == definition.Name)) + { + _logger.Warn("Definition {0} does not have unique file name or Indexer name", file.FullName); + continue; + } + + indexerList.Add(definition); + } + catch (Exception e) + { + _logger.Error($"Error while parsing Cardigann definition {file.FullName}\n{e}"); + } + } + } + + return indexerList; } - private CardigannDefinition LoadIndexerDef(string fileKey) + private CardigannDefinition GetUncachedDefinition(string fileKey) { if (string.IsNullOrEmpty(fileKey)) { @@ -184,9 +199,24 @@ namespace NzbDrone.Core.IndexerVersions } } + //Check to ensure it's in versioned defs before we go to web + if (!_versionService.All().Any(x => x.File == fileKey)) + { + throw new ArgumentNullException(nameof(fileKey)); + } + + //No definition was returned locally, go to the web return GetHttpDefinition(fileKey); } + private CardigannDefinition GetHttpDefinition(string id) + { + var req = new HttpRequest($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}/{id}"); + var response = _httpClient.Get(req); + var definition = _deserializer.Deserialize<CardigannDefinition>(response.Content); + return CleanIndexerDefinition(definition); + } + private CardigannDefinition CleanIndexerDefinition(CardigannDefinition definition) { if (definition.Settings == null) @@ -242,29 +272,44 @@ namespace NzbDrone.Core.IndexerVersions { var startupFolder = _appFolderInfo.AppDataFolder; + var request = new HttpRequest($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}"); + var response = _httpClient.Get<List<CardigannMetaDefinition>>(request); + + var currentDefs = _versionService.All().ToDictionary(x => x.DefinitionId, x => x.Sha); + try { EnsureDefinitionsFolder(); - var definitionsFolder = Path.Combine(startupFolder, "Definitions"); - var saveFile = Path.Combine(startupFolder, "Definitions", $"indexers.zip"); - - _httpClient.DownloadFile($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}/package.zip", saveFile); - - using (ZipArchive archive = ZipFile.OpenRead(saveFile)) + foreach (var def in response.Resource) { - archive.ExtractToDirectory(definitionsFolder, true); + try + { + var saveFile = Path.Combine(startupFolder, "Definitions", $"{def.File}.yml"); + + if (currentDefs.TryGetValue(def.Id, out var defSha) && defSha == def.Sha) + { + _logger.Trace("Indexer already up to date: {0}", def.File); + + continue; + } + + _httpClient.DownloadFile($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}/{def.File}", saveFile); + + _versionService.Upsert(new IndexerDefinitionVersion { Sha = def.Sha, DefinitionId = def.Id, File = def.File, LastUpdated = DateTime.UtcNow }); + + _cache.Remove(def.File); + _logger.Debug("Updated definition: {0}", def.File); + } + catch (Exception ex) + { + _logger.Error("Definition download failed: {0}, {1}", def.File, ex.Message); + } } - - _diskProvider.DeleteFile(saveFile); - - _cache.Clear(); - - _logger.Debug("Updated indexer definitions"); } catch (Exception ex) { - _logger.Error(ex, "Definition update failed"); + _logger.Error(ex, "Definition download failed, error creating definitions folder in {0}", startupFolder); } } } diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionVersion.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionVersion.cs new file mode 100644 index 000000000..df3d6a932 --- /dev/null +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionVersion.cs @@ -0,0 +1,13 @@ +using System; +using NzbDrone.Core.Datastore; + +namespace NzbDrone.Core.IndexerVersions +{ + public class IndexerDefinitionVersion : ModelBase + { + public string File { get; set; } + public string Sha { get; set; } + public DateTime LastUpdated { get; set; } + public string DefinitionId { get; set; } + } +} diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionVersionRepository.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionVersionRepository.cs new file mode 100644 index 000000000..8e14d5e13 --- /dev/null +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionVersionRepository.cs @@ -0,0 +1,25 @@ +using System; +using System.Linq; +using NzbDrone.Core.Datastore; +using NzbDrone.Core.Messaging.Events; + +namespace NzbDrone.Core.IndexerVersions +{ + public interface IIndexerDefinitionVersionRepository : IBasicRepository<IndexerDefinitionVersion> + { + public IndexerDefinitionVersion GetByDefId(string defId); + } + + public class IndexerDefinitionVersionRepository : BasicRepository<IndexerDefinitionVersion>, IIndexerDefinitionVersionRepository + { + public IndexerDefinitionVersionRepository(IMainDatabase database, IEventAggregator eventAggregator) + : base(database, eventAggregator) + { + } + + public IndexerDefinitionVersion GetByDefId(string defId) + { + return Query(x => x.DefinitionId == defId).SingleOrDefault(); + } + } +} diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionVersionService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionVersionService.cs new file mode 100644 index 000000000..8b2b06d94 --- /dev/null +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionVersionService.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using System.Linq; + +namespace NzbDrone.Core.IndexerVersions +{ + public interface IIndexerDefinitionVersionService + { + IndexerDefinitionVersion Get(int indexerVersionId); + IndexerDefinitionVersion GetByDefId(string defId); + List<IndexerDefinitionVersion> All(); + IndexerDefinitionVersion Add(IndexerDefinitionVersion defVersion); + IndexerDefinitionVersion Upsert(IndexerDefinitionVersion defVersion); + void Delete(int indexerVersionId); + } + + public class IndexerDefinitionVersionService : IIndexerDefinitionVersionService + { + private readonly IIndexerDefinitionVersionRepository _repo; + + public IndexerDefinitionVersionService(IIndexerDefinitionVersionRepository repo) + { + _repo = repo; + } + + public IndexerDefinitionVersion Get(int indexerVersionId) + { + return _repo.Get(indexerVersionId); + } + + public IndexerDefinitionVersion GetByDefId(string defId) + { + return _repo.GetByDefId(defId); + } + + public List<IndexerDefinitionVersion> All() + { + return _repo.All().ToList(); + } + + public IndexerDefinitionVersion Add(IndexerDefinitionVersion defVersion) + { + _repo.Insert(defVersion); + + return defVersion; + } + + public IndexerDefinitionVersion Upsert(IndexerDefinitionVersion defVersion) + { + var existing = _repo.GetByDefId(defVersion.DefinitionId); + + if (existing != null) + { + defVersion.Id = existing.Id; + } + + defVersion = _repo.Upsert(defVersion); + + return defVersion; + } + + public void Delete(int indexerVersionId) + { + _repo.Delete(indexerVersionId); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs index 9012983f1..6f4797c77 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs @@ -37,7 +37,7 @@ namespace NzbDrone.Core.Indexers.Cardigann { var generator = _generatorCache.Get(Settings.DefinitionFile, () => new CardigannRequestGenerator(_configService, - _definitionService.GetDefinition(Settings.DefinitionFile), + _definitionService.GetCachedDefinition(Settings.DefinitionFile), _logger) { HttpClient = _httpClient, @@ -57,7 +57,7 @@ namespace NzbDrone.Core.Indexers.Cardigann public override IParseIndexerResponse GetParser() { return new CardigannParser(_configService, - _definitionService.GetDefinition(Settings.DefinitionFile), + _definitionService.GetCachedDefinition(Settings.DefinitionFile), _logger) { Settings = Settings diff --git a/src/NzbDrone.Core/Indexers/IndexerFactory.cs b/src/NzbDrone.Core/Indexers/IndexerFactory.cs index 0140eb289..d08d57031 100644 --- a/src/NzbDrone.Core/Indexers/IndexerFactory.cs +++ b/src/NzbDrone.Core/Indexers/IndexerFactory.cs @@ -59,7 +59,7 @@ namespace NzbDrone.Core.Indexers catch { // Skip indexer if we fail in Cardigann mapping - continue; + _logger.Debug("Indexer {0} has no definition", definition.Name); } } @@ -96,7 +96,7 @@ namespace NzbDrone.Core.Indexers private void MapCardigannDefinition(IndexerDefinition definition) { var settings = (CardigannSettings)definition.Settings; - var defFile = _definitionService.GetDefinition(settings.DefinitionFile); + var defFile = _definitionService.GetCachedDefinition(settings.DefinitionFile); definition.ExtraFields = defFile.Settings; if (defFile.Login?.Captcha != null && !definition.ExtraFields.Any(x => x.Type == "cardigannCaptcha")) diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 202f4b46e..b72ef980e 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -178,6 +178,7 @@ "IndexerLongTermStatusCheckAllClientMessage": "All indexers are unavailable due to failures for more than 6 hours", "IndexerLongTermStatusCheckSingleClientMessage": "Indexers unavailable due to failures for more than 6 hours: {0}", "IndexerObsoleteCheckMessage": "Indexers are obsolete or have been updated: {0}. Please remove and (or) re-add to Prowlarr", + "IndexerNoDefCheckMessage": "Indexers have no definition and will not work: {0}. Please remove and (or) re-add to Prowlarr", "IndexerPriority": "Indexer Priority", "IndexerPriorityHelpText": "Indexer Priority from 1 (Highest) to 50 (Lowest). Default: 25.", "IndexerProxies": "Indexer Proxies", diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs b/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs index 3cd433e29..4dc7cbb08 100644 --- a/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs +++ b/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs @@ -114,7 +114,7 @@ namespace Prowlarr.Api.V1.Indexers var settings = (CardigannSettings)definition.Settings; - var cardigannDefinition = _definitionService.GetDefinition(settings.DefinitionFile); + var cardigannDefinition = _definitionService.GetCachedDefinition(settings.DefinitionFile); foreach (var field in resource.Fields) { From bc1e397ce355bff081536efc7faeae503252d2ba Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 31 Jan 2022 12:10:16 -0600 Subject: [PATCH 0339/2320] Sync Indexers on app start, go to http if not sync'd yet --- .../IndexerDefinitionUpdateService.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index 72cd5f817..54cff7492 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -8,7 +8,9 @@ using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Http; using NzbDrone.Core.Indexers.Cardigann; +using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Messaging.Commands; +using NzbDrone.Core.Messaging.Events; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; @@ -21,7 +23,7 @@ namespace NzbDrone.Core.IndexerVersions List<string> GetBlocklist(); } - public class IndexerDefinitionUpdateService : IIndexerDefinitionUpdateService, IExecute<IndexerDefinitionUpdateCommand> + public class IndexerDefinitionUpdateService : IIndexerDefinitionUpdateService, IExecute<IndexerDefinitionUpdateCommand>, IHandle<ApplicationStartedEvent> { /* Update Service will fall back if version # does not exist for an indexer per Ta */ @@ -199,8 +201,10 @@ namespace NzbDrone.Core.IndexerVersions } } + var dbDefs = _versionService.All(); + //Check to ensure it's in versioned defs before we go to web - if (!_versionService.All().Any(x => x.File == fileKey)) + if (dbDefs.Count > 0 && dbDefs.Any(x => x.File == fileKey)) { throw new ArgumentNullException(nameof(fileKey)); } @@ -256,6 +260,12 @@ namespace NzbDrone.Core.IndexerVersions return definition; } + public void Handle(ApplicationStartedEvent message) + { + // Sync indexers on app start + UpdateLocalDefinitions(); + } + public void Execute(IndexerDefinitionUpdateCommand message) { UpdateLocalDefinitions(); From 74663ea077d97ffdcf400976e23da6bd37047f60 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 3 Feb 2022 22:29:46 -0600 Subject: [PATCH 0340/2320] Fixed: (Cardigann) Replace legacy links with default link when making requests --- .../Definitions/Cardigann/CardigannBase.cs | 19 +++++++++++++++++++ .../Definitions/Cardigann/CardigannParser.cs | 2 +- .../Cardigann/CardigannRequestGenerator.cs | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index 05fdeda25..d3fb825f4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -816,5 +816,24 @@ namespace NzbDrone.Core.Indexers.Cardigann { return new Uri(currentUrl ?? new Uri(SiteLink), path); } + + protected string ResolveSiteLink() + { + var settingsBaseUrl = Settings?.BaseUrl; + var defaultLink = _definition.Links.First(); + + if (settingsBaseUrl == null) + { + return defaultLink; + } + + if (_definition.Legacylinks.Contains(settingsBaseUrl)) + { + _logger.Trace("Changing legacy site link from {0} to {1}", settingsBaseUrl, defaultLink); + return defaultLink; + } + + return settingsBaseUrl; + } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index 5ad00524c..d429a6a5f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -21,7 +21,7 @@ namespace NzbDrone.Core.Indexers.Cardigann { public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - protected override string SiteLink => Settings?.BaseUrl ?? _definition.Links.First(); + protected override string SiteLink => ResolveSiteLink(); public CardigannParser(IConfigService configService, CardigannDefinition definition, diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 2622142cd..1af2cb641 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Indexers.Cardigann public IDictionary<string, string> Cookies { get; set; } protected HttpResponse landingResult; protected IHtmlDocument landingResultDocument; - protected override string SiteLink => Settings?.BaseUrl ?? _definition.Links.First(); + protected override string SiteLink => ResolveSiteLink(); public CardigannRequestGenerator(IConfigService configService, CardigannDefinition definition, From 64c1e1fa549c4894112b5e743f6fea737d859e89 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 3 Feb 2022 23:16:20 -0600 Subject: [PATCH 0341/2320] Fixed: (Cardigann) Treat "Refresh" header as redirect Fixes #812 --- src/NzbDrone.Common/Http/HttpClient.cs | 2 +- src/NzbDrone.Common/Http/HttpResponse.cs | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Common/Http/HttpClient.cs b/src/NzbDrone.Common/Http/HttpClient.cs index 9c1e2221c..7be59b663 100644 --- a/src/NzbDrone.Common/Http/HttpClient.cs +++ b/src/NzbDrone.Common/Http/HttpClient.cs @@ -75,7 +75,7 @@ namespace NzbDrone.Common.Http do { - request.Url += new HttpUri(response.Headers.GetSingleValue("Location")); + request.Url = new HttpUri(response.RedirectUrl); autoRedirectChain.Add(request.Url.ToString()); _logger.Trace("Redirected to {0}", request.Url); diff --git a/src/NzbDrone.Common/Http/HttpResponse.cs b/src/NzbDrone.Common/Http/HttpResponse.cs index d108705b3..819b3b805 100644 --- a/src/NzbDrone.Common/Http/HttpResponse.cs +++ b/src/NzbDrone.Common/Http/HttpResponse.cs @@ -9,7 +9,7 @@ namespace NzbDrone.Common.Http { public class HttpResponse { - private static readonly Regex RegexSetCookie = new Regex("^(.*?)=(.*?)(?:;|$)", RegexOptions.Compiled); + private static readonly Regex RegexRefresh = new Regex("^(.*?url)=(.*?)(?:;|$)", RegexOptions.Compiled); public HttpResponse(HttpRequest request, HttpHeader headers, CookieCollection cookies, byte[] binaryData, long elapsedTime = 0, HttpStatusCode statusCode = HttpStatusCode.OK) { @@ -67,7 +67,8 @@ namespace NzbDrone.Common.Http StatusCode == HttpStatusCode.MovedPermanently || StatusCode == HttpStatusCode.RedirectMethod || StatusCode == HttpStatusCode.TemporaryRedirect || - StatusCode == HttpStatusCode.Found; + StatusCode == HttpStatusCode.Found || + Headers.ContainsKey("Refresh"); public string RedirectUrl { @@ -76,6 +77,20 @@ namespace NzbDrone.Common.Http var newUrl = Headers["Location"]; if (newUrl == null) { + newUrl = Headers["Refresh"]; + + if (newUrl == null) + { + return string.Empty; + } + + var match = RegexRefresh.Match(newUrl); + + if (match.Success) + { + return (Request.Url += new HttpUri(match.Groups[2].Value)).FullUri; + } + return string.Empty; } From d7b5100e3581048861c1ced0af9b2c3e25991095 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 3 Feb 2022 23:32:25 -0600 Subject: [PATCH 0342/2320] Fixed: (Cardigann) Smarter redirect domain compare Fixes #808 --- .../Definitions/Cardigann/CardigannRequestGenerator.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 1af2cb641..e7f360c02 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -647,10 +647,13 @@ namespace NzbDrone.Core.Indexers.Cardigann protected string GetRedirectDomainHint(string requestUrl, string redirectUrl) { - if (requestUrl.StartsWith(SiteLink) && !redirectUrl.StartsWith(SiteLink)) + var siteLinkUri = new HttpUri(SiteLink); + var requestUri = new HttpUri(requestUrl); + var redirectUri = new HttpUri(redirectUrl); + + if (requestUri.Host.StartsWith(siteLinkUri.Host) && !redirectUri.Host.StartsWith(siteLinkUri.Host)) { - var uri = new HttpUri(redirectUrl); - return uri.Scheme + "://" + uri.Host + "/"; + return redirectUri.Scheme + "://" + redirectUri.Host + "/"; } return null; From 95f62be50c623c5b1fa97a08b8ac83296d604829 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Feb 2022 05:47:36 +0000 Subject: [PATCH 0343/2320] Bump SharpZipLib from 1.3.1 to 1.3.3 in /src/NzbDrone.Common Bumps [SharpZipLib](https://github.com/icsharpcode/SharpZipLib) from 1.3.1 to 1.3.3. - [Release notes](https://github.com/icsharpcode/SharpZipLib/releases) - [Changelog](https://github.com/icsharpcode/SharpZipLib/blob/master/docs/Changes.txt) - [Commits](https://github.com/icsharpcode/SharpZipLib/compare/v1.3.1...v1.3.3) --- updated-dependencies: - dependency-name: SharpZipLib dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> --- src/NzbDrone.Common/Prowlarr.Common.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index aec3ac4ff..9870908de 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -11,7 +11,7 @@ <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="NLog" Version="4.7.9" /> <PackageReference Include="Sentry" Version="3.8.3" /> - <PackageReference Include="SharpZipLib" Version="1.3.1" /> + <PackageReference Include="SharpZipLib" Version="1.3.3" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> <PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" /> From a0d5421dc8b41ba1324bff542ecf0ec5c7513c03 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Fri, 4 Feb 2022 09:38:28 -0600 Subject: [PATCH 0344/2320] Fixed: (Cardigann) Requests Failing for Definitions without LegacyLinks --- .../Indexers/Definitions/Cardigann/CardigannBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index d3fb825f4..0bd470522 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -827,7 +827,7 @@ namespace NzbDrone.Core.Indexers.Cardigann return defaultLink; } - if (_definition.Legacylinks.Contains(settingsBaseUrl)) + if (_definition?.Legacylinks?.Contains(settingsBaseUrl) ?? false) { _logger.Trace("Changing legacy site link from {0} to {1}", settingsBaseUrl, defaultLink); return defaultLink; From a637677ec46292a838d111d73fd57541daee9871 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 4 Feb 2022 22:51:55 -0600 Subject: [PATCH 0345/2320] New: (Avistaz) Better error reporting for unauthorized tests Fixes #822 --- .../Indexers/Definitions/Avistaz/AvistazApi.cs | 5 +++++ .../Indexers/Definitions/Avistaz/AvistazBase.cs | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs index fc22adf4d..c82c057dd 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs @@ -46,6 +46,11 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz public List<AvistazRelease> Data { get; set; } } + public class AvistazErrorResponse + { + public string Message { get; set; } + } + public class AvistazIdInfo { public string Tmdb { get; set; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazBase.cs index 3663f1250..f0158aef4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazBase.cs @@ -89,6 +89,22 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz { await GetToken(); } + catch (HttpException ex) + { + if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) + { + _logger.Warn(ex, "Unauthorized request to indexer"); + + var jsonResponse = new HttpResponse<AvistazErrorResponse>(ex.Response); + return new ValidationFailure(string.Empty, jsonResponse.Resource?.Message ?? "Unauthorized request to indexer"); + } + else + { + _logger.Warn(ex, "Unable to connect to indexer"); + + return new ValidationFailure(string.Empty, "Unable to connect to indexer, check the log for more details"); + } + } catch (Exception ex) { _logger.Warn(ex, "Unable to connect to indexer"); From 505d9c151d1a879044b8d94464e041a65255c05d Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Fri, 4 Feb 2022 21:12:11 -0600 Subject: [PATCH 0346/2320] Fixed: Corrected Query Limit and Grab Limit HelpText --- src/NzbDrone.Core/Indexers/IndexerBaseSettings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/IndexerBaseSettings.cs b/src/NzbDrone.Core/Indexers/IndexerBaseSettings.cs index ab11dc3ca..c3e3019bd 100644 --- a/src/NzbDrone.Core/Indexers/IndexerBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/IndexerBaseSettings.cs @@ -14,10 +14,10 @@ namespace NzbDrone.Core.Indexers { private static readonly IndexerCommonSettingsValidator Validator = new IndexerCommonSettingsValidator(); - [FieldDefinition(1, Type = FieldType.Number, Label = "Query Limit", HelpText = "The number of queries per day Prowlarr will allow to the site", Advanced = true)] + [FieldDefinition(1, Type = FieldType.Number, Label = "Query Limit", HelpText = "The number of queries within a rolling 24 hour period Prowlarr will allow to the site", Advanced = true)] public int? QueryLimit { get; set; } - [FieldDefinition(2, Type = FieldType.Number, Label = "Grab Limit", HelpText = "The number of grabs per day Prowlarr will allow to the site", Advanced = true)] + [FieldDefinition(2, Type = FieldType.Number, Label = "Grab Limit", HelpText = "The number of grabs within a rolling 24 hour period Prowlarr will allow to the site", Advanced = true)] public int? GrabLimit { get; set; } } } From a5718ad93761c771ea5cddfa5f55d06207022948 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 8 Dec 2021 20:23:52 -0600 Subject: [PATCH 0347/2320] New: (Cardigann) - Cardigann v4 Improved Search Logging --- .../Definitions/Cardigann/CardigannRequestGenerator.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index e7f360c02..30ccb3ad0 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -41,7 +41,7 @@ namespace NzbDrone.Core.Indexers.Cardigann public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) { - _logger.Trace("Getting search"); + _logger.Trace("Getting Movie search"); var pageableRequests = new IndexerPageableRequestChain(); @@ -61,6 +61,8 @@ namespace NzbDrone.Core.Indexers.Cardigann public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) { + _logger.Trace("Getting Music search"); + var pageableRequests = new IndexerPageableRequestChain(); var variables = GetQueryVariableDefaults(searchCriteria); @@ -77,6 +79,8 @@ namespace NzbDrone.Core.Indexers.Cardigann public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) { + _logger.Trace("Getting TV search"); + var pageableRequests = new IndexerPageableRequestChain(); var variables = GetQueryVariableDefaults(searchCriteria); @@ -99,6 +103,8 @@ namespace NzbDrone.Core.Indexers.Cardigann public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) { + _logger.Trace("Getting Book search"); + var pageableRequests = new IndexerPageableRequestChain(); var variables = GetQueryVariableDefaults(searchCriteria); @@ -113,6 +119,8 @@ namespace NzbDrone.Core.Indexers.Cardigann public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) { + _logger.Trace("Getting Basic search"); + var pageableRequests = new IndexerPageableRequestChain(); var variables = GetQueryVariableDefaults(searchCriteria); From 69d31f96de1ac0626656958682cd0de07687452e Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 16 Jan 2022 11:54:28 -0600 Subject: [PATCH 0348/2320] New: (Cardigann) - Cardigann v4 Add Support for MapTrackerCatDescToNewznab --- .../Definitions/Cardigann/CardigannBase.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index 0bd470522..0976a9087 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -375,6 +375,22 @@ namespace NzbDrone.Core.Indexers.Cardigann return results; } + public ICollection<IndexerCategory> MapTrackerCatDescToNewznab(string trackerCategoryDesc) + { + if (string.IsNullOrWhiteSpace(trackerCategoryDesc)) + { + return new List<IndexerCategory>(); + } + + var cats = _categoryMapping + .Where(m => + !string.IsNullOrWhiteSpace(m.TrackerCategoryDesc) && + string.Equals(m.TrackerCategoryDesc, trackerCategoryDesc, StringComparison.InvariantCultureIgnoreCase)) + .Select(c => NewznabStandardCategory.AllCats.FirstOrDefault(n => n.Id == c.NewzNabCategory) ?? new IndexerCategory { Id = c.NewzNabCategory }) + .ToList(); + return cats; + } + protected delegate string TemplateTextModifier(string str); protected string ApplyGoTemplateText(string template, Dictionary<string, object> variables = null, TemplateTextModifier modifier = null) From 88c6cbf9430179d82bc4b09f2406b0fb121df513 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 16 Jan 2022 11:35:04 -0600 Subject: [PATCH 0349/2320] New: (Cardigann) - Cardigann v4 Support for categorydesc based on Jackett 02e43bd6a9838562a14c6bd6ea10cfed5a293d59 based on Jackett 60d2c425e1038a28f54bda658a9f543f3a197a66 Fixes #782 --- .../Definitions/Cardigann/CardigannParser.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index d429a6a5f..1dd78fb48 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -464,6 +464,22 @@ namespace NzbDrone.Core.Indexers.Cardigann } } + value = release.Categories.ToString(); + break; + case "categorydesc": + var catsDesc = MapTrackerCatDescToNewznab(value); + if (catsDesc.Any()) + { + if (release.Categories == null || fieldModifiers.Contains("noappend")) + { + release.Categories = catsDesc; + } + else + { + release.Categories = release.Categories.Union(catsDesc).ToList(); + } + } + value = release.Categories.ToString(); break; case "size": From 7e0f88ad7ac8389e6036d1b401474e37db730c51 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 17 Jan 2022 22:47:53 -0600 Subject: [PATCH 0350/2320] New: (Cardigann) - Cardigann v4 Support for Genre, Year, and TraktID --- src/NzbDrone.Core/IndexerSearch/NewznabResults.cs | 2 ++ .../IndexerDefinitionUpdateService.cs | 2 +- .../Definitions/Cardigann/CardigannParser.cs | 15 +++++++++++++++ src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs | 3 +++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs index ec3f6965b..d74bb2d78 100644 --- a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs +++ b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs @@ -91,10 +91,12 @@ namespace NzbDrone.Core.IndexerSearch r.IndexerFlags == null ? null : from f in r.IndexerFlags select GetNabElement("tag", f.Name, protocol), r.Languages == null ? null : from c in r.Languages select GetNabElement("language", c.Id, protocol), r.Subs == null ? null : from c in r.Subs select GetNabElement("subs", c.Id, protocol), + r.Genres == null ? null : GetNabElement("genre", string.Join(", ", r.Genres), protocol), GetNabElement("rageid", r.TvRageId, protocol), GetNabElement("tvdbid", r.TvdbId, protocol), GetNabElement("imdb", r.ImdbId.ToString("D7"), protocol), GetNabElement("tmdbid", r.TmdbId, protocol), + GetNabElement("traktid", r.TraktId, protocol), GetNabElement("seeders", t.Seeders, protocol), GetNabElement("files", r.Files, protocol), GetNabElement("grabs", r.Grabs, protocol), diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index 54cff7492..df55b502c 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.IndexerVersions /* Update Service will fall back if version # does not exist for an indexer per Ta */ private const string DEFINITION_BRANCH = "master"; - private const int DEFINITION_VERSION = 3; + private const int DEFINITION_VERSION = 4; //Used when moving yml to C# private readonly List<string> _defintionBlocklist = new List<string>() diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index 1dd78fb48..ef24e39a7 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -561,6 +561,13 @@ namespace NzbDrone.Core.Indexers.Cardigann release.TvRageId = (int)ParseUtil.CoerceLong(rageID); value = release.TvRageId.ToString(); break; + case "traktid": + var traktIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); + var traktIDMatch = traktIDRegEx.Match(value); + var traktID = traktIDMatch.Groups[1].Value; + release.TvRageId = (int)ParseUtil.CoerceLong(traktID); + value = release.TvRageId.ToString(); + break; case "tvdbid": var tvdbIdRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); var tvdbIdMatch = tvdbIdRegEx.Match(value); @@ -577,6 +584,14 @@ namespace NzbDrone.Core.Indexers.Cardigann value = release.PosterUrl; break; + case "genre": + release.Genres = release.Genres.Union(value.Split(',')).ToList(); + value = release.Genres.ToString(); + break; + case "year": + release.Year = ParseUtil.CoerceInt(value); + value = release.Year.ToString(); + break; case "author": release.Author = value; break; diff --git a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs index 5a67933d5..b8e77e328 100644 --- a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs +++ b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs @@ -32,6 +32,8 @@ namespace NzbDrone.Core.Parser.Model public int TvRageId { get; set; } public int ImdbId { get; set; } public int TmdbId { get; set; } + public int TraktId { get; set; } + public int Year { get; set; } public string Author { get; set; } public string BookTitle { get; set; } public string Artist { get; set; } @@ -45,6 +47,7 @@ namespace NzbDrone.Core.Parser.Model public string Container { get; set; } public string Codec { get; set; } public string Resolution { get; set; } + public ICollection<string> Genres { get; set; } public ICollection<Language> Languages { get; set; } public ICollection<Language> Subs { get; set; } public ICollection<IndexerCategory> Categories { get; set; } From bba6f9349ba8965864b2980b2ba7c18709a5a295 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 5 Feb 2022 14:16:05 -0600 Subject: [PATCH 0351/2320] Fixed: (Cardigann) TraktId was mapping to TvRageId --- .../Indexers/Definitions/Cardigann/CardigannParser.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index ef24e39a7..f09dfe81b 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -565,8 +565,8 @@ namespace NzbDrone.Core.Indexers.Cardigann var traktIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); var traktIDMatch = traktIDRegEx.Match(value); var traktID = traktIDMatch.Groups[1].Value; - release.TvRageId = (int)ParseUtil.CoerceLong(traktID); - value = release.TvRageId.ToString(); + release.TraktId = (int)ParseUtil.CoerceLong(traktID); + value = release.TraktId.ToString(); break; case "tvdbid": var tvdbIdRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); From d951943c670d1b773fa5c24da9962fb9e8b6a78a Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 29 Jan 2022 19:26:38 -0600 Subject: [PATCH 0352/2320] Fixed: (Immortalseed) Keywordless Search --- .../Indexers/Definitions/ImmortalSeed.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs b/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs index 59d3bb07d..4c370e31e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs @@ -170,16 +170,21 @@ namespace NzbDrone.Core.Indexers.Definitions private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null) { - var searchUrl = Settings.BaseUrl + "browse.php"; + var searchUrl = Settings.BaseUrl + "browse.php?"; if (term.IsNotNullOrWhiteSpace()) { - searchUrl += string.Format("?do=search&keywords={0}&search_type=t_name&category=0&include_dead_torrents=no", WebUtility.UrlEncode(term)); + searchUrl += string.Format("do=search&keywords={0}&search_type=t_name&category=0&include_dead_torrents=no", WebUtility.UrlEncode(term)); } if (categories != null && categories.Length > 0) { - searchUrl += "&selectedcats2=" + string.Join(",", Capabilities.Categories.MapTorznabCapsToTrackers(categories)); + if (term.IsNotNullOrWhiteSpace()) + { + searchUrl += "&"; + } + + searchUrl += "selectedcats2=" + string.Join(",", Capabilities.Categories.MapTorznabCapsToTrackers(categories)); } var request = new IndexerRequest(searchUrl, HttpAccept.Html); From dab4500b162a29c340663d44d20c031192031932 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 5 Feb 2022 16:43:22 -0600 Subject: [PATCH 0353/2320] Fixed: (BHD) Handle API Auth Errors --- .../Indexers/Definitions/BeyondHD.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs b/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs index e3c0fc054..c09a0aede 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs @@ -182,18 +182,23 @@ namespace NzbDrone.Core.Indexers.Definitions public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List<TorrentInfo>(); - - if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) + var indexerHttpResponse = indexerResponse.HttpResponse; + if (indexerHttpResponse.StatusCode != HttpStatusCode.OK) { - throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request"); + throw new IndexerException(indexerResponse, $"Unexpected response status {indexerHttpResponse.StatusCode} code from API request"); } - if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value)) + if (!indexerHttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value)) { - throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}"); + throw new IndexerException(indexerResponse, $"Unexpected response header {indexerHttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}"); } - var jsonResponse = new HttpResponse<BeyondHDResponse>(indexerResponse.HttpResponse); + if (indexerResponse.Content.ContainsIgnoreCase("Invalid API Key")) + { + throw new IndexerAuthException("API Key invalid or not authorized"); + } + + var jsonResponse = new HttpResponse<BeyondHDResponse>(indexerHttpResponse); foreach (var row in jsonResponse.Resource.Results) { From 94ef3ea88f5967b65e280b8d2214f7cce747f940 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 6 Feb 2022 16:11:42 -0500 Subject: [PATCH 0354/2320] Go to http if def exists on def server --- .../IndexerVersions/IndexerDefinitionUpdateService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index df55b502c..a84cdec05 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -204,7 +204,7 @@ namespace NzbDrone.Core.IndexerVersions var dbDefs = _versionService.All(); //Check to ensure it's in versioned defs before we go to web - if (dbDefs.Count > 0 && dbDefs.Any(x => x.File == fileKey)) + if (dbDefs.Count > 0 && !dbDefs.Any(x => x.File == fileKey)) { throw new ArgumentNullException(nameof(fileKey)); } From 64c9bb42312122afa4f876c6607b26271618c6cd Mon Sep 17 00:00:00 2001 From: James White <james@jmwhite.co.uk> Date: Mon, 7 Feb 2022 00:03:38 +0000 Subject: [PATCH 0355/2320] Set version header to X-Application-Version (missing hyphen) Not sure if this is intentional or really harms anything but to be consistent with other Arr apps like Sonarr and Radarr, this changes the version header to X-Application-Version. --- src/Prowlarr.Http/Middleware/VersionMiddleware.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Prowlarr.Http/Middleware/VersionMiddleware.cs b/src/Prowlarr.Http/Middleware/VersionMiddleware.cs index 107130941..f80c1c0cc 100644 --- a/src/Prowlarr.Http/Middleware/VersionMiddleware.cs +++ b/src/Prowlarr.Http/Middleware/VersionMiddleware.cs @@ -6,7 +6,7 @@ namespace Prowlarr.Http.Middleware { public class VersionMiddleware { - private const string VERSIONHEADER = "X-ApplicationVersion"; + private const string VERSIONHEADER = "X-Application-Version"; private readonly RequestDelegate _next; private readonly string _version; From 40f6c2e59dd7ffca1d8314edd8a6c614ef0550d4 Mon Sep 17 00:00:00 2001 From: Zak Saunders <thezak48@users.noreply.github.com> Date: Tue, 15 Feb 2022 22:35:12 +0000 Subject: [PATCH 0356/2320] Fixed: Clarify App Sync Settings (#847) --- src/NzbDrone.Core/Localization/Core/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index b72ef980e..7c851310b 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -355,8 +355,8 @@ "SuggestTranslationChange": "Suggest translation change", "SyncAppIndexers": "Sync App Indexers", "SyncLevel": "Sync Level", - "SyncLevelAddRemove": "Add and Remove Only: When it is added or removed from Prowlarr, it will update this remote app.", - "SyncLevelFull": "Full Sync: Will keep this app fully in sync. Changes made in Prowlarr are then synced to this app. Any change made remotely will be overridden by Prowlarr on the next sync.", + "SyncLevelAddRemove": "Add and Remove Only: When indexers are added or removed from Prowlarr, it will update this remote app.", + "SyncLevelFull": "Full Sync: Will keep this app's indexers fully in sync. Changes made to indexers in Prowlarr are then synced to this app. Any change made to indexers remotely within this app will be overridden by Prowlarr on the next sync.", "System": "System", "SystemTimeCheckMessage": "System time is off by more than 1 day. Scheduled tasks may not run correctly until the time is corrected", "TableOptions": "Table Options", From 98c3408909efdbcafbc0e4b8d0a22165be4d9b75 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 7 Feb 2022 12:25:28 -0600 Subject: [PATCH 0357/2320] Fixed: (RuTracker) Update Cats (cherry picked from jackett commit 7a7144bd9d6b4fc4c1ace4886d3bc62ec37b35e6) Fixes #836 --- .../Indexers/Definitions/RuTracker.cs | 638 +++++++++--------- 1 file changed, 331 insertions(+), 307 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs index 26dd1525e..6005cd09d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs @@ -120,6 +120,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(941, NewznabStandardCategory.Movies, "|- Кино СССР"); caps.Categories.AddCategoryMapping(1666, NewznabStandardCategory.Movies, "|- Детские отечественные фильмы"); caps.Categories.AddCategoryMapping(376, NewznabStandardCategory.Movies, "|- Авторские дебюты"); + caps.Categories.AddCategoryMapping(106, NewznabStandardCategory.Movies, "|- Фильмы России и СССР на национальных языках [без перевода]"); caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.MoviesForeign, "Зарубежное кино"); caps.Categories.AddCategoryMapping(187, NewznabStandardCategory.MoviesForeign, "|- Классика мирового кинематографа"); caps.Categories.AddCategoryMapping(2090, NewznabStandardCategory.MoviesForeign, "|- Фильмы до 1990 года"); @@ -127,14 +128,15 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2091, NewznabStandardCategory.MoviesForeign, "|- Фильмы 2001-2005"); caps.Categories.AddCategoryMapping(2092, NewznabStandardCategory.MoviesForeign, "|- Фильмы 2006-2010"); caps.Categories.AddCategoryMapping(2093, NewznabStandardCategory.MoviesForeign, "|- Фильмы 2011-2015"); - caps.Categories.AddCategoryMapping(2200, NewznabStandardCategory.MoviesForeign, "|- Фильмы 2016-2019"); - caps.Categories.AddCategoryMapping(1950, NewznabStandardCategory.MoviesForeign, "|- Фильмы 2020"); + caps.Categories.AddCategoryMapping(2200, NewznabStandardCategory.MoviesForeign, "|- Фильмы 2016-2020"); + caps.Categories.AddCategoryMapping(1950, NewznabStandardCategory.MoviesForeign, "|- Фильмы 2021-2022"); caps.Categories.AddCategoryMapping(2540, NewznabStandardCategory.MoviesForeign, "|- Фильмы Ближнего Зарубежья"); caps.Categories.AddCategoryMapping(934, NewznabStandardCategory.MoviesForeign, "|- Азиатские фильмы"); caps.Categories.AddCategoryMapping(505, NewznabStandardCategory.MoviesForeign, "|- Индийское кино"); caps.Categories.AddCategoryMapping(212, NewznabStandardCategory.MoviesForeign, "|- Сборники фильмов"); caps.Categories.AddCategoryMapping(2459, NewznabStandardCategory.MoviesForeign, "|- Короткий метр"); caps.Categories.AddCategoryMapping(1235, NewznabStandardCategory.MoviesForeign, "|- Грайндхаус"); + caps.Categories.AddCategoryMapping(166, NewznabStandardCategory.MoviesForeign, "|- Зарубежные фильмы без перевода"); caps.Categories.AddCategoryMapping(185, NewznabStandardCategory.Audio, "|- Звуковые дорожки и Переводы"); caps.Categories.AddCategoryMapping(124, NewznabStandardCategory.MoviesOther, "Арт-хаус и авторское кино"); caps.Categories.AddCategoryMapping(1543, NewznabStandardCategory.MoviesOther, "|- Короткий метр (Арт-хаус и авторское кино)"); @@ -160,44 +162,48 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2339, NewznabStandardCategory.MoviesHD, "|- Арт-хаус и авторское кино (HD Video)"); caps.Categories.AddCategoryMapping(140, NewznabStandardCategory.MoviesHD, "|- Индийское кино (HD Video)"); caps.Categories.AddCategoryMapping(194, NewznabStandardCategory.MoviesHD, "|- Грайндхаус (HD Video)"); - caps.Categories.AddCategoryMapping(352, NewznabStandardCategory.Movies3D, "3D/Стерео КиноВидео, TV и Спорт"); + caps.Categories.AddCategoryMapping(352, NewznabStandardCategory.Movies3D, "3D/Стерео Кино, Видео, TV и Спорт"); caps.Categories.AddCategoryMapping(549, NewznabStandardCategory.Movies3D, "|- 3D Кинофильмы"); caps.Categories.AddCategoryMapping(1213, NewznabStandardCategory.Movies3D, "|- 3D Мультфильмы"); caps.Categories.AddCategoryMapping(2109, NewznabStandardCategory.Movies3D, "|- 3D Документальные фильмы"); caps.Categories.AddCategoryMapping(514, NewznabStandardCategory.Movies3D, "|- 3D Спорт"); - caps.Categories.AddCategoryMapping(2097, NewznabStandardCategory.Movies3D, "|- 3D РоликиМузыкальное видео, Трейлеры к фильмам"); + caps.Categories.AddCategoryMapping(2097, NewznabStandardCategory.Movies3D, "|- 3D Ролики, Музыкальное видео, Трейлеры к фильмам"); caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.Movies, "Мультфильмы"); + caps.Categories.AddCategoryMapping(84, NewznabStandardCategory.MoviesUHD, "|- Мультфильмы (UHD Video)"); caps.Categories.AddCategoryMapping(2343, NewznabStandardCategory.MoviesHD, "|- Отечественные мультфильмы (HD Video)"); caps.Categories.AddCategoryMapping(930, NewznabStandardCategory.MoviesHD, "|- Иностранные мультфильмы (HD Video)"); caps.Categories.AddCategoryMapping(2365, NewznabStandardCategory.MoviesHD, "|- Иностранные короткометражные мультфильмы (HD Video)"); caps.Categories.AddCategoryMapping(1900, NewznabStandardCategory.MoviesDVD, "|- Отечественные мультфильмы (DVD)"); - caps.Categories.AddCategoryMapping(521, NewznabStandardCategory.MoviesDVD, "|- Иностранные мультфильмы (DVD)"); caps.Categories.AddCategoryMapping(2258, NewznabStandardCategory.MoviesDVD, "|- Иностранные короткометражные мультфильмы (DVD)"); + caps.Categories.AddCategoryMapping(521, NewznabStandardCategory.MoviesDVD, "|- Иностранные мультфильмы (DVD)"); caps.Categories.AddCategoryMapping(208, NewznabStandardCategory.Movies, "|- Отечественные мультфильмы"); caps.Categories.AddCategoryMapping(539, NewznabStandardCategory.Movies, "|- Отечественные полнометражные мультфильмы"); caps.Categories.AddCategoryMapping(209, NewznabStandardCategory.MoviesForeign, "|- Иностранные мультфильмы"); caps.Categories.AddCategoryMapping(484, NewznabStandardCategory.MoviesForeign, "|- Иностранные короткометражные мультфильмы"); caps.Categories.AddCategoryMapping(822, NewznabStandardCategory.Movies, "|- Сборники мультфильмов"); + caps.Categories.AddCategoryMapping(181, NewznabStandardCategory.Movies, "|- Мультфильмы без перевода"); caps.Categories.AddCategoryMapping(921, NewznabStandardCategory.TV, "Мультсериалы"); caps.Categories.AddCategoryMapping(815, NewznabStandardCategory.TVSD, "|- Мультсериалы (SD Video)"); caps.Categories.AddCategoryMapping(816, NewznabStandardCategory.TVHD, "|- Мультсериалы (DVD Video)"); caps.Categories.AddCategoryMapping(1460, NewznabStandardCategory.TVHD, "|- Мультсериалы (HD Video)"); caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.TVAnime, "Аниме"); - caps.Categories.AddCategoryMapping(2484, NewznabStandardCategory.TVAnime, "|- Артбуки и журналы (Аниме)"); - caps.Categories.AddCategoryMapping(1386, NewznabStandardCategory.TVAnime, "|- Обоисканы, аватары, арт"); - caps.Categories.AddCategoryMapping(1387, NewznabStandardCategory.TVAnime, "|- AMV и другие ролики"); - caps.Categories.AddCategoryMapping(599, NewznabStandardCategory.TVAnime, "|- Аниме (DVD)"); caps.Categories.AddCategoryMapping(1105, NewznabStandardCategory.TVAnime, "|- Аниме (HD Video)"); + caps.Categories.AddCategoryMapping(599, NewznabStandardCategory.TVAnime, "|- Аниме (DVD)"); caps.Categories.AddCategoryMapping(1389, NewznabStandardCategory.TVAnime, "|- Аниме (основной подраздел)"); caps.Categories.AddCategoryMapping(1391, NewznabStandardCategory.TVAnime, "|- Аниме (плеерный подраздел)"); caps.Categories.AddCategoryMapping(2491, NewznabStandardCategory.TVAnime, "|- Аниме (QC подраздел)"); - caps.Categories.AddCategoryMapping(404, NewznabStandardCategory.TVAnime, "|- Покемоны"); - caps.Categories.AddCategoryMapping(1390, NewznabStandardCategory.TVAnime, "|- Наруто"); + caps.Categories.AddCategoryMapping(2544, NewznabStandardCategory.TVAnime, "|- Ван-Пис"); caps.Categories.AddCategoryMapping(1642, NewznabStandardCategory.TVAnime, "|- Гандам"); + caps.Categories.AddCategoryMapping(1390, NewznabStandardCategory.TVAnime, "|- Наруто"); + caps.Categories.AddCategoryMapping(404, NewznabStandardCategory.TVAnime, "|- Покемоны"); caps.Categories.AddCategoryMapping(893, NewznabStandardCategory.TVAnime, "|- Японские мультфильмы"); caps.Categories.AddCategoryMapping(809, NewznabStandardCategory.Audio, "|- Звуковые дорожки (Аниме)"); + caps.Categories.AddCategoryMapping(2484, NewznabStandardCategory.TVAnime, "|- Артбуки и журналы (Аниме)"); + caps.Categories.AddCategoryMapping(1386, NewznabStandardCategory.TVAnime, "|- Обои, сканы, аватары, арт"); + caps.Categories.AddCategoryMapping(1387, NewznabStandardCategory.TVAnime, "|- AMV и другие ролики"); caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.TV, "Русские сериалы"); caps.Categories.AddCategoryMapping(81, NewznabStandardCategory.TVHD, "|- Русские сериалы (HD Video)"); + caps.Categories.AddCategoryMapping(920, NewznabStandardCategory.TVSD, "|- Русские сериалы (DVD Video)"); caps.Categories.AddCategoryMapping(80, NewznabStandardCategory.TV, "|- Возвращение Мухтара"); caps.Categories.AddCategoryMapping(1535, NewznabStandardCategory.TV, "|- Воронины"); caps.Categories.AddCategoryMapping(188, NewznabStandardCategory.TV, "|- Чернобыль: Зона отчуждения"); @@ -215,11 +221,11 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1531, NewznabStandardCategory.TVForeign, "|- Испанские сериалы"); caps.Categories.AddCategoryMapping(721, NewznabStandardCategory.TVForeign, "|- Итальянские сериалы"); caps.Categories.AddCategoryMapping(1102, NewznabStandardCategory.TVForeign, "|- Европейские сериалы"); - caps.Categories.AddCategoryMapping(1120, NewznabStandardCategory.TVForeign, "|- Сериалы стран АфрикиБлижнего и Среднего Востока"); + caps.Categories.AddCategoryMapping(1120, NewznabStandardCategory.TVForeign, "|- Сериалы стран Африки, Ближнего и Среднего Востока"); caps.Categories.AddCategoryMapping(1214, NewznabStandardCategory.TVForeign, "|- Сериалы Австралии и Новой Зеландии"); caps.Categories.AddCategoryMapping(489, NewznabStandardCategory.TVForeign, "|- Сериалы Ближнего Зарубежья"); caps.Categories.AddCategoryMapping(387, NewznabStandardCategory.TVForeign, "|- Сериалы совместного производства нескольких стран"); - caps.Categories.AddCategoryMapping(1359, NewznabStandardCategory.TVForeign, "|- Веб-сериалыВебизоды к сериалам и Пилотные серии сериалов"); + caps.Categories.AddCategoryMapping(1359, NewznabStandardCategory.TVForeign, "|- Веб-сериалы, Вебизоды к сериалам и Пилотные серии сериалов"); caps.Categories.AddCategoryMapping(184, NewznabStandardCategory.TVForeign, "|- Бесстыжие / Shameless (US)"); caps.Categories.AddCategoryMapping(1171, NewznabStandardCategory.TVForeign, "|- Викинги / Vikings"); caps.Categories.AddCategoryMapping(1417, NewznabStandardCategory.TVForeign, "|- Во все тяжкие / Breaking Bad"); @@ -236,13 +242,13 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(173, NewznabStandardCategory.TVForeign, "|- Черное зеркало / Black Mirror"); caps.Categories.AddCategoryMapping(195, NewznabStandardCategory.TVForeign, "|- Для некондиционных раздач"); caps.Categories.AddCategoryMapping(2366, NewznabStandardCategory.TVHD, "Зарубежные сериалы (HD Video)"); - caps.Categories.AddCategoryMapping(119, NewznabStandardCategory.TVForeign, "|- Зарубежные сериалы (UHD Video)"); + caps.Categories.AddCategoryMapping(119, NewznabStandardCategory.TVUHD, "|- Зарубежные сериалы (UHD Video)"); caps.Categories.AddCategoryMapping(1803, NewznabStandardCategory.TVHD, "|- Новинки и сериалы в стадии показа (HD Video)"); caps.Categories.AddCategoryMapping(266, NewznabStandardCategory.TVHD, "|- Сериалы США и Канады (HD Video)"); caps.Categories.AddCategoryMapping(193, NewznabStandardCategory.TVHD, "|- Сериалы Великобритании и Ирландии (HD Video)"); caps.Categories.AddCategoryMapping(1690, NewznabStandardCategory.TVHD, "|- Скандинавские сериалы (HD Video)"); caps.Categories.AddCategoryMapping(1459, NewznabStandardCategory.TVHD, "|- Европейские сериалы (HD Video)"); - caps.Categories.AddCategoryMapping(1463, NewznabStandardCategory.TVHD, "|- Сериалы стран АфрикиБлижнего и Среднего Востока (HD Video)"); + caps.Categories.AddCategoryMapping(1463, NewznabStandardCategory.TVHD, "|- Сериалы стран Африки, Ближнего и Среднего Востока (HD Video)"); caps.Categories.AddCategoryMapping(825, NewznabStandardCategory.TVHD, "|- Сериалы Австралии и Новой Зеландии (HD Video)"); caps.Categories.AddCategoryMapping(1248, NewznabStandardCategory.TVHD, "|- Сериалы Ближнего Зарубежья (HD Video)"); caps.Categories.AddCategoryMapping(1288, NewznabStandardCategory.TVHD, "|- Сериалы совместного производства нескольких стран (HD Video)"); @@ -257,7 +263,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2398, NewznabStandardCategory.TVHD, "|- Ходячие мертвецы + Бойтесь ходячих мертвецов (HD Video)"); caps.Categories.AddCategoryMapping(1949, NewznabStandardCategory.TVHD, "|- Черное зеркало / Black Mirror (HD Video)"); caps.Categories.AddCategoryMapping(1498, NewznabStandardCategory.TVHD, "|- Для некондиционных раздач (HD Video)"); - caps.Categories.AddCategoryMapping(911, NewznabStandardCategory.TVForeign, "Сериалы Латинской АмерикиТурции и Индии"); + caps.Categories.AddCategoryMapping(911, NewznabStandardCategory.TVForeign, "Сериалы Латинской Америки, Турции и Индии"); caps.Categories.AddCategoryMapping(1493, NewznabStandardCategory.TVForeign, "|- Актёры и актрисы латиноамериканских сериалов"); caps.Categories.AddCategoryMapping(325, NewznabStandardCategory.TVForeign, "|- Сериалы Аргентины"); caps.Categories.AddCategoryMapping(534, NewznabStandardCategory.TVForeign, "|- Сериалы Бразилии"); @@ -268,7 +274,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1539, NewznabStandardCategory.TVForeign, "|- Сериалы Латинской Америки с субтитрами"); caps.Categories.AddCategoryMapping(1940, NewznabStandardCategory.TVForeign, "|- Официальные краткие версии сериалов Латинской Америки"); caps.Categories.AddCategoryMapping(694, NewznabStandardCategory.TVForeign, "|- Сериалы Мексики"); - caps.Categories.AddCategoryMapping(775, NewznabStandardCategory.TVForeign, "|- Сериалы ПеруСальвадора, Чили и других стран"); + caps.Categories.AddCategoryMapping(775, NewznabStandardCategory.TVForeign, "|- Сериалы Перу, Сальвадора, Чили и других стран"); caps.Categories.AddCategoryMapping(781, NewznabStandardCategory.TVForeign, "|- Сериалы совместного производства"); caps.Categories.AddCategoryMapping(718, NewznabStandardCategory.TVForeign, "|- Сериалы США (латиноамериканские)"); caps.Categories.AddCategoryMapping(704, NewznabStandardCategory.TVForeign, "|- Сериалы Турции"); @@ -285,14 +291,14 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(670, NewznabStandardCategory.TVDocumentary, "Вера и религия"); caps.Categories.AddCategoryMapping(1475, NewznabStandardCategory.TVDocumentary, "|- [Видео Религия] Христианство"); caps.Categories.AddCategoryMapping(2107, NewznabStandardCategory.TVDocumentary, "|- [Видео Религия] Ислам"); - caps.Categories.AddCategoryMapping(294, NewznabStandardCategory.TVDocumentary, "|- [Видео Религия] Религии ИндииТибета и Восточной Азии"); + caps.Categories.AddCategoryMapping(294, NewznabStandardCategory.TVDocumentary, "|- [Видео Религия] Религии Индии, Тибета и Восточной Азии"); caps.Categories.AddCategoryMapping(1453, NewznabStandardCategory.TVDocumentary, "|- [Видео Религия] Культы и новые религиозные движения"); caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.TVDocumentary, "Документальные фильмы и телепередачи"); caps.Categories.AddCategoryMapping(103, NewznabStandardCategory.TVDocumentary, "|- Документальные (DVD)"); caps.Categories.AddCategoryMapping(671, NewznabStandardCategory.TVDocumentary, "|- [Док] Биографии. Личности и кумиры"); caps.Categories.AddCategoryMapping(2177, NewznabStandardCategory.TVDocumentary, "|- [Док] Кинематограф и мультипликация"); caps.Categories.AddCategoryMapping(656, NewznabStandardCategory.TVDocumentary, "|- [Док] Мастера искусств Театра и Кино"); - caps.Categories.AddCategoryMapping(2538, NewznabStandardCategory.TVDocumentary, "|- [Док] Искусствоистория искусств"); + caps.Categories.AddCategoryMapping(2538, NewznabStandardCategory.TVDocumentary, "|- [Док] Искусство, история искусств"); caps.Categories.AddCategoryMapping(2159, NewznabStandardCategory.TVDocumentary, "|- [Док] Музыка"); caps.Categories.AddCategoryMapping(251, NewznabStandardCategory.TVDocumentary, "|- [Док] Криминальная документалистика"); caps.Categories.AddCategoryMapping(98, NewznabStandardCategory.TVDocumentary, "|- [Док] Тайны века / Спецслужбы / Теории Заговоров"); @@ -306,16 +312,16 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(876, NewznabStandardCategory.TVDocumentary, "|- [Док] Путешествия и туризм"); caps.Categories.AddCategoryMapping(2139, NewznabStandardCategory.TVDocumentary, "|- [Док] Медицина"); caps.Categories.AddCategoryMapping(2380, NewznabStandardCategory.TVDocumentary, "|- [Док] Социальные ток-шоу"); - caps.Categories.AddCategoryMapping(1467, NewznabStandardCategory.TVDocumentary, "|- [Док] Информационно-аналитические и общественно-политические перед.."); + caps.Categories.AddCategoryMapping(1467, NewznabStandardCategory.TVDocumentary, "|- [Док] Информационно-аналитические и общественно-политические передачи"); caps.Categories.AddCategoryMapping(1469, NewznabStandardCategory.TVDocumentary, "|- [Док] Архитектура и строительство"); - caps.Categories.AddCategoryMapping(672, NewznabStandardCategory.TVDocumentary, "|- [Док] Всё о домебыте и дизайне"); + caps.Categories.AddCategoryMapping(672, NewznabStandardCategory.TVDocumentary, "|- [Док] Всё о доме, быте и дизайне"); caps.Categories.AddCategoryMapping(249, NewznabStandardCategory.TVDocumentary, "|- [Док] BBC"); caps.Categories.AddCategoryMapping(552, NewznabStandardCategory.TVDocumentary, "|- [Док] Discovery"); caps.Categories.AddCategoryMapping(500, NewznabStandardCategory.TVDocumentary, "|- [Док] National Geographic"); caps.Categories.AddCategoryMapping(2112, NewznabStandardCategory.TVDocumentary, "|- [Док] История: Древний мир / Античность / Средневековье"); caps.Categories.AddCategoryMapping(1327, NewznabStandardCategory.TVDocumentary, "|- [Док] История: Новое и Новейшее время"); caps.Categories.AddCategoryMapping(1468, NewznabStandardCategory.TVDocumentary, "|- [Док] Эпоха СССР"); - caps.Categories.AddCategoryMapping(1280, NewznabStandardCategory.TVDocumentary, "|- [Док] Битва экстрасенсов / Теория невероятности / Искатели / Галил.."); + caps.Categories.AddCategoryMapping(1280, NewznabStandardCategory.TVDocumentary, "|- [Док] Битва экстрасенсов / Теория невероятности / Искатели / Галилео"); caps.Categories.AddCategoryMapping(752, NewznabStandardCategory.TVDocumentary, "|- [Док] Русские сенсации / Программа Максимум / Профессия репортёр"); caps.Categories.AddCategoryMapping(1114, NewznabStandardCategory.TVDocumentary, "|- [Док] Паранормальные явления"); caps.Categories.AddCategoryMapping(2168, NewznabStandardCategory.TVDocumentary, "|- [Док] Альтернативная история и наука"); @@ -325,13 +331,14 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2323, NewznabStandardCategory.TVDocumentary, "|- Информационно-аналитические и общественно-политические (HD Video)"); caps.Categories.AddCategoryMapping(1278, NewznabStandardCategory.TVDocumentary, "|- Биографии. Личности и кумиры (HD Video)"); caps.Categories.AddCategoryMapping(1281, NewznabStandardCategory.TVDocumentary, "|- Военное дело (HD Video)"); - caps.Categories.AddCategoryMapping(2110, NewznabStandardCategory.TVDocumentary, "|- Естествознаниенаука и техника (HD Video)"); + caps.Categories.AddCategoryMapping(2110, NewznabStandardCategory.TVDocumentary, "|- Естествознание, наука и техника (HD Video)"); caps.Categories.AddCategoryMapping(979, NewznabStandardCategory.TVDocumentary, "|- Путешествия и туризм (HD Video)"); caps.Categories.AddCategoryMapping(2169, NewznabStandardCategory.TVDocumentary, "|- Флора и фауна (HD Video)"); caps.Categories.AddCategoryMapping(2166, NewznabStandardCategory.TVDocumentary, "|- История (HD Video)"); - caps.Categories.AddCategoryMapping(2164, NewznabStandardCategory.TVDocumentary, "|- BBCDiscovery, National Geographic (HD Video)"); + caps.Categories.AddCategoryMapping(2164, NewznabStandardCategory.TVDocumentary, "|- BBC, Discovery, National Geographic, History Channel (HD Video)"); caps.Categories.AddCategoryMapping(2163, NewznabStandardCategory.TVDocumentary, "|- Криминальная документалистика (HD Video)"); - caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.TVDocumentary, "Развлекательные телепередачи и шоуприколы и юмор"); + caps.Categories.AddCategoryMapping(85, NewznabStandardCategory.TVDocumentary, "|- Некондиционное видео - Документальные (HD Video)"); + caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.TVDocumentary, "Развлекательные телепередачи и шоу, приколы и юмор"); caps.Categories.AddCategoryMapping(1959, NewznabStandardCategory.TVOther, "|- [Видео Юмор] Интеллектуальные игры и викторины"); caps.Categories.AddCategoryMapping(939, NewznabStandardCategory.TVOther, "|- [Видео Юмор] Реалити и ток-шоу / номинации / показы"); caps.Categories.AddCategoryMapping(1481, NewznabStandardCategory.TVOther, "|- [Видео Юмор] Детские телешоу"); @@ -346,13 +353,26 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(137, NewznabStandardCategory.TVOther, "|- [Видео Юмор] Фильмы со смешным переводом (пародии)"); caps.Categories.AddCategoryMapping(2537, NewznabStandardCategory.TVOther, "|- [Видео Юмор] Stand-up comedy"); caps.Categories.AddCategoryMapping(532, NewznabStandardCategory.TVOther, "|- [Видео Юмор] Украинские Шоу"); - caps.Categories.AddCategoryMapping(827, NewznabStandardCategory.TVOther, "|- [Видео Юмор] Танцевальные шоуконцерты, выступления"); + caps.Categories.AddCategoryMapping(827, NewznabStandardCategory.TVOther, "|- [Видео Юмор] Танцевальные шоу, концерты, выступления"); caps.Categories.AddCategoryMapping(1484, NewznabStandardCategory.TVOther, "|- [Видео Юмор] Цирк"); caps.Categories.AddCategoryMapping(1485, NewznabStandardCategory.TVOther, "|- [Видео Юмор] Школа злословия"); caps.Categories.AddCategoryMapping(114, NewznabStandardCategory.TVOther, "|- [Видео Юмор] Сатирики и юмористы"); caps.Categories.AddCategoryMapping(1332, NewznabStandardCategory.TVOther, "|- Юмористические аудиопередачи"); caps.Categories.AddCategoryMapping(1495, NewznabStandardCategory.TVOther, "|- Аудио и видео ролики (Приколы и юмор)"); - caps.Categories.AddCategoryMapping(1315, NewznabStandardCategory.TVSport, "Зимние Олимпийские игры 2018"); + caps.Categories.AddCategoryMapping(1392, NewznabStandardCategory.TVSport, "XXXII Летние Олимпийские игры 2020"); + caps.Categories.AddCategoryMapping(2475, NewznabStandardCategory.TVSport, "|- Легкая атлетика"); + caps.Categories.AddCategoryMapping(2493, NewznabStandardCategory.TVSport, "|- Плавание. Прыжки в воду. Синхронное плавание"); + caps.Categories.AddCategoryMapping(2113, NewznabStandardCategory.TVSport, "|- Спортивная гимнастика. Художественная гимнастика. Прыжки на батуте"); + caps.Categories.AddCategoryMapping(2482, NewznabStandardCategory.TVSport, "|- Велоспорт"); + caps.Categories.AddCategoryMapping(2103, NewznabStandardCategory.TVSport, "|- Академическая гребля. Гребля на байдарках и каноэ"); + caps.Categories.AddCategoryMapping(2522, NewznabStandardCategory.TVSport, "|- Бокс. Борьба Вольная и Греко-римская. Дзюдо. Карате. Тхэквондо"); + caps.Categories.AddCategoryMapping(2485, NewznabStandardCategory.TVSport, "|- Футбол"); + caps.Categories.AddCategoryMapping(2486, NewznabStandardCategory.TVSport, "|- Баскетбол. Волейбол. Гандбол. Водное поло. Регби. Хоккей на траве"); + caps.Categories.AddCategoryMapping(2479, NewznabStandardCategory.TVSport, "|- Теннис. Настольный теннис. Бадминтон"); + caps.Categories.AddCategoryMapping(2089, NewznabStandardCategory.TVSport, "|- Фехтование. Стрельба. Стрельба из лука. Современное пятиборье"); + caps.Categories.AddCategoryMapping(1794, NewznabStandardCategory.TVSport, "|- Другие виды спорта"); + caps.Categories.AddCategoryMapping(2338, NewznabStandardCategory.TVSport, "|- Обзорные и аналитические программы"); + caps.Categories.AddCategoryMapping(1315, NewznabStandardCategory.TVSport, "XXIV Зимние Олимпийские игры 2022"); caps.Categories.AddCategoryMapping(1336, NewznabStandardCategory.TVSport, "|- Биатлон"); caps.Categories.AddCategoryMapping(2171, NewznabStandardCategory.TVSport, "|- Лыжные гонки"); caps.Categories.AddCategoryMapping(1339, NewznabStandardCategory.TVSport, "|- Прыжки на лыжах с трамплина / Лыжное двоеборье"); @@ -363,11 +383,11 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2068, NewznabStandardCategory.TVSport, "|- Хоккей"); caps.Categories.AddCategoryMapping(2016, NewznabStandardCategory.TVSport, "|- Керлинг"); caps.Categories.AddCategoryMapping(1311, NewznabStandardCategory.TVSport, "|- Обзорные и аналитические программы"); - caps.Categories.AddCategoryMapping(255, NewznabStandardCategory.TVSport, "Спортивные турнирыфильмы и передачи"); + caps.Categories.AddCategoryMapping(255, NewznabStandardCategory.TVSport, "Спортивные турниры, фильмы и передачи"); caps.Categories.AddCategoryMapping(256, NewznabStandardCategory.TVSport, "|- Автоспорт"); caps.Categories.AddCategoryMapping(1986, NewznabStandardCategory.TVSport, "|- Мотоспорт"); - caps.Categories.AddCategoryMapping(660, NewznabStandardCategory.TVSport, "|- Формула-1 (2020)"); - caps.Categories.AddCategoryMapping(1551, NewznabStandardCategory.TVSport, "|- Формула-1 (2012-2019)"); + caps.Categories.AddCategoryMapping(660, NewznabStandardCategory.TVSport, "|- Формула-1 (2021)"); + caps.Categories.AddCategoryMapping(1551, NewznabStandardCategory.TVSport, "|- Формула-1 (2012-2020)"); caps.Categories.AddCategoryMapping(626, NewznabStandardCategory.TVSport, "|- Формула 1 (до 2011 вкл.)"); caps.Categories.AddCategoryMapping(262, NewznabStandardCategory.TVSport, "|- Велоспорт"); caps.Categories.AddCategoryMapping(1326, NewznabStandardCategory.TVSport, "|- Волейбол/Гандбол"); @@ -390,15 +410,16 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(260, NewznabStandardCategory.TVSport, "|- Экстрим"); caps.Categories.AddCategoryMapping(1319, NewznabStandardCategory.TVSport, "|- Спорт (видео)"); caps.Categories.AddCategoryMapping(1608, NewznabStandardCategory.TVSport, "⚽ Футбол"); - caps.Categories.AddCategoryMapping(2294, NewznabStandardCategory.TVSport, "|- UHDTV. Футбол в формате высокой четкости"); - caps.Categories.AddCategoryMapping(136, NewznabStandardCategory.TVSport, "|- Чемпионат Европы 2020 (квалификация)"); + caps.Categories.AddCategoryMapping(2294, NewznabStandardCategory.TVSport, "|- UHDTV"); + caps.Categories.AddCategoryMapping(2532, NewznabStandardCategory.TVSport, "|- Чемпионат Европы 2020 [2021] (финальный турнир)"); + caps.Categories.AddCategoryMapping(136, NewznabStandardCategory.TVSport, "|- Чемпионат Европы 2020 [2021] (отбор)"); caps.Categories.AddCategoryMapping(592, NewznabStandardCategory.TVSport, "|- Лига Наций"); caps.Categories.AddCategoryMapping(1693, NewznabStandardCategory.TVSport, "|- Чемпионат Мира 2022 (отбор)"); caps.Categories.AddCategoryMapping(2533, NewznabStandardCategory.TVSport, "|- Чемпионат Мира 2018 (игры)"); - caps.Categories.AddCategoryMapping(1952, NewznabStandardCategory.TVSport, "|- Чемпионат Мира 2018 (обзорные передачидокументалистика)"); + caps.Categories.AddCategoryMapping(1952, NewznabStandardCategory.TVSport, "|- Чемпионат Мира 2018 (обзорные передачи, документалистика)"); caps.Categories.AddCategoryMapping(1621, NewznabStandardCategory.TVSport, "|- Чемпионаты Мира"); - caps.Categories.AddCategoryMapping(2075, NewznabStandardCategory.TVSport, "|- Россия 2018-2019"); - caps.Categories.AddCategoryMapping(1668, NewznabStandardCategory.TVSport, "|- Россия 2019-2020"); + caps.Categories.AddCategoryMapping(1668, NewznabStandardCategory.TVSport, "|- Россия 2021-2022"); + caps.Categories.AddCategoryMapping(2075, NewznabStandardCategory.TVSport, "|- Россия 2020-2021"); caps.Categories.AddCategoryMapping(1613, NewznabStandardCategory.TVSport, "|- Россия/СССР"); caps.Categories.AddCategoryMapping(1614, NewznabStandardCategory.TVSport, "|- Англия"); caps.Categories.AddCategoryMapping(1623, NewznabStandardCategory.TVSport, "|- Испания"); @@ -408,13 +429,13 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2514, NewznabStandardCategory.TVSport, "|- Украина"); caps.Categories.AddCategoryMapping(1616, NewznabStandardCategory.TVSport, "|- Другие национальные чемпионаты и кубки"); caps.Categories.AddCategoryMapping(2014, NewznabStandardCategory.TVSport, "|- Международные турниры"); + caps.Categories.AddCategoryMapping(1491, NewznabStandardCategory.TVSport, "|- Еврокубки 2021-2022"); caps.Categories.AddCategoryMapping(1442, NewznabStandardCategory.TVSport, "|- Еврокубки 2020-2021"); - caps.Categories.AddCategoryMapping(1491, NewznabStandardCategory.TVSport, "|- Еврокубки 2019-2020"); - caps.Categories.AddCategoryMapping(1987, NewznabStandardCategory.TVSport, "|- Еврокубки 2011-2018"); + caps.Categories.AddCategoryMapping(1987, NewznabStandardCategory.TVSport, "|- Еврокубки 2011-2020"); caps.Categories.AddCategoryMapping(1617, NewznabStandardCategory.TVSport, "|- Еврокубки"); caps.Categories.AddCategoryMapping(1620, NewznabStandardCategory.TVSport, "|- Чемпионаты Европы"); caps.Categories.AddCategoryMapping(1998, NewznabStandardCategory.TVSport, "|- Товарищеские турниры и матчи"); - caps.Categories.AddCategoryMapping(1343, NewznabStandardCategory.TVSport, "|- Обзорные и аналитические передачи 2018-2020"); + caps.Categories.AddCategoryMapping(1343, NewznabStandardCategory.TVSport, "|- Обзорные и аналитические передачи 2018-2021"); caps.Categories.AddCategoryMapping(751, NewznabStandardCategory.TVSport, "|- Обзорные и аналитические передачи"); caps.Categories.AddCategoryMapping(497, NewznabStandardCategory.TVSport, "|- Документальные фильмы (футбол)"); caps.Categories.AddCategoryMapping(1697, NewznabStandardCategory.TVSport, "|- Мини-футбол/Пляжный футбол"); @@ -422,11 +443,11 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2001, NewznabStandardCategory.TVSport, "|- Международные соревнования"); caps.Categories.AddCategoryMapping(2002, NewznabStandardCategory.TVSport, "|- NBA / NCAA (до 2000 г.)"); caps.Categories.AddCategoryMapping(283, NewznabStandardCategory.TVSport, "|- NBA / NCAA (2000-2010 гг.)"); - caps.Categories.AddCategoryMapping(1997, NewznabStandardCategory.TVSport, "|- NBA / NCAA (2010-2020 гг.)"); + caps.Categories.AddCategoryMapping(1997, NewznabStandardCategory.TVSport, "|- NBA / NCAA (2010-2022 гг.)"); caps.Categories.AddCategoryMapping(2003, NewznabStandardCategory.TVSport, "|- Европейский клубный баскетбол"); caps.Categories.AddCategoryMapping(2009, NewznabStandardCategory.TVSport, "🏒 Хоккей"); caps.Categories.AddCategoryMapping(2010, NewznabStandardCategory.TVSport, "|- Хоккей с мячом / Бенди"); - caps.Categories.AddCategoryMapping(1229, NewznabStandardCategory.TVSport, "|- Чемпионат Мира по хоккею 2019"); + caps.Categories.AddCategoryMapping(1229, NewznabStandardCategory.TVSport, "|- Чемпионат Мира по хоккею 2021"); caps.Categories.AddCategoryMapping(2006, NewznabStandardCategory.TVSport, "|- Международные турниры"); caps.Categories.AddCategoryMapping(2007, NewznabStandardCategory.TVSport, "|- КХЛ"); caps.Categories.AddCategoryMapping(2005, NewznabStandardCategory.TVSport, "|- НХЛ (до 2011/12)"); @@ -439,22 +460,23 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1527, NewznabStandardCategory.TVSport, "|- International Wrestling"); caps.Categories.AddCategoryMapping(2069, NewznabStandardCategory.TVSport, "|- Oldschool Wrestling"); caps.Categories.AddCategoryMapping(1323, NewznabStandardCategory.TVSport, "|- Documentary Wrestling"); - caps.Categories.AddCategoryMapping(1411, NewznabStandardCategory.TVSport, "|- Сканированиеобработка сканов"); + caps.Categories.AddCategoryMapping(1346, NewznabStandardCategory.TVSport, "Для дооформления раздач"); + caps.Categories.AddCategoryMapping(1411, NewznabStandardCategory.TVSport, "|- Сканирование, обработка сканов"); caps.Categories.AddCategoryMapping(21, NewznabStandardCategory.Books, "Книги и журналы (общий раздел)"); - caps.Categories.AddCategoryMapping(2157, NewznabStandardCategory.Books, "|- Кинотеатр, ТВ, мультипликация, цирк"); - caps.Categories.AddCategoryMapping(765, NewznabStandardCategory.Books, "|- Рисунокграфический дизайн"); + caps.Categories.AddCategoryMapping(2157, NewznabStandardCategory.Books, "|- Кино, театр, ТВ, мультипликация, цирк"); + caps.Categories.AddCategoryMapping(765, NewznabStandardCategory.Books, "|- Рисунок, графический дизайн"); caps.Categories.AddCategoryMapping(2019, NewznabStandardCategory.Books, "|- Фото и видеосъемка"); caps.Categories.AddCategoryMapping(31, NewznabStandardCategory.BooksMags, "|- Журналы и газеты (общий раздел)"); - caps.Categories.AddCategoryMapping(1427, NewznabStandardCategory.Books, "|- Эзотерикагадания, магия, фен-шуй"); + caps.Categories.AddCategoryMapping(1427, NewznabStandardCategory.Books, "|- Эзотерика, гадания, магия, фен-шуй"); caps.Categories.AddCategoryMapping(2422, NewznabStandardCategory.Books, "|- Астрология"); caps.Categories.AddCategoryMapping(2195, NewznabStandardCategory.Books, "|- Красота. Уход. Домоводство"); caps.Categories.AddCategoryMapping(2521, NewznabStandardCategory.Books, "|- Мода. Стиль. Этикет"); caps.Categories.AddCategoryMapping(2223, NewznabStandardCategory.Books, "|- Путешествия и туризм"); caps.Categories.AddCategoryMapping(2447, NewznabStandardCategory.Books, "|- Знаменитости и кумиры"); caps.Categories.AddCategoryMapping(39, NewznabStandardCategory.Books, "|- Разное (книги)"); - caps.Categories.AddCategoryMapping(2086, NewznabStandardCategory.Books, "- Самиздатстатьи из журналов, фрагменты книг"); - caps.Categories.AddCategoryMapping(1101, NewznabStandardCategory.Books, "Для детейродителей и учителей"); - caps.Categories.AddCategoryMapping(745, NewznabStandardCategory.Books, "|- Учебная литература для детского сада и начальной школы (до 4 класс.."); + caps.Categories.AddCategoryMapping(2086, NewznabStandardCategory.Books, "|- Самиздат, статьи из журналов, фрагменты книг"); + caps.Categories.AddCategoryMapping(1101, NewznabStandardCategory.Books, "Для детей, родителей и учителей"); + caps.Categories.AddCategoryMapping(745, NewznabStandardCategory.Books, "|- Учебная литература для детского сада и начальной школы (до 4 класса)"); caps.Categories.AddCategoryMapping(1689, NewznabStandardCategory.Books, "|- Учебная литература для старших классов (5-11 класс)"); caps.Categories.AddCategoryMapping(2336, NewznabStandardCategory.Books, "|- Учителям и педагогам"); caps.Categories.AddCategoryMapping(2337, NewznabStandardCategory.Books, "|- Научно-популярная и познавательная литература (для детей)"); @@ -462,16 +484,16 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1400, NewznabStandardCategory.Books, "|- Воспитание и развитие"); caps.Categories.AddCategoryMapping(1415, NewznabStandardCategory.Books, "|- Худ. лит-ра для дошкольников и младших классов"); caps.Categories.AddCategoryMapping(2046, NewznabStandardCategory.Books, "|- Худ. лит-ра для средних и старших классов"); - caps.Categories.AddCategoryMapping(1802, NewznabStandardCategory.Books, "Спортфизическая культура, боевые искусства"); + caps.Categories.AddCategoryMapping(1802, NewznabStandardCategory.Books, "Спорт, физическая культура, боевые искусства"); caps.Categories.AddCategoryMapping(2189, NewznabStandardCategory.Books, "|- Футбол (книги и журналы)"); caps.Categories.AddCategoryMapping(2190, NewznabStandardCategory.Books, "|- Хоккей (книги и журналы)"); caps.Categories.AddCategoryMapping(2443, NewznabStandardCategory.Books, "|- Игровые виды спорта"); caps.Categories.AddCategoryMapping(1477, NewznabStandardCategory.Books, "|- Легкая атлетика. Плавание. Гимнастика. Тяжелая атлетика. Гребля"); caps.Categories.AddCategoryMapping(669, NewznabStandardCategory.Books, "|- Автоспорт. Мотоспорт. Велоспорт"); caps.Categories.AddCategoryMapping(2196, NewznabStandardCategory.Books, "|- Шахматы. Шашки"); - caps.Categories.AddCategoryMapping(2056, NewznabStandardCategory.Books, "|- Боевые искусстваединоборства"); + caps.Categories.AddCategoryMapping(2056, NewznabStandardCategory.Books, "|- Боевые искусства, единоборства"); caps.Categories.AddCategoryMapping(1436, NewznabStandardCategory.Books, "|- Экстрим (книги)"); - caps.Categories.AddCategoryMapping(2191, NewznabStandardCategory.Books, "|- Физкультурафитнес, бодибилдинг"); + caps.Categories.AddCategoryMapping(2191, NewznabStandardCategory.Books, "|- Физкультура, фитнес, бодибилдинг"); caps.Categories.AddCategoryMapping(2477, NewznabStandardCategory.Books, "|- Спортивная пресса"); caps.Categories.AddCategoryMapping(1680, NewznabStandardCategory.Books, "Гуманитарные науки"); caps.Categories.AddCategoryMapping(1684, NewznabStandardCategory.Books, "|- Искусствоведение. Культурология"); @@ -481,15 +503,15 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(995, NewznabStandardCategory.Books, "|- Философия"); caps.Categories.AddCategoryMapping(2022, NewznabStandardCategory.Books, "|- Политология"); caps.Categories.AddCategoryMapping(2471, NewznabStandardCategory.Books, "|- Социология"); - caps.Categories.AddCategoryMapping(2375, NewznabStandardCategory.Books, "|- Публицистикажурналистика"); - caps.Categories.AddCategoryMapping(764, NewznabStandardCategory.Books, "|- Бизнесменеджмент"); + caps.Categories.AddCategoryMapping(2375, NewznabStandardCategory.Books, "|- Публицистика, журналистика"); + caps.Categories.AddCategoryMapping(764, NewznabStandardCategory.Books, "|- Бизнес, менеджмент"); caps.Categories.AddCategoryMapping(1685, NewznabStandardCategory.Books, "|- Маркетинг"); caps.Categories.AddCategoryMapping(1688, NewznabStandardCategory.Books, "|- Экономика"); caps.Categories.AddCategoryMapping(2472, NewznabStandardCategory.Books, "|- Финансы"); caps.Categories.AddCategoryMapping(1687, NewznabStandardCategory.Books, "|- Юридические науки. Право. Криминалистика"); caps.Categories.AddCategoryMapping(2020, NewznabStandardCategory.Books, "Исторические науки"); caps.Categories.AddCategoryMapping(1349, NewznabStandardCategory.Books, "|- Методология и философия исторической науки"); - caps.Categories.AddCategoryMapping(1967, NewznabStandardCategory.Books, "|- Исторические источники (книгипериодика)"); + caps.Categories.AddCategoryMapping(1967, NewznabStandardCategory.Books, "|- Исторические источники (книги, периодика)"); caps.Categories.AddCategoryMapping(1341, NewznabStandardCategory.Books, "|- Исторические источники (документы)"); caps.Categories.AddCategoryMapping(2049, NewznabStandardCategory.Books, "|- Исторические персоны"); caps.Categories.AddCategoryMapping(1681, NewznabStandardCategory.Books, "|- Альтернативные исторические теории"); @@ -499,15 +521,15 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2444, NewznabStandardCategory.Books, "|- История Нового и Новейшего времени"); caps.Categories.AddCategoryMapping(2427, NewznabStandardCategory.Books, "|- История Европы"); caps.Categories.AddCategoryMapping(2452, NewznabStandardCategory.Books, "|- История Азии и Африки"); - caps.Categories.AddCategoryMapping(2445, NewznabStandardCategory.Books, "|- История АмерикиАвстралии, Океании"); + caps.Categories.AddCategoryMapping(2445, NewznabStandardCategory.Books, "|- История Америки, Австралии, Океании"); caps.Categories.AddCategoryMapping(2435, NewznabStandardCategory.Books, "|- История России"); caps.Categories.AddCategoryMapping(667, NewznabStandardCategory.Books, "|- История России до 1917 года"); caps.Categories.AddCategoryMapping(2436, NewznabStandardCategory.Books, "|- Эпоха СССР"); caps.Categories.AddCategoryMapping(1335, NewznabStandardCategory.Books, "|- История России после 1991 года"); caps.Categories.AddCategoryMapping(2453, NewznabStandardCategory.Books, "|- История стран бывшего СССР"); - caps.Categories.AddCategoryMapping(2320, NewznabStandardCategory.Books, "|- Этнографияантропология"); + caps.Categories.AddCategoryMapping(2320, NewznabStandardCategory.Books, "|- Этнография, антропология"); caps.Categories.AddCategoryMapping(1801, NewznabStandardCategory.Books, "|- Международные отношения. Дипломатия"); - caps.Categories.AddCategoryMapping(2023, NewznabStandardCategory.BooksTechnical, "Точныеестественные и инженерные науки"); + caps.Categories.AddCategoryMapping(2023, NewznabStandardCategory.BooksTechnical, "Точные, естественные и инженерные науки"); caps.Categories.AddCategoryMapping(2024, NewznabStandardCategory.BooksTechnical, "|- Авиация / Космонавтика"); caps.Categories.AddCategoryMapping(2026, NewznabStandardCategory.BooksTechnical, "|- Физика"); caps.Categories.AddCategoryMapping(2192, NewznabStandardCategory.BooksTechnical, "|- Астрономия"); @@ -522,16 +544,16 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2526, NewznabStandardCategory.BooksTechnical, "|- Сварка / Пайка / Неразрушающий контроль"); caps.Categories.AddCategoryMapping(2527, NewznabStandardCategory.BooksTechnical, "|- Автоматизация / Робототехника"); caps.Categories.AddCategoryMapping(2254, NewznabStandardCategory.BooksTechnical, "|- Металлургия / Материаловедение"); - caps.Categories.AddCategoryMapping(2376, NewznabStandardCategory.BooksTechnical, "|- Механикасопротивление материалов"); + caps.Categories.AddCategoryMapping(2376, NewznabStandardCategory.BooksTechnical, "|- Механика, сопротивление материалов"); caps.Categories.AddCategoryMapping(2054, NewznabStandardCategory.BooksTechnical, "|- Энергетика / электротехника"); - caps.Categories.AddCategoryMapping(770, NewznabStandardCategory.BooksTechnical, "|- Нефтянаягазовая и химическая промышленность"); + caps.Categories.AddCategoryMapping(770, NewznabStandardCategory.BooksTechnical, "|- Нефтяная, газовая и химическая промышленность"); caps.Categories.AddCategoryMapping(2476, NewznabStandardCategory.BooksTechnical, "|- Сельское хозяйство и пищевая промышленность"); caps.Categories.AddCategoryMapping(2494, NewznabStandardCategory.BooksTechnical, "|- Железнодорожное дело"); caps.Categories.AddCategoryMapping(1528, NewznabStandardCategory.BooksTechnical, "|- Нормативная документация"); - caps.Categories.AddCategoryMapping(2032, NewznabStandardCategory.BooksTechnical, "|- Журналы: научныенаучно-популярные, радио и др."); + caps.Categories.AddCategoryMapping(2032, NewznabStandardCategory.BooksTechnical, "|- Журналы: научные, научно-популярные, радио и др."); caps.Categories.AddCategoryMapping(919, NewznabStandardCategory.Books, "Ноты и Музыкальная литература"); caps.Categories.AddCategoryMapping(944, NewznabStandardCategory.Books, "|- Академическая музыка (Ноты и Media CD)"); - caps.Categories.AddCategoryMapping(980, NewznabStandardCategory.Books, "|- Другие направления (Нотытабулатуры)"); + caps.Categories.AddCategoryMapping(980, NewznabStandardCategory.Books, "|- Другие направления (Ноты, табулатуры)"); caps.Categories.AddCategoryMapping(946, NewznabStandardCategory.Books, "|- Самоучители и Школы"); caps.Categories.AddCategoryMapping(977, NewznabStandardCategory.Books, "|- Песенники (Songbooks)"); caps.Categories.AddCategoryMapping(2074, NewznabStandardCategory.Books, "|- Музыкальная литература и Теория"); @@ -548,8 +570,8 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1686, NewznabStandardCategory.Books, "Вера и религия"); caps.Categories.AddCategoryMapping(2215, NewznabStandardCategory.Books, "|- Христианство"); caps.Categories.AddCategoryMapping(2216, NewznabStandardCategory.Books, "|- Ислам"); - caps.Categories.AddCategoryMapping(2217, NewznabStandardCategory.Books, "|- Религии ИндииТибета и Восточной Азии / Иудаизм"); - caps.Categories.AddCategoryMapping(2218, NewznabStandardCategory.Books, "|- Нетрадиционные религиозныедуховные и мистические учения"); + caps.Categories.AddCategoryMapping(2217, NewznabStandardCategory.Books, "|- Религии Индии, Тибета и Восточной Азии / Иудаизм"); + caps.Categories.AddCategoryMapping(2218, NewznabStandardCategory.Books, "|- Нетрадиционные религиозные, духовные и мистические учения"); caps.Categories.AddCategoryMapping(2252, NewznabStandardCategory.Books, "|- Религиоведение. История Религии"); caps.Categories.AddCategoryMapping(2543, NewznabStandardCategory.Books, "|- Атеизм. Научный атеизм"); caps.Categories.AddCategoryMapping(767, NewznabStandardCategory.Books, "Психология"); @@ -561,11 +583,11 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2520, NewznabStandardCategory.Books, "|- Саморазвитие и самосовершенствование"); caps.Categories.AddCategoryMapping(1696, NewznabStandardCategory.Books, "|- Популярная психология"); caps.Categories.AddCategoryMapping(2253, NewznabStandardCategory.Books, "|- Сексология. Взаимоотношения полов (18+)"); - caps.Categories.AddCategoryMapping(2033, NewznabStandardCategory.Books, "Коллекционированиеувлечения и хобби"); + caps.Categories.AddCategoryMapping(2033, NewznabStandardCategory.Books, "Коллекционирование, увлечения и хобби"); caps.Categories.AddCategoryMapping(1412, NewznabStandardCategory.Books, "|- Коллекционирование и вспомогательные ист. дисциплины"); caps.Categories.AddCategoryMapping(1446, NewznabStandardCategory.Books, "|- Вышивание"); caps.Categories.AddCategoryMapping(753, NewznabStandardCategory.Books, "|- Вязание"); - caps.Categories.AddCategoryMapping(2037, NewznabStandardCategory.Books, "|- Шитьепэчворк"); + caps.Categories.AddCategoryMapping(2037, NewznabStandardCategory.Books, "|- Шитье, пэчворк"); caps.Categories.AddCategoryMapping(2224, NewznabStandardCategory.Books, "|- Кружевоплетение"); caps.Categories.AddCategoryMapping(2194, NewznabStandardCategory.Books, "|- Бисероплетение. Ювелирика. Украшения из проволоки."); caps.Categories.AddCategoryMapping(2418, NewznabStandardCategory.Books, "|- Бумажный арт"); @@ -576,7 +598,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2432, NewznabStandardCategory.Books, "|- Кулинария (газеты и журналы)"); caps.Categories.AddCategoryMapping(565, NewznabStandardCategory.Books, "|- Моделизм"); caps.Categories.AddCategoryMapping(1523, NewznabStandardCategory.Books, "|- Приусадебное хозяйство / Цветоводство"); - caps.Categories.AddCategoryMapping(1575, NewznabStandardCategory.Books, "|- Ремонтчастное строительство, дизайн интерьеров"); + caps.Categories.AddCategoryMapping(1575, NewznabStandardCategory.Books, "|- Ремонт, частное строительство, дизайн интерьеров"); caps.Categories.AddCategoryMapping(1520, NewznabStandardCategory.Books, "|- Деревообработка"); caps.Categories.AddCategoryMapping(2424, NewznabStandardCategory.Books, "|- Настольные игры"); caps.Categories.AddCategoryMapping(769, NewznabStandardCategory.Books, "|- Прочие хобби и игры"); @@ -584,28 +606,28 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2043, NewznabStandardCategory.Books, "|- Русская литература"); caps.Categories.AddCategoryMapping(2042, NewznabStandardCategory.Books, "|- Зарубежная литература (до 1900 г.)"); caps.Categories.AddCategoryMapping(2041, NewznabStandardCategory.Books, "|- Зарубежная литература (XX и XXI век)"); - caps.Categories.AddCategoryMapping(2044, NewznabStandardCategory.Books, "|- Детективбоевик"); + caps.Categories.AddCategoryMapping(2044, NewznabStandardCategory.Books, "|- Детектив, боевик"); caps.Categories.AddCategoryMapping(2039, NewznabStandardCategory.Books, "|- Женский роман"); caps.Categories.AddCategoryMapping(2045, NewznabStandardCategory.Books, "|- Отечественная фантастика / фэнтези / мистика"); caps.Categories.AddCategoryMapping(2080, NewznabStandardCategory.Books, "|- Зарубежная фантастика / фэнтези / мистика"); caps.Categories.AddCategoryMapping(2047, NewznabStandardCategory.Books, "|- Приключения"); caps.Categories.AddCategoryMapping(2193, NewznabStandardCategory.Books, "|- Литературные журналы"); - caps.Categories.AddCategoryMapping(1037, NewznabStandardCategory.Books, "|- Самиздат и книгиизданные за счет авторов"); + caps.Categories.AddCategoryMapping(1037, NewznabStandardCategory.Books, "|- Самиздат и книги, изданные за счет авторов"); caps.Categories.AddCategoryMapping(1418, NewznabStandardCategory.BooksTechnical, "Компьютерная литература"); caps.Categories.AddCategoryMapping(1422, NewznabStandardCategory.BooksTechnical, "|- Программы от Microsoft"); caps.Categories.AddCategoryMapping(1423, NewznabStandardCategory.BooksTechnical, "|- Другие программы"); - caps.Categories.AddCategoryMapping(1424, NewznabStandardCategory.BooksTechnical, "|- Mac OS; LinuxFreeBSD и прочие *NIX"); + caps.Categories.AddCategoryMapping(1424, NewznabStandardCategory.BooksTechnical, "|- Mac OS; Linux, FreeBSD и прочие *NIX"); caps.Categories.AddCategoryMapping(1445, NewznabStandardCategory.BooksTechnical, "|- СУБД"); caps.Categories.AddCategoryMapping(1425, NewznabStandardCategory.BooksTechnical, "|- Веб-дизайн и программирование"); caps.Categories.AddCategoryMapping(1426, NewznabStandardCategory.BooksTechnical, "|- Программирование (книги)"); - caps.Categories.AddCategoryMapping(1428, NewznabStandardCategory.BooksTechnical, "|- Графикаобработка видео"); + caps.Categories.AddCategoryMapping(1428, NewznabStandardCategory.BooksTechnical, "|- Графика, обработка видео"); caps.Categories.AddCategoryMapping(1429, NewznabStandardCategory.BooksTechnical, "|- Сети / VoIP"); caps.Categories.AddCategoryMapping(1430, NewznabStandardCategory.BooksTechnical, "|- Хакинг и безопасность"); caps.Categories.AddCategoryMapping(1431, NewznabStandardCategory.BooksTechnical, "|- Железо (книги о ПК)"); caps.Categories.AddCategoryMapping(1433, NewznabStandardCategory.BooksTechnical, "|- Инженерные и научные программы (книги)"); caps.Categories.AddCategoryMapping(1432, NewznabStandardCategory.BooksTechnical, "|- Компьютерные журналы и приложения к ним"); caps.Categories.AddCategoryMapping(2202, NewznabStandardCategory.BooksTechnical, "|- Дисковые приложения к игровым журналам"); - caps.Categories.AddCategoryMapping(862, NewznabStandardCategory.BooksComics, "Комиксыманга, ранобэ"); + caps.Categories.AddCategoryMapping(862, NewznabStandardCategory.BooksComics, "Комиксы, манга, ранобэ"); caps.Categories.AddCategoryMapping(2461, NewznabStandardCategory.BooksComics, "|- Комиксы на русском языке"); caps.Categories.AddCategoryMapping(2462, NewznabStandardCategory.BooksComics, "|- Комиксы издательства Marvel"); caps.Categories.AddCategoryMapping(2463, NewznabStandardCategory.BooksComics, "|- Комиксы издательства DC"); @@ -632,8 +654,8 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2129, NewznabStandardCategory.Books, "|- Медико-биологические науки"); caps.Categories.AddCategoryMapping(2141, NewznabStandardCategory.Books, "|- Фармация и фармакология"); caps.Categories.AddCategoryMapping(2314, NewznabStandardCategory.Books, "|- Популярная медицинская периодика (газеты и журналы)"); - caps.Categories.AddCategoryMapping(2132, NewznabStandardCategory.Books, "|- Нетрадиционнаянародная медицина и популярные книги о здоровье"); - caps.Categories.AddCategoryMapping(2131, NewznabStandardCategory.Books, "|- Ветеринарияразное"); + caps.Categories.AddCategoryMapping(2132, NewznabStandardCategory.Books, "|- Нетрадиционная, народная медицина и популярные книги о здоровье"); + caps.Categories.AddCategoryMapping(2131, NewznabStandardCategory.Books, "|- Ветеринария, разное"); caps.Categories.AddCategoryMapping(2315, NewznabStandardCategory.Books, "|- Тематические коллекции книг"); caps.Categories.AddCategoryMapping(2362, NewznabStandardCategory.BooksEBook, "Иностранные языки для взрослых"); caps.Categories.AddCategoryMapping(1265, NewznabStandardCategory.BooksEBook, "|- Английский язык (для взрослых)"); @@ -655,7 +677,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2358, NewznabStandardCategory.BooksEBook, "|- Английский язык (для детей)"); caps.Categories.AddCategoryMapping(2359, NewznabStandardCategory.BooksEBook, "|- Другие европейские языки (для детей)"); caps.Categories.AddCategoryMapping(2360, NewznabStandardCategory.BooksEBook, "|- Восточные языки (для детей)"); - caps.Categories.AddCategoryMapping(2361, NewznabStandardCategory.BooksEBook, "|- Школьные учебникиЕГЭ"); + caps.Categories.AddCategoryMapping(2361, NewznabStandardCategory.BooksEBook, "|- Школьные учебники, ЕГЭ, ОГЭ"); caps.Categories.AddCategoryMapping(2057, NewznabStandardCategory.BooksEBook, "Художественная литература (ин.языки)"); caps.Categories.AddCategoryMapping(2355, NewznabStandardCategory.BooksEBook, "|- Художественная литература на английском языке"); caps.Categories.AddCategoryMapping(2474, NewznabStandardCategory.BooksEBook, "|- Художественная литература на французском языке"); @@ -683,19 +705,19 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1257, NewznabStandardCategory.BooksOther, "|- Бальные танцы"); caps.Categories.AddCategoryMapping(1258, NewznabStandardCategory.BooksOther, "|- Танец живота"); caps.Categories.AddCategoryMapping(2208, NewznabStandardCategory.BooksOther, "|- Уличные и клубные танцы"); - caps.Categories.AddCategoryMapping(677, NewznabStandardCategory.BooksOther, "|- Танцыразное"); + caps.Categories.AddCategoryMapping(677, NewznabStandardCategory.BooksOther, "|- Танцы, разное"); caps.Categories.AddCategoryMapping(1255, NewznabStandardCategory.BooksOther, "|- Охота"); caps.Categories.AddCategoryMapping(1479, NewznabStandardCategory.BooksOther, "|- Рыболовство и подводная охота"); caps.Categories.AddCategoryMapping(1261, NewznabStandardCategory.BooksOther, "|- Фокусы и трюки"); caps.Categories.AddCategoryMapping(614, NewznabStandardCategory.BooksOther, "|- Образование"); caps.Categories.AddCategoryMapping(1583, NewznabStandardCategory.BooksOther, "|- Финансы"); - caps.Categories.AddCategoryMapping(1259, NewznabStandardCategory.BooksOther, "|- Продажибизнес"); - caps.Categories.AddCategoryMapping(2065, NewznabStandardCategory.BooksOther, "|- Беременностьроды, материнство"); + caps.Categories.AddCategoryMapping(1259, NewznabStandardCategory.BooksOther, "|- Продажи, бизнес"); + caps.Categories.AddCategoryMapping(2065, NewznabStandardCategory.BooksOther, "|- Беременность, роды, материнство"); caps.Categories.AddCategoryMapping(1254, NewznabStandardCategory.BooksOther, "|- Учебные видео для детей"); caps.Categories.AddCategoryMapping(1260, NewznabStandardCategory.BooksOther, "|- Психология"); - caps.Categories.AddCategoryMapping(2209, NewznabStandardCategory.BooksOther, "|- Эзотерикасаморазвитие"); - caps.Categories.AddCategoryMapping(2210, NewznabStandardCategory.BooksOther, "|- Пикапзнакомства"); - caps.Categories.AddCategoryMapping(1547, NewznabStandardCategory.BooksOther, "|- Строительстворемонт и дизайн"); + caps.Categories.AddCategoryMapping(2209, NewznabStandardCategory.BooksOther, "|- Эзотерика, саморазвитие"); + caps.Categories.AddCategoryMapping(2210, NewznabStandardCategory.BooksOther, "|- Пикап, знакомства"); + caps.Categories.AddCategoryMapping(1547, NewznabStandardCategory.BooksOther, "|- Строительство, ремонт и дизайн"); caps.Categories.AddCategoryMapping(1548, NewznabStandardCategory.BooksOther, "|- Дерево- и металлообработка"); caps.Categories.AddCategoryMapping(2211, NewznabStandardCategory.BooksOther, "|- Растения и животные"); caps.Categories.AddCategoryMapping(1596, NewznabStandardCategory.BooksOther, "|- Хобби и рукоделие"); @@ -728,35 +750,35 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1656, NewznabStandardCategory.BooksTechnical, "|- Autodesk 3ds Max"); caps.Categories.AddCategoryMapping(1930, NewznabStandardCategory.BooksTechnical, "|- Autodesk Softimage (XSI)"); caps.Categories.AddCategoryMapping(1931, NewznabStandardCategory.BooksTechnical, "|- ZBrush"); - caps.Categories.AddCategoryMapping(1932, NewznabStandardCategory.BooksTechnical, "|- FlashFlex и ActionScript"); + caps.Categories.AddCategoryMapping(1932, NewznabStandardCategory.BooksTechnical, "|- Flash, Flex и ActionScript"); caps.Categories.AddCategoryMapping(1562, NewznabStandardCategory.BooksTechnical, "|- 2D-графика"); caps.Categories.AddCategoryMapping(1563, NewznabStandardCategory.BooksTechnical, "|- 3D-графика"); caps.Categories.AddCategoryMapping(1626, NewznabStandardCategory.BooksTechnical, "|- Инженерные и научные программы (видеоуроки)"); caps.Categories.AddCategoryMapping(1564, NewznabStandardCategory.BooksTechnical, "|- Web-дизайн"); - caps.Categories.AddCategoryMapping(1545, NewznabStandardCategory.BooksTechnical, "|- WEBSMM, SEO, интернет-маркетинг"); + caps.Categories.AddCategoryMapping(1545, NewznabStandardCategory.BooksTechnical, "|- WEB, SMM, SEO, интернет-маркетинг"); caps.Categories.AddCategoryMapping(1565, NewznabStandardCategory.BooksTechnical, "|- Программирование (видеоуроки)"); caps.Categories.AddCategoryMapping(1559, NewznabStandardCategory.BooksTechnical, "|- Программы для Mac OS"); caps.Categories.AddCategoryMapping(1566, NewznabStandardCategory.BooksTechnical, "|- Работа с видео"); caps.Categories.AddCategoryMapping(1573, NewznabStandardCategory.BooksTechnical, "|- Работа со звуком"); caps.Categories.AddCategoryMapping(1567, NewznabStandardCategory.BooksTechnical, "|- Разное (Компьютерные видеоуроки)"); - caps.Categories.AddCategoryMapping(2326, NewznabStandardCategory.AudioAudiobook, "Радиоспектаклиистория, мемуары"); + caps.Categories.AddCategoryMapping(2326, NewznabStandardCategory.AudioAudiobook, "Радиоспектакли, история, мемуары"); caps.Categories.AddCategoryMapping(574, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Радиоспектакли и литературные чтения"); - caps.Categories.AddCategoryMapping(1036, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Жизнь замечательных людей"); - caps.Categories.AddCategoryMapping(400, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Историякультурология, философия"); - caps.Categories.AddCategoryMapping(2389, NewznabStandardCategory.AudioAudiobook, "Фантастикафэнтези, мистика, ужасы, фанфики"); - caps.Categories.AddCategoryMapping(2388, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Зарубежная фантастикафэнтези, мистика, ужасы, фанфики"); - caps.Categories.AddCategoryMapping(2387, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Российская фантастикафэнтези, мистика, ужасы, фанфики"); + caps.Categories.AddCategoryMapping(1036, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Биографии и мемуары"); + caps.Categories.AddCategoryMapping(400, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] История, культурология, философия"); + caps.Categories.AddCategoryMapping(2389, NewznabStandardCategory.AudioAudiobook, "Фантастика, фэнтези, мистика, ужасы, фанфики"); + caps.Categories.AddCategoryMapping(2388, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Зарубежная фантастика, фэнтези, мистика, ужасы, фанфики"); + caps.Categories.AddCategoryMapping(2387, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Российская фантастика, фэнтези, мистика, ужасы, фанфики"); caps.Categories.AddCategoryMapping(661, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Любовно-фантастический роман"); - caps.Categories.AddCategoryMapping(2348, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Сборники/разное Фантастикафэнтези, мистика, ужасы, фанфи.."); + caps.Categories.AddCategoryMapping(2348, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Сборники/разное Фантастика, фэнтези, мистика, ужасы, фанфики"); caps.Categories.AddCategoryMapping(2327, NewznabStandardCategory.AudioAudiobook, "Художественная литература"); caps.Categories.AddCategoryMapping(695, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Поэзия"); caps.Categories.AddCategoryMapping(399, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Зарубежная литература"); caps.Categories.AddCategoryMapping(402, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Русская литература"); caps.Categories.AddCategoryMapping(467, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Современные любовные романы"); caps.Categories.AddCategoryMapping(490, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Детская литература"); - caps.Categories.AddCategoryMapping(499, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Зарубежные детективыприключения, триллеры, боевики"); - caps.Categories.AddCategoryMapping(2137, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Российские детективыприключения, триллеры, боевики"); - caps.Categories.AddCategoryMapping(2127, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Азиатская подростковая литератураранобэ, веб-новеллы"); + caps.Categories.AddCategoryMapping(499, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Зарубежные детективы, приключения, триллеры, боевики"); + caps.Categories.AddCategoryMapping(2137, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Российские детективы, приключения, триллеры, боевики"); + caps.Categories.AddCategoryMapping(2127, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Азиатская подростковая литература, ранобэ, веб-новеллы"); caps.Categories.AddCategoryMapping(2324, NewznabStandardCategory.AudioAudiobook, "Религии"); caps.Categories.AddCategoryMapping(2325, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Православие"); caps.Categories.AddCategoryMapping(2342, NewznabStandardCategory.AudioAudiobook, "|- [Аудио] Ислам"); @@ -773,10 +795,10 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1973, NewznabStandardCategory.Books, "|- Оригинальные каталоги по подбору запчастей"); caps.Categories.AddCategoryMapping(1974, NewznabStandardCategory.Books, "|- Неоригинальные каталоги по подбору запчастей"); caps.Categories.AddCategoryMapping(1975, NewznabStandardCategory.Books, "|- Программы по диагностике и ремонту"); - caps.Categories.AddCategoryMapping(1976, NewznabStandardCategory.Books, "|- Тюнингчиптюнинг, настройка"); + caps.Categories.AddCategoryMapping(1976, NewznabStandardCategory.Books, "|- Тюнинг, чиптюнинг, настройка"); caps.Categories.AddCategoryMapping(1977, NewznabStandardCategory.Books, "|- Книги по ремонту/обслуживанию/эксплуатации ТС"); caps.Categories.AddCategoryMapping(1203, NewznabStandardCategory.Books, "|- Мультимедийки по ремонту/обслуживанию/эксплуатации ТС"); - caps.Categories.AddCategoryMapping(1978, NewznabStandardCategory.Books, "|- Учетутилиты и прочее"); + caps.Categories.AddCategoryMapping(1978, NewznabStandardCategory.Books, "|- Учет, утилиты и прочее"); caps.Categories.AddCategoryMapping(1979, NewznabStandardCategory.Books, "|- Виртуальная автошкола"); caps.Categories.AddCategoryMapping(1980, NewznabStandardCategory.Books, "|- Видеоуроки по вождению транспортных средств"); caps.Categories.AddCategoryMapping(1981, NewznabStandardCategory.Books, "|- Видеоуроки по ремонту транспортных средств"); @@ -803,54 +825,54 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2309, NewznabStandardCategory.AudioMP3, "|- Вокальная и хоровая музыка (lossy)"); caps.Categories.AddCategoryMapping(2310, NewznabStandardCategory.AudioMP3, "|- Оркестровая музыка (lossy)"); caps.Categories.AddCategoryMapping(2311, NewznabStandardCategory.AudioMP3, "|- Камерная и сольная инструментальная музыка (lossy)"); - caps.Categories.AddCategoryMapping(969, NewznabStandardCategory.Audio, "|- Классика в современной обработкеClassical Crossover (lossy и los.."); - caps.Categories.AddCategoryMapping(1125, NewznabStandardCategory.Audio, "ФольклорНародная и Этническая музыка"); + caps.Categories.AddCategoryMapping(969, NewznabStandardCategory.Audio, "|- Классика в современной обработке, Classical Crossover (lossy и lossless)"); + caps.Categories.AddCategoryMapping(1125, NewznabStandardCategory.Audio, "Фольклор, Народная и Этническая музыка"); caps.Categories.AddCategoryMapping(1130, NewznabStandardCategory.AudioMP3, "|- Восточноевропейский фолк (lossy)"); caps.Categories.AddCategoryMapping(1131, NewznabStandardCategory.AudioLossless, "|- Восточноевропейский фолк (lossless)"); caps.Categories.AddCategoryMapping(1132, NewznabStandardCategory.AudioMP3, "|- Западноевропейский фолк (lossy)"); caps.Categories.AddCategoryMapping(1133, NewznabStandardCategory.AudioLossless, "|- Западноевропейский фолк (lossless)"); caps.Categories.AddCategoryMapping(2084, NewznabStandardCategory.Audio, "|- Klezmer и Еврейский фольклор (lossy и lossless)"); - caps.Categories.AddCategoryMapping(1128, NewznabStandardCategory.AudioMP3, "|- Этническая музыка СибириСредней и Восточной Азии (lossy)"); - caps.Categories.AddCategoryMapping(1129, NewznabStandardCategory.AudioLossless, "|- Этническая музыка СибириСредней и Восточной Азии (lossless)"); + caps.Categories.AddCategoryMapping(1128, NewznabStandardCategory.AudioMP3, "|- Этническая музыка Сибири, Средней и Восточной Азии (lossy)"); + caps.Categories.AddCategoryMapping(1129, NewznabStandardCategory.AudioLossless, "|- Этническая музыка Сибири, Средней и Восточной Азии (lossless)"); caps.Categories.AddCategoryMapping(1856, NewznabStandardCategory.AudioMP3, "|- Этническая музыка Индии (lossy)"); caps.Categories.AddCategoryMapping(2430, NewznabStandardCategory.AudioLossless, "|- Этническая музыка Индии (lossless)"); caps.Categories.AddCategoryMapping(1283, NewznabStandardCategory.AudioMP3, "|- Этническая музыка Африки и Ближнего Востока (lossy)"); caps.Categories.AddCategoryMapping(2085, NewznabStandardCategory.AudioLossless, "|- Этническая музыка Африки и Ближнего Востока (lossless)"); - caps.Categories.AddCategoryMapping(1282, NewznabStandardCategory.Audio, "|- ФольклорнаяНародная, Эстрадная музыка Кавказа и Закавказья (loss.."); + caps.Categories.AddCategoryMapping(1282, NewznabStandardCategory.Audio, "|- Фольклорная, Народная, Эстрадная музыка Кавказа и Закавказья (lossless)"); caps.Categories.AddCategoryMapping(1284, NewznabStandardCategory.AudioMP3, "|- Этническая музыка Северной и Южной Америки (lossy)"); caps.Categories.AddCategoryMapping(1285, NewznabStandardCategory.AudioLossless, "|- Этническая музыка Северной и Южной Америки (lossless)"); - caps.Categories.AddCategoryMapping(1138, NewznabStandardCategory.Audio, "|- Этническая музыка АвстралииТихого и Индийского океанов (lossy и .."); - caps.Categories.AddCategoryMapping(1136, NewznabStandardCategory.AudioMP3, "|- CountryBluegrass (lossy)"); - caps.Categories.AddCategoryMapping(1137, NewznabStandardCategory.AudioLossless, "|- CountryBluegrass (lossless)"); - caps.Categories.AddCategoryMapping(1849, NewznabStandardCategory.Audio, "New AgeRelax, Meditative & Flamenco"); + caps.Categories.AddCategoryMapping(1138, NewznabStandardCategory.Audio, "|- Этническая музыка Австралии, Тихого и Индийского океанов (lossy и lossless)"); + caps.Categories.AddCategoryMapping(1136, NewznabStandardCategory.AudioMP3, "|- Country, Bluegrass (lossy)"); + caps.Categories.AddCategoryMapping(1137, NewznabStandardCategory.AudioLossless, "|- Country, Bluegrass (lossless)"); + caps.Categories.AddCategoryMapping(1849, NewznabStandardCategory.Audio, "New Age, Relax, Meditative & Flamenco"); caps.Categories.AddCategoryMapping(1126, NewznabStandardCategory.AudioMP3, "|- New Age & Meditative (lossy)"); caps.Categories.AddCategoryMapping(1127, NewznabStandardCategory.AudioLossless, "|- New Age & Meditative (lossless)"); caps.Categories.AddCategoryMapping(1134, NewznabStandardCategory.AudioMP3, "|- Фламенко и акустическая гитара (lossy)"); caps.Categories.AddCategoryMapping(1135, NewznabStandardCategory.AudioLossless, "|- Фламенко и акустическая гитара (lossless)"); caps.Categories.AddCategoryMapping(2018, NewznabStandardCategory.Audio, "|- Музыка для бальных танцев (lossy и lossless)"); caps.Categories.AddCategoryMapping(855, NewznabStandardCategory.Audio, "|- Звуки природы"); - caps.Categories.AddCategoryMapping(408, NewznabStandardCategory.Audio, "РэпХип-Хоп, R'n'B"); - caps.Categories.AddCategoryMapping(441, NewznabStandardCategory.AudioMP3, "|- Отечественный РэпХип-Хоп (lossy)"); + caps.Categories.AddCategoryMapping(408, NewznabStandardCategory.Audio, "Рэп, Хип-Хоп, R'n'B"); + caps.Categories.AddCategoryMapping(441, NewznabStandardCategory.AudioMP3, "|- Отечественный Рэп, Хип-Хоп (lossy)"); caps.Categories.AddCategoryMapping(1173, NewznabStandardCategory.AudioMP3, "|- Отечественный R'n'B (lossy)"); - caps.Categories.AddCategoryMapping(1486, NewznabStandardCategory.AudioLossless, "|- Отечественный РэпХип-Хоп, R'n'B (lossless)"); + caps.Categories.AddCategoryMapping(1486, NewznabStandardCategory.AudioLossless, "|- Отечественный Рэп, Хип-Хоп, R'n'B (lossless)"); caps.Categories.AddCategoryMapping(1172, NewznabStandardCategory.AudioMP3, "|- Зарубежный R'n'B (lossy)"); - caps.Categories.AddCategoryMapping(446, NewznabStandardCategory.AudioMP3, "|- Зарубежный РэпХип-Хоп (lossy)"); - caps.Categories.AddCategoryMapping(909, NewznabStandardCategory.AudioLossless, "|- Зарубежный РэпХип-Хоп (lossless)"); + caps.Categories.AddCategoryMapping(446, NewznabStandardCategory.AudioMP3, "|- Зарубежный Рэп, Хип-Хоп (lossy)"); + caps.Categories.AddCategoryMapping(909, NewznabStandardCategory.AudioLossless, "|- Зарубежный Рэп, Хип-Хоп (lossless)"); caps.Categories.AddCategoryMapping(1665, NewznabStandardCategory.AudioLossless, "|- Зарубежный R'n'B (lossless)"); - caps.Categories.AddCategoryMapping(1760, NewznabStandardCategory.Audio, "ReggaeSka, Dub"); - caps.Categories.AddCategoryMapping(1764, NewznabStandardCategory.Audio, "|- RocksteadyEarly Reggae, Ska-Jazz, Trad.Ska (lossy и lossless)"); + caps.Categories.AddCategoryMapping(1760, NewznabStandardCategory.Audio, "Reggae, Ska, Dub"); + caps.Categories.AddCategoryMapping(1764, NewznabStandardCategory.Audio, "|- Rocksteady, Early Reggae, Ska-Jazz, Trad.Ska (lossy и lossless)"); caps.Categories.AddCategoryMapping(1767, NewznabStandardCategory.AudioMP3, "|- 3rd Wave Ska (lossy)"); - caps.Categories.AddCategoryMapping(1769, NewznabStandardCategory.AudioMP3, "|- Ska-PunkSka-Core (lossy)"); + caps.Categories.AddCategoryMapping(1769, NewznabStandardCategory.AudioMP3, "|- Ska-Punk, Ska-Core (lossy)"); caps.Categories.AddCategoryMapping(1765, NewznabStandardCategory.AudioMP3, "|- Reggae (lossy)"); caps.Categories.AddCategoryMapping(1771, NewznabStandardCategory.AudioMP3, "|- Dub (lossy)"); - caps.Categories.AddCategoryMapping(1770, NewznabStandardCategory.AudioMP3, "|- DancehallRaggamuffin (lossy)"); - caps.Categories.AddCategoryMapping(1768, NewznabStandardCategory.AudioLossless, "|- ReggaeDancehall, Dub (lossless)"); - caps.Categories.AddCategoryMapping(1774, NewznabStandardCategory.AudioLossless, "|- SkaSka-Punk, Ska-Jazz (lossless)"); - caps.Categories.AddCategoryMapping(1772, NewznabStandardCategory.Audio, "|- Отечественный ReggaeDub (lossy и lossless)"); + caps.Categories.AddCategoryMapping(1770, NewznabStandardCategory.AudioMP3, "|- Dancehall, Raggamuffin (lossy)"); + caps.Categories.AddCategoryMapping(1768, NewznabStandardCategory.AudioLossless, "|- Reggae, Dancehall, Dub (lossless)"); + caps.Categories.AddCategoryMapping(1774, NewznabStandardCategory.AudioLossless, "|- Ska, Ska-Punk, Ska-Jazz (lossless)"); + caps.Categories.AddCategoryMapping(1772, NewznabStandardCategory.Audio, "|- Отечественный Reggae, Dub (lossy и lossless)"); caps.Categories.AddCategoryMapping(1773, NewznabStandardCategory.Audio, "|- Отечественная Ska музыка (lossy и lossless)"); - caps.Categories.AddCategoryMapping(2233, NewznabStandardCategory.Audio, "|- ReggaeSka, Dub (компиляции) (lossy и lossless)"); - caps.Categories.AddCategoryMapping(416, NewznabStandardCategory.Audio, "Саундтрекикараоке и мюзиклы"); - caps.Categories.AddCategoryMapping(2377, NewznabStandardCategory.AudioVideo, "|- Караоке (видео)"); + caps.Categories.AddCategoryMapping(2233, NewznabStandardCategory.Audio, "|- Reggae, Ska, Dub (компиляции) (lossy и lossless)"); + caps.Categories.AddCategoryMapping(416, NewznabStandardCategory.Audio, "Саундтреки, караоке и мюзиклы"); + caps.Categories.AddCategoryMapping(2377, NewznabStandardCategory.AudioVideo, "|- Караоке"); caps.Categories.AddCategoryMapping(468, NewznabStandardCategory.Audio, "|- Минусовки (lossy и lossless)"); caps.Categories.AddCategoryMapping(691, NewznabStandardCategory.AudioLossless, "|- Саундтреки к отечественным фильмам (lossless)"); caps.Categories.AddCategoryMapping(469, NewznabStandardCategory.AudioMP3, "|- Саундтреки к отечественным фильмам (lossy)"); @@ -867,23 +889,23 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2331, NewznabStandardCategory.AudioMP3, "|- Неофициальные саундтреки к играм (lossy)"); caps.Categories.AddCategoryMapping(2431, NewznabStandardCategory.Audio, "|- Аранжировки музыки из игр (lossy и lossless)"); caps.Categories.AddCategoryMapping(880, NewznabStandardCategory.Audio, "|- Мюзикл (lossy и lossless)"); - caps.Categories.AddCategoryMapping(1215, NewznabStandardCategory.Audio, "ШансонАвторская и Военная песня"); + caps.Categories.AddCategoryMapping(1215, NewznabStandardCategory.Audio, "Шансон, Авторская и Военная песня"); caps.Categories.AddCategoryMapping(1220, NewznabStandardCategory.AudioLossless, "|- Отечественный шансон (lossless)"); caps.Categories.AddCategoryMapping(1221, NewznabStandardCategory.AudioMP3, "|- Отечественный шансон (lossy)"); caps.Categories.AddCategoryMapping(1334, NewznabStandardCategory.AudioMP3, "|- Сборники отечественного шансона (lossy)"); - caps.Categories.AddCategoryMapping(1216, NewznabStandardCategory.AudioLossless, "|- Военная песнямарши (lossless)"); - caps.Categories.AddCategoryMapping(1223, NewznabStandardCategory.AudioMP3, "|- Военная песнямарши (lossy)"); + caps.Categories.AddCategoryMapping(1216, NewznabStandardCategory.AudioLossless, "|- Военная песня, марши (lossless)"); + caps.Categories.AddCategoryMapping(1223, NewznabStandardCategory.AudioMP3, "|- Военная песня, марши (lossy)"); caps.Categories.AddCategoryMapping(1224, NewznabStandardCategory.AudioLossless, "|- Авторская песня (lossless)"); caps.Categories.AddCategoryMapping(1225, NewznabStandardCategory.AudioMP3, "|- Авторская песня (lossy)"); caps.Categories.AddCategoryMapping(1226, NewznabStandardCategory.Audio, "|- Менестрели и ролевики (lossy и lossless)"); caps.Categories.AddCategoryMapping(1842, NewznabStandardCategory.AudioLossless, "Label Packs (lossless)"); - caps.Categories.AddCategoryMapping(1648, NewznabStandardCategory.AudioMP3, "Label packsScene packs (lossy)"); + caps.Categories.AddCategoryMapping(1648, NewznabStandardCategory.AudioMP3, "Label packs, Scene packs (lossy)"); caps.Categories.AddCategoryMapping(2495, NewznabStandardCategory.Audio, "Отечественная поп-музыка"); - caps.Categories.AddCategoryMapping(424, NewznabStandardCategory.AudioMP3, "|- Отечественная поп-музыка (lossy)"); - caps.Categories.AddCategoryMapping(1361, NewznabStandardCategory.AudioMP3, "|- Отечественная поп-музыка (сборники) (lossy)"); - caps.Categories.AddCategoryMapping(425, NewznabStandardCategory.AudioLossless, "|- Отечественная поп-музыка (lossless)"); - caps.Categories.AddCategoryMapping(1635, NewznabStandardCategory.AudioMP3, "|- Советская эстрадаретро, романсы (lossy)"); - caps.Categories.AddCategoryMapping(1634, NewznabStandardCategory.AudioLossless, "|- Советская эстрадаретро, романсы (lossless)"); + caps.Categories.AddCategoryMapping(424, NewznabStandardCategory.AudioMP3, "|- Популярная музыка России и стран бывшего СССР (lossy)"); + caps.Categories.AddCategoryMapping(1361, NewznabStandardCategory.AudioMP3, "|- Популярная музыка России и стран бывшего СССР (сборники) (lossy)"); + caps.Categories.AddCategoryMapping(425, NewznabStandardCategory.AudioLossless, "|- Популярная музыка России и стран бывшего СССР (lossless)"); + caps.Categories.AddCategoryMapping(1635, NewznabStandardCategory.AudioMP3, "|- Советская эстрада, ретро, романсы (lossy)"); + caps.Categories.AddCategoryMapping(1634, NewznabStandardCategory.AudioLossless, "|- Советская эстрада, ретро, романсы (lossless)"); caps.Categories.AddCategoryMapping(2497, NewznabStandardCategory.Audio, "Зарубежная поп-музыка"); caps.Categories.AddCategoryMapping(428, NewznabStandardCategory.AudioMP3, "|- Зарубежная поп-музыка (lossy)"); caps.Categories.AddCategoryMapping(1362, NewznabStandardCategory.AudioMP3, "|- Зарубежная поп-музыка (сборники) (lossy)"); @@ -896,33 +918,33 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1330, NewznabStandardCategory.AudioLossless, "|- Восточноазиатская поп-музыка (lossless)"); caps.Categories.AddCategoryMapping(1219, NewznabStandardCategory.AudioMP3, "|- Зарубежный шансон (lossy)"); caps.Categories.AddCategoryMapping(1452, NewznabStandardCategory.AudioLossless, "|- Зарубежный шансон (lossless)"); - caps.Categories.AddCategoryMapping(2275, NewznabStandardCategory.AudioMP3, "|- Easy ListeningInstrumental Pop (lossy)"); - caps.Categories.AddCategoryMapping(2270, NewznabStandardCategory.AudioLossless, "|- Easy ListeningInstrumental Pop (lossless)"); + caps.Categories.AddCategoryMapping(2275, NewznabStandardCategory.AudioMP3, "|- Easy Listening, Instrumental Pop (lossy)"); + caps.Categories.AddCategoryMapping(2270, NewznabStandardCategory.AudioLossless, "|- Easy Listening, Instrumental Pop (lossless)"); caps.Categories.AddCategoryMapping(1351, NewznabStandardCategory.Audio, "|- Сборники песен для детей (lossy и lossless)"); - caps.Categories.AddCategoryMapping(2499, NewznabStandardCategory.Audio, "EurodanceDisco, Hi-NRG"); - caps.Categories.AddCategoryMapping(2503, NewznabStandardCategory.AudioMP3, "|- EurodanceEuro-House, Technopop (lossy)"); - caps.Categories.AddCategoryMapping(2504, NewznabStandardCategory.AudioMP3, "|- EurodanceEuro-House, Technopop (сборники) (lossy)"); - caps.Categories.AddCategoryMapping(2502, NewznabStandardCategory.AudioLossless, "|- EurodanceEuro-House, Technopop (lossless)"); - caps.Categories.AddCategoryMapping(2501, NewznabStandardCategory.AudioMP3, "|- DiscoItalo-Disco, Euro-Disco, Hi-NRG (lossy)"); - caps.Categories.AddCategoryMapping(2505, NewznabStandardCategory.AudioMP3, "|- DiscoItalo-Disco, Euro-Disco, Hi-NRG (сборники) (lossy)"); - caps.Categories.AddCategoryMapping(2500, NewznabStandardCategory.AudioLossless, "|- DiscoItalo-Disco, Euro-Disco, Hi-NRG (lossless)"); + caps.Categories.AddCategoryMapping(2499, NewznabStandardCategory.Audio, "Eurodance, Disco, Hi-NRG"); + caps.Categories.AddCategoryMapping(2503, NewznabStandardCategory.AudioMP3, "|- Eurodance, Euro-House, Technopop (lossy)"); + caps.Categories.AddCategoryMapping(2504, NewznabStandardCategory.AudioMP3, "|- Eurodance, Euro-House, Technopop (сборники) (lossy)"); + caps.Categories.AddCategoryMapping(2502, NewznabStandardCategory.AudioLossless, "|- Eurodance, Euro-House, Technopop (lossless)"); + caps.Categories.AddCategoryMapping(2501, NewznabStandardCategory.AudioMP3, "|- Disco, Italo-Disco, Euro-Disco, Hi-NRG (lossy)"); + caps.Categories.AddCategoryMapping(2505, NewznabStandardCategory.AudioMP3, "|- Disco, Italo-Disco, Euro-Disco, Hi-NRG (сборники) (lossy)"); + caps.Categories.AddCategoryMapping(2500, NewznabStandardCategory.AudioLossless, "|- Disco, Italo-Disco, Euro-Disco, Hi-NRG (lossless)"); caps.Categories.AddCategoryMapping(2267, NewznabStandardCategory.Audio, "Зарубежный джаз"); - caps.Categories.AddCategoryMapping(2277, NewznabStandardCategory.AudioLossless, "|- Early JazzSwing, Gypsy (lossless)"); + caps.Categories.AddCategoryMapping(2277, NewznabStandardCategory.AudioLossless, "|- Early Jazz, Swing, Gypsy (lossless)"); caps.Categories.AddCategoryMapping(2278, NewznabStandardCategory.AudioLossless, "|- Bop (lossless)"); - caps.Categories.AddCategoryMapping(2279, NewznabStandardCategory.AudioLossless, "|- Mainstream JazzCool (lossless)"); + caps.Categories.AddCategoryMapping(2279, NewznabStandardCategory.AudioLossless, "|- Mainstream Jazz, Cool (lossless)"); caps.Categories.AddCategoryMapping(2280, NewznabStandardCategory.AudioLossless, "|- Jazz Fusion (lossless)"); - caps.Categories.AddCategoryMapping(2281, NewznabStandardCategory.AudioLossless, "|- World FusionEthnic Jazz (lossless)"); - caps.Categories.AddCategoryMapping(2282, NewznabStandardCategory.AudioLossless, "|- Avant-Garde JazzFree Improvisation (lossless)"); - caps.Categories.AddCategoryMapping(2353, NewznabStandardCategory.AudioLossless, "|- Modern CreativeThird Stream (lossless)"); - caps.Categories.AddCategoryMapping(2284, NewznabStandardCategory.AudioLossless, "|- SmoothJazz-Pop (lossless)"); + caps.Categories.AddCategoryMapping(2281, NewznabStandardCategory.AudioLossless, "|- World Fusion, Ethnic Jazz (lossless)"); + caps.Categories.AddCategoryMapping(2282, NewznabStandardCategory.AudioLossless, "|- Avant-Garde Jazz, Free Improvisation (lossless)"); + caps.Categories.AddCategoryMapping(2353, NewznabStandardCategory.AudioLossless, "|- Modern Creative, Third Stream (lossless)"); + caps.Categories.AddCategoryMapping(2284, NewznabStandardCategory.AudioLossless, "|- Smooth, Jazz-Pop (lossless)"); caps.Categories.AddCategoryMapping(2285, NewznabStandardCategory.AudioLossless, "|- Vocal Jazz (lossless)"); - caps.Categories.AddCategoryMapping(2283, NewznabStandardCategory.AudioLossless, "|- FunkSoul, R&B (lossless)"); + caps.Categories.AddCategoryMapping(2283, NewznabStandardCategory.AudioLossless, "|- Funk, Soul, R&B (lossless)"); caps.Categories.AddCategoryMapping(2286, NewznabStandardCategory.AudioLossless, "|- Сборники зарубежного джаза (lossless)"); caps.Categories.AddCategoryMapping(2287, NewznabStandardCategory.AudioMP3, "|- Зарубежный джаз (lossy)"); caps.Categories.AddCategoryMapping(2268, NewznabStandardCategory.Audio, "Зарубежный блюз"); - caps.Categories.AddCategoryMapping(2293, NewznabStandardCategory.AudioLossless, "|- Blues (TexasChicago, Modern and Others) (lossless)"); + caps.Categories.AddCategoryMapping(2293, NewznabStandardCategory.AudioLossless, "|- Blues (Texas, Chicago, Modern and Others) (lossless)"); caps.Categories.AddCategoryMapping(2292, NewznabStandardCategory.AudioLossless, "|- Blues-rock (lossless)"); - caps.Categories.AddCategoryMapping(2290, NewznabStandardCategory.AudioLossless, "|- RootsPre-War Blues, Early R&B, Gospel (lossless)"); + caps.Categories.AddCategoryMapping(2290, NewznabStandardCategory.AudioLossless, "|- Roots, Pre-War Blues, Early R&B, Gospel (lossless)"); caps.Categories.AddCategoryMapping(2289, NewznabStandardCategory.AudioLossless, "|- Зарубежный блюз (сборники; Tribute VA) (lossless)"); caps.Categories.AddCategoryMapping(2288, NewznabStandardCategory.AudioMP3, "|- Зарубежный блюз (lossy)"); caps.Categories.AddCategoryMapping(2269, NewznabStandardCategory.Audio, "Отечественный джаз и блюз"); @@ -937,132 +959,132 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1705, NewznabStandardCategory.AudioMP3, "|- Progressive & Art-Rock (lossy)"); caps.Categories.AddCategoryMapping(1706, NewznabStandardCategory.AudioLossless, "|- Folk-Rock (lossless)"); caps.Categories.AddCategoryMapping(1707, NewznabStandardCategory.AudioMP3, "|- Folk-Rock (lossy)"); - caps.Categories.AddCategoryMapping(2329, NewznabStandardCategory.AudioLossless, "|- AOR (Melodic Hard RockArena rock) (lossless)"); - caps.Categories.AddCategoryMapping(2330, NewznabStandardCategory.AudioMP3, "|- AOR (Melodic Hard RockArena rock) (lossy)"); + caps.Categories.AddCategoryMapping(2329, NewznabStandardCategory.AudioLossless, "|- AOR (Melodic Hard Rock, Arena rock) (lossless)"); + caps.Categories.AddCategoryMapping(2330, NewznabStandardCategory.AudioMP3, "|- AOR (Melodic Hard Rock, Arena rock) (lossy)"); caps.Categories.AddCategoryMapping(1708, NewznabStandardCategory.AudioLossless, "|- Pop-Rock & Soft Rock (lossless)"); caps.Categories.AddCategoryMapping(1709, NewznabStandardCategory.AudioMP3, "|- Pop-Rock & Soft Rock (lossy)"); caps.Categories.AddCategoryMapping(1710, NewznabStandardCategory.AudioLossless, "|- Instrumental Guitar Rock (lossless)"); caps.Categories.AddCategoryMapping(1711, NewznabStandardCategory.AudioMP3, "|- Instrumental Guitar Rock (lossy)"); - caps.Categories.AddCategoryMapping(1712, NewznabStandardCategory.AudioLossless, "|- RockabillyPsychobilly, Rock'n'Roll (lossless)"); - caps.Categories.AddCategoryMapping(1713, NewznabStandardCategory.AudioMP3, "|- RockabillyPsychobilly, Rock'n'Roll (lossy)"); + caps.Categories.AddCategoryMapping(1712, NewznabStandardCategory.AudioLossless, "|- Rockabilly, Psychobilly, Rock'n'Roll (lossless)"); + caps.Categories.AddCategoryMapping(1713, NewznabStandardCategory.AudioMP3, "|- Rockabilly, Psychobilly, Rock'n'Roll (lossy)"); caps.Categories.AddCategoryMapping(731, NewznabStandardCategory.AudioLossless, "|- Сборники зарубежного рока (lossless)"); caps.Categories.AddCategoryMapping(1799, NewznabStandardCategory.AudioMP3, "|- Сборники зарубежного рока (lossy)"); caps.Categories.AddCategoryMapping(1714, NewznabStandardCategory.AudioLossless, "|- Восточноазиатский рок (lossless)"); caps.Categories.AddCategoryMapping(1715, NewznabStandardCategory.AudioMP3, "|- Восточноазиатский рок (lossy)"); caps.Categories.AddCategoryMapping(1716, NewznabStandardCategory.Audio, "Зарубежный Metal"); - caps.Categories.AddCategoryMapping(1796, NewznabStandardCategory.AudioLossless, "|- Avant-gardeExperimental Metal (lossless)"); - caps.Categories.AddCategoryMapping(1797, NewznabStandardCategory.AudioMP3, "|- Avant-gardeExperimental Metal (lossy)"); + caps.Categories.AddCategoryMapping(1796, NewznabStandardCategory.AudioLossless, "|- Avant-garde, Experimental Metal (lossless)"); + caps.Categories.AddCategoryMapping(1797, NewznabStandardCategory.AudioMP3, "|- Avant-garde, Experimental Metal (lossy)"); caps.Categories.AddCategoryMapping(1719, NewznabStandardCategory.AudioLossless, "|- Black (lossless)"); caps.Categories.AddCategoryMapping(1778, NewznabStandardCategory.AudioMP3, "|- Black (lossy)"); - caps.Categories.AddCategoryMapping(1779, NewznabStandardCategory.AudioLossless, "|- DeathDoom (lossless)"); - caps.Categories.AddCategoryMapping(1780, NewznabStandardCategory.AudioMP3, "|- DeathDoom (lossy)"); - caps.Categories.AddCategoryMapping(1720, NewznabStandardCategory.AudioLossless, "|- FolkPagan, Viking (lossless)"); - caps.Categories.AddCategoryMapping(798, NewznabStandardCategory.AudioMP3, "|- FolkPagan, Viking (lossy)"); + caps.Categories.AddCategoryMapping(1779, NewznabStandardCategory.AudioLossless, "|- Death, Doom (lossless)"); + caps.Categories.AddCategoryMapping(1780, NewznabStandardCategory.AudioMP3, "|- Death, Doom (lossy)"); + caps.Categories.AddCategoryMapping(1720, NewznabStandardCategory.AudioLossless, "|- Folk, Pagan, Viking (lossless)"); + caps.Categories.AddCategoryMapping(798, NewznabStandardCategory.AudioMP3, "|- Folk, Pagan, Viking (lossy)"); caps.Categories.AddCategoryMapping(1724, NewznabStandardCategory.AudioLossless, "|- Gothic Metal (lossless)"); caps.Categories.AddCategoryMapping(1725, NewznabStandardCategory.AudioMP3, "|- Gothic Metal (lossy)"); - caps.Categories.AddCategoryMapping(1730, NewznabStandardCategory.AudioLossless, "|- GrindBrutal Death (lossless)"); - caps.Categories.AddCategoryMapping(1731, NewznabStandardCategory.AudioMP3, "|- GrindBrutal Death (lossy)"); - caps.Categories.AddCategoryMapping(1726, NewznabStandardCategory.AudioLossless, "|- HeavyPower, Progressive (lossless)"); - caps.Categories.AddCategoryMapping(1727, NewznabStandardCategory.AudioMP3, "|- HeavyPower, Progressive (lossy)"); - caps.Categories.AddCategoryMapping(1815, NewznabStandardCategory.AudioLossless, "|- SludgeStoner, Post-Metal (lossless)"); - caps.Categories.AddCategoryMapping(1816, NewznabStandardCategory.AudioMP3, "|- SludgeStoner, Post-Metal (lossy)"); - caps.Categories.AddCategoryMapping(1728, NewznabStandardCategory.AudioLossless, "|- ThrashSpeed (lossless)"); - caps.Categories.AddCategoryMapping(1729, NewznabStandardCategory.AudioMP3, "|- ThrashSpeed (lossy)"); + caps.Categories.AddCategoryMapping(1730, NewznabStandardCategory.AudioLossless, "|- Grind, Brutal Death (lossless)"); + caps.Categories.AddCategoryMapping(1731, NewznabStandardCategory.AudioMP3, "|- Grind, Brutal Death (lossy)"); + caps.Categories.AddCategoryMapping(1726, NewznabStandardCategory.AudioLossless, "|- Heavy, Power, Progressive (lossless)"); + caps.Categories.AddCategoryMapping(1727, NewznabStandardCategory.AudioMP3, "|- Heavy, Power, Progressive (lossy)"); + caps.Categories.AddCategoryMapping(1815, NewznabStandardCategory.AudioLossless, "|- Sludge, Stoner, Post-Metal (lossless)"); + caps.Categories.AddCategoryMapping(1816, NewznabStandardCategory.AudioMP3, "|- Sludge, Stoner, Post-Metal (lossy)"); + caps.Categories.AddCategoryMapping(1728, NewznabStandardCategory.AudioLossless, "|- Thrash, Speed (lossless)"); + caps.Categories.AddCategoryMapping(1729, NewznabStandardCategory.AudioMP3, "|- Thrash, Speed (lossy)"); caps.Categories.AddCategoryMapping(2230, NewznabStandardCategory.AudioLossless, "|- Сборники (lossless)"); caps.Categories.AddCategoryMapping(2231, NewznabStandardCategory.AudioMP3, "|- Сборники (lossy)"); - caps.Categories.AddCategoryMapping(1732, NewznabStandardCategory.Audio, "Зарубежные AlternativePunk, Independent"); + caps.Categories.AddCategoryMapping(1732, NewznabStandardCategory.Audio, "Зарубежные Alternative, Punk, Independent"); caps.Categories.AddCategoryMapping(1736, NewznabStandardCategory.AudioLossless, "|- Alternative & Nu-metal (lossless)"); caps.Categories.AddCategoryMapping(1737, NewznabStandardCategory.AudioMP3, "|- Alternative & Nu-metal (lossy)"); caps.Categories.AddCategoryMapping(1738, NewznabStandardCategory.AudioLossless, "|- Punk (lossless)"); caps.Categories.AddCategoryMapping(1739, NewznabStandardCategory.AudioMP3, "|- Punk (lossy)"); caps.Categories.AddCategoryMapping(1740, NewznabStandardCategory.AudioLossless, "|- Hardcore (lossless)"); caps.Categories.AddCategoryMapping(1741, NewznabStandardCategory.AudioMP3, "|- Hardcore (lossy)"); - caps.Categories.AddCategoryMapping(1742, NewznabStandardCategory.AudioLossless, "|- IndiePost-Rock & Post-Punk (lossless)"); - caps.Categories.AddCategoryMapping(1743, NewznabStandardCategory.AudioMP3, "|- IndiePost-Rock & Post-Punk (lossy)"); + caps.Categories.AddCategoryMapping(1742, NewznabStandardCategory.AudioLossless, "|- Indie, Post-Rock & Post-Punk (lossless)"); + caps.Categories.AddCategoryMapping(1743, NewznabStandardCategory.AudioMP3, "|- Indie, Post-Rock & Post-Punk (lossy)"); caps.Categories.AddCategoryMapping(1744, NewznabStandardCategory.AudioLossless, "|- Industrial & Post-industrial (lossless)"); caps.Categories.AddCategoryMapping(1745, NewznabStandardCategory.AudioMP3, "|- Industrial & Post-industrial (lossy)"); - caps.Categories.AddCategoryMapping(1746, NewznabStandardCategory.AudioLossless, "|- EmocorePost-hardcore, Metalcore (lossless)"); - caps.Categories.AddCategoryMapping(1747, NewznabStandardCategory.AudioMP3, "|- EmocorePost-hardcore, Metalcore (lossy)"); + caps.Categories.AddCategoryMapping(1746, NewznabStandardCategory.AudioLossless, "|- Emocore, Post-hardcore, Metalcore (lossless)"); + caps.Categories.AddCategoryMapping(1747, NewznabStandardCategory.AudioMP3, "|- Emocore, Post-hardcore, Metalcore (lossy)"); caps.Categories.AddCategoryMapping(1748, NewznabStandardCategory.AudioLossless, "|- Gothic Rock & Dark Folk (lossless)"); caps.Categories.AddCategoryMapping(1749, NewznabStandardCategory.AudioMP3, "|- Gothic Rock & Dark Folk (lossy)"); - caps.Categories.AddCategoryMapping(2175, NewznabStandardCategory.AudioLossless, "|- Avant-gardeExperimental Rock (lossless)"); - caps.Categories.AddCategoryMapping(2174, NewznabStandardCategory.AudioMP3, "|- Avant-gardeExperimental Rock (lossy)"); - caps.Categories.AddCategoryMapping(722, NewznabStandardCategory.Audio, "Отечественный RockMetal"); + caps.Categories.AddCategoryMapping(2175, NewznabStandardCategory.AudioLossless, "|- Avant-garde, Experimental Rock (lossless)"); + caps.Categories.AddCategoryMapping(2174, NewznabStandardCategory.AudioMP3, "|- Avant-garde, Experimental Rock (lossy)"); + caps.Categories.AddCategoryMapping(722, NewznabStandardCategory.Audio, "Отечественный Rock, Metal"); caps.Categories.AddCategoryMapping(737, NewznabStandardCategory.AudioLossless, "|- Rock (lossless)"); caps.Categories.AddCategoryMapping(738, NewznabStandardCategory.AudioMP3, "|- Rock (lossy)"); - caps.Categories.AddCategoryMapping(464, NewznabStandardCategory.AudioLossless, "|- AlternativePunk, Independent (lossless)"); - caps.Categories.AddCategoryMapping(463, NewznabStandardCategory.AudioMP3, "|- AlternativePunk, Independent (lossy)"); + caps.Categories.AddCategoryMapping(464, NewznabStandardCategory.AudioLossless, "|- Alternative, Punk, Independent (lossless)"); + caps.Categories.AddCategoryMapping(463, NewznabStandardCategory.AudioMP3, "|- Alternative, Punk, Independent (lossy)"); caps.Categories.AddCategoryMapping(739, NewznabStandardCategory.AudioLossless, "|- Metal (lossless)"); caps.Categories.AddCategoryMapping(740, NewznabStandardCategory.AudioMP3, "|- Metal (lossy)"); caps.Categories.AddCategoryMapping(951, NewznabStandardCategory.AudioLossless, "|- Rock на языках народов xUSSR (lossless)"); caps.Categories.AddCategoryMapping(952, NewznabStandardCategory.AudioMP3, "|- Rock на языках народов xUSSR (lossy)"); - caps.Categories.AddCategoryMapping(1821, NewznabStandardCategory.Audio, "TranceGoa Trance, Psy-Trance, PsyChill, Ambient, Dub"); - caps.Categories.AddCategoryMapping(1844, NewznabStandardCategory.AudioLossless, "|- Goa TrancePsy-Trance (lossless)"); - caps.Categories.AddCategoryMapping(1822, NewznabStandardCategory.AudioMP3, "|- Goa TrancePsy-Trance (lossy)"); - caps.Categories.AddCategoryMapping(1894, NewznabStandardCategory.AudioLossless, "|- PsyChillAmbient, Dub (lossless)"); - caps.Categories.AddCategoryMapping(1895, NewznabStandardCategory.AudioMP3, "|- PsyChillAmbient, Dub (lossy)"); - caps.Categories.AddCategoryMapping(460, NewznabStandardCategory.AudioMP3, "|- Goa TrancePsy-Trance, PsyChill, Ambient, Dub (Live Sets, Mixes) .."); + caps.Categories.AddCategoryMapping(1821, NewznabStandardCategory.Audio, "Trance, Goa Trance, Psy-Trance, PsyChill, Ambient, Dub"); + caps.Categories.AddCategoryMapping(1844, NewznabStandardCategory.AudioLossless, "|- Goa Trance, Psy-Trance (lossless)"); + caps.Categories.AddCategoryMapping(1822, NewznabStandardCategory.AudioMP3, "|- Goa Trance, Psy-Trance (lossy)"); + caps.Categories.AddCategoryMapping(1894, NewznabStandardCategory.AudioLossless, "|- PsyChill, Ambient, Dub (lossless)"); + caps.Categories.AddCategoryMapping(1895, NewznabStandardCategory.AudioMP3, "|- PsyChill, Ambient, Dub (lossy)"); + caps.Categories.AddCategoryMapping(460, NewznabStandardCategory.AudioMP3, "|- Goa Trance, Psy-Trance, PsyChill, Ambient, Dub (Live Sets, Mixes) (lossy)"); caps.Categories.AddCategoryMapping(1818, NewznabStandardCategory.AudioLossless, "|- Trance (lossless)"); caps.Categories.AddCategoryMapping(1819, NewznabStandardCategory.AudioMP3, "|- Trance (lossy)"); - caps.Categories.AddCategoryMapping(1847, NewznabStandardCategory.AudioMP3, "|- Trance (SinglesEPs) (lossy)"); - caps.Categories.AddCategoryMapping(1824, NewznabStandardCategory.AudioMP3, "|- Trance (RadioshowsPodcasts, Live Sets, Mixes) (lossy)"); - caps.Categories.AddCategoryMapping(1807, NewznabStandardCategory.Audio, "HouseTechno, Hardcore, Hardstyle, Jumpstyle"); - caps.Categories.AddCategoryMapping(1829, NewznabStandardCategory.AudioLossless, "|- HardcoreHardstyle, Jumpstyle (lossless)"); - caps.Categories.AddCategoryMapping(1830, NewznabStandardCategory.AudioMP3, "|- HardcoreHardstyle, Jumpstyle (lossy)"); - caps.Categories.AddCategoryMapping(1831, NewznabStandardCategory.AudioMP3, "|- HardcoreHardstyle, Jumpstyle (vinyl, web)"); + caps.Categories.AddCategoryMapping(1847, NewznabStandardCategory.AudioMP3, "|- Trance (Singles, EPs) (lossy)"); + caps.Categories.AddCategoryMapping(1824, NewznabStandardCategory.AudioMP3, "|- Trance (Radioshows, Podcasts, Live Sets, Mixes) (lossy)"); + caps.Categories.AddCategoryMapping(1807, NewznabStandardCategory.Audio, "House, Techno, Hardcore, Hardstyle, Jumpstyle"); + caps.Categories.AddCategoryMapping(1829, NewznabStandardCategory.AudioLossless, "|- Hardcore, Hardstyle, Jumpstyle (lossless)"); + caps.Categories.AddCategoryMapping(1830, NewznabStandardCategory.AudioMP3, "|- Hardcore, Hardstyle, Jumpstyle (lossy)"); + caps.Categories.AddCategoryMapping(1831, NewznabStandardCategory.AudioMP3, "|- Hardcore, Hardstyle, Jumpstyle (vinyl, web)"); caps.Categories.AddCategoryMapping(1857, NewznabStandardCategory.AudioLossless, "|- House (lossless)"); - caps.Categories.AddCategoryMapping(1859, NewznabStandardCategory.AudioMP3, "|- House (RadioshowPodcast, Liveset, Mixes)"); + caps.Categories.AddCategoryMapping(1859, NewznabStandardCategory.AudioMP3, "|- House (Radioshow, Podcast, Liveset, Mixes)"); caps.Categories.AddCategoryMapping(1858, NewznabStandardCategory.AudioMP3, "|- House (lossy)"); - caps.Categories.AddCategoryMapping(840, NewznabStandardCategory.AudioMP3, "|- House (Проморелизысборники) (lossy)"); - caps.Categories.AddCategoryMapping(1860, NewznabStandardCategory.AudioMP3, "|- House (SinglesEPs) (lossy)"); + caps.Categories.AddCategoryMapping(840, NewznabStandardCategory.AudioMP3, "|- House (Проморелизы, сборники) (lossy)"); + caps.Categories.AddCategoryMapping(1860, NewznabStandardCategory.AudioMP3, "|- House (Singles, EPs) (lossy)"); caps.Categories.AddCategoryMapping(1825, NewznabStandardCategory.AudioLossless, "|- Techno (lossless)"); caps.Categories.AddCategoryMapping(1826, NewznabStandardCategory.AudioMP3, "|- Techno (lossy)"); - caps.Categories.AddCategoryMapping(1827, NewznabStandardCategory.AudioMP3, "|- Techno (RadioshowsPodcasts, Livesets, Mixes)"); - caps.Categories.AddCategoryMapping(1828, NewznabStandardCategory.AudioMP3, "|- Techno (SinglesEPs) (lossy)"); - caps.Categories.AddCategoryMapping(1808, NewznabStandardCategory.Audio, "Drum & BassJungle, Breakbeat, Dubstep, IDM, Electro"); - caps.Categories.AddCategoryMapping(797, NewznabStandardCategory.AudioLossless, "|- ElectroElectro-Freestyle, Nu Electro (lossless)"); - caps.Categories.AddCategoryMapping(1805, NewznabStandardCategory.AudioMP3, "|- ElectroElectro-Freestyle, Nu Electro (lossy)"); - caps.Categories.AddCategoryMapping(1832, NewznabStandardCategory.AudioLossless, "|- Drum & BassJungle (lossless)"); - caps.Categories.AddCategoryMapping(1833, NewznabStandardCategory.AudioMP3, "|- Drum & BassJungle (lossy)"); - caps.Categories.AddCategoryMapping(1834, NewznabStandardCategory.AudioMP3, "|- Drum & BassJungle (Radioshows, Podcasts, Livesets, Mixes)"); + caps.Categories.AddCategoryMapping(1827, NewznabStandardCategory.AudioMP3, "|- Techno (Radioshows, Podcasts, Livesets, Mixes)"); + caps.Categories.AddCategoryMapping(1828, NewznabStandardCategory.AudioMP3, "|- Techno (Singles, EPs) (lossy)"); + caps.Categories.AddCategoryMapping(1808, NewznabStandardCategory.Audio, "Drum & Bass, Jungle, Breakbeat, Dubstep, IDM, Electro"); + caps.Categories.AddCategoryMapping(797, NewznabStandardCategory.AudioLossless, "|- Electro, Electro-Freestyle, Nu Electro (lossless)"); + caps.Categories.AddCategoryMapping(1805, NewznabStandardCategory.AudioMP3, "|- Electro, Electro-Freestyle, Nu Electro (lossy)"); + caps.Categories.AddCategoryMapping(1832, NewznabStandardCategory.AudioLossless, "|- Drum & Bass, Jungle (lossless)"); + caps.Categories.AddCategoryMapping(1833, NewznabStandardCategory.AudioMP3, "|- Drum & Bass, Jungle (lossy)"); + caps.Categories.AddCategoryMapping(1834, NewznabStandardCategory.AudioMP3, "|- Drum & Bass, Jungle (Radioshows, Podcasts, Livesets, Mixes)"); caps.Categories.AddCategoryMapping(1836, NewznabStandardCategory.AudioLossless, "|- Breakbeat (lossless)"); caps.Categories.AddCategoryMapping(1837, NewznabStandardCategory.AudioMP3, "|- Breakbeat (lossy)"); caps.Categories.AddCategoryMapping(1839, NewznabStandardCategory.AudioLossless, "|- Dubstep (lossless)"); caps.Categories.AddCategoryMapping(454, NewznabStandardCategory.AudioMP3, "|- Dubstep (lossy)"); - caps.Categories.AddCategoryMapping(1838, NewznabStandardCategory.AudioMP3, "|- BreakbeatDubstep (Radioshows, Podcasts, Livesets, Mixes)"); + caps.Categories.AddCategoryMapping(1838, NewznabStandardCategory.AudioMP3, "|- Breakbeat, Dubstep (Radioshows, Podcasts, Livesets, Mixes)"); caps.Categories.AddCategoryMapping(1840, NewznabStandardCategory.AudioLossless, "|- IDM (lossless)"); caps.Categories.AddCategoryMapping(1841, NewznabStandardCategory.AudioMP3, "|- IDM (lossy)"); caps.Categories.AddCategoryMapping(2229, NewznabStandardCategory.AudioMP3, "|- IDM Discography & Collections (lossy)"); - caps.Categories.AddCategoryMapping(1809, NewznabStandardCategory.Audio, "ChilloutLounge, Downtempo, Trip-Hop"); - caps.Categories.AddCategoryMapping(1861, NewznabStandardCategory.AudioLossless, "|- ChilloutLounge, Downtempo (lossless)"); - caps.Categories.AddCategoryMapping(1862, NewznabStandardCategory.AudioMP3, "|- ChilloutLounge, Downtempo (lossy)"); - caps.Categories.AddCategoryMapping(1947, NewznabStandardCategory.AudioLossless, "|- Nu JazzAcid Jazz, Future Jazz (lossless)"); - caps.Categories.AddCategoryMapping(1946, NewznabStandardCategory.AudioMP3, "|- Nu JazzAcid Jazz, Future Jazz (lossy)"); - caps.Categories.AddCategoryMapping(1945, NewznabStandardCategory.AudioLossless, "|- Trip HopAbstract Hip-Hop (lossless)"); - caps.Categories.AddCategoryMapping(1944, NewznabStandardCategory.AudioMP3, "|- Trip HopAbstract Hip-Hop (lossy)"); - caps.Categories.AddCategoryMapping(1810, NewznabStandardCategory.Audio, "Traditional ElectronicAmbient, Modern Classical, Electroacoustic, Ex.."); - caps.Categories.AddCategoryMapping(1864, NewznabStandardCategory.AudioLossless, "|- Traditional ElectronicAmbient (lossless)"); - caps.Categories.AddCategoryMapping(1865, NewznabStandardCategory.AudioMP3, "|- Traditional ElectronicAmbient (lossy)"); - caps.Categories.AddCategoryMapping(1871, NewznabStandardCategory.AudioLossless, "|- Modern ClassicalElectroacoustic (lossless)"); - caps.Categories.AddCategoryMapping(1867, NewznabStandardCategory.AudioMP3, "|- Modern ClassicalElectroacoustic (lossy)"); + caps.Categories.AddCategoryMapping(1809, NewznabStandardCategory.Audio, "Chillout, Lounge, Downtempo, Trip-Hop"); + caps.Categories.AddCategoryMapping(1861, NewznabStandardCategory.AudioLossless, "|- Chillout, Lounge, Downtempo (lossless)"); + caps.Categories.AddCategoryMapping(1862, NewznabStandardCategory.AudioMP3, "|- Chillout, Lounge, Downtempo (lossy)"); + caps.Categories.AddCategoryMapping(1947, NewznabStandardCategory.AudioLossless, "|- Nu Jazz, Acid Jazz, Future Jazz (lossless)"); + caps.Categories.AddCategoryMapping(1946, NewznabStandardCategory.AudioMP3, "|- Nu Jazz, Acid Jazz, Future Jazz (lossy)"); + caps.Categories.AddCategoryMapping(1945, NewznabStandardCategory.AudioLossless, "|- Trip Hop, Abstract Hip-Hop (lossless)"); + caps.Categories.AddCategoryMapping(1944, NewznabStandardCategory.AudioMP3, "|- Trip Hop, Abstract Hip-Hop (lossy)"); + caps.Categories.AddCategoryMapping(1810, NewznabStandardCategory.Audio, "Traditional Electronic, Ambient, Modern Classical, Electroacoustic, Experimental"); + caps.Categories.AddCategoryMapping(1864, NewznabStandardCategory.AudioLossless, "|- Traditional Electronic, Ambient (lossless)"); + caps.Categories.AddCategoryMapping(1865, NewznabStandardCategory.AudioMP3, "|- Traditional Electronic, Ambient (lossy)"); + caps.Categories.AddCategoryMapping(1871, NewznabStandardCategory.AudioLossless, "|- Modern Classical, Electroacoustic (lossless)"); + caps.Categories.AddCategoryMapping(1867, NewznabStandardCategory.AudioMP3, "|- Modern Classical, Electroacoustic (lossy)"); caps.Categories.AddCategoryMapping(1869, NewznabStandardCategory.AudioLossless, "|- Experimental (lossless)"); caps.Categories.AddCategoryMapping(1873, NewznabStandardCategory.AudioMP3, "|- Experimental (lossy)"); - caps.Categories.AddCategoryMapping(1907, NewznabStandardCategory.Audio, "|- 8-bitChiptune (lossy & lossless)"); - caps.Categories.AddCategoryMapping(1811, NewznabStandardCategory.Audio, "IndustrialNoise, EBM, Dark Electro, Aggrotech, Synthpop, New Wave"); - caps.Categories.AddCategoryMapping(1868, NewznabStandardCategory.AudioLossless, "|- EBMDark Electro, Aggrotech (lossless)"); - caps.Categories.AddCategoryMapping(1875, NewznabStandardCategory.AudioMP3, "|- EBMDark Electro, Aggrotech (lossy)"); - caps.Categories.AddCategoryMapping(1877, NewznabStandardCategory.AudioLossless, "|- IndustrialNoise (lossless)"); - caps.Categories.AddCategoryMapping(1878, NewznabStandardCategory.AudioMP3, "|- IndustrialNoise (lossy)"); - caps.Categories.AddCategoryMapping(1880, NewznabStandardCategory.AudioLossless, "|- SynthpopFuturepop, New Wave, Electropop (lossless)"); - caps.Categories.AddCategoryMapping(1881, NewznabStandardCategory.AudioMP3, "|- SynthpopFuturepop, New Wave, Electropop (lossy)"); - caps.Categories.AddCategoryMapping(466, NewznabStandardCategory.AudioLossless, "|- SynthwaveSpacesynth, Dreamwave, Retrowave, Outrun (lossless)"); - caps.Categories.AddCategoryMapping(465, NewznabStandardCategory.AudioMP3, "|- SynthwaveSpacesynth, Dreamwave, Retrowave, Outrun (lossy)"); - caps.Categories.AddCategoryMapping(1866, NewznabStandardCategory.AudioLossless, "|- DarkwaveNeoclassical, Ethereal, Dungeon Synth (lossless)"); - caps.Categories.AddCategoryMapping(406, NewznabStandardCategory.AudioMP3, "|- DarkwaveNeoclassical, Ethereal, Dungeon Synth (lossy)"); + caps.Categories.AddCategoryMapping(1811, NewznabStandardCategory.Audio, "Industrial, Noise, EBM, Dark Electro, Aggrotech, Cyberpunk, Synthpop, New Wave"); + caps.Categories.AddCategoryMapping(1868, NewznabStandardCategory.AudioLossless, "|- EBM, Dark Electro, Aggrotech (lossless)"); + caps.Categories.AddCategoryMapping(1875, NewznabStandardCategory.AudioMP3, "|- EBM, Dark Electro, Aggrotech (lossy)"); + caps.Categories.AddCategoryMapping(1877, NewznabStandardCategory.AudioLossless, "|- Industrial, Noise (lossless)"); + caps.Categories.AddCategoryMapping(1878, NewznabStandardCategory.AudioMP3, "|- Industrial, Noise (lossy)"); + caps.Categories.AddCategoryMapping(1907, NewznabStandardCategory.Audio, "|- Cyberpunk, 8-bit, Chiptune (lossy & lossless)"); + caps.Categories.AddCategoryMapping(1880, NewznabStandardCategory.AudioLossless, "|- Synthpop, Futurepop, New Wave, Electropop (lossless)"); + caps.Categories.AddCategoryMapping(1881, NewznabStandardCategory.AudioMP3, "|- Synthpop, Futurepop, New Wave, Electropop (lossy)"); + caps.Categories.AddCategoryMapping(466, NewznabStandardCategory.AudioLossless, "|- Synthwave, Spacesynth, Dreamwave, Retrowave, Outrun (lossless)"); + caps.Categories.AddCategoryMapping(465, NewznabStandardCategory.AudioMP3, "|- Synthwave, Spacesynth, Dreamwave, Retrowave, Outrun (lossy)"); + caps.Categories.AddCategoryMapping(1866, NewznabStandardCategory.AudioLossless, "|- Darkwave, Neoclassical, Ethereal, Dungeon Synth (lossless)"); + caps.Categories.AddCategoryMapping(406, NewznabStandardCategory.AudioMP3, "|- Darkwave, Neoclassical, Ethereal, Dungeon Synth (lossy)"); caps.Categories.AddCategoryMapping(1299, NewznabStandardCategory.Audio, "Hi-Res stereo и многоканальная музыка"); caps.Categories.AddCategoryMapping(1884, NewznabStandardCategory.Audio, "|- Классика и классика в современной обработке (Hi-Res stereo)"); - caps.Categories.AddCategoryMapping(1164, NewznabStandardCategory.Audio, "|- Классика и классика в современной обработке (многоканальная музыка.."); - caps.Categories.AddCategoryMapping(2513, NewznabStandardCategory.Audio, "|- New AgeRelax, Meditative & Flamenco (Hi-Res stereo и многоканаль.."); + caps.Categories.AddCategoryMapping(1164, NewznabStandardCategory.Audio, "|- Классика и классика в современной обработке (многоканальная музыка)"); + caps.Categories.AddCategoryMapping(2513, NewznabStandardCategory.Audio, "|- New Age, Relax, Meditative & Flamenco (Hi-Res stereo и многоканальная музыка)"); caps.Categories.AddCategoryMapping(1397, NewznabStandardCategory.Audio, "|- Саундтреки (Hi-Res stereo и многоканальная музыка)"); caps.Categories.AddCategoryMapping(2512, NewznabStandardCategory.Audio, "|- Музыка разных жанров (Hi-Res stereo и многоканальная музыка)"); caps.Categories.AddCategoryMapping(1885, NewznabStandardCategory.Audio, "|- Поп-музыка (Hi-Res stereo)"); @@ -1075,80 +1097,81 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1890, NewznabStandardCategory.Audio, "|- Электронная музыка (многоканальная музыка)"); caps.Categories.AddCategoryMapping(2219, NewznabStandardCategory.Audio, "Оцифровки с аналоговых носителей"); caps.Categories.AddCategoryMapping(1660, NewznabStandardCategory.Audio, "|- Классика и классика в современной обработке (оцифровки)"); - caps.Categories.AddCategoryMapping(506, NewznabStandardCategory.Audio, "|- Фольклорнародная и этническая музыка (оцифровки)"); - caps.Categories.AddCategoryMapping(1835, NewznabStandardCategory.Audio, "|- RapHip-Hop, R'n'B, Reggae, Ska, Dub (оцифровки)"); + caps.Categories.AddCategoryMapping(506, NewznabStandardCategory.Audio, "|- Фольклор, народная и этническая музыка (оцифровки)"); + caps.Categories.AddCategoryMapping(1835, NewznabStandardCategory.Audio, "|- Rap, Hip-Hop, R'n'B, Reggae, Ska, Dub (оцифровки)"); caps.Categories.AddCategoryMapping(1625, NewznabStandardCategory.Audio, "|- Саундтреки и мюзиклы (оцифровки)"); - caps.Categories.AddCategoryMapping(1217, NewznabStandardCategory.Audio, "|- Шансонавторские, военные песни и марши (оцифровки)"); + caps.Categories.AddCategoryMapping(1217, NewznabStandardCategory.Audio, "|- Шансон, авторские, военные песни и марши (оцифровки)"); caps.Categories.AddCategoryMapping(974, NewznabStandardCategory.Audio, "|- Музыка других жанров (оцифровки)"); caps.Categories.AddCategoryMapping(1444, NewznabStandardCategory.Audio, "|- Зарубежная поп-музыка (оцифровки)"); - caps.Categories.AddCategoryMapping(2401, NewznabStandardCategory.Audio, "|- Советская эстрадаретро, романсы (оцифровки)"); + caps.Categories.AddCategoryMapping(2401, NewznabStandardCategory.Audio, "|- Советская эстрада, ретро, романсы (оцифровки)"); caps.Categories.AddCategoryMapping(239, NewznabStandardCategory.Audio, "|- Отечественная поп-музыка (оцифровки)"); caps.Categories.AddCategoryMapping(450, NewznabStandardCategory.Audio, "|- Инструментальная поп-музыка (оцифровки)"); caps.Categories.AddCategoryMapping(2301, NewznabStandardCategory.Audio, "|- Джаз и блюз (оцифровки)"); + caps.Categories.AddCategoryMapping(123, NewznabStandardCategory.Audio, "|- Alternative, Punk, Independent (оцифровки)"); caps.Categories.AddCategoryMapping(1756, NewznabStandardCategory.Audio, "|- Зарубежная рок-музыка (оцифровки)"); caps.Categories.AddCategoryMapping(1758, NewznabStandardCategory.Audio, "|- Отечественная рок-музыка (оцифровки)"); - caps.Categories.AddCategoryMapping(1766, NewznabStandardCategory.Audio, "|- Зарубежный Metal (оцифровки)"); + caps.Categories.AddCategoryMapping(1766, NewznabStandardCategory.Audio, "|- Зарубежный и Отечественный Metal (оцифровки)"); caps.Categories.AddCategoryMapping(1754, NewznabStandardCategory.Audio, "|- Электронная музыка (оцифровки)"); caps.Categories.AddCategoryMapping(860, NewznabStandardCategory.Audio, "Неофициальные конверсии цифровых форматов"); caps.Categories.AddCategoryMapping(453, NewznabStandardCategory.Audio, "|- Конверсии Quadraphonic"); caps.Categories.AddCategoryMapping(1170, NewznabStandardCategory.Audio, "|- Конверсии SACD"); - caps.Categories.AddCategoryMapping(1759, NewznabStandardCategory.Audio, "|- Конверсии Blu-RayADVD и DVD-Audio"); + caps.Categories.AddCategoryMapping(1759, NewznabStandardCategory.Audio, "|- Конверсии Blu-Ray, ADVD и DVD-Audio"); caps.Categories.AddCategoryMapping(1852, NewznabStandardCategory.Audio, "|- Апмиксы-Upmixes/Даунмиксы-Downmix"); caps.Categories.AddCategoryMapping(413, NewznabStandardCategory.AudioVideo, "Музыкальное SD видео"); caps.Categories.AddCategoryMapping(445, NewznabStandardCategory.AudioVideo, "|- Классическая и современная академическая музыка (Видео)"); - caps.Categories.AddCategoryMapping(702, NewznabStandardCategory.AudioVideo, "|- ОпераОперетта и Мюзикл (Видео) "); + caps.Categories.AddCategoryMapping(702, NewznabStandardCategory.AudioVideo, "|- Опера, Оперетта и Мюзикл (Видео)"); caps.Categories.AddCategoryMapping(1990, NewznabStandardCategory.AudioVideo, "|- Балет и современная хореография (Видео)"); - caps.Categories.AddCategoryMapping(1793, NewznabStandardCategory.AudioVideo, "|- Классика в современной обработкеical Crossover (Видео)"); - caps.Categories.AddCategoryMapping(1141, NewznabStandardCategory.AudioVideo, "|- ФольклорНародная и Этническая музыка и фламенко (Видео)"); - caps.Categories.AddCategoryMapping(1775, NewznabStandardCategory.AudioVideo, "|- New AgeRelax, Meditative, Рэп, Хип-Хоп, R'n'B, Reggae, Ska, Dub .. "); - caps.Categories.AddCategoryMapping(1227, NewznabStandardCategory.AudioVideo, "|- Зарубежный и Отечественный ШансонАвторская и Военная песня (Виде.."); - caps.Categories.AddCategoryMapping(475, NewznabStandardCategory.AudioVideo, "|- Музыка других жанровСоветская эстрада, ретро, романсы (Видео)"); + caps.Categories.AddCategoryMapping(1793, NewznabStandardCategory.AudioVideo, "|- Классика в современной обработке, Classical Crossover (Видео)"); + caps.Categories.AddCategoryMapping(1141, NewznabStandardCategory.AudioVideo, "|- Фольклор, Народная и Этническая музыка и фламенко (Видео)"); + caps.Categories.AddCategoryMapping(1775, NewznabStandardCategory.AudioVideo, "|- New Age, Relax, Meditative, Рэп, Хип-Хоп, R'n'B, Reggae, Ska, Dub (Видео)"); + caps.Categories.AddCategoryMapping(1227, NewznabStandardCategory.AudioVideo, "|- Зарубежный и Отечественный Шансон, Авторская и Военная песня (Видео)"); + caps.Categories.AddCategoryMapping(475, NewznabStandardCategory.AudioVideo, "|- Музыка других жанров, Советская эстрада, ретро, романсы (Видео)"); caps.Categories.AddCategoryMapping(1121, NewznabStandardCategory.AudioVideo, "|- Отечественная поп-музыка (Видео)"); - caps.Categories.AddCategoryMapping(431, NewznabStandardCategory.AudioVideo, "|- Зарубежная поп-музыка (Видео)"); + caps.Categories.AddCategoryMapping(431, NewznabStandardCategory.AudioVideo, "|- Зарубежная Поп-музыка, Eurodance, Disco (Видео)"); caps.Categories.AddCategoryMapping(2378, NewznabStandardCategory.AudioVideo, "|- Восточноазиатская поп-музыка (Видео)"); - caps.Categories.AddCategoryMapping(2383, NewznabStandardCategory.AudioVideo, "|- Зарубежный шансон (Видео)"); + caps.Categories.AddCategoryMapping(2383, NewznabStandardCategory.AudioVideo, "|- Разножанровые сборные концерты и сборники видеоклипов (Видео)"); caps.Categories.AddCategoryMapping(2305, NewznabStandardCategory.AudioVideo, "|- Джаз и Блюз (Видео)"); caps.Categories.AddCategoryMapping(1782, NewznabStandardCategory.AudioVideo, "|- Rock (Видео)"); caps.Categories.AddCategoryMapping(1787, NewznabStandardCategory.AudioVideo, "|- Metal (Видео)"); - caps.Categories.AddCategoryMapping(1789, NewznabStandardCategory.AudioVideo, "|- AlternativePunk, Independent (Видео)"); - caps.Categories.AddCategoryMapping(1791, NewznabStandardCategory.AudioVideo, "|- Отечественный РокПанк, Альтернатива (Видео)"); + caps.Categories.AddCategoryMapping(1789, NewznabStandardCategory.AudioVideo, "|- Зарубежный Alternative, Punk, Independent (Видео)"); + caps.Categories.AddCategoryMapping(1791, NewznabStandardCategory.AudioVideo, "|- Отечественный Рок, Панк, Альтернатива (Видео)"); caps.Categories.AddCategoryMapping(1912, NewznabStandardCategory.AudioVideo, "|- Электронная музыка (Видео)"); caps.Categories.AddCategoryMapping(1189, NewznabStandardCategory.AudioVideo, "|- Документальные фильмы о музыке и музыкантах (Видео)"); caps.Categories.AddCategoryMapping(2403, NewznabStandardCategory.AudioVideo, "Музыкальное DVD видео"); caps.Categories.AddCategoryMapping(984, NewznabStandardCategory.AudioVideo, "|- Классическая и современная академическая музыка (DVD Video)"); - caps.Categories.AddCategoryMapping(983, NewznabStandardCategory.AudioVideo, "|- ОпераОперетта и Мюзикл (DVD видео)"); + caps.Categories.AddCategoryMapping(983, NewznabStandardCategory.AudioVideo, "|- Опера, Оперетта и Мюзикл (DVD видео)"); caps.Categories.AddCategoryMapping(2352, NewznabStandardCategory.AudioVideo, "|- Балет и современная хореография (DVD Video)"); - caps.Categories.AddCategoryMapping(2384, NewznabStandardCategory.AudioVideo, "|- Классика в современной обработкеical Crossover (DVD Video)"); - caps.Categories.AddCategoryMapping(1142, NewznabStandardCategory.AudioVideo, "|- ФольклорНародная и Этническая музыка и Flamenco (DVD Video)"); - caps.Categories.AddCategoryMapping(1107, NewznabStandardCategory.AudioVideo, "|- New AgeRelax, Meditative, Рэп, Хип-Хоп, R 'n 'B, Reggae, Ska, Dub .."); - caps.Categories.AddCategoryMapping(1228, NewznabStandardCategory.AudioVideo, "|- Зарубежный и Отечественный ШансонАвторская и Военная песня (DVD .."); - caps.Categories.AddCategoryMapping(988, NewznabStandardCategory.AudioVideo, "|- Музыка других жанровСоветская эстрада, ретро, романсы (DVD Video.."); + caps.Categories.AddCategoryMapping(2384, NewznabStandardCategory.AudioVideo, "|- Классика в современной обработке, Classical Crossover (DVD Video)"); + caps.Categories.AddCategoryMapping(1142, NewznabStandardCategory.AudioVideo, "|- Фольклор, Народная и Этническая музыка и Flamenco (DVD Video)"); + caps.Categories.AddCategoryMapping(1107, NewznabStandardCategory.AudioVideo, "|- New Age, Relax, Meditative, Рэп, Хип-Хоп, R'n'B, Reggae, Ska, Dub (DVD Video)"); + caps.Categories.AddCategoryMapping(1228, NewznabStandardCategory.AudioVideo, "|- Зарубежный и Отечественный Шансон, Авторская и Военная песня (DVD Video)"); + caps.Categories.AddCategoryMapping(988, NewznabStandardCategory.AudioVideo, "|- Музыка других жанров, Советская эстрада, ретро, романсы (DVD Video)"); caps.Categories.AddCategoryMapping(1122, NewznabStandardCategory.AudioVideo, "|- Отечественная поп-музыка (DVD Video)"); - caps.Categories.AddCategoryMapping(986, NewznabStandardCategory.AudioVideo, "|- Зарубежная Поп-музыкаEurodance, Disco (DVD Video)"); + caps.Categories.AddCategoryMapping(986, NewznabStandardCategory.AudioVideo, "|- Зарубежная Поп-музыка, Eurodance, Disco (DVD Video)"); caps.Categories.AddCategoryMapping(2379, NewznabStandardCategory.AudioVideo, "|- Восточноазиатская поп-музыка (DVD Video)"); caps.Categories.AddCategoryMapping(2088, NewznabStandardCategory.AudioVideo, "|- Разножанровые сборные концерты и сборники видеоклипов (DVD Video)"); caps.Categories.AddCategoryMapping(2304, NewznabStandardCategory.AudioVideo, "|- Джаз и Блюз (DVD Видео)"); caps.Categories.AddCategoryMapping(1783, NewznabStandardCategory.AudioVideo, "|- Зарубежный Rock (DVD Video)"); caps.Categories.AddCategoryMapping(1788, NewznabStandardCategory.AudioVideo, "|- Зарубежный Metal (DVD Video)"); - caps.Categories.AddCategoryMapping(1790, NewznabStandardCategory.AudioVideo, "|- Зарубежный AlternativePunk, Independent (DVD Video)"); - caps.Categories.AddCategoryMapping(1792, NewznabStandardCategory.AudioVideo, "|- Отечественный РокМетал, Панк, Альтернатива (DVD Video)"); + caps.Categories.AddCategoryMapping(1790, NewznabStandardCategory.AudioVideo, "|- Зарубежный Alternative, Punk, Independent (DVD Video)"); + caps.Categories.AddCategoryMapping(1792, NewznabStandardCategory.AudioVideo, "|- Отечественный Рок, Метал, Панк, Альтернатива (DVD Video)"); caps.Categories.AddCategoryMapping(1886, NewznabStandardCategory.AudioVideo, "|- Электронная музыка (DVD Video)"); caps.Categories.AddCategoryMapping(2509, NewznabStandardCategory.AudioVideo, "|- Документальные фильмы о музыке и музыкантах (DVD Video)"); - caps.Categories.AddCategoryMapping(2507, NewznabStandardCategory.AudioVideo, "Неофициальные DVD видео "); - caps.Categories.AddCategoryMapping(2263, NewznabStandardCategory.AudioVideo, "Классическая музыкаОпера, Балет, Мюзикл (Неофициальные DVD Video)"); - caps.Categories.AddCategoryMapping(2511, NewznabStandardCategory.AudioVideo, "ШансонАвторская песня, Сборные концерты, МДЖ (Неофициальные DVD Video)"); + caps.Categories.AddCategoryMapping(2507, NewznabStandardCategory.AudioVideo, "Неофициальные DVD видео"); + caps.Categories.AddCategoryMapping(2263, NewznabStandardCategory.AudioVideo, "Классическая музыка, Опера, Балет, Мюзикл (Неофициальные DVD Video)"); + caps.Categories.AddCategoryMapping(2511, NewznabStandardCategory.AudioVideo, "Шансон, Авторская песня, Сборные концерты, МДЖ (Неофициальные DVD Video)"); caps.Categories.AddCategoryMapping(2264, NewznabStandardCategory.AudioVideo, "|- Зарубежная и Отечественная Поп-музыка (Неофициальные DVD Video)"); caps.Categories.AddCategoryMapping(2262, NewznabStandardCategory.AudioVideo, "|- Джаз и Блюз (Неофициальные DVD Video)"); caps.Categories.AddCategoryMapping(2261, NewznabStandardCategory.AudioVideo, "|- Зарубежная и Отечественная Рок-музыка (Неофициальные DVD Video)"); - caps.Categories.AddCategoryMapping(1887, NewznabStandardCategory.AudioVideo, "|- Электронная музыка (Неофициальныелюбительские DVD Video)"); + caps.Categories.AddCategoryMapping(1887, NewznabStandardCategory.AudioVideo, "|- Электронная музыка (Неофициальные DVD Video)"); caps.Categories.AddCategoryMapping(2531, NewznabStandardCategory.AudioVideo, "|- Прочие жанры (Неофициальные DVD видео)"); caps.Categories.AddCategoryMapping(2400, NewznabStandardCategory.AudioVideo, "Музыкальное HD видео"); caps.Categories.AddCategoryMapping(1812, NewznabStandardCategory.AudioVideo, "|- Классическая и современная академическая музыка (HD Video)"); - caps.Categories.AddCategoryMapping(655, NewznabStandardCategory.AudioVideo, "|- ОпераОперетта и Мюзикл (HD Видео)"); + caps.Categories.AddCategoryMapping(655, NewznabStandardCategory.AudioVideo, "|- Опера, Оперетта и Мюзикл (HD Видео)"); caps.Categories.AddCategoryMapping(1777, NewznabStandardCategory.AudioVideo, "|- Балет и современная хореография (HD Video)"); - caps.Categories.AddCategoryMapping(2530, NewznabStandardCategory.AudioVideo, "|- ФольклорНародная, Этническая музыка и Flamenco (HD Видео)"); - caps.Categories.AddCategoryMapping(2529, NewznabStandardCategory.AudioVideo, "|- New AgeRelax, Meditative, Рэп, Хип-Хоп, R'n'B, Reggae, Ska, Dub .."); - caps.Categories.AddCategoryMapping(1781, NewznabStandardCategory.AudioVideo, "|- Музыка других жанровРазножанровые сборные концерты (HD видео)"); + caps.Categories.AddCategoryMapping(2530, NewznabStandardCategory.AudioVideo, "|- Фольклор, Народная, Этническая музыка и Flamenco (HD Видео)"); + caps.Categories.AddCategoryMapping(2529, NewznabStandardCategory.AudioVideo, "|- New Age, Relax, Meditative, Рэп, Хип-Хоп, R'n'B, Reggae, Ska, Dub (HD Видео)"); + caps.Categories.AddCategoryMapping(1781, NewznabStandardCategory.AudioVideo, "|- Музыка других жанров, Разножанровые сборные концерты (HD видео)"); caps.Categories.AddCategoryMapping(2508, NewznabStandardCategory.AudioVideo, "|- Зарубежная поп-музыка (HD Video)"); caps.Categories.AddCategoryMapping(2426, NewznabStandardCategory.AudioVideo, "|- Отечественная поп-музыка (HD видео)"); caps.Categories.AddCategoryMapping(2351, NewznabStandardCategory.AudioVideo, "|- Восточноазиатская Поп-музыка (HD Video)"); @@ -1158,7 +1181,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1913, NewznabStandardCategory.AudioVideo, "|- Электронная музыка (HD Video)"); caps.Categories.AddCategoryMapping(1784, NewznabStandardCategory.AudioVideo, "|- UHD музыкальное видео"); caps.Categories.AddCategoryMapping(1892, NewznabStandardCategory.AudioVideo, "|- Документальные фильмы о музыке и музыкантах (HD Video)"); - caps.Categories.AddCategoryMapping(518, NewznabStandardCategory.AudioVideo, "Некондиционное музыкальное видео (ВидеоDVD видео, HD видео)"); + caps.Categories.AddCategoryMapping(518, NewznabStandardCategory.AudioVideo, "Некондиционное музыкальное видео (Видео, DVD видео, HD видео)"); caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.PCGames, "Игры для Windows"); caps.Categories.AddCategoryMapping(635, NewznabStandardCategory.PCGames, "|- Горячие Новинки"); caps.Categories.AddCategoryMapping(127, NewznabStandardCategory.PCGames, "|- Аркады"); @@ -1179,26 +1202,26 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2226, NewznabStandardCategory.PCGames, "|- Пошаговые стратегии"); caps.Categories.AddCategoryMapping(2228, NewznabStandardCategory.PCGames, "|- IBM-PC-несовместимые компьютеры"); caps.Categories.AddCategoryMapping(139, NewznabStandardCategory.PCGames, "Прочее для Windows-игр"); - caps.Categories.AddCategoryMapping(2478, NewznabStandardCategory.PCGames, "|- Официальные патчимоды, плагины, дополнения"); - caps.Categories.AddCategoryMapping(2480, NewznabStandardCategory.PCGames, "|- Неофициальные модификацииплагины, дополнения"); + caps.Categories.AddCategoryMapping(2478, NewznabStandardCategory.PCGames, "|- Официальные патчи, моды, плагины, дополнения"); + caps.Categories.AddCategoryMapping(2480, NewznabStandardCategory.PCGames, "|- Неофициальные модификации, плагины, дополнения"); caps.Categories.AddCategoryMapping(2481, NewznabStandardCategory.PCGames, "|- Русификаторы"); - caps.Categories.AddCategoryMapping(2142, NewznabStandardCategory.PCGames, "Прочее для Microsoft Flight SimulatorPrepar3D, X-Plane"); - caps.Categories.AddCategoryMapping(2060, NewznabStandardCategory.PCGames, "|- Сценариимеши и аэропорты для FS2004, FSX, P3D"); - caps.Categories.AddCategoryMapping(2145, NewznabStandardCategory.PCGames, "|- Самолёты и вертолёты для FS2004FSX, P3D"); - caps.Categories.AddCategoryMapping(2146, NewznabStandardCategory.PCGames, "|- Миссиитрафик, звуки, паки и утилиты для FS2004, FSX, P3D"); - caps.Categories.AddCategoryMapping(2143, NewznabStandardCategory.PCGames, "|- Сценариимиссии, трафик, звуки, паки и утилиты для X-Plane"); + caps.Categories.AddCategoryMapping(2142, NewznabStandardCategory.PCGames, "Прочее для Microsoft Flight Simulator, Prepar3D, X-Plane"); + caps.Categories.AddCategoryMapping(2060, NewznabStandardCategory.PCGames, "|- Сценарии, меши и аэропорты для FS2004, FSX, P3D"); + caps.Categories.AddCategoryMapping(2145, NewznabStandardCategory.PCGames, "|- Самолёты и вертолёты для FS2004, FSX, P3D"); + caps.Categories.AddCategoryMapping(2146, NewznabStandardCategory.PCGames, "|- Миссии, трафик, звуки, паки и утилиты для FS2004, FSX, P3D"); + caps.Categories.AddCategoryMapping(2143, NewznabStandardCategory.PCGames, "|- Сценарии, миссии, трафик, звуки, паки и утилиты для X-Plane"); caps.Categories.AddCategoryMapping(2012, NewznabStandardCategory.PCGames, "|- Самолёты и вертолёты для X-Plane"); caps.Categories.AddCategoryMapping(960, NewznabStandardCategory.PCMac, "Игры для Apple Macintosh"); caps.Categories.AddCategoryMapping(537, NewznabStandardCategory.PCMac, "|- Нативные игры для Mac"); - caps.Categories.AddCategoryMapping(637, NewznabStandardCategory.PCMac, "|- Портированные игры для Mac"); + caps.Categories.AddCategoryMapping(637, NewznabStandardCategory.PCMac, "|- Игры для Mac с Wineskin, DOSBox, Cider и другими"); caps.Categories.AddCategoryMapping(899, NewznabStandardCategory.PCGames, "Игры для Linux"); caps.Categories.AddCategoryMapping(1992, NewznabStandardCategory.PCGames, "|- Нативные игры для Linux"); - caps.Categories.AddCategoryMapping(2059, NewznabStandardCategory.PCGames, "|- Портированные игры для Linux"); + caps.Categories.AddCategoryMapping(2059, NewznabStandardCategory.PCGames, "|- Игры для Linux с Wine, DOSBox и другими"); caps.Categories.AddCategoryMapping(548, NewznabStandardCategory.Console, "Игры для консолей"); caps.Categories.AddCategoryMapping(908, NewznabStandardCategory.Console, "|- PS"); caps.Categories.AddCategoryMapping(357, NewznabStandardCategory.ConsoleOther, "|- PS2"); caps.Categories.AddCategoryMapping(886, NewznabStandardCategory.ConsolePS3, "|- PS3"); - caps.Categories.AddCategoryMapping(546, NewznabStandardCategory.Console, "|- Игры PS1PS2 и PSP для PS3"); + caps.Categories.AddCategoryMapping(546, NewznabStandardCategory.Console, "|- Игры PS1, PS2 и PSP для PS3"); caps.Categories.AddCategoryMapping(973, NewznabStandardCategory.ConsolePS4, "|- PS4"); caps.Categories.AddCategoryMapping(1352, NewznabStandardCategory.ConsolePSP, "|- PSP"); caps.Categories.AddCategoryMapping(1116, NewznabStandardCategory.ConsolePSP, "|- Игры PS1 для PSP"); @@ -1221,21 +1244,22 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1926, NewznabStandardCategory.ConsoleOther, "|- Видео для PS3 и других консолей"); caps.Categories.AddCategoryMapping(650, NewznabStandardCategory.PCMobileOther, "Игры для мобильных устройств"); caps.Categories.AddCategoryMapping(2149, NewznabStandardCategory.PCMobileAndroid, "|- Игры для Android"); - caps.Categories.AddCategoryMapping(1001, NewznabStandardCategory.PCMobileOther, "|- Игры для Java"); + caps.Categories.AddCategoryMapping(2420, NewznabStandardCategory.ConsoleOther, "|- Игры для Oculus Quest"); + caps.Categories.AddCategoryMapping(1001, NewznabStandardCategory.PC, "|- Игры для Java"); caps.Categories.AddCategoryMapping(1004, NewznabStandardCategory.PCMobileOther, "|- Игры для Symbian"); caps.Categories.AddCategoryMapping(1002, NewznabStandardCategory.PCMobileOther, "|- Игры для Windows Mobile"); - caps.Categories.AddCategoryMapping(2420, NewznabStandardCategory.PCMobileOther, "|- Игры для Windows Phone"); caps.Categories.AddCategoryMapping(240, NewznabStandardCategory.OtherMisc, "Игровое видео"); caps.Categories.AddCategoryMapping(2415, NewznabStandardCategory.OtherMisc, "|- Видеопрохождения игр"); caps.Categories.AddCategoryMapping(1012, NewznabStandardCategory.PC, "Операционные системы от Microsoft"); - caps.Categories.AddCategoryMapping(2523, NewznabStandardCategory.PC, "|- Настольные ОС от Microsoft - Windows 8 и далее"); - caps.Categories.AddCategoryMapping(2153, NewznabStandardCategory.PC, "|- Настольные ОС от Microsoft - Windows XP - Windows 7"); - caps.Categories.AddCategoryMapping(1019, NewznabStandardCategory.PC, "|- Настольные ОС от Microsoft (выпущенные до Windows XP)"); - caps.Categories.AddCategoryMapping(1021, NewznabStandardCategory.PC, "|- Серверные ОС от Microsoft"); - caps.Categories.AddCategoryMapping(1025, NewznabStandardCategory.PC, "|- Разное (Операционные системы от Microsoft)"); - caps.Categories.AddCategoryMapping(1376, NewznabStandardCategory.PC, "LinuxUnix и другие ОС"); - caps.Categories.AddCategoryMapping(1379, NewznabStandardCategory.PC, "|- Операционные системы (LinuxUnix)"); - caps.Categories.AddCategoryMapping(1381, NewznabStandardCategory.PC, "|- Программное обеспечение (LinuxUnix)"); + caps.Categories.AddCategoryMapping(2489, NewznabStandardCategory.PC, "|- Оригинальные образы Windows"); + caps.Categories.AddCategoryMapping(2523, NewznabStandardCategory.PC, "|- Сборки Windows 8 и далее"); + caps.Categories.AddCategoryMapping(2153, NewznabStandardCategory.PC, "|- Сборки Windows XP - Windows 7"); + caps.Categories.AddCategoryMapping(1019, NewznabStandardCategory.PC, "|- Операционные системы выпущенные до Windows XP"); + caps.Categories.AddCategoryMapping(1021, NewznabStandardCategory.PC, "|- Серверные ОС (оригинальные + сборки)"); + caps.Categories.AddCategoryMapping(1025, NewznabStandardCategory.PC, "|- Разное (сборки All-in-One, пакеты обновлений, утилиты, и прочее)"); + caps.Categories.AddCategoryMapping(1376, NewznabStandardCategory.PC, "Linux, Unix и другие ОС"); + caps.Categories.AddCategoryMapping(1379, NewznabStandardCategory.PC, "|- Операционные системы (Linux, Unix)"); + caps.Categories.AddCategoryMapping(1381, NewznabStandardCategory.PC, "|- Программное обеспечение (Linux, Unix)"); caps.Categories.AddCategoryMapping(1473, NewznabStandardCategory.PC, "|- Другие ОС и ПО под них"); caps.Categories.AddCategoryMapping(1195, NewznabStandardCategory.PC, "Тестовые диски для настройки аудио/видео аппаратуры"); caps.Categories.AddCategoryMapping(1013, NewznabStandardCategory.PC, "Системные программы"); @@ -1247,7 +1271,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1033, NewznabStandardCategory.PC, "|- Работа с носителями информации"); caps.Categories.AddCategoryMapping(1034, NewznabStandardCategory.PC, "|- Информация и диагностика"); caps.Categories.AddCategoryMapping(1066, NewznabStandardCategory.PC, "|- Программы для интернет и сетей"); - caps.Categories.AddCategoryMapping(1035, NewznabStandardCategory.PC, "|- ПО для защиты компьютера (Антивирусное ПОФаерволлы)"); + caps.Categories.AddCategoryMapping(1035, NewznabStandardCategory.PC, "|- ПО для защиты компьютера (Антивирусное ПО, Фаерволлы)"); caps.Categories.AddCategoryMapping(1038, NewznabStandardCategory.PC, "|- Анти-шпионы и анти-трояны"); caps.Categories.AddCategoryMapping(1039, NewznabStandardCategory.PC, "|- Программы для защиты информации"); caps.Categories.AddCategoryMapping(1536, NewznabStandardCategory.PC, "|- Драйверы и прошивки"); @@ -1256,73 +1280,73 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1041, NewznabStandardCategory.PC, "|- Изменение интерфейса ОС Windows"); caps.Categories.AddCategoryMapping(1636, NewznabStandardCategory.PC, "|- Скринсейверы"); caps.Categories.AddCategoryMapping(1042, NewznabStandardCategory.PC, "|- Разное (Системные программы под Windows)"); - caps.Categories.AddCategoryMapping(1014, NewznabStandardCategory.PC, "Системы для бизнесаофиса, научной и проектной работы"); + caps.Categories.AddCategoryMapping(1014, NewznabStandardCategory.PC, "Системы для бизнеса, офиса, научной и проектной работы"); caps.Categories.AddCategoryMapping(2134, NewznabStandardCategory.PC, "|- Медицина - интерактивный софт"); - caps.Categories.AddCategoryMapping(1060, NewznabStandardCategory.PC, "|- Всё для дома: кройкашитьё, кулинария"); + caps.Categories.AddCategoryMapping(1060, NewznabStandardCategory.PC, "|- Всё для дома: кройка, шитьё, кулинария"); caps.Categories.AddCategoryMapping(1061, NewznabStandardCategory.PC, "|- Офисные системы"); caps.Categories.AddCategoryMapping(1062, NewznabStandardCategory.PC, "|- Системы для бизнеса"); - caps.Categories.AddCategoryMapping(1067, NewznabStandardCategory.PC, "|- Распознавание текстазвука и синтез речи"); + caps.Categories.AddCategoryMapping(1067, NewznabStandardCategory.PC, "|- Распознавание текста, звука и синтез речи"); caps.Categories.AddCategoryMapping(1086, NewznabStandardCategory.PC, "|- Работа с PDF и DjVu"); - caps.Categories.AddCategoryMapping(1068, NewznabStandardCategory.PC, "|- Словарипереводчики"); + caps.Categories.AddCategoryMapping(1068, NewznabStandardCategory.PC, "|- Словари, переводчики"); caps.Categories.AddCategoryMapping(1063, NewznabStandardCategory.PC, "|- Системы для научной работы"); caps.Categories.AddCategoryMapping(1087, NewznabStandardCategory.PC, "|- САПР (общие и машиностроительные)"); - caps.Categories.AddCategoryMapping(1192, NewznabStandardCategory.PC, "|- САПР (электроникаавтоматика, ГАП)"); + caps.Categories.AddCategoryMapping(1192, NewznabStandardCategory.PC, "|- САПР (электроника, автоматика, ГАП)"); caps.Categories.AddCategoryMapping(1088, NewznabStandardCategory.PC, "|- Программы для архитекторов и строителей"); caps.Categories.AddCategoryMapping(1193, NewznabStandardCategory.PC, "|- Библиотеки и проекты для архитекторов и дизайнеров интерьеров"); caps.Categories.AddCategoryMapping(1071, NewznabStandardCategory.PC, "|- Прочие справочные системы"); - caps.Categories.AddCategoryMapping(1073, NewznabStandardCategory.PC, "|- Разное (Системы для бизнесаофиса, научной и проектной работы)"); + caps.Categories.AddCategoryMapping(1073, NewznabStandardCategory.PC, "|- Разное (Системы для бизнеса, офиса, научной и проектной работы)"); caps.Categories.AddCategoryMapping(1052, NewznabStandardCategory.PC, "Веб-разработка и Программирование"); caps.Categories.AddCategoryMapping(1053, NewznabStandardCategory.PC, "|- WYSIWYG Редакторы для веб-диза"); caps.Categories.AddCategoryMapping(1054, NewznabStandardCategory.PC, "|- Текстовые редакторы с подсветкой"); - caps.Categories.AddCategoryMapping(1055, NewznabStandardCategory.PC, "|- Среды программированиякомпиляторы и вспомогательные программы"); + caps.Categories.AddCategoryMapping(1055, NewznabStandardCategory.PC, "|- Среды программирования, компиляторы и вспомогательные программы"); caps.Categories.AddCategoryMapping(1056, NewznabStandardCategory.PC, "|- Компоненты для сред программирования"); caps.Categories.AddCategoryMapping(2077, NewznabStandardCategory.PC, "|- Системы управления базами данных"); - caps.Categories.AddCategoryMapping(1057, NewznabStandardCategory.PC, "|- Скрипты и движки сайтовCMS а также расширения к ним"); + caps.Categories.AddCategoryMapping(1057, NewznabStandardCategory.PC, "|- Скрипты и движки сайтов, CMS а также расширения к ним"); caps.Categories.AddCategoryMapping(1018, NewznabStandardCategory.PC, "|- Шаблоны для сайтов и CMS"); caps.Categories.AddCategoryMapping(1058, NewznabStandardCategory.PC, "|- Разное (Веб-разработка и программирование)"); caps.Categories.AddCategoryMapping(1016, NewznabStandardCategory.PC, "Программы для работы с мультимедиа и 3D"); caps.Categories.AddCategoryMapping(1079, NewznabStandardCategory.PC, "|- Программные комплекты"); caps.Categories.AddCategoryMapping(1080, NewznabStandardCategory.PC, "|- Плагины для программ компании Adobe"); caps.Categories.AddCategoryMapping(1081, NewznabStandardCategory.PC, "|- Графические редакторы"); - caps.Categories.AddCategoryMapping(1082, NewznabStandardCategory.PC, "|- Программы для версткипечати и работы со шрифтами"); - caps.Categories.AddCategoryMapping(1083, NewznabStandardCategory.PC, "|- 3D моделированиерендеринг и плагины для них"); + caps.Categories.AddCategoryMapping(1082, NewznabStandardCategory.PC, "|- Программы для верстки, печати и работы со шрифтами"); + caps.Categories.AddCategoryMapping(1083, NewznabStandardCategory.PC, "|- 3D моделирование, рендеринг и плагины для них"); caps.Categories.AddCategoryMapping(1084, NewznabStandardCategory.PC, "|- Анимация"); caps.Categories.AddCategoryMapping(1085, NewznabStandardCategory.PC, "|- Создание BD/HD/DVD-видео"); caps.Categories.AddCategoryMapping(1089, NewznabStandardCategory.PC, "|- Редакторы видео"); caps.Categories.AddCategoryMapping(1090, NewznabStandardCategory.PC, "|- Видео- Аудио- конверторы"); - caps.Categories.AddCategoryMapping(1065, NewznabStandardCategory.PC, "|- Аудио- и видео-CD- проигрыватели и каталогизаторы"); + caps.Categories.AddCategoryMapping(1065, NewznabStandardCategory.PC, "|- Аудио- и видео-, CD- проигрыватели и каталогизаторы"); caps.Categories.AddCategoryMapping(1064, NewznabStandardCategory.PC, "|- Каталогизаторы и просмотрщики графики"); caps.Categories.AddCategoryMapping(1092, NewznabStandardCategory.PC, "|- Разное (Программы для работы с мультимедиа и 3D)"); - caps.Categories.AddCategoryMapping(1204, NewznabStandardCategory.PC, "|- Виртуальные студиисеквенсоры и аудиоредакторы"); + caps.Categories.AddCategoryMapping(1204, NewznabStandardCategory.PC, "|- Виртуальные студии, секвенсоры и аудиоредакторы"); caps.Categories.AddCategoryMapping(1027, NewznabStandardCategory.PC, "|- Виртуальные инструменты и синтезаторы"); caps.Categories.AddCategoryMapping(1199, NewznabStandardCategory.PC, "|- Плагины для обработки звука"); caps.Categories.AddCategoryMapping(1091, NewznabStandardCategory.PC, "|- Разное (Программы для работы со звуком)"); - caps.Categories.AddCategoryMapping(838, NewznabStandardCategory.OtherMisc, "|- Ищу/Предлагаю (Материалы для мультимедиа и дизайна)"); + caps.Categories.AddCategoryMapping(828, NewznabStandardCategory.OtherMisc, "Материалы для мультимедиа и дизайна"); caps.Categories.AddCategoryMapping(1357, NewznabStandardCategory.OtherMisc, "|- Авторские работы"); caps.Categories.AddCategoryMapping(890, NewznabStandardCategory.OtherMisc, "|- Официальные сборники векторных клипартов"); caps.Categories.AddCategoryMapping(830, NewznabStandardCategory.OtherMisc, "|- Прочие векторные клипарты"); caps.Categories.AddCategoryMapping(1290, NewznabStandardCategory.OtherMisc, "|- Photostoсks"); caps.Categories.AddCategoryMapping(1962, NewznabStandardCategory.OtherMisc, "|- Дополнения для программ компоузинга и постобработки"); - caps.Categories.AddCategoryMapping(831, NewznabStandardCategory.OtherMisc, "|- Рамкишаблоны, текстуры и фоны"); + caps.Categories.AddCategoryMapping(831, NewznabStandardCategory.OtherMisc, "|- Рамки, шаблоны, текстуры и фоны"); caps.Categories.AddCategoryMapping(829, NewznabStandardCategory.OtherMisc, "|- Прочие растровые клипарты"); - caps.Categories.AddCategoryMapping(633, NewznabStandardCategory.OtherMisc, "|- 3D моделисцены и материалы"); + caps.Categories.AddCategoryMapping(633, NewznabStandardCategory.OtherMisc, "|- 3D модели, сцены и материалы"); caps.Categories.AddCategoryMapping(1009, NewznabStandardCategory.OtherMisc, "|- Футажи"); caps.Categories.AddCategoryMapping(1963, NewznabStandardCategory.OtherMisc, "|- Прочие сборники футажей"); caps.Categories.AddCategoryMapping(1954, NewznabStandardCategory.OtherMisc, "|- Музыкальные библиотеки"); caps.Categories.AddCategoryMapping(1010, NewznabStandardCategory.OtherMisc, "|- Звуковые эффекты"); caps.Categories.AddCategoryMapping(1674, NewznabStandardCategory.OtherMisc, "|- Библиотеки сэмплов"); - caps.Categories.AddCategoryMapping(2421, NewznabStandardCategory.OtherMisc, "|- Библиотеки и саундбанки для сэмплеровпресеты для синтезаторов"); + caps.Categories.AddCategoryMapping(2421, NewznabStandardCategory.OtherMisc, "|- Библиотеки и саундбанки для сэмплеров, пресеты для синтезаторов"); caps.Categories.AddCategoryMapping(2492, NewznabStandardCategory.OtherMisc, "|- Multitracks"); caps.Categories.AddCategoryMapping(839, NewznabStandardCategory.OtherMisc, "|- Материалы для создания меню и обложек DVD"); - caps.Categories.AddCategoryMapping(1679, NewznabStandardCategory.OtherMisc, "|- Дополнениястили, кисти, формы, узоры для программ Adobe"); + caps.Categories.AddCategoryMapping(1679, NewznabStandardCategory.OtherMisc, "|- Дополнения, стили, кисти, формы, узоры для программ Adobe"); caps.Categories.AddCategoryMapping(1011, NewznabStandardCategory.OtherMisc, "|- Шрифты"); caps.Categories.AddCategoryMapping(835, NewznabStandardCategory.OtherMisc, "|- Разное (Материалы для мультимедиа и дизайна)"); - caps.Categories.AddCategoryMapping(1503, NewznabStandardCategory.OtherMisc, "ГИСсистемы навигации и карты"); + caps.Categories.AddCategoryMapping(1503, NewznabStandardCategory.OtherMisc, "ГИС, системы навигации и карты"); caps.Categories.AddCategoryMapping(1507, NewznabStandardCategory.OtherMisc, "|- ГИС (Геоинформационные системы)"); - caps.Categories.AddCategoryMapping(1526, NewznabStandardCategory.OtherMisc, "|- Картыснабженные программной оболочкой"); + caps.Categories.AddCategoryMapping(1526, NewznabStandardCategory.OtherMisc, "|- Карты, снабженные программной оболочкой"); caps.Categories.AddCategoryMapping(1508, NewznabStandardCategory.OtherMisc, "|- Атласы и карты современные (после 1950 г.)"); caps.Categories.AddCategoryMapping(1509, NewznabStandardCategory.OtherMisc, "|- Атласы и карты старинные (до 1950 г.)"); - caps.Categories.AddCategoryMapping(1510, NewznabStandardCategory.OtherMisc, "|- Карты прочие (астрономическиеисторические, тематические)"); + caps.Categories.AddCategoryMapping(1510, NewznabStandardCategory.OtherMisc, "|- Карты прочие (астрономические, исторические, тематические)"); caps.Categories.AddCategoryMapping(1511, NewznabStandardCategory.OtherMisc, "|- Встроенная автомобильная навигация"); caps.Categories.AddCategoryMapping(1512, NewznabStandardCategory.OtherMisc, "|- Garmin"); caps.Categories.AddCategoryMapping(1513, NewznabStandardCategory.OtherMisc, "|- Ozi"); @@ -1335,7 +1359,6 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1005, NewznabStandardCategory.PCMobileOther, "|- Приложения для Java"); caps.Categories.AddCategoryMapping(289, NewznabStandardCategory.PCMobileOther, "|- Приложения для Symbian"); caps.Categories.AddCategoryMapping(290, NewznabStandardCategory.PCMobileOther, "|- Приложения для Windows Mobile"); - caps.Categories.AddCategoryMapping(2419, NewznabStandardCategory.PCMobileOther, "|- Приложения для Windows Phone"); caps.Categories.AddCategoryMapping(288, NewznabStandardCategory.PCMobileOther, "|- Софт для работы с телефоном"); caps.Categories.AddCategoryMapping(292, NewznabStandardCategory.PCMobileOther, "|- Прошивки для телефонов"); caps.Categories.AddCategoryMapping(291, NewznabStandardCategory.PCMobileOther, "|- Обои и темы"); @@ -1358,11 +1381,11 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1003, NewznabStandardCategory.PCMobileiOS, "|- Игры для iOS"); caps.Categories.AddCategoryMapping(1937, NewznabStandardCategory.PCMobileiOS, "|- Разное для iOS"); caps.Categories.AddCategoryMapping(2235, NewznabStandardCategory.PCMobileiOS, "Видео"); - caps.Categories.AddCategoryMapping(1908, NewznabStandardCategory.PCMobileiOS, "|- Фильмы для iPodiPhone, iPad"); - caps.Categories.AddCategoryMapping(864, NewznabStandardCategory.PCMobileiOS, "|- Сериалы для iPodiPhone, iPad"); - caps.Categories.AddCategoryMapping(863, NewznabStandardCategory.PCMobileiOS, "|- Мультфильмы для iPodiPhone, iPad"); - caps.Categories.AddCategoryMapping(2535, NewznabStandardCategory.PCMobileiOS, "|- Аниме для iPodiPhone, iPad"); - caps.Categories.AddCategoryMapping(2534, NewznabStandardCategory.PCMobileiOS, "|- Музыкальное видео для iPodiPhone, iPad"); + caps.Categories.AddCategoryMapping(1908, NewznabStandardCategory.PCMobileiOS, "|- Фильмы для iPod, iPhone, iPad"); + caps.Categories.AddCategoryMapping(864, NewznabStandardCategory.PCMobileiOS, "|- Сериалы для iPod, iPhone, iPad"); + caps.Categories.AddCategoryMapping(863, NewznabStandardCategory.PCMobileiOS, "|- Мультфильмы для iPod, iPhone, iPad"); + caps.Categories.AddCategoryMapping(2535, NewznabStandardCategory.PCMobileiOS, "|- Аниме для iPod, iPhone, iPad"); + caps.Categories.AddCategoryMapping(2534, NewznabStandardCategory.PCMobileiOS, "|- Музыкальное видео для iPod, iPhone, iPad"); caps.Categories.AddCategoryMapping(2238, NewznabStandardCategory.PCMac, "Видео HD"); caps.Categories.AddCategoryMapping(1936, NewznabStandardCategory.PCMac, "|- Фильмы HD для Apple TV"); caps.Categories.AddCategoryMapping(315, NewznabStandardCategory.PCMac, "|- Сериалы HD для Apple TV"); @@ -1370,15 +1393,15 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2082, NewznabStandardCategory.PCMac, "|- Документальное видео HD для Apple TV"); caps.Categories.AddCategoryMapping(2241, NewznabStandardCategory.PCMac, "|- Музыкальное видео HD для Apple TV"); caps.Categories.AddCategoryMapping(2236, NewznabStandardCategory.Audio, "Аудио"); - caps.Categories.AddCategoryMapping(1909, NewznabStandardCategory.AudioAudiobook, "|- Аудиокниги (AACALAC)"); + caps.Categories.AddCategoryMapping(1909, NewznabStandardCategory.AudioAudiobook, "|- Аудиокниги (AAC, ALAC)"); caps.Categories.AddCategoryMapping(1927, NewznabStandardCategory.AudioLossless, "|- Музыка lossless (ALAC)"); caps.Categories.AddCategoryMapping(2240, NewznabStandardCategory.Audio, "|- Музыка Lossy (AAC-iTunes)"); caps.Categories.AddCategoryMapping(2248, NewznabStandardCategory.Audio, "|- Музыка Lossy (AAC)"); - caps.Categories.AddCategoryMapping(2244, NewznabStandardCategory.Audio, "|- Музыка Lossy (AAC) (SinglesEPs)"); + caps.Categories.AddCategoryMapping(2244, NewznabStandardCategory.Audio, "|- Музыка Lossy (AAC) (Singles, EPs)"); caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.OtherMisc, "Разное (раздачи)"); caps.Categories.AddCategoryMapping(865, NewznabStandardCategory.OtherMisc, "|- Психоактивные аудиопрограммы"); - caps.Categories.AddCategoryMapping(1100, NewznabStandardCategory.OtherMisc, "|- АватарыИконки, Смайлы"); - caps.Categories.AddCategoryMapping(1643, NewznabStandardCategory.OtherMisc, "|- ЖивописьГрафика, Скульптура, Digital Art"); + caps.Categories.AddCategoryMapping(1100, NewznabStandardCategory.OtherMisc, "|- Аватары, Иконки, Смайлы"); + caps.Categories.AddCategoryMapping(1643, NewznabStandardCategory.OtherMisc, "|- Живопись, Графика, Скульптура, Digital Art"); caps.Categories.AddCategoryMapping(848, NewznabStandardCategory.OtherMisc, "|- Картинки"); caps.Categories.AddCategoryMapping(808, NewznabStandardCategory.OtherMisc, "|- Любительские фотографии"); caps.Categories.AddCategoryMapping(630, NewznabStandardCategory.OtherMisc, "|- Обои"); @@ -1390,6 +1413,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(147, NewznabStandardCategory.Books, "|- Публикации и учебные материалы (тексты)"); caps.Categories.AddCategoryMapping(847, NewznabStandardCategory.MoviesOther, "|- Трейлеры и дополнительные материалы к фильмам"); caps.Categories.AddCategoryMapping(1167, NewznabStandardCategory.TVOther, "|- Любительские видеоклипы"); + caps.Categories.AddCategoryMapping(321, NewznabStandardCategory.Other, "Место встречи изменить - Отчеты о встречах"); return caps; } From 77c840b03a41be8d15b7c8eb30a1b785200ad731 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 16 Feb 2022 13:42:54 -0600 Subject: [PATCH 0358/2320] Fixed: Enable response compression over https (cherry picked from commit cb0ae3603309daae4d6b026de15f26cb4b59096d) --- src/NzbDrone.Host/Startup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Host/Startup.cs b/src/NzbDrone.Host/Startup.cs index 730f16dea..44db1e7c7 100644 --- a/src/NzbDrone.Host/Startup.cs +++ b/src/NzbDrone.Host/Startup.cs @@ -62,7 +62,7 @@ namespace NzbDrone.Host services.AddRouting(options => options.LowercaseUrls = true); - services.AddResponseCompression(); + services.AddResponseCompression(options => options.EnableForHttps = true); services.AddCors(options => { From b2e300b6da823f8014efefb576f1cd460dc4588d Mon Sep 17 00:00:00 2001 From: Pfuenzle <dark.leon64@gmail.com> Date: Sun, 20 Feb 2022 17:50:54 +0100 Subject: [PATCH 0359/2320] Update Categories --- src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs index cd747a5dd..52dd2a23d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs @@ -48,14 +48,17 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVAnime, "Anime Series"); caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Anime Musik/OST"); caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.PCGames, "Anime Spiele"); - caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.XXX, "Hentai"); - caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.PCGames, "Spiele Linux"); + caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.XXX, "Anime Hentai"); + caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.PCGames, "Software"); caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.Other, "Sonstiges"); caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.Movies, "Filme"); caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.TV, "Serien"); caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.PCGames, "Spiele"); caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.Audio, "Musik"); caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.BooksComics, "Mangas"); + caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.Movies, "Cartoon Filme"); + caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.TV, "Cartoon Serie"); + caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.XXX, "H-Manga / Doujinshi"); return caps; } From aaef8fb29c720c0af5631732d7ad644fcce5ab18 Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Sun, 20 Feb 2022 21:38:07 +0000 Subject: [PATCH 0360/2320] Fixed: Make authentication cookie name unique to Prowlarr --- .../Authentication/AuthenticationBuilderExtensions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Prowlarr.Http/Authentication/AuthenticationBuilderExtensions.cs b/src/Prowlarr.Http/Authentication/AuthenticationBuilderExtensions.cs index d193dd965..0d0d0918f 100644 --- a/src/Prowlarr.Http/Authentication/AuthenticationBuilderExtensions.cs +++ b/src/Prowlarr.Http/Authentication/AuthenticationBuilderExtensions.cs @@ -29,6 +29,7 @@ namespace Prowlarr.Http.Authentication .AddBasic(AuthenticationType.Basic.ToString()) .AddCookie(AuthenticationType.Forms.ToString(), options => { + options.Cookie.Name = "ProwlarrAuth"; options.AccessDeniedPath = "/login?loginFailed=true"; options.LoginPath = "/login"; options.ExpireTimeSpan = TimeSpan.FromDays(7); From 4c68645175b898be2fad78c50010e789b99e14b5 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Wed, 23 Feb 2022 09:32:37 +0000 Subject: [PATCH 0361/2320] Translated using Weblate (Finnish) Currently translated at 100.0% (428 of 428 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (428 of 428 strings) Added translation using Weblate (Ukrainian) Added translation using Weblate (Persian) Added translation using Weblate (Bengali) Co-authored-by: Anonymous <noreply@weblate.org> Co-authored-by: Oskari Lavinto <olavinto@protonmail.com> Co-authored-by: Weblate <noreply@weblate.org> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/bn.json | 1 + src/NzbDrone.Core/Localization/Core/fa.json | 1 + src/NzbDrone.Core/Localization/Core/fi.json | 79 ++++++++------------- src/NzbDrone.Core/Localization/Core/uk.json | 1 + 4 files changed, 33 insertions(+), 49 deletions(-) create mode 100644 src/NzbDrone.Core/Localization/Core/bn.json create mode 100644 src/NzbDrone.Core/Localization/Core/fa.json create mode 100644 src/NzbDrone.Core/Localization/Core/uk.json diff --git a/src/NzbDrone.Core/Localization/Core/bn.json b/src/NzbDrone.Core/Localization/Core/bn.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/src/NzbDrone.Core/Localization/Core/bn.json @@ -0,0 +1 @@ +{} diff --git a/src/NzbDrone.Core/Localization/Core/fa.json b/src/NzbDrone.Core/Localization/Core/fa.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/src/NzbDrone.Core/Localization/Core/fa.json @@ -0,0 +1 @@ +{} diff --git a/src/NzbDrone.Core/Localization/Core/fi.json b/src/NzbDrone.Core/Localization/Core/fi.json index 0e3e6719e..498adda7e 100644 --- a/src/NzbDrone.Core/Localization/Core/fi.json +++ b/src/NzbDrone.Core/Localization/Core/fi.json @@ -2,19 +2,16 @@ "IndexerProxyStatusCheckSingleClientMessage": "Välityspalvelimet eivät ole käytettävissä virheiden vuoksi: {0}", "Logging": "Kirjaus", "LogLevel": "Kirjauksen taso", - "MovieIndexScrollTop": "Elokuvahakemisto: Vieritä yläreunaan", + "MovieIndexScrollTop": "Elokuvahakemisto: vieritä ylös", "Apply": "Käytä", "ClientPriority": "Lataustyökalun painotus", - "EnabledHelpText": "Käytä tätä tuontilistaa.", "IndexerPriorityHelpText": "Tietolähteen painotus: 1 (korkein) - 50 (matalin). Oletusarvo on 25.", "Manual": "Manuaalinen", "Add": "Lisää", "Reload": "Lataa uudelleen", "Indexers": "Tietolähteet", - "MovieIndexScrollBottom": "Elokuvahakemisto: Vieritä alareunaan", - "Movies": "Elokuvat", + "MovieIndexScrollBottom": "Elokuvahakemisto: vieritä alas", "PtpOldSettingsCheckMessage": "Seuraavat PassThePopcorn-tietolähteet sisältävät vanhentuneita asetuksia, jotka olisi syytä päivittää: {0}", - "QualityDefinitions": "Laatumääritykset", "SSLCertPassword": "SSL-varmenteen salasana", "Style": "Tyyli", "Tags": "Tunnisteet", @@ -32,9 +29,7 @@ "TestAll": "Testaa kaikki", "AddDownloadClient": "Lisää lataustyökalu", "CustomFilters": "Mukautetut suodattimet", - "DeleteIndexer": "Poista tietolähde", "DeleteTag": "Poista tunniste", - "DownloadClientCheckNoneAvailableMessage": "Lataustyökaluja ei ole käytettävissä", "EnableRss": "RSS-syöte", "Filter": "Suodata", "Fixed": "Korjattu", @@ -43,8 +38,6 @@ "HideAdvanced": "Piilota lisäasetukset", "History": "Historia", "MIA": "Puuttuu", - "MonoVersion": "Mono-versio", - "MonoVersionCheckUpgradeRecommendedMessage": "Tällä hetkellä asennettua mono-versiota {0} tuetaan, mutta sen päivitystä versioon {1} suositellaan.", "New": "Uusi", "PageSizeHelpText": "Sivulla näytettävien kohteiden määrä", "Proxy": "Välityspalvelin", @@ -86,28 +79,20 @@ "DeleteNotification": "Poista kytkentä", "Docker": "Docker", "DownloadClient": "Lataustyökalu", - "EnableMediaInfoHelpText": "Pura videotiedostoista tietoja, kuten videon resoluutio, kesto ja koodekki. Tätä varten Prowlarrin on luettava tiedostoja osittain ja tämä saattaa aiheuttaa korkeampaa levyn ja/tai verkon kuormitusta tarkistusten aikana.", "Language": "Kieli", "Search": "Haku", "Details": "Tiedot", "InteractiveSearch": "Vuorovaikutteinen haku", "Interval": "Aikaväli", "KeyboardShortcuts": "Pikanäppäimet", - "Languages": "Kielet", "LastWriteTime": "Viimeisin kirjoitusaika", "LogFiles": "Lokitiedostot", "LogLevelTraceHelpTextWarning": "Jäljityskirjausta tulisi käyttää vain väliaikaisesti", "Logs": "Lokitiedot", - "MaximumLimits": "Enimmäismäärät", "Mechanism": "Mekanismi", - "MonoTlsCheckMessage": "Radarr Mono 4.x tls -ongelmankiertotapa on edelleen käytössä. Pyri poistamaan MONO_TLS_PROVIDER = vanhan ympäristön vaihtoehto.", - "MovieDetailsNextMovie": "Elokuvan tiedot: Seuraava elokuva", - "MovieDetailsPreviousMovie": "Elokuvan tiedot: Edellinen elokuva", "Name": "Nimi", "NoLinks": "Ei linkkejä", "Peers": "Vertaiset", - "Pending": "Odottaa", - "PreferredSize": "Haluttu koko", "Presets": "Esiasetukset", "Priority": "Painotus", "PriorityHelpText": "Määritä useiden lataustyökalujen painotusasetukset. Tasaveroisesti painotettujen työkalujen käyttöä tasapainotetaan Round-Robin-tekniikalla.", @@ -119,7 +104,6 @@ "ProxyPasswordHelpText": "Käyttäjätunnus ja salasana tulee syöttää vain tarvittaessa. Muussa tapauksessa jätä kentät tyhjiksi.", "ProxyType": "Välityspalvelimen tyyppi", "ProxyUsernameHelpText": "Käyttäjätunnus ja salasana tulee syöttää vain tarvittaessa. Muussa tapauksessa jätä kentät tyhjiksi.", - "QualitySettings": "Laadun asetukset", "Queue": "Jono", "ReadTheWikiForMoreInformation": "Lue lisätietoja Wikistä", "ReleaseStatus": "Julkaisutila", @@ -173,13 +157,9 @@ "DeleteIndexerProxyMessageText": "Haluatko varmasti poistaa välityspalvelimen '{0}'?", "DeleteNotificationMessageText": "Haluatko varmasti poistaa kytkennän '{0}'?", "Disabled": "Ei käytössä", - "DownloadClientCheckUnableToCommunicateMessage": "Lataustyökalun '{0}' kanssa ei voida viestiä.", "DownloadClients": "Lataustyökalut", "DownloadClientSettings": "Lataustyökalujen asetukset", "DownloadClientStatusCheckAllClientMessage": "Yhtään lataustyökalua ei ole virheiden vuoksi käytettävissä", - "MinutesHundredTwenty": "120 minuuttia: {0}", - "MinutesNinety": "90 minuuttia: {0}", - "MinutesSixty": "60 minuuttia: {0}", "Mode": "Tila", "MoreInfo": "Lisätietoja", "SelectAll": "Valitse kaikki", @@ -194,9 +174,7 @@ "UnableToAddANewDownloadClientPleaseTryAgain": "Uuden lataustyökalun lisäys epäonnistui. Yitä uudelleen.", "AppDataLocationHealthCheckMessage": "Päivitystä ei sallita, jotta AppData-kansion poisto päivityksen yhteydessä voidaan estää.", "UnableToLoadHistory": "Historian lataus epäonnistui.", - "UnableToLoadIndexers": "Tietolähteiden lataus epäonnistui.", "UnableToLoadNotifications": "Kytkentöjen lataus epäonnistui.", - "UnableToLoadQualityDefinitions": "Laatumäärityksien lataus epäonnistui.", "UnableToLoadTags": "Tunnisteiden lataus epäonnistui.", "UnableToLoadUISettings": "Käyttöliittymän asetuksien lataus epäonnistui.", "UnsavedChanges": "Tallentamattomia muutoksia", @@ -207,14 +185,9 @@ "DeleteTagMessageText": "Haluatko varmasti poistaa tunnisteen '{0}'?", "Discord": "Discord", "Donations": "Lahjoitukset", - "DownloadClientUnavailable": "Lataustyökalu ei ole käytettävissä", - "Downloading": "Ladataan", "Edit": "Muokkaa", "EnableAutomaticSearchHelpText": "Profiilia käytetään automaattihaun yhteydessä, kun sellainen suoritetaan käyttöliittymästä tai Prowlarin toimesta.", - "EnableAutomaticSearchHelpTextWarning": "Profiilia käytetään vuorovaikutteisen haun yhteydessä.", - "EnableColorImpairedModeHelpText": "Muokattu tyyli käyttäjille, joiden värinäkö on heikentynyt. Auttaa erottamaan värikoodatun tiedon.", "Enabled": "Käytössä", - "EnableInteractiveSearchHelpTextWarning": "Tämä tietolähde ei tue hakua", "EventType": "Tapahtumatyyppi", "Exception": "Poikkeus", "FeatureRequests": "Kehitysehdotukset", @@ -223,7 +196,6 @@ "IllRestartLater": "Käynnistän uudelleen myöhemmin", "Info": "Tiedot", "LaunchBrowserHelpText": " Avaa Prowlarrin verkkokäyttöliittymä verkkoselaimeen sovelluksen käynnistyksen yhteydessä.", - "MinimumLimits": "Vähimmäismäärät", "NoChanges": "Ei muutoksia", "NoLeaveIt": "Ei, anna olla", "PendingChangesMessage": "On tallentamattomia muutoksia. Haluatko varmasti poistua sivulta?", @@ -253,7 +225,6 @@ "ApplyTagsHelpTexts1": "Tunnisteisiin kohdistettavat toimenpiteet:", "ApplyTagsHelpTexts2": "– 'Lisää' syötetyt tunnisteet aiempiin tunnisteisiin", "ApplyTagsHelpTexts4": "– 'Korvaa' kaikki aiemmat tunnisteet tai poista kaikki tunnisteet jättämällä tyhjäksi", - "Importing": "Tuodaan", "Port": "Portti", "AreYouSureYouWantToResetYourAPIKey": "Haluatko varmasti uudistaa API-avaimesi?", "Automatic": "Automaattinen", @@ -275,7 +246,6 @@ "CertificateValidationHelpText": "Aseta HTTPS-varmenteen vahvistuksen tiukkuus", "ChangeHasNotBeenSavedYet": "Muutosta ei ole vielä tallennettu", "Clear": "Tyhjennä", - "CloneIndexer": "Kloonaa tietolähde", "CloneProfile": "Kloonaa profiili", "CloseCurrentModal": "Sulje nykyinen ikkuna", "Columns": "Sarakkeet", @@ -284,20 +254,13 @@ "ConnectSettings": "Kytkentöjen asetukset", "CouldNotConnectSignalR": "SignalR-kirjastoa ei tavoitettu, eikä käyttöliittymää päivitetä", "Custom": "Mukautettu", - "DelayProfile": "Viiveprofiili", "DeleteApplicationMessageText": "Haluatko varmasti poistaa sovelluksen \"{0}\"?", "DeleteBackup": "Poista varmuuskopio", "DeleteBackupMessageText": "Haluatko varmasti poistaa varmuuskopion '{0}'?", "DeleteDownloadClient": "Poista lataustyökalu", - "DeleteIndexerMessageText": "Haluatko varmasti poistaa tietolähteen '{0}'?", "DownloadClientStatusCheckSingleClientMessage": "Lataustyökalut eivät ole virheiden vuoksi käytettävissä: {0}", "EditIndexer": "Muokkaa tietolähdettä", - "EnableAutoHelpText": "Elokuvat tältä tuontilistalta lisätään Prowlarriin automaattisesti.", - "EnableAutomaticAdd": "Automaattilisäys", "EnableAutomaticSearch": "Automaattihaku", - "EnableColorImpairedMode": "Heikentyneen värinäön tila", - "EnableCompletedDownloadHandlingHelpText": "Tuo valmistuneet lataukset lataustyökalusta automaattisesti.", - "EnableHelpText": "Luo tälle metatietotyypille metatietotiedostot.", "EnableInteractiveSearch": "Vuorovaikutteinen haku", "EnableInteractiveSearchHelpText": "Profiilia käytetään vuorovaikutteisen haun yhteydessä.", "EnableSSL": "SSL-salaus", @@ -305,7 +268,6 @@ "Error": "Virhe", "ErrorLoadingContents": "Sisällönlatauksen virhe", "Events": "Tapahtumat", - "ExistingMovies": "Olemassa olevat elokuva(t)", "ExistingTag": "Olemassa oleva tunniste", "Failed": "Epäonnistui", "Filename": "Tiedostonimi", @@ -332,9 +294,7 @@ "IndexerStatusCheckAllClientMessage": "Tietolähteet eivät ole käytettävissä virheiden vuoksi", "IndexerStatusCheckSingleClientMessage": "Tietolähteet eivät ole käytettävissä virheiden vuoksi: {0}", "NoChange": "Ei muutosta", - "NoLimitForAnyRuntime": "Ei toistoajan rajoitusta", "NoLogFiles": "Ei lokitiedostoja", - "NoMinimumForAnyRuntime": "Ei toistoajan vähimmäiskestoa", "SSLCertPasswordHelpText": "PFX-tiedoston salasana", "SSLCertPath": "SSL-varmenteen sijainti", "SSLCertPathHelpText": "PFX-tiedoston sijainti", @@ -353,7 +313,6 @@ "PendingChangesDiscardChanges": "Hylkää muutokset ja poistu", "PortNumber": "Portti", "RestoreBackup": "Palauta varmuuskopio", - "Restrictions": "Rajoitukset", "Retention": "Säilytys", "UILanguageHelpText": "Prowlarin käyttöliittymä näytetään tällä kielellä", "UILanguageHelpTextWarning": "Selaimen sivupäivitys vaaditaan", @@ -363,7 +322,7 @@ "AddDownloadClientToProwlarr": "Lisäämällä lataustyökalun Prowlarr voi käynnistää lataukset suoraan käyttöliittymästä manuaalisen haun yhteydessä.", "RedirectHelpText": "Uudelleenohjaa tietolähteeltä saapuvat latauspyynnöt ja ohjaa sieppaus suoraan sen sijaan, että se välitettäisiin Prowlarin kautta.", "FullSync": "Täysi synkronointi", - "SyncLevelFull": "Täysi synkronointi: Pitää sovelluksen täysin synkronoituna. Prowlarissa tehdyt muutokset synkronoidaan etäsovellukseen ja kaikki etäsovelluksessa tehdyt muutokset korvataan seuraavan synkronoinnin yhteydessä.", + "SyncLevelFull": "Täysi synkronointi: Pitää sovelluksen tietolähteet täysin synkronoituna. Tietolähteisiin Prowlarrissa tehdyt muutokset synkronoidaan etäsovelluksen kanssa ja kaikki etäsovelluksessa tehdyt muutokset korvataan seuraavan synkronoinnin yhteydessä.", "AppProfile": "Sovellusprofiili", "EnableIndexer": "Tietolähteen tila", "FilterPlaceHolder": "Hae tietolähteestä", @@ -387,12 +346,12 @@ "SearchIndexers": "Etsi tietolähteistä", "AddRemoveOnly": "Ainoastaan lisää/poista", "IndexerVipCheckExpiredClientMessage": "Tietolähteen VIP-edut ovat erääntyneet: {0}", - "MaintenanceRelease": "Huoltojulkaisu: Virhekorjauksia ja muita parannuksia. Lue lisää Githubin historiasta muutoshistoriasta.", + "MaintenanceRelease": "Huoltojulkaisu: Korjauksia ja muita parannuksia. Lue lisää Githubin historiasta muutoshistoriasta.", "Query": "Kysely", "Redirect": "Uudelleenohjaus", "RestartProwlarr": "Käynnistä Prowlarr uudelleen", "SyncLevel": "Synkronoinnin laajuus", - "SyncLevelAddRemove": "Ainoastaan lisää/poista: Etäsovellus päivitetään, kun sovellus lisätään tai poistetaan Prowlarista.", + "SyncLevelAddRemove": "Vain lisäys/poisto: Kun Prowlarrin tietolähteitä lisätään tai poistetaan, päivittyy myös etäsovellus.", "SyncAppIndexers": "Synkronoi tietolähteet", "TestAllApps": "Testaa kaikki sovellukset", "UnableToLoadIndexerProxies": "Tietolähdevälityspalvelinten lataus epäonnistui", @@ -403,7 +362,6 @@ "Notification": "Ilmoitus", "DeleteIndexerProxy": "Poista tiedonhaun välityspalvelin", "Encoding": "Enkoodaus", - "MonoNotNetCoreCheckMessage": "Päivitä Prowlar sen .NET Core -versioon", "SettingsLogRotateHelpText": "Lokien tallennuskansiossa säilytettävien lokitiedostojen enimmäismäärä", "SettingsLogRotate": "Lokitiedostojen kierrätys", "SettingsLogSql": "Kirjaa SQL", @@ -413,7 +371,6 @@ "DevelopmentSettings": "Kehittäjäasetukset", "Description": "Kuvaus", "Id": "Tunniste", - "ReleaseBranchCheckPreviousVersionMessage": "'{0}' on edellisen Prowlarr-version julkaisuhaara. Aseta haaraksi 'Nighly' saadaksesi päivityksiä jatkossa", "SettingsConsoleLogLevel": "Valvontalokin taso", "SettingsFilterSentryEvents": "Suodata analytiikan tapahtumia", "SettingsFilterSentryEventsHelpText": "Suodata tunnetut käyttäjävirheet pois analytiikkalähetyksistä", @@ -445,5 +402,29 @@ "AudioSearch": "Etsi ääniä", "MovieSearch": "Etsi elokuvia", "QueryOptions": "Kyselyasetukset", - "TvSearch": "Etsi televisiosarjoja" + "TvSearch": "Etsi televisiosarjoja", + "Filters": "Suodattimet", + "OnGrab": "Kun elokuva siepataan", + "OnHealthIssue": "Kun havaitaan kuntoon liittyvä ongelma", + "HistoryCleanupDaysHelpText": "Älä tyhjennä automaattisesti asettamalla arvoksi '0'.", + "HistoryCleanupDaysHelpTextWarning": "Tässä määritettyä aikaa vanhemmat tiedostot poistetaan roskakorista pysyvästi automaattisesti.", + "TestAllIndexers": "Testaa tietolähteet", + "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent-tiedon ilmoitti sovellus, joka kommunikoi API:n kanssa", + "Categories": "Kategoriat", + "Database": "Tietokanta", + "HistoryCleanup": "Historian siivous", + "IndexerAlreadySetup": "Tietolähteestä on määritetty jo ainakin yksi kopio", + "IndexerInfo": "Tietolähteen tiedot", + "MassEditor": "Massamuokkaus", + "OnApplicationUpdate": "Sovelluksen päivittyessä", + "OnApplicationUpdateHelpText": "Sovelluksen päivittyessä", + "Proxies": "Välityspalvelimet", + "Public": "Julkinen", + "SemiPrivate": "Osittain yksityinen", + "UnableToLoadApplicationList": "Sovelluslistausta ei voitu ladata", + "Url": "URL", + "Website": "Verkkosivusto", + "IndexerNoDefCheckMessage": "Tietolähteillä ei ole määritystä, eivätkä ne toimi: {0}. Poista ja/tai lisää Prowlarriin uudelleen", + "Private": "Yksityinen", + "QueryResults": "Kyselyn tulokset" } diff --git a/src/NzbDrone.Core/Localization/Core/uk.json b/src/NzbDrone.Core/Localization/Core/uk.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/src/NzbDrone.Core/Localization/Core/uk.json @@ -0,0 +1 @@ +{} From 68e41f0860845ea01073624dc6a9b2ebc4f798a0 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 27 Feb 2022 16:14:41 -0600 Subject: [PATCH 0362/2320] Fixed: WhereBuilder for Postgres --- .../Datastore/BasicRepository.cs | 2 +- .../Datastore/Extensions/BuilderExtensions.cs | 20 +- src/NzbDrone.Core/Datastore/SqlBuilder.cs | 8 + src/NzbDrone.Core/Datastore/TableMapper.cs | 2 +- src/NzbDrone.Core/Datastore/WhereBuilder.cs | 384 +---------------- .../Datastore/WhereBuilderPostgres.cs | 374 +++++++++++++++++ .../Datastore/WhereBuilderSqlite.cs | 387 ++++++++++++++++++ .../History/HistoryRepository.cs | 2 +- 8 files changed, 790 insertions(+), 389 deletions(-) create mode 100644 src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs create mode 100644 src/NzbDrone.Core/Datastore/WhereBuilderSqlite.cs diff --git a/src/NzbDrone.Core/Datastore/BasicRepository.cs b/src/NzbDrone.Core/Datastore/BasicRepository.cs index c03ecae4b..33253efa9 100644 --- a/src/NzbDrone.Core/Datastore/BasicRepository.cs +++ b/src/NzbDrone.Core/Datastore/BasicRepository.cs @@ -66,7 +66,7 @@ namespace NzbDrone.Core.Datastore _updateSql = GetUpdateSql(_properties); } - protected virtual SqlBuilder Builder() => new SqlBuilder(); + protected virtual SqlBuilder Builder() => new SqlBuilder(_database.DatabaseType); protected virtual List<TModel> Query(SqlBuilder builder) => _database.Query<TModel>(builder).ToList(); diff --git a/src/NzbDrone.Core/Datastore/Extensions/BuilderExtensions.cs b/src/NzbDrone.Core/Datastore/Extensions/BuilderExtensions.cs index dc3e442f2..d9c68da05 100644 --- a/src/NzbDrone.Core/Datastore/Extensions/BuilderExtensions.cs +++ b/src/NzbDrone.Core/Datastore/Extensions/BuilderExtensions.cs @@ -42,21 +42,21 @@ namespace NzbDrone.Core.Datastore public static SqlBuilder Where<TModel>(this SqlBuilder builder, Expression<Func<TModel, bool>> filter) { - var wb = new WhereBuilder(filter, true, builder.Sequence); + var wb = GetWhereBuilder(builder.DatabaseType, filter, true, builder.Sequence); return builder.Where(wb.ToString(), wb.Parameters); } public static SqlBuilder OrWhere<TModel>(this SqlBuilder builder, Expression<Func<TModel, bool>> filter) { - var wb = new WhereBuilder(filter, true, builder.Sequence); + var wb = GetWhereBuilder(builder.DatabaseType, filter, true, builder.Sequence); return builder.OrWhere(wb.ToString(), wb.Parameters); } public static SqlBuilder Join<TLeft, TRight>(this SqlBuilder builder, Expression<Func<TLeft, TRight, bool>> filter) { - var wb = new WhereBuilder(filter, false, builder.Sequence); + var wb = GetWhereBuilder(builder.DatabaseType, filter, false, builder.Sequence); var rightTable = TableMapping.Mapper.TableNameMapping(typeof(TRight)); @@ -65,7 +65,7 @@ namespace NzbDrone.Core.Datastore public static SqlBuilder LeftJoin<TLeft, TRight>(this SqlBuilder builder, Expression<Func<TLeft, TRight, bool>> filter) { - var wb = new WhereBuilder(filter, false, builder.Sequence); + var wb = GetWhereBuilder(builder.DatabaseType, filter, false, builder.Sequence); var rightTable = TableMapping.Mapper.TableNameMapping(typeof(TRight)); @@ -138,6 +138,18 @@ namespace NzbDrone.Core.Datastore return sb.ToString(); } + private static WhereBuilder GetWhereBuilder(DatabaseType databaseType, Expression filter, bool requireConcrete, int seq) + { + if (databaseType == DatabaseType.PostgreSQL) + { + return new WhereBuilderPostgres(filter, requireConcrete, seq); + } + else + { + return new WhereBuilderSqlite(filter, requireConcrete, seq); + } + } + private static Dictionary<string, object> ToDictionary(this DynamicParameters dynamicParams) { var argsDictionary = new Dictionary<string, object>(); diff --git a/src/NzbDrone.Core/Datastore/SqlBuilder.cs b/src/NzbDrone.Core/Datastore/SqlBuilder.cs index e686d4852..8febd5b6a 100644 --- a/src/NzbDrone.Core/Datastore/SqlBuilder.cs +++ b/src/NzbDrone.Core/Datastore/SqlBuilder.cs @@ -8,9 +8,17 @@ namespace NzbDrone.Core.Datastore public class SqlBuilder { private readonly Dictionary<string, Clauses> _data = new Dictionary<string, Clauses>(); + private readonly DatabaseType _databaseType; + + public SqlBuilder(DatabaseType databaseType) + { + _databaseType = databaseType; + } public int Sequence { get; private set; } + public DatabaseType DatabaseType => _databaseType; + public Template AddTemplate(string sql, dynamic parameters = null) => new Template(this, sql, parameters); diff --git a/src/NzbDrone.Core/Datastore/TableMapper.cs b/src/NzbDrone.Core/Datastore/TableMapper.cs index bbb84b9cb..d53e782f2 100644 --- a/src/NzbDrone.Core/Datastore/TableMapper.cs +++ b/src/NzbDrone.Core/Datastore/TableMapper.cs @@ -183,7 +183,7 @@ namespace NzbDrone.Core.Datastore (db, parent) => { var id = childIdSelector(parent); - return db.Query<TChild>(new SqlBuilder().Where<TChild>(x => x.Id == id)).SingleOrDefault(); + return db.Query<TChild>(new SqlBuilder(db.DatabaseType).Where<TChild>(x => x.Id == id)).SingleOrDefault(); }, parent => childIdSelector(parent) > 0); } diff --git a/src/NzbDrone.Core/Datastore/WhereBuilder.cs b/src/NzbDrone.Core/Datastore/WhereBuilder.cs index da94e20e1..969364e4f 100644 --- a/src/NzbDrone.Core/Datastore/WhereBuilder.cs +++ b/src/NzbDrone.Core/Datastore/WhereBuilder.cs @@ -1,389 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; using Dapper; namespace NzbDrone.Core.Datastore { - public class WhereBuilder : ExpressionVisitor + public abstract class WhereBuilder : ExpressionVisitor { - protected StringBuilder _sb; - - private const DbType EnumerableMultiParameter = (DbType)(-1); - private readonly string _paramNamePrefix; - private readonly bool _requireConcreteValue = false; - private int _paramCount = 0; - private bool _gotConcreteValue = false; - - public WhereBuilder(Expression filter, bool requireConcreteValue, int seq) - { - _paramNamePrefix = string.Format("Clause{0}", seq + 1); - _requireConcreteValue = requireConcreteValue; - _sb = new StringBuilder(); - - Parameters = new DynamicParameters(); - - if (filter != null) - { - Visit(filter); - } - } - - public DynamicParameters Parameters { get; private set; } - - private string AddParameter(object value, DbType? dbType = null) - { - _gotConcreteValue = true; - _paramCount++; - var name = _paramNamePrefix + "_P" + _paramCount; - Parameters.Add(name, value, dbType); - return '@' + name; - } - - protected override Expression VisitBinary(BinaryExpression expression) - { - _sb.Append('('); - - Visit(expression.Left); - - _sb.AppendFormat(" {0} ", Decode(expression)); - - Visit(expression.Right); - - _sb.Append(')'); - - return expression; - } - - protected override Expression VisitMethodCall(MethodCallExpression expression) - { - var method = expression.Method.Name; - - switch (expression.Method.Name) - { - case "Contains": - ParseContainsExpression(expression); - break; - - case "StartsWith": - ParseStartsWith(expression); - break; - - case "EndsWith": - ParseEndsWith(expression); - break; - - default: - var msg = string.Format("'{0}' expressions are not yet implemented in the where clause expression tree parser.", method); - throw new NotImplementedException(msg); - } - - return expression; - } - - protected override Expression VisitMemberAccess(MemberExpression expression) - { - var tableName = expression?.Expression?.Type != null ? TableMapping.Mapper.TableNameMapping(expression.Expression.Type) : null; - var gotValue = TryGetRightValue(expression, out var value); - - // Only use the SQL condition if the expression didn't resolve to an actual value - if (tableName != null && !gotValue) - { - _sb.Append($"\"{tableName}\".\"{expression.Member.Name}\""); - } - else - { - if (value != null) - { - // string is IEnumerable<Char> but we don't want to pick up that case - var type = value.GetType(); - var typeInfo = type.GetTypeInfo(); - var isEnumerable = - type != typeof(string) && ( - typeInfo.ImplementedInterfaces.Any(ti => ti.IsGenericType && ti.GetGenericTypeDefinition() == typeof(IEnumerable<>)) || - (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>))); - - var paramName = isEnumerable ? AddParameter(value, EnumerableMultiParameter) : AddParameter(value); - _sb.Append(paramName); - } - else - { - _gotConcreteValue = true; - _sb.Append("NULL"); - } - } - - return expression; - } - - protected override Expression VisitConstant(ConstantExpression expression) - { - if (expression.Value != null) - { - var paramName = AddParameter(expression.Value); - _sb.Append(paramName); - } - else - { - _gotConcreteValue = true; - _sb.Append("NULL"); - } - - return expression; - } - - private bool TryGetConstantValue(Expression expression, out object result) - { - result = null; - - if (expression is ConstantExpression constExp) - { - result = constExp.Value; - return true; - } - - return false; - } - - private bool TryGetPropertyValue(MemberExpression expression, out object result) - { - result = null; - - if (expression.Expression is MemberExpression nested) - { - // Value is passed in as a property on a parent entity - var container = (nested.Expression as ConstantExpression)?.Value; - - if (container == null) - { - return false; - } - - var entity = GetFieldValue(container, nested.Member); - result = GetFieldValue(entity, expression.Member); - return true; - } - - return false; - } - - private bool TryGetVariableValue(MemberExpression expression, out object result) - { - result = null; - - // Value is passed in as a variable - if (expression.Expression is ConstantExpression nested) - { - result = GetFieldValue(nested.Value, expression.Member); - return true; - } - - return false; - } - - private bool TryGetRightValue(Expression expression, out object value) - { - value = null; - - if (TryGetConstantValue(expression, out value)) - { - return true; - } - - var memberExp = expression as MemberExpression; - - if (TryGetPropertyValue(memberExp, out value)) - { - return true; - } - - if (TryGetVariableValue(memberExp, out value)) - { - return true; - } - - return false; - } - - private object GetFieldValue(object entity, MemberInfo member) - { - if (member.MemberType == MemberTypes.Field) - { - return (member as FieldInfo).GetValue(entity); - } - - if (member.MemberType == MemberTypes.Property) - { - return (member as PropertyInfo).GetValue(entity); - } - - throw new ArgumentException(string.Format("WhereBuilder could not get the value for {0}.{1}.", entity.GetType().Name, member.Name)); - } - - private bool IsNullVariable(Expression expression) - { - if (expression.NodeType == ExpressionType.Constant && - TryGetConstantValue(expression, out var constResult) && - constResult == null) - { - return true; - } - - if (expression.NodeType == ExpressionType.MemberAccess && - expression is MemberExpression member && - ((TryGetPropertyValue(member, out var result) && result == null) || - (TryGetVariableValue(member, out result) && result == null))) - { - return true; - } - - return false; - } - - private string Decode(BinaryExpression expression) - { - if (IsNullVariable(expression.Right)) - { - switch (expression.NodeType) - { - case ExpressionType.Equal: return "IS"; - case ExpressionType.NotEqual: return "IS NOT"; - } - } - - switch (expression.NodeType) - { - case ExpressionType.AndAlso: return "AND"; - case ExpressionType.And: return "AND"; - case ExpressionType.Equal: return "="; - case ExpressionType.GreaterThan: return ">"; - case ExpressionType.GreaterThanOrEqual: return ">="; - case ExpressionType.LessThan: return "<"; - case ExpressionType.LessThanOrEqual: return "<="; - case ExpressionType.NotEqual: return "<>"; - case ExpressionType.OrElse: return "OR"; - case ExpressionType.Or: return "OR"; - default: throw new NotSupportedException(string.Format("{0} statement is not supported", expression.NodeType.ToString())); - } - } - - private void ParseContainsExpression(MethodCallExpression expression) - { - var list = expression.Object; - - if (list != null && (list.Type == typeof(string))) - { - ParseStringContains(expression); - return; - } - - ParseEnumerableContains(expression); - } - - private void ParseEnumerableContains(MethodCallExpression body) - { - // Fish out the list and the item to compare - // It's in a different form for arrays and Lists - var list = body.Object; - Expression item; - - if (list != null) - { - // Generic collection - item = body.Arguments[0]; - } - else - { - // Static method - // Must be Enumerable.Contains(source, item) - if (body.Method.DeclaringType != typeof(Enumerable) || body.Arguments.Count != 2) - { - throw new NotSupportedException("Unexpected form of Enumerable.Contains"); - } - - list = body.Arguments[0]; - item = body.Arguments[1]; - } - - _sb.Append('('); - - Visit(item); - - _sb.Append(" IN "); - - // hardcode the integer list if it exists to bypass parameter limit - if (item.Type == typeof(int) && TryGetRightValue(list, out var value)) - { - var items = (IEnumerable<int>)value; - _sb.Append('('); - _sb.Append(string.Join(", ", items)); - _sb.Append(')'); - - _gotConcreteValue = true; - } - else - { - Visit(list); - } - - _sb.Append(')'); - } - - private void ParseStringContains(MethodCallExpression body) - { - _sb.Append('('); - - Visit(body.Object); - - _sb.Append(" LIKE '%' || "); - - Visit(body.Arguments[0]); - - _sb.Append(" || '%')"); - } - - private void ParseStartsWith(MethodCallExpression body) - { - _sb.Append('('); - - Visit(body.Object); - - _sb.Append(" LIKE "); - - Visit(body.Arguments[0]); - - _sb.Append(" || '%')"); - } - - private void ParseEndsWith(MethodCallExpression body) - { - _sb.Append('('); - - Visit(body.Object); - - _sb.Append(" LIKE '%' || "); - - Visit(body.Arguments[0]); - - _sb.Append(')'); - } - - public override string ToString() - { - var sql = _sb.ToString(); - - if (_requireConcreteValue && !_gotConcreteValue) - { - var e = new InvalidOperationException("WhereBuilder requires a concrete condition"); - e.Data.Add("sql", sql); - throw e; - } - - return sql; - } + public DynamicParameters Parameters { get; protected set; } } } diff --git a/src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs b/src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs new file mode 100644 index 000000000..bc4c39490 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs @@ -0,0 +1,374 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using Dapper; + +namespace NzbDrone.Core.Datastore +{ + public class WhereBuilderPostgres : WhereBuilder + { + protected StringBuilder _sb; + + private const DbType EnumerableMultiParameter = (DbType)(-1); + private readonly string _paramNamePrefix; + private readonly bool _requireConcreteValue = false; + private int _paramCount = 0; + private bool _gotConcreteValue = false; + + public WhereBuilderPostgres(Expression filter, bool requireConcreteValue, int seq) + { + _paramNamePrefix = string.Format("Clause{0}", seq + 1); + _requireConcreteValue = requireConcreteValue; + _sb = new StringBuilder(); + + Parameters = new DynamicParameters(); + + if (filter != null) + { + Visit(filter); + } + } + + private string AddParameter(object value, DbType? dbType = null) + { + _gotConcreteValue = true; + _paramCount++; + var name = _paramNamePrefix + "_P" + _paramCount; + Parameters.Add(name, value, dbType); + return '@' + name; + } + + protected override Expression VisitBinary(BinaryExpression expression) + { + _sb.Append('('); + + Visit(expression.Left); + + _sb.AppendFormat(" {0} ", Decode(expression)); + + Visit(expression.Right); + + _sb.Append(')'); + + return expression; + } + + protected override Expression VisitMethodCall(MethodCallExpression expression) + { + var method = expression.Method.Name; + + switch (expression.Method.Name) + { + case "Contains": + ParseContainsExpression(expression); + break; + + case "StartsWith": + ParseStartsWith(expression); + break; + + case "EndsWith": + ParseEndsWith(expression); + break; + + default: + var msg = string.Format("'{0}' expressions are not yet implemented in the where clause expression tree parser.", method); + throw new NotImplementedException(msg); + } + + return expression; + } + + protected override Expression VisitMemberAccess(MemberExpression expression) + { + var tableName = expression?.Expression?.Type != null ? TableMapping.Mapper.TableNameMapping(expression.Expression.Type) : null; + var gotValue = TryGetRightValue(expression, out var value); + + // Only use the SQL condition if the expression didn't resolve to an actual value + if (tableName != null && !gotValue) + { + _sb.Append($"\"{tableName}\".\"{expression.Member.Name}\""); + } + else + { + if (value != null) + { + // string is IEnumerable<Char> but we don't want to pick up that case + var type = value.GetType(); + var typeInfo = type.GetTypeInfo(); + var isEnumerable = + type != typeof(string) && ( + typeInfo.ImplementedInterfaces.Any(ti => ti.IsGenericType && ti.GetGenericTypeDefinition() == typeof(IEnumerable<>)) || + (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>))); + + var paramName = isEnumerable ? AddParameter(value, EnumerableMultiParameter) : AddParameter(value); + _sb.Append(paramName); + } + else + { + _gotConcreteValue = true; + _sb.Append("NULL"); + } + } + + return expression; + } + + protected override Expression VisitConstant(ConstantExpression expression) + { + if (expression.Value != null) + { + var paramName = AddParameter(expression.Value); + _sb.Append(paramName); + } + else + { + _gotConcreteValue = true; + _sb.Append("NULL"); + } + + return expression; + } + + private bool TryGetConstantValue(Expression expression, out object result) + { + result = null; + + if (expression is ConstantExpression constExp) + { + result = constExp.Value; + return true; + } + + return false; + } + + private bool TryGetPropertyValue(MemberExpression expression, out object result) + { + result = null; + + if (expression.Expression is MemberExpression nested) + { + // Value is passed in as a property on a parent entity + var container = (nested.Expression as ConstantExpression)?.Value; + + if (container == null) + { + return false; + } + + var entity = GetFieldValue(container, nested.Member); + result = GetFieldValue(entity, expression.Member); + return true; + } + + return false; + } + + private bool TryGetVariableValue(MemberExpression expression, out object result) + { + result = null; + + // Value is passed in as a variable + if (expression.Expression is ConstantExpression nested) + { + result = GetFieldValue(nested.Value, expression.Member); + return true; + } + + return false; + } + + private bool TryGetRightValue(Expression expression, out object value) + { + value = null; + + if (TryGetConstantValue(expression, out value)) + { + return true; + } + + var memberExp = expression as MemberExpression; + + if (TryGetPropertyValue(memberExp, out value)) + { + return true; + } + + if (TryGetVariableValue(memberExp, out value)) + { + return true; + } + + return false; + } + + private object GetFieldValue(object entity, MemberInfo member) + { + if (member.MemberType == MemberTypes.Field) + { + return (member as FieldInfo).GetValue(entity); + } + + if (member.MemberType == MemberTypes.Property) + { + return (member as PropertyInfo).GetValue(entity); + } + + throw new ArgumentException(string.Format("WhereBuilder could not get the value for {0}.{1}.", entity.GetType().Name, member.Name)); + } + + private bool IsNullVariable(Expression expression) + { + if (expression.NodeType == ExpressionType.Constant && + TryGetConstantValue(expression, out var constResult) && + constResult == null) + { + return true; + } + + if (expression.NodeType == ExpressionType.MemberAccess && + expression is MemberExpression member && + ((TryGetPropertyValue(member, out var result) && result == null) || + (TryGetVariableValue(member, out result) && result == null))) + { + return true; + } + + return false; + } + + private string Decode(BinaryExpression expression) + { + if (IsNullVariable(expression.Right)) + { + switch (expression.NodeType) + { + case ExpressionType.Equal: return "IS"; + case ExpressionType.NotEqual: return "IS NOT"; + } + } + + switch (expression.NodeType) + { + case ExpressionType.AndAlso: return "AND"; + case ExpressionType.And: return "AND"; + case ExpressionType.Equal: return "="; + case ExpressionType.GreaterThan: return ">"; + case ExpressionType.GreaterThanOrEqual: return ">="; + case ExpressionType.LessThan: return "<"; + case ExpressionType.LessThanOrEqual: return "<="; + case ExpressionType.NotEqual: return "<>"; + case ExpressionType.OrElse: return "OR"; + case ExpressionType.Or: return "OR"; + default: throw new NotSupportedException(string.Format("{0} statement is not supported", expression.NodeType.ToString())); + } + } + + private void ParseContainsExpression(MethodCallExpression expression) + { + var list = expression.Object; + + if (list != null && (list.Type == typeof(string))) + { + ParseStringContains(expression); + return; + } + + ParseEnumerableContains(expression); + } + + private void ParseEnumerableContains(MethodCallExpression body) + { + // Fish out the list and the item to compare + // It's in a different form for arrays and Lists + var list = body.Object; + Expression item; + + if (list != null) + { + // Generic collection + item = body.Arguments[0]; + } + else + { + // Static method + // Must be Enumerable.Contains(source, item) + if (body.Method.DeclaringType != typeof(Enumerable) || body.Arguments.Count != 2) + { + throw new NotSupportedException("Unexpected form of Enumerable.Contains"); + } + + list = body.Arguments[0]; + item = body.Arguments[1]; + } + + _sb.Append('('); + + Visit(item); + + _sb.Append(" = ANY ("); + + Visit(list); + + _sb.Append("))"); + } + + private void ParseStringContains(MethodCallExpression body) + { + _sb.Append('('); + + Visit(body.Object); + + _sb.Append(" LIKE '%' || "); + + Visit(body.Arguments[0]); + + _sb.Append(" || '%')"); + } + + private void ParseStartsWith(MethodCallExpression body) + { + _sb.Append('('); + + Visit(body.Object); + + _sb.Append(" LIKE "); + + Visit(body.Arguments[0]); + + _sb.Append(" || '%')"); + } + + private void ParseEndsWith(MethodCallExpression body) + { + _sb.Append('('); + + Visit(body.Object); + + _sb.Append(" LIKE '%' || "); + + Visit(body.Arguments[0]); + + _sb.Append(')'); + } + + public override string ToString() + { + var sql = _sb.ToString(); + + if (_requireConcreteValue && !_gotConcreteValue) + { + var e = new InvalidOperationException("WhereBuilder requires a concrete condition"); + e.Data.Add("sql", sql); + throw e; + } + + return sql; + } + } +} diff --git a/src/NzbDrone.Core/Datastore/WhereBuilderSqlite.cs b/src/NzbDrone.Core/Datastore/WhereBuilderSqlite.cs new file mode 100644 index 000000000..54b24d7e1 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/WhereBuilderSqlite.cs @@ -0,0 +1,387 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using Dapper; + +namespace NzbDrone.Core.Datastore +{ + public class WhereBuilderSqlite : WhereBuilder + { + protected StringBuilder _sb; + + private const DbType EnumerableMultiParameter = (DbType)(-1); + private readonly string _paramNamePrefix; + private readonly bool _requireConcreteValue = false; + private int _paramCount = 0; + private bool _gotConcreteValue = false; + + public WhereBuilderSqlite(Expression filter, bool requireConcreteValue, int seq) + { + _paramNamePrefix = string.Format("Clause{0}", seq + 1); + _requireConcreteValue = requireConcreteValue; + _sb = new StringBuilder(); + + Parameters = new DynamicParameters(); + + if (filter != null) + { + Visit(filter); + } + } + + private string AddParameter(object value, DbType? dbType = null) + { + _gotConcreteValue = true; + _paramCount++; + var name = _paramNamePrefix + "_P" + _paramCount; + Parameters.Add(name, value, dbType); + return '@' + name; + } + + protected override Expression VisitBinary(BinaryExpression expression) + { + _sb.Append('('); + + Visit(expression.Left); + + _sb.AppendFormat(" {0} ", Decode(expression)); + + Visit(expression.Right); + + _sb.Append(')'); + + return expression; + } + + protected override Expression VisitMethodCall(MethodCallExpression expression) + { + var method = expression.Method.Name; + + switch (expression.Method.Name) + { + case "Contains": + ParseContainsExpression(expression); + break; + + case "StartsWith": + ParseStartsWith(expression); + break; + + case "EndsWith": + ParseEndsWith(expression); + break; + + default: + var msg = string.Format("'{0}' expressions are not yet implemented in the where clause expression tree parser.", method); + throw new NotImplementedException(msg); + } + + return expression; + } + + protected override Expression VisitMemberAccess(MemberExpression expression) + { + var tableName = expression?.Expression?.Type != null ? TableMapping.Mapper.TableNameMapping(expression.Expression.Type) : null; + var gotValue = TryGetRightValue(expression, out var value); + + // Only use the SQL condition if the expression didn't resolve to an actual value + if (tableName != null && !gotValue) + { + _sb.Append($"\"{tableName}\".\"{expression.Member.Name}\""); + } + else + { + if (value != null) + { + // string is IEnumerable<Char> but we don't want to pick up that case + var type = value.GetType(); + var typeInfo = type.GetTypeInfo(); + var isEnumerable = + type != typeof(string) && ( + typeInfo.ImplementedInterfaces.Any(ti => ti.IsGenericType && ti.GetGenericTypeDefinition() == typeof(IEnumerable<>)) || + (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>))); + + var paramName = isEnumerable ? AddParameter(value, EnumerableMultiParameter) : AddParameter(value); + _sb.Append(paramName); + } + else + { + _gotConcreteValue = true; + _sb.Append("NULL"); + } + } + + return expression; + } + + protected override Expression VisitConstant(ConstantExpression expression) + { + if (expression.Value != null) + { + var paramName = AddParameter(expression.Value); + _sb.Append(paramName); + } + else + { + _gotConcreteValue = true; + _sb.Append("NULL"); + } + + return expression; + } + + private bool TryGetConstantValue(Expression expression, out object result) + { + result = null; + + if (expression is ConstantExpression constExp) + { + result = constExp.Value; + return true; + } + + return false; + } + + private bool TryGetPropertyValue(MemberExpression expression, out object result) + { + result = null; + + if (expression.Expression is MemberExpression nested) + { + // Value is passed in as a property on a parent entity + var container = (nested.Expression as ConstantExpression)?.Value; + + if (container == null) + { + return false; + } + + var entity = GetFieldValue(container, nested.Member); + result = GetFieldValue(entity, expression.Member); + return true; + } + + return false; + } + + private bool TryGetVariableValue(MemberExpression expression, out object result) + { + result = null; + + // Value is passed in as a variable + if (expression.Expression is ConstantExpression nested) + { + result = GetFieldValue(nested.Value, expression.Member); + return true; + } + + return false; + } + + private bool TryGetRightValue(Expression expression, out object value) + { + value = null; + + if (TryGetConstantValue(expression, out value)) + { + return true; + } + + var memberExp = expression as MemberExpression; + + if (TryGetPropertyValue(memberExp, out value)) + { + return true; + } + + if (TryGetVariableValue(memberExp, out value)) + { + return true; + } + + return false; + } + + private object GetFieldValue(object entity, MemberInfo member) + { + if (member.MemberType == MemberTypes.Field) + { + return (member as FieldInfo).GetValue(entity); + } + + if (member.MemberType == MemberTypes.Property) + { + return (member as PropertyInfo).GetValue(entity); + } + + throw new ArgumentException(string.Format("WhereBuilder could not get the value for {0}.{1}.", entity.GetType().Name, member.Name)); + } + + private bool IsNullVariable(Expression expression) + { + if (expression.NodeType == ExpressionType.Constant && + TryGetConstantValue(expression, out var constResult) && + constResult == null) + { + return true; + } + + if (expression.NodeType == ExpressionType.MemberAccess && + expression is MemberExpression member && + ((TryGetPropertyValue(member, out var result) && result == null) || + (TryGetVariableValue(member, out result) && result == null))) + { + return true; + } + + return false; + } + + private string Decode(BinaryExpression expression) + { + if (IsNullVariable(expression.Right)) + { + switch (expression.NodeType) + { + case ExpressionType.Equal: return "IS"; + case ExpressionType.NotEqual: return "IS NOT"; + } + } + + switch (expression.NodeType) + { + case ExpressionType.AndAlso: return "AND"; + case ExpressionType.And: return "AND"; + case ExpressionType.Equal: return "="; + case ExpressionType.GreaterThan: return ">"; + case ExpressionType.GreaterThanOrEqual: return ">="; + case ExpressionType.LessThan: return "<"; + case ExpressionType.LessThanOrEqual: return "<="; + case ExpressionType.NotEqual: return "<>"; + case ExpressionType.OrElse: return "OR"; + case ExpressionType.Or: return "OR"; + default: throw new NotSupportedException(string.Format("{0} statement is not supported", expression.NodeType.ToString())); + } + } + + private void ParseContainsExpression(MethodCallExpression expression) + { + var list = expression.Object; + + if (list != null && (list.Type == typeof(string))) + { + ParseStringContains(expression); + return; + } + + ParseEnumerableContains(expression); + } + + private void ParseEnumerableContains(MethodCallExpression body) + { + // Fish out the list and the item to compare + // It's in a different form for arrays and Lists + var list = body.Object; + Expression item; + + if (list != null) + { + // Generic collection + item = body.Arguments[0]; + } + else + { + // Static method + // Must be Enumerable.Contains(source, item) + if (body.Method.DeclaringType != typeof(Enumerable) || body.Arguments.Count != 2) + { + throw new NotSupportedException("Unexpected form of Enumerable.Contains"); + } + + list = body.Arguments[0]; + item = body.Arguments[1]; + } + + _sb.Append('('); + + Visit(item); + + _sb.Append(" IN "); + + // hardcode the integer list if it exists to bypass parameter limit + if (item.Type == typeof(int) && TryGetRightValue(list, out var value)) + { + var items = (IEnumerable<int>)value; + _sb.Append('('); + _sb.Append(string.Join(", ", items)); + _sb.Append(')'); + + _gotConcreteValue = true; + } + else + { + Visit(list); + } + + _sb.Append(')'); + } + + private void ParseStringContains(MethodCallExpression body) + { + _sb.Append('('); + + Visit(body.Object); + + _sb.Append(" LIKE '%' || "); + + Visit(body.Arguments[0]); + + _sb.Append(" || '%')"); + } + + private void ParseStartsWith(MethodCallExpression body) + { + _sb.Append('('); + + Visit(body.Object); + + _sb.Append(" LIKE "); + + Visit(body.Arguments[0]); + + _sb.Append(" || '%')"); + } + + private void ParseEndsWith(MethodCallExpression body) + { + _sb.Append('('); + + Visit(body.Object); + + _sb.Append(" LIKE '%' || "); + + Visit(body.Arguments[0]); + + _sb.Append(')'); + } + + public override string ToString() + { + var sql = _sb.ToString(); + + if (_requireConcreteValue && !_gotConcreteValue) + { + var e = new InvalidOperationException("WhereBuilder requires a concrete condition"); + e.Data.Add("sql", sql); + throw e; + } + + return sql; + } + } +} diff --git a/src/NzbDrone.Core/History/HistoryRepository.cs b/src/NzbDrone.Core/History/HistoryRepository.cs index e5e535fd8..1471d30f2 100644 --- a/src/NzbDrone.Core/History/HistoryRepository.cs +++ b/src/NzbDrone.Core/History/HistoryRepository.cs @@ -100,7 +100,7 @@ namespace NzbDrone.Core.History public int CountSince(int indexerId, DateTime date, List<HistoryEventType> eventTypes) { - var builder = new SqlBuilder() + var builder = new SqlBuilder(_database.DatabaseType) .SelectCount() .Where<History>(x => x.IndexerId == indexerId) .Where<History>(x => x.Date >= date) From c29fba3a2b355f75076a5486cbf40361d2b5571e Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 27 Feb 2022 19:10:49 -0600 Subject: [PATCH 0363/2320] Fixed: Convert List<HistoryEventTypes> to Int before passing to DB Fixes #861 --- src/NzbDrone.Core/History/HistoryRepository.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/History/HistoryRepository.cs b/src/NzbDrone.Core/History/HistoryRepository.cs index 1471d30f2..c61effdbd 100644 --- a/src/NzbDrone.Core/History/HistoryRepository.cs +++ b/src/NzbDrone.Core/History/HistoryRepository.cs @@ -100,11 +100,13 @@ namespace NzbDrone.Core.History public int CountSince(int indexerId, DateTime date, List<HistoryEventType> eventTypes) { + var intEvents = eventTypes.Select(t => (int)t).ToList(); + var builder = new SqlBuilder(_database.DatabaseType) .SelectCount() .Where<History>(x => x.IndexerId == indexerId) .Where<History>(x => x.Date >= date) - .Where<History>(x => eventTypes.Contains(x.EventType)); + .Where<History>(x => intEvents.Contains((int)x.EventType)); var sql = builder.AddPageCountTemplate(typeof(History)); From 76afb70b01f4a670d8e402d9a3de05c09611b7ab Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 27 Feb 2022 19:45:54 -0600 Subject: [PATCH 0364/2320] New: (Cardigann) Allow JSON filters Fixes #844 --- .../IndexerDefinitionUpdateService.cs | 2 +- .../Definitions/Cardigann/CardigannBase.cs | 100 +++++++++++++++++- .../Cardigann/CardigannDefinition.cs | 3 +- .../Definitions/Cardigann/CardigannParser.cs | 10 +- .../Definitions/Cardigann/CardigannRequest.cs | 7 -- 5 files changed, 104 insertions(+), 18 deletions(-) diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index a84cdec05..2bc83aae7 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.IndexerVersions /* Update Service will fall back if version # does not exist for an indexer per Ta */ private const string DEFINITION_BRANCH = "master"; - private const int DEFINITION_VERSION = 4; + private const int DEFINITION_VERSION = 5; //Used when moving yml to C# private readonly List<string> _defintionBlocklist = new List<string>() diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index 0976a9087..3dc12d51a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -48,6 +48,9 @@ namespace NzbDrone.Core.Indexers.Cardigann protected static readonly Regex _LogicFunctionRegex = new Regex( $@"\b({string.Join("|", _SupportedLogicFunctions.Select(Regex.Escape))})(?:\s+(\(?\.[^\)\s]+\)?|""[^""]+"")){{2,}}"); + // Matches CSS selectors for the JSON parser + protected static readonly Regex _jsonSelectorRegex = new Regex(@"\:(?<filter>.+?)\((?<key>.+?)\)(?=:|\z)", RegexOptions.Compiled); + public CardigannSettings Settings { get; set; } public CardigannBase(IConfigService configService, @@ -234,13 +237,20 @@ namespace NzbDrone.Core.Indexers.Cardigann if (selector.Selector != null) { - var selector_Selector = ApplyGoTemplateText(selector.Selector.TrimStart('.'), variables); - var selection = parentObj.SelectToken(selector_Selector); + var selectorSelector = ApplyGoTemplateText(selector.Selector.TrimStart('.'), variables); + selectorSelector = JsonParseFieldSelector(parentObj, selectorSelector); + + JToken selection = null; + if (selectorSelector != null) + { + selection = parentObj.SelectToken(selectorSelector); + } + if (selection == null) { if (required) { - throw new Exception(string.Format("Selector \"{0}\" didn't match {1}", selector_Selector, parentObj.ToString())); + throw new Exception(string.Format("Selector \"{0}\" didn't match {1}", selectorSelector, parentObj.ToString())); } return null; @@ -851,5 +861,89 @@ namespace NzbDrone.Core.Indexers.Cardigann return settingsBaseUrl; } + + protected JArray JsonParseRowsSelector(JToken parsedJson, string rowSelector) + { + var selector = rowSelector.Split(':')[0]; + var rowsObj = parsedJson.SelectToken(selector).Value<JArray>(); + return new JArray(rowsObj.Where(t => + JsonParseFieldSelector(t.Value<JObject>(), rowSelector.Remove(0, selector.Length)) != null)); + } + + private string JsonParseFieldSelector(JToken parsedJson, string rowSelector) + { + var selector = rowSelector.Split(':')[0]; + JToken parsedObject; + if (string.IsNullOrWhiteSpace(selector)) + { + parsedObject = parsedJson; + } + else if (parsedJson.SelectToken(selector) != null) + { + parsedObject = parsedJson.SelectToken(selector); + } + else + { + return null; + } + + foreach (Match match in _jsonSelectorRegex.Matches(rowSelector)) + { + var filter = match.Result("${filter}"); + var key = match.Result("${key}"); + Match innerMatch; + switch (filter) + { + case "has": + innerMatch = _jsonSelectorRegex.Match(key); + if (innerMatch.Success) + { + if (JsonParseFieldSelector(parsedObject, key) == null) + { + return null; + } + } + else + { + if (parsedObject.SelectToken(key) == null) + { + return null; + } + } + + break; + case "not": + innerMatch = _jsonSelectorRegex.Match(key); + if (innerMatch.Success) + { + if (JsonParseFieldSelector(parsedObject, key) != null) + { + return null; + } + } + else + { + if (parsedObject.SelectToken(key) != null) + { + return null; + } + } + + break; + case "contains": + if (!parsedObject.ToString().Contains(key)) + { + return null; + } + + break; + default: + _logger.Error(string.Format("CardigannIndexer ({0}): Unsupported selector: {1}", _definition.Id, rowSelector)); + continue; + } + } + + return selector; + } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs index 602d0f662..9b00b4043 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs @@ -151,6 +151,7 @@ namespace NzbDrone.Core.Indexers.Cardigann public int After { get; set; } public SelectorBlock Dateheaders { get; set; } public SelectorBlock Count { get; set; } + public bool Multiple { get; set; } = false; } public class SearchPathBlock : RequestBlock @@ -200,8 +201,6 @@ namespace NzbDrone.Core.Indexers.Cardigann public class ResponseBlock { public string Type { get; set; } - public string Attribute { get; set; } - public bool Multiple { get; set; } public string NoResultsMessage { get; set; } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index f09dfe81b..1916a01ed 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -83,16 +83,16 @@ namespace NzbDrone.Core.Indexers.Cardigann } } - var rowsObj = parsedJson.SelectToken(search.Rows.Selector); - if (rowsObj == null) + var rowsArray = JsonParseRowsSelector(parsedJson, search.Rows.Selector); + if (rowsArray == null) { throw new IndexerException(indexerResponse, "Error Parsing Rows Selector"); } - foreach (var row in rowsObj.Value<JArray>()) + foreach (var row in rowsArray) { - var selObj = request.SearchPath.Response.Attribute != null ? row.SelectToken(request.SearchPath.Response.Attribute).Value<JToken>() : row; - var mulRows = request.SearchPath.Response.Multiple == true ? selObj.Values<JObject>() : new List<JObject> { selObj.Value<JObject>() }; + var selObj = search.Rows.Attribute != null ? row.SelectToken(search.Rows.Attribute).Value<JToken>() : row; + var mulRows = search.Rows.Multiple ? selObj.Values<JObject>() : new List<JObject> { selObj.Value<JObject>() }; foreach (var mulRow in mulRows) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequest.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequest.cs index 37a5c2149..31ec2f587 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequest.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequest.cs @@ -8,13 +8,6 @@ namespace NzbDrone.Core.Indexers.Cardigann public Dictionary<string, object> Variables { get; private set; } public SearchPathBlock SearchPath { get; private set; } - public CardigannRequest(string url, HttpAccept httpAccept, Dictionary<string, object> variables, SearchPathBlock searchPath) - : base(url, httpAccept) - { - Variables = variables; - SearchPath = searchPath; - } - public CardigannRequest(HttpRequest httpRequest, Dictionary<string, object> variables, SearchPathBlock searchPath) : base(httpRequest) { From 80d295cce5fcb55363f3dc1417752674c2b71af5 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 27 Feb 2022 22:27:13 -0600 Subject: [PATCH 0365/2320] New: (HDTorrents) Add hd-torrents.org as Url option Fixes #853 --- src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs index e7957c0ea..3fdbc97cd 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs @@ -24,7 +24,7 @@ namespace NzbDrone.Core.Indexers.Definitions { public override string Name => "HD-Torrents"; - public override string[] IndexerUrls => new string[] { "https://hdts.ru/" }; + public override string[] IndexerUrls => new string[] { "https://hdts.ru/", "https://hd-torrents.org/" }; public override string Description => "HD-Torrents is a private torrent website with HD torrents and strict rules on their content."; private string LoginUrl => Settings.BaseUrl + "login.php"; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; From 9c5a88e2e7017ef56eb43398866357bf428bc2b1 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 16 Feb 2022 13:47:32 -0600 Subject: [PATCH 0366/2320] Fixed: Cleanse Tracker api_token from logs --- .../InstrumentationTests/CleanseLogMessageFixture.cs | 1 + src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs index 013ead2c2..1f098dee0 100644 --- a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs +++ b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs @@ -23,6 +23,7 @@ namespace NzbDrone.Common.Test.InstrumentationTests [TestCase(@"https://hd-space.org/index.php?page=login: uid=mySecret&pwd=mySecret")] [TestCase(@"https://beyond-hd.me/api/torrents/2b51db35e1912ffc138825a12b9933d2")] [TestCase(@"Req: [POST] https://www3.yggtorrent.nz/user/login: id=mySecret&pass=mySecret&ci_csrf_token=2b51db35e1912ffc138825a12b9933d2")] + [TestCase(@"https://torrentseeds.org/api/torrents/filter?api_token=2b51db35e1912ffc138825a12b9933d2&name=&sortField=created_at&sortDirection=desc&perPage=100&page=1")] //Indexer Responses diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index a3f81b6b4..60f266e66 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -11,7 +11,7 @@ namespace NzbDrone.Common.Instrumentation private static readonly Regex[] CleansingRules = new[] { // Url - new Regex(@"(?<=[?&: ;])(apikey|(?:access[-_]?)?token|pass(?:key|wd)?|auth|authkey|user|u?id|api|[a-z_]*apikey|account|pwd)=(?<secret>[^&=]+?)(?= |&|$|<)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"(?<=[?&: ;])(apikey|(?:(?:access|api)[-_]?)?token|pass(?:key|wd)?|auth|authkey|user|u?id|api|[a-z_]*apikey|account|pwd)=(?<secret>[^&=]+?)(?= |&|$|<)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"(?<=[?& ;])[^=]*?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"rss\.torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"rss\.torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), From 15dab381af86539b91792dcd3f6a9cbd12e7f50a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 27 Feb 2022 23:14:02 -0600 Subject: [PATCH 0367/2320] New: Housekeeper for ApplicationStatus --- ...CleanupOrphanedApplicationStatusFixture.cs | 54 +++++++++ ...anupOrphanedDownloadClientStatusFixture.cs | 56 +++++++++ .../FixFutureApplicationStatusTimesFixture.cs | 109 ++++++++++++++++++ ...xFutureDownloadClientStatusTimesFixture.cs | 109 ++++++++++++++++++ .../CleanupOrphanedApplicationStatus.cs | 27 +++++ 5 files changed, 355 insertions(+) create mode 100644 src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedApplicationStatusFixture.cs create mode 100644 src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedDownloadClientStatusFixture.cs create mode 100644 src/NzbDrone.Core.Test/Housekeeping/Housekeepers/FixFutureApplicationStatusTimesFixture.cs create mode 100644 src/NzbDrone.Core.Test/Housekeeping/Housekeepers/FixFutureDownloadClientStatusTimesFixture.cs create mode 100644 src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedApplicationStatus.cs diff --git a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedApplicationStatusFixture.cs b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedApplicationStatusFixture.cs new file mode 100644 index 000000000..35a6ea275 --- /dev/null +++ b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedApplicationStatusFixture.cs @@ -0,0 +1,54 @@ +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Applications; +using NzbDrone.Core.Housekeeping.Housekeepers; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.Housekeeping.Housekeepers +{ + [TestFixture] + public class CleanupOrphanedApplicationFixture : DbTest<CleanupOrphanedApplicationStatus, ApplicationStatus> + { + private ApplicationDefinition _application; + + [SetUp] + public void Setup() + { + _application = Builder<ApplicationDefinition>.CreateNew() + .BuildNew(); + } + + private void GivenApplication() + { + Db.Insert(_application); + } + + [Test] + public void should_delete_orphaned_applicationstatus() + { + var status = Builder<ApplicationStatus>.CreateNew() + .With(h => h.ProviderId = _application.Id) + .BuildNew(); + Db.Insert(status); + + Subject.Clean(); + AllStoredModels.Should().BeEmpty(); + } + + [Test] + public void should_not_delete_unorphaned_applicationstatus() + { + GivenApplication(); + + var status = Builder<ApplicationStatus>.CreateNew() + .With(h => h.ProviderId = _application.Id) + .BuildNew(); + Db.Insert(status); + + Subject.Clean(); + AllStoredModels.Should().HaveCount(1); + AllStoredModels.Should().Contain(h => h.ProviderId == _application.Id); + } + } +} diff --git a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedDownloadClientStatusFixture.cs b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedDownloadClientStatusFixture.cs new file mode 100644 index 000000000..da8e94f1e --- /dev/null +++ b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedDownloadClientStatusFixture.cs @@ -0,0 +1,56 @@ +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Download; +using NzbDrone.Core.Download.Clients.Flood; +using NzbDrone.Core.Housekeeping.Housekeepers; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.Housekeeping.Housekeepers +{ + [TestFixture] + public class CleanupOrphanedDownloadClientStatusFixture : DbTest<CleanupOrphanedDownloadClientStatus, DownloadClientStatus> + { + private DownloadClientDefinition _downloadClient; + + [SetUp] + public void Setup() + { + _downloadClient = Builder<DownloadClientDefinition>.CreateNew() + .With(c => c.Settings = new FloodSettings()) + .BuildNew(); + } + + private void GivenClient() + { + Db.Insert(_downloadClient); + } + + [Test] + public void should_delete_orphaned_downloadclientstatus() + { + var status = Builder<DownloadClientStatus>.CreateNew() + .With(h => h.ProviderId = _downloadClient.Id) + .BuildNew(); + Db.Insert(status); + + Subject.Clean(); + AllStoredModels.Should().BeEmpty(); + } + + [Test] + public void should_not_delete_unorphaned_downloadclientstatus() + { + GivenClient(); + + var status = Builder<DownloadClientStatus>.CreateNew() + .With(h => h.ProviderId = _downloadClient.Id) + .BuildNew(); + Db.Insert(status); + + Subject.Clean(); + AllStoredModels.Should().HaveCount(1); + AllStoredModels.Should().Contain(h => h.ProviderId == _downloadClient.Id); + } + } +} diff --git a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/FixFutureApplicationStatusTimesFixture.cs b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/FixFutureApplicationStatusTimesFixture.cs new file mode 100644 index 000000000..861b0538c --- /dev/null +++ b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/FixFutureApplicationStatusTimesFixture.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using FizzWare.NBuilder; +using Moq; +using NUnit.Framework; +using NzbDrone.Core.Applications; +using NzbDrone.Core.Housekeeping.Housekeepers; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.ThingiProvider.Status; + +namespace NzbDrone.Core.Test.Housekeeping.Housekeepers +{ + [TestFixture] + public class FixFutureApplicationStatusTimesFixture : CoreTest<FixFutureApplicationStatusTimes> + { + [Test] + public void should_set_disabled_till_when_its_too_far_in_the_future() + { + var disabledTillTime = EscalationBackOff.Periods[1]; + var applicationStatuses = Builder<ApplicationStatus>.CreateListOfSize(5) + .All() + .With(t => t.DisabledTill = DateTime.UtcNow.AddDays(5)) + .With(t => t.InitialFailure = DateTime.UtcNow.AddDays(-5)) + .With(t => t.MostRecentFailure = DateTime.UtcNow.AddDays(-5)) + .With(t => t.EscalationLevel = 1) + .BuildListOfNew(); + + Mocker.GetMock<IApplicationStatusRepository>() + .Setup(s => s.All()) + .Returns(applicationStatuses); + + Subject.Clean(); + + Mocker.GetMock<IApplicationStatusRepository>() + .Verify(v => v.UpdateMany( + It.Is<List<ApplicationStatus>>(i => i.All( + s => s.DisabledTill.Value <= DateTime.UtcNow.AddMinutes(disabledTillTime))))); + } + + [Test] + public void should_set_initial_failure_when_its_in_the_future() + { + var applicationStatuses = Builder<ApplicationStatus>.CreateListOfSize(5) + .All() + .With(t => t.DisabledTill = DateTime.UtcNow.AddDays(-5)) + .With(t => t.InitialFailure = DateTime.UtcNow.AddDays(5)) + .With(t => t.MostRecentFailure = DateTime.UtcNow.AddDays(-5)) + .With(t => t.EscalationLevel = 1) + .BuildListOfNew(); + + Mocker.GetMock<IApplicationStatusRepository>() + .Setup(s => s.All()) + .Returns(applicationStatuses); + + Subject.Clean(); + + Mocker.GetMock<IApplicationStatusRepository>() + .Verify(v => v.UpdateMany( + It.Is<List<ApplicationStatus>>(i => i.All( + s => s.InitialFailure.Value <= DateTime.UtcNow)))); + } + + [Test] + public void should_set_most_recent_failure_when_its_in_the_future() + { + var applicationStatuses = Builder<ApplicationStatus>.CreateListOfSize(5) + .All() + .With(t => t.DisabledTill = DateTime.UtcNow.AddDays(-5)) + .With(t => t.InitialFailure = DateTime.UtcNow.AddDays(-5)) + .With(t => t.MostRecentFailure = DateTime.UtcNow.AddDays(5)) + .With(t => t.EscalationLevel = 1) + .BuildListOfNew(); + + Mocker.GetMock<IApplicationStatusRepository>() + .Setup(s => s.All()) + .Returns(applicationStatuses); + + Subject.Clean(); + + Mocker.GetMock<IApplicationStatusRepository>() + .Verify(v => v.UpdateMany( + It.Is<List<ApplicationStatus>>(i => i.All( + s => s.MostRecentFailure.Value <= DateTime.UtcNow)))); + } + + [Test] + public void should_not_change_statuses_when_times_are_in_the_past() + { + var indexerStatuses = Builder<ApplicationStatus>.CreateListOfSize(5) + .All() + .With(t => t.DisabledTill = DateTime.UtcNow.AddDays(-5)) + .With(t => t.InitialFailure = DateTime.UtcNow.AddDays(-5)) + .With(t => t.MostRecentFailure = DateTime.UtcNow.AddDays(-5)) + .With(t => t.EscalationLevel = 0) + .BuildListOfNew(); + + Mocker.GetMock<IApplicationStatusRepository>() + .Setup(s => s.All()) + .Returns(indexerStatuses); + + Subject.Clean(); + + Mocker.GetMock<IApplicationStatusRepository>() + .Verify(v => v.UpdateMany( + It.Is<List<ApplicationStatus>>(i => i.Count == 0))); + } + } +} diff --git a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/FixFutureDownloadClientStatusTimesFixture.cs b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/FixFutureDownloadClientStatusTimesFixture.cs new file mode 100644 index 000000000..712849e69 --- /dev/null +++ b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/FixFutureDownloadClientStatusTimesFixture.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using FizzWare.NBuilder; +using Moq; +using NUnit.Framework; +using NzbDrone.Core.Download; +using NzbDrone.Core.Housekeeping.Housekeepers; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.ThingiProvider.Status; + +namespace NzbDrone.Core.Test.Housekeeping.Housekeepers +{ + [TestFixture] + public class FixFutureDownloadClientStatusTimesFixture : CoreTest<FixFutureDownloadClientStatusTimes> + { + [Test] + public void should_set_disabled_till_when_its_too_far_in_the_future() + { + var disabledTillTime = EscalationBackOff.Periods[1]; + var clientStatuses = Builder<DownloadClientStatus>.CreateListOfSize(5) + .All() + .With(t => t.DisabledTill = DateTime.UtcNow.AddDays(5)) + .With(t => t.InitialFailure = DateTime.UtcNow.AddDays(-5)) + .With(t => t.MostRecentFailure = DateTime.UtcNow.AddDays(-5)) + .With(t => t.EscalationLevel = 1) + .BuildListOfNew(); + + Mocker.GetMock<IDownloadClientStatusRepository>() + .Setup(s => s.All()) + .Returns(clientStatuses); + + Subject.Clean(); + + Mocker.GetMock<IDownloadClientStatusRepository>() + .Verify(v => v.UpdateMany( + It.Is<List<DownloadClientStatus>>(i => i.All( + s => s.DisabledTill.Value <= DateTime.UtcNow.AddMinutes(disabledTillTime))))); + } + + [Test] + public void should_set_initial_failure_when_its_in_the_future() + { + var clientStatuses = Builder<DownloadClientStatus>.CreateListOfSize(5) + .All() + .With(t => t.DisabledTill = DateTime.UtcNow.AddDays(-5)) + .With(t => t.InitialFailure = DateTime.UtcNow.AddDays(5)) + .With(t => t.MostRecentFailure = DateTime.UtcNow.AddDays(-5)) + .With(t => t.EscalationLevel = 1) + .BuildListOfNew(); + + Mocker.GetMock<IDownloadClientStatusRepository>() + .Setup(s => s.All()) + .Returns(clientStatuses); + + Subject.Clean(); + + Mocker.GetMock<IDownloadClientStatusRepository>() + .Verify(v => v.UpdateMany( + It.Is<List<DownloadClientStatus>>(i => i.All( + s => s.InitialFailure.Value <= DateTime.UtcNow)))); + } + + [Test] + public void should_set_most_recent_failure_when_its_in_the_future() + { + var clientStatuses = Builder<DownloadClientStatus>.CreateListOfSize(5) + .All() + .With(t => t.DisabledTill = DateTime.UtcNow.AddDays(-5)) + .With(t => t.InitialFailure = DateTime.UtcNow.AddDays(-5)) + .With(t => t.MostRecentFailure = DateTime.UtcNow.AddDays(5)) + .With(t => t.EscalationLevel = 1) + .BuildListOfNew(); + + Mocker.GetMock<IDownloadClientStatusRepository>() + .Setup(s => s.All()) + .Returns(clientStatuses); + + Subject.Clean(); + + Mocker.GetMock<IDownloadClientStatusRepository>() + .Verify(v => v.UpdateMany( + It.Is<List<DownloadClientStatus>>(i => i.All( + s => s.MostRecentFailure.Value <= DateTime.UtcNow)))); + } + + [Test] + public void should_not_change_statuses_when_times_are_in_the_past() + { + var clientStatuses = Builder<DownloadClientStatus>.CreateListOfSize(5) + .All() + .With(t => t.DisabledTill = DateTime.UtcNow.AddDays(-5)) + .With(t => t.InitialFailure = DateTime.UtcNow.AddDays(-5)) + .With(t => t.MostRecentFailure = DateTime.UtcNow.AddDays(-5)) + .With(t => t.EscalationLevel = 0) + .BuildListOfNew(); + + Mocker.GetMock<IDownloadClientStatusRepository>() + .Setup(s => s.All()) + .Returns(clientStatuses); + + Subject.Clean(); + + Mocker.GetMock<IDownloadClientStatusRepository>() + .Verify(v => v.UpdateMany( + It.Is<List<DownloadClientStatus>>(i => i.Count == 0))); + } + } +} diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedApplicationStatus.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedApplicationStatus.cs new file mode 100644 index 000000000..86e4cd2a5 --- /dev/null +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedApplicationStatus.cs @@ -0,0 +1,27 @@ +using Dapper; +using NzbDrone.Core.Datastore; + +namespace NzbDrone.Core.Housekeeping.Housekeepers +{ + public class CleanupOrphanedApplicationStatus : IHousekeepingTask + { + private readonly IMainDatabase _database; + + public CleanupOrphanedApplicationStatus(IMainDatabase database) + { + _database = database; + } + + public void Clean() + { + var mapper = _database.OpenConnection(); + + mapper.Execute(@"DELETE FROM ""ApplicationStatus"" + WHERE ""Id"" IN ( + SELECT ""ApplicationStatus"".""Id"" FROM ""ApplicationStatus"" + LEFT OUTER JOIN ""Applications"" + ON ""ApplicationStatus"".""ProviderId"" = ""Applications"".""Id"" + WHERE ""Applications"".""Id"" IS NULL)"); + } + } +} From 855f8d35f28cacc55a342ae1f83c249839128914 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 28 Feb 2022 18:44:12 -0600 Subject: [PATCH 0368/2320] Fixed:(pornolab) language formatting --- src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs b/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs index 8ec32e9b0..1cd899998 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs @@ -26,7 +26,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string[] IndexerUrls => new string[] { "https://pornolab.net/" }; private string LoginUrl => Settings.BaseUrl + "forum/login.php"; public override string Description => "PornoLab is a Semi-Private Russian site for Adult content"; - public override string Language => "ru-ru"; + public override string Language => "ru-RU"; public override Encoding Encoding => Encoding.GetEncoding("windows-1251"); public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPrivate; From bb3821c2544d41711691616c553d614e363b2031 Mon Sep 17 00:00:00 2001 From: gaizaharduz <89298551+gaizaharduz@users.noreply.github.com> Date: Sun, 6 Mar 2022 22:21:15 +0200 Subject: [PATCH 0369/2320] New: (RuTracker.org) add .bet mirror (#876) --- src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs index 6005cd09d..8e93bace9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs @@ -25,7 +25,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class RuTracker : TorrentIndexerBase<RuTrackerSettings> { public override string Name => "RuTracker"; - public override string[] IndexerUrls => new string[] { "https://rutracker.org/" }; + public override string[] IndexerUrls => new string[] { "https://rutracker.org/", "https://rutracker.net/" }; private string LoginUrl => Settings.BaseUrl + "forum/login.php"; public override string Description => "RuTracker is a Semi-Private Russian torrent site with a thriving file-sharing community"; From 495daf796720e43f460a1197d718ded6ccad9c94 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sun, 6 Mar 2022 20:21:21 +0000 Subject: [PATCH 0370/2320] Update translation files Updated by "Cleanup translation files" hook in Weblate. Update translation files Updated by "Cleanup translation files" hook in Weblate. Translated using Weblate (Chinese (Traditional) (zh_TW)) Currently translated at 0.4% (2 of 428 strings) Translated using Weblate (Arabic) Currently translated at 76.1% (326 of 428 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (428 of 428 strings) Translated using Weblate (Vietnamese) Currently translated at 75.9% (325 of 428 strings) Translated using Weblate (Turkish) Currently translated at 75.7% (324 of 428 strings) Translated using Weblate (Thai) Currently translated at 75.9% (325 of 428 strings) Translated using Weblate (Swedish) Currently translated at 93.4% (400 of 428 strings) Translated using Weblate (Russian) Currently translated at 77.1% (330 of 428 strings) Translated using Weblate (Romanian) Currently translated at 75.9% (325 of 428 strings) Translated using Weblate (Portuguese) Currently translated at 78.0% (334 of 428 strings) Translated using Weblate (Polish) Currently translated at 75.9% (325 of 428 strings) Translated using Weblate (Dutch) Currently translated at 93.6% (401 of 428 strings) Translated using Weblate (Dutch) Currently translated at 93.6% (401 of 428 strings) Translated using Weblate (Korean) Currently translated at 56.5% (242 of 428 strings) Translated using Weblate (Japanese) Currently translated at 75.9% (325 of 428 strings) Translated using Weblate (Italian) Currently translated at 80.3% (344 of 428 strings) Translated using Weblate (Icelandic) Currently translated at 75.9% (325 of 428 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (428 of 428 strings) Translated using Weblate (Hindi) Currently translated at 75.9% (325 of 428 strings) Translated using Weblate (Hebrew) Currently translated at 75.9% (325 of 428 strings) Translated using Weblate (French) Currently translated at 93.6% (401 of 428 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (428 of 428 strings) Translated using Weblate (Spanish) Currently translated at 76.8% (329 of 428 strings) Translated using Weblate (Greek) Currently translated at 75.9% (325 of 428 strings) Translated using Weblate (German) Currently translated at 100.0% (428 of 428 strings) Translated using Weblate (Danish) Currently translated at 75.9% (325 of 428 strings) Translated using Weblate (Czech) Currently translated at 76.4% (327 of 428 strings) Translated using Weblate (Bulgarian) Currently translated at 70.7% (303 of 428 strings) Translated using Weblate (Portuguese) Currently translated at 78.0% (334 of 428 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 98.3% (421 of 428 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 98.3% (421 of 428 strings) Translated using Weblate (German) Currently translated at 91.3% (391 of 428 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 93.6% (401 of 428 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (428 of 428 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (428 of 428 strings) Added translation using Weblate (Ukrainian) Added translation using Weblate (Persian) Added translation using Weblate (Bengali) Co-authored-by: Anonymous <noreply@weblate.org> Co-authored-by: Csaba <csab0825@gmail.com> Co-authored-by: Havok Dan <havokdan@yahoo.com.br> Co-authored-by: Nuno Filipe de Vilhena Santos <nunovilhenasantos@msn.com> Co-authored-by: Oskari Lavinto <olavinto@protonmail.com> Co-authored-by: Rico_Walker <ricardo.walker1203@gmail.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Zalhera <tobias.bechen@gmail.com> Co-authored-by: nopetw <lubduphaur@gmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ar/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/bg/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/cs/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/da/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/el/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/he/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/is/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/it/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ja/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ko/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pl/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ro/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ru/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sv/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/th/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/vi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_TW/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/ar.json | 50 ++------ src/NzbDrone.Core/Localization/Core/bg.json | 50 ++------ src/NzbDrone.Core/Localization/Core/ca.json | 1 - src/NzbDrone.Core/Localization/Core/cs.json | 51 ++------ src/NzbDrone.Core/Localization/Core/da.json | 50 ++------ src/NzbDrone.Core/Localization/Core/de.json | 115 +++++++++--------- src/NzbDrone.Core/Localization/Core/el.json | 51 ++------ src/NzbDrone.Core/Localization/Core/es.json | 51 ++------ src/NzbDrone.Core/Localization/Core/fi.json | 46 +++---- src/NzbDrone.Core/Localization/Core/fr.json | 52 ++------ src/NzbDrone.Core/Localization/Core/he.json | 50 ++------ src/NzbDrone.Core/Localization/Core/hi.json | 50 ++------ src/NzbDrone.Core/Localization/Core/hu.json | 77 +++++------- src/NzbDrone.Core/Localization/Core/is.json | 50 ++------ src/NzbDrone.Core/Localization/Core/it.json | 55 ++------- src/NzbDrone.Core/Localization/Core/ja.json | 50 ++------ src/NzbDrone.Core/Localization/Core/ko.json | 36 +----- .../Localization/Core/nb_NO.json | 1 - src/NzbDrone.Core/Localization/Core/nl.json | 54 ++------ src/NzbDrone.Core/Localization/Core/pl.json | 50 ++------ src/NzbDrone.Core/Localization/Core/pt.json | 53 ++------ .../Localization/Core/pt_BR.json | 83 +++++-------- src/NzbDrone.Core/Localization/Core/ro.json | 52 ++------ src/NzbDrone.Core/Localization/Core/ru.json | 55 ++------- src/NzbDrone.Core/Localization/Core/sk.json | 1 - src/NzbDrone.Core/Localization/Core/sv.json | 51 ++------ src/NzbDrone.Core/Localization/Core/th.json | 50 ++------ src/NzbDrone.Core/Localization/Core/tr.json | 52 ++------ src/NzbDrone.Core/Localization/Core/vi.json | 50 ++------ .../Localization/Core/zh_CN.json | 52 ++------ .../Localization/Core/zh_TW.json | 5 +- 31 files changed, 336 insertions(+), 1158 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/ar.json b/src/NzbDrone.Core/Localization/Core/ar.json index c25cb384a..63da90fbc 100644 --- a/src/NzbDrone.Core/Localization/Core/ar.json +++ b/src/NzbDrone.Core/Localization/Core/ar.json @@ -4,11 +4,8 @@ "About": "نبدة عن", "AcceptConfirmationModal": "نموذج قبول التأكيد", "Actions": "أجراءات", - "MinutesHundredTwenty": "120 دقيقة: {0}", - "MonoVersion": "نسخة أحادية", "MoreInfo": "مزيد من المعلومات", "BranchUpdateMechanism": "يستخدم الفرع بواسطة آلية التحديث الخارجية", - "CloneIndexer": "مفهرس استنساخ", "Added": "مضاف", "AddIndexer": "أضف مفهرس", "AddingTag": "مضيفا العلامة", @@ -18,7 +15,6 @@ "AreYouSureYouWantToResetYourAPIKey": "هل أنت متأكد أنك تريد إعادة تعيين مفتاح API الخاص بك؟", "Authentication": "المصادقة", "BackupIntervalHelpText": "الفاصل الزمني بين النسخ الاحتياطية التلقائية", - "Languages": "اللغات", "BackupNow": "اعمل نسخة احتياطية الان", "BackupRetentionHelpText": "سيتم تنظيف النسخ الاحتياطية التلقائية الأقدم من فترة الاحتفاظ تلقائيًا", "Backups": "النسخ الاحتياطية", @@ -32,18 +28,11 @@ "DeleteApplicationMessageText": "هل تريد بالتأكيد حذف الإشعار \"{0}\"؟", "DeleteDownloadClient": "حذف Download Client", "DeleteDownloadClientMessageText": "هل أنت متأكد أنك تريد حذف برنامج التنزيل \"{0}\"؟", - "DeleteIndexer": "حذف المفهرس", - "DeleteIndexerMessageText": "هل أنت متأكد أنك تريد حذف المفهرس \"{0}\"؟", - "EnableMediaInfoHelpText": "استخراج معلومات الفيديو مثل الدقة ووقت التشغيل ومعلومات الترميز من الملفات. يتطلب هذا من Radarr قراءة أجزاء من الملف والتي قد تسبب نشاطًا كبيرًا على القرص أو الشبكة أثناء عمليات الفحص.", "Filename": "اسم الملف", "HomePage": "الصفحة الرئيسية", "IndexerProxyStatusCheckSingleClientMessage": "المفهرسات غير متاحة بسبب الإخفاقات: {0}", "Language": "لغة", - "MinutesNinety": "90 دقيقة: {0}", "Usenet": "يوزنت", - "MinutesSixty": "60 دقيقة: {0}", - "MonoVersionCheckUpgradeRecommendedMessage": "يتم دعم الإصدار Mono المثبت حاليًا {0} ولكن يوصى بالترقية إلى {1}.", - "MovieDetailsNextMovie": "تفاصيل الفيلم: الفيلم القادم", "MovieIndexScrollTop": "فهرس الفيلم: قم بالتمرير لأعلى", "New": "جديد", "NoLinks": "لا روابط", @@ -66,7 +55,6 @@ "ProxyPasswordHelpText": "ما عليك سوى إدخال اسم مستخدم وكلمة مرور إذا كان أحدهما مطلوبًا. اتركها فارغة وإلا.", "ProxyUsernameHelpText": "ما عليك سوى إدخال اسم مستخدم وكلمة مرور إذا كان أحدهما مطلوبًا. اتركها فارغة وإلا.", "PtpOldSettingsCheckMessage": "مفهرسات PassThePopcorn التالية بها إعدادات مهملة ويجب تحديثها: {0}", - "QualitySettings": "إعدادات الجودة", "Queue": "طابور", "ReadTheWikiForMoreInformation": "اقرأ Wiki لمزيد من المعلومات", "Reddit": "رديت", @@ -83,19 +71,12 @@ "UnableToAddANewDownloadClientPleaseTryAgain": "غير قادر على إضافة عميل تنزيل جديد ، يرجى المحاولة مرة أخرى.", "UnableToAddANewIndexerPleaseTryAgain": "غير قادر على إضافة مفهرس جديد ، يرجى المحاولة مرة أخرى.", "UnableToLoadBackups": "تعذر تحميل النسخ الاحتياطية", - "UnableToLoadIndexers": "تعذر تحميل المفهرسات", - "UnableToLoadQualityDefinitions": "تعذر تحميل تعريفات الجودة", "UnsavedChanges": "التغييرات غير المحفوظة", "UpdateCheckUINotWritableMessage": "لا يمكن تثبيت التحديث لأن مجلد واجهة المستخدم '{0}' غير قابل للكتابة بواسطة المستخدم '{1}'", "UpdateScriptPathHelpText": "المسار إلى برنامج نصي مخصص يأخذ حزمة تحديث مستخرجة ويتعامل مع ما تبقى من عملية التحديث", "Username": "اسم المستخدم", "Warn": "حذر", "Yesterday": "في الامس", - "EnableColorImpairedMode": "تفعيل وضع ضعف الألوان", - "EnableColorImpairedModeHelpText": "تم تغيير النمط للسماح للمستخدمين الذين يعانون من ضعف الألوان بتمييز المعلومات المشفرة بالألوان بشكل أفضل", - "EnableCompletedDownloadHandlingHelpText": "استيراد التنزيلات المكتملة تلقائيًا من عميل التنزيل", - "EnabledHelpText": "قم بتمكين هذه القائمة للاستخدام في Radarr", - "EnableHelpText": "تفعيل إنشاء ملف البيانات الوصفية لنوع البيانات الوصفية هذا", "EnableInteractiveSearch": "تمكين البحث التفاعلي", "Source": "مصدر", "SSLCertPassword": "كلمة مرور شهادة SSL", @@ -107,19 +88,15 @@ "CouldNotConnectSignalR": "تعذر الاتصال بـ SignalR ، لن يتم تحديث واجهة المستخدم", "Dates": "تواريخ", "DBMigration": "ترحيل DB", - "DelayProfile": "ملف التأخير", "Delete": "حذف", "Details": "تفاصيل", "Donations": "التبرعات", "DownloadClient": "تحميل العميل", - "EnableAutoHelpText": "في حالة التمكين ، ستتم إضافة الأفلام تلقائيًا إلى Radarr من هذه القائمة", "IndexerStatusCheckAllClientMessage": "جميع المفهرسات غير متوفرة بسبب الفشل", "IndexerStatusCheckSingleClientMessage": "المفهرسات غير متاحة بسبب الإخفاقات: {0}", "Info": "معلومات", "Interval": "فترة", "Manual": "كتيب", - "MaximumLimits": "الحدود القصوى", - "NoLimitForAnyRuntime": "لا يوجد حد لأي وقت تشغيل", "General": "جنرال لواء", "GeneralSettings": "الاعدادات العامة", "Grabbed": "اقتطف", @@ -168,7 +145,6 @@ "IndexerProxyStatusCheckAllClientMessage": "جميع المفهرسات غير متوفرة بسبب الفشل", "NoChange": "لا تغيير", "NoLogFiles": "لا توجد ملفات سجل", - "NoMinimumForAnyRuntime": "لا يوجد حد أدنى لأي وقت تشغيل", "NoTagsHaveBeenAddedYet": "لم يتم إضافة أي علامات حتى الان", "NotificationTriggers": "مشغلات الإخطار", "NoUpdatesAreAvailable": "لا توجد تحديثات متوفرة", @@ -195,10 +171,8 @@ "Clear": "واضح", "ClientPriority": "أولوية العميل", "Tomorrow": "غدا", - "DownloadClientCheckUnableToCommunicateMessage": "تعذر الاتصال بـ {0}.", "Torrent": "السيول", "Torrents": "السيول", - "ExistingMovies": "فيلم (أفلام) موجود", "ExistingTag": "علامة موجودة", "Failed": "فشل", "FeatureRequests": "طلبات مخصصة", @@ -210,23 +184,18 @@ "History": "التاريخ", "Hostname": "اسم المضيف", "IgnoredAddresses": "العناوين التي تم تجاهلها", - "Importing": "استيراد", "UILanguage": "لغة واجهة المستخدم", "UILanguageHelpText": "اللغة التي سيستخدمها Radarr لواجهة المستخدم", "UILanguageHelpTextWarning": "يلزم إعادة تحميل المتصفح", "KeyboardShortcuts": "اختصارات لوحة المفاتيح", "LogFiles": "ملفات الدخول", "LogLevelTraceHelpTextWarning": "يجب تمكين تسجيل التتبع مؤقتًا فقط", - "MonoTlsCheckMessage": "لا يزال الحل البديل لـ Radarr Mono 4.x tls ممكّنًا ، فجرّب إزالة MONO_TLS_PROVIDER = خيار البيئة القديمة", - "Movies": "أفلام", "Name": "اسم", "NetCore": ".شبكة", "Password": "كلمه السر", - "PreferredSize": "الحجم المفضل", "Proxy": "الوكيل", "ProxyCheckResolveIpMessage": "فشل حل عنوان IP لمضيف الخادم الوكيل المكون {0}", "ProxyType": "نوع الوكيل", - "QualityDefinitions": "تعريفات الجودة", "ReleaseStatus": "حالة الإصدار", "Search": "بحث", "SettingsShortDateFormat": "تنسيق التاريخ القصير", @@ -254,16 +223,11 @@ "DownloadClients": "تحميل العملاء", "DownloadClientStatusCheckAllClientMessage": "جميع عملاء التنزيل غير متاحين بسبب الفشل", "DownloadClientStatusCheckSingleClientMessage": "برامج التنزيل غير متاحة بسبب الإخفاقات: {0}", - "DownloadClientUnavailable": "عميل التنزيل غير متوفر", - "Downloading": "جارى التحميل", "Edit": "تعديل", "EditIndexer": "تحرير المفهرس", "Enable": "ممكن", - "EnableAutomaticAdd": "تمكين إضافة تلقائية", "EnableAutomaticSearch": "تمكين البحث التلقائي", - "EnableAutomaticSearchHelpTextWarning": "سيتم استخدامها عند استخدام البحث التفاعلي", "Enabled": "ممكن", - "EnableInteractiveSearchHelpTextWarning": "البحث غير معتمد مع هذا المفهرس", "IndexerPriority": "أولوية المفهرس", "Port": "ميناء", "SettingsTimeFormat": "تنسيق الوقت", @@ -292,12 +256,10 @@ "SettingsLongDateFormat": "تنسيق التاريخ الطويل", "ConnectionLost": "انقطع الاتصال", "Connections": "روابط", - "MovieDetailsPreviousMovie": "تفاصيل الفيلم: الفيلم السابق", "MovieIndexScrollBottom": "فهرس الفيلم: التمرير لأسفل", "NoBackupsAreAvailable": "لا توجد نسخ احتياطية متاحة", "NoChanges": "لا تغيرات", "NoLeaveIt": "لا ، اتركها", - "Pending": "قيد الانتظار", "PendingChangesDiscardChanges": "تجاهل التغييرات واترك", "RSS": "RSS", "System": "النظام", @@ -328,7 +290,6 @@ "Mechanism": "آلية", "Message": "رسالة", "MIA": "MIA", - "MinimumLimits": "الحد الأدنى", "RefreshMovie": "تحديث الفيلم", "EnableAutomaticSearchHelpText": "سيتم استخدامه عند إجراء عمليات البحث التلقائي عبر واجهة المستخدم أو بواسطة Radarr", "Status": "الحالة", @@ -336,7 +297,6 @@ "ApplyTagsHelpTexts4": "استبدال: استبدل العلامات بالعلامات التي تم إدخالها (لا تدخل أي علامات لمسح جميع العلامات)", "AuthenticationMethodHelpText": "طلب اسم المستخدم وكلمة المرور للوصول إلى Radarr", "Automatic": "تلقائي", - "DownloadClientCheckNoneAvailableMessage": "لا يوجد عميل تنزيل متاح", "Mode": "الوضع", "Options": "خيارات", "Ok": "موافق", @@ -347,7 +307,6 @@ "RestartRequiredHelpTextWarning": "يتطلب إعادة التشغيل ليصبح ساري المفعول", "Restore": "استعادة", "RestoreBackup": "استرجاع النسخة الاحتياطية", - "Restrictions": "قيود", "Result": "نتيجة", "Retention": "احتفاظ", "SaveChanges": "حفظ التغييرات", @@ -358,5 +317,12 @@ "Test": "اختبار", "TestAll": "اختبار الكل", "TestAllClients": "اختبر كل العملاء", - "UnableToAddANewApplicationPleaseTryAgain": "تعذر إضافة إشعار جديد ، يرجى المحاولة مرة أخرى." + "UnableToAddANewApplicationPleaseTryAgain": "تعذر إضافة إشعار جديد ، يرجى المحاولة مرة أخرى.", + "MaintenanceRelease": "إصدار الصيانة: إصلاحات الأخطاء والتحسينات الأخرى. راجع Github Commit History لمزيد من التفاصيل", + "Filters": "منقي", + "HistoryCleanupDaysHelpText": "اضبط على 0 لتعطيل التنظيف التلقائي", + "HistoryCleanupDaysHelpTextWarning": "سيتم تنظيف الملفات الموجودة في سلة المحذوفات الأقدم من عدد الأيام المحدد تلقائيًا", + "OnGrab": "عند الاستيلاء", + "OnHealthIssue": "في قضية الصحة", + "TestAllIndexers": "اختبار كافة المفهرسات" } diff --git a/src/NzbDrone.Core/Localization/Core/bg.json b/src/NzbDrone.Core/Localization/Core/bg.json index 0298586d7..999107fb9 100644 --- a/src/NzbDrone.Core/Localization/Core/bg.json +++ b/src/NzbDrone.Core/Localization/Core/bg.json @@ -42,11 +42,9 @@ "Delete": "Изтрий", "DeleteDownloadClient": "Изтриване на клиент за изтегляне", "DeleteDownloadClientMessageText": "Наистина ли искате да изтриете клиента за изтегляне '{0}'?", - "DeleteIndexer": "Изтрийте Indexer", "DeleteNotification": "Изтриване на известието", "DeleteNotificationMessageText": "Наистина ли искате да изтриете известието '{0}'?", "Donations": "Дарения", - "DownloadClientCheckUnableToCommunicateMessage": "Не може да се комуникира с {0}.", "About": "относно", "AcceptConfirmationModal": "Приемете модал за потвърждение", "AddDownloadClient": "Добавяне на клиент за изтегляне", @@ -66,20 +64,15 @@ "Connections": "Връзки", "CouldNotConnectSignalR": "Не можах да се свържа със SignalR, потребителският интерфейс няма да се актуализира", "DeleteBackupMessageText": "Наистина ли искате да изтриете резервното копие '{0}'?", - "DeleteIndexerMessageText": "Наистина ли искате да изтриете индексатора '{0}'?", "DeleteTag": "Изтриване на маркера", "DeleteTagMessageText": "Наистина ли искате да изтриете маркера '{0}'?", - "DownloadClientCheckNoneAvailableMessage": "Няма наличен клиент за изтегляне", "IndexerProxyStatusCheckAllClientMessage": "Всички списъци са недостъпни поради неуспехи", "LastWriteTime": "Време за последно писане", "Columns": "Колони", "EnableRss": "Активиране на RSS", - "Downloading": "Изтегляне", "IndexerProxyStatusCheckSingleClientMessage": "Списъци, недостъпни поради неуспехи: {0}", - "Languages": "Езици", "LogLevel": "Log Level", "MovieIndexScrollTop": "Индекс на филма: Превъртете отгоре", - "Movies": "Филми", "Queue": "Опашка", "ReadTheWikiForMoreInformation": "Прочетете Wiki за повече информация", "Reddit": "Reddit", @@ -89,7 +82,6 @@ "RemovedFromTaskQueue": "Премахнато от опашката на задачите", "RemoveFilter": "Отстранете филтъра", "RestoreBackup": "Възстанови архива", - "Restrictions": "Ограничения", "Result": "Резултат", "Save": "Запазете", "SaveChanges": "Запазите промените", @@ -114,7 +106,6 @@ "UnableToAddANewIndexerPleaseTryAgain": "Не може да се добави нов индексатор, моля, опитайте отново.", "UnableToAddANewIndexerProxyPleaseTryAgain": "Не може да се добави нов индексатор, моля, опитайте отново.", "UnableToAddANewNotificationPleaseTryAgain": "Не може да се добави ново известие, моля, опитайте отново.", - "UnableToLoadQualityDefinitions": "Определенията за качество не могат да се заредят", "UpdateAutomaticallyHelpText": "Автоматично изтегляне и инсталиране на актуализации. Все още ще можете да инсталирате от System: Updates", "UpdateCheckStartupTranslocationMessage": "Не може да се инсталира актуализация, защото стартовата папка „{0}“ е в папка за преместване на приложения.", "ReleaseStatus": "Състояние на освобождаване", @@ -129,7 +120,6 @@ "StartupDirectory": "Стартова директория", "Disabled": "хора с увреждания", "EditIndexer": "Редактиране на Indexer", - "EnableAutomaticSearchHelpTextWarning": "Ще се използва, когато се използва интерактивно търсене", "Enabled": "Активирано", "General": "Общ", "Grabbed": "Грабната", @@ -148,21 +138,17 @@ "Language": "Език", "LogLevelTraceHelpTextWarning": "Регистрацията на проследяване трябва да бъде разрешена само временно", "Manual": "Ръчно", - "MaximumLimits": "Максимални граници", "Mechanism": "Механизъм", "Message": "Съобщение", "MIA": "МВР", - "MinutesHundredTwenty": "120 минути: {0}", "NoChange": "Няма промяна", "NoChanges": "Без промени", "NoLeaveIt": "Не, оставете го", "NoLogFiles": "Няма регистрационни файлове", - "NoMinimumForAnyRuntime": "Няма минимум за всяко време на изпълнение", "RestartRequiredHelpTextWarning": "Изисква рестартиране, за да влезе в сила", "SettingsShortDateFormat": "Формат на кратка дата", "SSLCertPath": "SSL Cert Path", "URLBase": "URL база", - "CloneIndexer": "Clone Indexer", "CloneProfile": "Профил на клониране", "EnableInteractiveSearch": "Активирайте интерактивно търсене", "TagIsNotUsedAndCanBeDeleted": "Етикетът не се използва и може да бъде изтрит", @@ -175,7 +161,6 @@ "UnableToLoadBackups": "Архивите не могат да се заредят", "AllIndexersHiddenDueToFilter": "Всички филми са скрити поради приложен филтър.", "Level": "Ниво", - "MinimumLimits": "Минимални лимити", "ApplicationStatusCheckAllClientMessage": "Всички списъци са недостъпни поради неуспехи", "ApplicationStatusCheckSingleClientMessage": "Списъци, недостъпни поради неуспехи: {0}", "Close": "Близо", @@ -204,7 +189,6 @@ "PackageVersion": "Версия на пакета", "PageSize": "Размер на страницата", "PendingChangesStayReview": "Останете и прегледайте промените", - "PreferredSize": "Предпочитан размер", "Presets": "Предварителни настройки", "Priority": "Приоритет", "PrioritySettings": "Приоритет", @@ -212,13 +196,8 @@ "SettingsLongDateFormat": "Формат с дълга дата", "SettingsShowRelativeDates": "Показване на относителни дати", "UnableToLoadDownloadClients": "Клиентите за изтегляне не могат да се заредят", - "DelayProfile": "Профил за забавяне", "Logging": "Регистрация", "Exception": "Изключение", - "MinutesNinety": "90 минути: {0}", - "MinutesSixty": "60 минути: {0}", - "MovieDetailsNextMovie": "Подробности за филма: Следващ филм", - "MovieDetailsPreviousMovie": "Подробности за филма: Предишен филм", "MovieIndexScrollBottom": "Индекс на филма: Превъртане отдолу", "Name": "Име", "New": "Ново", @@ -233,12 +212,8 @@ "ProxyCheckResolveIpMessage": "Неуспешно разрешаване на IP адреса за конфигурирания прокси хост {0}", "ProxyPasswordHelpText": "Трябва само да въведете потребителско име и парола, ако е необходимо. В противен случай ги оставете празни.", "ProxyType": "Тип прокси", - "ExistingMovies": "Съществуващи филми", "ExistingTag": "Съществуващ маркер", "ProxyUsernameHelpText": "Трябва само да въведете потребителско име и парола, ако е необходимо. В противен случай ги оставете празни.", - "QualityDefinitions": "Определения за качество", - "QualitySettings": "Настройки за качество", - "Importing": "Импортиране", "ReleaseBranchCheckOfficialBranchMessage": "Клон {0} не е валиден клон за издаване на Radarr, няма да получавате актуализации", "IncludeHealthWarningsHelpText": "Включете здравни предупреждения", "SaveSettings": "Запазване на настройките", @@ -275,8 +250,6 @@ "UpdateCheckStartupNotWritableMessage": "Не може да се инсталира актуализация, тъй като стартовата папка „{0}“ не може да се записва от потребителя „{1}“.", "UpdateCheckUINotWritableMessage": "Не може да се инсталира актуализация, защото папката „{0}“ на потребителския интерфейс не може да се записва от потребителя „{1}“.", "Enable": "Активиране", - "EnableColorImpairedMode": "Активирайте режима с увредени цветове", - "EnableColorImpairedModeHelpText": "Променен стил, за да позволи на потребителите с увредени цветове да разграничат по-добре информацията, кодирана в цвят", "EventType": "Тип на събитието", "Failed": "Се провали", "FeatureRequests": "Заявки за функции", @@ -298,10 +271,6 @@ "Indexers": "Индексатори", "IndexerStatusCheckAllClientMessage": "Всички индексатори са недостъпни поради грешки", "Mode": "Режим", - "MonoTlsCheckMessage": "Работното решение на Radarr Mono 4.x tls все още е активирано, помислете за премахване на MONO_TLS_PROVIDER = опция за наследствена среда", - "MonoVersion": "Моно версия", - "MonoVersionCheckUpgradeRecommendedMessage": "Понастоящем инсталираната моно версия {0} се поддържа, но се препоръчва надстройка до {1}.", - "NoLimitForAnyRuntime": "Няма ограничение за всяко време на изпълнение", "TagsSettingsSummary": "Вижте всички тагове и как се използват. Неизползваните маркери могат да бъдат премахнати", "TestAllClients": "Тествайте всички клиенти", "UnableToAddANewDownloadClientPleaseTryAgain": "Не може да се добави нов клиент за изтегляне, моля, опитайте отново.", @@ -315,17 +284,9 @@ "DownloadClientSettings": "Изтеглете настройките на клиента", "DownloadClientStatusCheckAllClientMessage": "Всички клиенти за изтегляне са недостъпни поради неуспехи", "DownloadClientStatusCheckSingleClientMessage": "Клиентите за изтегляне са недостъпни поради грешки: {0}", - "DownloadClientUnavailable": "Клиентът за изтегляне не е наличен", "Edit": "редактиране", - "EnableAutoHelpText": "Ако е активирано, Филмите ще бъдат автоматично добавени към Radarr от този списък", - "EnableAutomaticAdd": "Активирайте автоматичното добавяне", "EnableAutomaticSearch": "Активирайте автоматичното търсене", "EnableAutomaticSearchHelpText": "Ще се използва, когато се извършват автоматични търсения чрез потребителския интерфейс или от Radarr", - "EnableCompletedDownloadHandlingHelpText": "Автоматично импортирайте завършени изтегляния от клиент за изтегляне", - "EnabledHelpText": "Активирайте този списък за използване в Radarr", - "EnableHelpText": "Активирайте създаването на файл с метаданни за този тип метаданни", - "EnableInteractiveSearchHelpTextWarning": "Търсенето не се поддържа с този индексатор", - "EnableMediaInfoHelpText": "Извличайте видео информация като резолюция, време на работа и информация за кодеци от файлове. Това изисква от Radarr да чете части от файла, които могат да причинят висока активност на диска или мрежата по време на сканиране.", "EnableSSL": "Активирайте SSL", "EnableSslHelpText": " Изисква рестартиране, изпълнено като администратор, за да влезе в сила", "Error": "Грешка", @@ -350,12 +311,17 @@ "PageSizeHelpText": "Брой елементи за показване на всяка страница", "Password": "Парола", "Peers": "Връстници", - "Pending": "В очакване", "PendingChangesDiscardChanges": "Изхвърлете промените и оставете", "PriorityHelpText": "Приоритизирайте множество клиенти за изтегляне. Round-Robin се използва за клиенти със същия приоритет.", "Protocol": "Протокол", "UnableToLoadGeneralSettings": "Не може да се заредят общи настройки", "UnableToLoadHistory": "Историята не може да се зареди", - "UnableToLoadIndexers": "Индексаторите не могат да се заредят", - "UnableToLoadNotifications": "Известията не могат да се заредят" + "UnableToLoadNotifications": "Известията не могат да се заредят", + "MaintenanceRelease": "Издание за поддръжка: поправки на грешки и други подобрения. Вижте История на комисиите на Github за повече подробности", + "Filters": "Филтър", + "HistoryCleanupDaysHelpText": "Задайте на 0, за да деактивирате автоматичното почистване", + "HistoryCleanupDaysHelpTextWarning": "Файловете в кошчето, по-стари от избрания брой дни, ще се почистват автоматично", + "OnGrab": "На Граб", + "OnHealthIssue": "По здравен въпрос", + "TestAllIndexers": "Тествайте всички индексатори" } diff --git a/src/NzbDrone.Core/Localization/Core/ca.json b/src/NzbDrone.Core/Localization/Core/ca.json index ec9f77a0e..1dc2adb33 100644 --- a/src/NzbDrone.Core/Localization/Core/ca.json +++ b/src/NzbDrone.Core/Localization/Core/ca.json @@ -4,7 +4,6 @@ "Actions": "Accions", "AcceptConfirmationModal": "Accepta el mètode de confirmació", "About": "Quant a", - "Movies": "Pel·lícula", "New": "Nou", "Reload": "Recarregar", "Queue": "Cua", diff --git a/src/NzbDrone.Core/Localization/Core/cs.json b/src/NzbDrone.Core/Localization/Core/cs.json index 3467a6296..323649494 100644 --- a/src/NzbDrone.Core/Localization/Core/cs.json +++ b/src/NzbDrone.Core/Localization/Core/cs.json @@ -6,19 +6,16 @@ "About": "O", "Component": "Součástka", "Info": "Info", - "Languages": "Jazyky", "LogFiles": "Záznam souborů", "PrioritySettings": "Přednost", "Logs": "Protokoly", "ProxyBypassFilterHelpText": "Použijte ',' jako oddělovač a '*.' jako zástupný znak pro subdomény", - "QualityDefinitions": "Definice kvality", "SaveSettings": "Uložit nastavení", "Scheduled": "Naplánováno", "ScriptPath": "Cesta skriptu", "SetTags": "Nastavit značky", "Settings": "Nastavení", "StartTypingOrSelectAPathBelow": "Začněte psát nebo vyberte cestu níže", - "UnableToLoadIndexers": "Nelze načíst indexery", "Usenet": "Usenet", "AddDownloadClient": "Přidat staženého klienta", "Backups": "Zálohy", @@ -26,10 +23,8 @@ "MovieIndexScrollBottom": "Rejstřík filmů: Posun dolů", "ProxyType": "Typ serveru proxy", "Reddit": "Reddit", - "DownloadClientUnavailable": "Stahovací klient není k dispozici", "ErrorLoadingContents": "Chyba při načítání obsahu", "IndexerLongTermStatusCheckAllClientMessage": "Všechny indexery nejsou k dispozici z důvodu selhání po dobu delší než 6 hodin", - "MonoVersion": "Mono verze", "RemovedFromTaskQueue": "Odebráno z fronty úkolů", "ResetAPIKey": "Resetovat klíč API", "SSLCertPassword": "Heslo SSL Cert", @@ -49,7 +44,6 @@ "DownloadClientSettings": "Stáhněte si nastavení klienta", "DownloadClientStatusCheckAllClientMessage": "Všichni klienti pro stahování nejsou kvůli chybám k dispozici", "DownloadClientStatusCheckSingleClientMessage": "Stahování klientů není k dispozici z důvodu selhání: {0}", - "Downloading": "Stahování", "Folder": "Složka", "Grabs": "Urvat", "HealthNoIssues": "Žádné problémy s vaší konfigurací", @@ -68,12 +62,10 @@ "Level": "Úroveň", "LogLevel": "Úroveň protokolu", "Manual": "Manuál", - "MaximumLimits": "Maximální limity", "Message": "Zpráva", "MIA": "MIA", "Mode": "Režim", "NoTagsHaveBeenAddedYet": "Zatím nebyly přidány žádné značky", - "NoMinimumForAnyRuntime": "Žádné minimum za běhu", "Ok": "OK", "SendAnonymousUsageData": "Odesílejte anonymní údaje o používání", "UnselectAll": "Odznačit vše", @@ -91,10 +83,6 @@ "Branch": "Větev", "BranchUpdate": "Pobočka, která se má použít k aktualizaci Radarr", "EditIndexer": "Upravit indexátor", - "EnableColorImpairedModeHelpText": "Upravený styl umožňující uživatelům s barevným postižením lépe rozlišovat barevně kódované informace", - "EnableCompletedDownloadHandlingHelpText": "Automaticky importovat dokončená stahování z klienta pro stahování", - "EnabledHelpText": "Povolte tento seznam pro použití v Radarru", - "EnableHelpText": "Povolit vytváření souborů metadat pro tento typ metadat", "ForMoreInformationOnTheIndividualDownloadClients": "Další informace o jednotlivých klientech pro stahování získáte kliknutím na informační tlačítka.", "General": "Všeobecné", "ApplyTagsHelpTexts3": "Odebrat: Odebere zadané značky", @@ -103,7 +91,6 @@ "ConnectionLost": "Spojení ztraceno", "ConnectSettings": "Připojit nastavení", "Custom": "Zvyk", - "EnableAutomaticAdd": "Povolit automatické přidání", "Error": "Chyba", "Failed": "Selhalo", "FeatureRequests": "Žádosti o funkce", @@ -127,8 +114,6 @@ "ApplyTags": "Použít značky", "MoreInfo": "Více informací", "System": "Systém", - "EnableAutomaticSearchHelpTextWarning": "Bude použito při použití interaktivního vyhledávání", - "EnableColorImpairedMode": "Aktivujte režim se sníženou barevností", "Enabled": "Povoleno", "IgnoredAddresses": "Ignorované adresy", "AcceptConfirmationModal": "Přijměte potvrzení Modal", @@ -138,16 +123,8 @@ "LaunchBrowserHelpText": " Otevřete webový prohlížeč a při spuštění aplikace přejděte na domovskou stránku Radarr.", "Logging": "Protokolování", "Mechanism": "Mechanismus", - "MinutesNinety": "90 minut: {0}", - "MinutesSixty": "60 minut: {0}", - "MonoTlsCheckMessage": "Řešení Radarr Mono 4.x tls je stále povoleno, zvažte odebrání MONO_TLS_PROVIDER = možnost staršího prostředí", - "MonoVersionCheckUpgradeRecommendedMessage": "Aktuálně nainstalovaná mono verze {0} je podporována, ale doporučuje se upgradovat na {1}.", - "MovieDetailsNextMovie": "Detaily filmu: Další film", - "MovieDetailsPreviousMovie": "Detaily filmu: Předchozí film", - "Movies": "Filmy", "NoLimitForAnyRuntime": "Žádné omezení za běhu", "NoLinks": "Žádné odkazy", - "PreferredSize": "Preferovaná velikost", "Presets": "Předvolby", "Priority": "Přednost", "PriorityHelpText": "Upřednostněte více klientů pro stahování. Round-Robin se používá pro klienty se stejnou prioritou.", @@ -160,7 +137,6 @@ "ProxyPasswordHelpText": "Musíte pouze zadat uživatelské jméno a heslo, pokud je požadováno. Jinak je nechte prázdné.", "ProxyUsernameHelpText": "Musíte pouze zadat uživatelské jméno a heslo, pokud je požadováno. Jinak je nechte prázdné.", "PtpOldSettingsCheckMessage": "Následující indexovače PassThePopcorn mají zastaralá nastavení a měla by být aktualizována: {0}", - "QualitySettings": "Nastavení kvality", "Queue": "Fronta", "ReadTheWikiForMoreInformation": "Další informace najdete na Wiki", "Refresh": "Obnovit", @@ -193,7 +169,6 @@ "UnableToAddANewIndexerPleaseTryAgain": "Nelze přidat nový indexer, zkuste to znovu.", "UnableToAddANewIndexerProxyPleaseTryAgain": "Nelze přidat nový indexer, zkuste to znovu.", "UnableToLoadNotifications": "Nelze načíst oznámení", - "UnableToLoadQualityDefinitions": "Nelze načíst definice kvality", "UpdateCheckStartupTranslocationMessage": "Aktualizaci nelze nainstalovat, protože spouštěcí složka „{0}“ je ve složce Translocation aplikace.", "UpdateCheckUINotWritableMessage": "Aktualizaci nelze nainstalovat, protože uživatelská složka „{0}“ není zapisovatelná uživatelem „{1}“.", "UpdateMechanismHelpText": "Použijte vestavěný aktualizátor Radarr nebo skript", @@ -226,7 +201,6 @@ "Restart": "Restartujte", "RestartNow": "Restartovat nyní", "RestoreBackup": "Obnovit zálohu", - "Restrictions": "Omezení", "RSSIsNotSupportedWithThisIndexer": "RSS není u tohoto indexeru podporováno", "Save": "Uložit", "SSLCertPasswordHelpText": "Heslo pro soubor pfx", @@ -235,8 +209,6 @@ "UnableToLoadBackups": "Nelze načíst zálohy", "UnableToLoadDownloadClients": "Nelze načíst klienty pro stahování", "UnableToLoadGeneralSettings": "Nelze načíst obecná nastavení", - "DeleteIndexer": "Odstranit indexer", - "DeleteIndexerMessageText": "Opravdu chcete odstranit indexer „{0}“?", "DeleteNotification": "Smazat oznámení", "EnableAutomaticSearch": "Povolit automatické vyhledávání", "EnableInteractiveSearchHelpText": "Bude použito při použití interaktivního vyhledávání", @@ -245,8 +217,6 @@ "Interval": "Interval", "KeyboardShortcuts": "Klávesové zkratky", "Language": "Jazyk", - "MinimumLimits": "Minimální limity", - "MinutesHundredTwenty": "120 minut: {0}", "NoLogFiles": "Žádné soubory protokolu", "NoBackupsAreAvailable": "Nejsou k dispozici žádné zálohy", "NoChanges": "Žádné změny", @@ -278,7 +248,6 @@ "ChangeHasNotBeenSavedYet": "Změna ještě nebyla uložena", "Clear": "Průhledná", "ClientPriority": "Priorita klienta", - "CloneIndexer": "Klonovat indexátor", "CloneProfile": "Klonovat profil", "Close": "Zavřít", "ConnectionLostAutomaticMessage": "Radarr se pokusí připojit automaticky, nebo můžete kliknout na znovu načíst níže.", @@ -287,7 +256,6 @@ "Date": "datum", "Dates": "Termíny", "DBMigration": "Migrace databáze", - "DelayProfile": "Zpožděný profil", "Delete": "Vymazat", "DeleteApplicationMessageText": "Opravdu chcete smazat oznámení „{0}“?", "DeleteBackup": "Odstranit zálohu", @@ -296,25 +264,18 @@ "DeleteTagMessageText": "Opravdu chcete smazat značku „{0}“?", "Discord": "Svár", "DownloadClient": "Stáhnout klienta", - "DownloadClientCheckNoneAvailableMessage": "Není k dispozici žádný klient pro stahování", - "DownloadClientCheckUnableToCommunicateMessage": "S uživatelem {0} nelze komunikovat.", "DownloadClients": "Stáhnout klienty", "Edit": "Upravit", "Enable": "Umožnit", - "EnableAutoHelpText": "Pokud je tato možnost povolena, filmy budou automaticky přidány do Radarru z tohoto seznamu", "EnableAutomaticSearchHelpText": "Použije se, když se automatické vyhledávání provádí pomocí uživatelského rozhraní nebo Radarr", "EnableInteractiveSearch": "Povolit interaktivní vyhledávání", - "EnableInteractiveSearchHelpTextWarning": "Vyhledávání není u tohoto indexeru podporováno", - "EnableMediaInfoHelpText": "Extrahujte ze souborů informace o videu, jako je rozlišení, runtime a informace o kodeku. To vyžaduje, aby Radarr četl části souboru, což může během skenování způsobit vysokou aktivitu disku nebo sítě.", "EnableSSL": "Povolit SSL", "EnableSslHelpText": " Vyžaduje restartování spuštěné jako správce, aby se projevilo", "Events": "Události", "EventType": "Typ události", "Exception": "Výjimka", - "ExistingMovies": "Stávající filmy", "ExistingTag": "Stávající značka", "IllRestartLater": "Restartuji později", - "Importing": "Import", "IndexerLongTermStatusCheckSingleClientMessage": "Indexery nedostupné z důvodu selhání po dobu delší než 6 hodin: {0}", "IndexerStatusCheckSingleClientMessage": "Indexery nedostupné z důvodu selhání: {0}", "SettingsTimeFormat": "Časový formát", @@ -335,7 +296,6 @@ "PageSizeHelpText": "Počet položek, které se mají zobrazit na každé stránce", "Password": "Heslo", "Peers": "Vrstevníci", - "Pending": "čekající", "PendingChangesDiscardChanges": "Zahodit změny a odejít", "PortNumber": "Číslo portu", "Result": "Výsledek", @@ -357,5 +317,14 @@ "UISettings": "Nastavení uživatelského rozhraní", "UnableToLoadUISettings": "Nelze načíst nastavení uživatelského rozhraní", "UnsavedChanges": "Neuložené změny", - "UpdateAutomaticallyHelpText": "Automaticky stahovat a instalovat aktualizace. Stále budete moci instalovat ze systému: Aktualizace" + "UpdateAutomaticallyHelpText": "Automaticky stahovat a instalovat aktualizace. Stále budete moci instalovat ze systému: Aktualizace", + "NetCore": ".NET Core", + "Filters": "Filtr", + "ConnectionLostMessage": "Radarr ztratil spojení s back-endem a pro obnovení funkčnosti bude nutné jej znovu načíst.", + "HistoryCleanupDaysHelpText": "Nastavením na 0 zakážete automatické čištění", + "HistoryCleanupDaysHelpTextWarning": "Soubory v koši starší než vybraný počet dní budou automaticky vyčištěny", + "MaintenanceRelease": "Údržbové vydání: opravy chyb a další vylepšení. Další podrobnosti najdete v GitHub Commit History", + "OnGrab": "Chyť", + "OnHealthIssue": "K otázce zdraví", + "TestAllIndexers": "Vyzkoušejte všechny indexery" } diff --git a/src/NzbDrone.Core/Localization/Core/da.json b/src/NzbDrone.Core/Localization/Core/da.json index c62ab1fa7..7020e54fc 100644 --- a/src/NzbDrone.Core/Localization/Core/da.json +++ b/src/NzbDrone.Core/Localization/Core/da.json @@ -1,6 +1,5 @@ { "LastWriteTime": "Sidste Skrive Tid", - "Languages": "Sprog", "Language": "Sprog", "KeyboardShortcuts": "Keyboard Genveje", "Info": "Information", @@ -26,8 +25,6 @@ "DownloadClientStatusCheckAllClientMessage": "Alle download klienter er utilgængelige på grund af fejl", "DownloadClientsSettingsSummary": "Download klienter, download håndtering og remote path mappings", "DownloadClients": "Download Klienter", - "DownloadClientCheckUnableToCommunicateMessage": "Ude af stand til at kommunikere med {0}.", - "DownloadClientCheckNoneAvailableMessage": "Ingen download klient tilgængelig", "DownloadClient": "Download Klient", "Details": "Detaljer", "Delete": "Slet", @@ -59,10 +56,7 @@ "Add": "Tilføj", "AddDownloadClient": "Tilføj downloadklient", "DBMigration": "DB Migration", - "DelayProfile": "Udskyd Profiler", "MIA": "MIA", - "MovieDetailsNextMovie": "Filmoplysninger: Næste film", - "MovieDetailsPreviousMovie": "Filmdetaljer: Forrige film", "ResetAPIKey": "Nulstil API-nøgle", "SettingsTimeFormat": "Tidsformat", "SystemTimeCheckMessage": "Systemtiden er slukket mere end 1 dag. Planlagte opgaver kører muligvis ikke korrekt, før tiden er rettet", @@ -109,13 +103,10 @@ "BypassProxyForLocalAddresses": "Bypass-proxy til lokale adresser", "CancelPendingTask": "Er du sikker på, at du vil annullere denne afventende opgave?", "CertificateValidation": "Validering af certifikat", - "CloneIndexer": "Klonindekser", "CloseCurrentModal": "Luk Nuværende Modal", "CouldNotConnectSignalR": "Kunne ikke oprette forbindelse til SignalR, UI opdateres ikke", "DeleteApplicationMessageText": "Er du sikker på, at du vil slette underretningen '{0}'?", "DeleteDownloadClientMessageText": "Er du sikker på, at du vil slette downloadklienten '{0}'?", - "DeleteIndexer": "Slet Indexer", - "DeleteIndexerMessageText": "Er du sikker på, at du vil slette indeksøren '{0}'?", "DeleteIndexerProxyMessageText": "Er du sikker på, at du vil slette tagget '{0}'?", "DeleteNotification": "Slet underretning", "DeleteNotificationMessageText": "Er du sikker på, at du vil slette underretningen '{0}'?", @@ -125,27 +116,16 @@ "Docker": "Docker", "Donations": "Donationer", "DownloadClientSettings": "Download klientindstillinger", - "DownloadClientUnavailable": "Downloadklienten er ikke tilgængelig", - "Downloading": "Downloader", "EditIndexer": "Rediger indekser", "Enable": "Aktiver", - "EnableAutoHelpText": "Hvis det er aktiveret, føjes film automatisk til Radarr fra denne liste", - "EnableAutomaticAdd": "Aktivér automatisk tilføjelse", "EnableAutomaticSearch": "Aktivér automatisk søgning", "EnableAutomaticSearchHelpText": "Bruges, når der foretages automatiske søgninger via brugergrænsefladen eller af Radarr", - "EnableAutomaticSearchHelpTextWarning": "Bruges, når der bruges interaktiv søgning", - "EnableColorImpairedMode": "Aktivér farve-nedsat tilstand", - "EnableColorImpairedModeHelpText": "Ændret stil for at give farvehæmmede brugere bedre at skelne mellem farvekodede oplysninger", - "EnableCompletedDownloadHandlingHelpText": "Importer automatisk afsluttede downloads fra downloadklienten", "Enabled": "Aktiveret", - "EnableHelpText": "Aktivér oprettelse af metadatafiler for denne metadatatype", "EnableInteractiveSearch": "Aktivér interaktiv søgning", - "EnableMediaInfoHelpText": "Uddrag videoinformation såsom opløsning, runtime og codec-oplysninger fra filer. Dette kræver, at Radarr læser dele af filen, som kan forårsage høj disk- eller netværksaktivitet under scanninger.", "EnableRss": "Aktivér RSS", "EnableSslHelpText": " Kræver genstart, der kører som administrator for at træde i kraft", "ErrorLoadingContents": "Fejl ved indlæsning af indhold", "Exception": "Undtagelse", - "ExistingMovies": "Eksisterende film", "ExistingTag": "Eksisterende mærke", "FeatureRequests": "Funktionsanmodninger", "Filter": "Filter", @@ -158,7 +138,6 @@ "Hostname": "Værtsnavn", "IgnoredAddresses": "Ignorerede adresser", "IllRestartLater": "Jeg genstarter senere", - "Importing": "Importerer", "IncludeHealthWarningsHelpText": "Inkluder sundhedsadvarsler", "Indexer": "Indekser", "IndexerLongTermStatusCheckAllClientMessage": "Alle indeksatorer er ikke tilgængelige på grund af fejl i mere end 6 timer", @@ -173,17 +152,9 @@ "LogLevelTraceHelpTextWarning": "Sporlogning bør kun aktiveres midlertidigt", "Logs": "Logfiler", "Manual": "brugervejledning", - "MaximumLimits": "Maksimale grænser", "Mechanism": "Mekanisme", "Message": "Besked", - "MinimumLimits": "Minimumsgrænser", - "MinutesHundredTwenty": "120 minutter: {0}", - "MinutesNinety": "90 minutter: {0}", - "MinutesSixty": "60 minutter: {0}", "Mode": "Mode", - "MonoTlsCheckMessage": "Radarr Mono 4.x tls-løsning er stadig aktiveret, overvej at fjerne MONO_TLS_PROVIDER = ældre miljømulighed", - "MonoVersion": "Mono-version", - "MonoVersionCheckUpgradeRecommendedMessage": "Aktuelt installeret Mono-version {0} understøttes, men det anbefales at opgradere til {1}.", "MovieIndexScrollBottom": "Filmindeks: Rul ned", "MovieIndexScrollTop": "Filmindeks: Scroll Top", "Name": "Navn", @@ -191,23 +162,19 @@ "NoBackupsAreAvailable": "Ingen sikkerhedskopier er tilgængelige", "NoChanges": "Ingen ændringer", "NoLeaveIt": "Nej, lad det være", - "NoLimitForAnyRuntime": "Ingen grænse for nogen runtime", "NoLinks": "Ingen links", "NoLogFiles": "Ingen logfiler", - "NoMinimumForAnyRuntime": "Intet minimum for enhver driftstid", "NoTagsHaveBeenAddedYet": "Der er ikke tilføjet nogen tags endnu", "NotificationTriggers": "Meddelelsesudløsere", "OnHealthIssueHelpText": "Om sundhedsspørgsmål", "OpenThisModal": "Åbn denne modal", "PackageVersion": "Pakkeversion", "PageSize": "Sidestørrelse", - "Pending": "Verserende", "PendingChangesDiscardChanges": "Kassér ændringer og gå ud", "PendingChangesMessage": "Du har ikke gemte ændringer. Er du sikker på, at du vil forlade denne side?", "PendingChangesStayReview": "Bliv og gennemgå ændringer", "Port": "Havn", "PortNumber": "Portnummer", - "PreferredSize": "Foretrukken størrelse", "Priority": "Prioritet", "Protocol": "Protokol", "ProxyBypassFilterHelpText": "Brug ',' som en separator og '*.' som et jokertegn for underdomæner", @@ -217,8 +184,6 @@ "ProxyPasswordHelpText": "Du skal kun indtaste et brugernavn og en adgangskode, hvis der kræves et. Lad dem være tomme ellers.", "ProxyUsernameHelpText": "Du skal kun indtaste et brugernavn og en adgangskode, hvis der kræves et. Lad dem være tomme ellers.", "PtpOldSettingsCheckMessage": "Følgende PassThePopcorn-indeksatorer har forældede indstillinger og skal opdateres: {0}", - "QualityDefinitions": "Kvalitetsdefinitioner", - "QualitySettings": "Kvalitetsindstillinger", "ReadTheWikiForMoreInformation": "Læs Wiki for mere information", "Reddit": "Reddit", "Refresh": "Opdater", @@ -275,7 +240,6 @@ "UnableToAddANewIndexerPleaseTryAgain": "Kunne ikke tilføje en ny indekser. Prøv igen.", "UnableToLoadBackups": "Kunne ikke indlæse sikkerhedskopier", "UnableToLoadGeneralSettings": "Kan ikke indlæse generelle indstillinger", - "UnableToLoadIndexers": "Kan ikke indlæse indeksatorer", "UnableToLoadNotifications": "Kunne ikke indlæse meddelelser", "UnableToLoadTags": "Kan ikke indlæse tags", "UnableToLoadUISettings": "UI-indstillingerne kunne ikke indlæses", @@ -297,7 +261,6 @@ "ReleaseStatus": "Frigør status", "Restore": "Gendan", "RestoreBackup": "Gendan sikkerhedskopi", - "Restrictions": "Begrænsninger", "RSS": "RSS", "RSSIsNotSupportedWithThisIndexer": "RSS understøttes ikke med denne indekseringsenhed", "Save": "Gemme", @@ -310,12 +273,10 @@ "StartupDirectory": "Startmappe", "Status": "Status", "UnableToLoadDownloadClients": "Kunne ikke indlæse downloadklienter", - "UnableToLoadQualityDefinitions": "Kunne ikke indlæse kvalitetsdefinitioner", "UpdateCheckStartupTranslocationMessage": "Kan ikke installere opdatering, fordi startmappen '{0}' er i en App Translocation-mappe.", "UpdateMechanismHelpText": "Brug Radarrs indbyggede opdatering eller et script", "View": "Udsigt", "Warn": "Advare", - "Movies": "Film", "AddingTag": "Tilføjer tag", "ApplicationStatusCheckAllClientMessage": "Alle lister er utilgængelige på grund af fejl", "ApplicationStatusCheckSingleClientMessage": "Lister utilgængelige på grund af fejl: {0}", @@ -340,7 +301,6 @@ "ClientPriority": "Kundens prioritet", "CloneProfile": "Klonprofil", "EnableInteractiveSearchHelpText": "Bruges, når der bruges interaktiv søgning", - "EnableInteractiveSearchHelpTextWarning": "Søgning understøttes ikke med denne indekser", "UISettings": "UI-indstillinger", "NoUpdatesAreAvailable": "Ingen opdateringer er tilgængelige", "OAuthPopupMessage": "Pop-ups blokeres af din browser", @@ -357,9 +317,15 @@ "AppDataDirectory": "AppData-bibliotek", "CertificateValidationHelpText": "Skift, hvor streng HTTPS-certificering er", "ChangeHasNotBeenSavedYet": "Ændring er endnu ikke gemt", - "EnabledHelpText": "Aktivér denne liste til brug i Radarr", "ConnectSettings": "Forbind indstillinger", "DeleteBackup": "Slet sikkerhedskopi", "DeleteBackupMessageText": "Er du sikker på, at du vil slette sikkerhedskopien '{0}'?", - "DeleteDownloadClient": "Slet Download Client" + "DeleteDownloadClient": "Slet Download Client", + "MaintenanceRelease": "Vedligeholdelsesfrigivelse: fejlrettelser og andre forbedringer. Se Github Commit History for flere detaljer", + "Filters": "Filter", + "HistoryCleanupDaysHelpText": "Sæt til 0 for at deaktivere automatisk oprydning", + "HistoryCleanupDaysHelpTextWarning": "Filer i papirkurven, der er ældre end det valgte antal dage, renses automatisk", + "OnGrab": "On Grab", + "OnHealthIssue": "Om sundhedsspørgsmål", + "TestAllIndexers": "Test alle indeksører" } diff --git a/src/NzbDrone.Core/Localization/Core/de.json b/src/NzbDrone.Core/Localization/Core/de.json index 4941bc708..4ef76a47f 100644 --- a/src/NzbDrone.Core/Localization/Core/de.json +++ b/src/NzbDrone.Core/Localization/Core/de.json @@ -6,16 +6,14 @@ "Backup": "Backups", "BackupNow": "Jetzt sichern", "Clear": "Leeren", - "Connect": "Verbindungen", + "Connect": "Benachrichtigungen", "Connections": "Verbindungen", "CustomFilters": "Filter anpassen", "Date": "Datum", "Dates": "Termine", "Delete": "Löschen", - "DownloadClientCheckNoneAvailableMessage": "Es ist kein Downloader verfügbar", - "DownloadClientCheckUnableToCommunicateMessage": "Kommunikation mit {0} nicht möglich.", - "DownloadClientStatusCheckAllClientMessage": "Alle Downloader sind aufgrund von Fehlern nicht verfügbar", - "DownloadClientStatusCheckSingleClientMessage": "Downloader aufgrund von Fehlern nicht verfügbar: {0}", + "DownloadClientStatusCheckAllClientMessage": "Alle Download Clients sind aufgrund von Fehlern nicht verfügbar", + "DownloadClientStatusCheckSingleClientMessage": "Download Clients aufgrund von Fehlern nicht verfügbar: {0}", "DownloadClients": "Downloader", "Edit": "Bearbeiten", "Events": "Events", @@ -30,13 +28,9 @@ "IndexerStatusCheckAllClientMessage": "Alle Indexer sind aufgrund von Fehlern nicht verfügbar", "IndexerStatusCheckSingleClientMessage": "Indexer aufgrund von Fehlern nicht verfügbar: {0}", "Indexers": "Indexer", - "Languages": "Sprachen", "LogFiles": "Protokolle", "Logging": "Protokollierung", - "MonoNotNetCoreCheckMessage": "Bitte aktualisieren Sie auf die .NET Core-Version von Prowlarr", - "MonoTlsCheckMessage": "Der Workaround für Prowlarr Mono 4.x TLS ist weiterhin aktiviert. Entferne möglicherweise die Option MONO_TLS_PROVIDER=legacy", "MoreInfo": "Mehr Infos", - "Movies": "Filme", "NoChange": "Keine Änderung", "NoChanges": "Keine Änderungen", "Options": "Optionen", @@ -45,13 +39,10 @@ "ProxyCheckFailedToTestMessage": "Proxy konnte nicht getestet werden: {0}", "ProxyCheckResolveIpMessage": "Fehler beim Auflösen der IP-Adresse für den konfigurierten Proxy-Host {0}", "PtpOldSettingsCheckMessage": "Die folgenden PassThePopcorn-Indexer haben veraltete Einstellungen und sollten aktualisiert werden: {0}", - "QualityDefinitions": "Qualitätsdefinitionen", "Queue": "Warteschlange", "Refresh": "Aktualisieren", "ReleaseBranchCheckOfficialBranchMessage": "Zweig {0} ist kein gültiger Prowlarr-Release-Zweig. Sie erhalten keine Updates", - "ReleaseBranchCheckPreviousVersionMessage": "Zweig {0} ist für eine frühere Version von Prowlarr. Setzen Sie den Zweig für weitere Aktualisierungen auf 'nightly'", "RestoreBackup": "Backup einspielen", - "Restrictions": "Beschränkungen", "SaveChanges": "Änderungen speichern", "Scheduled": "Geplant", "Search": "Suche", @@ -74,16 +65,16 @@ "Updates": "Updates", "View": "Ansicht", "Language": "Sprache", - "UISettingsSummary": "Einstellungen für Kalender, Datumsformat und Farbbeeinträchtigung", + "UISettingsSummary": "Optionen für Datum, Sprache und Farbbeinträchtigungen", "TagsSettingsSummary": "Alle Tags und deren Benutzung anzeigen. Unbenutzte Tags können entfernt werden", "Size": "Größe", "ReleaseStatus": "Releasestatus", "Protocol": "Protokoll", "LastWriteTime": "Zuletzt beschrieben", "Indexer": "Indexer", - "DownloadClientsSettingsSummary": "Downloader, Downloadverarbeitung und Remote-Pfadzuordnungen", + "DownloadClientsSettingsSummary": "Download der Client-Konfigurationen für die Integration in die Prowlarr UI-Suche", "Grabbed": "Erfasste", - "GeneralSettingsSummary": "Port, SSL, Benutzername/Passwort, Proxy, Statistik und Updates", + "GeneralSettingsSummary": "Port, SSL, Benutzername/Passwort, Proxy, Analytik und Updates", "Filename": "Dateiname", "Failed": "Fehlgeschlagen", "EventType": "Event Typ", @@ -140,11 +131,8 @@ "PendingChangesStayReview": "Auf der Seite bleiben", "PendingChangesMessage": "Es gibt noch ungespeicherte Änderungen, bist du sicher, dass du die Seite verlassen möchtest?", "PendingChangesDiscardChanges": "Änderungen verwerfen und schließen", - "MonoVersionCheckUpgradeRecommendedMessage": "Die momentane installierte Mono Version {0} wird unterstützt aber es wird empfohlen auf {1} zu updaten.", - "ExistingMovies": "Vorhandene Filme", "UpdateAutomaticallyHelpText": "Updates automatisch herunteraden und installieren. Es kann weiterhin unter \"System -> Updates\" ein manuelles Update angestoßen werden", "UrlBaseHelpText": "Für Reverse-Proxy-Unterstützung. Die Standardeinstellung leer", - "EnableAutoHelpText": "Wenn aktiviert werden Filme dieser Liste automatisch hinzugefügt", "AppDataDirectory": "AppData Ordner", "ApplyTags": "Tags setzen", "Authentication": "Authentifizierung", @@ -163,17 +151,11 @@ "CloneProfile": "Profil kopieren", "DeleteBackup": "Backup löschen", "DeleteDownloadClient": "Downloader löschen", - "DeleteIndexer": "Indexer löschen", "DeleteTag": "Tag löschen", "Docker": "Docker", "DownloadClientSettings": "Downloader Einstellungen", "Enable": "Aktivieren", - "EnableAutomaticAdd": "Automatisch hinzufügen", "EnableAutomaticSearch": "Automatisch suchen", - "EnableColorImpairedMode": "Farbbeeinträchtigter Modus aktivieren", - "EnableCompletedDownloadHandlingHelpText": "Importiere fertige Downloads vom Downloader automatisch", - "EnabledHelpText": "Aktiviere diese Liste", - "EnableHelpText": "Metadaten Dateien erstellen für diesen Metadata Typ", "EnableInteractiveSearch": "Interaktive Suche", "EnableSSL": "SSL", "EnableSslHelpText": " Erfordert einen Neustart als Administrator", @@ -182,21 +164,17 @@ "Hostname": "Hostname", "IgnoredAddresses": "Ignorierte Adressen", "IllRestartLater": "Später neustarten", - "Importing": "Importiere", "IncludeHealthWarningsHelpText": "Zustandswarnung", - "IndexerFlags": "Indexer Flags", + "IndexerFlags": "Indexer-Flags", "Interval": "Intervall", "LogLevel": "Log Level", - "Logs": "Logs", + "Logs": "Protokolle", "Mechanism": "Verfahren", "MIA": "MIA", - "MinimumLimits": "Mindest Grenzen", "Mode": "Modus", - "MonoVersion": "Mono Version", "NetCore": ".NET Core", "New": "Neu", "NoLeaveIt": "Nein, nicht ändern", - "NoLimitForAnyRuntime": "Keine Begrenzung der Laufzeiten", "NotificationTriggers": "Benachrichtigungs Auslöser", "OnHealthIssueHelpText": "Zustandsproblem", "OpenBrowserOnStart": "Browser beim Start öffnen", @@ -205,11 +183,9 @@ "Password": "Passwort", "Port": "Port", "PortNumber": "Port Nummer", - "PreferredSize": "Bevorzugte Größe", "ProxyBypassFilterHelpText": "Verwende ',' als Trennzeichen und '*.' als Platzhalter für Subdomains", "ProxyType": "Proxy Typ", "ProxyUsernameHelpText": "Nur wenn ein Benutzername und Passwort erforderlich ist, muss es eingegeben werden. Ansonsten leer lassen.", - "QualitySettings": "Qualitäts Einstellungen", "RefreshMovie": "Film aktualisieren", "RemovedFromTaskQueue": "Aus der Aufgabenwarteschlage entfernt", "RemoveFilter": "Filter entfernen", @@ -227,25 +203,20 @@ "SuggestTranslationChange": "Schlage eine Übersetzung vor", "TagsHelpText": "Wird auf Filme mit mindestens einem passenden Tag angewandt", "TestAllClients": "Alle testen", - "UpdateMechanismHelpText": "Benutze den Built-In Updater oder ein Script", + "UpdateMechanismHelpText": "Benutze Prowlarr's Built-In Updater oder ein Script", "UpdateScriptPathHelpText": "Pfad zu einem benutzerdefinierten Skript, das ein extrahiertes Update-Paket übernimmt und den Rest des Update-Prozesses abwickelt", "Uptime": "Laufzeit", - "URLBase": "URL Base", + "URLBase": "URL-Basis", "Torrents": "Torrents", "UISettings": "Benutzeroberflächen Einstellungen", "UnableToLoadDownloadClients": "Downloader konnten nicht geladen werden", - "UnableToLoadIndexers": "Indexer konnten nicht geladen werden", "UnableToLoadNotifications": "Benachrichtigungen konnten nicht geladen werden", - "UnableToLoadQualityDefinitions": "Qualitätsdefinitionen konnten nicht geladen werden", "UnableToLoadTags": "Tags konnten nicht geladen werden", "Usenet": "Usenet", "UseProxy": "Proxy benutzen", "Username": "Benutzername", "Version": "Version", "YesCancel": "Ja, abbrechen", - "EnableColorImpairedModeHelpText": "Alternativer Stil, um farbbeeinträchtigten Benutzern eine bessere Unterscheidung farbcodierter Informationen zu ermöglichen", - "EnableMediaInfoHelpText": "Videoinformationen wie Auflösung, Laufzeit und Codec aus Datien erkennen. Dazu ist es erforderlich, dass Prowlarr Teile der Datei liest, was zu hoher Festplatten- oder Netzwerkaktivität während der Scans führen kann.", - "NoMinimumForAnyRuntime": "Kein Minimum für Laufzeiten", "AnalyticsEnabledHelpText": "Sende anonyme Nutzungs- und Fehlerinformationen an die Server von Prowlarr. Dazu gehören Informationen über Browser, welche Seiten der Prowlarr-Weboberfläche aufgerufen wurden, Fehlerberichte sowie Betriebssystem- und Laufzeitversion. Wir werden diese Informationen verwenden, um Funktionen und Fehlerbehebungen zu priorisieren.", "RestartRequiredHelpTextWarning": "Erfordert einen Neustart", "ApiKey": "API-Schlüssel", @@ -258,10 +229,7 @@ "LaunchBrowserHelpText": " Öffne die Startseite von Prowlarr im Webbrowser nach dem Start.", "ReadTheWikiForMoreInformation": "Lese das Wiki für mehr Informationen", "BackupFolderHelpText": "Relative Pfade befinden sich unter Prowlarrs AppData Ordner", - "DelayProfile": "Verzögerungsprofil", - "MaximumLimits": "Maximale Grenzen", "DeleteNotification": "Benachrichtigung löschen", - "CloneIndexer": "Indexer kopieren", "ConnectSettings": "Eintellungen für Verbindungen", "TagCannotBeDeletedWhileInUse": "Kann während der Benutzung nicht gelöscht werden", "SSLCertPathHelpText": "Pfad zur PFX Datei", @@ -269,20 +237,14 @@ "ShownClickToHide": "Angezeigt, zum verstecken klicken", "RSSIsNotSupportedWithThisIndexer": "RSS wird von diesem Indexer nicht unterstützt", "RemovingTag": "Tag entfernen", - "Pending": "Ausstehend", "Manual": "Manuell", "LogLevelTraceHelpTextWarning": "Trace logging sollte nur kurzzeitig aktiviert werden", "HiddenClickToShow": "Versteckt, klicken zum anzeigen", "ExistingTag": "Vorhandener Tag", - "EnableInteractiveSearchHelpTextWarning": "Der Indexer unterstützt keine Suchen", "EnableInteractiveSearchHelpText": "Wird bei der manuellen Suche benutzt", - "EnableAutomaticSearchHelpTextWarning": "Wird für die manuelle Suche benutzt", "EnableAutomaticSearchHelpText": "Wird für automatische Suchen genutzt die vom Benutzer oder von Prowlarr gestartet werden", - "Downloading": "Lädt herunter", - "DownloadClientUnavailable": "Downloader ist nicht verfügbar", "DeleteTagMessageText": "Tag '{0}' wirklich löschen?", "DeleteNotificationMessageText": "Benachrichtigung '{0}' wirklich löschen?", - "DeleteIndexerMessageText": "Indexer '{0}' wirklich löschen?", "DeleteDownloadClientMessageText": "Downloader '{0}' wirklich löschen?", "DeleteBackupMessageText": "Backup '{0}' wirkich löschen?", "CancelPendingTask": "Diese laufende Aufgabe wirklich abbrechen?", @@ -306,10 +268,7 @@ "NoTagsHaveBeenAddedYet": "Es wurden noch keine Tags erstellt", "NoLogFiles": "Keine Log-Dateien", "NoBackupsAreAvailable": "Es sind keine Backups vorhanden", - "MinutesSixty": "60 Minuten: {0}", - "MinutesNinety": "90 Minuten: {0}", - "MinutesHundredTwenty": "120 Minuten: {0}", - "MaintenanceRelease": "Wartungsupdate", + "MaintenanceRelease": "Wartung: Fehlerbehebung und andere Verbesserungen. Siehe Github Commit History für weitere Details", "ForMoreInformationOnTheIndividualDownloadClients": "Für mehr Infomationen klicke auf die Info-Knöpfe.", "FilterPlaceHolder": "Filme suchen", "Exception": "Ausnahme", @@ -323,7 +282,7 @@ "UILanguage": "Oberflächen Sprache ( UI Language )", "Priority": "Priorität", "InteractiveSearch": "Interaktive Suche", - "IndexerPriorityHelpText": "Indexer Priorität von 1 (höchste) bis 50 (niedrigste). Standart: 25.", + "IndexerPriorityHelpText": "Indexer Priorität von 1 (höchste) bis 50 (niedrigste). Standard: 25.", "IndexerPriority": "Priorität", "EditIndexer": "Indexer bearbeiten", "Disabled": "Deaktiviert", @@ -333,8 +292,6 @@ "OpenThisModal": "Dieses Modal öffnen", "MovieIndexScrollTop": "Filmindex: Nach oben scrollen", "MovieIndexScrollBottom": "Filmindex: Nach unten scrollen", - "MovieDetailsPreviousMovie": "Film Details: Vorheriger Film", - "MovieDetailsNextMovie": "Film Details: Nächster Film", "FocusSearchBox": "Suchbox fokussieren", "CloseCurrentModal": "Momentanes Modal schließen", "AcceptConfirmationModal": "Bestätigung akzeptieren Modal", @@ -382,7 +339,7 @@ "EditAppProfile": "App-Profil bearbeiten", "Wiki": "Wiki", "RSS": "RSS", - "RedirectHelpText": "Leiten Sie eingehende Download-Anfragen für den Indexer um, statt Proxying mit Prowlarr", + "RedirectHelpText": "Eingehende Download-Anfragen für den Indexer umleiten, anstatt Proxying mit Prowlarr", "Redirect": "Umleiten", "Reddit": "Reddit", "HomePage": "Startseite", @@ -396,8 +353,8 @@ "UnableToLoadAppProfiles": "App-Profile können nicht geladen werden", "UnableToAddANewAppProfilePleaseTryAgain": "Es kann kein neues Anwendungsprofil hinzugefügt werden. Bitte versuchen Sie es erneut.", "UnableToAddANewApplicationPleaseTryAgain": "Es kann keine neue Anwendung hinzugefügt werden. Bitte versuchen Sie es erneut.", - "SyncLevelFull": "Vollständige Synchronisierung: Hält diese App vollständig synchron. In Prowlarr vorgenommene Änderungen werden dann mit dieser App synchronisiert. Alle aus der Ferne vorgenommenen Änderungen werden von Prowlarr bei der nächsten Synchronisierung überschrieben.", - "SyncLevelAddRemove": "Nur hinzufügen und entfernen: Wenn es in Prowlarr hinzugefügt oder entfernt wird, aktualisiert es diese Remote-App.", + "SyncLevelFull": "Vollständige Synchronisierung: Hält die Indexer dieser App vollständig synchronisiert. Änderungen an Indexern in Prowlarr werden mit dieser App synchronisiert. Jede Änderung die and Indexern dieser App gemacht werden, wird von Prowlarr bei der nächsten Synchronisierung überschrieben.", + "SyncLevelAddRemove": "Nur hinzufügen und entfernen: Wenn Indexer zu Prowlarr hinzugefügt oder entfernt werden, wird diese Remote-App aktualisiert.", "SyncLevel": "Sync-Level", "Privacy": "Privatsphäre", "Presets": "Voreinstellungen", @@ -429,5 +386,45 @@ "AudioSearch": "Audio Suche", "AddIndexerProxy": "Indexer Proxy hinzufügen", "AppSettingsSummary": "Anwendungen und Einstellungen um zu konfigurieren, wie Prowlarr mit deinen PVR Programmen interagiert", - "DeleteIndexerProxy": "Indexer Proxy löschen" + "DeleteIndexerProxy": "Indexer Proxy löschen", + "Notification": "Benachrichtigungen", + "Filters": "Filter", + "Notifications": "Benachrichtigungen", + "HistoryCleanupDaysHelpText": "Auf 0 setzen um das automatische leeren des Papierkorbs zu deaktivieren", + "HistoryCleanupDaysHelpTextWarning": "Datien im Papierkorb die älter sind als der gewählte Wert, werden endgültig gelöscht", + "OnApplicationUpdate": "Bei Anwendungsaktualisierung", + "OnApplicationUpdateHelpText": "Bei Anwendungsaktualisierung", + "OnGrab": "Bei Erfassung", + "OnHealthIssue": "Bei Zustandsproblem", + "TestAllIndexers": "Alle testen", + "UserAgentProvidedByTheAppThatCalledTheAPI": "UserAgent von der App welcher die API aufgerufen hat", + "BookSearch": "Buch Suche", + "Id": "Id", + "IndexerProxies": "Indexer-Proxies", + "IndexerTagsHelpText": "Benutze Tags, um Indexer-Proxies zu spezifizieren oder um Indexer zu organisieren.", + "MovieSearch": "Film Suche", + "QueryOptions": "Abfrage-Optionen", + "Categories": "Kategorien", + "Database": "Datenbank", + "IndexerNoDefCheckMessage": "Indexer haben keine Definition und werden nicht funktionieren: {0}. Bitte entferne und (oder) füge diese neu zu Prowlarr hinzu", + "MassEditor": "Masseneditor", + "Private": "Privat", + "TvSearch": "TV Suche", + "Url": "Url", + "Auth": "Authentifizierung", + "HistoryCleanup": "Verlaufsbereinigung", + "IndexerAlreadySetup": "Mindestens eine Indexer Instanz ist bereits eingerichtet", + "IndexerInfo": "Indexer-Info", + "IndexerProxy": "Indexer-Proxy", + "IndexerSettingsSummary": "Konfiguration verschiedener globaler Indexer Einstellungen, einschließlich Proxies.", + "IndexerVipCheckExpiredClientMessage": "Die VIP Indexer Vorteile sind abgelaufen: {0}", + "IndexerVipCheckExpiringClientMessage": "Die Indexer VIP Vorteile verfallen bald: {0}", + "Proxies": "Proxies", + "Public": "Öffentlich", + "QueryResults": "Abfrageergebnisse", + "SearchType": "Suchtyp", + "SemiPrivate": "Halbprivat", + "UnableToLoadApplicationList": "Anwendungsliste kann nicht geladen werden", + "UnableToLoadIndexerProxies": "Indexer-Proxies können nicht geladen werden", + "Website": "Webseite" } diff --git a/src/NzbDrone.Core/Localization/Core/el.json b/src/NzbDrone.Core/Localization/Core/el.json index dd7ee2a33..5e65f50a2 100644 --- a/src/NzbDrone.Core/Localization/Core/el.json +++ b/src/NzbDrone.Core/Localization/Core/el.json @@ -1,7 +1,5 @@ { "DownloadClients": "Προγράμματα Λήψης", - "DownloadClientCheckUnableToCommunicateMessage": "Αδύνατο να επικοινωνήσει με {0}.", - "DownloadClientCheckNoneAvailableMessage": "Δεν υπάρχει διαθέσιμο πρόγραμμα Λήψης", "DownloadClient": "Πρόγραμμα Λήψης", "Details": "Λεπτομέρειες", "Delete": "Διαγραφή", @@ -61,7 +59,6 @@ "IllRestartLater": "Θα επανεκκινήσω αργότερα", "Protocol": "Πρωτόκολλο", "Reddit": "Reddit", - "Restrictions": "Περιορισμοί", "Result": "Αποτέλεσμα", "Retention": "Κράτηση", "RSS": "RSS", @@ -77,16 +74,13 @@ "ApplyTagsHelpTexts2": "Προσθήκη: Προσθέστε τις ετικέτες στην υπάρχουσα λίστα ετικετών", "ApplyTagsHelpTexts3": "Αφαίρεση: Καταργήστε τις καταχωρημένες ετικέτες", "AreYouSureYouWantToResetYourAPIKey": "Είστε βέβαιοι ότι θέλετε να επαναφέρετε το κλειδί API σας;", - "DeleteIndexer": "Διαγραφή ευρετηρίου", "NoChange": "Καμία αλλαγή", "Port": "Λιμάνι", "PortNumber": "Αριθμός θύρας", - "PreferredSize": "Προτιμώμενο μέγεθος", "IndexerStatusCheckAllClientMessage": "Όλοι οι δείκτες δεν είναι διαθέσιμοι λόγω αστοχιών", "IndexerStatusCheckSingleClientMessage": "Τα ευρετήρια δεν είναι διαθέσιμα λόγω αστοχιών: {0}", "KeyboardShortcuts": "Συντομεύσεις πληκτρολογίου", "Language": "Γλώσσα", - "MonoTlsCheckMessage": "Η λύση Radarr Mono 4.x tls είναι ακόμα ενεργοποιημένη, εξετάστε το ενδεχόμενο να καταργήσετε το MONO_TLS_PROVIDER = επιλογή περιβάλλοντος παλαιού τύπου", "PriorityHelpText": "Προτεραιότητα πολλαπλών πελατών λήψης. Το Round-Robin χρησιμοποιείται για πελάτες με την ίδια προτεραιότητα.", "PrioritySettings": "Προτεραιότητα", "Reset": "Επαναφορά", @@ -103,11 +97,6 @@ "ConnectSettings": "Σύνδεση ρυθμίσεων", "Disabled": "άτομα με ειδικές ανάγκες", "Manual": "Εγχειρίδιο", - "MaximumLimits": "Μέγιστα όρια", - "MinutesSixty": "60 λεπτά: {0}", - "MovieDetailsNextMovie": "Λεπτομέρειες ταινίας: Επόμενη ταινία", - "QualityDefinitions": "Ορισμοί ποιότητας", - "QualitySettings": "Ρυθμίσεις ποιότητας", "SetTags": "Ορισμός ετικετών", "ShowSearch": "Εμφάνιση αναζήτησης", "Status": "Κατάσταση", @@ -123,7 +112,6 @@ "IndexerPriority": "Προτεραιότητα ευρετηρίου", "Indexers": "Ευρετήρια", "Info": "Πληροφορίες", - "Languages": "Γλώσσες", "LastWriteTime": "Τελευταία ώρα εγγραφής", "Level": "Επίπεδο", "LogLevel": "Επίπεδο καταγραφής", @@ -143,24 +131,16 @@ "CloneProfile": "Προφίλ κλώνου", "CloseCurrentModal": "Κλείσιμο τρέχοντος modal", "DBMigration": "Μετεγκατάσταση DB", - "DelayProfile": "Προφίλ χρονοκαθυστέρησης", "DeleteApplicationMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε την ειδοποίηση \"{0}\";", "DeleteBackupMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε το αντίγραφο ασφαλείας \"{0}\";", - "DeleteIndexerMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε το ευρετήριο \"{0}\";", "DeleteIndexerProxyMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε τη λίστα \"{0}\";", "DeleteNotificationMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε την ειδοποίηση \"{0}\";", "DeleteTagMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε την ετικέτα \"{0}\";", - "DownloadClientUnavailable": "Ο πελάτης λήψης δεν είναι διαθέσιμος", - "EnableAutoHelpText": "Εάν ενεργοποιηθεί, οι Ταινίες θα προστεθούν αυτόματα στο Radarr από αυτήν τη λίστα", - "EnableAutomaticAdd": "Ενεργοποίηση αυτόματης προσθήκης", "EnableAutomaticSearch": "Ενεργοποίηση αυτόματης αναζήτησης", "EnableAutomaticSearchHelpText": "Θα χρησιμοποιηθεί όταν πραγματοποιούνται αυτόματες αναζητήσεις μέσω του περιβάλλοντος χρήστη ή του Radarr", - "EnableColorImpairedModeHelpText": "Τροποποιημένο στυλ για να επιτρέπεται στους χρήστες με προβλήματα χρώματος να διακρίνουν καλύτερα τις πληροφορίες με χρωματική κωδικοποίηση", - "EnableMediaInfoHelpText": "Εξαγωγή πληροφοριών βίντεο, όπως ανάλυση, χρόνος εκτέλεσης και πληροφορίες κωδικοποιητή από αρχεία. Αυτό απαιτεί από τον Radarr να διαβάσει τμήματα του αρχείου που ενδέχεται να προκαλέσουν υψηλή δραστηριότητα δίσκου ή δικτύου κατά τη διάρκεια των σαρώσεων.", "EnableSslHelpText": " Απαιτείται επανεκκίνηση ως διαχειριστής για να τεθεί σε ισχύ", "Error": "Λάθος", "ErrorLoadingContents": "Σφάλμα κατά τη φόρτωση περιεχομένων", - "ExistingMovies": "Υφιστάμενες ταινίες", "GeneralSettings": "Γενικές Ρυθμίσεις", "Grabs": "Αρπάζω", "HealthNoIssues": "Δεν υπάρχουν προβλήματα με τη διαμόρφωσή σας", @@ -177,29 +157,19 @@ "LogLevelTraceHelpTextWarning": "Η καταγραφή ιχνών πρέπει να ενεργοποιηθεί προσωρινά", "Mechanism": "Μηχανισμός", "Message": "Μήνυμα", - "MinimumLimits": "Ελάχιστα όρια", - "MinutesHundredTwenty": "120 λεπτά: {0}", - "MinutesNinety": "90 λεπτά: {0}", - "MonoVersion": "Μονο έκδοση", - "MonoVersionCheckUpgradeRecommendedMessage": "Η τρέχουσα εγκατεστημένη έκδοση Mono {0} υποστηρίζεται, αλλά συνιστάται η αναβάθμιση σε {1}.", - "MovieDetailsPreviousMovie": "Λεπτομέρειες ταινίας: Προηγούμενη ταινία", "MovieIndexScrollBottom": "Ευρετήριο ταινιών: Κύλιση κάτω", "MovieIndexScrollTop": "Ευρετήριο ταινιών: Κύλιση στην κορυφή", - "Movies": "Κινηματογράφος", "Name": "Ονομα", "New": "Νέος", "NoBackupsAreAvailable": "Δεν υπάρχουν διαθέσιμα αντίγραφα ασφαλείας", "NoLeaveIt": "Όχι, άσε το", - "NoLimitForAnyRuntime": "Δεν υπάρχει όριο για οποιοδήποτε χρόνο εκτέλεσης", "NoLinks": "Χωρίς συνδέσμους", "NoLogFiles": "Δεν υπάρχουν αρχεία καταγραφής", - "NoMinimumForAnyRuntime": "Χωρίς ελάχιστο για κάθε χρόνο εκτέλεσης", "NoTagsHaveBeenAddedYet": "Δεν έχουν προστεθεί ετικέτες ακόμη", "NotificationTriggers": "Ενεργοποιήσεις ειδοποίησης", "PageSizeHelpText": "Αριθμός στοιχείων προς εμφάνιση σε κάθε σελίδα", "Password": "Κωδικός πρόσβασης", "Peers": "Ομότιμοι", - "Pending": "εκκρεμής", "PendingChangesMessage": "Έχετε μη αποθηκευμένες αλλαγές, είστε βέβαιοι ότι θέλετε να αποχωρήσετε από αυτήν τη σελίδα;", "PendingChangesStayReview": "Παραμείνετε και ελέγξτε τις αλλαγές", "Presets": "Προεπιλογές", @@ -257,7 +227,6 @@ "UnableToAddANewIndexerPleaseTryAgain": "Δεν είναι δυνατή η προσθήκη νέου ευρετηρίου, δοκιμάστε ξανά.", "UnableToLoadGeneralSettings": "Δεν είναι δυνατή η φόρτωση των γενικών ρυθμίσεων", "UnableToLoadNotifications": "Δεν είναι δυνατή η φόρτωση ειδοποιήσεων", - "UnableToLoadQualityDefinitions": "Δεν είναι δυνατή η φόρτωση των ορισμών ποιότητας", "UnableToLoadUISettings": "Δεν είναι δυνατή η φόρτωση των ρυθμίσεων διεπαφής χρήστη", "UnsavedChanges": "Μη αποθηκευμένες αλλαγές", "UpdateCheckStartupTranslocationMessage": "Δεν είναι δυνατή η εγκατάσταση της ενημέρωσης επειδή ο φάκελος εκκίνησης \"{0}\" βρίσκεται σε ένα φάκελο \"Μετατόπιση εφαρμογών\".", @@ -272,19 +241,16 @@ "Warn": "Προειδοποιώ", "YesCancel": "Ναι, Ακύρωση", "Exception": "Εξαίρεση", - "Importing": "Εισαγωγή", "IncludeHealthWarningsHelpText": "Συμπεριλάβετε προειδοποιήσεις για την υγεία", "Security": "Ασφάλεια", "Tasks": "Καθήκοντα", "UnableToLoadBackups": "Δεν είναι δυνατή η φόρτωση αντιγράφων ασφαλείας", "UnableToLoadDownloadClients": "Δεν είναι δυνατή η φόρτωση πελατών λήψης", - "UnableToLoadIndexers": "Δεν είναι δυνατή η φόρτωση του ευρετηρίου", "UpdateMechanismHelpText": "Χρησιμοποιήστε το ενσωματωμένο πρόγραμμα ενημέρωσης του Radarr ή ένα σενάριο", "AnalyticsEnabledHelpText": "Στείλτε ανώνυμες πληροφορίες χρήσης και σφάλματος στους διακομιστές του Radarr. Αυτό περιλαμβάνει πληροφορίες στο πρόγραμμα περιήγησής σας, ποιες σελίδες Radarr WebUI χρησιμοποιείτε, αναφορά σφαλμάτων καθώς και έκδοση λειτουργικού συστήματος και χρόνου εκτέλεσης. Θα χρησιμοποιήσουμε αυτές τις πληροφορίες για να δώσουμε προτεραιότητα σε λειτουργίες και διορθώσεις σφαλμάτων.", "AppDataDirectory": "Κατάλογος AppData", "BindAddress": "Δεσμευμένη διεύθυνση", "EnableRss": "Ενεργοποίηση RSS", - "EnableInteractiveSearchHelpTextWarning": "Η αναζήτηση δεν υποστηρίζεται με αυτό το ευρετήριο", "IndexerFlags": "Σημαίες ευρετηρίου", "IndexerLongTermStatusCheckAllClientMessage": "Όλοι οι δείκτες δεν είναι διαθέσιμοι λόγω αστοχιών για περισσότερο από 6 ώρες", "InteractiveSearch": "Διαδραστική αναζήτηση", @@ -314,14 +280,12 @@ "CertificateValidation": "Επικύρωση πιστοποιητικού", "CertificateValidationHelpText": "Αλλάξτε πόσο αυστηρή είναι η επικύρωση πιστοποίησης HTTPS", "ClientPriority": "Προτεραιότητα πελάτη", - "CloneIndexer": "Δείκτης κλώνου", "DeleteBackup": "Διαγραφή αντιγράφων ασφαλείας", "DeleteDownloadClient": "Διαγραφή προγράμματος-πελάτη λήψης", "DeleteDownloadClientMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε τον πελάτη λήψης \"{0}\";", "DeleteNotification": "Διαγραφή ειδοποίησης", "Docker": "Λιμενεργάτης", "DownloadClientSettings": "Λήψη ρυθμίσεων πελάτη", - "Downloading": "Λήψη", "EnableInteractiveSearch": "Ενεργοποίηση διαδραστικής αναζήτησης", "SuggestTranslationChange": "Προτείνετε αλλαγή μετάφρασης", "System": "Σύστημα", @@ -354,11 +318,14 @@ "DeleteTag": "Διαγραφή ετικέτας", "EditIndexer": "Επεξεργασία ευρετηρίου", "Enable": "επιτρέπω", - "EnableAutomaticSearchHelpTextWarning": "Θα χρησιμοποιηθεί όταν χρησιμοποιείται διαδραστική αναζήτηση", - "EnableColorImpairedMode": "Ενεργοποίηση λειτουργίας με προβλήματα χρώματος", - "EnableCompletedDownloadHandlingHelpText": "Αυτόματη εισαγωγή ολοκληρωμένων λήψεων από τον πελάτη λήψης", "Enabled": "Ενεργοποιήθηκε", - "EnabledHelpText": "Ενεργοποιήστε αυτήν τη λίστα για χρήση στο Radarr", - "EnableHelpText": "Ενεργοποίηση δημιουργίας αρχείων μεταδεδομένων για αυτόν τον τύπο μεταδεδομένων", - "EnableInteractiveSearchHelpText": "Θα χρησιμοποιηθεί όταν χρησιμοποιείται διαδραστική αναζήτηση" + "EnableInteractiveSearchHelpText": "Θα χρησιμοποιηθεί όταν χρησιμοποιείται διαδραστική αναζήτηση", + "OnGrab": "Στο Grab", + "Filters": "Φίλτρο", + "HistoryCleanupDaysHelpText": "Ορίστε σε 0 για να απενεργοποιήσετε τον αυτόματο καθαρισμό", + "HistoryCleanupDaysHelpTextWarning": "Τα αρχεία στον κάδο ανακύκλωσης παλαιότερα από τον επιλεγμένο αριθμό ημερών θα καθαρίζονται αυτόματα", + "OnHealthIssue": "Σχετικά με το θέμα της υγείας", + "TestAllIndexers": "Δοκιμάστε όλους τους δείκτες", + "MaintenanceRelease": "Έκδοση συντήρησης: επιδιορθώσεις σφαλμάτων και άλλες βελτιώσεις. Δείτε το Github Commit History για περισσότερες λεπτομέρειες", + "ConnectionLostMessage": "Το Radarr έχασε τη σύνδεσή του με το backend και θα χρειαστεί να επαναφορτωθεί για να αποκαταστήσει τη λειτουργικότητά του." } diff --git a/src/NzbDrone.Core/Localization/Core/es.json b/src/NzbDrone.Core/Localization/Core/es.json index 10e42093b..05f4eaded 100644 --- a/src/NzbDrone.Core/Localization/Core/es.json +++ b/src/NzbDrone.Core/Localization/Core/es.json @@ -13,8 +13,6 @@ "DownloadClientStatusCheckSingleClientMessage": "Gestores de descargas no disponibles debido a errores: {0}", "DownloadClientStatusCheckAllClientMessage": "Los gestores de descargas no están disponibles debido a errores", "DownloadClients": "Gestores de Descargas", - "DownloadClientCheckUnableToCommunicateMessage": "Incapaz de comunicarse con {0}.", - "DownloadClientCheckNoneAvailableMessage": "Ningún gestor de descargas disponible", "Delete": "Borrar", "Dates": "Fechas", "Date": "Fecha", @@ -49,13 +47,10 @@ "Search": "Buscar", "Scheduled": "Programado", "SaveChanges": "Guardar Cambios", - "Restrictions": "Restricciones", "RestoreBackup": "Recuperar Backup", - "ReleaseBranchCheckPreviousVersionMessage": "La versión {0} es de una versión anterior de Prowlarr, ajusta la versión a 'Nightly' para recibir actualizaciones", "ReleaseBranchCheckOfficialBranchMessage": "Las versión {0} no es una versión válida de Prowlarr, no recibirás actualizaciones", "Refresh": "Actualizar", "Queue": "Cola", - "QualityDefinitions": "Definiciones de Calidad", "PtpOldSettingsCheckMessage": "Los siguientes indexers PassThePopcorn tienen configuraciones obsoletas y deben de ser actualizados: {0}", "ProxyCheckResolveIpMessage": "No se pudo resolver la dirección IP del Host Proxy configurado {0}", "ProxyCheckFailedToTestMessage": "Fallo al comprobar el proxy: {0}", @@ -64,12 +59,9 @@ "Options": "Opciones", "NoChange": "Sin Cambio", "NoChanges": "Sin Cambios", - "Movies": "Películas", - "MonoNotNetCoreCheckMessage": "Por favor actualiza a la versión .NET Core de Prowlarr", "MoreInfo": "Más Información", "Logging": "Registro de eventos", "LogFiles": "Archivos de Registro", - "Languages": "Idiomas", "Language": "Idioma", "IndexerStatusCheckAllClientMessage": "Los indexers no están disponibles debido a errores", "Added": "An̄adida", @@ -79,7 +71,6 @@ "Size": "Tamaño", "ReleaseStatus": "Estado del Estreno", "Protocol": "Protocolo", - "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls todavía está habilitado, considera la posibilidad de eliminar la opción MONO_TLS_PROVIDER=legacy", "LastWriteTime": "Última Fecha de Escritura", "IndexerStatusCheckSingleClientMessage": "Indexers no disponibles debido a errores: {0}", "Indexer": "Indexer", @@ -127,7 +118,6 @@ "Apply": "Aplicar", "Age": "Edad", "SystemTimeCheckMessage": "El reloj del sistema está retrasado más de un día. Las tareas de mantenimiento no se ejecutarán correctamente hasta que se haya corregido", - "ExistingMovies": "Película(s) Existente", "UnsavedChanges": "Cambios no guardados", "ShowSearchHelpText": "Mostrar botón de búsqueda al pasar el cursor por encima", "ShowSearch": "Mostrar Búsqueda", @@ -139,25 +129,20 @@ "PendingChangesStayReview": "Permanecer y revisar cambios", "PendingChangesMessage": "Hay cambios sin salvar, estás seguro de que quieres salir de esta página?", "PendingChangesDiscardChanges": "Descartar cambios y salir", - "MonoVersionCheckUpgradeRecommendedMessage": "Le versión de Mono {0} instalada actualmente es compatible pero se recomienda actualizar a {1}.", "SettingsEnableColorImpairedModeHelpText": "Estilo modificado para permitir que usuarios con problemas de color distingan mejor la información codificada por colores", "SettingsEnableColorImpairedMode": "Activar Modo De Color Degradado", "GeneralSettings": "Ajustes Generales", "Fixed": "Arreglado", "EnableSslHelpText": " Requiere reiniciar la aplicación como administrador para que surta efecto", - "EnableMediaInfoHelpText": "Extraiga información de video como resolución, tiempo de ejecución e información de códec de los archivos. Esto requiere que Prowlarr lea partes del archivo y puede causar una alta actividad en el disco o en la red durante los escaneos.", "Enable": "Habilitar", "DownloadClientSettings": "Ajustes de Gestor de Descargas", "Docker": "Docker", "DeleteTag": "Borrar Etiqueta", "DeleteNotification": "Borrar Notificación", - "DeleteIndexer": "Borrar Indexer", "DeleteDownloadClient": "Borrar Gestor de Descargas", "DeleteBackup": "Borrar Backup", - "DelayProfile": "Perfil de Retraso", "DBMigration": "Migración de DB", "CloneProfile": "Clonar Perfil", - "CloneIndexer": "Clonar Indexer", "ClientPriority": "Prioridad de Cliente", "ChangeHasNotBeenSavedYet": "El cambio aún no se ha guardado", "CertificateValidationHelpText": "Cambiar la rigidez de la validación de la certificación HTTPS", @@ -189,9 +174,7 @@ "UpdateMechanismHelpText": "Usar el actualizador de Prowlarr o un script", "UpdateAutomaticallyHelpText": "Descargar e instalar actualizaciones automáticamente. Se podrán instalar desde Sistema: Actualizaciones también", "UnableToLoadTags": "No se pueden cargar las Etiquetas", - "UnableToLoadQualityDefinitions": "No se pueden cargar las Definiciones de Calidad", "UnableToLoadNotifications": "No se pueden cargar las Notificaciones", - "UnableToLoadIndexers": "No se pueden cargar los indexers", "UnableToLoadDownloadClients": "No se puden cargar los gestores de descargas", "UISettings": "Ajustes del UI", "Torrents": "Torrents", @@ -215,50 +198,35 @@ "RemovedFromTaskQueue": "Eliminar de la cola de tareas", "RefreshMovie": "Actualizar película", "ReadTheWikiForMoreInformation": "Lee la Wiki para más información", - "QualitySettings": "Ajustes de Calidad", "ProxyUsernameHelpText": "Tienes que introducir tu nombre de usuario y contraseña sólo si son requeridos. Si no, déjalos vacios.", "ProxyType": "Tipo de Proxy", "ProxyPasswordHelpText": "Tienes que introducir tu nombre de usuario y contraseña sólo si son requeridos. Si no, déjalos vacios.", "ProxyBypassFilterHelpText": "Usa ',' como separador, y '*.' como wildcard para subdominios", "PriorityHelpText": "Priorizar múltiples Gestores de Descargas. Se usa Round-Robin para gestores con la misma prioridad.", - "PreferredSize": "Tamaño Preferido", "PortNumber": "Número de Puerto", "Port": "Puerto", "Password": "Contraseña", "PageSizeHelpText": "Número de elementos por página", "PackageVersion": "Versión del paquete", "NotificationTriggers": "Desencadenantes de Notificaciones", - "NoMinimumForAnyRuntime": "Sin mínimo para el tiempo de ejecución", - "NoLimitForAnyRuntime": "SIn límite para el tiempo de ejecución", "NoLeaveIt": "No, Déjalo", "New": "Nueva", "NetCore": ".NET Core", - "MonoVersion": "Version de Mono", "Mode": "Modo", - "MinimumLimits": "Límites Mínimos", "MIA": "MIA", "Mechanism": "Mecanismo", - "MaximumLimits": "Límites Máximos", "Logs": "Registros", "LogLevel": "Nivel de Registro", "LaunchBrowserHelpText": " Abrir un navegador web e ir a la página de inicio de Prowlarr al arrancar la app.", "Interval": "Intervalo", "IndexerFlags": "Marcas de Indexer", "IncludeHealthWarningsHelpText": "Incluir Alertas de Salud", - "Importing": "Importando", "IllRestartLater": "Lo reiniciaré más tarde", "IgnoredAddresses": "Direcciones Ignoradas", "Hostname": "Nombre del Host", "EnableSSL": "Habilitar SSL", "EnableInteractiveSearch": "Habilitar Búsqueda Interactiva", - "EnableHelpText": "Habilitar la creación de un fichero de metadatos para este tipo de metadato", - "EnabledHelpText": "Habilitar esta lista para usar en Prowlarr", - "EnableCompletedDownloadHandlingHelpText": "Importar automáticamente las descargas completas del gestor de descargas", - "EnableColorImpairedModeHelpText": "Estilo modificado para permitir que usuarios con problemas de color distingan mejor la información codificada por colores", - "EnableColorImpairedMode": "Activar Modo De Color Degradado", "EnableAutomaticSearch": "Habilitar Búsqueda Automática", - "EnableAutomaticAdd": "Habilitar Añadido Automático", - "EnableAutoHelpText": "Si se habilita, las Películas en esta lista se añadirán automáticamente a Prowlarr", "ConnectSettings": "Conectar Ajustes", "BindAddress": "Dirección de Ligado", "OpenBrowserOnStart": "Abrir navegador al arrancar", @@ -269,22 +237,16 @@ "ShownClickToHide": "Mostrado, clic para ocultar", "RSSIsNotSupportedWithThisIndexer": "RSS no son soportadas por este indexer", "RemovingTag": "Eliminando etiqueta", - "Pending": "Pendiente", "Manual": "Manual", "LogLevelTraceHelpTextWarning": "El registro de seguimiento se ha de habilitar solo temporalmente", "HiddenClickToShow": "Oculto, clic para mostrar", "ExistingTag": "Etiqueta existente", - "EnableInteractiveSearchHelpTextWarning": "Buscar no está soportado por este indexer", "EnableInteractiveSearchHelpText": "Se usará cuando se utilice la búsqueda interactiva", "EnableAutomaticSearchHelpText": "Se usará cuando las búsquedas automáticas se realicen desde el UI o por Prowlarr", - "EnableAutomaticSearchHelpTextWarning": "Se usará cuando se utilice la búsqueda interactiva", - "Downloading": "Descargando", - "DownloadClientUnavailable": "El gestor de descargas no está disponible", "DeleteTagMessageText": "Seguro que quieres eliminar la etiqueta '{0}'?", "DeleteNotificationMessageText": "Seguro que quieres elminiar la notificación '{0}'?", "DeleteBackupMessageText": "Seguro que quieres eliminar la copia de seguridad '{0}'?", "DeleteDownloadClientMessageText": "Seguro que quieres eliminar el gestor de descargas '{0}'?", - "DeleteIndexerMessageText": "Seguro que quieres eliminar el indexer '{0}'?", "CancelPendingTask": "Seguro que quieres cancelar esta tarea pendiente?", "BranchUpdateMechanism": "Rama usada por el mecanismo de actualización externo", "BranchUpdate": "Qué rama usar para actualizar Prowlarr", @@ -306,9 +268,6 @@ "NoTagsHaveBeenAddedYet": "No se han añadido etiquetas todavía", "NoLogFiles": "Sin archivos de registro", "NoBackupsAreAvailable": "No hay copias de seguridad disponibles", - "MinutesSixty": "60 Minutos: {0}", - "MinutesNinety": "90 Minutos: {0}", - "MinutesHundredTwenty": "120 Minutos: {0}", "MaintenanceRelease": "Lanzamiento de mantenimiento", "ForMoreInformationOnTheIndividualDownloadClients": "Para más información individual de los gestores de descarga, haz clic en lls botones de información.", "FilterPlaceHolder": "Buscar películas", @@ -334,8 +293,6 @@ "OpenThisModal": "Abrir este Modal", "MovieIndexScrollTop": "Indice de Películas: Desplazar hacia arriba", "MovieIndexScrollBottom": "Indice de Películas: Desplazar hacia abajo", - "MovieDetailsPreviousMovie": "Detalles de la Película: Película Anterior", - "MovieDetailsNextMovie": "Detalles de la película: Siguiente Película", "CloseCurrentModal": "Cerrar Modal Actual", "AcceptConfirmationModal": "Aceptar el Modal de Confirmación", "IndexerLongTermStatusCheckSingleClientMessage": "Indexers no disponible por errores durando más de 6 horas: {0}", @@ -371,5 +328,11 @@ "EnableRss": "Habilitar RSS", "FeatureRequests": "Peticiones de características", "HomePage": "Página de inicio", - "UnableToAddANewApplicationPleaseTryAgain": "No se ha podido añadir una nueva notificación, prueba otra vez." + "UnableToAddANewApplicationPleaseTryAgain": "No se ha podido añadir una nueva notificación, prueba otra vez.", + "Filters": "Filtro", + "HistoryCleanupDaysHelpText": "Ajustar a 0 para desactivar la limpieza automática", + "HistoryCleanupDaysHelpTextWarning": "Los archivos en la papelera de reciclaje más antiguos que el número de días seleccionado serán limpiados automáticamente", + "OnGrab": "Al Capturar", + "OnHealthIssue": "En Problema de Salud", + "TestAllIndexers": "Comprobar Todos los Indexers" } diff --git a/src/NzbDrone.Core/Localization/Core/fi.json b/src/NzbDrone.Core/Localization/Core/fi.json index 498adda7e..9955875fc 100644 --- a/src/NzbDrone.Core/Localization/Core/fi.json +++ b/src/NzbDrone.Core/Localization/Core/fi.json @@ -5,7 +5,7 @@ "MovieIndexScrollTop": "Elokuvahakemisto: vieritä ylös", "Apply": "Käytä", "ClientPriority": "Lataustyökalun painotus", - "IndexerPriorityHelpText": "Tietolähteen painotus: 1 (korkein) - 50 (matalin). Oletusarvo on 25.", + "IndexerPriorityHelpText": "Tietolähteen painotus: 1 (korkein) - 50 (matalin). Oletusarvo on 25. Käytetään muutoin tasaveroisten julkaisujen sieppauspäätökseen. Kaikkia käytössä olevia tietolähteitä käytetään edelleen RSS-synkronointiin ja hakuun.", "Manual": "Manuaalinen", "Add": "Lisää", "Reload": "Lataa uudelleen", @@ -46,7 +46,7 @@ "Refresh": "Päivitä", "RefreshMovie": "Päivitä elokuva", "ReleaseBranchCheckOfficialBranchMessage": "'{0}' ei ole kelvollinen Prowlarr-julkaisuhaara, etkä saa päivityksiä sen kautta", - "RestartRequiredHelpTextWarning": "Käyttöönotto vaatii uudelleenkäynnistyksen", + "RestartRequiredHelpTextWarning": "Käyttöönotto vaatii uudelleenkäynnistyksen.", "Result": "Tulos", "Settings": "Asetukset", "SettingsLongDateFormat": "Päiväyksen pitkä esitystapa", @@ -58,7 +58,7 @@ "ApplyTagsHelpTexts3": "– 'Poista' ainoastaan syötetyt tunnisteet", "Enable": "Käytä", "UI": "Käyttöliittymä", - "UrlBaseHelpText": "Käänteisen välityspalvelimen tuki (esim. 'http://[host]:[port]/[urlBase]'). Oletus on tyhjä.", + "UrlBaseHelpText": "Käänteisen välityspalvelimen tuki (esim. 'http://[host]:[port]/[urlBase]'). Käytä oletusta jättämällä tyhjäksi.", "Usenet": "Usenet", "BackupNow": "Varmuuskopioi nyt", "NoBackupsAreAvailable": "Varmuuskopioita ei ole saatavilla", @@ -70,10 +70,10 @@ "UseProxy": "Käytä välityspalvelinta", "Username": "Käyttäjätunnus", "YesCancel": "Kyllä, peruuta", - "NoTagsHaveBeenAddedYet": "Tunnisteita ei ole vielä lisätty", + "NoTagsHaveBeenAddedYet": "Tunnisteita ei ole vielä lisätty.", "ApplyTags": "Toimenpide tunnisteille", "Authentication": "Todennus", - "AuthenticationMethodHelpText": "Vaadi Prowlarrin käyttöön käyttäjätunnus ja salasana", + "AuthenticationMethodHelpText": "Vaadi käyttäjätunnus ja salasana.", "BindAddressHelpText": "Toimiva IPv4-osoite tai jokerimerkkinä '*' (tähti) kaikille yhteyksille.", "Close": "Sulje", "DeleteNotification": "Poista kytkentä", @@ -95,7 +95,7 @@ "Peers": "Vertaiset", "Presets": "Esiasetukset", "Priority": "Painotus", - "PriorityHelpText": "Määritä useiden lataustyökalujen painotusasetukset. Tasaveroisesti painotettujen työkalujen käyttöä tasapainotetaan Round-Robin-tekniikalla.", + "PriorityHelpText": "Tietolähteen painotus: 1 (korkein) - 50 (matalin). Oletusarvo on 25. Käytetään muutoin tasaveroisten julkaisujen sieppauspäätökseen. Kaikkia käytössä olevia tietolähteitä käytetään edelleen RSS-synkronointiin ja hakuun.", "PrioritySettings": "Painotus", "Protocol": "Protokolla", "ProxyCheckBadRequestMessage": "Välityspalvelintesti epäonnistui. Tilakoodi: {0}", @@ -141,7 +141,7 @@ "UnableToLoadBackups": "Varmuuskopioiden lataus epäonnistui.", "UnableToLoadDownloadClients": "Lataustyökalujen lataus epäonnistui.", "UnableToLoadGeneralSettings": "Yleisten asetusten lataus epäonnistui.", - "UpdateAutomaticallyHelpText": "Lataa ja asenna päivitykset automaattisesti. Voit silti asentaa ne myös lähteestä System:Updates.", + "UpdateAutomaticallyHelpText": "Lataa ja asenna päivitykset automaattisesti. Voit edelleen asentaa ne myös lähteestä System:Updates.", "Added": "Lisätty", "AddIndexer": "Lisää tietolähde", "AddingTag": "Tunniste lisätään", @@ -149,7 +149,7 @@ "All": "Kaikki", "AllIndexersHiddenDueToFilter": "Aktiivinen suodatin on piilottanut kaikki tietolähteet.", "Analytics": "Analytiikka", - "AnalyticsEnabledHelpText": "Lähetä nimettömiä käyttö- ja virhetietoja Prowlarin palvelimille. Tämä sisältää tietoja selaimestasi, verkkokäyttöliittymän sivujen käytöstä, virheraportoinnista sekä käyttöjärjestelmästäsi ja versiosta. Käytämme näitä tietoja ominaisuuksien ja virhekorjauksien painotukseen.", + "AnalyticsEnabledHelpText": "Lähetä nimettömiä käyttö- ja virhetietoja sovelluksen palvelimille. Tämä sisältää tietoja selaimestasi, verkkokäyttöliittymän sivujen käytöstä, virheraportoinnista sekä käyttöjärjestelmästäsi ja versiosta. Käytämme näitä tietoja ominaisuuksien ja virhekorjauksien painotukseen.", "ApiKey": "API-avain", "AppDataDirectory": "AppData-kansio", "DBMigration": "Tietokannan siirto", @@ -206,7 +206,7 @@ "Scheduled": "Ajoitettu", "SettingsEnableColorImpairedModeHelpText": "Muokattu tyyli käyttäjille, joiden värinäkö on heikentynyt. Auttaa erottamaan värikoodatun tiedon.", "SettingsShowRelativeDates": "Näytä suhteutetut päiväykset", - "SettingsShowRelativeDatesHelpText": "Näytä suhteutetut (tänään/eilen/yms.) tai absoluuttiset päiväykset", + "SettingsShowRelativeDatesHelpText": "Näytä suhteutetut (tänään/eilen/yms.) tai absoluuttiset päiväykset.", "ShownClickToHide": "Näkyvissä, piilota painamalla", "ShowSearch": "Näytä haku", "Source": "Lähde", @@ -215,7 +215,7 @@ "StartupDirectory": "Käynnistyskansio", "TableOptions": "Taulukkoasetukset", "TableOptionsColumnsMessage": "Valitse näytettävät sarakkeet ja niiden järjestys", - "TagsHelpText": "Käytetään vähintään yhdellä täsmäävällä tunnisteella merkityille tietolähteille.", + "TagsHelpText": "Käytetään vähintään yhdellä täsmäävällä tunnisteella merkityille tietolähteille. Käytä kaikille jättämällä tyhjäksi.", "UnableToAddANewAppProfilePleaseTryAgain": "Uuden sovellusprofiilin lisäys epäonnistui. Yritä uudelleen.", "UnableToAddANewNotificationPleaseTryAgain": "Kytkennän lisäys epäonnistui. Yritä uudelleen.", "Version": "Versio", @@ -230,20 +230,20 @@ "Automatic": "Automaattinen", "AutomaticSearch": "Automaattihaku", "Backup": "Varmuuskopio", - "BackupFolderHelpText": "Suhteelliset polut sijaitsevat Prowlarrin AppData-kansiossa", + "BackupFolderHelpText": "Suhteelliset polut kohdistuvat sovelluksen AppData-kansioon.", "BackupIntervalHelpText": "Automaattisen varmuuskopioinnin aikaväli", "BackupRetentionHelpText": "Säilytysjaksoa vanhemmat automaattiset varmuuskopiot poistetaan automaattisesti.", "Backups": "Varmuuskopiot", "BeforeUpdate": "Ennen päivitystä", "BindAddress": "Sidososoite", "Branch": "Kehityshaara", - "BranchUpdate": "Kehityshaara, jota käytetään Prowlarrin päivityksille.", - "BranchUpdateMechanism": "Ulkoisen päivittysmekanismin käyttämä kehityshaara", + "BranchUpdate": "Sovelluksen versiopäivityksiin käytettävä kehityshaara.", + "BranchUpdateMechanism": "Ulkoisen päivitysratkaisun käyttämä kehityshaara.", "BypassProxyForLocalAddresses": "Ohjaa paikalliset osoitteet välityspalvelimen ohi", "Cancel": "Peruuta", "CancelPendingTask": "Haluatko varmasti perua tämän odottavan tehtävän?", "CertificateValidation": "Varmenteen vahvistus", - "CertificateValidationHelpText": "Aseta HTTPS-varmenteen vahvistuksen tiukkuus", + "CertificateValidationHelpText": "Valitse HTTPS-varmenteen vahvistuksen tarkkuus. Älä muuta, jollet ymmärrä tähän liittyviä riskejä.", "ChangeHasNotBeenSavedYet": "Muutosta ei ole vielä tallennettu", "Clear": "Tyhjennä", "CloneProfile": "Kloonaa profiili", @@ -264,7 +264,7 @@ "EnableInteractiveSearch": "Vuorovaikutteinen haku", "EnableInteractiveSearchHelpText": "Profiilia käytetään vuorovaikutteisen haun yhteydessä.", "EnableSSL": "SSL-salaus", - "EnableSslHelpText": " Käyttöönotto edellyttää uudelleenkäynnistystä järjestelmänvalvojan oikeuksilla", + "EnableSslHelpText": " Käyttöönotto edellyttää uudelleenkäynnistystä järjestelmänvalvojan oikeuksilla.", "Error": "Virhe", "ErrorLoadingContents": "Sisällönlatauksen virhe", "Events": "Tapahtumat", @@ -287,7 +287,7 @@ "IncludeHealthWarningsHelpText": "Sisällytä kuntovaroitukset", "Indexer": "Tietolähde", "IndexerFlags": "Tietolähteen liput", - "IndexerLongTermStatusCheckAllClientMessage": "Tietolähteet eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi", + "IndexerLongTermStatusCheckAllClientMessage": "Mikään tietolähde ei ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi.", "IndexerLongTermStatusCheckSingleClientMessage": "Tietolähteet eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi: {0}", "IndexerPriority": "Tietolähteiden painotus", "IndexerProxyStatusCheckAllClientMessage": "Välityspalvelimet eivät ole käytettävissä virheiden vuoksi", @@ -299,12 +299,12 @@ "SSLCertPath": "SSL-varmenteen sijainti", "SSLCertPathHelpText": "PFX-tiedoston sijainti", "Status": "Tila", - "NotificationTriggers": "Ilmoituksen laukaisimet", + "NotificationTriggers": "Laukaisijat", "NoUpdatesAreAvailable": "Päivityksiä ei ole saatavilla", "OAuthPopupMessage": "Selaimesi estää ponnahdukset", "Ok": "Ok", "OnHealthIssueHelpText": "Kuntoon liittyvä ongelma", - "OpenBrowserOnStart": "Avaa selain käynnistyksen yhteydessä", + "OpenBrowserOnStart": "Avaa selain käynnistettäessä", "OpenThisModal": "Avaa tämä ikkuna", "Options": "Valinnat", "PackageVersion": "Pakettiversio", @@ -314,8 +314,8 @@ "PortNumber": "Portti", "RestoreBackup": "Palauta varmuuskopio", "Retention": "Säilytys", - "UILanguageHelpText": "Prowlarin käyttöliittymä näytetään tällä kielellä", - "UILanguageHelpTextWarning": "Selaimen sivupäivitys vaaditaan", + "UILanguageHelpText": "Käyttöliittymä näytetään tällä kielellä.", + "UILanguageHelpTextWarning": "Käyttöönotto vaatii selaimen sivupäivityksen.", "UISettings": "Käyttöliittymän asetukset", "DownloadClientsSettingsSummary": "Prowlarrin käyttöliittymästä suoritettavien hakujen yhteydessä käytettävien lataustyökalujen määritykset.", "ProwlarrSupportsAnyDownloadClient": "Prowlarr tukee alla listatuja lataustyökaluja.", @@ -325,7 +325,7 @@ "SyncLevelFull": "Täysi synkronointi: Pitää sovelluksen tietolähteet täysin synkronoituna. Tietolähteisiin Prowlarrissa tehdyt muutokset synkronoidaan etäsovelluksen kanssa ja kaikki etäsovelluksessa tehdyt muutokset korvataan seuraavan synkronoinnin yhteydessä.", "AppProfile": "Sovellusprofiili", "EnableIndexer": "Tietolähteen tila", - "FilterPlaceHolder": "Hae tietolähteestä", + "FilterPlaceHolder": "Suodata tietolähteitä", "IndexerHealthCheckNoIndexers": "Yhtään tietolähdettä ei ole käytössä, eikä Prowlarr tämän vuoksi löydä tuloksia.", "IndexerObsoleteCheckMessage": "Tietolähteet ovat vanhentuneita tai niitä on päivitetty: {0}. Poista ja/tai lisää ne Prowlariin uudelleen.", "IndexerProxy": "Tietolähteen välityspalvelin", @@ -390,7 +390,7 @@ "IndexerAuth": "Tietolähteen todennus", "IndexersSelectedInterp": "{0} valittua tietolähdettä", "Notifications": "Kytkennät", - "NotificationTriggersHelpText": "Valitse tapahtumat, jotka laukaisevat tämän ilmoituksen", + "NotificationTriggersHelpText": "Valitse tapahtumat, jotka aiheuttavat ilmoituksen.", "Stats": "Tilastot", "UnableToLoadDevelopmentSettings": "Kehittäjäasetusten lataus epäonnistui", "AppSettingsSummary": "Sovellukset ja asetukset, joilla määritetään miten Prowlarr viestii PVR-sovellustesi kanssa.", @@ -407,7 +407,7 @@ "OnGrab": "Kun elokuva siepataan", "OnHealthIssue": "Kun havaitaan kuntoon liittyvä ongelma", "HistoryCleanupDaysHelpText": "Älä tyhjennä automaattisesti asettamalla arvoksi '0'.", - "HistoryCleanupDaysHelpTextWarning": "Tässä määritettyä aikaa vanhemmat tiedostot poistetaan roskakorista pysyvästi automaattisesti.", + "HistoryCleanupDaysHelpTextWarning": "Tässä määritettyä aikaa vanhemmat tiedostot poistetaan automaattisesti roskakorista pysyvästi.", "TestAllIndexers": "Testaa tietolähteet", "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent-tiedon ilmoitti sovellus, joka kommunikoi API:n kanssa", "Categories": "Kategoriat", diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index ef2c3049b..fcef9a2b8 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -13,7 +13,6 @@ "Edit": "Éditer", "DownloadClientStatusCheckAllClientMessage": "Aucun client de téléchargement n'est disponible en raison d'échecs", "DownloadClients": "Clients Télécharg.", - "DownloadClientCheckNoneAvailableMessage": "Aucun client de téléchargement n'est disponible", "Dates": "Dates", "Date": "Date", "Delete": "Supprimer", @@ -48,13 +47,10 @@ "Search": "Rechercher", "Scheduled": "Programmé", "SaveChanges": "Sauvegarder les modifications", - "Restrictions": "Restrictions", "RestoreBackup": "Restaurer la sauvegarde", - "ReleaseBranchCheckPreviousVersionMessage": "La branche {0} est pour une version précédente de Prowlarr, définissez la branche sur 'Nightly' pour d'autres mises à jour", "ReleaseBranchCheckOfficialBranchMessage": "La branche {0} n'est pas une branche de version Prowlarr valide, vous ne recevrez pas de mises à jour", "Refresh": "Rafraîchir", "Queue": "File d'attente", - "QualityDefinitions": "Définitions qualité", "PtpOldSettingsCheckMessage": "Les indexeurs PassThePopcorn suivants ont des paramètres obsolètes et doivent être mis à jour : {0}", "ProxyCheckResolveIpMessage": "Impossible de résoudre l'adresse IP de l'hôte proxy configuré {0}", "ProxyCheckFailedToTestMessage": "Échec du test du proxy : {0}", @@ -64,14 +60,10 @@ "Options": "Options", "NoChanges": "Aucun changement", "NoChange": "Pas de changement", - "Movies": "Films", "MoreInfo": "Plus d'informations", - "MonoTlsCheckMessage": "Solution de contournement Prowlarr Mono 4.x tls toujours activée, pensez à supprimer l'option d'environnement MONO_TLS_PROVIDER = legacy", "Grabbed": "Attrapé", "DownloadClientsSettingsSummary": "Clients de Téléchargement configuration pour l'intégration dans la recherche de l'interface utilisateur Prowlarr", - "DownloadClientCheckUnableToCommunicateMessage": "Impossible de communiquer avec {0}.", "DownloadClient": "Client de Téléchargement", - "MonoNotNetCoreCheckMessage": "Veuillez mettre à niveau vers la version .NET Core de Prowlarr", "Logging": "Enregistrement", "LogFiles": "Fichiers Log", "View": "Vue", @@ -81,7 +73,6 @@ "Tags": "Tags", "System": "Système", "LastWriteTime": "Heure de la dernière écriture", - "Languages": "Langues", "Language": "Langue", "Indexer": "Indexeur", "GeneralSettingsSummary": "Port, SSL, nom d'utilisateur/mot de passe, proxy, analyses et mises à jour", @@ -140,10 +131,7 @@ "PendingChangesStayReview": "Rester et vérifier les changements", "PendingChangesMessage": "Vous avez effectué des changements non sauvegardés, souhaitez vous quitter cette page ?", "PendingChangesDiscardChanges": "Abandonner les changements et quitter", - "MonoVersionCheckUpgradeRecommendedMessage": "La version installée de Mono {0} est supportée mais mettre à jour en version {1} est recommandé.", - "ExistingMovies": "Films existants", "CloneProfile": "Cloner le profil", - "CloneIndexer": "Cloner l'indexeur", "ClientPriority": "Priorité du client", "ChangeHasNotBeenSavedYet": "Les changements n'ont pas encore été sauvegardés", "CertificateValidationHelpText": "Change la rigueur de la vérification du certificat HTTPS", @@ -169,22 +157,13 @@ "Fixed": "Corrigé", "EnableSslHelpText": " Nécessite un redémarrage en tant qu'administrateur pour être effectif", "EnableSSL": "Activer le SSL", - "EnableMediaInfoHelpText": "Extraire les informations de la vidéo (résolution, temps et codec par exemple) depuis les fichiers. Cela nécessite que Prowlarr lise des parties du fichier ce qui peut entraîner une forte utilisation du disque dur ou du réseau pendant les scans.", "EnableInteractiveSearch": "Activer la recherche interactive", - "EnableHelpText": "Activer la création d'un fichier de métadonnées pour ce type de métadonnée", - "EnabledHelpText": "Activer cette liste pour usage dans Prowlarr", - "EnableCompletedDownloadHandlingHelpText": "Importer automatiquement les téléchargements terminés depuis le client de téléchargement", - "EnableColorImpairedModeHelpText": "Style modifié pour permettre aux utilisateurs daltoniens de distinguer les codes couleurs", - "EnableColorImpairedMode": "Activer le mode daltonien", "EnableAutomaticSearch": "Activer la recherche automatique", - "EnableAutomaticAdd": "Activer l'ajout automatique", - "EnableAutoHelpText": "En cas d'activation, les films seront automatiquement ajoutés à Prowlarr depuis cette liste", "Enable": "Activer", "DownloadClientSettings": "Réglages Clients de téléchargement", "Docker": "Docker", "DeleteTag": "Supprimer le tag", "DeleteNotification": "Supprimer la notification", - "DeleteIndexer": "Supprimer l'indexeur", "DeleteDownloadClient": "Supprimer le client de téléchargement", "DeleteBackup": "Supprimer la sauvegarde", "DBMigration": "Migration de la base de données", @@ -202,13 +181,8 @@ "DeleteDownloadClientMessageText": "Êtes-vous sûr de vouloir supprimer le client de téléchargement '{0}' ?", "DeleteBackupMessageText": "Êtes-vous sûr de vouloir supprimer la sauvegarde '{0}' ?", "ErrorLoadingContents": "Erreur lors du chargement du contenu", - "EnableInteractiveSearchHelpTextWarning": "La recherche n'est pas prise en charge avec cet indexeur", "EnableInteractiveSearchHelpText": "Sera utilisé lorsque la recherche interactive est utilisée", - "EnableAutomaticSearchHelpTextWarning": "Sera utilisé lorsque la recherche interactive est utilisée", "EnableAutomaticSearchHelpText": "Sera utilisé lorsque les recherches automatiques sont effectuées via l'interface utilisateur ou par Prowlarr", - "Downloading": "Téléchargement", - "DownloadClientUnavailable": "Le client de téléchargement n'est pas disponible", - "DeleteIndexerMessageText": "Voulez-vous vraiment supprimer l'indexeur '{0}' ?", "ForMoreInformationOnTheIndividualDownloadClients": "Pour plus d'informations sur les clients de téléchargement individuels, cliquez sur les boutons d'information.", "FilterPlaceHolder": "Rechercher des indexeurs", "Exception": "Exception", @@ -221,8 +195,6 @@ "InteractiveSearch": "Recherche interactive", "IndexerPriorityHelpText": "Priorité de l'indexeur de 1 (la plus élevée) à 50 (la plus basse). Par défaut: 25.", "IndexerPriority": "Priorité de l'indexeur", - "Importing": "Importation", - "UnableToLoadQualityDefinitions": "Impossible de charger les définitions de qualité", "UnableToLoadNotifications": "Impossible de charger les notifications", "Version": "Version", "Username": "Nom d'utilisateur", @@ -231,14 +203,8 @@ "UrlBaseHelpText": "Pour la prise en charge du proxy inverse, la valeur par défaut est vide", "URLBase": "Base URL", "YesCancel": "Oui, annuler", - "MonoVersion": "Mono Version", "Mode": "Mode", - "MinutesSixty": "60 Minutes : {0}", - "MinutesNinety": "90 Minutes : {0}", - "MinutesHundredTwenty": "120 Minutes : {0}", - "MinimumLimits": "Limites minimales", "Mechanism": "Mécanisme", - "MaximumLimits": "Limites maximales", "Manual": "Manuel", "MaintenanceRelease": "Version de maintenance", "Logs": "Journaux", @@ -254,7 +220,6 @@ "UpdateAutomaticallyHelpText": "Télécharger et installer automatiquement les mises à jour. Vous pourrez toujours installer à partir de System : Updates", "UnableToLoadUISettings": "Impossible de charger les paramètres de l'interface utilisateur", "UnableToLoadTags": "Impossible de charger les balises", - "UnableToLoadIndexers": "Impossible de charger les indexeurs", "UnableToLoadHistory": "Impossible de charger l'historique", "UnableToLoadGeneralSettings": "Impossible de charger les paramètres généraux", "UnableToLoadDownloadClients": "Impossible de charger les clients de téléchargement", @@ -269,7 +234,6 @@ "NoTagsHaveBeenAddedYet": "Aucune identification n'a été ajoutée pour l'instant", "IndexerFlags": "Indicateurs d'indexeur", "DeleteTagMessageText": "Voulez-vous vraiment supprimer la balise '{0}' ?", - "DelayProfile": "Profil de delai", "UISettings": "Paramètres UI", "UILanguageHelpTextWarning": "Rechargement du navigateur requis", "UILanguageHelpText": "Langue que Prowlarr utilisera pour l'interface utilisateur", @@ -305,23 +269,18 @@ "ReadTheWikiForMoreInformation": "Consultez le Wiki pour plus d'informations", "ProwlarrSupportsAnyIndexer": "Prowlarr prend en charge de nombreux indexeurs en plus de tout indexeur qui utilise la norme Newznab/Torznab en utilisant « Generic Newznab » (pour usenet) ou « Generic Torznab » (pour les torrents). Recherchez et sélectionnez votre indexeur ci-dessous.", "ProwlarrSupportsAnyDownloadClient": "Prowlarr prend en charge tout client de téléchargement qui utilise le standard Newznab, ainsi que d'autres clients de téléchargement répertoriés ci-dessous.", - "QualitySettings": "Paramètres Qualité", "ProxyUsernameHelpText": "Il vous suffit de saisir un nom d'utilisateur et un mot de passe si vous en avez besoin. Sinon, laissez-les vides.", "ProxyType": "Type de proxy", "ProxyPasswordHelpText": "Il vous suffit de saisir un nom d'utilisateur et un mot de passe si vous en avez besoin. Sinon, laissez-les vides.", "Priority": "Priorité", - "PreferredSize": "Taille préférée", "PortNumber": "Numéro de port", "Port": "Port", - "Pending": "En attente", "Password": "Mot de passe", "PageSizeHelpText": "Nombre d'éléments à afficher sur chaque page", "PackageVersion": "Version du package", "OpenBrowserOnStart": "Ouvrir le navigateur au démarrage", "NoUpdatesAreAvailable": "Aucune mise à jour n'est disponible", "NotificationTriggers": "Déclencheurs de notification", - "NoLimitForAnyRuntime": "Aucune limite pour aucune durée", - "NoMinimumForAnyRuntime": "Aucun minimum pour n'importe quel durée", "NoLogFiles": "Aucun fichier journal", "NoLeaveIt": "Non, laisse-le", "NoBackupsAreAvailable": "Aucune sauvegarde n'est disponible", @@ -329,8 +288,6 @@ "NetCore": ".NET Core", "MovieIndexScrollTop": "Index des films : faire défiler vers le haut", "MovieIndexScrollBottom": "Index des Films : faire défiler vers le bas", - "MovieDetailsPreviousMovie": "Détails du film : Film Précédent", - "MovieDetailsNextMovie": "Détails du film : Prochain Film", "MIA": "MIA", "LaunchBrowserHelpText": " Ouvrer un navigateur Web et accéder à la page d'accueil de Prowlarr au démarrage de l'application.", "CloseCurrentModal": "Fermer le modal actuel", @@ -439,5 +396,12 @@ "NoLinks": "Aucun liens", "Notification": "Notification", "UnableToAddANewIndexerProxyPleaseTryAgain": "Impossible d'ajouter un nouveau proxy d'indexation, veuillez réessayer.", - "UnableToLoadIndexerProxies": "Impossible de charger les proxys d'indexation" + "UnableToLoadIndexerProxies": "Impossible de charger les proxys d'indexation", + "Filters": "Filtres", + "HistoryCleanupDaysHelpText": "Définir sur 0 pour désactiver le nettoyage automatique", + "HistoryCleanupDaysHelpTextWarning": "Les fichiers dans la corbeille plus anciens que le nombre de jours sélectionné seront nettoyés automatiquement", + "OnGrab": "À la Récupération", + "OnHealthIssue": "Lors d'un problème de santé", + "TestAllIndexers": "Tester tous les indexeurs", + "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent fourni par l'application qui a appelé l'API" } diff --git a/src/NzbDrone.Core/Localization/Core/he.json b/src/NzbDrone.Core/Localization/Core/he.json index 26e2f5ec9..abf33af18 100644 --- a/src/NzbDrone.Core/Localization/Core/he.json +++ b/src/NzbDrone.Core/Localization/Core/he.json @@ -6,30 +6,23 @@ "CouldNotConnectSignalR": "לא ניתן להתחבר ל- SignalR, ממשק המשתמש לא יתעדכן", "Dates": "תאריכים", "EnableAutomaticSearchHelpText": "ישמש כאשר חיפושים אוטומטיים מבוצעים דרך ממשק המשתמש או על ידי Radarr", - "EnableAutomaticSearchHelpTextWarning": "ישמש כאשר נעשה שימוש בחיפוש אינטראקטיבי", - "EnableColorImpairedMode": "אפשר מצב של פגיעה בצבע", - "EnableHelpText": "אפשר יצירת קובץ מטא-נתונים עבור סוג מטא-נתונים זה", "EnableRss": "אפשר RSS", "EnableSSL": "אפשר SSL", - "MinutesSixty": "60 דקות: {0}", "Age": "גיל", "All": "את כל", "AllIndexersHiddenDueToFilter": "כל הסרטים מוסתרים בגלל המסנן שהוחל.", "Interval": "הַפסָקָה", "KeyboardShortcuts": "קיצורי דרך במקלדת", - "MaximumLimits": "מגבלות מקסימליות", "Mechanism": "מַנגָנוֹן", "Message": "הוֹדָעָה", "MIA": "MIA", "Name": "שֵׁם", "NoLinks": "אין קישורים", - "Pending": "ממתין ל", "PendingChangesDiscardChanges": "מחק שינויים ועזוב", "PriorityHelpText": "העדיפו עדיפות למספר לקוחות הורדה. Round-Robin משמש ללקוחות עם אותה עדיפות.", "PrioritySettings": "עדיפות", "ProxyBypassFilterHelpText": "השתמש ב- ',' כמפריד וב- '*.' כתו כללי לתת-דומיינים", "ProxyCheckBadRequestMessage": "נכשל בדיקת ה- proxy. קוד קוד: {0}", - "QualityDefinitions": "הגדרות איכות", "ReleaseStatus": "שחרור סטטוס", "Reload": "לִטעוֹן מִחָדָשׁ", "RemovedFromTaskQueue": "הוסר מתור המשימות", @@ -43,7 +36,6 @@ "UnableToLoadDownloadClients": "לא ניתן לטעון לקוחות הורדות", "UnableToAddANewNotificationPleaseTryAgain": "לא ניתן להוסיף התראה חדשה, נסה שוב.", "UnableToLoadGeneralSettings": "לא ניתן לטעון את ההגדרות הכלליות", - "UnableToLoadIndexers": "לא ניתן לטעון אינדקסים", "About": "על אודות", "AcceptConfirmationModal": "קבל את מודל האישור", "Added": "נוסף", @@ -59,13 +51,10 @@ "DeleteIndexerProxyMessageText": "האם אתה בטוח שברצונך למחוק את התג '{0}'?", "Donations": "תרומות", "DownloadClient": "הורד לקוח", - "DownloadClientCheckNoneAvailableMessage": "אין לקוח להורדה זמין", - "DownloadClientCheckUnableToCommunicateMessage": "לא ניתן לתקשר עם {0}.", "PendingChangesMessage": "יש לך שינויים שלא נשמרו, האם אתה בטוח שברצונך לעזוב דף זה?", "PendingChangesStayReview": "הישאר וסקר שינויים", "Port": "נמל", "PortNumber": "מספר יציאה", - "PreferredSize": "גודל מועדף", "Presets": "הגדרות קבועות מראש", "Proxy": "פרוקסי", "ProxyType": "סוג proxy", @@ -82,7 +71,6 @@ "UISettings": "הגדרות ממשק המשתמש", "UnableToAddANewAppProfilePleaseTryAgain": "לא ניתן להוסיף פרופיל איכות חדש, נסה שוב.", "UnableToLoadBackups": "לא ניתן לטעון גיבויים", - "UnableToLoadQualityDefinitions": "לא ניתן לטעון הגדרות איכות", "UnableToLoadTags": "לא ניתן לטעון תגים", "UnableToLoadUISettings": "לא ניתן לטעון הגדרות ממשק משתמש", "UnsavedChanges": "שינויים שלא נשמרו", @@ -96,8 +84,6 @@ "Date": "תַאֲרִיך", "DownloadClientStatusCheckAllClientMessage": "כל לקוחות ההורדה אינם זמינים עקב כשלים", "DownloadClientStatusCheckSingleClientMessage": "הורדת לקוחות לא זמינה עקב כשלים: {0}", - "DownloadClientUnavailable": "לקוח ההורדות אינו זמין", - "Downloading": "מוריד", "Fixed": "תוקן", "FocusSearchBox": "תיבת חיפוש פוקוס", "Folder": "תיקיה", @@ -111,7 +97,6 @@ "BeforeUpdate": "לפני העדכון", "Enabled": "מופעל", "Language": "שפה", - "Languages": "שפות", "LastWriteTime": "זמן כתיבה אחרון", "LaunchBrowserHelpText": " פתח דפדפן אינטרנט ונווט אל דף הבית של Radarr בהתחלת האפליקציה.", "Level": "רָמָה", @@ -120,9 +105,6 @@ "LogLevel": "רמת יומן", "LogLevelTraceHelpTextWarning": "יש להפעיל רישום מעקב באופן זמני בלבד", "Logs": "יומנים", - "MinimumLimits": "מגבלות מינימום", - "MinutesHundredTwenty": "120 דקות: {0}", - "MinutesNinety": "90 דקות: {0}", "NoChange": "ללא שינוי", "Analytics": "ניתוח", "AnalyticsEnabledHelpText": "שלח פרטי שימוש ושגיאה אנונימיים לשרתי Radarr. זה כולל מידע בדפדפן שלך, אילו דפי Radarr WebUI אתה משתמש, דיווח על שגיאות וכן מערכת הפעלה וגרסת זמן ריצה. אנו נשתמש במידע זה כדי לתעדף תכונות ותיקוני באגים.", @@ -187,7 +169,6 @@ "IndexerStatusCheckAllClientMessage": "כל האינדקסים אינם זמינים עקב כשלים", "IndexerStatusCheckSingleClientMessage": "אינדקסים לא זמינים בגלל כשלים: {0}", "NoBackupsAreAvailable": "אין גיבויים", - "NoLimitForAnyRuntime": "אין הגבלה לכל זמן ריצה", "PackageVersion": "גרסת חבילה", "Peers": "עמיתים", "ProxyCheckFailedToTestMessage": "נכשל בדיקת ה- proxy: {0}", @@ -209,7 +190,6 @@ "ConnectionLostAutomaticMessage": "Radarr ינסה להתחבר אוטומטית, או שתלחץ על טען מחדש למטה.", "Connections": "חיבורים", "ConnectSettings": "חבר הגדרות", - "QualitySettings": "הגדרות איכות", "Queue": "תוֹר", "ReadTheWikiForMoreInformation": "קרא את הוויקי למידע נוסף", "ResetAPIKey": "אפס את מפתח ה- API", @@ -217,7 +197,6 @@ "RestartNow": "אתחל עכשיו", "Restore": "לשחזר", "RestoreBackup": "שחזור גיבוי", - "Restrictions": "מגבלות", "Result": "תוֹצָאָה", "TagsHelpText": "חל על סרטים עם תג אחד לפחות תואם", "Today": "היום", @@ -245,16 +224,9 @@ "Edit": "לַעֲרוֹך", "EditIndexer": "ערוך אינדקס", "Enable": "לְאַפשֵׁר", - "EnableAutoHelpText": "אם מופעלת, סרטים יתווספו אוטומטית לרדאר מרשימה זו", - "EnableAutomaticAdd": "אפשר הוספה אוטומטית", - "MonoTlsCheckMessage": "הפיתרון לעקיפת הבעיה של Radarr Mono 4.x עדיין מופעל, שקול להסיר MONO_TLS_PROVIDER = אפשרות סביבה מדור קודם", - "MonoVersion": "גרסת מונו", - "MonoVersionCheckUpgradeRecommendedMessage": "גרסת מונו המותקנת כעת {0} נתמכת, אך מומלץ לשדרג ל- {1}.", "MoreInfo": "עוד מידע", - "MovieDetailsNextMovie": "פרטי הסרט: הסרט הבא", "MovieIndexScrollBottom": "אינדקס סרטים: גלילה תחתונה", "MovieIndexScrollTop": "אינדקס הסרטים: גלול למעלה", - "Movies": "סרטים", "Priority": "עדיפות", "SettingsTimeFormat": "פורמט זמן", "ShowAdvanced": "הצג מתקדם", @@ -267,7 +239,6 @@ "BackupRetentionHelpText": "גיבויים אוטומטיים ישנים יותר מתקופת השמירה ינוקו אוטומטית", "EnableInteractiveSearch": "אפשר חיפוש אינטראקטיבי", "EnableInteractiveSearchHelpText": "ישמש כאשר נעשה שימוש בחיפוש אינטראקטיבי", - "EnableInteractiveSearchHelpTextWarning": "אינדקס זה אינו נתמך בחיפוש", "IgnoredAddresses": "כתובות שהתעלמו מהן", "RestartRequiredHelpTextWarning": "נדרש הפעלה מחדש כדי להיכנס לתוקף", "UnableToAddANewApplicationPleaseTryAgain": "לא ניתן להוסיף התראה חדשה, נסה שוב.", @@ -276,19 +247,15 @@ "DeleteBackupMessageText": "האם אתה בטוח שברצונך למחוק את הגיבוי '{0}'?", "DeleteDownloadClient": "מחק את לקוח ההורדות", "DeleteDownloadClientMessageText": "האם אתה בטוח שברצונך למחוק את לקוח ההורדות '{0}'?", - "DeleteIndexer": "מחק את אינדקס", "Docker": "דוקר", "InteractiveSearch": "חיפוש אינטראקטיבי", "IllRestartLater": "אתחיל מאוחר יותר", - "Importing": "מייבא", "IncludeHealthWarningsHelpText": "כלול אזהרות בריאות", "Indexer": "מַפתְחָן", "IndexerFlags": "אינדקס דגלים", - "MovieDetailsPreviousMovie": "פרטי הסרט: הסרט הקודם", "NoChanges": "אין שינויים", "NoLeaveIt": "לא, עזוב את זה", "NoLogFiles": "אין קבצי יומן", - "NoMinimumForAnyRuntime": "אין מינימום לכל זמן ריצה", "Scheduled": "מתוזמן", "ApplyTagsHelpTexts1": "כיצד להחיל תגים על הסרטים שנבחרו", "ApiKey": "מפתח API", @@ -313,14 +280,11 @@ "CertificateValidation": "אימות תעודה", "Clear": "ברור", "ClientPriority": "עדיפות לקוח", - "CloneIndexer": "אינדקס שיבוט", "CloneProfile": "פרופיל שיבוט", "Close": "סגור", "CloseCurrentModal": "סגור את המודול הנוכחי", "DBMigration": "הגירת DB", - "DelayProfile": "עיכוב פרופיל", "Delete": "לִמְחוֹק", - "DeleteIndexerMessageText": "האם אתה בטוח שברצונך למחוק את האינדקס '{0}'?", "DeleteNotification": "מחק הודעה", "DeleteNotificationMessageText": "האם אתה בטוח שברצונך למחוק את ההודעה '{0}'?", "DeleteTag": "מחק את התג", @@ -329,17 +293,12 @@ "Disabled": "נָכֶה", "Discord": "מַחֲלוֹקֶת", "EnableAutomaticSearch": "אפשר חיפוש אוטומטי", - "EnableColorImpairedModeHelpText": "סגנון שונה כדי לאפשר למשתמשים לקויי צבע להבחין טוב יותר במידע המקודד בצבע", - "EnableCompletedDownloadHandlingHelpText": "ייבא אוטומטית הורדות שהושלמו מלקוח ההורדות", - "EnabledHelpText": "אפשר רשימה זו לשימוש ברדאר", - "EnableMediaInfoHelpText": "חלץ מידע וידאו כגון רזולוציה, זמן ריצה ומידע קודק מקבצים. זה מחייב את Radarr לקרוא חלקים מהקובץ שעלולים לגרום לדיסק גבוה או לפעילות רשת במהלך הסריקות.", "EnableSslHelpText": " דרוש הפעלה מחדש כמנהל כדי להיכנס לתוקף", "Error": "שְׁגִיאָה", "ErrorLoadingContents": "שגיאה בטעינת התוכן", "Events": "אירועים", "EventType": "סוג אירוע", "Exception": "יוצא מן הכלל", - "ExistingMovies": "סרטים קיימים", "ExistingTag": "תג קיים", "Failed": "נִכשָׁל", "FeatureRequests": "בקשות תכונה", @@ -357,5 +316,12 @@ "ShowSearch": "הצג חיפוש", "ShowSearchHelpText": "הצג את לחצן החיפוש ברחף", "UnableToAddANewDownloadClientPleaseTryAgain": "לא ניתן להוסיף לקוח הורדות חדש, נסה שוב.", - "UnableToAddANewIndexerPleaseTryAgain": "לא ניתן להוסיף אינדקס חדש, נסה שוב." + "UnableToAddANewIndexerPleaseTryAgain": "לא ניתן להוסיף אינדקס חדש, נסה שוב.", + "Filters": "לְסַנֵן", + "MaintenanceRelease": "שחרור תחזוקה: תיקוני באגים ושיפורים אחרים. לפרטים נוספים, ראה היסטוריית התחייבויות של Github", + "HistoryCleanupDaysHelpText": "הגדר ל 0 כדי להשבית ניקוי אוטומטי", + "HistoryCleanupDaysHelpTextWarning": "קבצים בסל המיחזור ישנים יותר ממספר הימים שנבחר ינוקו באופן אוטומטי", + "OnGrab": "על לתפוס", + "OnHealthIssue": "בנושא הבריאות", + "TestAllIndexers": "בדוק את כל האינדקסים" } diff --git a/src/NzbDrone.Core/Localization/Core/hi.json b/src/NzbDrone.Core/Localization/Core/hi.json index 81b5f1421..64e9d50fa 100644 --- a/src/NzbDrone.Core/Localization/Core/hi.json +++ b/src/NzbDrone.Core/Localization/Core/hi.json @@ -1,7 +1,6 @@ { "LogLevel": "छांटने का स्तर", "Message": "संदेश", - "Movies": "चलचित्र", "Name": "नाम", "Add": "जोड़ना", "Date": "दिनांक", @@ -17,10 +16,8 @@ "LogLevelTraceHelpTextWarning": "ट्रेस लॉगिंग को केवल अस्थायी रूप से सक्षम किया जाना चाहिए", "Logs": "लॉग्स", "Manual": "गाइड", - "MaximumLimits": "अधिकतम सीमा", "Mechanism": "तंत्र", "MIA": "एमआईए", - "MinutesSixty": "60 मिनट: {0}", "Mode": "मोड", "Proxy": "प्रतिनिधि", "ProxyBypassFilterHelpText": "एक विभाजक के रूप में ',' और '*' का प्रयोग करें। उपडोमेन के लिए एक वाइल्डकार्ड के रूप में", @@ -58,7 +55,6 @@ "ClientPriority": "ग्राहक प्राथमिकता", "Connections": "सम्बन्ध", "DownloadClientStatusCheckSingleClientMessage": "विफलताओं के कारण अनुपलब्ध ग्राहक डाउनलोड करें: {0}", - "MovieDetailsNextMovie": "मूवी विवरण: अगली फिल्म", "NoChanges": "कोई बदलाव नहीं", "Yesterday": "बिता कल", "DeleteIndexerProxyMessageText": "क्या आप वाकई '{0}' टैग हटाना चाहते हैं?", @@ -67,9 +63,6 @@ "Details": "विवरण", "EditIndexer": "अनुक्रमणिका संपादित करें", "Enable": "सक्षम", - "EnableAutomaticAdd": "स्वचालित जोड़ें सक्षम करें", - "EnableColorImpairedMode": "रंग-बिगड़ा मोड सक्षम करें", - "EnableAutomaticSearchHelpTextWarning": "इंटरैक्टिव खोज का उपयोग करने पर उपयोग किया जाएगा", "Filter": "फ़िल्टर", "Fixed": "फिक्स्ड", "Peers": "साथियों", @@ -93,9 +86,7 @@ "AddDownloadClient": "डाउनलोड क्लाइंट जोड़ें", "BackupIntervalHelpText": "स्वचालित बैकअप के बीच अंतराल", "Backups": "बैकअप", - "DelayProfile": "देरी प्रोफ़ाइल", "Delete": "हटाएं", - "EnableInteractiveSearchHelpTextWarning": "खोज इस अनुक्रमणिका के साथ समर्थित नहीं है", "Indexer": "इंडेक्सर", "ShowAdvanced": "शो पहले होगा", "ShowSearch": "खोज दिखाएँ", @@ -117,7 +108,6 @@ "IndexerStatusCheckSingleClientMessage": "अनुक्रमणिका विफलताओं के कारण अनुपलब्ध: {0}", "Info": "जानकारी", "Language": "भाषा: हिन्दी", - "Languages": "बोली", "PrioritySettings": "वरीयता", "UnableToAddANewDownloadClientPleaseTryAgain": "नया डाउनलोड क्लाइंट जोड़ने में असमर्थ, कृपया पुनः प्रयास करें।", "UnableToAddANewIndexerPleaseTryAgain": "नया अनुक्रमणिका जोड़ने में असमर्थ, कृपया पुनः प्रयास करें।", @@ -137,14 +127,8 @@ "DeleteBackupMessageText": "क्या आप वाकई '{0}' बैकअप हटाना चाहते हैं?", "DeleteDownloadClient": "डाउनलोड क्लाइंट हटाएं", "DeleteDownloadClientMessageText": "क्या आप वाकई डाउनलोड क्लाइंट '{0}' को हटाना चाहते हैं?", - "DeleteIndexer": "अनुक्रमणिका हटाएं", - "DeleteIndexerMessageText": "क्या आप वाकई '{0}' इंडेक्स को हटाना चाहते हैं?", "GeneralSettingsSummary": "पोर्ट, एसएसएल, उपयोगकर्ता नाम / पासवर्ड, प्रॉक्सी, एनालिटिक्स और अपडेट", "UrlBaseHelpText": "रिवर्स प्रॉक्सी समर्थन के लिए, डिफ़ॉल्ट खाली है", - "MonoTlsCheckMessage": "रेडार मोनो 4.x tls वर्कअराउंड अभी भी सक्षम है, MONO_TLS_PROVIDER = विरासत पर्यावरण विकल्प को हटाने पर विचार करें", - "MonoVersion": "मोनो संस्करण", - "MonoVersionCheckUpgradeRecommendedMessage": "वर्तमान में स्थापित मोनो संस्करण {0} समर्थित है लेकिन {1} में अपग्रेड करने की सिफारिश की गई है।", - "MovieDetailsPreviousMovie": "मूवी का विवरण: पिछला मूवी", "MovieIndexScrollBottom": "मूवी इंडेक्स: नीचे स्क्रॉल करें", "MovieIndexScrollTop": "मूवी इंडेक्स: टॉप स्क्रॉल करें", "NoLinks": "कोई लिंक नहीं", @@ -157,8 +141,6 @@ "ProxyType": "प्रॉक्सी प्रकार", "ProxyUsernameHelpText": "यदि आवश्यक हो तो आपको केवल एक उपयोगकर्ता नाम और पासवर्ड दर्ज करना होगा। उन्हें खाली छोड़ दें अन्यथा।", "PtpOldSettingsCheckMessage": "निम्न PassThePopcorn इंडेक्सर्स को हटाए गए सेटिंग्स हैं और उन्हें अपडेट किया जाना चाहिए: {0}", - "QualityDefinitions": "गुणवत्ता परिभाषाएँ", - "QualitySettings": "गुणवत्ता सेटिंग्स", "ReadTheWikiForMoreInformation": "अधिक जानकारी के लिए विकी पढ़ें", "Refresh": "ताज़ा करना", "RefreshMovie": "फिल्म को रिफ्रेश करें", @@ -197,9 +179,6 @@ "AllIndexersHiddenDueToFilter": "सभी फिल्में लागू फिल्टर के कारण छिपी हुई हैं।", "Analytics": "एनालिटिक्स", "AnalyticsEnabledHelpText": "बेनामी उपयोग और त्रुटि जानकारी को Radarr के सर्वर पर भेजें। इसमें आपके ब्राउज़र की जानकारी शामिल है, जो आपके द्वारा उपयोग किए जाने वाले रेडर वेबयूआई पृष्ठों, त्रुटि रिपोर्टिंग के साथ-साथ ओएस और रनटाइम संस्करण भी है। हम इस जानकारी का उपयोग सुविधाओं और बग फिक्स को प्राथमिकता देने के लिए करेंगे।", - "MinimumLimits": "न्यूनतम सीमा", - "MinutesHundredTwenty": "120 मिनट: {0}", - "MinutesNinety": "90 मिनट: {0}", "TagsHelpText": "कम से कम एक मिलान टैग के साथ फिल्मों पर लागू होता है", "DeleteTagMessageText": "क्या आप वाकई '{0}' टैग हटाना चाहते हैं?", "Disabled": "विकलांग", @@ -207,17 +186,12 @@ "Docker": "डाक में काम करनेवाला मज़दूर", "Donations": "दान", "DownloadClient": "क्लाइंट डाउनलोड करें", - "DownloadClientCheckNoneAvailableMessage": "कोई डाउनलोड क्लाइंट उपलब्ध नहीं है", - "DownloadClientCheckUnableToCommunicateMessage": "{0} के साथ संवाद करने में असमर्थ।", "DownloadClients": "ग्राहक डाउनलोड करें", - "Downloading": "डाउनलोड", - "Pending": "विचाराधीन", "PendingChangesDiscardChanges": "परिवर्तन छोड़ें और छोड़ें", "PendingChangesMessage": "आपने परिवर्तन रद्द कर दिए हैं, क्या आप वाकई इस पृष्ठ को छोड़ना चाहते हैं?", "RestartRequiredHelpTextWarning": "प्रभावी करने के लिए पुनरारंभ की आवश्यकता है", "Restore": "पुनर्स्थापित", "RestoreBackup": "बैकअप बहाल", - "Restrictions": "प्रतिबंध", "Result": "परिणाम", "Retention": "अवधारण", "RSS": "आरएसएस", @@ -227,7 +201,6 @@ "ShownClickToHide": "दिखाया, छिपाने के लिए क्लिक करें", "Tasks": "कार्य", "UnableToLoadHistory": "इतिहास लोड करने में असमर्थ", - "UnableToLoadIndexers": "अनुक्रमणिका लोड करने में असमर्थ", "AppDataLocationHealthCheckMessage": "अद्यतन पर अद्यतन AppData को रोकने के लिए अद्यतन करना संभव नहीं होगा", "Usenet": "यूज़नेट", "UseProxy": "प्रॉक्सी का उपयोग करें", @@ -244,7 +217,6 @@ "DeleteNotificationMessageText": "क्या आप वाकई '{0}' की सूचना हटाना चाहते हैं?", "IgnoredAddresses": "उपेक्षित पते", "IllRestartLater": "मैं बाद में पुनः आरंभ करूँगा", - "Importing": "आयात कर रहा है", "NotificationTriggers": "अधिसूचना ट्रिगर", "PageSize": "पृष्ठ आकार", "Time": "समय", @@ -268,31 +240,22 @@ "CertificateValidation": "प्रमाणपत्र सत्यापन", "CertificateValidationHelpText": "बदलें कि HTTPS प्रमाणन सत्यापन कितना सख्त है", "Clear": "स्पष्ट", - "CloneIndexer": "क्लोन इंडेक्सर", "CloneProfile": "क्लोन प्रोफ़ाइल", "Close": "बंद करे", "CloseCurrentModal": "वर्तमान मोडल को बंद करें", "DownloadClientStatusCheckAllClientMessage": "सभी डाउनलोड क्लाइंट विफलताओं के कारण अनुपलब्ध हैं", - "DownloadClientUnavailable": "डाउनलोड क्लाइंट अनुपलब्ध है", "Edit": "संपादित करें", - "EnableAutoHelpText": "यदि सक्षम किया गया है, तो फिल्में इस सूची से स्वचालित रूप से Radarr में जुड़ जाएंगी", "EnableAutomaticSearch": "स्वचालित खोज सक्षम करें", "EnableAutomaticSearchHelpText": "यूआई के माध्यम से या रेडर द्वारा स्वचालित खोज किए जाने पर उपयोग किया जाएगा", - "EnableColorImpairedModeHelpText": "रंग बिगड़ा हुआ उपयोगकर्ताओं को बेहतर रंग कोडित जानकारी को अलग करने की अनुमति देने के लिए बदल शैली", - "EnableCompletedDownloadHandlingHelpText": "डाउनलोड क्लाइंट से स्वचालित रूप से पूर्ण डाउनलोड आयात करें", "Enabled": "सक्रिय", - "EnabledHelpText": "इस सूची को Radarr में उपयोग के लिए सक्षम करें", - "EnableHelpText": "इस मेटाडेटा प्रकार के लिए मेटाडेटा फ़ाइल निर्माण सक्षम करें", "EnableInteractiveSearch": "इंटरएक्टिव खोज सक्षम करें", "EnableInteractiveSearchHelpText": "इंटरैक्टिव खोज का उपयोग करने पर उपयोग किया जाएगा", - "EnableMediaInfoHelpText": "वीडियो जानकारी जैसे रिज़ॉल्यूशन, रनटाइम और कोडेक जानकारी फ़ाइलों से निकालें। इसके लिए रेडर को फ़ाइल के कुछ हिस्सों को पढ़ना पड़ता है, जिससे स्कैन के दौरान हाई डिस्क या नेटवर्क गतिविधि हो सकती है।", "EnableRss": "आरएसएस को सक्षम करें", "EnableSSL": "SSL सक्षम करें", "EnableSslHelpText": " प्रभावी होने के लिए प्रशासक के रूप में पुनः आरंभ करने की आवश्यकता है", "Error": "त्रुटि", "ErrorLoadingContents": "सामग्री लोड करने में त्रुटि", "Events": "आयोजन", - "ExistingMovies": "मौजूदा मूवी", "ExistingTag": "मौजूदा टैग", "Failed": "अनुत्तीर्ण होना", "FeatureRequests": "सुविधा का अनुरोध", @@ -329,15 +292,12 @@ "NoBackupsAreAvailable": "कोई बैकअप उपलब्ध नहीं हैं", "NoChange": "कोई परिवर्तन नहीं होता है", "NoLeaveIt": "नहीं, इसे छोड़ो", - "NoLimitForAnyRuntime": "किसी भी रनटाइम के लिए कोई सीमा नहीं", "NoLogFiles": "कोई लॉग फ़ाइल नहीं", - "NoMinimumForAnyRuntime": "किसी रनटाइम के लिए कोई न्यूनतम नहीं", "Ok": "ठीक", "PackageVersion": "पैकेज संस्करण", "PageSizeHelpText": "प्रत्येक पृष्ठ पर दिखाने के लिए मदों की संख्या", "Password": "कुंजिका", "PendingChangesStayReview": "रहें और परिवर्तनों की समीक्षा करें", - "PreferredSize": "पसंदीदा आकार", "Presets": "प्रीसेट", "Priority": "वरीयता", "PriorityHelpText": "एकाधिक डाउनलोड ग्राहकों को प्राथमिकता दें। राउंड-रॉबिन का उपयोग उसी प्राथमिकता वाले ग्राहकों के लिए किया जाता है।", @@ -348,7 +308,6 @@ "UnableToLoadDownloadClients": "डाउनलोड क्लाइंट लोड करने में असमर्थ", "UnableToLoadGeneralSettings": "सामान्य सेटिंग्स लोड करने में असमर्थ", "UnableToLoadNotifications": "सूचनाएं लोड करने में असमर्थ", - "UnableToLoadQualityDefinitions": "गुणवत्ता परिभाषाएँ लोड करने में असमर्थ", "UpdateCheckStartupNotWritableMessage": "अपडेट स्थापित नहीं किया जा सकता क्योंकि स्टार्टअप फ़ोल्डर '{0}' उपयोगकर्ता '{1}' द्वारा लिखने योग्य नहीं है।", "UpdateCheckStartupTranslocationMessage": "अपडेट स्थापित नहीं किया जा सकता क्योंकि स्टार्टअप फ़ोल्डर '{0}' ऐप ट्रांसलेशन फ़ोल्डर में है।", "NoUpdatesAreAvailable": "कोई अद्यतन उपलब्ध नहीं हैं", @@ -357,5 +316,12 @@ "OpenBrowserOnStart": "प्रारंभ पर ब्राउज़र खोलें", "OpenThisModal": "इस मोडल को खोलें", "Options": "विकल्प", - "Status": "स्थिति" + "Status": "स्थिति", + "OnGrab": "हड़पने पर", + "OnHealthIssue": "स्वास्थ्य के मुद्दे पर", + "TestAllIndexers": "सभी सूचकांक का परीक्षण करें", + "MaintenanceRelease": "रखरखाव रिलीज: बग फिक्स और अन्य सुधार। अधिक जानकारी के लिए गितुब कमिट इतिहास देखें", + "Filters": "फ़िल्टर", + "HistoryCleanupDaysHelpText": "स्वचालित सफाई को अक्षम करने के लिए 0 पर सेट करें", + "HistoryCleanupDaysHelpTextWarning": "रीसायकल बिन में चयनित दिनों की तुलना में पुरानी फाइलें अपने आप साफ हो जाएंगी" } diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index c3a8e3d52..c327f5027 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -4,26 +4,17 @@ "AddIndexer": "Indexer hozzáadása", "AddingTag": "Címke hozzáadása", "Error": "Hiba", - "EnableCompletedDownloadHandlingHelpText": "A befejezett letöltések automatikus importálása a letöltési kliensből", - "EnableColorImpairedModeHelpText": "Megváltoztatott színek, hogy a színvak felhasználók jobban meg tudják különböztetni a színkódolt információkat", - "EnableAutomaticSearchHelpTextWarning": "Interaktív keresés esetén is felhasználható", "DeleteTag": "Címke Törlése", "EnableAutomaticSearchHelpText": "Akkor kerül felhasználásra, ha az automatikus kereséseket a kezelőfelületen vagy a Prowlarr-on keresztül hajtják végre", "EnableAutomaticSearch": "Engedélyezd az Automatikus Keresést", - "EnableAutomaticAdd": "Engedélyezd az automatikus hozzáadást", - "EnableAutoHelpText": "Ha engedélyezve van, a Filmek automatikusan hozzáadódnak a Prowlarr-hoz ebből a listából", "Enable": "Aktiválás", "EditIndexer": "Indexer Szerkesztése", "Edit": "Szerkesztés", - "Downloading": "Letöltés Alatt", - "DownloadClientUnavailable": "Letöltőkliens nem elérhető", "DownloadClientStatusCheckSingleClientMessage": "Letöltőkliens hiba miatt nem elérhető: {0}", "DownloadClientStatusCheckAllClientMessage": "Az összes letöltőkliens elérhetetlen, hiba miatt", "DownloadClientsSettingsSummary": "Letöltőkliens konfigurációja a Prowlarr felhasználói felület keresésbe történő integráláshoz", "DownloadClientSettings": "Letöltőkliens Beállítások", "DownloadClients": "Letöltőkliensek", - "DownloadClientCheckUnableToCommunicateMessage": "Nem lehet kommunikálni a következővel: {0}.", - "DownloadClientCheckNoneAvailableMessage": "Nem található letöltési kliens", "DownloadClient": "Letöltési Kliens", "Docker": "Docker", "Disabled": "Letiltott", @@ -31,14 +22,11 @@ "DeleteTagMessageText": "Biztosan törlöd a(z) „{0}” címkét?", "DeleteNotificationMessageText": "Biztosan törlöd a(z) „{0}” értesítést?", "DeleteNotification": "Értesítés Törlése", - "DeleteIndexerMessageText": "Biztosan törlöd a(z) „{0}” indexert?", - "DeleteIndexer": "Indexer Törlése", "DeleteDownloadClientMessageText": "Biztosan törlöd a(z) „{0}” letöltő klienst?", "DeleteDownloadClient": "Letöltőkliens Törlése", "DeleteBackupMessageText": "Biztosan törlöd a(z) „{0}” biztonsági mentést?", "DeleteBackup": "Biztonsági Mentés Törlése", "Delete": "Törlés", - "DelayProfile": "Késleltetési Profil", "DBMigration": "DB Migráció", "Dates": "Dátumok", "Date": "Dátum", @@ -55,7 +43,6 @@ "CloseCurrentModal": "Aktuális Mód Bezárása", "Close": "Bezárás", "CloneProfile": "Profil Klónozása", - "CloneIndexer": "Indexer Klónozása", "ClientPriority": "Kliens Prioritás", "Clear": "Törölni", "ChangeHasNotBeenSavedYet": "A változások még nem lettek elmentve", @@ -112,20 +99,14 @@ "Filename": "Fájlnév", "Failed": "Sikertelen", "ExistingTag": "Meglévő Címke", - "ExistingMovies": "Létező Film(ek)", "Exception": "Kivétel", "EventType": "Események Típusa", "Events": "Események", "ErrorLoadingContents": "Hiba történt a tartalom betöltésekor", "EnableSslHelpText": " A hatálybalépéshez újra kell indítani rendszergazdaként", "EnableSSL": "SSL Engedélyezése", - "EnableMediaInfoHelpText": "Videofájlok, például felbontás, filmhossz és kodek információk kiolvasása fájlokból. Ehhez a Prowlarr-nak fel kell dolgoznia a fájl olyan részeit, amelyek nagy lemez, illetve hálózati aktivitást okozhatnak a vizsgálatok során.", - "EnableInteractiveSearchHelpTextWarning": "A keresés nem támogatott ezzel az Indexerrel", "EnableInteractiveSearchHelpText": "Interaktív keresés esetén használható", "EnableInteractiveSearch": "Interaktív Keresés Engedélyezése", - "EnableHelpText": "Engedélyezze a metaadatfájlok létrehozását ehhez a metaadat típushoz", - "EnabledHelpText": "Engedélyezze ezt a lista használatát a Prowlarr alkalmazásban", - "EnableColorImpairedMode": "Engedélyezze a színtévesztő módot", "System": "Rendszer", "SuggestTranslationChange": "Javasolj fordítási változtatást", "Style": "Stílus", @@ -142,8 +123,6 @@ "Size": "Méret", "Shutdown": "Leállítás", "ShowSearchHelpText": "A kereső gomb megjelenítése az egérrel", - "MonoVersion": "Mono Verzió", - "MonoTlsCheckMessage": "A Prowlarr Mono 4.x tls megoldás továbbra is engedélyezett, fontolja meg a MONO_TLS_PROVIDER =legacy opció eltávolítását", "ShownClickToHide": "Kattints, hogy elrejtsd", "ShowAdvanced": "Haladó nézet", "SettingsTimeFormat": "Időformátum", @@ -167,7 +146,6 @@ "RSSIsNotSupportedWithThisIndexer": "Az RSS nem támogatott ezzel az indexerrel", "Retention": "Visszatartás", "Result": "Eredmények", - "Restrictions": "Korlátozások", "RestoreBackup": "Biztonsági mentés visszaállítása", "Restore": "Visszaállítás", "RestartRequiredHelpTextWarning": "Újraindítás szükséges a hatálybalépéshez", @@ -181,7 +159,6 @@ "RemovedFromTaskQueue": "Eltávolítva a feladatsorról", "Reload": "Újratöltés", "ReleaseStatus": "Kiadás státusza", - "ReleaseBranchCheckPreviousVersionMessage": "Az ágazat {0} a Prowlarr előző verziójához tartozik, a további frissítések érdekében állítsd az ágat 'nightly'-ra", "ReleaseBranchCheckOfficialBranchMessage": "A(z) {0} nem érvényes Prowlarr frissítési ágazat, ezért nem kap frissítéseket", "RefreshMovie": "Film frissítése", "Refresh": "Frissítés", @@ -189,8 +166,6 @@ "ProwlarrSupportsAnyIndexer": "A Prowlarr számos indexert támogat, minden olyan indexelő mellett, amely a Newznab / Torznab szabványt használja, valamint a 'Generic Newznab' (usenethez) vagy a 'Generic Torznab' (torrentekhez) használatával. Keresés és az alább felsorolt indexelők kiválasztása.", "ProwlarrSupportsAnyDownloadClient": "A Prowlarr minden olyan letöltési klienst támogat, amely a Newznab szabványt használja, valamint az alább felsorolt letöltési klienseket.", "Queue": "Várakozási sor", - "QualitySettings": "Minőségi beállítások", - "QualityDefinitions": "Minőségi meghatározások", "PtpOldSettingsCheckMessage": "A következő PassThePopcorn indexerek elavult beállításokkal rendelkeznek, és frissíteni kell őket: {0}", "ProxyUsernameHelpText": "Csak akkor kell megadnod felhasználónevet és jelszót, ha szükséges. Egyébként hagyd üresen.", "ProxyType": "Proxy Típusa", @@ -203,14 +178,11 @@ "Protocol": "Protokoll", "PriorityHelpText": "Priorizálj több letöltési klienst. A Round-Robint azonos prioritású letöltőkliensek használják.", "Priority": "Prioritás", - "MonoVersionCheckUpgradeRecommendedMessage": "A jelenleg telepített Mono {0} verzió támogatott, de ajánlott frissíteni a(z) {1} verzióra.", - "PreferredSize": "Preferált méret", "PortNumber": "Port száma", "Port": "Port", "PendingChangesStayReview": "Maradj, és tekintsd át a változásokat", "PendingChangesMessage": "Nem mentett módosításaid vannak, biztosan el akarod hagyni ezt az oldalt?", "PendingChangesDiscardChanges": "Változtatások törlése és kilépés", - "Pending": "Függőben", "Peers": "Peerek", "Password": "Jelszó", "PageSizeHelpText": "Az egyes oldalakon megjelenítendő elemek száma", @@ -224,9 +196,7 @@ "OAuthPopupMessage": "A böngésződ blokkolja az előugró ablakokat", "NoUpdatesAreAvailable": "Nincsenek elérhető frissítések", "NoTagsHaveBeenAddedYet": "Még nem adtál hozzá címkéket", - "NoMinimumForAnyRuntime": "Nincs minimális futásidő", "NoLogFiles": "Nincsen log fájl", - "NoLimitForAnyRuntime": "Nincs futási idő korlát", "NoLeaveIt": "Nem, hagyd így", "NoChanges": "Nincsenek változások", "NoChange": "Nincs változtatás", @@ -234,24 +204,15 @@ "New": "Új", "NetCore": ".NET", "Name": "Név", - "Movies": "Filmek", "MovieIndexScrollTop": "Film Index: Görgess fel", "MovieIndexScrollBottom": "Film Index: Görgess le", - "MovieDetailsPreviousMovie": "A film részletei: Előző film", - "MovieDetailsNextMovie": "A film részletei: Következő film", "MoreInfo": "Több Információ", - "MonoNotNetCoreCheckMessage": "Kérjük, frissítsd a Prowlarr .NET Core verzióját", "Mode": "Mód", - "MinutesSixty": "60 Perc: {0}", - "MinutesNinety": "90 Perc: {0}", - "MinutesHundredTwenty": "120 Perc: {0}", - "MinimumLimits": "Minimális Határ", "MIA": "MIA", "Message": "Üzenet", "Mechanism": "Mechanizmus", - "MaximumLimits": "Maximális Limit", "Manual": "Manuális", - "MaintenanceRelease": "Karbantartási kiadás", + "MaintenanceRelease": "Karbantartási frissítés: hibajavítások és egyéb fejlesztések. További részletekért lásd: Github Commit History", "Logs": "Logok", "LogLevelTraceHelpTextWarning": "A nyomkövetést csak ideiglenesen szabad engedélyezni", "LogLevel": "Log Szint", @@ -260,7 +221,6 @@ "Level": "Szint", "LaunchBrowserHelpText": " Nyisson meg egy böngészőt, és az alkalmazás indításakor lépjen a Prowlarr kezdőlapjára.", "LastWriteTime": "Utolsó írási idő", - "Languages": "Nyelvek", "Language": "Nyelv", "KeyboardShortcuts": "Gyorsbillentyűk", "Interval": "Intervallum", @@ -272,7 +232,6 @@ "Grabbed": "Megfogva", "GeneralSettings": "Általános Beállítások", "General": "Általános", - "UnableToLoadIndexers": "Nem lehet betölteni az indexereket", "UnableToLoadHistory": "Nem sikerült betölteni az előzményeket", "UnableToLoadGeneralSettings": "Nem sikerült betölteni az általános beállításokat", "UnableToLoadDownloadClients": "Nem sikerült betölteni a letöltőkliens(eke)t", @@ -308,7 +267,6 @@ "IndexerFlags": "Indexer Zászló", "Indexer": "Indexelő", "IncludeHealthWarningsHelpText": "Tartalmazza a Állapot Figyelmeztetéseket", - "Importing": "Importálás Folyamatban", "IllRestartLater": "Később Újraindítom", "IgnoredAddresses": "Ignorált Címek", "YesCancel": "Igen, Mégsem", @@ -332,7 +290,6 @@ "UnsavedChanges": "Nem mentett változások", "UnableToLoadUISettings": "Nem sikerült betölteni a felhasználói felület beállításait", "UnableToLoadTags": "Nem sikerült betölteni a címkéket", - "UnableToLoadQualityDefinitions": "Nem lehet betölteni a minőségi meghatározásokat", "UnableToLoadNotifications": "Nem sikerült betölteni az Értesítéseket", "TableOptions": "Táblázat beállításai", "ShowSearch": "Keresés(ek) megjelenítése", @@ -415,8 +372,8 @@ "Torrent": "Torrent", "UnableToLoadAppProfiles": "Nem sikerült betölteni az alkalmazásprofilokat", "PrioritySettings": "Prioritás", - "SyncLevelFull": "Teljes szinkron: Teljesen szinkronban tartja ezt az alkalmazást. A Prowlarr-ban végrehajtott módosításokat ezután szinkronizálja ezzel az alkalmazással. A távolról végrehajtott módosításokat a Prowlarr felülírja a következő szinkronizáláskor.", - "SyncLevelAddRemove": "Csak hozzáadás és eltávolítás: Amikor hozzáadja vagy eltávolítja a Prowlarr-ból, frissíti ezt a távoli alkalmazást.", + "SyncLevelFull": "Teljes szinkronizálás: Az alkalmazás indexereit teljesen szinkronban tartja. A Prowlarr indexerein végrehajtott módosítások ezután szinkronizálódnak ezzel az alkalmazással. A Prowlarr a következő szinkronizáláskor felülírja az indexerekben távolról végrehajtott módosításokat.", + "SyncLevelAddRemove": "Hozzáadás és eltávolítás: Ha indexereket ad hozzá vagy távolít el a Prowlarr-ból, az frissíti ezt a távoli alkalmazást.", "SyncLevel": "Szinkronizálás Szintje", "FullSync": "Teljes Szinkron", "AddRemoveOnly": "Csak hozzáadás és eltávolítás", @@ -429,7 +386,7 @@ "IndexerProxies": "Indexer Proxy(k)", "IndexerProxyStatusCheckAllClientMessage": "Az összes Proxy elérhetetlen, hiba miatt", "IndexerProxyStatusCheckSingleClientMessage": "Proxyk elérhetetlenek az alábbi hibák miatt: {0}", - "IndexerTagsHelpText": "Címkékkel határozhatja meg az alapértelmezett ügyfeleket, adhat meg indexer proxyt, vagy csak rendszerezheti indexelőit.", + "IndexerTagsHelpText": "A címkék segítségével megadhatja az indexelő proxykat, vagy egyszerűen rendezheti az indexelőket.", "UnableToLoadIndexerProxies": "Nem lehet betölteni az Indexer Proxyt", "AddIndexerProxy": "Indexer Proxy hozzáadása", "IndexerSettingsSummary": "Konfigurálja a különböző globális indexer beállításokat, beleértve a proxykat is.", @@ -445,5 +402,29 @@ "AudioSearch": "Hang keresés", "MovieSearch": "Film Kereső", "QueryOptions": "Lekérdezési beállítások", - "SearchType": "Keresés típusa" + "SearchType": "Keresés típusa", + "Categories": "Kategóriák", + "Database": "Adatbázis", + "Filters": "Szűrők", + "HistoryCleanup": "Előzmények törlése", + "HistoryCleanupDaysHelpText": "Állítsd 0-ra az automatikus tisztítás letiltásához", + "HistoryCleanupDaysHelpTextWarning": "A kiválasztott napszámnál régebbi előzmények automatikusan törlődnek", + "IndexerAlreadySetup": "Az indexelő legalább egy példánya már be van állítva", + "IndexerInfo": "Indexer információ", + "IndexerNoDefCheckMessage": "Az indexereknek nincs definíciójuk, és nem működnek: {0}. Kérjük, távolítsa el és (vagy) adja hozzá újra a Prowlarrhoz", + "MassEditor": "Tömeges szerkesztő", + "OnApplicationUpdate": "Alkalmazásfrissítésről", + "OnApplicationUpdateHelpText": "Alkalmazásfrissítésről", + "OnGrab": "Kiválasztás alatt", + "OnHealthIssue": "Állapotprobléma", + "Private": "Privát", + "Proxies": "Proxyk", + "Public": "Publikus", + "QueryResults": "Lekérdezési eredmények", + "SemiPrivate": "Fél-Privát", + "TestAllIndexers": "Indexerek tesztelése", + "UnableToLoadApplicationList": "Nem sikerült betölteni az alkalmazáslistát", + "Url": "URL", + "UserAgentProvidedByTheAppThatCalledTheAPI": "Az API-t hívó alkalmazás biztosítja a User-Agent szolgáltatást", + "Website": "Weboldal" } diff --git a/src/NzbDrone.Core/Localization/Core/is.json b/src/NzbDrone.Core/Localization/Core/is.json index f4ac2cb0c..d05dcf9d9 100644 --- a/src/NzbDrone.Core/Localization/Core/is.json +++ b/src/NzbDrone.Core/Localization/Core/is.json @@ -15,7 +15,6 @@ "About": "Um það bil", "Added": "Bætt við", "DeleteIndexerProxyMessageText": "Ertu viss um að þú viljir eyða merkinu '{0}'?", - "EnableColorImpairedModeHelpText": "Breyttur stíll til að leyfa litaskertum notendum að greina betur litakóðuð upplýsingar", "Enabled": "Virkt", "EnableInteractiveSearchHelpText": "Verður notað þegar gagnvirk leit er notuð", "EnableRss": "Virkja RSS", @@ -70,7 +69,6 @@ "UnableToLoadDownloadClients": "Ekki er hægt að hlaða niður viðskiptavinum", "UnableToLoadGeneralSettings": "Ekki er hægt að hlaða almennar stillingar", "UnableToLoadHistory": "Ekki er hægt að hlaða sögu", - "UnableToLoadIndexers": "Ekki er hægt að hlaða Indexers", "UnableToLoadNotifications": "Ekki er hægt að hlaða tilkynningar", "UrlBaseHelpText": "Fyrir öfugan umboðsmannastuðning er sjálfgefið autt", "UseProxy": "Notaðu Proxy", @@ -78,28 +76,21 @@ "Version": "Útgáfa", "LaunchBrowserHelpText": " Opnaðu vafra og farðu á Radarr heimasíðuna þegar forritið byrjar.", "Level": "Stig", - "MaximumLimits": "Hámarksmörk", "Mechanism": "Mekanismi", "Message": "Skilaboð", "AcceptConfirmationModal": "Samþykkja staðfestingarform", "Actions": "Aðgerðir", - "CloneIndexer": "Clone Indexer", "Proxy": "Umboðsmaður", "SuggestTranslationChange": "Legg til þýðingabreytingu", "DeleteTag": "Eyða tagi", "DeleteTagMessageText": "Ertu viss um að þú viljir eyða merkinu '{0}'?", "Donations": "Framlög", "DownloadClient": "Sæktu viðskiptavin", - "DownloadClientCheckNoneAvailableMessage": "Enginn niðurhalsþjónn er í boði", "Edit": "Breyta", - "EnableCompletedDownloadHandlingHelpText": "Flytja sjálfkrafa niður niðurhal frá niðurhalsþjóni", - "EnabledHelpText": "Virkaðu þennan lista til notkunar í Radarr", - "EnableHelpText": "Virkja stofnun lýsigagna fyrir þessa gerð lýsigagna", "EnableInteractiveSearch": "Virkja gagnvirka leit", "EnableSSL": "Virkja SSL", "EnableSslHelpText": " Krefst endurræsingar sem stjórnandi til að taka gildi", "Error": "Villa", - "ExistingMovies": "Núverandi kvikmynd (ir)", "ExistingTag": "Núverandi merki", "Failed": "Mistókst", "FeatureRequests": "Aðgerðarbeiðnir", @@ -109,10 +100,7 @@ "LogLevelTraceHelpTextWarning": "Aðeins ætti að virkja rakningaskráningu tímabundið", "Manual": "Handbók", "MIA": "MIA", - "MinimumLimits": "Lágmark", - "MinutesHundredTwenty": "120 mínútur: {0}", "New": "Nýtt", - "NoMinimumForAnyRuntime": "Ekkert lágmark fyrir neina keyrslutíma", "NotificationTriggers": "Tilkynningakveikjur", "PackageVersion": "Pakki Útgáfa", "PageSize": "Stærð blaðsíðu", @@ -120,8 +108,6 @@ "ProxyCheckResolveIpMessage": "Mistókst að leysa IP-tölu fyrir stillta proxy-gestgjafa {0}", "ProxyPasswordHelpText": "Þú þarft aðeins að slá inn notendanafn og lykilorð ef þess er krafist. Láttu þá vera auða annars.", "ProxyType": "Umboðsmaður", - "QualityDefinitions": "Gæðaskilgreiningar", - "QualitySettings": "Gæðastillingar", "Queue": "Biðröð", "ReadTheWikiForMoreInformation": "Lestu Wiki fyrir frekari upplýsingar", "Refresh": "Hressa", @@ -138,7 +124,6 @@ "UILanguageHelpText": "Tungumál sem Radarr mun nota fyrir HÍ", "UILanguageHelpTextWarning": "Endurhlaða vafra krafist", "UISettings": "Stillingar HÍ", - "UnableToLoadQualityDefinitions": "Ekki er hægt að hlaða gæðaskilgreiningar", "UnableToLoadTags": "Ekki er hægt að hlaða merkin", "UnableToLoadUISettings": "Ekki er hægt að hlaða stillingar HÍ", "UnselectAll": "Afmarkaðu allt", @@ -157,7 +142,6 @@ "Yesterday": "Í gær", "Connections": "Tengingar", "Custom": "Sérsniðin", - "EnableColorImpairedMode": "Virkja litaskerta ham", "HideAdvanced": "Fela lengra komna", "HomePage": "Heimasíða", "PriorityHelpText": "Forgangsraðaðu mörgum niðurhal viðskiptavinum. Round-Robin er notað fyrir viðskiptavini með sömu forgang.", @@ -223,34 +207,23 @@ "CustomFilters": "Sérsniðin síur", "Dates": "Dagsetningar", "DBMigration": "DB fólksflutningar", - "DelayProfile": "Seinka prófíl", "Delete": "Eyða", "DeleteApplicationMessageText": "Ertu viss um að þú viljir eyða tilkynningunni „{0}“?", "DeleteBackup": "Eyða afritun", "DeleteBackupMessageText": "Ertu viss um að þú viljir eyða öryggisafritinu '{0}'?", "DeleteDownloadClientMessageText": "Ertu viss um að þú viljir eyða niðurhalsviðskiptavininum '{0}'?", - "DeleteIndexer": "Eyða Indexer", - "DeleteIndexerMessageText": "Ertu viss um að þú viljir eyða vísitölunni '{0}'?", "DeleteNotification": "Eyða tilkynningu", "DeleteNotificationMessageText": "Ertu viss um að þú viljir eyða tilkynningunni „{0}“?", "Disabled": "Öryrkjar", "Discord": "Ósætti", "Docker": "Docker", - "DownloadClientCheckUnableToCommunicateMessage": "Ekki er hægt að eiga samskipti við {0}.", "DownloadClients": "Sækja viðskiptavini", "DownloadClientStatusCheckAllClientMessage": "Allir viðskiptavinir sem hlaða niður eru ekki tiltækir vegna bilana", "DownloadClientStatusCheckSingleClientMessage": "Sæktu viðskiptavini sem eru ekki tiltækir vegna bilana: {0}", - "DownloadClientUnavailable": "Niðurhalsþjónn er ekki tiltækur", - "Downloading": "Sækir", "EditIndexer": "Breyttu Indexer", "Enable": "Virkja", - "EnableAutoHelpText": "Ef það er virkt verður kvikmyndum sjálfkrafa bætt við Radarr af þessum lista", - "EnableAutomaticAdd": "Virkja sjálfvirka viðbót", "EnableAutomaticSearch": "Virkja sjálfvirka leit", "EnableAutomaticSearchHelpText": "Verður notað þegar sjálfvirkar leitir eru framkvæmdar í HÍ eða af Radarr", - "EnableAutomaticSearchHelpTextWarning": "Verður notað þegar gagnvirk leit er notuð", - "EnableInteractiveSearchHelpTextWarning": "Leit er ekki studd með þessum flokkara", - "EnableMediaInfoHelpText": "Dragðu út myndbandsupplýsingar eins og upplausn, keyrslutíma og merkjamál upplýsingar úr skrám. Þetta krefst þess að Radarr lesi hluta af skránni sem geta valdið mikilli virkni á diski eða neti meðan á skönnunum stendur.", "Filter": "Sía", "Fixed": "Fastur", "HealthNoIssues": "Engin vandamál með stillingar þínar", @@ -258,7 +231,6 @@ "Host": "Gestgjafi", "Hostname": "Gestgjafanafn", "IllRestartLater": "Ég byrja aftur seinna", - "Importing": "Innflutningur", "IncludeHealthWarningsHelpText": "Láttu heilsuviðvaranir fylgja með", "Indexer": "Indexer", "Info": "Upplýsingar", @@ -269,7 +241,6 @@ "Indexers": "Vísitölufólk", "IndexerStatusCheckAllClientMessage": "Allir verðtryggingaraðilar eru ekki tiltækir vegna bilana", "IndexerStatusCheckSingleClientMessage": "Vísitölufólk er ekki tiltækt vegna bilana: {0}", - "NoLimitForAnyRuntime": "Engin takmörk fyrir neina keyrslutíma", "NoLogFiles": "Engar logskrár", "Ok": "Allt í lagi", "OnHealthIssueHelpText": "Um heilbrigðismál", @@ -277,11 +248,9 @@ "Options": "Valkostir", "Password": "Lykilorð", "Peers": "Jafningjar", - "Pending": "Í bið", "PendingChangesDiscardChanges": "Fargaðu breytingum og farðu", "PendingChangesMessage": "Þú ert með óvistaðar breytingar, ertu viss um að þú viljir yfirgefa þessa síðu?", "PendingChangesStayReview": "Vertu og skoðaðu breytingar", - "PreferredSize": "Æskileg stærð", "ShowAdvanced": "Sýna lengra komna", "UnableToAddANewAppProfilePleaseTryAgain": "Ekki er hægt að bæta við nýjum gæðaprófíl, reyndu aftur.", "UnableToAddANewDownloadClientPleaseTryAgain": "Ekki er hægt að bæta við nýjum niðurhalsþjóni, reyndu aftur.", @@ -298,19 +267,10 @@ "KeyboardShortcuts": "Flýtilyklar", "Language": "Tungumál", "LogFiles": "Log skrár", - "Languages": "Tungumál", "LastWriteTime": "Síðasti skrifatími", - "MinutesNinety": "90 mínútur: {0}", - "MinutesSixty": "60 mínútur: {0}", "Mode": "Mode", - "MonoTlsCheckMessage": "Radarr Mono 4.x tls lausn enn virk, íhugaðu að fjarlægja MONO_TLS_PROVIDER = arfur umhverfis valkostur", - "MonoVersion": "Mónóútgáfa", - "MonoVersionCheckUpgradeRecommendedMessage": "Núverandi uppsett Mono útgáfa {0} er studd en mælt er með uppfærslu í {1}.", "MoreInfo": "Meiri upplýsingar", - "MovieDetailsNextMovie": "Upplýsingar um kvikmynd: Næsta kvikmynd", - "MovieDetailsPreviousMovie": "Upplýsingar um kvikmynd: Fyrri kvikmynd", "MovieIndexScrollTop": "Kvikmyndavísitala: Scroll Top", - "Movies": "Kvikmyndir", "Name": "Nafn", "NoLinks": "Engir krækjur", "Port": "Höfn", @@ -331,7 +291,6 @@ "RestartRequiredHelpTextWarning": "Krefst endurræsingar til að taka gildi", "Restore": "Endurheimta", "RestoreBackup": "Endurheimtu öryggisafrit", - "Restrictions": "Takmarkanir", "Retention": "Varðveisla", "RSS": "RSS", "RSSIsNotSupportedWithThisIndexer": "RSS er ekki studd með þessum flokkara", @@ -357,5 +316,12 @@ "StartupDirectory": "Ræsiskrá", "Status": "Staða", "Style": "Stíll", - "System": "Kerfi" + "System": "Kerfi", + "MaintenanceRelease": "Útgáfa viðhalds: villuleiðréttingar og aðrar úrbætur. Sjá Github skuldbindingarferil fyrir frekari upplýsingar", + "Filters": "Sía", + "HistoryCleanupDaysHelpText": "Stilltu á 0 til að gera sjálfvirka hreinsun óvirka", + "HistoryCleanupDaysHelpTextWarning": "Skrár í ruslakörfunni eldri en valinn fjöldi daga verða hreinsaðir upp sjálfkrafa", + "OnGrab": "Á grípa", + "OnHealthIssue": "Um heilbrigðismál", + "TestAllIndexers": "Prófaðu alla verðtryggjendur" } diff --git a/src/NzbDrone.Core/Localization/Core/it.json b/src/NzbDrone.Core/Localization/Core/it.json index b01b3d9f0..83eefad49 100644 --- a/src/NzbDrone.Core/Localization/Core/it.json +++ b/src/NzbDrone.Core/Localization/Core/it.json @@ -6,9 +6,7 @@ "SetTags": "Imposta Tag", "SelectAll": "Seleziona Tutto", "Scheduled": "In Programma", - "ReleaseBranchCheckPreviousVersionMessage": "Il Branch {0} corrisponde ad una versione precedente di Prowlarr, imposta il branch su \"Nightly\" per ricevere gli aggiornamenti futuri", "ReleaseBranchCheckOfficialBranchMessage": "Il Branch {0} non è un branch valido per le release di Prowlarr, non riceverai aggiornamenti", - "QualityDefinitions": "Definizioni delle Qualità", "PtpOldSettingsCheckMessage": "Il seguente indexer PassThePopcorn ha delle impostazioni obsolete e deve essere aggiornato: {0}", "ProxyCheckResolveIpMessage": "Impossibile risolvere l'indirizzo IP per il Proxy {0}", "NoChanges": "Nessuna Modifica", @@ -40,7 +38,6 @@ "Security": "Sicurezza", "Search": "Cerca", "SaveChanges": "Salva Modifiche", - "Restrictions": "Restrizioni", "RestoreBackup": "Ripristina Backup", "ReleaseStatus": "Stato Release", "Refresh": "Aggiorna", @@ -50,13 +47,9 @@ "Proxy": "Proxy", "Protocol": "Protocollo", "Options": "Opzioni", - "Movies": "Film", "MoreInfo": "Maggiori Info", - "MonoTlsCheckMessage": "Il workaround per Prowlarr Mono 4.x tls è ancora disabilitato, potresti considerare di rimuovere l'opzione ambiente MONO_TLS_PROVIDER=legacy", - "MonoNotNetCoreCheckMessage": "Per favore aggiorna alla versione .NET Core di Prowlarr", "Logging": "Logging", "LogFiles": "File di Log", - "Languages": "Lingue", "Language": "Lingua", "IndexerStatusCheckSingleClientMessage": "Indexer non disponibili a causa di errori: {0}", "IndexerStatusCheckAllClientMessage": "Tutti gli indexer non sono disponibili a causa di errori", @@ -77,8 +70,6 @@ "DownloadClientStatusCheckAllClientMessage": "Tutti i client per il download non sono disponibili a causa di errori", "DownloadClientsSettingsSummary": "Configurazione client di download per integrazione nella ricerca di Prowlarr", "DownloadClients": "Client Download", - "DownloadClientCheckUnableToCommunicateMessage": "Impossibile comunicare con {0}.", - "DownloadClientCheckNoneAvailableMessage": "Non è disponibile nessun client per il download", "DownloadClient": "Client Download", "Details": "Dettagli", "Delete": "Cancella", @@ -95,7 +86,6 @@ "Age": "Età", "Close": "Chiudi", "CloneProfile": "Clona il Profilo", - "CloneIndexer": "Clona Indexer", "ClientPriority": "Priorità del Client", "ChangeHasNotBeenSavedYet": "Il cambiamento non è stato ancora salvato", "CertificateValidationHelpText": "Cambiare il \"grado di severità\" della convalida del certificato HTTPS", @@ -138,23 +128,19 @@ "Ok": "Ok", "OAuthPopupMessage": "I Pop-ups sono bloccati dal tuo browser", "Name": "Nome", - "MonoVersionCheckUpgradeRecommendedMessage": "La versione di Mono {0} attualmente installata è supportata ma è raccomandato l'aggiornamento alla versione {1}.", "Message": "Messaggio", "Level": "Livello", "KeyboardShortcuts": "Scorciatoie Tastiera", "Info": "Info", "HealthNoIssues": "La tua configurazione non presenta problemi", "Error": "Errore", - "EnableAutoHelpText": "Se abilitato, i film saranno aggiunti automaticamente a Prowlarr da questa lista", "Enable": "Abilita", "DownloadClientSettings": "Impostazioni del client di download", "Docker": "Docker", "DeleteTag": "Cancella Tag", "DeleteNotification": "Cancellare la notifica", - "DeleteIndexer": "Cancella Indexer", "DeleteDownloadClient": "Cancellare il client di download", "DeleteBackup": "Cancellare il backup", - "DelayProfile": "Profili di Ritardo", "DBMigration": "Migrazione del DataBase", "ConnectSettings": "Impostazioni di connessione", "ConnectionLostMessage": "Prowlarr ha perso la connessione al backend e dovrà essere ricaricato per ripristinare la funzionalità.", @@ -178,7 +164,6 @@ "MIA": "MIA", "IndexerFlags": "Etichetta indexer", "EnableSSL": "Abilita SSL", - "EnableColorImpairedModeHelpText": "Stile alterato per permettere agli utenti daltonici di distinguere meglio le informazioni con colori codificati", "SettingsLongDateFormat": "Formato Data Lungo", "SettingsEnableColorImpairedMode": "Abilità la modalità colori alternati", "SendAnonymousUsageData": "Invia dati sull'uso anonimamente", @@ -199,38 +184,27 @@ "ReadTheWikiForMoreInformation": "Leggi le Wiki per maggiori informazioni", "ProwlarrSupportsAnyIndexer": "Prowlarr supporta qualunque indexer che usi gli standard Newznab, cosi come gli altri Indexer sotto.", "ProwlarrSupportsAnyDownloadClient": "Prowlarr supporta qualunque client di download che usi gli standard Newznab, cosi come gli altri client sotto.", - "QualitySettings": "Impostazione di Qualità", "ProxyUsernameHelpText": "Devi inserire nome utente e password solo se richiesto. Altrimenti lascia vuoto.", "ProxyType": "Tipo di proxy", "ProxyPasswordHelpText": "Devi inserire nome utente e password solo se richiesto. Altrimenti lascia vuoto.", "ProxyBypassFilterHelpText": "Usa ',' come separatore, e '*.' come jolly per i sottodomini", "PriorityHelpText": "Dai priorità ai client di download multipli. Round-Robin è usato per i client con la stessa priorità.", - "PreferredSize": "Dimensione preferita", "PortNumber": "Numero di porta", "Port": "Porta", "PendingChangesStayReview": "Rimani e rivedi modifiche", "PendingChangesMessage": "Hai cambiamenti non salvati, sicuro di voler abbandonare la pagina?", "PendingChangesDiscardChanges": "Abbandona le modifiche ed esci", - "Pending": "In sospeso", "PageSizeHelpText": "Numero di voci da mostrare in ogni pagina", "PackageVersion": "Versione del pacchetto", "OpenBrowserOnStart": "Apri il browser all'avvio", "NoUpdatesAreAvailable": "Nessun aggiornamento disponibile", "NoTagsHaveBeenAddedYet": "Nessun tag è ancora stato aggiunto", - "NoMinimumForAnyRuntime": "Nessuna durata minima", "NoLogFiles": "Nessun file di log", - "NoLimitForAnyRuntime": "Nessun limite di durata", "NoLeaveIt": "No, lascialo", "NoBackupsAreAvailable": "Nessun Backup disponibile", "New": "Nuovo", - "MonoVersion": "Versione Mono", "Mode": "Modo", - "MinutesSixty": "60 Minuti: {0}", - "MinutesNinety": "90 Minuti: {0}", - "MinutesHundredTwenty": "120 Minuti: {0}", - "MinimumLimits": "Limiti minimi", "Mechanism": "Meccanismo", - "MaximumLimits": "Limiti massimi", "Manual": "Manuale", "MaintenanceRelease": "Release di Manutenzione", "LogLevelTraceHelpTextWarning": "Il Trace Log dovrebbe essere abilitato solo temporaneamente", @@ -238,36 +212,23 @@ "LaunchBrowserHelpText": " Apri un browser e vai all'homepage di Prowlarr all'avvio dell'app.", "Interval": "Intervallo", "IncludeHealthWarningsHelpText": "Includi gli avvisi di salute", - "Importing": "Importazione", "IllRestartLater": "Riavvierò più tardi", "IgnoredAddresses": "Indirizzi ignorati", "HiddenClickToShow": "Nascosto, premi per mostrare", "GeneralSettings": "Impostazioni Generali", "ForMoreInformationOnTheIndividualDownloadClients": "Per maggiori informazioni sui singoli client di download clicca sul pulsante info.", "Fixed": "Fissato", - "ExistingMovies": "Film esistente(i)", - "EnableInteractiveSearchHelpTextWarning": "La ricerca non è supportata dal questo indexer", "FilterPlaceHolder": "Cerca Films", "ExistingTag": "Tag esistente", "Exception": "Eccezione", "ErrorLoadingContents": "Errore nel caricare i contenuti", "EnableSslHelpText": " Richiede il riavvio come amministratore per avere effetto", - "EnableMediaInfoHelpText": "Estrai le informazioni video tipo risoluzione, durata, codec dai file. Questo richiede che Prowlarr legga delle parti di file, ciò potrebbe causare un alto utilizzo del disco e della rete durante le scansioni.", "EnableInteractiveSearchHelpText": "Verrà usato quando la ricerca interattiva sarà utilizzata", "EnableInteractiveSearch": "Abilita la ricerca interattiva", - "EnableHelpText": "Abilita la creazione del file di metadati per questo tipo di metadati", - "EnabledHelpText": "Abilita questa lista per essere usata in Prowlarr", - "EnableCompletedDownloadHandlingHelpText": "Importa automaticamente i download completati dai client di download", - "EnableColorImpairedMode": "Abilità la modalità a colori alternati", - "EnableAutomaticSearchHelpTextWarning": "Sarà usata quando la ricerca interattiva è utilizzata", "EnableAutomaticSearchHelpText": "Sarà usata quando la ricerca automatica è eseguita dalla UI o da Prowlarr", "EnableAutomaticSearch": "Attiva la ricerca automatica", - "EnableAutomaticAdd": "Attiva l'aggiunta automatica", - "Downloading": "Scaricando", - "DownloadClientUnavailable": "Il client di download non è disponibile", "DeleteTagMessageText": "Sei sicuro di voler eliminare il tag '{0}'?", "DeleteNotificationMessageText": "Sei sicuro di voler eliminare la notifica '{0}'?", - "DeleteIndexerMessageText": "Sei sicuro di voler eliminare l'indexer '{0}'?", "DeleteDownloadClientMessageText": "Sei sicuro di voler eliminare il client di download '{0}'?", "BeforeUpdate": "Prima di aggiornare", "ApplyTagsHelpTexts4": "Sostituire: sostituisci le tag con le tag inserite (non inserire nessuna tag per pulirle tutte)", @@ -286,9 +247,7 @@ "UnsavedChanges": "Modifiche non salvate", "UnableToLoadUISettings": "Non riesco a caricare le impostazioni della UI", "UnableToLoadTags": "Non riesco a caricare i tag", - "UnableToLoadQualityDefinitions": "Non riesco a caricare le definizioni della qualità", "UnableToLoadNotifications": "Non riesco a caricare le notifiche", - "UnableToLoadIndexers": "Non riesco a caricare l'indexer", "UnableToLoadHistory": "Non riesco a caricare la storia", "UnableToLoadGeneralSettings": "Non riesco a caricare le impostazioni generali", "UnableToLoadDownloadClients": "Non riesco a caricare i client di download", @@ -333,8 +292,6 @@ "OpenThisModal": "Apri questa modalità", "MovieIndexScrollTop": "Elenco film: scorri in alto", "MovieIndexScrollBottom": "Elenco film: scorri in basso", - "MovieDetailsNextMovie": "Dettagli del film: film successivo", - "MovieDetailsPreviousMovie": "Dettagli del film: film precedente", "FocusSearchBox": "Attiva casella di ricerca", "CloseCurrentModal": "Chiudi la modalità corrente", "AcceptConfirmationModal": "Accetta modalità di conferma", @@ -382,5 +339,15 @@ "Reddit": "Reddit", "Torrent": "Torrent", "UnableToAddANewApplicationPleaseTryAgain": "Non riesco ad aggiungere una nuova notifica, riprova.", - "UnableToAddANewAppProfilePleaseTryAgain": "Non riesco ad aggiungere un nuovo profilo di qualità, riprova." + "UnableToAddANewAppProfilePleaseTryAgain": "Non riesco ad aggiungere un nuovo profilo di qualità, riprova.", + "NotificationTriggersHelpText": "Selezionare quali eventi attiveranno questa notifica", + "HistoryCleanupDaysHelpTextWarning": "I file nel cestino più vecchi del numero selezionato di giorni saranno eliminati automaticamente", + "OnApplicationUpdate": "All'aggiornamento dell'applicazione", + "Filters": "Filtro", + "HistoryCleanupDaysHelpText": "Imposta a 0 per disabilitare la pulizia automatica", + "OnApplicationUpdateHelpText": "All'aggiornamento dell'applicazione", + "OnGrab": "Quando viene prelevato", + "OnHealthIssue": "Quando c'è un problema", + "TestAllIndexers": "Testa tutti gli indexer", + "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent esposto dalla app che ha chiamato la API" } diff --git a/src/NzbDrone.Core/Localization/Core/ja.json b/src/NzbDrone.Core/Localization/Core/ja.json index 7815f7528..ae21ed5e2 100644 --- a/src/NzbDrone.Core/Localization/Core/ja.json +++ b/src/NzbDrone.Core/Localization/Core/ja.json @@ -1,5 +1,4 @@ { - "MovieDetailsNextMovie": "映画の詳細:次の映画", "OpenThisModal": "このモーダルを開く", "InteractiveSearch": "インタラクティブ検索", "Interval": "間隔", @@ -9,15 +8,12 @@ "CloneProfile": "クローンプロファイル", "Close": "閉じる", "EditIndexer": "インデクサーの編集", - "ExistingMovies": "既存の映画", "ExistingTag": "既存のタグ", "Failed": "失敗しました", "Indexer": "インデクサー", "IndexerFlags": "インデクサフラグ", - "MovieDetailsPreviousMovie": "映画の詳細:前の映画", "NoChanges": "変更なし", "NoLeaveIt": "いいえ、そのままにしておきます", - "NoLimitForAnyRuntime": "ランタイムに制限はありません", "NoUpdatesAreAvailable": "利用可能なアップデートはありません", "OAuthPopupMessage": "ポップアップがブラウザによってブロックされています", "Ok": "OK", @@ -60,13 +56,9 @@ "Edit": "編集", "DownloadClientSettings": "クライアント設定のダウンロード", "DownloadClientStatusCheckAllClientMessage": "障害のため、すべてのダウンロードクライアントを利用できません", - "EnableAutoHelpText": "有効にすると、映画はこのリストからRadarrに自動的に追加されます", - "EnableAutomaticAdd": "自動追加を有効にする", "EnableAutomaticSearch": "自動検索を有効にする", "EnableAutomaticSearchHelpText": "UIまたはRadarによって自動検索が実行されるときに使用されます", - "EnableCompletedDownloadHandlingHelpText": "完了したダウンロードをダウンロードクライアントから自動的にインポートします", "Enabled": "有効", - "EnableInteractiveSearchHelpTextWarning": "このインデクサーでは検索はサポートされていません", "EnableSslHelpText": " 有効にするには、管理者として実行を再開する必要があります", "FeatureRequests": "機能リクエスト", "Filename": "ファイル名", @@ -76,22 +68,15 @@ "IndexerProxyStatusCheckAllClientMessage": "障害のため、すべてのインデクサーを使用できません", "IndexerProxyStatusCheckSingleClientMessage": "失敗のため利用できないリスト:{0}", "Indexers": "インデクサー", - "Languages": "言語", "LastWriteTime": "最終書き込み時間", "Level": "レベル", "LogFiles": "ログファイル", "Logging": "ロギング", "Logs": "ログ", "Manual": "マニュアル", - "MaximumLimits": "最大制限", "Message": "メッセージ", "MIA": "MIA", - "MinimumLimits": "最小制限", - "MinutesHundredTwenty": "120分:{0}", - "Pending": "保留中", "PtpOldSettingsCheckMessage": "次のPassThePopcornインデクサーは非推奨の設定であり、更新する必要があります:{0}", - "QualityDefinitions": "品質の定義", - "QualitySettings": "品質設定", "Refresh": "更新", "ReleaseStatus": "リリースステータス", "Reload": "リロード", @@ -122,7 +107,6 @@ "TestAll": "すべてテスト", "UnableToLoadDownloadClients": "ダウンロードクライアントを読み込めません", "UnableToLoadGeneralSettings": "一般設定を読み込めません", - "UnableToLoadIndexers": "インデクサーを読み込めません", "UpdateAutomaticallyHelpText": "アップデートを自動的にダウンロードしてインストールします。 System:Updatesから引き続きインストールできます。", "Updates": "更新", "Uptime": "稼働時間", @@ -132,15 +116,11 @@ "DownloadClient": "クライアントのダウンロード", "DownloadClientStatusCheckSingleClientMessage": "失敗のためにダウンロードできないクライアント:{0}", "Restore": "戻す", - "DeleteIndexer": "インデクサーを削除する", "EnableRss": "RSSを有効にする", "EnableInteractiveSearch": "インタラクティブ検索を有効にする", "OpenBrowserOnStart": "起動時にブラウザを開く", - "MinutesSixty": "60分:{0}", "Mode": "モード", - "MonoVersion": "モノバージョン", "MoreInfo": "より詳しい情報", - "Downloading": "ダウンロード", "Usenet": "Usenet", "ApplyTagsHelpTexts2": "追加:既存のタグリストにタグを追加します", "Authentication": "認証", @@ -152,7 +132,6 @@ "ChangeHasNotBeenSavedYet": "変更はまだ保存されていません", "Clear": "晴れ", "ClientPriority": "クライアントの優先順位", - "CloneIndexer": "クローンインデクサー", "CloseCurrentModal": "現在のモーダルを閉じる", "Columns": "列", "Component": "成分", @@ -170,7 +149,6 @@ "CouldNotConnectSignalR": "SignalRに接続できませんでした。UIは更新されません", "Custom": "カスタム", "DBMigration": "DB移行", - "DelayProfile": "遅延プロファイル", "Delete": "削除", "DeleteApplicationMessageText": "通知「{0}」を削除してもよろしいですか?", "DeleteBackup": "バックアップを削除する", @@ -179,21 +157,14 @@ "DeleteDownloadClientMessageText": "ダウンロードクライアント「{0}」を削除してもよろしいですか?", "Docker": "Docker", "Donations": "寄付", - "DownloadClientCheckNoneAvailableMessage": "ダウンロードクライアントは利用できません", - "DownloadClientCheckUnableToCommunicateMessage": "{0}と通信できません。", "DownloadClients": "クライアントのダウンロード", - "DownloadClientUnavailable": "ダウンロードクライアントは利用できません", "Enable": "有効にする", - "EnableAutomaticSearchHelpTextWarning": "インタラクティブ検索を使用する場合に使用されます", - "EnableColorImpairedMode": "色障害モードを有効にする", "Backup": "バックアップ", "UpdateScriptPathHelpText": "抽出された更新パッケージを取得し、更新プロセスの残りを処理するカスタムスクリプトへのパス", "LogLevelTraceHelpTextWarning": "トレースログは一時的にのみ有効にする必要があります", "Mechanism": "機構", - "MinutesNinety": "90分:{0}", "MovieIndexScrollBottom": "映画インデックス:下にスクロール", "MovieIndexScrollTop": "映画インデックス:スクロールトップ", - "Movies": "映画", "Name": "名前", "New": "新着", "NoLinks": "リンクなし", @@ -203,7 +174,6 @@ "PendingChangesStayReview": "滞在して変更を確認する", "Port": "港", "PortNumber": "ポート番号", - "PreferredSize": "推奨サイズ", "Presets": "プリセット", "PriorityHelpText": "複数のダウンロードクライアントに優先順位を付けます。ラウンドロビンは、同じ優先度のクライアントに使用されます。", "PrioritySettings": "優先", @@ -219,7 +189,6 @@ "ReleaseBranchCheckOfficialBranchMessage": "ブランチ{0}は有効なRadarrリリースブランチではありません。更新を受け取りません。", "ResetAPIKey": "APIキーをリセット", "RestartNow": "今すぐ再起動", - "Restrictions": "制限", "Result": "結果", "Retention": "保持", "RSS": "RSS", @@ -249,7 +218,6 @@ "UnableToAddANewNotificationPleaseTryAgain": "新しい通知を追加できません。もう一度やり直してください。", "UnableToLoadBackups": "バックアップを読み込めません", "UnableToLoadHistory": "履歴を読み込めません", - "UnableToLoadQualityDefinitions": "品質定義を読み込めません", "UnableToLoadTags": "タグを読み込めません", "UnableToLoadUISettings": "UI設定を読み込めません", "UnsavedChanges": "保存されていない変更", @@ -292,11 +260,7 @@ "Health": "健康", "HealthNoIssues": "構成に問題はありません", "HideAdvanced": "高度な非表示", - "EnabledHelpText": "Radarrで使用するためにこのリストを有効にします", - "EnableHelpText": "このメタデータタイプのメタデータファイルの作成を有効にする", "EnableInteractiveSearchHelpText": "インタラクティブ検索を使用する場合に使用されます", - "MonoVersionCheckUpgradeRecommendedMessage": "現在インストールされているMonoバージョン{0}がサポートされていますが、{1}にアップグレードすることをお勧めします。", - "EnableMediaInfoHelpText": "ファイルから解像度、ランタイム、コーデック情報などのビデオ情報を抽出します。これには、Radarrがファイルの一部を読み取る必要があり、スキャン中にディスクまたはネットワークのアクティビティが高くなる可能性があります。", "Error": "エラー", "ErrorLoadingContents": "コンテンツの読み込み中にエラーが発生しました", "Events": "イベント", @@ -324,7 +288,6 @@ "BypassProxyForLocalAddresses": "ローカルアドレスのプロキシをバイパスする", "Cancel": "キャンセル", "CancelPendingTask": "この保留中のタスクをキャンセルしてもよろしいですか?", - "DeleteIndexerMessageText": "インデクサー「{0}」を削除してもよろしいですか?", "DeleteNotification": "通知を削除", "DeleteNotificationMessageText": "通知「{0}」を削除してもよろしいですか?", "DeleteTag": "タグを削除", @@ -334,8 +297,6 @@ "Discord": "不和", "IndexerPriority": "インデクサの優先順位", "IndexerPriorityHelpText": "インデクサーの優先度は1(最高)から50(最低)です。デフォルト:25。", - "MonoTlsCheckMessage": "Radarr Mono 4.x tlsの回避策は引き続き有効です。MONO_TLS_PROVIDER=レガシー環境オプションを削除することを検討してください", - "EnableColorImpairedModeHelpText": "色が損なわれたユーザーが色分けされた情報をよりよく区別できるようにスタイルを変更", "EnableSSL": "SSLを有効にする", "FocusSearchBox": "フォーカス検索ボックス", "Folder": "フォルダ", @@ -348,14 +309,19 @@ "Host": "ホスト", "Hostname": "ホスト名", "IllRestartLater": "後で再起動します", - "Importing": "インポート", "IndexerLongTermStatusCheckSingleClientMessage": "6時間以上の障害のため、インデクサーを使用できません:{0}", "IndexerStatusCheckSingleClientMessage": "失敗のためインデクサーを利用できません:{0}", "Info": "情報", "NoLogFiles": "ログファイルがありません", - "NoMinimumForAnyRuntime": "ランタイムの最小値はありません", "NoTagsHaveBeenAddedYet": "タグはまだ追加されていません", "ProxyUsernameHelpText": "ユーザー名とパスワードが必要な場合にのみ入力する必要があります。それ以外の場合は空白のままにします。", "ReadTheWikiForMoreInformation": "詳細については、Wikiをお読みください", - "SettingsEnableColorImpairedModeHelpText": "色が損なわれたユーザーが色分けされた情報をよりよく区別できるようにスタイルを変更" + "SettingsEnableColorImpairedModeHelpText": "色が損なわれたユーザーが色分けされた情報をよりよく区別できるようにスタイルを変更", + "HistoryCleanupDaysHelpTextWarning": "選択した日数より古いごみ箱内のファイルは自動的にクリーンアップされます", + "OnHealthIssue": "健康問題について", + "Filters": "フィルタ", + "HistoryCleanupDaysHelpText": "自動クリーンアップを無効にするには、0に設定します", + "OnGrab": "グラブで", + "TestAllIndexers": "すべてのインデクサーをテストする", + "MaintenanceRelease": "メンテナンスリリース:バグ修正およびその他の改善。詳細については、Githubのコミット履歴を参照してください" } diff --git a/src/NzbDrone.Core/Localization/Core/ko.json b/src/NzbDrone.Core/Localization/Core/ko.json index 295fd9497..c02ca4982 100644 --- a/src/NzbDrone.Core/Localization/Core/ko.json +++ b/src/NzbDrone.Core/Localization/Core/ko.json @@ -1,7 +1,5 @@ { "ChangeHasNotBeenSavedYet": "변경 사항이 아직 저장되지 않았습니다.", - "DownloadClientUnavailable": "다운로드 클라이언트를 사용할 수 없습니다.", - "Downloading": "다운로드 중", "ConnectionLost": "연결이 끊어졌습니다.", "Dates": "날짜", "DeleteBackup": "백업 삭제", @@ -20,7 +18,6 @@ "AddDownloadClient": "다운로드 클라이언트 추가", "DeleteTag": "태그 삭제", "ConnectSettings": "연결 설정", - "CloneIndexer": "인덱서 복제", "CloneProfile": "프로필 복제", "Close": "닫기", "CloseCurrentModal": "현재 모달 닫기", @@ -30,7 +27,6 @@ "CouldNotConnectSignalR": "SignalR에 연결할 수 없습니다. UI가 업데이트되지 않습니다.", "Custom": "사용자 지정", "DBMigration": "DB 마이그레이션", - "DelayProfile": "지연 프로필", "DeleteBackupMessageText": "백업 '{0}'을(를) 삭제하시겠습니까?", "BackupNow": "지금 백업", "Authentication": "인증", @@ -50,15 +46,12 @@ "CancelPendingTask": "이 보류 중인 작업을 취소하시겠습니까?", "Delete": "삭제", "DeleteDownloadClient": "다운로드 클라이언트 삭제", - "DeleteIndexer": "인덱서 삭제", - "DeleteIndexerMessageText": "인덱서 '{0}'을(를) 삭제하시겠습니까?", "DeleteTagMessageText": "'{0}' 태그를 삭제하시겠습니까?", "Details": "세부 정보", "Disabled": "비활성화됨", "Docker": "Docker", "Donations": "기부", "DownloadClient": "클라이언트 다운로드", - "DownloadClientCheckNoneAvailableMessage": "사용 가능한 다운로드 클라이언트가 없습니다.", "DownloadClientSettings": "클라이언트 설정 다운로드", "DownloadClientStatusCheckAllClientMessage": "실패로 인해 모든 다운로드 클라이언트를 사용할 수 없습니다.", "Add": "추가", @@ -76,17 +69,13 @@ "DeleteDownloadClientMessageText": "다운로드 클라이언트 '{0}'을(를) 삭제하시겠습니까?", "DeleteNotification": "알림 삭제", "DeleteNotificationMessageText": "알림 '{0}'을(를) 삭제하시겠습니까?", - "DownloadClientCheckUnableToCommunicateMessage": "{0}와(과) 통신할 수 없습니다.", "DownloadClientStatusCheckSingleClientMessage": "실패로 인해 다운 불러올 수 없는 클라이언트 : {0}", "MoreInfo": "더 많은 정보", "Edit": "편집하다", "Indexer": "인덱서", - "MinutesSixty": "60 분 : {0}", - "MinutesNinety": "60 분 : {0}", "Name": "이름", "New": "새로운", "ProxyUsernameHelpText": "필요한 경우 사용자 이름과 암호 만 입력하면됩니다. 그렇지 않으면 공백으로 두십시오.", - "QualityDefinitions": "품질 정의", "RestartRequiredHelpTextWarning": "적용하려면 다시 시작해야합니다.", "SaveChanges": "변경 사항을 저장하다", "Settings": "설정", @@ -121,13 +110,11 @@ "ReadTheWikiForMoreInformation": "자세한 내용은 Wiki를 참조하십시오.", "Tomorrow": "내일", "UI": "UI", - "UnableToLoadIndexers": "인덱서를로드 할 수 없습니다.", "Updates": "업데이트", "Uptime": "가동 시간", "YesCancel": "예, 취소합니다", "Folder": "폴더", "ConnectionLostMessage": "Radarr는 백엔드와의 연결이 끊어졌으며 기능을 복원하려면 다시 로딩해야 합니다.", - "EnableAutomaticAdd": "자동 추가 활성화", "EnableAutomaticSearch": "자동 검색 활성화", "EnableAutomaticSearchHelpText": "UI 또는 Radarr를 통해 자동 검색을 수행 할 때 사용됩니다.", "ErrorLoadingContents": "콘텐츠로드 오류", @@ -143,10 +130,7 @@ "Branch": "분기", "BranchUpdate": "Radarr 업데이트에 사용할 분기", "DeleteIndexerProxyMessageText": "'{0}' 태그를 삭제하시겠습니까?", - "EnableCompletedDownloadHandlingHelpText": "다운로드 클라이언트에서 완료된 다운로드를 자동으로 가져 오기", - "EnableHelpText": "이 메타 데이터 유형에 대한 메타 데이터 파일 생성 활성화", "EnableInteractiveSearch": "대화 형 검색 활성화", - "EnableInteractiveSearchHelpTextWarning": "이 인덱서에서는 검색이 지원되지 않습니다.", "EnableSSL": "SSL 활성화", "EnableSslHelpText": " 적용하려면 관리자로 실행을 다시 시작해야합니다.", "History": "역사", @@ -154,12 +138,9 @@ "Refresh": "새롭게 하다", "Mode": "방법", "TagCannotBeDeletedWhileInUse": "사용 중에는 삭제할 수 없습니다.", - "NoLimitForAnyRuntime": "런타임 제한 없음", - "NoMinimumForAnyRuntime": "런타임에 대한 최소값 없음", "NoUpdatesAreAvailable": "사용 가능한 업데이트가 없습니다.", "OnHealthIssueHelpText": "건강 문제", "OpenBrowserOnStart": "시작시 브라우저 열기", - "QualitySettings": "품질 설정", "Reload": "새로 고침", "RemovedFromTaskQueue": "작업 대기열에서 제거됨", "ResetAPIKey": "API 키 재설정", @@ -188,20 +169,17 @@ "UILanguageHelpTextWarning": "브라우저 새로 고침 필요", "UnableToLoadDownloadClients": "다운로드 클라이언트를로드 할 수 없습니다.", "UnableToLoadHistory": "기록을로드 할 수 없습니다.", - "UnableToLoadQualityDefinitions": "품질 정의를로드 할 수 없습니다.", "UnableToLoadTags": "태그를로드 할 수 없습니다.", "UnableToLoadUISettings": "UI 설정을로드 할 수 없습니다.", "ConnectionLostAutomaticMessage": "Radarr가 자동으로 연결을 시도하거나 아래에서 새로고침을 클릭할 수 있습니다.", "RemovingTag": "태그 제거", "IndexerPriority": "인덱서 우선 순위", "Language": "언어", - "Languages": "언어", "LaunchBrowserHelpText": " 웹 브라우저를 열고 앱 시작시 Radarr 홈페이지로 이동합니다.", "SSLPort": "SSL 포트", "StartupDirectory": "시작 디렉토리", "LogFiles": "로그 파일", "Logging": "벌채 반출", - "MonoVersion": "모노 버전", "NoLogFiles": "로그 파일 없음", "NotificationTriggers": "알림 트리거", "PackageVersion": "패키지 버전", @@ -223,23 +201,16 @@ "UseProxy": "프록시 사용", "Username": "사용자 이름", "Version": "버전", - "EnableAutomaticSearchHelpTextWarning": "대화 형 검색을 사용할 때 사용됩니다.", - "EnableColorImpairedMode": "색 장애 모드 활성화", - "EnableColorImpairedModeHelpText": "색상 장애가있는 사용자가 색상 코드 정보를 더 잘 구별 할 수 있도록 스타일 변경", "Exception": "예외", "ExistingTag": "기존 태그", "Files": "파일", "IgnoredAddresses": "무시 된 주소", "IllRestartLater": "나중에 다시 시작하겠습니다", - "Importing": "가져 오기", "IncludeHealthWarningsHelpText": "건강 경고 포함", "LogLevel": "로그 수준", "LogLevelTraceHelpTextWarning": "추적 로깅은 일시적으로 만 활성화해야합니다.", - "MaximumLimits": "최대 한도", "Mechanism": "기구", "MIA": "MIA", - "MinimumLimits": "최소 한도", - "MinutesHundredTwenty": "120 분 : {0}", "PageSize": "페이지 크기", "Password": "암호", "TestAll": "모두 테스트", @@ -264,5 +235,10 @@ "ShownClickToHide": "표시됨, 숨기려면 클릭", "ShowSearch": "검색 표시", "UILanguage": "UI 언어", - "UILanguageHelpText": "Radarr가 UI에 사용할 언어" + "UILanguageHelpText": "Radarr가 UI에 사용할 언어", + "HistoryCleanupDaysHelpText": "자동 정리를 사용하지 않으려면 0으로 설정하십시오.", + "HistoryCleanupDaysHelpTextWarning": "선택한 일 수보다 오래된 휴지통에있는 파일은 자동으로 정리됩니다.", + "OnGrab": "잡기", + "OnHealthIssue": "건강 문제", + "TestAllIndexers": "모든 인덱서 테스트" } diff --git a/src/NzbDrone.Core/Localization/Core/nb_NO.json b/src/NzbDrone.Core/Localization/Core/nb_NO.json index 5f720b635..97a9e9d95 100644 --- a/src/NzbDrone.Core/Localization/Core/nb_NO.json +++ b/src/NzbDrone.Core/Localization/Core/nb_NO.json @@ -50,7 +50,6 @@ "BranchUpdate": "Gren som skal brukes til å oppdatere Radarr", "DeleteApplicationMessageText": "Er du sikker på at du vil slette formattaggen {0}?", "DeleteDownloadClientMessageText": "Er du sikker på at du vil slette formattaggen {0}?", - "DeleteIndexerMessageText": "Er du sikker på at du vil slette formattaggen {0}?", "DeleteIndexerProxyMessageText": "Er du sikker på at du vil slette formattaggen {0}?", "DeleteNotificationMessageText": "Er du sikker på at du vil slette formattaggen {0}?", "DeleteTagMessageText": "Er du sikker på at du vil slette formattaggen {0}?" diff --git a/src/NzbDrone.Core/Localization/Core/nl.json b/src/NzbDrone.Core/Localization/Core/nl.json index 732c90d33..33f00afe8 100644 --- a/src/NzbDrone.Core/Localization/Core/nl.json +++ b/src/NzbDrone.Core/Localization/Core/nl.json @@ -13,8 +13,6 @@ "DownloadClientStatusCheckSingleClientMessage": "Downloaders onbeschikbaar wegens fouten: {0}", "DownloadClientStatusCheckAllClientMessage": "Alle downloaders zijn onbeschikbaar wegens fouten", "DownloadClients": "Downloaders", - "DownloadClientCheckUnableToCommunicateMessage": "Niet in staat om te communiceren met {0}.", - "DownloadClientCheckNoneAvailableMessage": "Er is geen downloader beschikbaar", "Delete": "Verwijderen", "Dates": "Datum en tijd", "Date": "Datum", @@ -25,7 +23,7 @@ "BackupNow": "Veiligheidskopie Maken", "Analytics": "Statistieken", "Backup": "Veiligheidskopie", - "AppDataLocationHealthCheckMessage": "Bijwerken zal niet mogelijk zijn om het verwijderen van AppData te voorkomen", + "AppDataLocationHealthCheckMessage": "Updaten zal niet mogelijk zijn om het verwijderen van AppData te voorkomen", "All": "Alles", "About": "Over", "View": "Weergave", @@ -41,27 +39,21 @@ "Search": "Zoeken", "Scheduled": "Gepland", "SaveChanges": "Wijzigingen Opslaan", - "Restrictions": "Restricties", "RestoreBackup": "Veiligheidskopie Herstellen", "Refresh": "Vernieuw", "Queue": "Wachtrij", - "QualityDefinitions": "Kwaliteitsdefinities", "Proxy": "Proxy", "Options": "Opties", "NoChanges": "Geen Wijzigingen", "NoChange": "Geen Wijziging", - "Movies": "Films", "MoreInfo": "Meer Info", - "MonoNotNetCoreCheckMessage": "Gelieve te opwaarderen naar de .NET Core versie van Prowlarr", "Logging": "Logbeheer", "LogFiles": "Logbestanden", - "Languages": "Talen", "Language": "Taal", "ShowAdvanced": "Toon Gevorderd", "UpdateCheckUINotWritableMessage": "Kan de update niet installeren omdat de UI map '{0}' niet schrijfbaar is voor de gebruiker '{1}'.", "UpdateCheckStartupTranslocationMessage": "Kan de update niet installeren omdat de map '{0}' zich in een 'App Translocation' map bevindt.", "UpdateCheckStartupNotWritableMessage": "Kan de update niet installeren omdat de map '{0}' niet schrijfbaar is voor de gebruiker '{1}'.", - "ReleaseBranchCheckPreviousVersionMessage": "Branch {0} is voor een oudere versie van Prowlarr, gebruik branch 'Aphrodite' om toekomstige updates te ontvangen", "PtpOldSettingsCheckMessage": "De volgende PassThePopcorn indexeerders hebben verouderde instellingen en moeten worden bijgewerkt: {0}", "IndexerStatusCheckSingleClientMessage": "Indexeerders onbeschikbaar wegens fouten: {0}", "IndexerStatusCheckAllClientMessage": "Alle indexeerders zijn onbeschikbaar wegens fouten", @@ -73,7 +65,6 @@ "ProxyCheckResolveIpMessage": "Achterhalen van het IP-adres voor de geconfigureerde proxy host {0} is mislukt", "ProxyCheckFailedToTestMessage": "Testen van proxy is mislukt: {0}", "ProxyCheckBadRequestMessage": "Testen van proxy is mislukt. Statuscode: {0}", - "MonoTlsCheckMessage": "Tijdelijke Prowlarr Mono 4.x TLS oplossing nog steeds ingeschakeld, overweeg de MONO_TLS_PROVIDER=legacy omgevingsvariabele te verwijderen", "UISettingsSummary": "Datum, kleurenblindheid en taal instellingen", "TagsSettingsSummary": "Bekijk alle tags en hun gebruik. Ongebruikte tags kunnen worden verwijderd", "Size": "Grootte", @@ -140,8 +131,6 @@ "PendingChangesStayReview": "Blijf en bekijk de wijzigingen", "PendingChangesMessage": "U heeft onopgeslagen wijzigingen, bent u zeker dat u deze pagina wilt sluiten?", "PendingChangesDiscardChanges": "Wijzigingen verwerpen en verdergaan", - "MonoVersionCheckUpgradeRecommendedMessage": "De huidige geïnstalleerde Mono versie {0} wordt ondersteund, maar het is aangeraden om te opwaarderen naar versie {1}.", - "ExistingMovies": "Bestaande Film(s)", "Interval": "Tussentijd", "Fixed": "Opgelost", "Automatic": "Automatisch", @@ -152,16 +141,13 @@ "YesCancel": "Ja, Annuleren", "DeleteTag": "Verwijder Tag", "DeleteNotification": "Verwijder Notificatie", - "DeleteIndexer": "Verwijder Indexeerder", "DeleteDownloadClient": "Verwijder Downloader", "Enable": "Activeer", "DownloadClientSettings": "Downloader Instellingen", "Docker": "Docker", - "DelayProfile": "Vertragingsprofiel", "DBMigration": "DB Migratie", "ConnectSettings": "Connecties Instellingen", "CloneProfile": "Dupliceer Profiel", - "CloneIndexer": "Dupliceer Indexeerder", "ClientPriority": "Client Prioriteit", "ChangeHasNotBeenSavedYet": "Wijziging is nog niet opgeslagen", "CertificateValidationHelpText": "Wijzig hoe strikt HTTPS certificaat validatie is", @@ -177,21 +163,13 @@ "AreYouSureYouWantToResetYourAPIKey": "Bent u zeker dat u uw API-sleutel wilt resetten?", "ApplyTags": "Tags Toepassen", "ApiKey": "API-sleutel", - "Importing": "Importeren", "IllRestartLater": "Ik zal later herstarten", "IgnoredAddresses": "Genegeerde Adressen", "Hostname": "Hostnaam", "GeneralSettings": "Algemene Instellingen", "EnableSSL": "Activeer SSL", "EnableInteractiveSearch": "Activeer Interactief Zoeken", - "EnableHelpText": "Schakel het maken van metadata bestanden in voor dit metadata type", - "EnabledHelpText": "Activeer deze lijst voor gebruik in Prowlarr", - "EnableCompletedDownloadHandlingHelpText": "Importeer automatisch voltooide downloads vanuit de downloader", - "EnableColorImpairedModeHelpText": "Aangepaste stijl voor gebruikers die kleurenblind zijn om gemakkelijker kleurgecodeerde informatie te onderscheiden", - "EnableColorImpairedMode": "Activeer Kleurenblindheid-modus", "EnableAutomaticSearch": "Activeer Automatisch Zoeken", - "EnableAutomaticAdd": "Activeer Automatisch Toevoegen", - "EnableAutoHelpText": "Indien ingeschakeld, zullen films automatisch aan Prowlarr worden toegevoegd van deze lijst", "PortNumber": "Poort Nummer", "Port": "Poort", "Password": "Wachtwoord", @@ -199,20 +177,15 @@ "OnHealthIssueHelpText": "Bij Gezondheidsprobleem", "NoLeaveIt": "Nee, Ongemoeid Laten", "New": "Nieuw", - "MonoVersion": "Mono Versie", "Mode": "Modus", - "MinimumLimits": "Minimum Limieten", "Mechanism": "Mechanisme", - "MaximumLimits": "Maximum Limiet", "Logs": "Logbestanden", "LogLevel": "Log Niveau", - "EnableMediaInfoHelpText": "Video informatie extraheren zoals resolutie, speelduur en codec informatie van bestanden. Dit maakt het noodzakelijk dat Prowlarr delen van een bestand moet inlezen dewelke hoge schijf- of netwerkactiviteit kan veroorzaken tijdens het scannen.", "BindAddress": "Aanhaak Adres", "IndexerFlags": "Indexeerder Flags", "EnableSslHelpText": " Vereist herstart als administrator om in werking te treden", "PriorityHelpText": "Geef prioriteit aan meerdere downloaders. Round-Robin wordt gebruikt voor downloaders met dezelfde prioriteit.", "SendAnonymousUsageData": "Zend Anonieme Gebruiksdata", - "UnableToLoadIndexers": "Indexeerders kunnen niet worden geladen", "UnableToLoadNotifications": "Notificaties kunnen niet worden geladen", "UpdateAutomaticallyHelpText": "Download en installeer updates automatisch. Je zal nog steeds kunnen installeren vanuit Systeem: Updates", "UrlBaseHelpText": "Voor reverse proxy ondersteuning, leeg is standaard", @@ -222,13 +195,9 @@ "NotificationTriggers": "Melding Reactiestarters", "OpenBrowserOnStart": "Open de browser bij het starten", "PageSizeHelpText": "Aantal items om te tonen op iedere pagina", - "NoLimitForAnyRuntime": "Geen limiet voor eender welke speelduur", - "NoMinimumForAnyRuntime": "Geen minimum voor een speelduur", "NetCore": ".NET", - "PreferredSize": "Gewenste Grootte", "ProxyPasswordHelpText": "Je moet alleen een gebruikersnaam en wachtwoord ingeven als dit vereist is, laat ze anders leeg.", "ProxyUsernameHelpText": "Je moet alleen een gebruikersnaam en wachtwoord ingeven als dit vereist is, laat ze anders leeg.", - "QualitySettings": "Kwaliteitsinstellingen", "ReadTheWikiForMoreInformation": "Lees de Wiki voor meer informatie", "RefreshMovie": "Film vernieuwen", "ProxyType": "Proxy Type", @@ -253,7 +222,6 @@ "Torrents": "Torrents", "UISettings": "Gebruikersinterface Instellingen", "UnableToLoadDownloadClients": "Downloaders kunnen niet worden geladen", - "UnableToLoadQualityDefinitions": "Kwaliteitsdefinities kunnen niet worden geladen", "UnableToLoadTags": "Tags kunnen niet worden geladen", "UpdateMechanismHelpText": "Gebruik het ingebouwde updatemechanisme of een extern script", "UpdateScriptPathHelpText": "Pad naar een aangepast script dat een uitgepakt updatepakket accepteert en de rest van het updateproces afhandelt", @@ -269,20 +237,14 @@ "ShownClickToHide": "Getoond, klik om te verbergen", "RSSIsNotSupportedWithThisIndexer": "RSS wordt niet ondersteund door deze indexeerder", "RemovingTag": "Tag verwijderen", - "Pending": "In afwachting", "Manual": "Manueel", "LogLevelTraceHelpTextWarning": "Trace log niveau moet enkel tijdelijk worden gebruikt", "HiddenClickToShow": "Verborgen, klik om te tonen", "ExistingTag": "Bestaande tag", - "EnableInteractiveSearchHelpTextWarning": "Zoeken wordt niet ondersteund door deze indexeerder", "EnableInteractiveSearchHelpText": "Zal worden gebruikt wanneer interactief zoeken wordt gebruikt", - "EnableAutomaticSearchHelpTextWarning": "Zal worden gebruikt wanneer interactief zoeken wordt gebruikt", "EnableAutomaticSearchHelpText": "Zal worden gebruikt wanneer automatische zoekopdrachten worden uitgevoerd via de gebruikersinterface of door Prowlarr", - "Downloading": "Downloaden", - "DownloadClientUnavailable": "Downloader is onbeschikbaar", "DeleteTagMessageText": "Bent u zeker dat u de tag '{0}' wilt verwijderen?", "DeleteNotificationMessageText": "Bent u zeker dat u de notificatie '{0}' wilt verwijderen?", - "DeleteIndexerMessageText": "Bent u zeker dat u de indexeerder '{0}' wilt verwijderen?", "DeleteDownloadClientMessageText": "Bent u zeker dat u de downloader '{0}' wilt verwijderen?", "DeleteBackupMessageText": "Bent u zeker dat u de veiligheidskopie '{0}' wilt verwijderen?", "CancelPendingTask": "Bent u zeker dat u deze taak in afwachting wilt annuleren?", @@ -311,9 +273,6 @@ "NoUpdatesAreAvailable": "Geen updates beschikbaar", "NoLogFiles": "Geen logbestanden", "NoBackupsAreAvailable": "Geen veiligheidskopieën beschikbaar", - "MinutesSixty": "60 Minuten: {0}", - "MinutesNinety": "90 Minuten: {0}", - "MinutesHundredTwenty": "120 Minuten: {0}", "MaintenanceRelease": "Onderhoudsuitgave", "FilterPlaceHolder": "Zoek indexeerder", "Exception": "Uitzondering", @@ -338,8 +297,6 @@ "SaveSettings": "Instellingen Opslaan", "MovieIndexScrollTop": "Film Index: Scroll omhoog", "MovieIndexScrollBottom": "Film Index: Scroll naar onder", - "MovieDetailsPreviousMovie": "Film Details: Vorige Film", - "MovieDetailsNextMovie": "Film Details: Volgende Film", "IndexerLongTermStatusCheckSingleClientMessage": "Indexeerders zijn niet beschikbaar vanwege storingen gedurende meer dan 6 uur: {0}", "IndexerLongTermStatusCheckAllClientMessage": "Alle indexeerders zijn niet beschikbaar vanwege storingen gedurende meer dan 6 uur", "ClearHistoryMessageText": "Weet je zeker dat je alle geschiedenis van Prowlarr wilt verwijderen", @@ -439,5 +396,12 @@ "IndexerProxy": "Indexeerder-proxy", "IndexerProxyStatusCheckAllClientMessage": "Alle proxy's zijn niet beschikbaar vanwege storingen", "IndexerProxyStatusCheckSingleClientMessage": "Proxy's niet beschikbaar vanwege storingen: {0}", - "IndexerQuery": "Indexeer zoekopdracht" + "IndexerQuery": "Indexeer zoekopdracht", + "HistoryCleanupDaysHelpText": "Zet op 0 om automatisch opschonen uit te schakelen", + "HistoryCleanupDaysHelpTextWarning": "Bestanden in de prullenbak ouder dan het geselecteerde aantal dagen zullen automatisch opgeschoond worden", + "OnGrab": "Bij Ophalen", + "OnHealthIssue": "Bij Gezondheidsprobleem", + "Filters": "Filter", + "TestAllIndexers": "Test Alle Indexeerders", + "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent geleverd door de app die de API heeft aangeroepen" } diff --git a/src/NzbDrone.Core/Localization/Core/pl.json b/src/NzbDrone.Core/Localization/Core/pl.json index ab8d68c8a..7cfe991b0 100644 --- a/src/NzbDrone.Core/Localization/Core/pl.json +++ b/src/NzbDrone.Core/Localization/Core/pl.json @@ -9,7 +9,6 @@ "Actions": "Aktywności", "About": "O", "Logging": "Logowanie", - "MinutesNinety": "90 minut: {0}", "EnableSslHelpText": " Wymaga ponownego uruchomienia jako administrator, aby odniosło skutek", "ReadTheWikiForMoreInformation": "Przeczytaj Wiki, aby uzyskać więcej informacji", "Reload": "Przeładować", @@ -30,26 +29,20 @@ "Delete": "Usunąć", "Discord": "Niezgoda", "Edit": "Edytować", - "EnableAutoHelpText": "Jeśli włączone, filmy będą automatycznie dodawane do Radarr z tej listy", "EnableAutomaticSearchHelpText": "Będzie używany, gdy automatyczne wyszukiwania są wykonywane przez interfejs użytkownika lub przez Radarr", - "EnableHelpText": "Włącz tworzenie pliku metadanych dla tego typu metadanych", "KeyboardShortcuts": "Skróty klawiszowe", "UnableToAddANewAppProfilePleaseTryAgain": "Nie można dodać nowego profilu jakości, spróbuj ponownie.", "URLBase": "Baza adresów URL", "CustomFilters": "Filtry niestandardowe", - "DeleteIndexerMessageText": "Czy na pewno chcesz usunąć indeksator „{0}”?", - "EnableInteractiveSearchHelpTextWarning": "Wyszukiwanie nie jest obsługiwane przez ten indeksator", "EnableRss": "Włącz RSS", "LaunchBrowserHelpText": " Otwórz przeglądarkę internetową i przejdź do strony głównej Radarr po uruchomieniu aplikacji.", "Password": "Hasło", "Peers": "Rówieśnicy", - "Pending": "W oczekiwaniu", "PrioritySettings": "Priorytet", "Protocol": "Protokół", "Options": "Opcje", "ProxyType": "Typ proxy", "ShownClickToHide": "Pokazane, kliknij, aby ukryć", - "QualityDefinitions": "Definicje jakości", "Refresh": "Odświeżać", "ReleaseStatus": "Stan wydania", "RemovingTag": "Usuwanie tagu", @@ -72,12 +65,9 @@ "ChangeHasNotBeenSavedYet": "Zmiana nie została jeszcze zapisana", "DownloadClient": "Pobierz klienta", "Exception": "Wyjątek", - "ExistingMovies": "Istniejące filmy", "ExistingTag": "Istniejący tag", "Filename": "Nazwa pliku", - "Languages": "Języki", "NoChange": "Bez zmiany", - "NoMinimumForAnyRuntime": "Brak minimum dla dowolnego środowiska uruchomieniowego", "Add": "Dodaj", "AppDataDirectory": "Katalog AppData", "AreYouSureYouWantToResetYourAPIKey": "Czy na pewno chcesz zresetować swój klucz API?", @@ -92,9 +82,7 @@ "LastWriteTime": "Czas ostatniego zapisu", "Level": "Poziom", "LogFiles": "Pliki dziennika", - "MaximumLimits": "Maksymalne limity", "Mechanism": "Mechanizm", - "MovieDetailsPreviousMovie": "Szczegóły filmu: poprzedni film", "NoChanges": "Bez zmian", "NoUpdatesAreAvailable": "Brak dostępnych aktualizacji", "OAuthPopupMessage": "Twoja przeglądarka blokuje wyskakujące okienka", @@ -134,7 +122,6 @@ "CancelPendingTask": "Czy na pewno chcesz anulować to oczekujące zadanie?", "CertificateValidation": "Walidacja certyfikatu", "ClientPriority": "Priorytet klienta", - "CloneIndexer": "Clone Indexer", "CloneProfile": "Klonuj profil", "Component": "Składnik", "ConnectionLost": "Utracono połączenie", @@ -143,34 +130,21 @@ "Date": "Data", "Dates": "Daktyle", "DBMigration": "Migracja bazy danych", - "DelayProfile": "Profil opóźnienia", "DeleteApplicationMessageText": "Czy na pewno chcesz usunąć powiadomienie „{0}”?", "DeleteBackup": "Usuń kopię zapasową", "DeleteBackupMessageText": "Czy na pewno chcesz usunąć kopię zapasową „{0}”?", "DeleteDownloadClient": "Usuń klienta pobierania", "DeleteDownloadClientMessageText": "Czy na pewno chcesz usunąć klienta pobierania „{0}”?", - "DeleteIndexer": "Usuń indeksator", "DeleteNotification": "Usuń powiadomienie", "Disabled": "Wyłączone", "Docker": "Doker", - "DownloadClientCheckNoneAvailableMessage": "Żaden klient pobierania nie jest dostępny", - "DownloadClientCheckUnableToCommunicateMessage": "Nie można skomunikować się z {0}.", "DownloadClientStatusCheckSingleClientMessage": "Klienci pobierania niedostępni z powodu błędów: {0}", - "DownloadClientUnavailable": "Klient pobierania jest niedostępny", - "Downloading": "Ściąganie", "EditIndexer": "Edytuj indeksator", "Enable": "Włączyć", - "EnableAutomaticAdd": "Włącz automatyczne dodawanie", "EnableAutomaticSearch": "Włącz automatyczne wyszukiwanie", - "EnableAutomaticSearchHelpTextWarning": "Będzie używany, gdy używane jest wyszukiwanie interaktywne", - "EnableColorImpairedMode": "Włącz tryb z zaburzeniami kolorów", - "EnableColorImpairedModeHelpText": "Zmieniony styl, aby umożliwić użytkownikom z zaburzeniami kolorów lepsze rozróżnianie informacji oznaczonych kolorami", - "EnableCompletedDownloadHandlingHelpText": "Automatycznie importuj ukończone pliki do pobrania z klienta pobierania", "Enabled": "Włączone", - "EnabledHelpText": "Włącz tę listę do użytku w Radarr", "DownloadClientStatusCheckAllClientMessage": "Wszyscy klienci pobierania są niedostępni z powodu błędów", "EnableInteractiveSearch": "Włącz wyszukiwanie interaktywne", - "EnableMediaInfoHelpText": "Wyodrębnij z plików informacje wideo, takie jak rozdzielczość, czas działania i kodeki. Wymaga to odczytu przez Radarr części pliku, które mogą powodować dużą aktywność dysku lub sieci podczas skanowania.", "EventType": "Typ wydarzenia", "Failed": "Niepowodzenie", "FeatureRequests": "Żądania funkcji", @@ -193,7 +167,6 @@ "IllRestartLater": "Zrestartuję później", "IndexerLongTermStatusCheckAllClientMessage": "Wszystkie indeksatory są niedostępne z powodu awarii przez ponad 6 godzin", "IndexerLongTermStatusCheckSingleClientMessage": "Indeksatory niedostępne z powodu błędów przez ponad 6 godzin: {0}", - "QualitySettings": "Ustawienia jakości", "IndexerPriority": "Priorytet indeksatora", "IndexerPriorityHelpText": "Priorytet indeksatora od 1 (najwyższy) do 50 (najniższy). Domyślnie: 25.", "IndexerProxyStatusCheckAllClientMessage": "Wszystkie listy są niedostępne z powodu błędów", @@ -206,17 +179,14 @@ "LogLevelTraceHelpTextWarning": "Rejestrowanie śledzenia powinno być włączone tylko tymczasowo", "Logs": "Dzienniki", "Manual": "podręcznik", - "MovieDetailsNextMovie": "Szczegóły filmu: następny film", "MovieIndexScrollBottom": "Indeks filmów: przewiń w dół", "MovieIndexScrollTop": "Indeks filmów: przewiń do góry", "Name": "Nazwa", "New": "Nowy", "NoBackupsAreAvailable": "Brak dostępnych kopii zapasowych", - "UnableToLoadQualityDefinitions": "Nie można załadować definicji jakości", "Uptime": "Dostępność", "UnableToLoadUISettings": "Nie można załadować ustawień interfejsu użytkownika", "NoLeaveIt": "Nie, zostaw to", - "NoLimitForAnyRuntime": "Brak ograniczeń dla dowolnego czasu wykonywania", "NoLinks": "Brak linków", "NoLogFiles": "Brak plików dziennika", "NoTagsHaveBeenAddedYet": "Żadne tagi nie zostały jeszcze dodane", @@ -229,7 +199,6 @@ "PendingChangesMessage": "Masz niezapisane zmiany, czy na pewno chcesz opuścić tę stronę?", "Port": "Port", "PortNumber": "Numer portu", - "PreferredSize": "Preferowany rozmiar", "Presets": "Presety", "Priority": "Priorytet", "PriorityHelpText": "Nadaj priorytet wielu klientom pobierania. W przypadku klientów o tym samym priorytecie używane jest działanie okrężne.", @@ -253,7 +222,6 @@ "RestartRequiredHelpTextWarning": "Wymaga ponownego uruchomienia, aby odniosło skutek", "Restore": "Przywracać", "RestoreBackup": "Przywracania kopii zapasowej", - "Restrictions": "Ograniczenia", "Result": "Wynik", "Retention": "Zatrzymywanie", "Save": "Zapisać", @@ -308,7 +276,6 @@ "UnableToLoadDownloadClients": "Nie można załadować klientów pobierania", "UnableToLoadGeneralSettings": "Nie można załadować ustawień ogólnych", "UnableToLoadHistory": "Nie można załadować historii", - "UnableToLoadIndexers": "Nie można załadować indeksatorów", "UnableToLoadTags": "Nie można załadować tagów", "UnsavedChanges": "Niezapisane zmiany", "UpdateAutomaticallyHelpText": "Automatycznie pobieraj i instaluj aktualizacje. Nadal będziesz mógł zainstalować z System: Updates", @@ -325,7 +292,6 @@ "Donations": "Darowizny", "DownloadClients": "Pobierz klientów", "DownloadClientSettings": "Pobierz ustawienia klienta", - "Importing": "Importowanie", "IncludeHealthWarningsHelpText": "Uwzględnij ostrzeżenia zdrowotne", "Indexer": "Indeksator", "IndexerFlags": "Flagi indeksujące", @@ -342,20 +308,20 @@ "Backups": "Kopie zapasowe", "Message": "Wiadomość", "MIA": "MIA", - "MinimumLimits": "Minimalne limity", - "MinutesHundredTwenty": "120 minut: {0}", - "MinutesSixty": "60 minut: {0}", "Mode": "Tryb", - "MonoTlsCheckMessage": "Obejście problemu z Radarr Mono 4.x tls jest nadal włączone, rozważ usunięcie MONO_TLS_PROVIDER = starsza opcja środowiska", - "MonoVersion": "Wersja mono", - "MonoVersionCheckUpgradeRecommendedMessage": "Aktualnie zainstalowana wersja Mono {0} jest obsługiwana, ale zalecana jest aktualizacja do {1}.", "MoreInfo": "Więcej informacji", - "Movies": "Kino", "Columns": "Kolumny", "Host": "Gospodarz", "Indexers": "Indeksatory", "IndexerStatusCheckAllClientMessage": "Wszystkie indeksatory są niedostępne z powodu błędów", "RestartNow": "Zrestartuj teraz", "RSS": "RSS", - "Tasks": "Zadania" + "Tasks": "Zadania", + "MaintenanceRelease": "Wersja konserwacyjna: poprawki błędów i inne ulepszenia. Aby uzyskać więcej informacji, zobacz historię zatwierdzeń na Github", + "HistoryCleanupDaysHelpTextWarning": "Pliki w koszu starsze niż wybrana liczba dni zostaną automatycznie wyczyszczone", + "Filters": "Filtr", + "HistoryCleanupDaysHelpText": "Ustaw na 0, aby wyłączyć automatyczne czyszczenie", + "OnGrab": "Na Grab", + "OnHealthIssue": "W kwestii zdrowia", + "TestAllIndexers": "Przetestuj wszystkie indeksatory" } diff --git a/src/NzbDrone.Core/Localization/Core/pt.json b/src/NzbDrone.Core/Localization/Core/pt.json index 8df0e10ea..edf2d82c2 100644 --- a/src/NzbDrone.Core/Localization/Core/pt.json +++ b/src/NzbDrone.Core/Localization/Core/pt.json @@ -48,16 +48,13 @@ "Scheduled": "Agendado", "SaveChanges": "Guardar mudanças", "Save": "Guardar", - "Restrictions": "Restrições", "RestoreBackup": "Restaurar cópia de segurança", "Restart": "Reiniciar", "Reload": "Recarregar", "ReleaseStatus": "Estado da versão", - "ReleaseBranchCheckPreviousVersionMessage": "A ramificação {0} é para versões anteriores do Prowlarr, utilize a ramificação \"Nightly\" para futuras atualizações", "ReleaseBranchCheckOfficialBranchMessage": "A ramificação {0} não é uma ramificação de versões válida do Prowlarr, você não receberá atualizações", "Refresh": "Atualizar", "Queue": "Fila", - "QualityDefinitions": "Definições de qualidade", "PtpOldSettingsCheckMessage": "As definições dos seguintes indexadores do PassThePopcorn são obsoletas e precisam ser atualizadas: {0}", "ProxyCheckResolveIpMessage": "Não é possível resolver o Endereço IP para o Anfitrião de proxy {0} definido", "ProxyCheckFailedToTestMessage": "Falha ao testar o proxy: {0}", @@ -74,18 +71,13 @@ "NoChanges": "Sem mudanças", "NoChange": "Sem mudança", "Name": "Nome", - "Movies": "Filmes", "MoreInfo": "Mais informações", - "MonoVersionCheckUpgradeRecommendedMessage": "A versão Mono {0} atualmente instalada é suportada, mas recomenda-se atualizar para {1}.", - "MonoTlsCheckMessage": "Uma solução para o Prowlarr Mono 4.x tls ainda está ativa, considere remover a opção de ambiente MONO_TLS_PROVIDER=legacy", - "MonoNotNetCoreCheckMessage": "Atualiza para a versão .NET Core do Prowlarr", "Message": "Mensagem", - "Logging": "Registo em log", + "Logging": "guardar nos registos", "LogFiles": "Ficheiros de log", "Level": "Nível", "LastWriteTime": "Hora da última escrita", "Language": "Idioma", - "Languages": "Idiomas", "KeyboardShortcuts": "Atalhos do teclado", "Info": "Informações", "IndexerStatusCheckSingleClientMessage": "Indexadores indisponíveis devido a falhas: {0}", @@ -105,7 +97,6 @@ "Files": "Ficheiros", "Filename": "Nome do ficheiro", "Failed": "Falhado", - "ExistingMovies": "Filme(s) existente(s)", "EventType": "Tipo de evento", "Events": "Eventos", "Error": "Erro", @@ -114,8 +105,6 @@ "DownloadClientStatusCheckAllClientMessage": "Todos os clientes de transferências estão indisponíveis devido a falhas", "DownloadClientsSettingsSummary": "Definições do cliente de transferências para integração à pesquisa da IU do Prowlarr", "DownloadClients": "Clientes de transferências", - "DownloadClientCheckUnableToCommunicateMessage": "Não é possível ligar-se a {0}.", - "DownloadClientCheckNoneAvailableMessage": "Nenhum cliente de transferências disponível", "DownloadClient": "Cliente de transferências", "Details": "Detalhes", "Delete": "Eliminar", @@ -150,7 +139,6 @@ "AppDataDirectory": "Pasta AppData", "ApiKey": "Chave da API", "AnalyticsEnabledHelpText": "Envia informações anônimas de uso e de erros aos servidores do Prowlarr. Isso inclui informações sobre seu browser, páginas utilizadas na WebUI do Prowlarr, relatórios de erros, bem como as versões do sistema operativo e da aplicação. Utilizaremos essas informações para priorizar funcionalidades e correções de bugs.", - "QualitySettings": "Definições de qualidade", "ProxyType": "Tipo de proxy", "PortNumber": "Número da porta", "Port": "Porta", @@ -160,22 +148,16 @@ "OpenBrowserOnStart": "Abrir browser ao iniciar", "OnHealthIssueHelpText": "Ao ter problemas no estado de funcionamento", "NotificationTriggers": "Acionadores de notificação", - "NoMinimumForAnyRuntime": "Sem mínimo para tempo de execução", - "NoLimitForAnyRuntime": "Sem limite de tempo de execução", "NoLeaveIt": "Não, deixe-o", "New": "Novo", "NetCore": ".NET", - "MonoVersion": "Versão do Mono", "Mode": "Modo", - "MinimumLimits": "Limites mínimos", "Mechanism": "Mecanismo", - "MaximumLimits": "Limites máximos", "Logs": "Logs", "LogLevel": "Nível de log", "Interval": "Intervalo", "IndexerFlags": "Sinalizadores do indexador", "IncludeHealthWarningsHelpText": "Incluir avisos de estado de funcionamento", - "Importing": "Importando", "IllRestartLater": "Reiniciarei mais tarde", "IgnoredAddresses": "Endereços ignorados", "Hostname": "Nome do anfitrião", @@ -183,29 +165,18 @@ "Fixed": "Corrigido", "EnableSslHelpText": " Requer reinício da aplicação como administrador para aplicar alterações", "EnableSSL": "Ativar SSL", - "EnableMediaInfoHelpText": "Extraia informações de vídeo como resolução, tempo de execução e informações de codec dos ficheiros. Isso requer que o Prowlarr leia partes do ficheiro, o que pode causar alta atividade do disco ou da rede durante as análises.", "EnableInteractiveSearch": "Ativar pesquisa interativa", - "EnableHelpText": "Ativar criação do ficheiro de metadados para este tipo de metadados", - "EnabledHelpText": "Ativar esta lista para uso no Prowlarr", - "EnableCompletedDownloadHandlingHelpText": "Automaticamente importar transferências concluídas do cliente de transferências", - "EnableColorImpairedModeHelpText": "Estilo alterado para permitir que utilizadores com daltonismo possam melhor distinguir informações de cores", - "EnableColorImpairedMode": "Ativar modo de daltonismo", "EnableAutomaticSearch": "Ativar pesquisa automática", - "EnableAutomaticAdd": "Ativar adição automática", - "EnableAutoHelpText": "Se ativado, os filmes desta lista serão automaticamente adicionados ao Prowlarr", "Enable": "Ativar", "DownloadClientSettings": "Definições do cliente de transferências", "Docker": "Docker", "DeleteTag": "Eliminar etiqueta", "DeleteNotification": "Eliminar notificação", - "DeleteIndexer": "Eliminar indexador", "DeleteDownloadClient": "Eliminar cliente de transferências", "DeleteBackup": "Eliminar cópia de segurança", - "DelayProfile": "Perfil de atraso", "DBMigration": "Migração da base de dados", "ConnectSettings": "Definições de ligação", "CloneProfile": "Clonar perfil", - "CloneIndexer": "Clonar indexador", "ChangeHasNotBeenSavedYet": "A mudança ainda não foi guardada", "CertificateValidationHelpText": "Mudar nível de restrição da validação da certificação HTTPS", "CertificateValidation": "Validação de certificado", @@ -228,15 +199,12 @@ "ApplyTagsHelpTexts1": "Como aplicar etiquetas aos indexadores selecionados", "AddingTag": "A adicionar etiqueta", "AutomaticSearch": "Pesquisa automática", - "UnableToLoadIndexers": "Não foi possível carregar os indexadores", "UnableToAddANewIndexerPleaseTryAgain": "Não foi possível adicionar um novo indexador, tenta novamente.", "RSSIsNotSupportedWithThisIndexer": "RSS não é suportado por esse indexador", "ProwlarrSupportsAnyIndexer": "O Prowlarr suporta qualquer indexador que usa o padrão Newznab, bem como os outros indexadores listados abaixo.", "IndexerPriorityHelpText": "Prioridade do indexador de 1 (mais alta) a 50 (mais baixa). Padrão: 25.", "IndexerPriority": "Prioridade do indexador", - "EnableInteractiveSearchHelpTextWarning": "Este indexador não suporta pesquisas", "EditIndexer": "Editar indexador", - "DeleteIndexerMessageText": "Tem a certeza que quer eliminar o indexador \"{0}\"?", "AddIndexer": "Adicionar indexador", "ScriptPath": "Caminho do script", "Retention": "Retenção", @@ -251,14 +219,10 @@ "RefreshMovie": "Atualizar filme", "ReadTheWikiForMoreInformation": "Leia a Wiki para obter mais informações", "Priority": "Prioridade", - "Pending": "Pendente", "NoUpdatesAreAvailable": "Não há atualizações disponíveis", "NoTagsHaveBeenAddedYet": "Você ainda não adicionou etiquetas", "NoLogFiles": "Sem ficheiros de log", "NoBackupsAreAvailable": "Não há cópias de segurança disponíveis", - "MinutesSixty": "60 minutos: {0}", - "MinutesNinety": "90 minutos: {0}", - "MinutesHundredTwenty": "120 minutos: {0}", "MIA": "Desaparecidos", "Manual": "Manual", "InteractiveSearch": "Pesquisa interativa", @@ -269,11 +233,7 @@ "Exception": "Exceção", "ErrorLoadingContents": "Erro ao carregar conteúdo", "EnableInteractiveSearchHelpText": "Será utilizado ao realizar uma pesquisa interativa", - "EnableAutomaticSearchHelpTextWarning": "Será utilizado ao realizar uma pesquisa interativa", "EnableAutomaticSearchHelpText": "Será utilizado ao realizar pesquisas automáticas através da IU ou pelo Prowlarr", - "PreferredSize": "Tamanho preferido", - "Downloading": "Transferindo", - "DownloadClientUnavailable": "O cliente de transferências está indisponível", "Disabled": "Desativado", "DeleteTagMessageText": "Tem a certeza que quer eliminar a etiqueta \"{0}\"?", "DeleteNotificationMessageText": "Tem a certeza que quer eliminar a notificação \"{0}\"?", @@ -316,7 +276,6 @@ "Uptime": "Tempo de atividade", "UnableToLoadUISettings": "Não foi possível carregar as definições da IU", "UnableToLoadTags": "Não foi possível carregar as etiquetas", - "UnableToLoadQualityDefinitions": "Não foi possível carregar as definições de qualidade", "UnableToLoadNotifications": "Não foi possível carregar as notificações", "UnableToLoadHistory": "Não foi possível carregar o histórico", "UnableToLoadGeneralSettings": "Não foi possível carregar as definições gerais", @@ -336,8 +295,6 @@ "SaveSettings": "Guardar definições", "MovieIndexScrollTop": "Índice do filme: deslocar para cima", "MovieIndexScrollBottom": "Índice do filme: deslocar para baixo", - "MovieDetailsPreviousMovie": "Detalhes do filme: filme anterior", - "MovieDetailsNextMovie": "Detalhes do filme: próximo filme", "SettingsConsoleLogLevel": "Nível de registo do console", "SearchIndexers": "Pesquisar indexadores", "IndexersSelectedInterp": "{0} indexador(es) selecionado(s)", @@ -430,5 +387,11 @@ "IndexerProxies": "Proxys de Indexadores", "IndexerProxyStatusCheckAllClientMessage": "Todos os proxys estão indisponíveis devido a falhas", "NoLinks": "Sem ligações", - "UnableToAddANewIndexerProxyPleaseTryAgain": "Não foi possível adicionar um novo indexador, tenta novamente." + "UnableToAddANewIndexerProxyPleaseTryAgain": "Não foi possível adicionar um novo indexador, tenta novamente.", + "Filters": "Filtros", + "HistoryCleanupDaysHelpText": "Defina como 0 para desativar a limpeza automática", + "OnGrab": "Ao capturar", + "OnHealthIssue": "Ao ter problemas no estado de funcionamento", + "TestAllIndexers": "Testar todos os indexadores", + "UserAgentProvidedByTheAppThatCalledTheAPI": "Par Utilizador-Agente fornecido pela aplicação que chamou a API" } diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index 0127b2257..bdec083e4 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -11,14 +11,9 @@ "ClientPriority": "Prioridade do cliente", "ConnectionLostAutomaticMessage": "O Prowlarr tentará se conectar automaticamente, ou você pode clicar em Recarregar abaixo.", "ConnectSettingsSummary": "Notificações e scripts personalizados", - "DeleteIndexerMessageText": "Tem certeza de que deseja excluir o indexador \"{0}\"?", "IndexerObsoleteCheckMessage": "Os seguintes indexadores são obsoletos ou foram atualizados: {0}. Remova-os e/ou adicione-os novamente ao Prowlarr", "DownloadClientsSettingsSummary": "Configuração de clientes de download para integração com a pesquisa da interface do usuário do Prowlarr", - "EnableAutoHelpText": "Se habilitada, os filmes serão automaticamente adicionados ao Prowlarr a partir desta lista", - "EnableAutomaticSearchHelpTextWarning": "Será usado com a pesquisa interativa", - "EnableColorImpairedModeHelpText": "Estilo alterado para permitir que usuários com daltonismo distingam melhor as informações codificadas por cores", "EnableInteractiveSearchHelpText": "Será usado com a pesquisa interativa", - "EnableMediaInfoHelpText": "Extrair informações do vídeo, como resolução, tempo de execução e informações do codec de arquivos. Isso requer que o Prowlarr leia partes do arquivo que podem causar alta atividade no disco ou na rede durante as verificações.", "ForMoreInformationOnTheIndividualDownloadClients": "Para saber mais sobre cada cliente de download, clique nos botões de informações.", "IndexerFlags": "Sinalizadores do indexador", "IndexerHealthCheckNoIndexers": "Não há indexadores habilitados, o Prowlarr não retornará resultados para a pesquisa", @@ -26,8 +21,6 @@ "IndexersSelectedInterp": "{0} indexador(es) selecionado(s)", "LastWriteTime": "Hora da última gravação", "LaunchBrowserHelpText": " Abrir o navegador Web e navegar até a página inicial do Prowlarr ao iniciar o aplicativo.", - "MonoNotNetCoreCheckMessage": "Atualize para a versão .NET Core do Prowlarr", - "MonoTlsCheckMessage": "Solução alternativa para o Prowlarr Mono 4.x tls ainda habilitada, considere remover a opção de ambiente MONO_TLS_PROVIDER=legacy", "NoTagsHaveBeenAddedYet": "Você ainda não adicionou tags", "NotificationTriggers": "Acionadores da notificação", "NoUpdatesAreAvailable": "Não há atualizações disponíveis", @@ -52,7 +45,6 @@ "UILanguageHelpText": "Idioma que o Prowlarr usará para a interface", "UnableToAddANewIndexerPleaseTryAgain": "Não foi possível adicionar um novo indexador, tente novamente.", "UnableToLoadGeneralSettings": "Não foi possível carregar as configurações gerais", - "UnableToLoadQualityDefinitions": "Não foi possível carregar as definições de qualidade", "UpdateAutomaticallyHelpText": "Baixar e instalar atualizações automaticamente. Você ainda poderá instalar a partir de Sistema: Atualizações", "UpdateCheckStartupTranslocationMessage": "Não é possível instalar a atualização porque a pasta de inicialização \"{0}\" está em uma pasta de transposição de aplicativos.", "UrlBaseHelpText": "Para suporte de proxy reverso, o padrão é vazio", @@ -68,7 +60,7 @@ "Analytics": "Análises", "ApiKey": "Chave da API", "AppDataDirectory": "Diretório AppData", - "AppDataLocationHealthCheckMessage": "Não será possível atualizar, a fim de evitar a exclusão de AppData durante a atualização", + "AppDataLocationHealthCheckMessage": "A atualização não será possível para evitar a exclusão de AppData na atualização", "ApplicationStatusCheckAllClientMessage": "Não há aplicativos disponíveis devido a falhas", "ApplicationStatusCheckSingleClientMessage": "Aplicativos indisponíveis devido a falhas: {0}", "Apply": "Aplicar", @@ -98,7 +90,6 @@ "Clear": "Limpar", "ClearHistory": "Limpar histórico", "ClearHistoryMessageText": "Tem certeza de que deseja limpar o histórico do Prowlarr?", - "CloneIndexer": "Clonar indexador", "Close": "Fechar", "CloseCurrentModal": "Fechar modal atual", "Columns": "Colunas", @@ -111,13 +102,11 @@ "Date": "Data", "Dates": "Datas", "DBMigration": "Migração de banco de dados", - "DelayProfile": "Perfil de atraso", "Delete": "Excluir", "DeleteApplication": "Excluir aplicativo", "DeleteApplicationMessageText": "Tem certeza de que deseja excluir o aplicativo \"{0}\"?", "DeleteBackup": "Excluir backup", "DeleteBackupMessageText": "Tem certeza que deseja excluir o backup \"{0}\"?", - "DeleteIndexer": "Excluir indexador", "DeleteNotification": "Excluir notificação", "DeleteNotificationMessageText": "Tem certeza de que deseja excluir a notificação \"{0}\"?", "DeleteTag": "Excluir tag", @@ -127,26 +116,16 @@ "Disabled": "Desabilitado", "Docker": "Docker", "DownloadClient": "Cliente de download", - "DownloadClientCheckNoneAvailableMessage": "Não há cliente de download disponível", - "DownloadClientCheckUnableToCommunicateMessage": "Não é possível comunicar-se com {0}.", "DownloadClients": "Clientes de download", "DownloadClientSettings": "Configurações do cliente de download", - "DownloadClientStatusCheckAllClientMessage": "Todos os clientes de download estão indisponíveis devido a falhas", + "DownloadClientStatusCheckAllClientMessage": "Todos os clientes download não estão disponíveis devido a falhas", "DownloadClientStatusCheckSingleClientMessage": "Clientes de download indisponíveis devido a falhas: {0}", - "DownloadClientUnavailable": "O cliente de download está indisponível", - "Downloading": "Baixando", "EditIndexer": "Editar indexador", "Enable": "Habilitar", - "EnableAutomaticAdd": "Habilitar adição automática", "EnableAutomaticSearch": "Habilitar pesquisa automática", "EnableAutomaticSearchHelpText": "Será usado ao realizar pesquisas automáticas pela interface ou pelo Prowlarr", - "EnableColorImpairedMode": "Habilitar modo para daltonismo", - "EnableCompletedDownloadHandlingHelpText": "Importar automaticamente downloads concluídos do cliente de download", - "EnabledHelpText": "Habilitar esta lista para uso no Prowlarr", - "EnableHelpText": "Habilitar a criação de um arquivo de metadados para este tipo de metadados", "EnableIndexer": "Habilitar indexador", "EnableInteractiveSearch": "Habilitar pesquisa interativa", - "EnableInteractiveSearchHelpTextWarning": "A pesquisa não é compatível com este indexador", "EnableSSL": "Habilitar SSL", "EnableSslHelpText": " Requer a reinicialização com a execução como administrador para fazer efeito", "Error": "Erro", @@ -154,7 +133,6 @@ "Events": "Eventos", "EventType": "Tipo de evento", "Exception": "Exceção", - "ExistingMovies": "Filme(s) existente(s)", "ExistingTag": "Tag existente", "Filename": "Nome do arquivo", "Files": "Arquivos", @@ -176,7 +154,6 @@ "Hostname": "Nome do host", "IgnoredAddresses": "Endereços ignorados", "IllRestartLater": "Reiniciarei mais tarde", - "Importing": "Importando", "IncludeHealthWarningsHelpText": "Incluir avisos de integridade", "Indexer": "Indexador", "IndexerAuth": "Autenticação do indexador", @@ -192,32 +169,21 @@ "Interval": "Intervalo", "KeyboardShortcuts": "Atalhos de teclado", "Language": "Idioma", - "Languages": "Idiomas", "Level": "Nível", "LogFiles": "Arquivos de log", "Logging": "Registro em log", "LogLevel": "Nível do log", "LogLevelTraceHelpTextWarning": "O registro de rastreamento deve ser ativado apenas temporariamente", "Logs": "Logs", - "MaintenanceRelease": "Versão de manutenção", + "MaintenanceRelease": "Lançamento de manutenção: correções de bugs e outras melhorias. Veja o histórico de mudanças no github para mais detalhes", "Manual": "Manual", - "MaximumLimits": "Limites máximos", "Mechanism": "Mecanismo", "Message": "Mensagem", "MIA": "Desaparecidos", - "MinimumLimits": "Limites mínimos", - "MinutesHundredTwenty": "120 minutos: {0}", - "MinutesNinety": "90 minutos: {0}", - "MinutesSixty": "60 minutos: {0}", "Mode": "Modo", - "MonoVersion": "Versão do Mono", - "MonoVersionCheckUpgradeRecommendedMessage": "A versão do Mono {0} atualmente instalada é compatível, mas recomenda-se atualizar para a versão {1}.", "MoreInfo": "Mais informações", - "MovieDetailsNextMovie": "Detalhes do filme: próximo filme", - "MovieDetailsPreviousMovie": "Detalhes do filme: filme anterior", "MovieIndexScrollBottom": "Índice do filme: rolar pra baixo", "MovieIndexScrollTop": "Índice do filme: rolar para cima", - "Movies": "Filmes", "Name": "Nome", "NetCore": ".NET", "New": "Novo", @@ -225,9 +191,7 @@ "NoChange": "Sem alteração", "NoChanges": "Sem alterações", "NoLeaveIt": "Não, deixe assim", - "NoLimitForAnyRuntime": "Sem limite para qualquer tempo de execução", "NoLogFiles": "Sem arquivos de log", - "NoMinimumForAnyRuntime": "Sem mínimo para qualquer tempo de execução", "OAuthPopupMessage": "Os pop-ups estão bloqueados em seu navegador", "Ok": "Ok", "OnHealthIssueHelpText": "Ao ter problema de integridade", @@ -238,12 +202,10 @@ "PageSizeHelpText": "Quantidade de itens a exibir em cada página", "Password": "Senha", "Peers": "Pares", - "Pending": "Pendente", "PendingChangesMessage": "Há alterações não salvas. Tem certeza que deseja sair desta página?", "PendingChangesStayReview": "Ficar e revisar alterações", "Port": "Porta", "PortNumber": "Número da porta", - "PreferredSize": "Tamanho preferido", "Priority": "Prioridade", "Protocol": "Protocolo", "ProwlarrSupportsAnyDownloadClient": "O Prowlarr é compatível com todos os clientes de download listados abaixo.", @@ -255,13 +217,10 @@ "ProxyPasswordHelpText": "Você só precisa inserir um nome de usuário e uma senha se solicitado. Caso contrário, deixe em branco.", "ProxyType": "Tipo de proxy", "PtpOldSettingsCheckMessage": "As configurações dos seguintes indexadores do PassThePopcorn são obsoletas e devem ser atualizadas: {0}", - "QualityDefinitions": "Definições de qualidade", - "QualitySettings": "Configurações de qualidade", "Queue": "Fila", "ReadTheWikiForMoreInformation": "Leia a Wiki para saber mais", "Refresh": "Atualizar", "RefreshMovie": "Atualizar filme", - "ReleaseBranchCheckPreviousVersionMessage": "A ramificação {0} é para uma versão anterior do Prowlarr, defina a ramificação como \"Nightly\" para obter mais atualizações", "ReleaseStatus": "Status da versão", "Reload": "Recarregar", "RemovedFromTaskQueue": "Removido da fila de tarefas", @@ -273,7 +232,6 @@ "RestartRequiredHelpTextWarning": "Requer reinício para ter efeito", "Restore": "Restaurar", "RestoreBackup": "Restaurar backup", - "Restrictions": "Restrições", "Result": "Resultado", "Retention": "Retenção", "Save": "Salvar", @@ -343,14 +301,13 @@ "UnableToLoadBackups": "Não foi possível carregar os backups", "UnableToLoadDevelopmentSettings": "Não foi possível carregar as configurações de desenvolvimento", "UnableToLoadHistory": "Não foi possível carregar o histórico", - "UnableToLoadIndexers": "Não foi possível carregar os indexadores", "UnableToLoadNotifications": "Não foi possível carregar as notificações", "UnableToLoadTags": "Não foi possível carregar as tags", "UnableToLoadUISettings": "Não foi possível carregar as configurações da interface", "UnsavedChanges": "Alterações não salvas", "UnselectAll": "Desmarcar tudo", "UpdateCheckStartupNotWritableMessage": "Não é possível instalar a atualização porque a pasta de inicialização \"{0}\" não pode ser acessada pelo usuário \"{1}\".", - "UpdateCheckUINotWritableMessage": "Não é possível instalar a atualização porque a pasta de interface \"{0}\" não pode ser acessada pelo usuário \"{1}\".", + "UpdateCheckUINotWritableMessage": "Não é possível instalar a atualização porque a pasta de interface do usuário '{0}' não é gravável pelo usuário '{1}'.", "UpdateMechanismHelpText": "Usar o atualizador embutido do Prowlarr ou um script", "Updates": "Atualizações", "UpdateScriptPathHelpText": "Caminho para um script personalizado que usa um pacote de atualização extraído e lida com o restante do processo de atualização", @@ -414,8 +371,8 @@ "AddDownloadClient": "Adicionar cliente de download", "CouldNotConnectSignalR": "Não é possível conectar ao SignalR, a interface não atualizará", "PrioritySettings": "Prioridade", - "SyncLevelFull": "Sincronização completa: manterá este aplicativo completamente sincronizado. Alterações feitas no Prowlarr são, então, sincronizadas com este aplicativo. Qualquer alteração feita remotamente será substituída pelo Prowlarr na próxima sincronização.", - "SyncLevelAddRemove": "Adicionar e remover apenas: quando o Prowlarr adiciona ou remove, ele atualizará este aplicativo remoto.", + "SyncLevelFull": "Full Sync: manterá totalmente os indexadores deste aplicativo em sincronia. As alterações feitas em indexadores em Prowlarr são então sincronizadas com este aplicativo. Qualquer alteração feita para indexadores remotamente dentro deste aplicativo será substituída por Prowlarr na próxima sincronização.", + "SyncLevelAddRemove": "Adicione e remova somente: quando os indexadores são adicionados ou removidos do Prowlarr, ele atualizará este aplicativo remoto.", "SyncLevel": "Nível de sincronização", "FullSync": "Sincronização completa", "Edit": "Editar", @@ -431,7 +388,7 @@ "IndexerSettingsSummary": "Defina várias configurações globais do Indexador, incluindo Proxies.", "IndexerProxyStatusCheckAllClientMessage": "Todos os proxies estão indisponíveis devido a falhas", "IndexerProxyStatusCheckSingleClientMessage": "Proxies indisponíveis devido a falhas: {0}", - "IndexerTagsHelpText": "Use etiquetas para especificar clientes padrão, especificar proxies indexadores ou apenas para organizar seus indexadores.", + "IndexerTagsHelpText": "Use etiquetas para especificar proxies de indexador ou apenas para organizar seus indexadores.", "Notifications": "Notificações", "UnableToAddANewIndexerProxyPleaseTryAgain": "Não foi possível adicionar um novo proxy indexador, tente novamente.", "UnableToLoadIndexerProxies": "Incapaz de carregar proxies indexadores", @@ -445,5 +402,29 @@ "MovieSearch": "Pesquisar Filme", "QueryOptions": "Opções de Consulta", "SearchType": "Tipo de Pesquisa", - "TvSearch": "Pesquisar Séries" + "TvSearch": "Pesquisar Séries", + "HistoryCleanupDaysHelpTextWarning": "Os arquivos na lixeira mais antigos do que o número de dias selecionado serão limpos automaticamente", + "Filters": "Filtros", + "HistoryCleanupDaysHelpText": "Defina como 0 para desabilitar a limpeza automática", + "OnApplicationUpdate": "Ao Atualizar o Aplicativo", + "OnApplicationUpdateHelpText": "Ao Atualizar o Aplicativo", + "OnGrab": "Ao Baixar", + "OnHealthIssue": "Ao ter problema de integridade", + "TestAllIndexers": "Testar todos os indexadores", + "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent fornecido pelo aplicativo que chamou a API", + "Categories": "Categorias", + "IndexerAlreadySetup": "Pelo menos uma instância do indexador já está configurado", + "IndexerInfo": "Info do Indexador", + "MassEditor": "Editor em Massa", + "Database": "Banco de dados", + "HistoryCleanup": "Histórico de Limpeza", + "IndexerNoDefCheckMessage": "Os indexadores não têm definição e não funcionarão: {0}. Por favor, remova e (ou) adicione novamente ao Prowlarr", + "Private": "Privado", + "Proxies": "Proxies", + "Public": "Público", + "QueryResults": "Resultados da Consulta", + "SemiPrivate": "Semi-Privado", + "UnableToLoadApplicationList": "Não é possível carregar a lista de aplicativos", + "Url": "Url", + "Website": "Website" } diff --git a/src/NzbDrone.Core/Localization/Core/ro.json b/src/NzbDrone.Core/Localization/Core/ro.json index 4d67e97c7..0fc1b4b45 100644 --- a/src/NzbDrone.Core/Localization/Core/ro.json +++ b/src/NzbDrone.Core/Localization/Core/ro.json @@ -1,8 +1,6 @@ { "DownloadClientsSettingsSummary": "Clienți de descărcare, abordarea descărcărilor și configurarea căilor externe de stocare", "DownloadClients": "Clienți de descărcare", - "DownloadClientCheckUnableToCommunicateMessage": "Nu pot comunica cu {0}.", - "DownloadClientCheckNoneAvailableMessage": "Niciun client de descărcare disponibil", "DownloadClient": "Client de descărcare", "Details": "Detalii", "Delete": "Șterge", @@ -49,16 +47,12 @@ "NoChanges": "Nicio Modificare", "NoChange": "Nicio Modificare", "Name": "Nume", - "Movies": "Filme", "MoreInfo": "Mai multă informație", - "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls este încă activ, ia în calcul să configurezi MONO_TLS_PROVIDER=legacy în opțiunile de mediu", - "MonoNotNetCoreCheckMessage": "Actualizează versiunea de .NET Core a Prowlarr", "Message": "Mesaj", "Logging": "Logare", "LogFiles": "Fișiere de loguri", "Level": "Nivel", "LastWriteTime": "Data ultimei scrieri", - "Languages": "Limbi", "Language": "Limbă", "KeyboardShortcuts": "Scurtături din tastatură", "Info": "Info", @@ -74,7 +68,6 @@ "Cancel": "Anulează", "Apply": "Aplică", "Age": "Vechime", - "QualityDefinitions": "Definiții de calitate", "PtpOldSettingsCheckMessage": "Următorul indexer PassThePopcorn are setări depreciate și ar trebui actualizate: {0}", "ProxyCheckResolveIpMessage": "Nu am putut găsi adresa IP pentru Hostul Proxy Configurat {0}", "ProxyCheckFailedToTestMessage": "Nu am putut testa proxy: {0}", @@ -118,35 +111,26 @@ "Scheduled": "Programat", "SaveChanges": "Salvează modificările", "Save": "Salvează", - "Restrictions": "Restricții", "RestoreBackup": "Restaurează salvarea", "Restart": "Repornește", "Reload": "Reîncarcă", "ReleaseStatus": "Statusul apariției", - "ReleaseBranchCheckPreviousVersionMessage": "Branch {0} este pentru o versiune precedentă a Prowlarr, configurează branchul 'Aphrodite' pentru a primi updateuri", "ReleaseBranchCheckOfficialBranchMessage": "Branchul {0} nu este un branch Prowlarr valid, nu vei primi actualizări", "Refresh": "Reîmprospătează", "Queue": "Coadă", "New": "Nou", - "MonoVersion": "Versiune mono", - "MonoVersionCheckUpgradeRecommendedMessage": "Versiunea mono instalată în prezent {0} este acceptată, dar se recomandă actualizarea la {1}.", "OpenThisModal": "Deschideți acest mod", "SettingsEnableColorImpairedMode": "Activați modul afectat de culoare", "SettingsEnableColorImpairedModeHelpText": "Stil modificat pentru a permite utilizatorilor cu deficiențe de culoare să distingă mai bine informațiile codificate prin culoare", "SettingsLongDateFormat": "Format de dată lungă", "SettingsShortDateFormat": "Format scurt de dată", "SettingsTimeFormat": "Format de timp", - "NoLimitForAnyRuntime": "Fără limită pentru orice timp de rulare", "RSSIsNotSupportedWithThisIndexer": "RSS nu este acceptat cu acest indexer", "ShowSearchHelpText": "Afișați butonul de căutare pe hover", "UILanguageHelpText": "Limba pe care Radarr o va folosi pentru interfața de utilizare", "UILanguageHelpTextWarning": "Reîncărcare browser necesară", "Wiki": "Wiki", "YesCancel": "Da, Anulați", - "EnableColorImpairedModeHelpText": "Stil modificat pentru a permite utilizatorilor cu deficiențe de culoare să distingă mai bine informațiile codificate prin culoare", - "EnableCompletedDownloadHandlingHelpText": "Importați automat descărcările finalizate de la clientul de descărcare", - "DeleteIndexer": "Ștergeți Indexer", - "DeleteIndexerMessageText": "Sigur doriți să ștergeți indexatorul „{0}”?", "DeleteNotification": "Ștergeți notificarea", "DeleteNotificationMessageText": "Sigur doriți să ștergeți notificarea „{0}”?", "DeleteTag": "Ștergeți eticheta", @@ -171,9 +155,7 @@ "CertificateValidation": "Validarea certificatului", "CertificateValidationHelpText": "Modificați cât de strictă este validarea certificării HTTPS", "ClientPriority": "Prioritatea clientului", - "CloneIndexer": "Clonă Indexer", "CloseCurrentModal": "Închideți modul curent", - "EnableAutoHelpText": "Dacă este activată, Filme vor fi adăugate automat la Radarr din această listă", "EnableAutomaticSearch": "Activați Căutarea automată", "EnableAutomaticSearchHelpText": "Va fi utilizat atunci când căutările automate sunt efectuate prin interfața de utilizare sau de către Radarr", "EnableInteractiveSearchHelpText": "Va fi utilizat atunci când este utilizată căutarea interactivă", @@ -181,7 +163,6 @@ "IllRestartLater": "Voi reporni mai târziu", "IndexerProxyStatusCheckAllClientMessage": "Niciun indexator nu este disponibil datorită eșuărilor", "IndexerProxyStatusCheckSingleClientMessage": "Liste indisponibile datorită erorilor: {0}", - "NoMinimumForAnyRuntime": "Niciun minim pentru orice timp de rulare", "Add": "Adăuga", "Custom": "Personalizat", "DeleteBackup": "Ștergeți Backup", @@ -192,13 +173,10 @@ "OnHealthIssueHelpText": "Cu privire la problema sănătății", "PackageVersion": "Versiunea pachetului", "Password": "Parola", - "Pending": "In asteptarea", "PendingChangesDiscardChanges": "Aruncați modificările și plecați", - "PreferredSize": "Dimensiune preferată", "Priority": "Prioritate", "PriorityHelpText": "Prioritizați mai mulți clienți de descărcare. Round-Robin este utilizat pentru clienții cu aceeași prioritate.", "PrioritySettings": "Prioritate", - "QualitySettings": "Setări de calitate", "Reddit": "Reddit", "Result": "Rezultat", "RSS": "RSS", @@ -215,7 +193,6 @@ "Enable": "Permite", "EnableRss": "Activați RSS", "ErrorLoadingContents": "Eroare la încărcarea conținutului", - "ExistingMovies": "Filme existente", "FocusSearchBox": "Caseta de căutare Focus", "IndexerFlags": "Steaguri indexatoare", "Presets": "Presetări", @@ -227,9 +204,6 @@ "UnableToAddANewApplicationPleaseTryAgain": "Imposibil de adăugat o nouă notificare, încercați din nou.", "UnableToAddANewDownloadClientPleaseTryAgain": "Imposibil de adăugat un nou client de descărcare, încercați din nou.", "DownloadClientSettings": "Descărcați setările clientului", - "EnableMediaInfoHelpText": "Extrageți informații video, cum ar fi rezoluția, runtime și informații despre codec din fișiere. Acest lucru necesită ca Radarr să citească părți ale fișierului care pot provoca activitate ridicată pe disc sau rețea în timpul scanărilor.", - "EnableInteractiveSearchHelpTextWarning": "Căutarea nu este acceptată cu acest indexer", - "EnableAutomaticSearchHelpTextWarning": "Va fi utilizat atunci când este utilizată căutarea interactivă", "Enabled": "Activat", "IncludeHealthWarningsHelpText": "Includeți avertismente de sănătate", "IndexerPriorityHelpText": "Prioritatea indexerului de la 1 (cea mai mare) la 50 (cea mai mică). Implicit: 25.", @@ -237,11 +211,8 @@ "LogLevel": "Nivel jurnal", "LogLevelTraceHelpTextWarning": "Înregistrarea urmăririi trebuie activată doar temporar", "Logs": "Jurnale", - "MaximumLimits": "Limite maxime", "Mechanism": "Mecanism", "MIA": "MIA", - "MinimumLimits": "Limite minime", - "MinutesHundredTwenty": "120 de minute: {0}", "ProxyBypassFilterHelpText": "Folosiți „,” ca separator și „*.” ca un wildcard pentru subdomenii", "ProxyType": "Tip proxy", "ProxyPasswordHelpText": "Trebuie să introduceți un nume de utilizator și o parolă numai dacă este necesară. Lasă-le necompletate altfel.", @@ -252,7 +223,6 @@ "Restore": "Restabili", "Retention": "Retenţie", "ScriptPath": "Calea Scriptului", - "UnableToLoadIndexers": "Imposibil de încărcat indexatori", "UnableToLoadNotifications": "Nu se pot încărca notificările", "UnableToLoadTags": "Nu se pot încărca etichete", "UnableToLoadUISettings": "Nu se pot încărca setările UI", @@ -265,11 +235,8 @@ "CloneProfile": "Profil de clonare", "NoLeaveIt": "Nu, lasă-l", "DBMigration": "Migrarea DB", - "UnableToLoadQualityDefinitions": "Nu se pot încărca definițiile de calitate", - "DelayProfile": "Profile de întârziere", "DeleteBackupMessageText": "Sigur doriți să ștergeți copia de rezervă „{0}”?", "DeleteTagMessageText": "Sigur doriți să ștergeți eticheta „{0}”?", - "EnableHelpText": "Activați crearea fișierului de metadate pentru acest tip de metadate", "EnableInteractiveSearch": "Activați căutarea interactivă", "EnableSSL": "Activați SSL", "EnableSslHelpText": " Necesită repornirea în funcție de administrator pentru a intra în vigoare", @@ -279,15 +246,10 @@ "HomePage": "Pagina principala", "Hostname": "Numele gazdei", "IgnoredAddresses": "Adrese ignorate", - "Importing": "Importând", "IndexerLongTermStatusCheckAllClientMessage": "Toți indexatorii nu sunt disponibili din cauza unor eșecuri de mai mult de 6 ore", "IndexerLongTermStatusCheckSingleClientMessage": "Indexatori indisponibili din cauza unor eșecuri de mai mult de 6 ore: {0}", "IndexerPriority": "Prioritatea indexerului", - "MinutesNinety": "90 de minute: {0}", - "MinutesSixty": "60 de minute: {0}", "Mode": "Mod", - "MovieDetailsNextMovie": "Detalii film: Următorul film", - "MovieDetailsPreviousMovie": "Detalii film: Filmul anterior", "MovieIndexScrollTop": "Index film: Derulați sus", "NoBackupsAreAvailable": "Nu sunt disponibile copii de rezervă", "NoLogFiles": "Nu există fișiere jurnal", @@ -324,9 +286,6 @@ "Discord": "Discordie", "Docker": "Docher", "Donations": "Donații", - "Downloading": "Descărcarea", - "EnableColorImpairedMode": "Activați modul afectat de culoare", - "EnabledHelpText": "Activați această listă pentru utilizare în Radarr", "Interval": "Interval", "Manual": "Manual", "UnableToLoadGeneralSettings": "Nu se pot încărca setările generale", @@ -340,7 +299,6 @@ "DeleteDownloadClientMessageText": "Sigur doriți să ștergeți clientul de descărcare „{0}”?", "ConnectSettings": "Setări conectare", "CouldNotConnectSignalR": "Nu s-a putut conecta la SignalR, UI nu se va actualiza", - "EnableAutomaticAdd": "Activați adăugarea automată", "GeneralSettings": "setari generale", "Grabs": "Apuca", "Port": "Port", @@ -363,6 +321,12 @@ "ApplyTagsHelpTexts4": "Înlocuire: înlocuiți etichetele cu etichetele introduse (nu introduceți etichete pentru a șterge toate etichetele)", "Automatic": "Automat", "DeleteApplicationMessageText": "Sigur doriți să ștergeți notificarea „{0}”?", - "DownloadClientUnavailable": "Clientul de descărcare nu este disponibil", - "Exception": "Excepție" + "Exception": "Excepție", + "MaintenanceRelease": "Versiune de întreținere: remedieri de erori și alte îmbunătățiri. Consultați Istoricul comiterilor Github pentru mai multe detalii", + "Filters": "Filtru", + "HistoryCleanupDaysHelpText": "Setați la 0 pentru a dezactiva curățarea automată", + "HistoryCleanupDaysHelpTextWarning": "Fișierele din coșul de reciclare mai vechi de numărul de zile selectat vor fi curățate automat", + "OnGrab": "Pe Grab", + "OnHealthIssue": "Cu privire la problema sănătății", + "TestAllIndexers": "Testați toți indexatorii" } diff --git a/src/NzbDrone.Core/Localization/Core/ru.json b/src/NzbDrone.Core/Localization/Core/ru.json index 9b3de53b1..ed612afa9 100644 --- a/src/NzbDrone.Core/Localization/Core/ru.json +++ b/src/NzbDrone.Core/Localization/Core/ru.json @@ -1,7 +1,6 @@ { "Close": "Закрыть", "CloneProfile": "Клонировать профиль", - "CloneIndexer": "Клонировать индексер", "ClientPriority": "Приоритет клиента", "Backups": "Резервные копии", "BackupRetentionHelpText": "Автоматические резервные копии старше указанного периода будут автоматически удалены", @@ -24,19 +23,13 @@ "DeleteBackupMessageText": "Вы уверены, что хотите удалить резервную копию '{0}'?", "DeleteBackup": "Удалить резервную копию", "Delete": "Удалить", - "MinutesHundredTwenty": "120 минут: {0}", - "MinutesNinety": "90 минут: {0}", - "MinutesSixty": "60 минут: {0}", - "MonoTlsCheckMessage": "Radarr Mono 4.x tls включён, удалите настройку MONO_TLS_PROVIDER=legacy", "NoLinks": "Нет ссылок", "Refresh": "Обновить", "RefreshMovie": "Обновить фильм", "RSS": "RSS", "SendAnonymousUsageData": "Отправить анонимные данные об использовании", "UnableToLoadHistory": "Не удалось загрузить историю", - "MonoVersionCheckUpgradeRecommendedMessage": "Установленная Mono версия {0} поддерживается, но рекомендуем обновить до версии {1}.", "MoreInfo": "Ещё инфо", - "MovieDetailsNextMovie": "Подробности фильма: следующий фильм", "MovieIndexScrollTop": "Индекс фильма: промотать вверх", "Size": "Размер", "OpenBrowserOnStart": "Открывать браузер при запуске", @@ -47,26 +40,21 @@ "PageSizeHelpText": "Количество показываемое на каждой страницы", "Password": "Пароль", "Peers": "Пиры", - "Pending": "В ожидании", "PendingChangesDiscardChanges": "Не применять изменения и выйти", "PendingChangesStayReview": "Оставайтесь и просмотрите изменения", "Port": "Порт", "PortNumber": "Номер порта", - "PreferredSize": "Предпочитаемый размер", - "QualityDefinitions": "Определения качества", "LogFiles": "Файлы журнала", "Details": "Подробности", "DownloadClients": "Клиенты для скачивания", "Filename": "Имя файла", "Files": "Файлы", "Filter": "Фильтр", - "Importing": "Импортирование", "IndexerStatusCheckAllClientMessage": "Все индексаторы недоступны из-за ошибок", "LogLevel": "Уровень журнала", "LogLevelTraceHelpTextWarning": "Отслеживание журнала желательно включать только на короткое время", "Logs": "Журналы", "Manual": "Ручной", - "MaximumLimits": "Максимальные ограничения", "Mechanism": "Механизм", "NoBackupsAreAvailable": "Нет резервных копий", "DeleteDownloadClientMessageText": "Вы уверены, что хотите удалить программу для скачивания '{0}'?", @@ -76,7 +64,6 @@ "SettingsShortDateFormat": "Короткий формат даты", "SettingsShowRelativeDates": "Показать относительные даты", "SettingsShowRelativeDatesHelpText": "Показывать относительные (сегодня / вчера / и т. д.) или абсолютные даты", - "DeleteIndexer": "Удалить индексер", "Docker": "Docker", "FocusSearchBox": "Поле поиска в фокусе", "Reset": "Сбросить", @@ -89,7 +76,6 @@ "AcceptConfirmationModal": "Окно подтверждения", "Today": "Сегодня", "DeleteIndexerProxyMessageText": "Вы уверены, что хотите удалить тэг '{0}'?", - "ExistingMovies": "Существующие фильм(ы)", "ExistingTag": "Существующий тэг", "Failed": "Неудачно", "IndexerProxyStatusCheckSingleClientMessage": "Индексаторы недоступны из-за ошибок: {0}", @@ -98,16 +84,13 @@ "Interval": "Интервал", "KeyboardShortcuts": "Горячие клавиши", "Language": "Язык", - "Languages": "Языки", "LastWriteTime": "Последнее время записи", "LaunchBrowserHelpText": " Открывать браузер и переходить на страницу Radarr при запуске программы.", "Level": "Уровень", - "MinimumLimits": "Минимальные ограничения", "Ok": "Ok", "AddDownloadClient": "Добавить программу для скачивания", "UpdateMechanismHelpText": "Используйте встроенную в Radarr функцию обновления или скрипт", "IndexerStatusCheckSingleClientMessage": "Индексаторы недоступны из-за ошибок: {0}", - "NoMinimumForAnyRuntime": "Нет минимума для любого времени", "NoTagsHaveBeenAddedYet": "Теги еще не добавлены", "UnableToLoadTags": "Невозможно загрузить теги", "AnalyticsEnabledHelpText": "Отправлять в Radarr информацию о использовании и ошибках. Анонимная статистика включает в себя информацию о браузере, какие страницы загружены, сообщения об ошибках, а так же операционной системе. Мы используем эту информацию для выявления ошибок, а так же для разработки нового функционала.", @@ -139,8 +122,6 @@ "Date": "Дата", "Dates": "Даты", "DBMigration": "Перенос БД", - "DelayProfile": "Профиль приостановки", - "DeleteIndexerMessageText": "Вы уверены что хотите удалить индексер '{0}'?", "DeleteNotification": "Удалить уведомление", "DeleteNotificationMessageText": "Вы уверены, что хотите удалить уведомление '{0}'?", "DeleteTag": "Удалить тэг", @@ -149,23 +130,12 @@ "Discord": "Discord", "Donations": "Пожертвования", "DownloadClient": "Загрузчик", - "DownloadClientCheckNoneAvailableMessage": "Ни один загрузчик не доступен", - "DownloadClientCheckUnableToCommunicateMessage": "Невозможно связаться с {0}.", "DownloadClientSettings": "Настройки клиента скачиваний", "DownloadClientStatusCheckAllClientMessage": "Все клиенты для скачивания недоступны из-за ошибок", "DownloadClientStatusCheckSingleClientMessage": "Клиенты для скачивания недоступны из-за ошибок: {0}", - "DownloadClientUnavailable": "Программа для скачивания недоступна", - "Downloading": "Скачивается", - "EnableAutoHelpText": "Если включено, то Radarr автоматически добавит фильмы из списка", - "EnableAutomaticAdd": "Включить автоматическое добавление", "EnableAutomaticSearch": "Включить автоматический поиск", "EnableAutomaticSearchHelpText": "Будет использовано для автоматических поисков через интерфейс или Radarr", - "EnableAutomaticSearchHelpTextWarning": "Будет использовано при автоматических поисках", - "EnableColorImpairedModeHelpText": "Стиль изменён чтобы слабовидящие лучше различали цвета", - "EnableCompletedDownloadHandlingHelpText": "Автоматически импортировать завершенные скачивания", "Enabled": "Включено", - "EnabledHelpText": "Использовать этот лист в Radarr", - "EnableHelpText": "Создавать файл метаданных для это типа метаданных", "EnableInteractiveSearch": "Включить интерактивный поиск", "EnableRss": "Включить RSS", "Fixed": "Исправлено", @@ -197,15 +167,11 @@ "Message": "Сообщение", "MIA": "MIA", "Mode": "Режим", - "MonoVersion": "Моно версия", - "MovieDetailsPreviousMovie": "Подробности фильма: предыдущий фильм", "MovieIndexScrollBottom": "Индекс фильма: промотать в низ", - "Movies": "Фильмы", "Name": "Имя", "New": "Новый", "NoChanges": "Нет изменений", "NoLeaveIt": "Нет, оставить", - "NoLimitForAnyRuntime": "Нет ограничений для любого времени", "NoLogFiles": "Нет файлов журнала", "NoUpdatesAreAvailable": "Нет обновлений", "OAuthPopupMessage": "Ваш браузер блокирует всплывающие окна", @@ -224,7 +190,6 @@ "ProxyType": "Тип прокси", "ProxyUsernameHelpText": "Нужно ввести имя пользователя и пароль только если они необходимы. В противном случае оставьте их пустыми.", "PtpOldSettingsCheckMessage": "Следующие индексаторы PassThePopcorn устарели и должны быть обновлены: {0}", - "QualitySettings": "Настройки качества", "Queue": "Очередь", "ReadTheWikiForMoreInformation": "Прочтите Wiki для получения дополнительной информации", "ReleaseBranchCheckOfficialBranchMessage": "Ветка {0} не является допустимой веткой выпуска Radarr, вы не будете получать обновления", @@ -239,7 +204,6 @@ "RestartRequiredHelpTextWarning": "Для вступления в силу требуется перезапуск", "Restore": "Восстановить", "RestoreBackup": "Восстановить из резервной копии", - "Restrictions": "Ограничения", "Result": "Результат", "Retention": "Удержание", "RSSIsNotSupportedWithThisIndexer": "RSS не поддерживается этим индексатором", @@ -302,9 +266,7 @@ "UnableToLoadBackups": "Невозможно загрузить резервные копии", "UnableToLoadDownloadClients": "Невозможно загрузить загрузчики", "UnableToLoadGeneralSettings": "Невозможно загрузить общие настройки", - "UnableToLoadIndexers": "Не удалось загрузить индексаторы", "UnableToLoadNotifications": "Невозможно загрузить уведомления", - "UnableToLoadQualityDefinitions": "Не удалось загрузить определения качества", "UnableToLoadUISettings": "Не удалось загрузить настройки пользовательского интерфейса", "UnsavedChanges": "Несохраненные изменения", "UnselectAll": "Снять все выделения", @@ -323,8 +285,6 @@ "AddingTag": "Добавить ярлык", "SSLPort": "SSL порт", "UILanguageHelpText": "Язык, который Radarr будет использовать для пользовательского интерфейса", - "EnableInteractiveSearchHelpTextWarning": "Поиск не поддерживается с этим индексатором", - "EnableMediaInfoHelpText": "Извлекать из файлов видео разрешение, длительность и информацию о кодеках. Это может привести к высокой активности диска и сети во время сканирования.", "EnableSslHelpText": " Требуется перезапуск от администратора", "ErrorLoadingContents": "Ошибка при загрузке содержимого", "Events": "События", @@ -341,7 +301,6 @@ "ConnectionLostAutomaticMessage": "Radarr попытается соединиться автоматически или нажмите кнопку внизу.", "DeleteApplicationMessageText": "Вы уверены, что хотите удалить уведомление '{0}'?", "DeleteDownloadClient": "Удалить программу для скачивания", - "EnableColorImpairedMode": "Версия для слабовидящих", "EnableInteractiveSearchHelpText": "Будет использовано при автоматических поисках", "Error": "Ошибка", "NoChange": "Нет изменений", @@ -357,5 +316,17 @@ "ApplicationStatusCheckSingleClientMessage": "Листы недоступны из-за ошибок: {0}", "ApplyTagsHelpTexts1": "Как добавить ярлыки к выбранным фильмам", "ApplyTagsHelpTexts2": "Добавить: добавить ярлыки к существующему списку", - "EditIndexer": "Редактировать индексатор" + "EditIndexer": "Редактировать индексатор", + "ConnectionLostMessage": "Radarr потерял связь с сервером и его необходимо перезагрузить, чтобы восстановить работоспособность.", + "MaintenanceRelease": "Техническая версия: исправления ошибок и другие улучшения. См. Историю коммитов Github для более подробной информации", + "Filters": "Фильтры", + "HistoryCleanupDaysHelpText": "Установите 0, чтобы отключить автоматическую очистку", + "HistoryCleanupDaysHelpTextWarning": "Файлы в корзине старше указанного количества дней будут очищены автоматически", + "OnApplicationUpdateHelpText": "О обновлении приложения", + "OnGrab": "При захвате", + "OnHealthIssue": "О проблемах в системе", + "OnApplicationUpdate": "О обновлении приложения", + "TestAllIndexers": "Тестировать все индексаторы", + "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent, представленный приложением, который вызывает API", + "NotificationTriggersHelpText": "Выберите, какие события должны вызвать это уведомление" } diff --git a/src/NzbDrone.Core/Localization/Core/sk.json b/src/NzbDrone.Core/Localization/Core/sk.json index 3769e165e..ac09f2be5 100644 --- a/src/NzbDrone.Core/Localization/Core/sk.json +++ b/src/NzbDrone.Core/Localization/Core/sk.json @@ -34,7 +34,6 @@ "BranchUpdateMechanism": "Vetva používaná externým mechanizmom aktualizácie", "DeleteApplicationMessageText": "Naozaj chcete zmazať značku formátu {0} ?", "DeleteBackupMessageText": "Naozaj chcete zmazať značku formátu {0} ?", - "DeleteIndexerMessageText": "Naozaj chcete zmazať značku formátu {0} ?", "DeleteIndexerProxyMessageText": "Naozaj chcete zmazať značku formátu {0} ?", "DeleteNotificationMessageText": "Naozaj chcete zmazať značku formátu {0} ?", "DeleteTagMessageText": "Naozaj chcete zmazať značku formátu {0} ?", diff --git a/src/NzbDrone.Core/Localization/Core/sv.json b/src/NzbDrone.Core/Localization/Core/sv.json index 2af3172b7..9eca93d66 100644 --- a/src/NzbDrone.Core/Localization/Core/sv.json +++ b/src/NzbDrone.Core/Localization/Core/sv.json @@ -1,6 +1,5 @@ { "About": "Om", - "Languages": "Språk", "Language": "Språk", "IndexerStatusCheckSingleClientMessage": "Indexerare otillgängliga på grund av fel: {0}", "IndexerStatusCheckAllClientMessage": "Samtliga indexerare otillgängliga på grund av fel", @@ -18,8 +17,6 @@ "DownloadClientStatusCheckSingleClientMessage": "Otillgängliga nedladdningsklienter på grund av misslyckade anslutningsförsök: {0}", "DownloadClientStatusCheckAllClientMessage": "Samtliga nedladdningsklienter är otillgängliga på grund av misslyckade anslutningsförsök", "DownloadClients": "Nedladdningsklienter", - "DownloadClientCheckUnableToCommunicateMessage": "Kommunikation med {0} ej möjlig.", - "DownloadClientCheckNoneAvailableMessage": "Ingen nedladdningsklient tillgänglig", "Delete": "Radera", "Dates": "Datum", "Date": "Datum", @@ -33,8 +30,6 @@ "Analytics": "Analys", "All": "Samtliga", "MoreInfo": "Mer info", - "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls workaround är aktiverad, överväg att ta bort \"MONO_TLS_PROVIDER=legacy environment\"-alternativet", - "MonoNotNetCoreCheckMessage": "Var vänlig uppgradera till .NET Core-versionen av Prowlarr", "Logging": "Loggning", "LogFiles": "Loggfiler", "View": "Vy", @@ -61,13 +56,10 @@ "Search": "Sök", "Scheduled": "Schemalagt", "SaveChanges": "Spara ändringar", - "Restrictions": "Restriktioner", "RestoreBackup": "Återställ säkerhetskopia", "ReleaseBranchCheckOfficialBranchMessage": "Gren {0} är inte en giltig gren av Prowlarr, du kommer ej erhålla uppdateringar", - "ReleaseBranchCheckPreviousVersionMessage": "Gren {0} är ämnad en tidigare version av Prowlarr, välj gren 'Aphrodite' för ytterligare uppdateringar", "Refresh": "Uppdatera", "Queue": "Kö", - "QualityDefinitions": "Kvalitetsdefinitioner", "PtpOldSettingsCheckMessage": "Följande PassThePopcorn-indexerare har inaktuella inställningar och bör uppdateras: {0}", "ProxyCheckResolveIpMessage": "Misslyckades att slå upp IP-adressen till konfigurerad proxyvärd {0}", "ProxyCheckFailedToTestMessage": "Test av proxy misslyckades: {0}", @@ -91,7 +83,6 @@ "Options": "Alternativ", "NoChanges": "Inga ändringar", "NoChange": "Ingen förändring", - "Movies": "Filmer", "Warn": "Varna", "Type": "Typ", "Title": "Titel", @@ -129,10 +120,8 @@ "SystemTimeCheckMessage": "Systemklockan går fel med mer än en dag. Schemalagda uppgifter kan få problem att köras innan tiden är korrigerad", "HomePage": "Hemsida", "IndexerPriority": "Indexerprioritet", - "Pending": "I väntan på", "Reddit": "Reddit", "IndexerProxyStatusCheckAllClientMessage": "Samtliga indexerare otillgängliga på grund av fel", - "MovieDetailsNextMovie": "Filmdetaljer: Nästa film", "NoLinks": "Inga länkar", "NoTagsHaveBeenAddedYet": "Inga taggar har lagts till ännu", "NotificationTriggers": "Meddelandeutlösare", @@ -159,11 +148,8 @@ "Yesterday": "Igår", "ShowSearchHelpText": "Visa sökknappen på svävaren", "ConnectSettings": "Anslutnings inställningar", - "Downloading": "Laddar Ned", "EditIndexer": "Redigera indexerare", "EnableAutomaticSearchHelpText": "Används när automatiska sökningar utförs via användargränssnittet eller av Radarr", - "EnableColorImpairedMode": "Aktivera färgskadat läge", - "EnableMediaInfoHelpText": "Extrahera videoinformation som upplösning, runtime och codec-information från filer. Detta kräver att Radarr läser delar av filen som kan orsaka hög disk- eller nätverksaktivitet under skanningar.", "Password": "Lösenord", "Port": "Port", "Add": "Lägg till", @@ -175,16 +161,13 @@ "Retention": "Bibehållande", "ApplyTagsHelpTexts2": "Lägg till: Lägg till taggarna i den befintliga listan med taggar", "CertificateValidation": "Validering av Certifikat", - "CloneIndexer": "Klona indexerare", "RSSIsNotSupportedWithThisIndexer": "RSS stöds inte av denna indexerare", "SaveSettings": "Spara inställningar", "ScriptPath": "Skriptsökväg", "CouldNotConnectSignalR": "Kunde inte ansluta till SignalR, UI uppdateras inte", "DeleteTag": "Radera Tagg", "Hostname": "Värdnamn", - "MinutesSixty": "60 minuter: {0}", "Mode": "Läge", - "NoMinimumForAnyRuntime": "Inget minimum för någon körtid", "Docker": "Docker", "Enable": "Aktivera", "ProxyPasswordHelpText": "Du behöver bara ange ett användarnamn och lösenord om det krävs. Lämna dem tomma annars.", @@ -193,18 +176,11 @@ "Branch": "Gren", "CloseCurrentModal": "Stäng nuvarande modal", "DBMigration": "DB Migration", - "DelayProfile": "Fördröjande profil", "DeleteApplicationMessageText": "Är du säker på att du vill radera aviseringen '{0}'?", - "DeleteIndexer": "Radera indexerare", "Discord": "Discord", "Donations": "Donationer", "DownloadClientSettings": "Inställningar för Nedladdningsklient", - "EnableCompletedDownloadHandlingHelpText": "Importera automatiskt färdiga nedladdningar från nedladdningsklienten", - "EnabledHelpText": "Aktivera den här listan för användning i Radarr", "EnableRss": "Aktivera RSS", - "MinimumLimits": "Minsta gränser", - "MinutesNinety": "90 minuter: {0}", - "MovieDetailsPreviousMovie": "Filmdetaljer: Föregående film", "MovieIndexScrollBottom": "Filmindex: Skrolla ner", "PendingChangesDiscardChanges": "Kassera ändringar och lämna", "ProxyType": "Proxy-typ", @@ -222,7 +198,6 @@ "LogLevelTraceHelpTextWarning": "Spårloggning bör endast aktiveras tillfälligt", "DeleteIndexerProxyMessageText": "Är du säker på att du vill radera taggen '{0}'?", "DeleteNotification": "Radera Avisering", - "DownloadClientUnavailable": "Nedladdningsklient är otillgänglig", "Fixed": "Fast", "FocusSearchBox": "Fokus sökruta", "IncludeHealthWarningsHelpText": "Inkludera hälsovarningar", @@ -262,19 +237,12 @@ "DeleteNotificationMessageText": "Är du säker på att du vill radera aviseringen '{0}'?", "DeleteTagMessageText": "Är du säker på att du vill radera taggen '{0}'?", "Disabled": "Inaktiverad", - "EnableAutoHelpText": "Om det är aktiverat läggs filmer automatiskt till Radarr från den här listan", - "EnableAutomaticAdd": "Aktivera Automstisk Tillägg", "EnableAutomaticSearch": "Aktivera Automatisk Sökning", - "EnableAutomaticSearchHelpTextWarning": "Används när interaktiv sökning används", - "EnableColorImpairedModeHelpText": "Ändrad stil för att göra det möjligt för användare med färgstörning att bättre skilja färgkodad information", - "EnableHelpText": "Aktivera metadatafilskapande för denna metadatatyp", "EnableInteractiveSearch": "Aktivera interaktiv sökning", "EnableInteractiveSearchHelpText": "Används när interaktiv sökning används", - "EnableInteractiveSearchHelpTextWarning": "Sökning stöds ej av denna indexerare", "EnableSSL": "Aktivera SSL", "EnableSslHelpText": " Kräver omstart som administratör för att träda i kraft", "ErrorLoadingContents": "Fel vid inläsning av innehåll", - "ExistingMovies": "Befintliga film(er)", "ExistingTag": "Befintlig tagg", "FeatureRequests": "Funktionsbegäranden", "ForMoreInformationOnTheIndividualDownloadClients": "Klicka på informationsknapparna för mer information om de enskilda nedladdningsklienterna.", @@ -283,7 +251,6 @@ "HiddenClickToShow": "Dold, klicka för att visa", "IgnoredAddresses": "Ignorerade adresser", "IllRestartLater": "Jag startar om senare", - "Importing": "Importerar", "IndexerLongTermStatusCheckAllClientMessage": "Alla indexerare är inte tillgängliga på grund av fel i mer än 6 timmar", "IndexerLongTermStatusCheckSingleClientMessage": "Indexatorer är inte tillgängliga på grund av misslyckanden i mer än sex timmar: {0}", "IndexerPriorityHelpText": "Indexeringsprioritet från 1 (högst) till 50 (lägst). Standard: 25.", @@ -292,11 +259,8 @@ "LaunchBrowserHelpText": " Öppna en webbläsare och navigera till Radarr-hemsidan vid appstart.", "Logs": "Loggar", "Manual": "Manuell", - "MaximumLimits": "Maximala gränser", "Mechanism": "Mekanism", "MIA": "MIA", - "MinutesHundredTwenty": "120 minuter: {0}", - "MonoVersionCheckUpgradeRecommendedMessage": "För närvarande installerad monoversion {0} stöds men uppgradering till {1} rekommenderas.", "MovieIndexScrollTop": "Filmindex: Skrolla upp", "NoUpdatesAreAvailable": "Inga uppdateringar är tillgängliga", "OnHealthIssueHelpText": "På hälsofrågan", @@ -307,12 +271,10 @@ "PendingChangesMessage": "Du har osparade ändringar, är du säker på att du vill lämna sidan?", "PendingChangesStayReview": "Bo och granska ändringar", "PortNumber": "Portnummer", - "PreferredSize": "Önskad storlek", "Priority": "Prioritet", "PriorityHelpText": "Prioritera flera nedladdningsklienter. Round-Robin används för kunder med samma prioritet.", "ProxyBypassFilterHelpText": "Använd ',' som separator och '*.' som ett jokertecken för underdomäner", "ProxyUsernameHelpText": "Du behöver bara ange ett användarnamn och lösenord om det krävs. Lämna dem tomma annars.", - "QualitySettings": "Kvalitetsalternativ", "ReadTheWikiForMoreInformation": "Läs Wiki för mer information", "RemovedFromTaskQueue": "Borttagen från uppgiftskön", "RemovingTag": "Ta bort taggen", @@ -340,15 +302,11 @@ "UILanguage": "UI-språk", "UnableToAddANewApplicationPleaseTryAgain": "Det gick inte att lägga till ett nytt meddelande, försök igen.", "UnableToLoadBackups": "Det gick inte att ladda säkerhetskopior", - "DeleteIndexerMessageText": "Är du säker på att du vill ta bort indexeraren '{0}'?", "UnableToAddANewIndexerProxyPleaseTryAgain": "Inte möjligt att lägga till en ny indexerare, var god försök igen.", "UnableToLoadGeneralSettings": "Det går inte att läsa in allmänna inställningar", - "UnableToLoadIndexers": "Det går inte att ladda indexerare", "New": "Ny", "NoBackupsAreAvailable": "Inga säkerhetskopior tillgängliga", "NoLeaveIt": "Nej, lämna det", - "NoLimitForAnyRuntime": "Ingen gräns för någon körtid", - "UnableToLoadQualityDefinitions": "Det går inte att ladda kvalitetsdefinitioner", "AuthenticationMethodHelpText": "Kräva användarnamn och lösenord för att komma åt Prowlarr", "AutomaticSearch": "Automatisk sökning", "BackupFolderHelpText": "Relativa sökvägar finns under Prowlarr's AppData-katalog", @@ -361,7 +319,6 @@ "ApiKey": "API-nyckel", "ApplicationStatusCheckAllClientMessage": "Samtliga listor otillgängliga på grund av fel", "LogLevel": "Loggnivå", - "MonoVersion": "Mono version", "NoLogFiles": "Inga loggfiler", "UnableToLoadDownloadClients": "Det gick inte att ladda nedladdningsklienter", "UpdateMechanismHelpText": "Använd Radarrs inbyggda uppdaterare eller ett skript", @@ -439,5 +396,11 @@ "AppProfiles": "App Profiler", "AppProfileInUse": "App Profil i användning", "AppProfileDeleteConfirm": "Är du säker på att du vill radera {0}?", - "Applications": "Applikationer" + "Applications": "Applikationer", + "Filters": "Filter", + "HistoryCleanupDaysHelpText": "Ställ in på 0 för att inaktivera automatisk rensning", + "HistoryCleanupDaysHelpTextWarning": "Filer i papperskorgen som är äldre än det valda antalet dagar rensas automatiskt", + "OnGrab": "Vid hämtning", + "OnHealthIssue": "På hälsofrågan", + "TestAllIndexers": "Testa samtliga indexerare" } diff --git a/src/NzbDrone.Core/Localization/Core/th.json b/src/NzbDrone.Core/Localization/Core/th.json index 2ecf0e205..87f40407c 100644 --- a/src/NzbDrone.Core/Localization/Core/th.json +++ b/src/NzbDrone.Core/Localization/Core/th.json @@ -11,11 +11,7 @@ "Analytics": "การวิเคราะห์", "Backup": "การสำรองข้อมูล", "BackupFolderHelpText": "เส้นทางสัมพัทธ์จะอยู่ภายใต้ไดเรกทอรี AppData ของ Radarr", - "EnableAutoHelpText": "หากเปิดใช้งานภาพยนตร์จะถูกเพิ่มลงใน Radarr โดยอัตโนมัติจากรายการนี้", - "EnableAutomaticAdd": "เปิดใช้งานการเพิ่มอัตโนมัติ", - "Importing": "กำลังนำเข้า", "IncludeHealthWarningsHelpText": "รวมคำเตือนด้านสุขภาพ", - "Pending": "รอดำเนินการ", "PortNumber": "หมายเลขพอร์ต", "Restart": "เริ่มต้นใหม่", "SSLCertPathHelpText": "พา ธ ไปยังไฟล์ pfx", @@ -26,20 +22,10 @@ "InteractiveSearch": "การค้นหาแบบโต้ตอบ", "LastWriteTime": "เวลาเขียนล่าสุด", "LaunchBrowserHelpText": " เปิดเว็บเบราว์เซอร์และไปที่หน้าแรกของ Radarr เมื่อเริ่มแอป", - "MinimumLimits": "ขีด จำกัด ขั้นต่ำ", - "MinutesHundredTwenty": "120 นาที: {0}", - "MinutesNinety": "90 นาที: {0}", - "MinutesSixty": "60 นาที: {0}", "Mode": "โหมด", - "MonoTlsCheckMessage": "วิธีแก้ปัญหา Radarr Mono 4.x tls ยังคงเปิดใช้งานอยู่ให้พิจารณาลบตัวเลือก MONO_TLS_PROVIDER = สภาพแวดล้อมเดิม", - "MonoVersion": "เวอร์ชันโมโน", - "MonoVersionCheckUpgradeRecommendedMessage": "ปัจจุบันรองรับเวอร์ชัน Mono {0} ที่ติดตั้งแล้ว แต่แนะนำให้อัปเกรดเป็น {1}", "MoreInfo": "ข้อมูลเพิ่มเติม", - "MovieDetailsNextMovie": "รายละเอียดภาพยนตร์: ภาพยนตร์เรื่องต่อไป", - "MovieDetailsPreviousMovie": "รายละเอียดภาพยนตร์: ภาพยนตร์เรื่องก่อนหน้า", "MovieIndexScrollBottom": "ดัชนีภาพยนตร์: เลื่อนด้านล่าง", "MovieIndexScrollTop": "ดัชนีภาพยนตร์: เลื่อนด้านบน", - "Movies": "ภาพยนตร์", "New": "ใหม่", "NoLinks": "ไม่มีลิงค์", "OpenThisModal": "เปิด Modal นี้", @@ -99,8 +85,6 @@ "Message": "ข้อความ", "NoUpdatesAreAvailable": "ไม่มีการอัปเดต", "PtpOldSettingsCheckMessage": "ตัวสร้างดัชนี PassThePopcorn ต่อไปนี้ได้เลิกใช้การตั้งค่าและควรได้รับการอัปเดต: {0}", - "QualityDefinitions": "คำจำกัดความคุณภาพ", - "QualitySettings": "การตั้งค่าคุณภาพ", "Queue": "คิว", "ReadTheWikiForMoreInformation": "อ่าน Wiki สำหรับข้อมูลเพิ่มเติม", "Reddit": "Reddit", @@ -121,10 +105,8 @@ "UnableToAddANewNotificationPleaseTryAgain": "ไม่สามารถเพิ่มการแจ้งเตือนใหม่โปรดลองอีกครั้ง", "UnableToLoadBackups": "ไม่สามารถโหลดข้อมูลสำรอง", "UnableToLoadNotifications": "ไม่สามารถโหลดการแจ้งเตือน", - "UnableToLoadQualityDefinitions": "ไม่สามารถโหลดคำจำกัดความคุณภาพ", "ApplicationStatusCheckAllClientMessage": "รายการทั้งหมดไม่พร้อมใช้งานเนื่องจากความล้มเหลว", "ApplicationStatusCheckSingleClientMessage": "รายการไม่พร้อมใช้งานเนื่องจากความล้มเหลว: {0}", - "DeleteIndexer": "ลบ Indexer", "DeleteNotification": "ลบการแจ้งเตือน", "IgnoredAddresses": "ที่อยู่ที่ถูกละเว้น", "Level": "ระดับ", @@ -154,7 +136,6 @@ "CancelPendingTask": "แน่ใจไหมว่าต้องการยกเลิกงานที่รอดำเนินการนี้", "ChangeHasNotBeenSavedYet": "ยังไม่ได้บันทึกการเปลี่ยนแปลง", "Clear": "ชัดเจน", - "CloneIndexer": "Clone Indexer", "CloneProfile": "โปรไฟล์โคลน", "Close": "ปิด", "ConnectionLost": "ขาดการเชื่อมต่อ", @@ -167,38 +148,25 @@ "Date": "วันที่", "Dates": "วันที่", "DBMigration": "การย้ายฐานข้อมูล", - "DelayProfile": "โปรไฟล์ล่าช้า", "Delete": "ลบ", "DeleteApplicationMessageText": "แน่ใจไหมว่าต้องการลบการแจ้งเตือน \"{0}\"", "DeleteBackup": "ลบข้อมูลสำรอง", "DeleteBackupMessageText": "แน่ใจไหมว่าต้องการลบข้อมูลสำรอง \"{0}\"", "DeleteDownloadClient": "ลบไคลเอนต์ดาวน์โหลด", - "DeleteIndexerMessageText": "แน่ใจไหมว่าต้องการลบตัวสร้างดัชนี \"{0}\"", "Donations": "การบริจาค", "DownloadClient": "ดาวน์โหลดไคลเอนต์", - "DownloadClientCheckNoneAvailableMessage": "ไม่มีไคลเอนต์ดาวน์โหลด", - "DownloadClientCheckUnableToCommunicateMessage": "ไม่สามารถสื่อสารกับ {0}", "DownloadClients": "ดาวน์โหลดไคลเอนต์", "DownloadClientSettings": "ดาวน์โหลด Client Settings", "DownloadClientStatusCheckAllClientMessage": "ไคลเอนต์ดาวน์โหลดทั้งหมดไม่สามารถใช้งานได้เนื่องจากความล้มเหลว", "DownloadClientStatusCheckSingleClientMessage": "ดาวน์โหลดไคลเอ็นต์ไม่ได้เนื่องจากความล้มเหลว: {0}", - "DownloadClientUnavailable": "ไม่สามารถดาวน์โหลดไคลเอนต์ได้", - "Downloading": "กำลังดาวน์โหลด", "Edit": "แก้ไข", "EditIndexer": "แก้ไข Indexer", "Enable": "เปิดใช้งาน", "EnableAutomaticSearch": "เปิดใช้งานการค้นหาอัตโนมัติ", "EnableAutomaticSearchHelpText": "จะใช้เมื่อทำการค้นหาอัตโนมัติผ่าน UI หรือโดย Radarr", - "EnableAutomaticSearchHelpTextWarning": "จะใช้เมื่อใช้การค้นหาแบบโต้ตอบ", - "EnableColorImpairedMode": "เปิดใช้งานโหมดไร้สี", - "EnableColorImpairedModeHelpText": "รูปแบบที่เปลี่ยนแปลงเพื่อให้ผู้ใช้ที่มีความบกพร่องทางสีแยกแยะข้อมูลรหัสสีได้ดีขึ้น", - "EnableCompletedDownloadHandlingHelpText": "นำเข้าการดาวน์โหลดที่เสร็จสมบูรณ์โดยอัตโนมัติจากไคลเอนต์ดาวน์โหลด", "Enabled": "เปิดใช้งาน", - "EnabledHelpText": "เปิดใช้รายการนี้เพื่อใช้ใน Radarr", - "EnableHelpText": "เปิดใช้งานการสร้างไฟล์ข้อมูลเมตาสำหรับประเภทข้อมูลเมตานี้", "EnableInteractiveSearch": "เปิดใช้งานการค้นหาแบบโต้ตอบ", "EnableInteractiveSearchHelpText": "จะใช้เมื่อใช้การค้นหาแบบโต้ตอบ", - "EnableInteractiveSearchHelpTextWarning": "ตัวสร้างดัชนีนี้ไม่รองรับการค้นหา", "ForMoreInformationOnTheIndividualDownloadClients": "สำหรับข้อมูลเพิ่มเติมเกี่ยวกับไคลเอนต์ดาวน์โหลดแต่ละรายการคลิกที่ปุ่มข้อมูล", "General": "ทั่วไป", "GeneralSettings": "การตั้งค่าทั่วไป", @@ -226,14 +194,11 @@ "NoChange": "ไม่มีการเปลี่ยนแปลง", "NoChanges": "ไม่มีการเปลี่ยนแปลง", "NoLeaveIt": "ไม่ปล่อยไว้", - "NoLimitForAnyRuntime": "ไม่มีขีด จำกัด สำหรับรันไทม์ใด ๆ", - "NoMinimumForAnyRuntime": "ไม่มีขั้นต่ำสำหรับรันไทม์ใด ๆ", "NoTagsHaveBeenAddedYet": "ยังไม่มีการเพิ่มแท็ก", "OAuthPopupMessage": "เบราว์เซอร์ของคุณบล็อกป๊อปอัป", "OnHealthIssueHelpText": "เกี่ยวกับปัญหาสุขภาพ", "OpenBrowserOnStart": "เปิดเบราว์เซอร์เมื่อเริ่มต้น", "Port": "ท่าเรือ", - "PreferredSize": "ขนาดที่ต้องการ", "Presets": "ค่าที่ตั้งไว้ล่วงหน้า", "Priority": "ลำดับความสำคัญ", "PriorityHelpText": "จัดลำดับความสำคัญของไคลเอนต์ดาวน์โหลดหลายรายการ Round-Robin ใช้สำหรับลูกค้าที่มีลำดับความสำคัญเดียวกัน", @@ -244,7 +209,6 @@ "ProxyCheckBadRequestMessage": "ไม่สามารถทดสอบพร็อกซี StatusCode: {0}", "Restore": "คืนค่า", "RestoreBackup": "คืนค่าการสำรองข้อมูล", - "Restrictions": "ข้อ จำกัด", "Retention": "การเก็บรักษา", "RSS": "RSS", "SendAnonymousUsageData": "ส่งข้อมูลการใช้งานแบบไม่ระบุตัวตน", @@ -258,7 +222,6 @@ "UpdateMechanismHelpText": "ใช้ตัวอัปเดตหรือสคริปต์ในตัวของ Radarr", "UnableToLoadGeneralSettings": "ไม่สามารถโหลดการตั้งค่าทั่วไป", "UnableToLoadHistory": "ไม่สามารถโหลดประวัติ", - "UnableToLoadIndexers": "ไม่สามารถโหลด Indexers", "UnableToLoadTags": "ไม่สามารถโหลดแท็ก", "UnableToLoadUISettings": "ไม่สามารถโหลดการตั้งค่า UI", "UnsavedChanges": "การเปลี่ยนแปลงที่ไม่ได้บันทึก", @@ -303,24 +266,20 @@ "Cancel": "ยกเลิก", "NoLogFiles": "ไม่มีไฟล์บันทึก", "Details": "รายละเอียด", - "EnableMediaInfoHelpText": "ดึงข้อมูลวิดีโอเช่นความละเอียดรันไทม์และข้อมูลตัวแปลงสัญญาณออกจากไฟล์ สิ่งนี้ต้องใช้ Radarr เพื่ออ่านบางส่วนของไฟล์ซึ่งอาจทำให้เกิดดิสก์หรือกิจกรรมเครือข่ายสูงระหว่างการสแกน", "EnableRss": "เปิดใช้ RSS", "EnableSslHelpText": " ต้องรีสตาร์ทในฐานะผู้ดูแลระบบจึงจะมีผล", "Error": "ข้อผิดพลาด", "ErrorLoadingContents": "เกิดข้อผิดพลาดในการโหลดเนื้อหา", "Exception": "ข้อยกเว้น", - "ExistingMovies": "ภาพยนตร์ที่มีอยู่", "Interval": "ช่วงเวลา", "KeyboardShortcuts": "แป้นพิมพ์ลัด", "Language": "ภาษา", - "Languages": "ภาษา", "LogFiles": "ล็อกไฟล์", "Logging": "การบันทึก", "LogLevel": "ระดับบันทึก", "LogLevelTraceHelpTextWarning": "ควรเปิดใช้งานการบันทึกการติดตามชั่วคราวเท่านั้น", "Logs": "บันทึก", "Manual": "คู่มือ", - "MaximumLimits": "ขีด จำกัด สูงสุด", "Mechanism": "กลไก", "Ok": "ตกลง", "ResetAPIKey": "รีเซ็ตคีย์ API", @@ -357,5 +316,12 @@ "ReleaseStatus": "สถานะการเปิดตัว", "SaveSettings": "บันทึกการตั้งค่า", "Branch": "สาขา", - "Sort": "จัดเรียง" + "Sort": "จัดเรียง", + "HistoryCleanupDaysHelpTextWarning": "ไฟล์ในถังรีไซเคิลที่เก่ากว่าจำนวนวันที่เลือกจะถูกล้างโดยอัตโนมัติ", + "MaintenanceRelease": "รุ่นการบำรุงรักษา: การแก้ไขข้อบกพร่องและการปรับปรุงอื่น ๆ ดู Github Commit History สำหรับรายละเอียดเพิ่มเติม", + "Filters": "กรอง", + "HistoryCleanupDaysHelpText": "ตั้งค่าเป็น 0 เพื่อปิดใช้งานการล้างข้อมูลอัตโนมัติ", + "OnGrab": "บน Grab", + "OnHealthIssue": "เกี่ยวกับปัญหาสุขภาพ", + "TestAllIndexers": "ทดสอบดัชนีทั้งหมด" } diff --git a/src/NzbDrone.Core/Localization/Core/tr.json b/src/NzbDrone.Core/Localization/Core/tr.json index 0330a7025..af4ead78e 100644 --- a/src/NzbDrone.Core/Localization/Core/tr.json +++ b/src/NzbDrone.Core/Localization/Core/tr.json @@ -44,23 +44,16 @@ "Security": "Güvenlik", "Search": "Ara", "SaveChanges": "Değişiklikleri Kaydet", - "Restrictions": "Kısıtlamalar", "ReleaseStatus": "Yayın Durumu", - "ReleaseBranchCheckPreviousVersionMessage": "Dal {0}, Prowlarr'ın önceki bir versiyon için, dalı daha fazla güncelleme için 'Aphrodite' olarak ayarlayın", "ReleaseBranchCheckOfficialBranchMessage": "Dal {0} geçerli bir Prowlarr sürüm dalı değil, güncelleme almayacaksınız", "Refresh": "Yenile", "Queue": "Sıra", - "QualityDefinitions": "Kalite Tanımları", "Protocol": "Protokol", "Options": "Seçenekler", "NoChanges": "Değişiklikler yok", "NoChange": "Değişiklik yok", - "Movies": "Filmler", "MoreInfo": "Daha fazla bilgi", - "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls geçici çözümü hala etkin, MONO_TLS_PROVIDER=legacy seçeneğini kaldırmayı düşünün", - "MonoNotNetCoreCheckMessage": "Lütfen Prowlarr'ın .NET Core sürümüne güncelle", "LastWriteTime": "Son Yazma Zamanı", - "Languages": "Diller", "Language": "Dil", "History": "Tarih", "HideAdvanced": "Gelişmiş'i Gizle", @@ -69,7 +62,6 @@ "Filter": "Filtre", "Failed": "Başarısız oldu", "Edit": "Düzenle", - "DownloadClientCheckUnableToCommunicateMessage": "{0} ile iletişim kurulamıyor.", "CustomFilters": "Özel Filtreler", "ConnectSettingsSummary": "Bildirimler, medya sunucularına/oynatıcılara bağlantılar ve özel komut kodları", "Analytics": "Analitik", @@ -83,14 +75,12 @@ "HiddenClickToShow": "Gizli, göstermek için tıklayın", "LogLevelTraceHelpTextWarning": "İzleme günlük kaydı yalnızca geçici olarak etkinleştirilmelidir", "Peers": "Akranlar", - "Pending": "Bekliyor", "Presets": "Ön ayarlar", "RemoveFilter": "Filtreyi kaldır", "SettingsEnableColorImpairedMode": "Renk Bozukluğu Modunu Etkinleştir", "ShowSearchHelpText": "Fareyle üzerine gelindiğinde arama düğmesini göster", "Shutdown": "Kapat", "TableOptions": "Masa Seçenekleri", - "UnableToLoadIndexers": "Dizinleyiciler yüklenemiyor", "UnableToLoadTags": "Etiketler yüklenemiyor", "UnsavedChanges": "Kaydedilmemiş Değişiklikler", "ApplyTagsHelpTexts4": "Değiştir: Etiketleri girilen etiketlerle değiştirin (tüm etiketleri temizlemek için hiçbir etiket girmeyin)", @@ -104,7 +94,6 @@ "PendingChangesStayReview": "Kalın ve değişiklikleri inceleyin", "Port": "Liman", "PortNumber": "Port numarası", - "PreferredSize": "Tercih Edilen Boyut", "RestoreBackup": "Yedeği Geri Yükle", "RSS": "RSS", "Save": "Kayıt etmek", @@ -120,7 +109,6 @@ "BindAddressHelpText": "Tüm arayüzler için geçerli IP4 adresi veya '*'", "ConnectSettings": "Bağlantı Ayarları", "DBMigration": "DB Geçişi", - "DelayProfile": "Gecikme Profilleri", "DeleteApplicationMessageText": "'{0}' bildirimini silmek istediğinizden emin misiniz?", "DeleteBackup": "Yedeklemeyi Sil", "DeleteBackupMessageText": "'{0}' yedeğini silmek istediğinizden emin misiniz?", @@ -135,9 +123,6 @@ "Mechanism": "Mekanizma", "Message": "İleti", "MIA": "MIA", - "MonoVersion": "Mono Versiyon", - "MovieDetailsNextMovie": "Film Ayrıntıları: Sonraki Film", - "MovieDetailsPreviousMovie": "Film Detayları: Önceki Film", "MovieIndexScrollBottom": "Film Dizini: Alta Kaydırma", "MovieIndexScrollTop": "Film Dizini: Yukarı Kaydırma", "NoLinks": "Bağlantı Yok", @@ -154,7 +139,6 @@ "AnalyticsEnabledHelpText": "Anonim kullanım ve hata bilgilerini Radarr sunucularına gönderin. Bu, tarayıcınızla ilgili bilgileri, kullandığınız Radarr WebUI sayfalarını, hata raporlamasının yanı sıra işletim sistemi ve çalışma zamanı sürümünü içerir. Bu bilgileri, özellikleri ve hata düzeltmelerini önceliklendirmek için kullanacağız.", "ApiKey": "API Anahtarı", "AppDataDirectory": "AppData dizini", - "MonoVersionCheckUpgradeRecommendedMessage": "Şu anda kurulu Mono sürümü {0} desteklenmektedir, ancak {1} sürümüne yükseltilmesi önerilir.", "NoUpdatesAreAvailable": "Güncelleme yok", "OAuthPopupMessage": "Pop-up'lar tarayıcınız tarafından engelleniyor", "Ok": "Tamam", @@ -180,7 +164,6 @@ "CertificateValidationHelpText": "HTTPS sertifika doğrulamasının ne kadar katı olduğunu değiştirin", "ChangeHasNotBeenSavedYet": "Değişiklik henüz kaydedilmedi", "ClientPriority": "Müşteri Önceliği", - "CloneIndexer": "Klon İndeksleyici", "CloneProfile": "Klon Profili", "CloseCurrentModal": "Geçerli Modeli Kapat", "Columns": "Sütunlar", @@ -194,17 +177,9 @@ "Docker": "Liman işçisi", "Donations": "Bağışlar", "DownloadClient": "İstemciyi İndir", - "DownloadClientCheckNoneAvailableMessage": "İndirme istemcisi yok", "DownloadClients": "İstemcileri İndir", - "EnableAutomaticAdd": "Otomatik Eklemeyi Etkinleştir", "EnableAutomaticSearch": "Otomatik Aramayı Etkinleştir", - "EnableAutomaticSearchHelpTextWarning": "Etkileşimli arama kullanıldığında kullanılacak", - "EnableColorImpairedMode": "Renk Bozukluğu Modunu Etkinleştir", - "EnableColorImpairedModeHelpText": "Renk bozukluğu olan kullanıcıların renk kodlu bilgileri daha iyi ayırt etmesine olanak tanıyan değiştirilmiş stil", - "EnableCompletedDownloadHandlingHelpText": "Tamamlanan indirmeleri indirme istemcisinden otomatik olarak içe aktarın", - "EnableHelpText": "Bu meta veri türü için meta veri dosyası oluşturmayı etkinleştirin", "EnableInteractiveSearchHelpText": "Etkileşimli arama kullanıldığında kullanılacak", - "EnableInteractiveSearchHelpTextWarning": "Bu indeksleyici ile arama desteklenmiyor", "FocusSearchBox": "Arama Kutusuna Odaklan", "GeneralSettings": "Genel Ayarlar", "Grabs": "Kapmak", @@ -224,10 +199,6 @@ "KeyboardShortcuts": "Klavye kısayolları", "LaunchBrowserHelpText": " Bir web tarayıcısı açın ve uygulama başlangıcında Radarr ana sayfasına gidin.", "LogLevel": "Günlük Düzeyi", - "MinimumLimits": "Minimum Limitler", - "MinutesHundredTwenty": "120 Dakika: {0}", - "MinutesNinety": "90 Dakika: {0}", - "MinutesSixty": "60 Dakika: {0}", "Mode": "Mod", "NoTagsHaveBeenAddedYet": "Henüz etiket eklenmedi", "NotificationTriggers": "Bildirim Tetikleyicileri", @@ -239,7 +210,6 @@ "PrioritySettings": "Öncelik", "ProxyType": "Proxy Türü", "PtpOldSettingsCheckMessage": "Aşağıdaki PassThePopcorn dizinleyicilerinin ayarları kullanımdan kaldırıldı ve güncellenmeleri gerekiyor: {0}", - "QualitySettings": "Kalite Ayarları", "ReadTheWikiForMoreInformation": "Daha fazla bilgi için Wiki'yi okuyun", "Reddit": "Reddit", "RefreshMovie": "Filmi yenile", @@ -284,7 +254,6 @@ "UnableToLoadBackups": "Yedeklemeler yüklenemiyor", "UnableToLoadHistory": "Geçmiş yüklenemiyor", "UnableToLoadNotifications": "Bildirimler yüklenemiyor", - "UnableToLoadQualityDefinitions": "Kalite Tanımları yüklenemiyor", "UnableToLoadUISettings": "UI ayarları yüklenemiyor", "Yesterday": "Dün", "AcceptConfirmationModal": "Onay Modelini Kabul Et", @@ -293,22 +262,14 @@ "AddingTag": "Etiket ekleniyor", "CouldNotConnectSignalR": "SignalR'ye bağlanılamadı, kullanıcı arayüzü güncellenmeyecek", "Custom": "Özel", - "DeleteIndexer": "Dizinleyiciyi Sil", - "DeleteIndexerMessageText": "Dizin oluşturucuyu '{0}' silmek istediğinizden emin misiniz?", "DownloadClientStatusCheckSingleClientMessage": "Hatalar nedeniyle indirilemeyen istemciler: {0}", - "Downloading": "İndiriliyor", "Enabled": "Etkin", "IgnoredAddresses": "Yoksayılan Adresler", - "Importing": "İçe aktarılıyor", "Indexer": "Dizin oluşturucu", "DownloadClientStatusCheckAllClientMessage": "Hatalar nedeniyle tüm indirme istemcileri kullanılamıyor", - "DownloadClientUnavailable": "İndirme istemcisi kullanılamıyor", "EditIndexer": "Dizinleyiciyi Düzenle", "Enable": "etkinleştirme", - "EnableAutoHelpText": "Etkinleştirilirse, Filmler bu listeden Radarr'a otomatik olarak eklenecektir", - "EnabledHelpText": "Bu listeyi Radarr'da kullanmak üzere etkinleştirin", "EnableInteractiveSearch": "Etkileşimli Aramayı Etkinleştir", - "EnableMediaInfoHelpText": "Dosyalardan çözünürlük, çalışma zamanı ve kodek bilgileri gibi video bilgilerini çıkarın. Bu, Radarr'ın dosyanın taramalar sırasında yüksek disk veya ağ etkinliğine neden olabilecek bölümlerini okumasını gerektirir.", "EnableRss": "RSS'yi etkinleştir", "EnableSSL": "SSL'yi etkinleştir", "NoLeaveIt": "Hayır, Bırak", @@ -316,18 +277,14 @@ "Events": "Etkinlikler", "EventType": "Etkinlik tipi", "Exception": "İstisna", - "ExistingMovies": "Mevcut Filmler", "ExistingTag": "Mevcut etiket", "IndexerProxyStatusCheckAllClientMessage": "Hatalar nedeniyle tüm dizinleyiciler kullanılamıyor", "IndexerProxyStatusCheckSingleClientMessage": "Hatalar nedeniyle dizinleyiciler kullanılamıyor: {0}", "Indexers": "Dizin oluşturucular", - "MaximumLimits": "Maksimum Sınırlar", "Name": "İsim", "New": "Yeni", "NoBackupsAreAvailable": "Kullanılabilir yedek yok", - "NoLimitForAnyRuntime": "Herhangi bir çalışma zamanı için sınır yok", "NoLogFiles": "Günlük dosyası yok", - "NoMinimumForAnyRuntime": "Herhangi bir çalışma süresi için minimum değer yok", "Restart": "Tekrar başlat", "RestartRequiredHelpTextWarning": "Etkili olması için yeniden başlatma gerektirir", "Restore": "Onarmak", @@ -362,5 +319,12 @@ "Backup": "Destek olmak", "Cancel": "İptal etmek", "Level": "Seviye", - "Time": "Zaman" + "Time": "Zaman", + "MaintenanceRelease": "Bakım Sürümü: hata düzeltmeleri ve diğer iyileştirmeler. Daha fazla ayrıntı için Github İşlem Geçmişine bakın", + "HistoryCleanupDaysHelpText": "Otomatik temizlemeyi devre dışı bırakmak için 0'a ayarlayın", + "HistoryCleanupDaysHelpTextWarning": "Geri dönüşüm kutusundaki, seçilen gün sayısından daha eski olan dosyalar otomatik olarak temizlenecektir", + "Filters": "Filtre", + "OnGrab": "Yakalandığında", + "OnHealthIssue": "Sağlık Sorunu Hakkında", + "TestAllIndexers": "Tüm Dizinleyicileri Test Et" } diff --git a/src/NzbDrone.Core/Localization/Core/vi.json b/src/NzbDrone.Core/Localization/Core/vi.json index bcd81e73d..e0372485d 100644 --- a/src/NzbDrone.Core/Localization/Core/vi.json +++ b/src/NzbDrone.Core/Localization/Core/vi.json @@ -10,21 +10,14 @@ "NoBackupsAreAvailable": "Không có bản sao lưu nào", "NoChanges": "Không thay đổi", "NoLeaveIt": "Không để nó", - "NoLimitForAnyRuntime": "Không có giới hạn cho bất kỳ thời gian chạy nào", "NoLogFiles": "Không có tệp nhật ký", - "QualitySettings": "Cài đặt chất lượng", "IndexerProxyStatusCheckSingleClientMessage": "Danh sách không có sẵn do lỗi: {0}", "Indexers": "Người lập chỉ mục", "InteractiveSearch": "Tìm kiếm tương tác", "Message": "Thông điệp", - "MinutesHundredTwenty": "120 phút: {0}", - "MinutesNinety": "90 phút: {0}", - "MinutesSixty": "60 phút: {0}", "Mode": "Chế độ", - "MonoTlsCheckMessage": "Giải pháp thay thế Radarr Mono 4.x tls vẫn được bật, hãy xem xét loại bỏ MONO_TLS_PROVIDER = tùy chọn môi trường kế thừa", "Name": "Tên", "NoLinks": "Không có liên kết", - "NoMinimumForAnyRuntime": "Không có tối thiểu cho bất kỳ thời gian chạy nào", "NoTagsHaveBeenAddedYet": "Chưa có thẻ nào được thêm vào", "NotificationTriggers": "Kích hoạt thông báo", "NoUpdatesAreAvailable": "Không có bản cập nhật nào có sẵn", @@ -38,7 +31,6 @@ "PendingChangesDiscardChanges": "Hủy các thay đổi và rời khỏi", "PendingChangesMessage": "Bạn có các thay đổi chưa được lưu, bạn có chắc chắn muốn rời khỏi trang này không?", "PendingChangesStayReview": "Ở lại và xem xét các thay đổi", - "PreferredSize": "Kích thước ưa thích", "Presets": "Cài đặt trước", "Priority": "Sự ưu tiên", "PriorityHelpText": "Ưu tiên nhiều Khách hàng tải xuống. Round-Robin được sử dụng cho các khách hàng có cùng mức độ ưu tiên.", @@ -51,7 +43,6 @@ "ProxyType": "Loại proxy", "ProxyUsernameHelpText": "Bạn chỉ cần nhập tên người dùng và mật khẩu nếu được yêu cầu. Nếu không, hãy để trống chúng.", "PtpOldSettingsCheckMessage": "Các trình lập chỉ mục PassThePopcorn sau đây có cài đặt không được dùng nữa và sẽ được cập nhật: {0}", - "QualityDefinitions": "Định nghĩa chất lượng", "Reddit": "Reddit", "Refresh": "Làm tươi", "ReleaseBranchCheckOfficialBranchMessage": "Nhánh {0} không phải là nhánh phát hành Radarr hợp lệ, bạn sẽ không nhận được cập nhật", @@ -94,7 +85,6 @@ "Backups": "Sao lưu", "BeforeUpdate": "Trước khi cập nhật", "CertificateValidationHelpText": "Thay đổi cách xác thực chứng chỉ HTTPS nghiêm ngặt", - "MinimumLimits": "Giới hạn tối thiểu", "About": "Trong khoảng", "AcceptConfirmationModal": "Phương thức xác nhận chấp nhận", "Actions": "Hành động", @@ -105,28 +95,21 @@ "All": "Tất cả", "Analytics": "phân tích", "Automatic": "Tự động", - "DeleteIndexer": "Xóa trình lập chỉ mục", "DownloadClientSettings": "Tải xuống cài đặt ứng dụng khách", "DownloadClientStatusCheckAllClientMessage": "Tất cả các ứng dụng khách tải xuống không khả dụng do lỗi", "DownloadClientStatusCheckSingleClientMessage": "Ứng dụng khách tải xuống không khả dụng do lỗi: {0}", - "DownloadClientUnavailable": "Ứng dụng khách tải xuống không khả dụng", - "Downloading": "Đang tải xuống", "Edit": "Biên tập", "EditIndexer": "Chỉnh sửa trình lập chỉ mục", - "EnableColorImpairedModeHelpText": "Đã thay đổi kiểu để cho phép người dùng khiếm thị phân biệt rõ hơn thông tin mã màu", "Enabled": "Đã bật", "HiddenClickToShow": "Ẩn, bấm để hiển thị", "History": "Lịch sử", "HomePage": "Trang chủ", "Host": "Tổ chức", "IllRestartLater": "Tôi sẽ khởi động lại sau", - "Importing": "Nhập khẩu", "Password": "Mật khẩu", "Peers": "Ngang hàng", - "Pending": "Đang chờ xử lý", "Port": "Hải cảng", "RestoreBackup": "Khôi phục lại bản sao lưu", - "Restrictions": "Những hạn chế", "Result": "Kết quả", "Retention": "Giữ lại", "RSS": "RSS", @@ -147,7 +130,6 @@ "IndexerPriority": "Mức độ ưu tiên của người lập chỉ mục", "KeyboardShortcuts": "Các phím tắt bàn phím", "Language": "Ngôn ngữ", - "Languages": "Ngôn ngữ", "LastWriteTime": "Lần viết cuối cùng", "LaunchBrowserHelpText": " Mở trình duyệt web và điều hướng đến trang chủ Radarr khi khởi động ứng dụng.", "Level": "Cấp độ", @@ -157,7 +139,6 @@ "LogLevelTraceHelpTextWarning": "Ghi nhật ký theo dõi chỉ nên được bật tạm thời", "Logs": "Nhật ký", "Manual": "Thủ công", - "MaximumLimits": "Giới hạn tối đa", "Mechanism": "Cơ chế", "MIA": "MIA", "New": "Mới", @@ -189,7 +170,6 @@ "Cancel": "Huỷ bỏ", "CancelPendingTask": "Bạn có chắc chắn muốn hủy nhiệm vụ đang chờ xử lý này không?", "ClientPriority": "Ưu tiên khách hàng", - "CloneIndexer": "Trình lập chỉ mục nhân bản", "CloneProfile": "Hồ sơ nhân bản", "Close": "Đóng", "Columns": "Cột", @@ -200,34 +180,22 @@ "ConnectSettings": "Kết nối Cài đặt", "CouldNotConnectSignalR": "Không thể kết nối với SignalR, giao diện người dùng sẽ không cập nhật", "Custom": "Tập quán", - "DelayProfile": "Hồ sơ trì hoãn", "Delete": "Xóa bỏ", "DeleteApplicationMessageText": "Bạn có chắc chắn muốn xóa thông báo '{0}' không?", "DeleteBackup": "Xóa bản sao lưu", "DeleteBackupMessageText": "Bạn có chắc chắn muốn xóa bản sao lưu '{0}' không?", - "DeleteIndexerMessageText": "Bạn có chắc chắn muốn xóa trình lập chỉ mục '{0}' không?", - "DownloadClientCheckNoneAvailableMessage": "Không có ứng dụng khách tải xuống nào", - "DownloadClientCheckUnableToCommunicateMessage": "Không thể giao tiếp với {0}.", - "EnableCompletedDownloadHandlingHelpText": "Tự động nhập các bản tải xuống đã hoàn thành từ máy khách tải xuống", - "EnabledHelpText": "Bật danh sách này để sử dụng trong Radarr", - "EnableHelpText": "Cho phép tạo tệp siêu dữ liệu cho loại siêu dữ liệu này", "FeatureRequests": "Yêu cầu tính năng", "Filename": "Tên tệp", "Files": "Các tập tin", - "MonoVersion": "Phiên bản Mono", "NoChange": "Không thay đổi", "PortNumber": "Số cổng", "Proxy": "Ủy quyền", "IndexerProxyStatusCheckAllClientMessage": "Tất cả các trình lập chỉ mục không khả dụng do lỗi", "IndexerStatusCheckAllClientMessage": "Tất cả các trình lập chỉ mục không khả dụng do lỗi", "Info": "Thông tin", - "MonoVersionCheckUpgradeRecommendedMessage": "Phiên bản Mono được cài đặt hiện tại {0} được hỗ trợ nhưng nên nâng cấp lên {1}.", "MoreInfo": "Thêm thông tin", - "MovieDetailsNextMovie": "Chi tiết phim: Phim tiếp theo", - "MovieDetailsPreviousMovie": "Chi tiết phim: Phim trước", "MovieIndexScrollBottom": "Mục lục phim: Cuộn dưới cùng", "MovieIndexScrollTop": "Mục lục phim: Cuộn lên đầu", - "Movies": "Phim", "Ok": "Đồng ý", "RemovingTag": "Xóa thẻ", "Reset": "Cài lại", @@ -256,7 +224,6 @@ "UnableToLoadDownloadClients": "Không thể tải ứng dụng khách tải xuống", "UnableToLoadGeneralSettings": "Không thể tải Cài đặt chung", "UnableToLoadHistory": "Không thể tải lịch sử", - "UnableToLoadIndexers": "Không thể tải Trình chỉ mục", "UnableToLoadNotifications": "Không thể tải thông báo", "UnableToLoadTags": "Không thể tải thẻ", "UnableToLoadUISettings": "Không thể tải cài đặt giao diện người dùng", @@ -318,22 +285,15 @@ "Version": "Phiên bản", "AllIndexersHiddenDueToFilter": "Tất cả phim đều bị ẩn do áp dụng bộ lọc.", "DeleteTag": "Xóa thẻ", - "UnableToLoadQualityDefinitions": "Không thể tải Định nghĩa chất lượng", "Enable": "Kích hoạt", - "EnableAutoHelpText": "Nếu được bật, Phim sẽ tự động được thêm vào Radarr từ danh sách này", - "EnableAutomaticAdd": "Bật tính năng Thêm tự động", "EnableAutomaticSearch": "Bật tìm kiếm tự động", "EnableAutomaticSearchHelpText": "Sẽ được sử dụng khi tìm kiếm tự động được thực hiện qua giao diện người dùng hoặc bằng Radarr", - "EnableAutomaticSearchHelpTextWarning": "Sẽ được sử dụng khi tìm kiếm tương tác được sử dụng", - "EnableColorImpairedMode": "Bật Chế độ Khuyết màu", "General": "Chung", "Warn": "Cảnh báo", "DeleteDownloadClient": "Xóa ứng dụng khách tải xuống", "DeleteDownloadClientMessageText": "Bạn có chắc chắn muốn xóa ứng dụng khách tải xuống '{0}' không?", "EnableInteractiveSearch": "Bật tìm kiếm tương tác", "EnableInteractiveSearchHelpText": "Sẽ được sử dụng khi tìm kiếm tương tác được sử dụng", - "EnableInteractiveSearchHelpTextWarning": "Trình lập chỉ mục này không hỗ trợ tìm kiếm", - "EnableMediaInfoHelpText": "Trích xuất thông tin video như độ phân giải, thời gian chạy và thông tin codec từ các tệp. Điều này yêu cầu Radarr đọc các phần của tệp có thể gây ra hoạt động mạng hoặc đĩa cao trong quá trình quét.", "EnableRss": "Bật RSS", "EnableSSL": "Bật SSL", "EnableSslHelpText": " Yêu cầu khởi động lại chạy với tư cách quản trị viên để có hiệu lực", @@ -342,7 +302,6 @@ "Events": "Sự kiện", "EventType": "Loại sự kiện", "Exception": "ngoại lệ", - "ExistingMovies": "(Các) phim hiện có", "ExistingTag": "Thẻ hiện có", "Failed": "Thất bại", "Filter": "Bộ lọc", @@ -357,5 +316,12 @@ "System": "Hệ thống", "Time": "Thời gian", "UI": "Giao diện người dùng", - "UISettings": "Cài đặt giao diện người dùng" + "UISettings": "Cài đặt giao diện người dùng", + "MaintenanceRelease": "Bản phát hành bảo trì: sửa lỗi và các cải tiến khác. Xem Lịch sử cam kết Github để biết thêm chi tiết", + "HistoryCleanupDaysHelpText": "Đặt thành 0 để tắt tính năng dọn dẹp tự động", + "HistoryCleanupDaysHelpTextWarning": "Các tệp trong thùng rác cũ hơn số ngày đã chọn sẽ tự động được dọn dẹp", + "OnHealthIssue": "Về vấn đề sức khỏe", + "Filters": "Bộ lọc", + "OnGrab": "Trên Grab", + "TestAllIndexers": "Kiểm tra tất cả các chỉ mục" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index d34964835..436c48fc3 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -22,19 +22,10 @@ "Actions": "操作", "About": "关于", "MoreInfo": "更多信息", - "MonoVersionCheckUpgradeRecommendedMessage": "当前安装的Mono版本 {0} 在支持范围但建议升级Mono到版本 {1} 。", - "MonoVersion": "Mono版本", - "MonoTlsCheckMessage": "Prowlarr Mono 4.x tls 功能仍然启用,请删除 MONO_TLS_PROVIDER=legacy 环境选项", - "MonoNotNetCoreCheckMessage": "请升级至.NET核心版本的Prowlarr", "Mode": "模式", - "MinutesSixty": "60分钟: {0}", - "MinutesNinety": "90分钟: {0}", - "MinutesHundredTwenty": "120分钟: {0}", - "MinimumLimits": "最小限制", "MIA": "MIA", "Message": "信息", "Mechanism": "机制", - "MaximumLimits": "最大限制", "Manual": "手动", "MaintenanceRelease": "维护版本", "Logs": "日志", @@ -45,7 +36,6 @@ "Level": "等级", "LaunchBrowserHelpText": " 启动浏览器时导航到Prowlarr 主页。", "LastWriteTime": "最后写入时间", - "Languages": "语言", "Language": "语言", "KeyboardShortcuts": "键盘快捷键", "Interval": "间隔", @@ -67,7 +57,6 @@ "IndexerAuth": "搜刮器认证", "Indexer": "搜刮器", "IncludeHealthWarningsHelpText": "包含健康度警告", - "Importing": "导入中", "IllRestartLater": "稍后重启", "IgnoredAddresses": "已忽略地址", "Id": "Id", @@ -96,7 +85,6 @@ "FeatureRequests": "功能建议", "Failed": "失败", "ExistingTag": "已有标签", - "ExistingMovies": "已有影片", "Exception": "例外", "EventType": "事件类型", "Events": "事件", @@ -107,35 +95,21 @@ "EnableSSL": "启用SSL", "EnableRssHelpText": "为搜刮器启用 RSS订阅", "EnableRss": "启用RSS", - "EnableMediaInfoHelpText": "从文件中提取视频信息,如分辨率,时长和编解码器信息。这需要Prowlarr 在扫描期间读取文件并可能导致高磁盘或网络占用。", - "EnableInteractiveSearchHelpTextWarning": "该搜刮器不支持搜索", "EnableInteractiveSearchHelpText": "当手动搜索启用时使用", "EnableInteractiveSearch": "启用手动搜索", "EnableIndexer": "启用搜刮器", - "EnableHelpText": "启用此元数据类型的元数据文件创建", - "EnabledHelpText": "在 Prowlarr 中启用该列表", "Enabled": "已启用", - "EnableCompletedDownloadHandlingHelpText": "自动从下载客户端导入已下载的影片", - "EnableColorImpairedModeHelpText": "改变样式,以允许有颜色障碍的用户更好地区分颜色编码信息", - "EnableColorImpairedMode": "启用色障模式", - "EnableAutomaticSearchHelpTextWarning": "当手动搜索启用时使用", "EnableAutomaticSearchHelpText": "当自动搜索通过UI或Prowlarr执行时将被使用", "EnableAutomaticSearch": "启用自动搜索", - "EnableAutomaticAdd": "启用自动添加", - "EnableAutoHelpText": "如已启用,影片会自动从列表中添加到 Prowlarr", "Enable": "启用", "EditIndexer": "编辑搜刮器", "EditAppProfile": "编辑应用配置", "Edit": "编辑", - "Downloading": "下载中", - "DownloadClientUnavailable": "下载客户端不可用", "DownloadClientStatusCheckSingleClientMessage": "所有下载客户端都不可用: {0}", "DownloadClientStatusCheckAllClientMessage": "所有下载客户端都不可用", "DownloadClientsSettingsSummary": "下载客户端配置以集成到 Prowlarr UI 搜索中", "DownloadClientSettings": "下载客户端设置", "DownloadClients": "下载客户端", - "DownloadClientCheckUnableToCommunicateMessage": "无法与{0}进行通讯。", - "DownloadClientCheckNoneAvailableMessage": "无可用的下载客户端", "DownloadClient": "下载客户端", "Donations": "捐赠", "Docker": "Docker", @@ -148,8 +122,6 @@ "DeleteTag": "删除标签", "DeleteNotificationMessageText": "您确定要删除推送 '{0}' 吗?", "DeleteNotification": "删除消息推送", - "DeleteIndexerMessageText": "您确定要删除索引 '{0}'吗?", - "DeleteIndexer": "删除索引", "DeleteDownloadClientMessageText": "您确定要删除下载客户端 '{0}' 吗?", "DeleteDownloadClient": "删除下载客户端", "DeleteBackupMessageText": "您确定要删除备份 '{0}' 吗?", @@ -158,7 +130,6 @@ "DeleteApplicationMessageText": "您确定要删除应用程序“{0}”吗?", "DeleteApplication": "删除应用程序", "Delete": "删除", - "DelayProfile": "延时配置", "DBMigration": "数据库迁移版本", "Dates": "日期", "Date": "日期", @@ -177,7 +148,6 @@ "CloseCurrentModal": "关闭当前模组", "Close": "关闭", "CloneProfile": "复制配置", - "CloneIndexer": "复制索引", "ClientPriority": "客户端优先级", "ClearHistoryMessageText": "您确定要清除Prowlarr所有的历史记录吗?", "ClearHistory": "清楚历史", @@ -222,8 +192,6 @@ "Add": "添加", "SettingsEnableColorImpairedModeHelpText": "改变样式,以允许有颜色障碍的用户更好地区分颜色编码信息", "SettingsEnableColorImpairedMode": "启用色障模式", - "QualitySettings": "影片质量配置设置", - "QualityDefinitions": "影片质量定义", "PtpOldSettingsCheckMessage": "下列PassThePopcorn搜刮器有已启用的设置,请更新:{0}", "ProxyUsernameHelpText": "如果需要,您只需要输入用户名和密码。否则就让它们为空。", "ProxyType": "代理类型", @@ -241,13 +209,11 @@ "PriorityHelpText": "优先考虑多个下载客户端,循环查询用于具有相同优先级的客户端。", "Priority": "优先级", "Presets": "预设", - "PreferredSize": "首选影片大小", "PortNumber": "端口号", "Port": "端口", "PendingChangesStayReview": "留下检查更改", "PendingChangesMessage": "您有未保存的修改,确定要退出本页么?", "PendingChangesDiscardChanges": "舍弃修改并退出", - "Pending": "挂起", "Peers": "用户", "Password": "密码", "PageSizeHelpText": "每页显示的项目数", @@ -263,9 +229,7 @@ "NotificationTriggersHelpText": "选择触发此通知的事件", "NotificationTriggers": "通知触发器", "NoTagsHaveBeenAddedYet": "未添加标签", - "NoMinimumForAnyRuntime": "影片时间没有最小限制", "NoLogFiles": "没有日志文件", - "NoLimitForAnyRuntime": "不限制任何影片时长", "NoLeaveIt": "不,就这样", "NoChanges": "无修改", "NoChange": "无修改", @@ -273,11 +237,8 @@ "New": "新的", "NetCore": ".NET", "Name": "名称", - "Movies": "电影", "MovieIndexScrollTop": "影片索引:滚动到顶部", "MovieIndexScrollBottom": "影片索引:滚动到底部", - "MovieDetailsPreviousMovie": "影片详细:前一个", - "MovieDetailsNextMovie": "影片详细:下一个", "BackupIntervalHelpText": "自动备份时间间隔", "IndexerProxyStatusCheckAllClientMessage": "所有搜刮器都因错误不可用", "SettingsShowRelativeDates": "显示相对日期", @@ -314,7 +275,6 @@ "Torrents": "种子", "Type": "类型", "UnableToLoadNotifications": "无法加载通知连接", - "UnableToLoadQualityDefinitions": "无法加载影片质量定义", "RefreshMovie": "刷新影片", "Reload": "重新加载", "Restore": "恢复", @@ -387,8 +347,6 @@ "UrlBaseHelpText": "对于反向代理支持,默认为空", "ReleaseStatus": "发布状态", "SetTags": "设定标签", - "UnableToLoadIndexers": "无法加载搜刮器", - "Restrictions": "限制条件", "Search": "搜索", "SSLCertPassword": "SSL证书密码", "UnableToAddANewIndexerPleaseTryAgain": "无法添加搜刮器,请稍后重试。", @@ -436,8 +394,14 @@ "SettingsLogRotate": "日志轮替", "SettingsIndexerLoggingHelpText": "记录额外的搜刮器数据,包括响应", "SettingsFilterSentryEventsHelpText": "过滤已知的用户错误事件,不让其作为分析报告发送", - "ReleaseBranchCheckPreviousVersionMessage": "分支 {0} 适用于 Prowlarr 的先前版本,将分支设置为“Nightly”以获得进一步更新", "RedirectHelpText": "重定向搜刮器的传入下载请求并直接传递抓取,而不是通过Prowlarr代理请求搜刮器", "IndexerTagsHelpText": "使用标签来指定默认客户端、搜刮器代理或仅群组搜刮器。", - "IndexerSettingsSummary": "配置全局索引器设置,包括代理。" + "IndexerSettingsSummary": "配置全局索引器设置,包括代理。", + "HistoryCleanupDaysHelpTextWarning": "回收站中的文件在超出选择的天数后会被自动清理", + "UserAgentProvidedByTheAppThatCalledTheAPI": "由调用API的应用程序提供的User-Agent", + "Filters": "过滤", + "HistoryCleanupDaysHelpText": "设置为0关闭自动清理", + "OnGrab": "抓取中", + "OnHealthIssue": "健康度异常", + "TestAllIndexers": "测试全部搜刮器" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_TW.json b/src/NzbDrone.Core/Localization/Core/zh_TW.json index 0967ef424..4ab65ccd6 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_TW.json +++ b/src/NzbDrone.Core/Localization/Core/zh_TW.json @@ -1 +1,4 @@ -{} +{ + "About": "關於", + "Add": "添加" +} From 09bd8137fc9c2a2bfbcc4c0bb7a6955ca393949b Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 1 Mar 2022 09:24:09 -0600 Subject: [PATCH 0371/2320] New: (DanishBytes) Move to YML --- src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs index c5def10a7..54f251320 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs @@ -21,6 +21,7 @@ namespace NzbDrone.Core.Indexers.Definitions { public class DanishBytes : TorrentIndexerBase<DanishBytesSettings> { + [Obsolete("Moved to YML")] public override string Name => "DanishBytes"; public override string[] IndexerUrls => new string[] { "https://danishbytes.club/", "https://danishbytes2.org/" }; public override string Description => "DanishBytes is a Private Danish Tracker"; From 3b51a3a6185436ace567022add01416c31a3f27a Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 1 Mar 2022 09:44:43 -0600 Subject: [PATCH 0372/2320] fixup! New: (DanishBytes) Move to YML --- src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs index 54f251320..7c7ce7f7f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs @@ -19,9 +19,9 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete("Moved to YML")] public class DanishBytes : TorrentIndexerBase<DanishBytesSettings> { - [Obsolete("Moved to YML")] public override string Name => "DanishBytes"; public override string[] IndexerUrls => new string[] { "https://danishbytes.club/", "https://danishbytes2.org/" }; public override string Description => "DanishBytes is a Private Danish Tracker"; From 684c30893ae1b29f15cd0dcb5e311f3f65326a63 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Wed, 9 Mar 2022 23:11:27 +0000 Subject: [PATCH 0373/2320] Translated using Weblate (Portuguese (Brazil)) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (428 of 428 strings) Translated using Weblate (Portuguese) Currently translated at 82.0% (351 of 428 strings) Translated using Weblate (French) Currently translated at 96.7% (414 of 428 strings) Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Havok Dan <havokdan@yahoo.com.br> Co-authored-by: José Eduardo Veiga <vitruxpt@vitruxbot.com> Co-authored-by: KevoM <lilmarsu@gmail.com> Co-authored-by: Weblate <noreply@weblate.org> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/cs.json | 1 - src/NzbDrone.Core/Localization/Core/fr.json | 36 ++++++++++++++----- src/NzbDrone.Core/Localization/Core/pt.json | 6 ++-- .../Localization/Core/pt_BR.json | 4 +-- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/cs.json b/src/NzbDrone.Core/Localization/Core/cs.json index 323649494..a8716cb79 100644 --- a/src/NzbDrone.Core/Localization/Core/cs.json +++ b/src/NzbDrone.Core/Localization/Core/cs.json @@ -123,7 +123,6 @@ "LaunchBrowserHelpText": " Otevřete webový prohlížeč a při spuštění aplikace přejděte na domovskou stránku Radarr.", "Logging": "Protokolování", "Mechanism": "Mechanismus", - "NoLimitForAnyRuntime": "Žádné omezení za běhu", "NoLinks": "Žádné odkazy", "Presets": "Předvolby", "Priority": "Přednost", diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index fcef9a2b8..4fde30987 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -22,7 +22,7 @@ "Clear": "Effacer", "BackupNow": "Sauvegarder maintenant", "Backup": "Sauvegarde", - "AppDataLocationHealthCheckMessage": "La mise à jour ne sera pas possible d'empêcher la suppression AppData sur mise à jour", + "AppDataLocationHealthCheckMessage": "Mettre à jour ne sera pas possible pour éviter la suppression AppData lors de la mise à jour", "Analytics": "Analytique", "All": "Tout", "About": "À propos", @@ -193,7 +193,7 @@ "AddIndexer": "Ajouter un indexeur", "Interval": "Intervalle", "InteractiveSearch": "Recherche interactive", - "IndexerPriorityHelpText": "Priorité de l'indexeur de 1 (la plus élevée) à 50 (la plus basse). Par défaut: 25.", + "IndexerPriorityHelpText": "Priorité de l'indexeur de 1 (la plus élevée) à 50 (la plus basse). Par défaut : 25.", "IndexerPriority": "Priorité de l'indexeur", "UnableToLoadNotifications": "Impossible de charger les notifications", "Version": "Version", @@ -206,7 +206,7 @@ "Mode": "Mode", "Mechanism": "Mécanisme", "Manual": "Manuel", - "MaintenanceRelease": "Version de maintenance", + "MaintenanceRelease": "Version de maintenance : corrections de bugs et autres améliorations. Voir historique des changements Github pour plus d'informations", "Logs": "Journaux", "LogLevelTraceHelpTextWarning": "La journalisation des traces ne doit être activée que temporairement", "LogLevel": "Niveau du journal", @@ -216,7 +216,7 @@ "ProxyBypassFilterHelpText": "Utiliser ',' comme séparateur et '*.' comme caractère générique pour les sous-domaines", "Uptime": "Durée de fonctionnent", "UpdateScriptPathHelpText": "Chemin vers un script personnalisé qui prend un package de mise à jour extraite et gère le reste du processus de mise à jour", - "UpdateMechanismHelpText": "Utiliser le programme de mise à jour intégré dans Prowlarr ou un script", + "UpdateMechanismHelpText": "Utiliser l'outil de mise à jour intégré de Prowlarr ou un script", "UpdateAutomaticallyHelpText": "Télécharger et installer automatiquement les mises à jour. Vous pourrez toujours installer à partir de System : Updates", "UnableToLoadUISettings": "Impossible de charger les paramètres de l'interface utilisateur", "UnableToLoadTags": "Impossible de charger les balises", @@ -384,15 +384,15 @@ "DeleteIndexerProxyMessageText": "Êtes-vous sur de vouloir supprimer le proxy '{0}'  ?", "AddIndexerProxy": "Ajouter proxy indexeur", "AppSettingsSummary": "Applications et paramètres pour configurer comment Prowlarr interagit avec vos programmes PVR", - "IndexerTagsHelpText": "Utilisez des balises pour spécifier des clients par défaut, spécifier les proxies d'indexeur ou pour organiser vos indexeurs.", + "IndexerTagsHelpText": "Utilisez des balises pour spécifier les proxys d'indexeur ou pour simplement organiser vos indexeurs.", "Notifications": "Notifications", - "IndexerVipCheckExpiredClientMessage": "Les avantages VIP de l'indexeur ont expiré: {0}", + "IndexerVipCheckExpiredClientMessage": "Les avantages VIP de l'indexeur ont expiré : {0}", "IndexerProxy": "Proxy d'indexation", "IndexerSettingsSummary": "Configuration de divers paramètres globaux de l'indexeur, y compris les proxys.", "IndexerProxies": "Proxys d'indexation", "IndexerProxyStatusCheckAllClientMessage": "Tous les proxys sont indisponibles en raison d'échecs", - "IndexerProxyStatusCheckSingleClientMessage": "Proxys indisponibles en raison d'échecs: {0}", - "IndexerVipCheckExpiringClientMessage": "Les avantages VIP de l'indexeur arrivent bientôt à expiration: {0}", + "IndexerProxyStatusCheckSingleClientMessage": "Proxys indisponibles en raison d'échecs : {0}", + "IndexerVipCheckExpiringClientMessage": "Les avantages VIP de l'indexeur arrivent bientôt à expiration : {0}", "NoLinks": "Aucun liens", "Notification": "Notification", "UnableToAddANewIndexerProxyPleaseTryAgain": "Impossible d'ajouter un nouveau proxy d'indexation, veuillez réessayer.", @@ -403,5 +403,23 @@ "OnGrab": "À la Récupération", "OnHealthIssue": "Lors d'un problème de santé", "TestAllIndexers": "Tester tous les indexeurs", - "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent fourni par l'application qui a appelé l'API" + "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent fourni par l'application qui a appelé l'API", + "Database": "Base de données", + "HistoryCleanup": "Nettoyage de l'historique", + "IndexerAlreadySetup": "Au moins une instance de l'indexeur est déjà configuré", + "IndexerInfo": "Info de l'indexeur", + "Private": "Privé", + "Proxies": "Proxies", + "Public": "Publique", + "QueryResults": "Résultats de la requête", + "SemiPrivate": "Semi-privé", + "Url": "Url", + "QueryOptions": "Options de recherche", + "SearchType": "Type de recherche", + "Categories": "Catégories", + "MassEditor": "Éditeur de masse", + "UnableToLoadApplicationList": "Impossible de charger la liste des applications", + "Website": "Site internet", + "AudioSearch": "Recherche de musique", + "BookSearch": "Recherche de livres" } diff --git a/src/NzbDrone.Core/Localization/Core/pt.json b/src/NzbDrone.Core/Localization/Core/pt.json index edf2d82c2..2aacd72e6 100644 --- a/src/NzbDrone.Core/Localization/Core/pt.json +++ b/src/NzbDrone.Core/Localization/Core/pt.json @@ -1,6 +1,6 @@ { "Peers": "Elementos", - "AppDataLocationHealthCheckMessage": "Não será possível atualizar para evitar a exclusão de AppData", + "AppDataLocationHealthCheckMessage": "Não será possível atualizar para evitar a exclusão da pasta AppData durante a atualização", "Warn": "Avisar", "View": "Ver", "Updates": "Atualizações", @@ -393,5 +393,7 @@ "OnGrab": "Ao capturar", "OnHealthIssue": "Ao ter problemas no estado de funcionamento", "TestAllIndexers": "Testar todos os indexadores", - "UserAgentProvidedByTheAppThatCalledTheAPI": "Par Utilizador-Agente fornecido pela aplicação que chamou a API" + "UserAgentProvidedByTheAppThatCalledTheAPI": "Par Utilizador-Agente fornecido pela aplicação que chamou a API", + "OnApplicationUpdate": "Quando a aplicação atualizar", + "OnApplicationUpdateHelpText": "Quando a aplicação atualizar" } diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index bdec083e4..1e8d6c1da 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -119,7 +119,7 @@ "DownloadClients": "Clientes de download", "DownloadClientSettings": "Configurações do cliente de download", "DownloadClientStatusCheckAllClientMessage": "Todos os clientes download não estão disponíveis devido a falhas", - "DownloadClientStatusCheckSingleClientMessage": "Clientes de download indisponíveis devido a falhas: {0}", + "DownloadClientStatusCheckSingleClientMessage": "Clientes de download indisponíveis por falhas: {0}", "EditIndexer": "Editar indexador", "Enable": "Habilitar", "EnableAutomaticSearch": "Habilitar pesquisa automática", @@ -146,7 +146,7 @@ "GeneralSettingsSummary": "Porta, SSL, nome de usuário/senha, proxy, análises e atualizações", "Grabbed": "Obtido", "Health": "Integridade", - "HealthNoIssues": "Não há problemas com sua configuração", + "HealthNoIssues": "Nenhum problema com sua configuração", "HiddenClickToShow": "Oculto, clique para mostrar", "HideAdvanced": "Ocultar avançado", "History": "Histórico", From 55d03967ec70c59cc16ee199886dfb3886d9068c Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 14 Mar 2022 22:33:08 -0500 Subject: [PATCH 0374/2320] Bump Swashbuckle to 6.3.0 --- docs.sh | 4 ++-- src/NzbDrone.Host/Prowlarr.Host.csproj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs.sh b/docs.sh index bc9a94ff0..71c3359c9 100644 --- a/docs.sh +++ b/docs.sh @@ -27,11 +27,11 @@ dotnet clean $slnFile -c Release dotnet msbuild -restore $slnFile -p:Configuration=Debug -p:Platform=$platform -p:RuntimeIdentifiers=$RUNTIME -t:PublishAllRids dotnet new tool-manifest -dotnet tool install --version 6.2.3 Swashbuckle.AspNetCore.Cli +dotnet tool install --version 6.3.0 Swashbuckle.AspNetCore.Cli dotnet tool run swagger tofile --output ./src/Prowlarr.Api.V1/openapi.json "$outputFolder/net6.0/$RUNTIME/prowlarr.console.dll" v1 & -sleep 10 +sleep 30 kill %1 diff --git a/src/NzbDrone.Host/Prowlarr.Host.csproj b/src/NzbDrone.Host/Prowlarr.Host.csproj index 0b6b294e2..1e8956696 100644 --- a/src/NzbDrone.Host/Prowlarr.Host.csproj +++ b/src/NzbDrone.Host/Prowlarr.Host.csproj @@ -7,7 +7,7 @@ <PackageReference Include="NLog.Extensions.Logging" Version="1.7.2" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> - <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.2.3" /> + <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.3.0" /> <PackageReference Include="DryIoc.dll" Version="4.8.1" /> <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="5.1.0" /> </ItemGroup> From 77caaa2a551814279c1e467e42c51d2a3618278c Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Fri, 18 Mar 2022 16:11:29 +0000 Subject: [PATCH 0375/2320] Translated using Weblate (French) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 97.1% (416 of 428 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 1.6% (7 of 428 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 95.5% (409 of 428 strings) Co-authored-by: Ayi <4ayixd@gmail.com> Co-authored-by: Kakise <sam.taa@icloud.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: 杰森 <john@johnrosen1.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_Hans/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/fr.json | 4 +++- src/NzbDrone.Core/Localization/Core/zh_CN.json | 10 +++++++++- src/NzbDrone.Core/Localization/Core/zh_Hans.json | 4 +++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index 4fde30987..0a078be72 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -421,5 +421,7 @@ "UnableToLoadApplicationList": "Impossible de charger la liste des applications", "Website": "Site internet", "AudioSearch": "Recherche de musique", - "BookSearch": "Recherche de livres" + "BookSearch": "Recherche de livres", + "OnApplicationUpdate": "Lors de la mise à jour de l'app", + "OnApplicationUpdateHelpText": "Lors de la mise à jour de l'app" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index 436c48fc3..8ae36d444 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -403,5 +403,13 @@ "HistoryCleanupDaysHelpText": "设置为0关闭自动清理", "OnGrab": "抓取中", "OnHealthIssue": "健康度异常", - "TestAllIndexers": "测试全部搜刮器" + "TestAllIndexers": "测试全部搜刮器", + "AudioSearch": "音频搜索", + "BookSearch": "图书搜索", + "Categories": "分类", + "Database": "数据库", + "HistoryCleanup": "清理历史记录", + "IndexerAlreadySetup": "至少有一个索引器已经设置完毕", + "IndexerInfo": "索引器信息", + "IndexerNoDefCheckMessage": "索引器没有定义,将无法工作: {0}. 请删除或重新添加到Prowlarr" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_Hans.json b/src/NzbDrone.Core/Localization/Core/zh_Hans.json index 9257cfdd8..fd0464c12 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_Hans.json +++ b/src/NzbDrone.Core/Localization/Core/zh_Hans.json @@ -3,5 +3,7 @@ "AddDownloadClient": "添加下载客户端", "Add": "添加", "About": "关于", - "Analytics": "分析" + "Analytics": "分析", + "AddIndexer": "添加索引器", + "ApiKey": "API密钥" } From e0da422b0e195c295439efb8868692c8580ed935 Mon Sep 17 00:00:00 2001 From: nitsua <austin.w.best@gmail.com> Date: Mon, 21 Mar 2022 10:58:08 -0400 Subject: [PATCH 0376/2320] Fix app settings delete modal not closing and reloading app profiles --- src/Prowlarr.Api.V1/Profiles/App/AppProfileController.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Prowlarr.Api.V1/Profiles/App/AppProfileController.cs b/src/Prowlarr.Api.V1/Profiles/App/AppProfileController.cs index 2225ace22..586b2ca9f 100644 --- a/src/Prowlarr.Api.V1/Profiles/App/AppProfileController.cs +++ b/src/Prowlarr.Api.V1/Profiles/App/AppProfileController.cs @@ -30,9 +30,10 @@ namespace Prowlarr.Api.V1.Profiles.App [RestDeleteById] [Produces("application/json")] - public void DeleteProfile(int id) + public object DeleteProfile(int id) { _profileService.Delete(id); + return new { }; } [RestPutById] From cb74fade18a66d025a3979e0732159c77d0f4878 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sun, 20 Mar 2022 19:11:30 +0000 Subject: [PATCH 0377/2320] Translated using Weblate (French) Currently translated at 98.5% (422 of 428 strings) Co-authored-by: KevoM <lilmarsu@gmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/fr.json | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index 0a078be72..3a7c62e5b 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -216,7 +216,7 @@ "ProxyBypassFilterHelpText": "Utiliser ',' comme séparateur et '*.' comme caractère générique pour les sous-domaines", "Uptime": "Durée de fonctionnent", "UpdateScriptPathHelpText": "Chemin vers un script personnalisé qui prend un package de mise à jour extraite et gère le reste du processus de mise à jour", - "UpdateMechanismHelpText": "Utiliser l'outil de mise à jour intégré de Prowlarr ou un script", + "UpdateMechanismHelpText": "Utiliser le programme de mise à jour intégré de Prowlarr ou un script", "UpdateAutomaticallyHelpText": "Télécharger et installer automatiquement les mises à jour. Vous pourrez toujours installer à partir de System : Updates", "UnableToLoadUISettings": "Impossible de charger les paramètres de l'interface utilisateur", "UnableToLoadTags": "Impossible de charger les balises", @@ -374,7 +374,7 @@ "UnableToLoadAppProfiles": "Impossible de charger les profils d'application", "Add": "Ajouter", "SyncLevelFull": "Synchronisation complète : gardera cette application entièrement synchronisée. Les modifications apportées dans Prowlarr sont ensuite synchronisées avec cette application. Toute modification effectuée à distance sera annulée par Prowlarr lors de la prochaine synchronisation.", - "SyncLevelAddRemove": "Ajouter et supprimer uniquement : lorsqu'il est ajouté ou supprimé de Prowlarr, il mettra à jour cette application distante.", + "SyncLevelAddRemove": "Ajouter et supprimer uniquement : lorsque les indexeurs sont ajoutés ou supprimés de Prowlarr, ils mettront à jour cette application à distance.", "SyncLevel": "Niveau de synchronisation", "FullSync": "Synchronisation complète", "AddRemoveOnly": "Ajouter et supprimer uniquement", @@ -406,7 +406,7 @@ "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent fourni par l'application qui a appelé l'API", "Database": "Base de données", "HistoryCleanup": "Nettoyage de l'historique", - "IndexerAlreadySetup": "Au moins une instance de l'indexeur est déjà configuré", + "IndexerAlreadySetup": "Au moins une instance de l'indexeur est déjà configurée", "IndexerInfo": "Info de l'indexeur", "Private": "Privé", "Proxies": "Proxies", @@ -423,5 +423,8 @@ "AudioSearch": "Recherche de musique", "BookSearch": "Recherche de livres", "OnApplicationUpdate": "Lors de la mise à jour de l'app", - "OnApplicationUpdateHelpText": "Lors de la mise à jour de l'app" + "OnApplicationUpdateHelpText": "Lors de la mise à jour de l'app", + "IndexerNoDefCheckMessage": "Les indexeurs ne sont pas définis et ne fonctionneront pas :Merci de les retirer et (ou) les ajouter à nouveau à Prowlarr", + "MovieSearch": "Recherche de films", + "TvSearch": "Recherche de séries TV" } From 2f5b55013af063fd7ac659c692eab3b3db3734d5 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 8 Mar 2022 16:09:52 -0600 Subject: [PATCH 0378/2320] Fixed: '/indexers' URL Base breaking UI navigation (cherry picked from commit 140547e42a32cbaf80e7a794c5be9bfb574e97a2) --- frontend/src/Components/Link/Link.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/frontend/src/Components/Link/Link.js b/frontend/src/Components/Link/Link.js index 3a582e217..6cb0565d0 100644 --- a/frontend/src/Components/Link/Link.js +++ b/frontend/src/Components/Link/Link.js @@ -47,10 +47,6 @@ class Link extends Component { el = 'a'; linkProps.href = to; linkProps.target = target || '_self'; - } else if (to.startsWith(`${window.Prowlarr.urlBase}/`)) { - el = RouterLink; - linkProps.to = to; - linkProps.target = target; } else { el = RouterLink; linkProps.to = `${window.Prowlarr.urlBase}/${to.replace(/^\//, '')}`; From 930370729b831bf1ce03b3b04a98211f9496ae3c Mon Sep 17 00:00:00 2001 From: JigSawFr <JigSawFr@users.noreply.github.com> Date: Tue, 22 Mar 2022 01:00:18 +0100 Subject: [PATCH 0379/2320] indexer(xthor): moved to YAML definition v5 --- src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs b/src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs index 8747fbc00..373aab7f1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Xthor/Xthor.cs @@ -8,6 +8,7 @@ using NzbDrone.Core.Messaging.Events; namespace NzbDrone.Core.Indexers.Definitions.Xthor { + [Obsolete("Moved to YML for Cardigann v5")] public class Xthor : TorrentIndexerBase<XthorSettings> { public override string Name => "Xthor"; From e66c69a2922f53e13724ffd18c66aca5aa587ca3 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Wed, 23 Mar 2022 05:26:32 +0000 Subject: [PATCH 0380/2320] Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 98.3% (421 of 428 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 98.1% (420 of 428 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 98.1% (420 of 428 strings) Translated using Weblate (French) Currently translated at 98.5% (422 of 428 strings) Co-authored-by: EthanChoy <ethanchoy@163.com> Co-authored-by: KevoM <lilmarsu@gmail.com> Co-authored-by: Vincent <intelligentvincent@gmail.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: wzw1wzw <opinionspirit222@gmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/zh_CN.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index 8ae36d444..84c73a256 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -399,7 +399,7 @@ "IndexerSettingsSummary": "配置全局索引器设置,包括代理。", "HistoryCleanupDaysHelpTextWarning": "回收站中的文件在超出选择的天数后会被自动清理", "UserAgentProvidedByTheAppThatCalledTheAPI": "由调用API的应用程序提供的User-Agent", - "Filters": "过滤", + "Filters": "过滤器", "HistoryCleanupDaysHelpText": "设置为0关闭自动清理", "OnGrab": "抓取中", "OnHealthIssue": "健康度异常", @@ -411,5 +411,17 @@ "HistoryCleanup": "清理历史记录", "IndexerAlreadySetup": "至少有一个索引器已经设置完毕", "IndexerInfo": "索引器信息", - "IndexerNoDefCheckMessage": "索引器没有定义,将无法工作: {0}. 请删除或重新添加到Prowlarr" + "IndexerNoDefCheckMessage": "索引器没有定义,将无法工作: {0}. 请删除或重新添加到Prowlarr", + "MovieSearch": "搜索电影", + "OnApplicationUpdate": "应用更新中", + "OnApplicationUpdateHelpText": "应用更新中,请耐心等待", + "Private": "私有", + "Public": "公开", + "QueryOptions": "查询选项", + "QueryResults": "查询结果", + "MassEditor": "批量编辑器", + "Proxies": "代理", + "SearchType": "搜索类型", + "TvSearch": "搜索剧集", + "UnableToLoadApplicationList": "123" } From aee6ee1a00947cea203a71aa5ded56d6486ac9d8 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 23 Mar 2022 20:58:42 -0500 Subject: [PATCH 0381/2320] Fixed: No longer require first run as admin on windows (#885) * Fixed: No longer require first run as admin on windows (cherry picked from commit 8d9302da7761752189b2d2820915d7d13197ce47) (cherry picked from commit daa9ee30a2c5fc2511e34167ce642c1bfe2a8b41) Co-Authored By: ta264 <ta264@users.noreply.github.com> * Build installer from build.sh (cherry picked from commit 6db135877a8394244a95142347b99ea651e0cceb) (cherry picked from commit 86102349c54f7e20f2d1e5ab104505a4ea0d68bc) * Fixed: (macOS) Prowlarr Bundle Identifier using .video * fixup! Fixed: No longer require first run as admin on windows * fixup! Build installer from build.sh Co-authored-by: ta264 <ta264@users.noreply.github.com> --- azure-pipelines.yml | 22 +- build.sh | 39 ++ .../osx/Prowlarr.app/Contents/Info.plist | 2 +- distribution/windows/setup/build.bat | 3 - distribution/windows/setup/inno/Default.isl | 336 ------------------ distribution/windows/setup/inno/ISCC.exe | Bin 109568 -> 0 bytes distribution/windows/setup/inno/ISCmplr.dll | Bin 407552 -> 0 bytes distribution/windows/setup/inno/ISPP.dll | Bin 187904 -> 0 bytes distribution/windows/setup/inno/Setup.e32 | Bin 707072 -> 0 bytes distribution/windows/setup/inno/SetupLdr.e32 | Bin 56832 -> 0 bytes .../windows/setup/inno/WizModernImage.bmp | Bin 52574 -> 0 bytes .../setup/inno/WizModernSmallImage.bmp | Bin 4158 -> 0 bytes distribution/windows/setup/inno/islzma.dll | Bin 74240 -> 0 bytes distribution/windows/setup/prowlarr.iss | 39 +- 14 files changed, 70 insertions(+), 371 deletions(-) delete mode 100644 distribution/windows/setup/build.bat delete mode 100644 distribution/windows/setup/inno/Default.isl delete mode 100644 distribution/windows/setup/inno/ISCC.exe delete mode 100644 distribution/windows/setup/inno/ISCmplr.dll delete mode 100644 distribution/windows/setup/inno/ISPP.dll delete mode 100644 distribution/windows/setup/inno/Setup.e32 delete mode 100644 distribution/windows/setup/inno/SetupLdr.e32 delete mode 100644 distribution/windows/setup/inno/WizModernImage.bmp delete mode 100644 distribution/windows/setup/inno/WizModernSmallImage.bmp delete mode 100644 distribution/windows/setup/inno/islzma.dll diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 40b05d1da..0f73dec09 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -14,6 +14,7 @@ variables: sentryOrg: 'servarr' sentryUrl: 'https://sentry.servarr.com' dotnetVersion: '6.0.100' + innoVersion: '6.2.0' yarnCacheFolder: $(Pipeline.Workspace)/.yarn trigger: @@ -200,16 +201,11 @@ stages: artifactName: WindowsFrontend targetPath: _output displayName: Fetch Frontend - - bash: ./build.sh --packages - displayName: Create Packages - bash: | - distribution/windows/setup/inno/ISCC.exe distribution/windows/setup/prowlarr.iss //DFramework=net6.0 //DRuntime=win-x86 - cp distribution/windows/setup/output/Prowlarr.*windows.net6.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Prowlarr.${BUILDNAME}.windows-core-x86-installer.exe - displayName: Create x86 .NET Core Windows installer - - bash: | - distribution/windows/setup/inno/ISCC.exe distribution/windows/setup/prowlarr.iss //DFramework=net6.0 //DRuntime=win-x64 - cp distribution/windows/setup/output/Prowlarr.*windows.net6.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Prowlarr.${BUILDNAME}.windows-core-x64-installer.exe - displayName: Create x64 .NET Core Windows installer + ./build.sh --packages --installer + cp distribution/windows/setup/output/Prowlarr.*win-x64.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Prowlarr.${BUILDNAME}.windows-core-x64-installer.exe + cp distribution/windows/setup/output/Prowlarr.*win-x86.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Prowlarr.${BUILDNAME}.windows-core-x86-installer.exe + displayName: Create Installers - publish: $(Build.ArtifactStagingDirectory) artifact: 'WindowsInstaller' displayName: Publish Installer @@ -706,17 +702,17 @@ stages: osName: 'Linux' imageName: 'ubuntu-18.04' pattern: 'Prowlarr.*.linux-core-x64.tar.gz' - failBuild: false + failBuild: true Mac: osName: 'Mac' imageName: 'macos-10.15' pattern: 'Prowlarr.*.osx-core-x64.tar.gz' - failBuild: false + failBuild: true Windows: osName: 'Windows' imageName: 'windows-2019' pattern: 'Prowlarr.*.windows-core-x64.zip' - failBuild: false + failBuild: true pool: vmImage: $(imageName) @@ -944,7 +940,7 @@ stages: - job: displayName: Discord Notification pool: - vmImage: 'windows-2019' + vmImage: 'ubuntu-18.04' steps: - task: DownloadPipelineArtifact@2 continueOnError: true diff --git a/build.sh b/build.sh index 1e31e7dd1..93396ffdf 100755 --- a/build.sh +++ b/build.sh @@ -234,6 +234,32 @@ Package() esac } +BuildInstaller() +{ + local framework="$1" + local runtime="$2" + + ./_inno/ISCC.exe distribution/windows/setup/prowlarr.iss "//DFramework=$framework" "//DRuntime=$runtime" +} + +InstallInno() +{ + ProgressStart "Installing portable Inno Setup" + + rm -rf _inno + curl -s --output innosetup.exe "https://files.jrsoftware.org/is/6/innosetup-${INNOVERSION:-6.2.0}.exe" + mkdir _inno + ./innosetup.exe //portable=1 //silent //currentuser //dir=.\\_inno + rm innosetup.exe + + ProgressEnd "Installed portable Inno Setup" +} + +RemoveInno() +{ + rm -rf _inno +} + PackageTests() { local framework="$1" @@ -265,6 +291,7 @@ if [ $# -eq 0 ]; then BACKEND=YES FRONTEND=YES PACKAGES=YES + INSTALLER=NO LINT=YES ENABLE_BSD=NO fi @@ -300,6 +327,10 @@ case $key in PACKAGES=YES shift # past argument ;; + --installer) + INSTALLER=YES + shift # past argument + ;; --lint) LINT=YES shift # past argument @@ -383,3 +414,11 @@ then Package "$FRAMEWORK" "$RID" fi fi + +if [ "$INSTALLER" = "YES" ]; +then + InstallInno + BuildInstaller "net6.0" "win-x64" + BuildInstaller "net6.0" "win-x86" + RemoveInno +fi diff --git a/distribution/osx/Prowlarr.app/Contents/Info.plist b/distribution/osx/Prowlarr.app/Contents/Info.plist index 040b18e60..1021548cc 100644 --- a/distribution/osx/Prowlarr.app/Contents/Info.plist +++ b/distribution/osx/Prowlarr.app/Contents/Info.plist @@ -15,7 +15,7 @@ <key>CFBundleIconFile</key> <string>prowlarr.icns</string> <key>CFBundleIdentifier</key> - <string>com.osx.prowlarr.video</string> + <string>com.osx.prowlarr.com</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> diff --git a/distribution/windows/setup/build.bat b/distribution/windows/setup/build.bat deleted file mode 100644 index bf0c5edb4..000000000 --- a/distribution/windows/setup/build.bat +++ /dev/null @@ -1,3 +0,0 @@ -#SET BUILD_NUMBER=1 -#SET branch=develop -inno\ISCC.exe prowlarr.iss \ No newline at end of file diff --git a/distribution/windows/setup/inno/Default.isl b/distribution/windows/setup/inno/Default.isl deleted file mode 100644 index b417cf916..000000000 --- a/distribution/windows/setup/inno/Default.isl +++ /dev/null @@ -1,336 +0,0 @@ -; *** Inno Setup version 5.5.3+ English messages *** -; -; To download user-contributed translations of this file, go to: -; http://www.jrsoftware.org/files/istrans/ -; -; Note: When translating this text, do not add periods (.) to the end of -; messages that didn't have them already, because on those messages Inno -; Setup adds the periods automatically (appending a period would result in -; two periods being displayed). - -[LangOptions] -; The following three entries are very important. Be sure to read and -; understand the '[LangOptions] section' topic in the help file. -LanguageName=English -LanguageID=$0409 -LanguageCodePage=0 -; If the language you are translating to requires special font faces or -; sizes, uncomment any of the following entries and change them accordingly. -;DialogFontName= -;DialogFontSize=8 -;WelcomeFontName=Verdana -;WelcomeFontSize=12 -;TitleFontName=Arial -;TitleFontSize=29 -;CopyrightFontName=Arial -;CopyrightFontSize=8 - -[Messages] - -; *** Application titles -SetupAppTitle=Setup -SetupWindowTitle=Setup - %1 -UninstallAppTitle=Uninstall -UninstallAppFullTitle=%1 Uninstall - -; *** Misc. common -InformationTitle=Information -ConfirmTitle=Confirm -ErrorTitle=Error - -; *** SetupLdr messages -SetupLdrStartupMessage=This will install %1. Do you wish to continue? -LdrCannotCreateTemp=Unable to create a temporary file. Setup aborted -LdrCannotExecTemp=Unable to execute file in the temporary directory. Setup aborted - -; *** Startup error messages -LastErrorMessage=%1.%n%nError %2: %3 -SetupFileMissing=The file %1 is missing from the installation directory. Please correct the problem or obtain a new copy of the program. -SetupFileCorrupt=The setup files are corrupted. Please obtain a new copy of the program. -SetupFileCorruptOrWrongVer=The setup files are corrupted, or are incompatible with this version of Setup. Please correct the problem or obtain a new copy of the program. -InvalidParameter=An invalid parameter was passed on the command line:%n%n%1 -SetupAlreadyRunning=Setup is already running. -WindowsVersionNotSupported=This program does not support the version of Windows your computer is running. -WindowsServicePackRequired=This program requires %1 Service Pack %2 or later. -NotOnThisPlatform=This program will not run on %1. -OnlyOnThisPlatform=This program must be run on %1. -OnlyOnTheseArchitectures=This program can only be installed on versions of Windows designed for the following processor architectures:%n%n%1 -MissingWOW64APIs=The version of Windows you are running does not include functionality required by Setup to perform a 64-bit installation. To correct this problem, please install Service Pack %1. -WinVersionTooLowError=This program requires %1 version %2 or later. -WinVersionTooHighError=This program cannot be installed on %1 version %2 or later. -AdminPrivilegesRequired=You must be logged in as an administrator when installing this program. -PowerUserPrivilegesRequired=You must be logged in as an administrator or as a member of the Power Users group when installing this program. -SetupAppRunningError=Setup has detected that %1 is currently running.%n%nPlease close all instances of it now, then click OK to continue, or Cancel to exit. -UninstallAppRunningError=Uninstall has detected that %1 is currently running.%n%nPlease close all instances of it now, then click OK to continue, or Cancel to exit. - -; *** Misc. errors -ErrorCreatingDir=Setup was unable to create the directory "%1" -ErrorTooManyFilesInDir=Unable to create a file in the directory "%1" because it contains too many files - -; *** Setup common messages -ExitSetupTitle=Exit Setup -ExitSetupMessage=Setup is not complete. If you exit now, the program will not be installed.%n%nYou may run Setup again at another time to complete the installation.%n%nExit Setup? -AboutSetupMenuItem=&About Setup... -AboutSetupTitle=About Setup -AboutSetupMessage=%1 version %2%n%3%n%n%1 home page:%n%4 -AboutSetupNote= -TranslatorNote= - -; *** Buttons -ButtonBack=< &Back -ButtonNext=&Next > -ButtonInstall=&Install -ButtonOK=OK -ButtonCancel=Cancel -ButtonYes=&Yes -ButtonYesToAll=Yes to &All -ButtonNo=&No -ButtonNoToAll=N&o to All -ButtonFinish=&Finish -ButtonBrowse=&Browse... -ButtonWizardBrowse=B&rowse... -ButtonNewFolder=&Make New Folder - -; *** "Select Language" dialog messages -SelectLanguageTitle=Select Setup Language -SelectLanguageLabel=Select the language to use during the installation: - -; *** Common wizard text -ClickNext=Click Next to continue, or Cancel to exit Setup. -BeveledLabel= -BrowseDialogTitle=Browse For Folder -BrowseDialogLabel=Select a folder in the list below, then click OK. -NewFolderName=New Folder - -; *** "Welcome" wizard page -WelcomeLabel1=Welcome to the [name] Setup Wizard -WelcomeLabel2=This will install [name/ver] on your computer.%n%nIt is recommended that you close all other applications before continuing. - -; *** "Password" wizard page -WizardPassword=Password -PasswordLabel1=This installation is password protected. -PasswordLabel3=Please provide the password, then click Next to continue. Passwords are case-sensitive. -PasswordEditLabel=&Password: -IncorrectPassword=The password you entered is not correct. Please try again. - -; *** "License Agreement" wizard page -WizardLicense=License Agreement -LicenseLabel=Please read the following important information before continuing. -LicenseLabel3=Please read the following License Agreement. You must accept the terms of this agreement before continuing with the installation. -LicenseAccepted=I &accept the agreement -LicenseNotAccepted=I &do not accept the agreement - -; *** "Information" wizard pages -WizardInfoBefore=Information -InfoBeforeLabel=Please read the following important information before continuing. -InfoBeforeClickLabel=When you are ready to continue with Setup, click Next. -WizardInfoAfter=Information -InfoAfterLabel=Please read the following important information before continuing. -InfoAfterClickLabel=When you are ready to continue with Setup, click Next. - -; *** "User Information" wizard page -WizardUserInfo=User Information -UserInfoDesc=Please enter your information. -UserInfoName=&User Name: -UserInfoOrg=&Organization: -UserInfoSerial=&Serial Number: -UserInfoNameRequired=You must enter a name. - -; *** "Select Destination Location" wizard page -WizardSelectDir=Select Destination Location -SelectDirDesc=Where should [name] be installed? -SelectDirLabel3=Setup will install [name] into the following folder. -SelectDirBrowseLabel=To continue, click Next. If you would like to select a different folder, click Browse. -DiskSpaceMBLabel=At least [mb] MB of free disk space is required. -CannotInstallToNetworkDrive=Setup cannot install to a network drive. -CannotInstallToUNCPath=Setup cannot install to a UNC path. -InvalidPath=You must enter a full path with drive letter; for example:%n%nC:\APP%n%nor a UNC path in the form:%n%n\\server\share -InvalidDrive=The drive or UNC share you selected does not exist or is not accessible. Please select another. -DiskSpaceWarningTitle=Not Enough Disk Space -DiskSpaceWarning=Setup requires at least %1 KB of free space to install, but the selected drive only has %2 KB available.%n%nDo you want to continue anyway? -DirNameTooLong=The folder name or path is too long. -InvalidDirName=The folder name is not valid. -BadDirName32=Folder names cannot include any of the following characters:%n%n%1 -DirExistsTitle=Folder Exists -DirExists=The folder:%n%n%1%n%nalready exists. Would you like to install to that folder anyway? -DirDoesntExistTitle=Folder Does Not Exist -DirDoesntExist=The folder:%n%n%1%n%ndoes not exist. Would you like the folder to be created? - -; *** "Select Components" wizard page -WizardSelectComponents=Select Components -SelectComponentsDesc=Which components should be installed? -SelectComponentsLabel2=Select the components you want to install; clear the components you do not want to install. Click Next when you are ready to continue. -FullInstallation=Full installation -; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) -CompactInstallation=Compact installation -CustomInstallation=Custom installation -NoUninstallWarningTitle=Components Exist -NoUninstallWarning=Setup has detected that the following components are already installed on your computer:%n%n%1%n%nDeselecting these components will not uninstall them.%n%nWould you like to continue anyway? -ComponentSize1=%1 KB -ComponentSize2=%1 MB -ComponentsDiskSpaceMBLabel=Current selection requires at least [mb] MB of disk space. - -; *** "Select Additional Tasks" wizard page -WizardSelectTasks=Select Additional Tasks -SelectTasksDesc=Which additional tasks should be performed? -SelectTasksLabel2=Select the additional tasks you would like Setup to perform while installing [name], then click Next. - -; *** "Select Start Menu Folder" wizard page -WizardSelectProgramGroup=Select Start Menu Folder -SelectStartMenuFolderDesc=Where should Setup place the program's shortcuts? -SelectStartMenuFolderLabel3=Setup will create the program's shortcuts in the following Start Menu folder. -SelectStartMenuFolderBrowseLabel=To continue, click Next. If you would like to select a different folder, click Browse. -MustEnterGroupName=You must enter a folder name. -GroupNameTooLong=The folder name or path is too long. -InvalidGroupName=The folder name is not valid. -BadGroupName=The folder name cannot include any of the following characters:%n%n%1 -NoProgramGroupCheck2=&Don't create a Start Menu folder - -; *** "Ready to Install" wizard page -WizardReady=Ready to Install -ReadyLabel1=Setup is now ready to begin installing [name] on your computer. -ReadyLabel2a=Click Install to continue with the installation, or click Back if you want to review or change any settings. -ReadyLabel2b=Click Install to continue with the installation. -ReadyMemoUserInfo=User information: -ReadyMemoDir=Destination location: -ReadyMemoType=Setup type: -ReadyMemoComponents=Selected components: -ReadyMemoGroup=Start Menu folder: -ReadyMemoTasks=Additional tasks: - -; *** "Preparing to Install" wizard page -WizardPreparing=Preparing to Install -PreparingDesc=Setup is preparing to install [name] on your computer. -PreviousInstallNotCompleted=The installation/removal of a previous program was not completed. You will need to restart your computer to complete that installation.%n%nAfter restarting your computer, run Setup again to complete the installation of [name]. -CannotContinue=Setup cannot continue. Please click Cancel to exit. -ApplicationsFound=The following applications are using files that need to be updated by Setup. It is recommended that you allow Setup to automatically close these applications. -ApplicationsFound2=The following applications are using files that need to be updated by Setup. It is recommended that you allow Setup to automatically close these applications. After the installation has completed, Setup will attempt to restart the applications. -CloseApplications=&Automatically close the applications -DontCloseApplications=&Do not close the applications -ErrorCloseApplications=Setup was unable to automatically close all applications. It is recommended that you close all applications using files that need to be updated by Setup before continuing. - -; *** "Installing" wizard page -WizardInstalling=Installing -InstallingLabel=Please wait while Setup installs [name] on your computer. - -; *** "Setup Completed" wizard page -FinishedHeadingLabel=Completing the [name] Setup Wizard -FinishedLabelNoIcons=Setup has finished installing [name] on your computer. -FinishedLabel=Setup has finished installing [name] on your computer. The application may be launched by selecting the installed icons. -ClickFinish=Click Finish to exit Setup. -FinishedRestartLabel=To complete the installation of [name], Setup must restart your computer. Would you like to restart now? -FinishedRestartMessage=To complete the installation of [name], Setup must restart your computer.%n%nWould you like to restart now? -ShowReadmeCheck=Yes, I would like to view the README file -YesRadio=&Yes, restart the computer now -NoRadio=&No, I will restart the computer later -; used for example as 'Run MyProg.exe' -RunEntryExec=Run %1 -; used for example as 'View Readme.txt' -RunEntryShellExec=View %1 - -; *** "Setup Needs the Next Disk" stuff -ChangeDiskTitle=Setup Needs the Next Disk -SelectDiskLabel2=Please insert Disk %1 and click OK.%n%nIf the files on this disk can be found in a folder other than the one displayed below, enter the correct path or click Browse. -PathLabel=&Path: -FileNotInDir2=The file "%1" could not be located in "%2". Please insert the correct disk or select another folder. -SelectDirectoryLabel=Please specify the location of the next disk. - -; *** Installation phase messages -SetupAborted=Setup was not completed.%n%nPlease correct the problem and run Setup again. -EntryAbortRetryIgnore=Click Retry to try again, Ignore to proceed anyway, or Abort to cancel installation. - -; *** Installation status messages -StatusClosingApplications=Closing applications... -StatusCreateDirs=Creating directories... -StatusExtractFiles=Extracting files... -StatusCreateIcons=Creating shortcuts... -StatusCreateIniEntries=Creating INI entries... -StatusCreateRegistryEntries=Creating registry entries... -StatusRegisterFiles=Registering files... -StatusSavingUninstall=Saving uninstall information... -StatusRunProgram=Finishing installation... -StatusRestartingApplications=Restarting applications... -StatusRollback=Rolling back changes... - -; *** Misc. errors -ErrorInternal2=Internal error: %1 -ErrorFunctionFailedNoCode=%1 failed -ErrorFunctionFailed=%1 failed; code %2 -ErrorFunctionFailedWithMessage=%1 failed; code %2.%n%3 -ErrorExecutingProgram=Unable to execute file:%n%1 - -; *** Registry errors -ErrorRegOpenKey=Error opening registry key:%n%1\%2 -ErrorRegCreateKey=Error creating registry key:%n%1\%2 -ErrorRegWriteKey=Error writing to registry key:%n%1\%2 - -; *** INI errors -ErrorIniEntry=Error creating INI entry in file "%1". - -; *** File copying errors -FileAbortRetryIgnore=Click Retry to try again, Ignore to skip this file (not recommended), or Abort to cancel installation. -FileAbortRetryIgnore2=Click Retry to try again, Ignore to proceed anyway (not recommended), or Abort to cancel installation. -SourceIsCorrupted=The source file is corrupted -SourceDoesntExist=The source file "%1" does not exist -ExistingFileReadOnly=The existing file is marked as read-only.%n%nClick Retry to remove the read-only attribute and try again, Ignore to skip this file, or Abort to cancel installation. -ErrorReadingExistingDest=An error occurred while trying to read the existing file: -FileExists=The file already exists.%n%nWould you like Setup to overwrite it? -ExistingFileNewer=The existing file is newer than the one Setup is trying to install. It is recommended that you keep the existing file.%n%nDo you want to keep the existing file? -ErrorChangingAttr=An error occurred while trying to change the attributes of the existing file: -ErrorCreatingTemp=An error occurred while trying to create a file in the destination directory: -ErrorReadingSource=An error occurred while trying to read the source file: -ErrorCopying=An error occurred while trying to copy a file: -ErrorReplacingExistingFile=An error occurred while trying to replace the existing file: -ErrorRestartReplace=RestartReplace failed: -ErrorRenamingTemp=An error occurred while trying to rename a file in the destination directory: -ErrorRegisterServer=Unable to register the DLL/OCX: %1 -ErrorRegSvr32Failed=RegSvr32 failed with exit code %1 -ErrorRegisterTypeLib=Unable to register the type library: %1 - -; *** Post-installation errors -ErrorOpeningReadme=An error occurred while trying to open the README file. -ErrorRestartingComputer=Setup was unable to restart the computer. Please do this manually. - -; *** Uninstaller messages -UninstallNotFound=File "%1" does not exist. Cannot uninstall. -UninstallOpenError=File "%1" could not be opened. Cannot uninstall -UninstallUnsupportedVer=The uninstall log file "%1" is in a format not recognized by this version of the uninstaller. Cannot uninstall -UninstallUnknownEntry=An unknown entry (%1) was encountered in the uninstall log -ConfirmUninstall=Are you sure you want to completely remove %1 and all of its components? -UninstallOnlyOnWin64=This installation can only be uninstalled on 64-bit Windows. -OnlyAdminCanUninstall=This installation can only be uninstalled by a user with administrative privileges. -UninstallStatusLabel=Please wait while %1 is removed from your computer. -UninstalledAll=%1 was successfully removed from your computer. -UninstalledMost=%1 uninstall complete.%n%nSome elements could not be removed. These can be removed manually. -UninstalledAndNeedsRestart=To complete the uninstallation of %1, your computer must be restarted.%n%nWould you like to restart now? -UninstallDataCorrupted="%1" file is corrupted. Cannot uninstall - -; *** Uninstallation phase messages -ConfirmDeleteSharedFileTitle=Remove Shared File? -ConfirmDeleteSharedFile2=The system indicates that the following shared file is no longer in use by any programs. Would you like for Uninstall to remove this shared file?%n%nIf any programs are still using this file and it is removed, those programs may not function properly. If you are unsure, choose No. Leaving the file on your system will not cause any harm. -SharedFileNameLabel=File name: -SharedFileLocationLabel=Location: -WizardUninstalling=Uninstall Status -StatusUninstalling=Uninstalling %1... - -; *** Shutdown block reasons -ShutdownBlockReasonInstallingApp=Installing %1. -ShutdownBlockReasonUninstallingApp=Uninstalling %1. - -; The custom messages below aren't used by Setup itself, but if you make -; use of them in your scripts, you'll want to translate them. - -[CustomMessages] - -NameAndVersion=%1 version %2 -AdditionalIcons=Additional icons: -CreateDesktopIcon=Create a &desktop icon -CreateQuickLaunchIcon=Create a &Quick Launch icon -ProgramOnTheWeb=%1 on the Web -UninstallProgram=Uninstall %1 -LaunchProgram=Launch %1 -AssocFileExtension=&Associate %1 with the %2 file extension -AssocingFileExtension=Associating %1 with the %2 file extension... -AutoStartProgramGroupDescription=Startup: -AutoStartProgram=Automatically start %1 -AddonHostProgramNotFound=%1 could not be located in the folder you selected.%n%nDo you want to continue anyway? diff --git a/distribution/windows/setup/inno/ISCC.exe b/distribution/windows/setup/inno/ISCC.exe deleted file mode 100644 index 8e54535ce4118059dccb42ba052bc5ac34a3e294..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 109568 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 diff --git a/distribution/windows/setup/inno/ISCmplr.dll b/distribution/windows/setup/inno/ISCmplr.dll deleted file mode 100644 index 39129a3d2a1141cb2034d1ddf6dd8543a29819b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 407552 zcmdSC4R}<=^*??$yGb_5LKX<`2vHX$1TZn8z(Nfq8v_a~gg^*Jr9uqITa&whH3=J+ zRBp!9)KY7!wNhVdk=j(P1oW#L783%9A)tg81r_Zq7d1eH1tR<ZoVj;50fF!DdH&Dy zd!ApOCp&Xz&YU@O=FFKhGiUCdn(ve%BuO$!@lr4-Np*<RU%E6vi(K#5AW2)TQuiV6 z#C&{Xo#DQZZ>*`ARkWxiaYga+M~de!O<d|KkrRKpFtOOREYY=W!NTIiIg6I1-QF$M zcGvaL{@=`VIwa{nL$uWYfl0$d^&XRcyCKdH(O-HlQj%WKQdhr*xE1kQgpyl}gK=Pi z_%rFDR1-za6n_!nTzW)dDzC*PsV!1^lpc;nN=^$xC(4bXge(7|q>l6})BgWIXH3sT z%O&akXZ3bbTf>de@Fz;rLzxq2O{AyR9{8cQ_eA&t!Y+U5lH{F~lOt04#Ug0d^WVH2 z4msXYix$k6=cBpQX0%=Ej_?Y&bb?!`!3iFLS3*eNzZ@UnoTG{tE?NGtr1J<ooCJIy zTn(<I7+@NY!@LH3m%nu2>+&dxzNCaP{|nq@h5p}qh>a?dix(|><Vvc?TiqgQX%BZ; zECR#b()J{`bQ1q5i1(1<r11z%S;Y$%_L8y@wM<^NNS?f`M4rFw;e~yq1xSj|Sh8^b zGS`Yws#S8Md`!lY`6VT@9$T@{Dy<DaPn*AVVNdBfJjaQAdY)X;Q}TvWob!tpE|aZN zJ1}cFCNC>o-b=D-m1`B}Ec!L*Ij$uYEi7Inmt++$Um7oUAjzD$sAR=_`Qf4j$(HPv zx=mdu7cE~falwM(g(W3Dq!mbu)zYZ;UeYEcSh5x^ToQumEfFKSXD%$9?^+^f&tJA+ z$-?5Ef-`Z`7Oo1lvzOqLg?JN6ik>z7mx~uZELW#X(V=*V(UKIE^H_<zaH%BukRKd6 z=F3Wnd4ogm(8Clx9HEE9^w6e<>3W!`hlBL6pB^UYp;ZqpdT7=|lO9TX*l|p&KcI*0 zdf29iC-so)VV+)YmL59w@IF1v*2CjE{4qT|qKB<|xL*&O^>DWy?hs+l><{kPUnzNh zA-TpCWnx?|miX(zV36&oY;r}Wc^{bP+mHeP#h`SfFs+4cGkU8t>rHI1(ocz+<hiiG zb&^FftI`LsHHxI9n|#chGn<`et^6-QRq53cu|A5^%x0Sur-k)WtV*6qnPgIowFVSq zP7^aLvC0e+>rDhH)|V;p<;<RwJA<845^RjK0*RSyR1=_;*(PRZ8D`dO%(2+}xDuF; zZzjSs%t{o?uo$vTY9H3eINN03=IVybKZ{ICXGiU-Ya9EFeZ+H-xYp}3rFoU8{DKET z2xNuo^lT5XR(6ry4t(~u;w5a4af*p?<D(Y)$EzN&x48zgNhSlTpJYnPuy`J~NUls& zG8*_)JBww-CgUC!Fg|Xvf8vTvDzT`yuvlPFEVktHN~z7ndL}n3ITp4bg_<vgh)^xH z2Gz_4+Aq2))4X#vifTX)JH*;5F42rv7X1MQs->cV?2C$TCD<8CiD|K+NJ^BX+33H( zPhdkpu~!D=o7uj)G2kO#qSeu>i00bG5;HpaL4cv%Mrt+Hk;@LE&v;`7rY)<q*d*{3 zQ9PHw8b;|Fa%IID;Ot!P29RR(*rm>De?$`a+qK$X>eUKvi+VlVPb&A>Oz7jrOq&@T z45qaxvuqahxXEVxNXfKW*$vbRbq2b;#BBe5RTgV7W?1aVS!K7&Hgkzd!EY$hveJY? z7QL;r`41gJ3S%216M%(G3~;@Qnsl_{A|ZDDon_igsMYEzwOJ&&KRvQpHnU<y%#sYU z@I>P3*`6Q>*JPw!r<*mi6BXY`ZNZ>1!B(*?7>|zmiXPDnGvQK(;n$q}k&cCp7R?#Y z9x$_Vi}9jeT^YeXx0l+?D@_c)_KPbAQwPAnNxnEIhu@+%fKU;YYAn06;*y~Jeb07_ zpoqpCjg?k*20cU+d@Crp!^TvjP96BE7}!V22qv0zBF2P?7-TCkvOzZc4<!-oCy+3x z2xhBBz&|f`<sj@dDNKO(XXEBH3;a(uxLVN|yc=ZvSMq|>1(KR(f84TW1lz+7U{LX` zkVvQ<*~zlRK*|aaq+g(SPNG6}G)BVbt|pAsMt%+~An+U6ZZUGd27qV0O>(`81n7b& z{%=jNqV!>-@q=W`Vq+Ir+f_-5pc>>zdx_cgBmK+)iSfUE7VWEsM6v_P7@`?wh#Egk z^<&^lavHKM)er~hj{>5CM8@@RN+pq@KH@`3xJ)+cD}PNG8*AX}!)Wg4f~HRhO?+h` z#Q!o>hfqRCrDn57&GsK%<A{-?8QOIKH2g}d%QHrjhXIhK3wDY~NHtl((LY}RN27I2 zAu*=$2NtpON`kHWIniBTi|)F^W^981q37&hl+0tFu+NhB0m+|G7pMbg>Zpf#0g$r$ zZKle@@{lmqJ|VB*gGHfXgh7hXtT8Wv7^ju}0}(`;HyYHC63S&K(^_(iPWN|93xc;V zP;M&fM|F%n9}K!DjB2iwBso?~8igcHuRTRELCO;plc~UJ#EJqK0nmj<0>R+RE0F4$ zK);fFTb+@lw>LedH7WN!(VjlR0FCE5S(k?-%wCH0@&d#fB75N1kmk*wJ9mL%Ejkaf zt{~%IK<@L8?JY^_H!l%%0kt8=J%Qp<{MtRJiCWY;Ak?BO5EKG|R*$rS2y*f}kdo#V z6ze*#XGmpdn4Nqmve`ggX??4)KtY<uf;AKqEN~$v=Iu(a+!r%u?-YUkvvc8Omw&<2 z!mRgfHy0fRfme{W51<;e_af%==Omz&hvya0+-{E~2DxHr8tzR|n!U5l73WD|tr?C9 z*IMt75G^82zOG%p0nh9PYN9fWwKGYHP@E>r`k_b->rHg4RyM_KuP=@^PO%{9!+KU+ zpmZ14R5x`USs<9N*iMh%R6WSxxnM1gZ!|_rlAG=28=&0h`8*d)r53icq6v!1t(cX# zdA?v|U?1pg_ME`fTk#df)EYz$y*rQ!<S-JM*K@&A+TF7=0<(bE#CKvK3QVz`n2g&z ziI-rL=y;IvB~?*zo_=M0exX$#J5=#C)sgIDJJNcb+Xh`14CNEo&l(JJB4M$xVsmnX zeT6xcOG_jEXTTf3V7{<D!dlaU%=i!Fx#hT_gxMG{wld@E5w2eB4D?D7O0X<5rFw3@ z#2RTlX>(M7lpi1nCnkqS&FmxSGuB*fxhr`un!Luu0?C(HL-I$SfTgS_sn_Hjvyn8* zQBuP3NI3vrRcD#_9we|4w#x6wVp3Dsr^%lI^9sWJk&(ta3c?!ORuWsCa946O-$*%R z;{4-mFj#BQH8bdfp%Gw5l@c@a85=y@qO35(ydmjHVV~8X&}4^Y*0jTTv<g8|?yqTA z=9!d%>Nv=AhDqrK^E2P1jzGEbl2qDF%n~u+GwhAN8%QdZ8-#3jfhMk?pC=R{S1M1} zB9=0XCS8yrNlo5BnVuaHtoIVa5wU>+5{NBgetDT5F+vGS*tyW3ZLF<&yzSLjSqFbf zQ{QGNNHGw{{|FA;Z!=dO7A%{|qV26Eu>x08wBa5Ti#Fotj8V2(><uMmZUx6e$*?ke zc(`dR2^5b*?VjZ(6c7}!drX3aT7zf1m6}C%t7f$Bug);>6;J>)J<4%xJD;O*h59Ul zdO_HG1Pl|M?XJe`>EoYtEpW>f1vLC=E%iKNf&_9__0be4oApF{WsA$KtI!h|nM4QK zl5HOn^Z$p~#BR7BznEU*f4de<VMByXUH&+A|2z}Y*92H!Ws=!GL^dfy)Q5FR=mybJ zKnQCE^QPfpkVaK>n%BP$c<e4|%_~VR$x|j-%FIR=dPQ+aqPq;Esh8Mip~0+;e$V$N z!)O}t>V0VNog~XSX0|Q40fG;GvCsI~GyEa2S?$SA+lRO!8Kf*)2x#IZ=DQ{~VSPdG zgP|nZt-AVm_2S8xh#-xzL|BJ^7IahE+1#QfH_~iy=K|%HD^zaYY4n*d+VgdX=c1)7 z@;%zpsklg^BL3;$6XSf9-p7m{udzM==_F;U@n3$7?PT>vA9NFzBlc$3fXg696J%OY zDg8}5Rv~99&jLq-vHns76H}s+xw)O)uDAls6;QA^!fy(zXEV(q=7Dydf2zrFgHV`* zF}eDwFYPx_2d|luB*M^m>Sh#=`Y6$Q<Ob0r`>unusXK<>?dX~J(FdqBJoA=-VOOwf z^eLK?KI}#_FLQKY0L-0RK(dE^m?3%rl_!9-P-hI`FJc-)XY|p=x*5bbIyxxu&!>)Q z$}Q@7Gj&Yr0_DalYWonDJUavNVS~^5B3$triWn;UBYuM2#N6T&dKm*YDUz6U)@P6% zjFcO5nrUh=pWBA{%Ps50X=Bg-E`FeTx7nTM%hF#&x)EzWUV~w&O(j^|_*lR`f%xbe zktFzO5PYtfK%GEZuso6vfmjQ9<Bx$mexysxdUjicJV>AQE|^04E)IF>T^_SRO=69n z)g~wlG9sfqtIc7ZC}4V_1;#_%1X|cW3`9FDw++PIuD#SB+`EErPyax@)E{yj?j>PA z=<Dm#o`z`8w;i5K5cUs9*ctbHXJTboGSCc%DW#FM+AqaF;i0?($)CYUwTpJU#=wqE ziWDMcvKb<&{krhQSKo*3M7AN6og}i^Ie!{uw4OCa(0%}#WJs{_6i5a1q@{Eq`y4Z_ z$p+1@7@3b0{to2%FHzm+{O2fWNN$8BYtm_WM9dUegPKZn$mrMWK}@SUG#dH|I4#XM znn=|L2H`UZSz!)oD9J`#o8ppc4gSBOHl7RZ0iuo)!BfHaZ7{KDEn~6SVS$%)$5Ip9 z0^kE`R7dbaOtFFtw1FDb9sFxxXks<GO&w>%IuI>{aiES0SrRvDmV^(p04-;H{9B>0 z<QS^f-wo;(Ge-Ywk{Q~c2#q<+CZXZhi{IAXRrfuE29YKF+R$rQ!uNj%>OTVsM=|)< zdgVx^phLY2vi35qFaqchZemhsgxTB5B3J|VH+r%iSOfX^T<TgMzXah|$~ra2KT+Kk zGI{YN$z&x4?`1LxJ2^Jk+gw{I#du|d4}Gv0B>QT#bc;xLAw9xBQ=~I<Ws`h+WsBU; zsq6^$wgO--O7>R-%qYNMg9{mYNtH16Ln=yGol3J-6_xleN<eRUj;&$cOwE-N&>HiD zd$X(D^KWrWkHzsPFa(*KYydwWC`r3^?`S&k$&Qcr9B$ot@X(RZzc_mAOV}aKnKO7E zAU$;iDb3B#1GTAM|10Q3!tdncko&a2L(lwS6~g^3<-(S3#g34V?~ccYJs*dRLfW(A zt;i*NY4#kYK{=r87<+C_FZs6m^AW3upLtcO_k3wQ^U8w{_^RdZ9o41r9hA}ICp`x< zjHeO#P|ZGfV1BXL9r*Psqnjs^{dLm({K4_I=MRod0NV~@`S|?75jM|uQ=YG;u7w&J z#9^7(lcI`Ky{Ro#QB{4j?n!E16=B#m6ZWBe3+v8?j6LYeoFeyT(@g9^6CUpJG?+b& z<|(eP)F@Ab$<t`c_k3lP2UT?+7w@`lirlMenqk~@gUdEWHdjrH7&kq_)!*P%d*_ci z=(3La$z`ecTkBOTo+8Hlq}hr&vu7xK>c6K7&1?Yba7;sm*(R1x6^`+E&7N)MX`(`} z$+OM$fahDId}oz;T&yc)8Y;{-jGJO`4V{Jxvm?e$iEs@_r9IULu2v(`Yvw48>poU? z)E~1JDm#?D#M78FZzy|-*&81eJelb^nV@{4H2f*GIjMOIO(Us?Q(MlR@@z|4moO*; zU3aSTY*}Q3Y0$`wbwlo9_t_FE&SR?(v%?k&k`9(fOVfk3iDx!eWey6ii@xVx*ICc@ ze$?O^Wp8SW|BoaVV*f;GaAE|^Ko=bTaQE)rma4&7?u&_X;6IZ4;z-%yzL+dea$mH` zlhz)VZ+ELH?u#+2hK~)bx~1CWHh2xKfM0vq_3fpPWoxCk)H*lyta3Zmlck!@wU)Qd zOZr0n{?bQ)Qa|_*mBtHr`Ahf3`Nc-Jny6u18Ru4exGzSoYIgf#fxM~ym??z%Q}qqs z;jbY|{UA!9nL%zKuLszQ<Ec$m-6v`i3Y#?ba7>Flh^14q**>MiWt~zr-hBJ`SoeRA zx=fQ@r!&^IqWvuWq;HOsrE`9QbV;MKE$<DM%~QQIu!5a@=8d_cBb4R`1%DJDOJTE{ z*~*g`*U|hg3?QYo@~lhc+fkbM2~57VEwUMl1bzfc3h~(R!rS7j!E+=JA_Mrq>1bwt z%MhH=;X@Pt&+GjVmXlU5suXyvOd8uPo6#DG!;ertH0FUnftkndmAkXaC$YW%V{NQ| zE$F1YIlpI*AA>^e7QZ=uhNm&2@btgr*tu-pN!Z@sJm||ac$0Rp`|s(Xc3*)RZQSo8 z965z-Kw->bxo;t?R&R;b$s|ttClA{E;Jo0M^O!j}zfH(+YEx>kY5-etr1GrXyO90D z(-2WLEo#g`dgyN0Gu?GcBmHx=U)2Cr{f|_2fA^@{2gSO-KI-~@GIFybLgRCe@(JX> zNyF6(#evH{J3>Zuu;Gizt}_~@qwAv8SWiP#SSrN&Sfc}kvK8nzIYE#TrIFGPiY<D& z>$Fz>i+pup)d1wEybCSg5iL>qhGwE>=8T-6vpuy18)4Q3Y=F{VS!8aUXu5HPTT&)k z7AUdv=H~nSeQ2u6w2fft79NY$9-oSt-^Z-MnE~+DJ;4M)HmtNR#_rW(spyjn-*xA! zz7gY5%ai0jPUp;7izAS`pK|9S7n?YFzFCV6NNc7vhe(4$4dIJ%21`u-Lo~2!LTS;? z9RChVA=zlcruRgHd#qo!xW}q4OZ*4ki4#?$r#{k9--WJ0G|_y5LNm15_EK#Jjt7Ht zG39iD>j4Uhnik66jQsr0dV7V)-$$8$rp!E|fvlHv=_c9%iLcy*--<DN0KuI7SayPZ z8&7~$$a-67l5B}z%K#8;sr1ILtw0P04EAWjPGuXRVc8Z>wkZOm9=7HJHZTWd17z4@ z$yxNzk#1=wPeZlXY9GdL!h{*D1qw-diGJB~GiH;<drSub=kZ1IkAXG#wSOl1jsJ+g zVzl^_SP!K}gcHsF3=md_Z0MfL+RztiS{vlSd^ScJ>uuJl?*KGW?~3)GB5djXAcNRF z7HemmG|i2y{#A_f5sSj0ouK?MHXz>xHDsU8U45a$*c_q8Fv-NEPvUv7+T?z04UXX| zgRcFU1n+e<(5lo=8`+>J;W9?{gH-}5P}?B>4_ayw#}dG?)WcmkMeM_2lC$W@C}NlC zYuEyUU#GFxbp^k`Ec0z{s>#e5Fa{qs`EN$myaBL3XIBC^p|K14nmP;Z*85!^!lsxS zCz&1sI>Cy?W=J3}C!~9+NuhH2vvTLmMz79V9F3DN5|f#J=U19617}KOy6F?(;F&~$ z)={yF)^U?8o`+07>HX4;O)_&2Y)t+HIx*FYt>^{JI+yiSdURF?+2j||mscV(^T{Zg z&lcE5q<XPQY|bm-7l9`Dl`pjg^R74x0R0P;h~VCB7Si!bg3W&;d_G9tVK=i}GmDr2 z>)5+ygna*m-%_NvJZEGiBJ%wsp9B--3EA>A^`XdL1%r2cctr7?a*8^00(#cFriVOX zBsK=T@~CXNSGH_Z$Bq1n9&hvT3GyxKh}s?M@Y*KzmfDZin`%E%2jh7_?E$q<?H;vf zZL8Y7_K+G|dr*z4-HCmngG0$UU^6W|4=pIzX6iZ~U61l-Y4wMmBAIAQA(?19h7?$D z6?QR9a}roaKlz5v5jqHXlvZtwS`lYC79OBc&`qLI&?JK^;F78CAXPjgfp`-MznE07 zuLfGw(Y}Dif^~`+ow*w|Dn(``axK<R;3N1eq5v7Y!)0a?0DUaRb3Q1W#~NHeVrN;* zc{!d5yRjIT%3|xjB8hwzyD3Fx#1^M>FVRn%OBO9pL7r;K*+2!Hd@*vB8`hyZnp3N~ zji50TNqK9VT*DTy-Xn-=(-S`a9JNj4IQa;a!jLuiSR@toIr#uB<)E*I2an<~f-qEi zL-h1Uonn6ub?Bs)_SPvl25{hta`M5zf%1n@Q3xnb2YMSoD9d+|?i(qgPUQv@{f;)% z?*t2e8zPB#19O0X3DgXSCH-$!WMpq8R={?_^pH?FsJ2qdW4&#FKvG1o<t2h~2f$b_ zWR<VS3Nsb^B-9rRSdW>&hrJRqhOIMZ@)qn~<>v)kQd=+*V&@hJ38Hee9dn+x8tbSs z{tV!hF)Y`L6M%+DI@U2@6wG9~mYL4F*4y2Zb9N5@pD%(zjP?Qy8t4cs$m!pR!eIE6 zz~s_y%9Mc1Ts<kk3xEv!+=@^6jP(*wP|!bvx(iSqpJ|%wux1~%;DCBcVB(qq&Y5gd z2hT$Z*m*Nqb_chfp;o9y)bJ!#+v|!7PtwK{&6nUA;V8c*<TirD`mubF)8mcd&*KrR zg?z=?(U=~f$)dqzm9Rw9);VYZZ2AD-jV@NsD~&KlVw7!48(%~0YUKgyUOQPC%sW&0 zY6~IYJ^*80g-H`TiNA{nii5HnXO4@N`(oiC_rQ`vjvF_{C`V#(qVh?TCMkRKllJ=8 z5j5H{$2o&mSf}4~MV#B4XQ<D6(7%+jAa_QV-r)nbyJ@W(zqSDspeqHdAM0SVI}8`b z?veZQ2yk3!W79fVFT(}ijAjy*TqVV8RL-lMaLgwRYk|RTmG8Hk<?hZI+=a*dJpZ3j z9pT-l>~XS;4r5jaZ=}Y;^j2Egy&b#^D3uGM3S&+OUxvp#<pOL~V{m$a-v(H!P}%9X zQL&x=$wYt7?3qqwU#gegx86!iYU9L?DX!CeDL|Y`1Iv6NK{<^!#-h&+d-wq0yw~N= z&jYE(;FN&yjmUpsUS73reef9Zi73QcbZm3{+NZ&KbWaf|c$8&zusI!9S(oN@U6<Z_ z^>yh@w1&k(aN-oXFIJ!9rpVTcuQ9nw6<^XX)|a<pb$YX?KpljtlA5o(Rz-VoBo~+j znRJpZiRTEPRQJ0(-DF>)X~`ta^3WVCTOjuHwYlG@^kUf<R7NE`KqH_#ZFcsWr!@O= zfM6uc>%igeEmKMdjy+U1Bxzq|Q)&OP2iNp4kkw%3=|H0PNNrKSQ4XrANScZna2}=) zI)5T*Q9j}2=n^qLQ`nS_X{E!*?kT&aGFX07(y6hZlt(C^B%L>$t~QP1&tSt4u0gGA zW=GNm{yG><T?;a116QtwjP;yJy#$cyWf7^tu?K+Q0DH7UX)~PQE)>Zd+v<v7gIQE{ z!fj|!(q6+hLxA4})Ii)v@k2_7<AJ7kvA>fJbg6p(vgsXjAlg$_53GvHO4?hVfPrCE zcA+7A&%E~F1F{9JJei;BRm~W<`AQ&382-9^pslGvAj@V(kbJXeb->`d!Najb5aU#i z@g{6><v|4~MrB1ugDFK)hbhhcFeXH$QIxPM7eMdWQ>78gDgNa5L@$>pTOap1z}=7K zQ-Aardk|0u*O}9w;RS%4=WC#YPt1!=IaN~(#Q17CHkOsfM!~&;^)a+^*cKAxaQd3> zso~+i5qm4M4XI7;K&;%~9k9rQ-GOfM2zQ{noKZ`wEdN6wT#17MoxUcZW+-vWy(Z;e zvvRM+<Fig*^Mjg_t9+`o8t)$!!R{Ls#b%9)6@FjS*PJL&6T*4QY5pL@VEURi!FljZ zC^3IA4Oi%`Ytaqk=sI+VsZJ)UM-$ceX;g2-MxW=rL1|qR&9}lrR<o6zd@n`rR$4(h z9}B~O`kFIWBmY@J=#}J?T@)f;qkWm6eJ1|^duI9Q^Jpi(6-n5~a&lU0<?;8Cqw9~{ zitQ5FP^YkK8-UdjgWb&=iJtjbE`ye`Tf~Y_!Yo-0-w9{V9D3#_4xr2qoT4`HeFUAR ztqd1Sdj3wz=d6K!oYuns4G7B5Wl^E>8<CHifi=W;%{MQHzeFXQ;g93v1t1nuq4~_{ zbhaY>N8rQhG5m255l4Sz$wfpgC^R`|Bjb+{P^TcYKhQZvI{yV>4yageEtY2Ih}?^x z5t+GY(2XLK%y*IT6=gJbp|GYl-v8YRu&vhW|AxZUmO^Gdw@pfim&O3k1#@xliVNh$ z<?2;PMgfMD|KK@nTG9gyuDw9$!yd(wLeCg;@j&Oy!iq7HL5BClX5^@5!1I3qK0mL} zGtOMngT*RlxE(0j__Zk67GGh-ILYAZk0UT_8FkL`gx>%UMxUr?rjxG#x)^VK<t&l{ z$TMsmZ1Z4bY35F0g&k<@g^i9jNkU%=zRj+7v^n`NP!i%2$$OwEm^gp}M;i_v903JR zg^ms-!=m;J7s}z5P>G}3e8;{Kz9uuUcPmbNu#BnB?cg^e7x;D}C~P#6$p=j4dD__+ z`n{EwJN*cVI`w4@%q-y~7QHX%KbfOAP8PBVcCgUiih~lzNnQ&u{|+#>Z~_`Mx6pIZ ztYy3bvi<*}4ADk3P1wR|-rS<m6KJD9Wr31do!bT^Y#09=Xu@ZDuOgq|6OriipT+#E zw$Zkc!G&H4m|d|{@j&2LXNHj%ZZS*zj{-|>(fTVY;NM>jeLbcppZ|{ny+*|xfXyTB zF|XFoX7sb)k7IgFi=LC#!bXz~2F<Z8Bw^eSXlUVI(<wftJH?38c5&A3e}phI?}n#f zB9nuS2+1F25G-1jZVop4m`H>Rp-6+d`!WGFMiN9D$S0YBe~c5Buw`bo(>gP_!W>+Y z5KQ5}-6!P3nCA8It%&;&nZcZv%9ip0a9YZ?%pfPM87M%|ZVej8`*VGq;XyqYqy=#8 z0kpt~=WLt>@M6L<o3%k)vMfrL74yQ#e*;2}%a#+f<x&30XfRz@ac_m`CT$@@x-n}| z$}ilKdMl-;Zv}v~g)-H6O7Ln4I$%Bk8?$UriXd?g0(W^foS@zWB!u6MV8&u;rn5RL z+sR!mP|ks1{8|;sN>oL;>1~h_U->c~gVRilrQn@>5n$5e*ES((WCeaoBGSC1F`US& z)bjp`WE@@W2VPM@^|N&NHxmH&0U$p+zLEhV%?po|``qtGQRV>In6CanyJyMU2$P*K z$&VnGgjlw#K)ngAAo4-fTf`sJ;<IYR;ve~!dj-w1UC=97*B8aMA{k@Z>Ip=+q8qak zi4X9b_95#@WHn}qeyCdnLR7#0#J@p~dboNWQKV!ipigO$OC8pjZgv9{eXL|#8`Jy! z73h@gK}vR_l5ML_&xQ>!@IOz$;K$s*wn^?0jzwSk*u}Hg4I@|TiVH-!%N%qL!WL6^ zU&RGM?zy^0fZE@N&B4on60ZWZ3qX)h=obP#A<B36T!>iJUqc$le8C(W3P!-#e-Xgy zxe0ebu;n&U32Z^{%l+`|o<M6)N$%^OK&weZ{1aZ#Ae-Z`aaWJn1{w`<UfF_?AjV0s zSyep~5=Eh3Z6Flyjjyeg#6d?Ijyc>o=IC`VDn9*QHqti`<jD27Rsnaaui~qou}yMI z0I26C*LUs-Bath)dP4xG0JvxbelP_MZU(&xby7>Ew3U*0Dx{kK3!PC%ZQxN*JR+BO zKmqVuTgd~F$d_DJUIF7VIGPCK?|y>ZU*WkSQsfG9&$SNprZchdW?~V}#DbiO#d#A} zv?-~#r`<97&b!8poj55Y(~*TkR?-8#sU?0|`%uEuk>arqkI>s~uo-5f8%RRrSkDFH zs{VXFvRH%ifGIe;pO{SgVM`Ngysi*z<#BjWPi>`sQ$N^B;-GHcN`p+TCHJd})k3&k zquA;M<7#qINOoH6d)M?aI4#LLoio_ZGp}eJoi;a5J!HtXh?A5F#4=aH49tFXOCT?Q zu8v6FEF_$-$3CI@8Lviwav!suTb<yq=X`qkjUIoxbH<i*BJS5H%l`qpRX?tDbp!CH zSR+3D5ORET^L%NvruEOnQ%>69ssYKn%HyzD-^*#r$<JfE=1uaGul?2<U>7Qhlh2Z$ z{BA={8;mVYd$zeO#+aS3u17H4;&aZ_nsh5x_+M#F>4}zn0Y>KKhZ@o(8sguD%|zaS zAM8!ftez3%sld<nYYT7kUCsxMssvuP&0rTiP1q7W{pPv7li7v*<h`t61~&kHF3hq6 z4?f_pqOKzUY}V#H_<fo;?QmK!r}Aw4+N0pc<!5Tqbf#ufBgLuM+Qac{{|6xY$y&c7 z-TFJA4hGo{nQYq8+Bg1k%D;HYl_V14*H(AJ_vs3stra+~I^7q0%aQJjqg@M;^o}^m z3)i|GNqTMfu#2LI+(%EivwHl8#-LG4b)C4h8+!&vaZX@t#F@aYsCI5X4*KG77LleO z^Bp{<p32IbmwZP30onMor9-FSBrsccOpxGF8ehEzsWftjR3|)hctq|FwC{_idLAj; z#CVo1TKc6dE!~6!ll$-p$NGCH!FR4z;3=DQC64oi<Jiw}Al)SI=z`<C@9@YEP^<6Y z_dY=**cl|M=+8|q(c<r=h;$K3(vHYb?1EX3rN3a&V@_YZ9<#Og)MD;upX;N=65s!z zzZM(z==X!P*!hS*B#K!2=8Ua3i<tG*{rnaY8~)$5zZ*_5cYETu{~1ZKms0=n;MXY> zGkw@J@V9qR?4wcd|Lxy*A(p;!+@o<{j6;korkfk9eu3C8H+`h8{^!JW$^GlTn{PSL znwc)uY+82v>fbz>oi4pIC-&|>MgO=rUE1*7?mYvy?VFbV(%OXd`7`FOoteJl)&4bG zUS0lbZu+?R#P(aC-nAz$eQnJ8!0NGgSKOceP283{4@5t`;lcEy(;hK>+;qC>m+8;m zRN+W3UEZ-U{l)*RNPhjFAN^%f`lqjb5}Z6_^|pQKFDE?zQJ**7{$awzV^8_rP4{g5 z{p%Aq_WgEE@`gU|_MG%+?yY01&#gFCIw_@T{MW%}XIA}p(r>>w|Cftu`NkO;Pu;fo z{{9`ew7i$G^6TBFlWtpEaZ6@PY|UZm)>r;oli7D;;7#k-A8o&oIroKHfAkAgrx!T( zpE;*~Ipx=X_{8zczx^TlNb4`^#%4ACuKR0mzSRHgm$Uj>Tou1@t!&Dkdi?LdA8Q|7 z_ttkg-xN&vsKCx%d?x?3whf8iS+72I*L;@GT89=W=MO&;ICJZVf7?;;xqI33e@v{3 znEBB5p{};MpDz1lkI`@Ld|cb-B+K{D*&)kU?9kR9i+H&iTfXr5p(z6aO?U`Mz4KT7 z(Dp4#4OUc?HVkPEk+<PDq9HOx3sMmn3mYR_frKpWNREgBbJUlZqiD9;`Z{XlwOG+; z6PkG3fXA@0y#W9||L@@Kp$4#^FVN*YIP|HnV5{Oz+&Vp6tA}nqEY-u+dMNAR3O!t+ zhedk0Ko1|%!~69xPY-A5p;Hg<)5B~%%+$klJshuxWAyM2JxtNV5qdaG4{dswsE32} zu%8|#=%G~)EqZ9yLz5m#df1`gu?y&7yB@ab;YmH@dU#w9kLlqNJ#5v({d(A}hr9J~ zhaPU%L$4mbuZMMd_>Lad>ft6md|eM;(ZiSY@C7}5P7l}XVT~R>rHAYEaIGG?^{`YA zSL>myhb#1Oi5?c|;Q~E;NDp7o`S_e3uGd4a9=@-Kb$Ym658u(lT0PvPhp+45D<Z_y ztzcqx^55eZYcaA)YAC_U|Ac@)B{El1CiY_}M9vz@$roukMIHBI<opDifwdM{?!%Fz zxI0H1IYo(h3^o_pMCw-n5vc|@)+fzHV?^q1EfrVqg3a?VrXF2bylml;wA)85Sh55| zRmxc?XD(Tixu_UdRF@Y&Hiy#a59v7z=NCU*<eV=TO<lfVp_b+>Uj8ty%w{^A&gDxM zJ^Yw}b)%*$|DHjb1&MUk^~yWM-373LevwORCC0J(;e{*YMa!3otgHMq>-eayEAd4+ zCjN4Hv0QVNVj{^hRimYA*&_?wQZxQ7j_EFWdg0WCOVN7F``7w&0tb%4q^>wZccSAQ zla~RDqqul^@wLj=T!n^E`52VfN;B`Z$~Wuf3D1@7k9A}&S~=;l{DsBKugL@JG>r#W zD<9{WIe*zB3$IJR^E%}%ME~@a3yTYvEMIjU9<JAMT#bjZj;RndLBciLuwO4vcz(`< z$;(#GU$SVy^cB}EpD<nH!PUygIf#AW<02vISM7#b*C`+42r=N=eYpNQ<zpSW^s)@% z;5F&rub00X|KiaHqW#Y0i<Zd?uPKN9oIf86AvvUe6gV>Gm(YFnYyI7S9UR>p8OxVJ z6#h4Pe(5?mtd5Bfla`siX!(-)q!g}03%?GYSckJ19lB)UBMYy|(_u5N&5!Pm9C`l3 zkA^z-nmCqR2S*I?LoQyvB;(q0vFSSHyE$ghFJ3hNf7K6dz+pv)T}?K6IvlGZ63gZ< z39DK1r)9g|GSpFD@(<zAz^8pqM>OG`VXOng`SCrGKMMIU%rJ+EJz5`Mip@GK`Ww=k z*gnob#X|$K(N}~+yU&%6wJ9oU1i%{F(D{trg@d8qRT1Oo7e|f%^{R*wiR+>!W!;OD z1~r5`RCaJ@*^JA}PDI)KRS~8u%WB7;@K>f&VQh=j`I}NdcJImvW$)OgGq1_!_;<5{ z@$b$F(vcYXVCK+y>2(SWuX-Rzex7FcMe+<*6RXw)-9dT|((@0AV=l_A@$dTL-#w7j zJdbd8w*3LvzG!;`?~i>39APwKd-+}XNaQe_!2AcMFEzLe{HPGTpBk>g|0V>#v=d%j zh-%<LWI2KTJwQ9LPyT~=_VG99nJ(I6Ugdk>;0}KrR0O(m*$FtQH}a1F$=cqd`Byb$ z*w2(kyGw@z6IZs|&y>aDMqTPr*x-Gqxl8XtVj!38N!~RPuKkU?2B<sFXF~n766nIn ze1vQ;A)B)WdkbsCRg658qsDgfW)hLmsv6Mo<>3Nsm)NUCn{L$$K$dV}X|Y5X8XB;* ztzCHDwzYK@gtj=E7W1@BKt(~?@g2GVcFSzf_I9wHF7zD}0xE8p^;h5nL@46uZf{ys zojVBj#KSnk?U(HqU2bP!2Wvn72a1V85zL2cXe94A`N4rPalZ3lDQ5$@sW^GWS>$ME zUkAPr$5`Mz5Q=ev>oNMi@?s<TuMcelomky7Q{^kQDDC;$$V`8Ej-qI{=tG`*CUnk4 zKJP_tl%TC(L=p3%T|2-%Cyxb~;OPwQC}**D-i0G8{zr5>HXoyLOhCNB{fm5^|38OS zuMR7=!Ff3{$u2EFO(E$FAD<#>e+4PDiFghU$#8sVq}~puz(<2N1A|FBlmo)Y`7^jk z?1WE#4>=jW$?&@uPU5;peh?n{LHH{FbmkS$_eReTM);Bw5c%Vy8N#7|SBe*|5s^6J zHcU*~rJTc2{RQQqhU=j4?%$|1&wJoOP4DPq<L^h&=w{(a4uby;f<%AJnT;C)4T4hg zCONkkUL`GOUaQIqR*^~o66U=IjBEqcWp@Nn#C?G@!3EL;ClZsI<yK%Ix>1R;E7co= z%NM8L1knezdj8LF=xv$f?84J?dmmia4A!FmC6`eNWTT$TvVWR>S$;ZPpfPrc7N2q; z#VeXDcK+m1${yut_&Mp+${UoU)ei)f&o+U@J(L}Dl!I_0Q0iUZRo@d-BT~Ir@D`eU z!jVq-#DP0F{P4#(f$Hb+;<hx+4bbM=TUn5GjD}bnUWLK;pc`<GyN`c^Bz=5%wzuMi z9&MhBL&_uH8-muc?a-3j0f3tUc)-9<#Hh7JVbms8|K=qO+O#I&OX}G^EHuXGf+%i2 z^1a&DGRB>d)5SR4*3S#;pm`vOdyG@9xOtO`n~nj+(T*9SJG_HpH@O2t<?b8ddZPrA zaR>4v=n|x#7U{hDflEq3+d9V&?!ZV_B+?IU;%-pt4vcffDg^<g?AW9pRSNifXdq-{ zlq(i#?`-1vfKm#ME3RYkJR>jHd{)4dc9le=9(I@gFwzy9w6nxyz+HwjuROUc6sH>x zolh7TW$oBZp9x1pJ{0Kl=Q7tZ|0KkKBrsgQ$sI^39`6o}U3J%^hhyD5CH`Hn!H4>d zo7CfZ{$v2+xYq74uj(0e1XzK^UFw6=<RG66Dgbt5lh1Z^UA^#FWd#9yfq9ja09}^q zJHB91@$X{i-u9Q#`EIEc|4Z?I6#pyd;bl$u&%^&1{8M_@|3OGA#{UVV!@UWIt5c69 z?d2Az2KV_)xrh6FE<8BS=efSxLN<%qH^%!|_j9cr8eOU#IdR&$D4#e=sdnw4OCvZ< zabFmR%NE<Br>*M~<8_^=p1LFH6w5u1i}l3@U((K%v4*|1DJVC^b;0L8pW{-*9ymqg zD`_Ji$Lxlc@ya&hV-ty_t6d$E+N1%@1%T49DgNCZYEMxjTO`Dsl|P5en0@N;RdAJ@ zdRzk@A@U$jDPE*~Ei}_~<$Thq2a)fLue2b)(Q(|2rijM*??S?6gBr0}QX1Zt+~@C+ z?|$3hKJSpnydB{_pC$Kv+vq+&O^$P)pBi7e2P}HqR0n%YLi5IMTRBu5bRy3+F#g@% z&*69nH-8<+w;BQA3G`eUSr?BOoQ$g-b;{}ZcR%56aS*%uYFC{PIv<C~ILv`A(Dwec znF526e1e^G;2h~B*NUwmaSh*#DXzg}#4Lq^<Qa)FGuTw~@1EStBT)$@)gY~6y9w@B zPS5rZn$XW<&ZKkt<v4%RG486ayoB?ntp;>1f1D=H){2Yt;EJvLdk|@Ba8zCW2ZF)b z!!F_Dq0?&8X~l#KnxIThu>x}u9dlP#QwnXLd<mx+xGdsY-Q?;&P$FtCH~^a^MyP=( zM74%P&@p$<nIYa86j&Ug`Gd^iFKGxOt4ubP=6KYt`4x~~1bHg7D-Ik%=N3(QAhb=& zpF$a^4PoefP={{#kmCp9<b>})wdX@>)_xdiY-(F|PUaL0I`N(*mfH?)-v-BsFz6=) zO1>Qebc_IvrB(p6k(&UT;b}C{)v$}*TrX-B_WKkS-hrR$jL0oCO8#{2ypr1y#(9)* z=4v=uZii=EDiQDwgh?adO<3n);BN_dSQp^o1pK59+{h~c945i+dMdm{I|J;1KZKA- zo(w3T|4TZgB-35@^&m3^UO&Xf+@hBr3bSu2T#Q&Nk&xE3H31DkpY_&itg8VdxkaaN zOC1Vr#T`O|I71`V(GH)X`7pBnwqEDB1~W*5`6LW8fnfdsn17GhN`nFjE+O-8&r;H; zt+eZeB$bl>cp0YtT25sc)0rOuLu2jVw{5*a%Y285{V7yzI}tfV%b7;Sa@*@(KqhzW z*BHHJKS3mF5F>Pmmk8o!K>T~$*1=j<0ik^*g!UvA8m8sYyMzes>s07_n54wKEdhc^ z(jY$7AvO`j?hu6F-%t(WZGsT|yAdsdMHpZ0=-6tS@0NsZtahVED?RSLtoY4ZaXDQ4 zE6qqm@xazW1iu0Bsu_>McO&TPC>nv}pes;U3u=UR;y0j6DQAqH^G-O&h@7xg{T)q0 z+q5#D!oR`iXRsB*Ql;7Vv|35QKTrmv5H7uK!EKLW`;ne$pK&Sv5*Lg}d<=hh6zQ}k zn7_0$zCw=^F0!SmEWs4vf#Q*fCr+H|oT}%MjvcpjsmP-`5g%7lg2D59NWDi`W0D-t zEAhnK$S0Q?@`9m*ZgJW#)&O(hQ<p~)aDugInry9YEr6Z+`e6V^->$W}k@VL6+y)_L z&6C*nEq5b<{|Lsv$A9UDy1@@?*h=er{^1UB|M*6@$ME+cPr}|=Df$REqe_jzQF7#m zCsAN=I&@y9v*<+(dA+(EoaQVxRj;>g0vqr~s**-gJv}KP3_-(M+d2d$QkO`2N=vFi z5QWv@5HJd<>$TM95JW03*j~^cUm_soecLPA<LmTT{gl883oaAQq?YsL=Rt!`+Fv_K zs{<!=ZwUDYQ0NA%=HYNB*2esuWB93qKe^h!$eM^5ftm)C>i`DtKCYm6#rD_HqhgVY zRQ!#?KfIz$WDoN*pxwFUFQ^eaAGD*)KSH*D)@}$L@;5l4VR;rk(YiczC9(<J)*K?M z@fwuR_<Zy?u99}SBB{N~hUP}0`$7e4!UahizV&cO8)DQsag_j5E9QnjlDj2T`8_6X z2IBCr*aC0>@|QoM5%JhAG`sC8wazWrhGnss-!H2>;j+4KT@bE2w*!?9KNYU@_rM>n zbQIvI(ov#P)3qz5`BK;Pq1OHlf~2vDT3g#$BU)RX8$hk^v;hLfrD(c%*M;8j_^vc; z7BmF3S>_{X0-yhJyyr+&uhx3ed~rYZK~#_NM*T?dm`OW~y$#RBs5J@v8+534Io)ph zybeok*SD0>msvi4A5RbkCpOi^yWX%Tk;MNKhF45BtUgTAti{rnb(+)&&>+oRt^BD@ zK)igd98aNRQs$!<*yO-8YQ{D0DV`I(ieuD4LcY`i)uxY*p<dicdCP#?r;~t8jpX-0 zHgo(<O|)o18<-TjaW!|sZ?WvhjjJ5(##OF%<7#}ioUP`DZ(OCxcd7S;Zd{GlZd?r$ zH?I1qw`n)7hSH6z8`K+XjlNowuQt+G8|ABw_SKqwwK2ZhIA5*BSKG~3+uc{&8~1n~ z2R+(tD~(+67Jcs7euO6X7A5yMId$e14SXadS(sa?4O*FI&$gdDC(OlW`3AH;resNH zqZv5Pr;<W!Q-AGwJVA0rfAA`pt44nC8UprsKfD=JaqtGm$;fI{)4)r=C%HKeqpZQv z9;cKA8XO&w)ei1l9I@q3TDQ=4GB47Q4#kxY$B_odF^KXJD26SYG#J_<<(UFTdB75u z`J2#!YR7Rt4*lozTQP1_Y-;KzO^tYuh*%!+pRl0xZFy2dMrTU=NlcJ0lhSC6q}L)8 zErfSrq=eWA;H)E6{jwELjgfSt(pE^h7R1INMtxkdeF+$bO`7$RB+cS;vFnAYBL?cq z`ttf(yqj=4W%z1h@w)*3921iDRz$)+6nFQUJS}V5#A(zsCkN4b-_cRm3jpr(5-wpn zEO7WMi>!l6q{Tvcq*z!e4vVuc9(dek)`()b^O~L1{#ls*SXoE>X2<c7<XeKGCD!V9 z(s!dR!qM`~E9%YFuK&irTVQoxG|2cdt%`~N&~e=Eu#`u<Ed>+)vIM(TtPzW7>>6lG zkKZHZNBkEp(*E}#+!X6|8L?dRxy!zlWMl2fjXn;A6pa6H>hZJ|`&7%CA)fO;l@5q& zS~I9NWuqH!R7`(~Oty{Z4%Vie*{BW@tGh|SBlq9<Re-|YRmTKK;T!Z6y-^JiWL%3J z1y80XHQC3XMh(0IKUG5sSK%9Ms%0`?fdrs<CmGt<bKX=Ok=9h}s4Dnx{D-;6r)-R+ zH)6G@v2iVBQMDt_9a5uWkITlY?HiwQvLkTx8(j<L2xq^H$#GuScc9pRZ<TSQ{fH}& z=Myi3!o4xig`UNcTWL*4Ed)#?TBQz4!#0350@r)$v)?wJJyUfggMS5GuyL~7?Os>= zOJufgeA}p=KqCfd&Hp+E1*gcCiLUc}Gl5QVo%6x<>;|%oMIQ-{##P-wX7HAH6Ks}) zD<i57MtolV!t-}6Mn{s3Q)L{VE)SlOGu|dgj~_0_Zd5J28`7bLrhy&v=4O0#1YWqK z$uP$yqDU-)&%E-0&o(?gJ$<+hKej|fhbJOB%r-nJeI(`BM$*slkw_bELmB}NA4xwp zq>Uu#kyH+mk%WMLP-OT>WDLV|(lF#C2|-TR1Q}-t2Zh_5`y$LN79DqwNglwao9g{T z)SmI1?=i=Tr0Dp~)6Mn%c>WZcAm7Km2;fG&Rg>^`EIN}NoHYy4r)9DiFJsxo3o#}N znZpZraW`HDFd?`G+Y%QgS7PCWo>KV$H@00|37FyHv1{w-5Jmoo(XQU;F7rvQKAJn< z0IKnj-PHy!`N@d$AMm4#J{F%Y^Vc_Q8h@*78-J6W2&uG=x4VA$>bt5a#7&6D0YW@P zjJNx$j%^yZU2ewEIH&$MM{%{iM}sh}DXpc^!O<(hb-96cx$T?A-z?uUK1Cinev~|7 z{0KP>_(ubO>Uf7dZu~;|&hd6R3rG&A>66qJ`#!vb=FlXzQ*HE=@t~_-$>r+%4UT|8 zeOIgSU!uZ<P2)#`q-56yXjsE0;J>IotK^;(g^Vb~96Y(c9L~*(;~2$#Wg>oj9>y>> zsG^aEancLgz-xE#HBc%XBgmVa%b|*u+*amlgKnuV0QfdI*4kZWXn>I$sWrEvwwuwK zGic2ZXw6`>W&m1aLu(SznjCOz`bKp>p9<!xA8TYcAaUGAwY};VcSo`u?d}-qI&%AQ zv9CEX%l(TK`8*Bg$SoKFQchKYPbY>CM<32p*9jfv^OUtp^1xCHPXJVKYOCw4+AZj4 zWsW0u$MN!>>clEz2G|pKuShvoo?4sYDLW#$;=;N{9lX(97J%b0AUpv>dHh?(v!~r1 z23M3ee1lVuh@FL#10d3{(oaJ#;~gB4u!}L+VmhV83}MW|d!mO@r^{A|BX&y?3M<N^ zAfCqbw3dbpqvYR)0*6P9B!9m}UMu)fAF!rlS3<~kvLkTtOP+Zk7(Cc<c%&DKsrBIV zpO<w!UwF>ZAx)HH4he0A-Myo(Z>t|SZl&s<ugdKGP1P|kH@T0;7e=O}6uvRVrQYt{ z$jSo7GV^2fI=(0DWfn{mWfo7cXUVPZQoC_<@z91$yHT3Hy4xj$lr(nLcj}PB#tdVs zgc{U@4@uqWKse#C8&l*{u>A_zY;$4#iTFarxGo2GcBAOExI5x@#;<(`@Nq4VMV~u# zuGMo0g3rp#aY2Y#&=WM34*8IJa^gr#gnzF%^!B^Qx|N)s3|)q&7J7nhpyak6UD}3s z8WLpkHaYsx9hIBF1+BHu$2GYIZlNYuWp>kA>>6CP-4^c}GTC)f9a~jzO4)dMJ`xB3 z!DQD7)>wUCFJp3j171txzB@%e2g2)53{ml-zqFQh8AiQ9LVrb3XSb31dj4S9h35}{ zb#UZP5OVN)PD_=lU$}$G@NEr_bQ!YP9*&-dXLVK7xJa6oT;?pk6e;Hp+4sm(s-kR1 z$2(lHSu?qe#5`j&cOb-!2&d?6n1x+N?7H*mSWgqah=a#SSDKFAtwtQa`}w2C3jYx! zxuWpCZqw(m)`*g&7oOJ?l#k{~)A&UB+%&9N(^@u-7-xzti9ghhrZkulha4S~)Dv1> zRd@G!BKbU#ToolCyJtPx5^HR(xX=z^E<Qnd5$6t(wClS+&#VYphP)ArTK?yg_&JDc zdfbG)r?C0;CxH3<fBFErRrC9!d-GLJLv^N=?sNm0zG>;>*xwJb^ca2wp~u?|2MuT8 zlJBiDrW<_I@J1W#pW%4n8LSX#M^BW+O@y(ydYo-wndUeI)i?uYrRL~VZ&i1C!A`HL z`(uN*59)r_chnV$_oS%ZtGcJ-ohpX0f%4BiJG3)eaQv!&3x0KN-vJAJ2Z|TYUn)FW zVC!A$?{ysq;kweNrJExw12|;OGlzMvh2!LPaKt&XrmtAI?7F@^BZ{?lT#W{lhXY0N zb;~c&%M+d}+YsxRxp4l1>-+U=x=#5x#~ggh;rhNwC-w4VaR0pi`xcdG&L}n4;@^mp zYxkp-`VrsC2xGZUUzP$7cDaA%^Y;2Gx0JcsExnKb$XSG`voD)brt9B!Jd*;un%~^} zzs9#X@Zb6vj$dXu7Z#TQ6~2rS-Swdk2v+wXq|xGY8Vj*u)rIC4WXkINtHHAwk5ueR z-cfz8l)9xIkArr=ZO8xp<yhI^e|Lpj>cIb6k6X%K3mCwj#J?4=y8*W!|C`F((nElK zX^mStf@h~2`0(#UIr#~|;XeiC&9gKfmw?Xb@WU{a(74mt5a#u-c?<hh>5_ky9xm6z zNA&PPE$kkrBb|)TYfuBBrLcN(({ERPyzkPIL^^(I@jMJ6)!vmK&1=DfF8m1m#w{g2 z>6UExCw^qEb4yR*pZKv}aZ7_LJNfYf;`{MG0%eFFOHk$&{9lV7O8~nT|22Sr1-L>@ zA<02scM9Yf5UX`)CyToDb*N3DFmdIzWosDnQt&?p|It(hbeF#uj?RhKae8Rf!VtbI zLpRD2s}m4*<sE%DCX>0PS@>Uo|8BFi52$FhbdH59@ipuC<SXzcK6N?1xLKs5G;CMm z2t5zN7_?r4w)=pO+P)THuUQ$c5_$Pj%^~#qIA!2W08T5yuI+stcnIgFY7OTIgxzL! z#i*T8lYbTIE`B#nje9oJ)=!<K4eN+6FvHOvq&Qo{yG&6DcE6&r7qa>t%z>BrS+&yF zCQ2+WyakwE&}E`G0*|i^;)X75Vu<}PY}K@2dxo}fMI;9i;d?~>5|w95>DvOOQKEd$ z;Js$?>f^Hh$qj5r{g)BISDjExznQfrzWz;dcwfVFh{P`QGthJgnzES6An-jN#)pCo z#qTvS%NE5_t0dGBRl=79UoFY#Lbp%%nfW<Qgu_%T=5%^#)_HSz^j7LjwFj(x#LX0s z6z`xm?iKG>@a169Z<t6|tIRCVWKUqO(|CZn)D&d(y5E&};fvn<a=rP~_O3+HmsKuf z#jIN5aJ8wHEB{1SgqTf@LVtmF;w4@b4)#QckfM8JE8ZFYRRq2Edf_JQpqGSvjzk#{ z@$(|(G2&&TuK|<xGU~o82VL<59I|$>dfeGaYkG#SK!0dAqwy{c>~=hZ_t*9C;l#`c zo}hnVk5z0x32MkHYf`3m5Q(&L_ctgr?ea6Ms2i&PK$i${9I)VD81mwQ_JOl-GOV2v z)d8Hpfdv-b)~+Ok4V7*9jnhjS`EV*(NobVHc9Bo-gE3VLV0ff$ks#S2kHi1LDFi<P zSq|HQ|3C#)<=b_TE5Cv)wGB+Ab44&9NX=QcXo>U;AC4zqjgV{MXGqQ;kb5gEZhQd( z5B-8U_jSs?upbG=9Go$tD@<Y-hK%;@?K*?nm0UQ7;PtGzMVm2~X)Hpc`6W<5sekU0 z8qjNo^;tSHEA4Rg)OL8hVT*fAaE=8hZ%*wARVTnj%+Zlg87UdlT%U#8y#eS5{Tz%* z+<$qS+8xgP0GT)&<1a!t`24cS)R_Xk47zc*{t&3e5k5^={541eUQFvCgwu3-6ETB_ zTS4@WA)-2nA9sW+N(B%V+DlU7j}sLMF#dOJn1=4=vsTaJCVW!?`__V=!-5%b`Jr<U zh`s}Fa_nF$20@%gyiM<M!fBNts)t6@t(5ec01NOk)Ppzio-yES3RF;IBwm#FS08;* zK)g2qyZAXc<i`3I9Ca2+uogt*zO`;Cmp=(Hn9Fu-<r?Ma^<Lur+CWV55{(er8<ty% z6wEf!o1<OPP=09jFp?e7=VGaXLD8m6J=xjqe}dVfF|5IHj<}+AGWG>DD)GtzJ3B*N zo+7%uP2;E5<!#RDsVB8w7YVs1^Y{XYw9AZM-v@-9AM1Dt^;Bb{DgvbPBmbcueg+e) zs#ZD9>7A_axeLF9!*D}V3fj92;i<4CG(t)4Nc2UO6d{QN<Ep2&;fN)afd?IEkd~^; zB_*Z=XD2dX5zu%T#HQk)hKgc1C5Gi>7OD)p01Oi}e^E;`>jc-}_%nPCrYV}gcTy?v zq0)XNY7yWH|M(y@3iOfw{gO8Y`VRgkhQH6hmN3J&1i0~X2%Q&PAE*4XK6@G_=4C=| zB^Qpv*mk0RO3G?<w1dl1^;Av{5$IB_w>Ymu8$8|!V{6dSKFxKM`gj+#XE!9nABqjs zF{F25!29sJU^vNF5@-M~TIx>Sev*B{SNt9N>S%+pTSkL1HbWrZ5pLqMpcH2pTCabL zf#&nS0L>ZZU`RHvqK~@4cD}rktQ8)#r8j4!oz)~D+%R-xfH&_G2MW<y_qvXG_H?S+ z1mGd9k}YZ<Otp8Oc!cx{JmxT2kZ%tHyilDub{`#CQk-N$^a{O!kLDP9#|L&wch+r( z9fk9q7;-|=wCHo4REPS1R+t-qMJ5TutN$QI{2rP@ZKKX68KUv8O<Dn=<Vg8W!qOqk z0{-Ylnm}@khIXd<cq}$~K(&v51G6Bx4L%BN4|>#&#)2v2?nJtRqM8!4g^3vfG(^m9 zp!NBq1To>v$;c#shhA7;`22p%{bGKiSNeC-iZL4KGC<!C(`9#c$fK$;q<%I^;gYQn z*zt2hV~+nCGiSJFpI-Bypd5Vu<y~tQ_E#?R3%^$#O~PduKPK#aIPi%>aWQX#UU61T zy-VyXgl5&5>f-~ufqe~Po=_9;x)zk4MM;P?XmhBKKWKqH>XpAlUOS>;N|yo=&EY>_ z;QIU@!Oqcmr1dAsNKr5dTwyW!3SFd&$%mapgv8{bFyaQG`#X3!MwZXNL?9091g$N) zS#u-SU!k^8BQo(38BnBvcht2_6z&j>;Zre3gliavas+sXAU(DV=|a9Qt3wXgff8^C z7(qxwM0bkQ<2uSOF~EHO&2MyaBQ(Z;F5lzUhRFvp488&MM*15>Dt&E=WR|9I+@eTV z$1)!dxvP5N{5#ftA{HBTCycHi*skOqIB$Q3PexNZ#e9U@-pysmaNA?WujJYmZo3WW zi8=dGozLH05E{;$h)k0Efua?sHilXOxew2ySJ7451j+Pn9jH{klO#wZ-Ky!VAwSbu zq*VjF7Ld?a$0_~-;$b?P1Rd?1bcD~pC`1R@huS)c-Wk(R$r?mqqLO7}Sr(k8TCw5G zcGMk*b@U8>SQwmmwG0e_2ENo3URB)$xe}`?^81)UqsdJN(^v^v-~)g!lF;|u#PqrX za^JTqqxT3y@t{jP<Onskt~=~nKH@Ym?7^oDFeX-GMi2Si3&W#Fp=b2~xbZ^rn%Trb zm;im@^qa!zw&09J_zb|tvPkj>RELgU0?VJ>YuQTl^H-q4(7FsF-^bsCNvr`CU9pz4 zlt%J*PJx~<ifU7vhQbdN!F%z&I7{cU#)vwq6WZuEv(3!kdMQ-0NUUk}{Z~w*Sl?Mf z>pQB$*`*F)dh_m5m?lgQ+S)S@$oIiBs@k*z-<<5H44^kznXo9smywigvLC^7e9JQY zokA|IdZeAjiNkdJrP4d92i>(-B`eX?N}r0ju$yMJvdHQZgPOoDPKR4tH!5Lpm-RNt z5$ufpQrT{D`B74;kR1B-AjTZ((e{$j7A$$G3Ds?AY$JVQC*d^TjZsfz<E_{FTCNjt z0Rf^fGTTf9;bqy@|7{)G4PpR1o#ND8=;FZ`Wh7L6bfLmr3Zc5}vPM_FlOW2mb=^qF z8h=33HQMnNmA!b<mOMNPd>52=-7nYW$70X0(&hl4jIRHA$Ioh`^*#iIZ+THP5mE61 zCLEm8r*`mi5WXBLA&BpB33)1_im1;tUUsGL)=v7s+f<^js|W(qP+;nU=JNdmy-&`6 zAA%w2S4!J(#emu(Di(9C&^MTCVGIYbLSO-!#TF}J)mhMiF9gBDfl@Z+2KJs{)6u_s z`AJe5h75L(5T)F9{;!=RN~PbahG`-Z#&SFVvq)U?9WF+7!-%GfPj_Jrlrat0qqbun zFSj5Sl{WGf;0itgVlN1kb~?%a3S^LRr3#Ct{#9LH>Us*Ah4ulA)%dt%!3(r>w}P9H zP3UlZpB4jNYbxmhp@MFNHZYVA4Ds<^%VaV5f5e2Ya|Qbjh46<!G9<|?_E2zm7LKEz zTJ?Nk<(pYsAx^Ie3z>9gFpoZ7DeQc6_?v8SnZCf<Fw4;A8+SnnQi6T#t#Y3&M#v!+ z@k?miY8{Ms-WM$ljdj!&DmOG-4j;Frf+npX?e+8NRPc*eLgzH1PsJ;E4{ED0Tp&pR zftUhPNoEm_rmz(~j@PdNQF%-wURZ|+UV>YISGTqCV}AxS9VbZ;(pX3kK>tX4L0fqw ztax~OpJ8PuLDn8Z*pCp3cn8l!JoyV$x-UH2i~|n3w}2PCy$H-cf8b?w<ab!oqpj4J z_<|*OLsIa9Fc*%(#q$eYp5r$+5y*d#q}higvmsZxRit81t;;3H%`$WR=EezR7P&@a zQZl0ezKi>~sWMnLPjR*5tUeCnL~cw5je~Sz#LHU2!54_8JL5MWK)ISGv_Hc{>+`ak zFE1CNm7`N4?x1oDP|jTzgj(tR%7a*Cp<(3XukSl%nJ_jY`6Xc1Hy<zl6~xizBi<2? z*T`j?H9gSE9=BlE&xY5oCSo%(`CR4M^1k*xa6LGM{V{wXX%8;|6Ak#na0Jx4*p@8x z_zlG|vZXNCBwJK^yPO(_*E*?DMyHv+y$lr`qN9O6DMJF=z>EJ9re%32Ef^~#&K#yF z>;=3_P)w2-7c=m-Zm<}40m*X3_XHU>H+?*v`W~N`&9K5rPs|I#e)e&i9EFbFhKRPS zhF<fGlgh0uwxT{bM55Q;9z$L%TVaAAjbnLM`$c&sK;X^Mz{h=n8M;ZG1X+TIN~8oQ zF4mI={s(Arw<LaZH!TH_?IH~yxahMbQtKZ&edD7)L;q~w0QmZ_KF<XkPoNnYuxCog zK>y!?k2YVzt7%7Io3*@${c$UH3h4tw7NYubGj<8_fkXBY*#7Nvlwx5GV7yl>0MH(B z4|K!*a9d+}=6gLCrP4`kpLpiwCs1=6*0PcIa<gk_<#$-r&bGqqckg!6l=zOL4p{F8 zU<3dDc~}#ki$T{1;d`MVl=iiSf_UUpwB{^?9sAn7(aJ0LwdY~aYh0@wADm_dvKg2! z`F^xP%rC&><KqCZ)*HXx8@v~<G^G2w2b5h(gL)^MmXJKnx+)egpT3=Jj%f*F4;JHP zv$K<S(HADOtcGb;+``+5i-H~DTZa$C9CkI(EnTh8TWQ)STgXJ(jkPHy2{=T)T*bW# zdiWh^0f`i;YOHNBSn;yM7NL_u^Sl1iEs#71xp*-czJb*Mn2(_3&@^FRHfzZ~eg{DC z;^t6UpvH%AeZs$GM3fwb|DI}MC&oyCtG)3IdzEf5knV@~$VQq18t|npRPz8;(+6>6 ze};6zj(3gdIJgf<xa^Xz?V)IE8L<gGt|p`^wUyo|ROKn_kX)TxkP`ty3!{Nh8b1H2 z7g0Cu%j#?N99+-w_&V^-UL*e<k!KYCtT2+lNAv*d)%NoA`#f|vu>5X%g(h_PVEy(E z?f-RXud*C~0u?Ids=d4B!eJ};6Zm?#^6;Aa&|Q-mM6*_yIKw{&1fHF=lu^(STAFv+ zM}W_2Xk+)|--Vh@u%Dt*eA>zrh>L&nIUow!DsKV6X8h;je?I<~<G&354F7-9|0$pT zU&H^u@UK3Y%TEB+Ty=J?<}hj^BGl|$;eW}`io9{T!as#`@iZd0j+{IBA@MYr+@wL! z>u8ADBUj8(b5(lNDt7=NJUQ)0ZL}m?2R-5QKk%1Omr#3YjC_VM(ugrK-I6?=#z;UL zBhxL~7)jbS2iA`99;;!xm9FPrHbx%oIz})CX^2=cMEH<^J_y7ZSO}_V3=~kP+qjVP z#eajoG1)4{+c2L=Yx=*1Qx!fI(N1ZeN7CH)Ef|wLQOnT9nl3d$`3f1n6LDRJ*FlBr zZ?sFKRLC%N*oV*k8|o{X6c{$ZdSfw(qS5?=Z!lcv{xKND67qXIPeWAGqZ?{afd2x| z8`e|o4#b4MPisl@@^3F7oirjJL=brt>xme?_4NWlf3`6ggi@1nNX}cHh0`x#LjoPZ z@_I@jq#=k}N+1G534f&of&Lq87QQ?S=tEg+DU0e8?V@=IM$64$&evGpRZ09I@Cd7e z9;{)@k>5iA_wkwNbsF9ch!22fLL4w)4Sk_Wx*z}AIaF0<8g7Y?f0q<DJ`v#K9|IVx zKC=)<loCRUux9-I@B_U~Ho}a-N0>C59N)ebSI=Mt_qCr9--YcVY~jD6B4aCTVSlZG zSSxfXeJhvr^^53Be5v;$MB(>{;-kR<*I;&FN@YuFuSxLKu|$ot7-e!Qi%p;6YJ+1E z<|V?S?HOOT%kusD&>*F8-oWXbE*J{pE&+Uj#8V)jM}GjZ>D)p75v4FTwC&X=U!(yt z0k#KT^(nTIF+{XIvl%2;*!AR_(I6J^1S3ids-pNQj58>&nN?W^{*4yTdXLVY(!Tru zX!{oUsEcd=O|pa#77{REz=*4ciVzWjT1r3zn+=KPvF5?cXCNCA4N02p@=zX$3oXgd zRBH8J+iI_^w%6X;*47uqS_8qvS1Z2p(TYm16BaEhl?X`w-|v~<@3)(fVEg&}@4_#? z-@MM8IWu$S%*>fHna4L=+L}EHYu4I-qBrza?8fsw@SiCDkBNWqlkiBck%}!R5bF5G z=Z((X@C~89m<?&j;dY&ROcO7@9WHec_JAOlV?h75WdLC=A{qM#`WrN-FgJLPL?4%V zeAAd#=OlH71~RP86B9-kBNdnH^*xU7SU8o^VVkB)C853`P;S5#HeKrZpTeQqu8+wK zZ<sAeJEGBX8pp#<T%hCh;E*ZH@CR@rT;bfAi-XwC%rNHF-I4o|Bj-RlS184CoCNIB zB%_wP)MT_ZpE?HuRZAyW{+VF;2-uiJ>kDED;~{db5%_#VmEjYx5FTkyxSMy@$AB|| z2=_`s&SOD@CTEc*({cB0*kjT<QSbz<|86{E(*am%xsbfpIK0I8izaWU>PDSM@*?)g z>bn9Tk{hs67h!G|PKvT&ai^IC^d(&GfQcP1z-?O`gMCrhy69B3W-Q%@taw!e^Iv2} zW8YziXZJ#n#yTxX(UyX%J=Hbn%pAj+ANp2kJ`V)M28wT-s#-u*bm>LH0aAe|wrxM< z%j~hoH+<8GZ_Q5ab3UChu`vlnyB}0+f`^;*iU;3#8!Oz>Hs3%UaDh1Zq^5|h#YkuF zQuhkXr^r<@zuGWi?lsf<f==U^@EGHDz@$y}IF<R;#*a+NGHRU^1m#5R(A`!K21Sbq zjpk5t@PRF~WQeR?YS;;uCF#!2a28zCBxvKTwi347AaVffn+)m07qJa8k}U#DiEpas z5YDt6IJFZCYo*pE(&xyQ5=*sA+%5-$4cnVYuw^lo3;5e{j`%`;VE;5cYRfCS21Gt> zO`iL9@MDwql$8%l^Xo=#SXoCq`3VaG+a+jj<JwXt!RvRZe(>r?F^T};|AkLEBB78Y zA%(x80%Sl*Wsx#0LN!Y><^2~)_hR<Q_dR^~O@7U^AGg<hzbJ2e&0gfT6F;&jtL3(0 zAV4wUw;&+w%K@J#mKgVAO^;<iA~(GFu731D`$P4wk#tLu4)fW7^TA~D=&Lar2!B_b z0p1J<nxlj{N2J|_y8suBqEilKNEcJT1iVnD1M2#5O>@o*e2CyURRA*JJQT8PMEM!) zf-mo)Vw}I(V+r~`b|$*i*@&OnxoMe)-TjteoG0vinvF5^XLxT|*jhTNuj$||Q2xeM zn`6Rf8n0fFc`z_+kr57`TNIvDglonoc*3~q=|POdt@)Gsn%}2Tl5~G!V~od>*}3sg z*dOe)<}HzRCCG_Kbo(8Ck45E2VkGCD2LOP5YffLr<iOb(i-Vico!*plPuv2;4)Z%b zw<AtbcmpTxM!X!#K#Vdr8mtQCfmWej4uS84tGP^+fPgMXx=4OU)butmOz(*hb;=nf zr)>#(f<A0eOb}h_O;WM!#J18o5Ti6Mx`=Y{D(U{%#+XHmz!BcV)GxC)>H7t!JG*O) zMv0g!<)Y4>^dH(yflC_F_hq$GW+c+_k>P&;5bkvTYQvn??CE`T_XUTwWTc0u&ASCc z2^j&$B12)Sn2JF|h#kSi>ji^&mTTb_olBbch^EQDDktiaM@)Tc4z{!~-0V^R`J{{l z!ur4)?R6n@nGZ|_XY)Bf(KqX{#rL8l*y<Ho1*PV-pwqmEv#=DDdF`RiRe!*Cd#3mB z#<SX7amHn>`AK~^hA`JP9MpX!9G``t4S&a~%mvt_1v|wC`K#(6st7#s1+Ef(gT%)B z4uFl@7yfC}#so)Tl(5kM{6f57K<U~;o9?z3hPZx$v#1L|b;!ldd#DK`yQrP&E%ZEH z;4{(YRU-aC)Zj8Js8EV~>{Jr{d8a4*=g4@<b!?yd2fSo2qZ8w2!cJ07eFVN1!cgtN z6y2HbLqyDc9DTl&<~=TiQ>HSKX|vtftrpz|Y|Q=hBk1wPs_h|??TD<K{?uyaZ*4qD zk9^yM;}B}!r%qzo7U~3cJ1RjGDwCh=?0IiH8qw!=$afGz#TPXVIdt~yV(33WLYcIQ ztf;90zHu$+K`xLAF7QvxE}G^{UxR5u`=bD%rl5EzgDuxiN3Rk)Odu?-9AA$W8W}l9 zL(3%XzmOn_d~G_CQwvz#YX}its7TCRs4IfT`5H3X(u#z<r{pHY$E;M7O3Tk<k;m2A zL|V~`8(|Q0J~WOn!y%7+bw>qr`3}f|b&wRe>*+4nZkt=$_)Y~Z<SH`x<@iQh)+{sJ zNbUU*O_@^z&WB^e!PdBpshIPR3(g5I@?dqE0mqs$9l>)T9cv36l*IlBSj#ZD;I?)( z=S$LnVD<yTERodK9g(qzqV;)*GESnP{#^XnM|j(qz^O%UYS>77&{KsnkpY%5i+M2^ zP#Mg+0)5aTjkjrf3gSE)Uoq}BpcAVu>hOagYfLU|ag1&)b;2Byd(CG}$EF8927zDr zfqD+?1rU%>?-zvjU_*1spWeL>$I!6v>-hW^*GqRm!~YW?p@Gkt^+kAcYxeBK)@x>u zoVu@Jyk{G1h&$6YL;3aalg{*$F9biq<*B@nJ&`dJvuBSCzG&VI44_~4(>CH-p2sbU zAH==f^K#GU{~a98i<5#eS+w6~@vfvhI?#Xhw5I*RpP{OMdM9qMbhkf>Z_u>^d%o<F z?H$_vu(*Q>UGcaZ9Ss)^aW7L<=~VCPSglqnrQJ8{RKvUCW2}n7WX@_gGf)_QW2)n* zt<&Gb@LgG6)95$D(0(14nBSbItcSig(}3!ZKtqtxc+xoY3g=o^!)PNRGjXl6A)Z%5 zWp(0wgWT<QVRC3GuEN@GBwom^xe2+>&h0VDA)nKc^h3%dMq&*8$K*P-TTFAk4C4bw z-%t8sCpU@WkG|g$AG4U@?tNEZhcvkFuB+u`aLVhPKco$xA0GX*B_8(xwCuIU`BTFg zq~|Y(xNxhm?l|EN9FPTT<0^@W7HDiqO&cBQ!4dSvoWZeBj%a7@PP*+LxWMu9(_Qj6 znS%YaqZ=A?TC?Z(sfk<I6O2yh-i*YC1m~9-@eLP-YtRB+2HLgUi3GNLHICxE8ag<G z{^}^0H~bcbGr(yRl7pAovA@(I7wOpFlGx8_zX^*9gWm^B22>aBRVhuEO9a8kW3V0R z#NC}T6r!9oes#EQUivS7fo68%NjI>+(&%oN1)-+^E7UP#TXtGP=yFH!qtIsPuf4yM zai+b{R+>i30oCBGFoVU34C-j_t`Aa;XR$mDA!pb72_s(?2VA>);Mk>7NA5LtcW&=? z#GLP4)t%*R`SqXwfqOhozT19xcb02S>CEKrtmMP*zk*er79VzBT70SI+@9;t`#{T^ zQeql$eP&ALGmUY5p48CaFW-?xe4a5><|k{;Xe&tz?arF^I_7kLQLAqSYgiKH^=Gvl zUTs%i13z@1e<ESrSJVC(K9BD1odl%jM8|j)KB4Zc&?i};lUa>#Ni+aXK^$9_&}-R; zjhvLw{>$4Ir^W5<ifvlB^IJ$d4JxwOC3c585~wDd7eeNR*B}lEw+`X>+A#-j24)}- zFm~;aQ=G%M<SaFEQsFWdr|dd-_Q>7pzr?rH2EYuSW=}N!h9QNzzPNM;SC8SIWk^Ij zsS~blY6ei)#%!l)4E3Cawr=11(MX+GC=&}&#%^9vYRoWB?)oUz_@w#oQiXp{82Obr zScM<MvFnr6ktbU+kq?f1<pp07nxT2&M)%pq%vlYGW;MJvtKmhXE3RYLC+CdpYQY_{ zyAkn2BP|_zZ0JzX4M(%gN`Sn99Z-C^xZ0MN%pN018v$SyNKZCC-}S%4jN`lhan{JA zSPn>-)qDQ2S-o*b;{xa`8`6{GzSZ3IqxH8g2Ot*(598Rbk0#;9`;o`6&Oi;ZzlCsy z9eF=)gAH~006FCp$kA|92=`~<w`xxdHwAEa*l?S>?gO;}I&~oE^N$(o{DUB3O?txl zYUEco`l-z3-9Mgn`)RXDMK%vbWph|(lQuA$S<xj(Bj`7Ft$6;lpwn0akUnMt|6B$A z_;g;x8*>GAsncT?x(v-cVtmP=J#K02vJTL^rvfd_JPo%;&E(JwsTrMO2|wS20DTZ2 z&3oA5$Q4W;bL43@NaI-?6rZpw>}>tXLzob4o0QW!q3Oe<<_|e3vi%km1^1ynzP57; zeARHsjV6bQJF65X!Grat0r0wp1+Wc{gIOyB!3IAEAqPjF*$*~3M%0&=)!tNFx3+dz zefiQkm-6qWv*YW_^A=n>d;4gYhLej^Vg81BNO=wuCpYo0yg72wO%Z`_?&|SPUe9-m z`A#+8Y3AE)zSGS&OThRU=9{A_-LuU%dq3Ut%y*Xg&Nkn<<~!ef`^<N#`Ce+iuQA^@ znC}YnU1h#&%y+%{4w&zCcpDvb4EB5NS3{rG*^e-V=P;gLJdXe286kacg(qQpuHFc4 zhjTk6=KD(X?J?h(`aM{_^eY8CQoV!lr{dh#g*eNEXU1=ErUlOdJSo4$c^*8^;<*9t zVR8n?=wSN6eh&a9YiuA)$HO=uhUXzXJMbLFGv)Uzk3KKM@(c!#ekTYM&0-$j|0<qI zrKSFL0Yc@u#G&nEFa33sw77p2_TE1<IU=y-%woe(c;92f9{ju_ant7|X~za5uep8g zl-XX;^+k4iToV>Qp+Yol2PD1CG&Q65xhy?A=<RYMm-mo0v(u|Y8JHu;?%qT$sX>_n z$_0+LvLi5udjp~>*TY~V1t+jIK@8QGk7Hb0>Qdjt@MzEPe2B=!H5cYoojo65ShJ65 zh}<~_g=Pudc^4PC{j`YhrdeLjp;YR<fWH@`e-Y5ua{`DKSS1xj46Tlmc{t!|{{|9Z zV4Z?!<YOR%2z1UCFv{0tD<6h`W&Uzi$zn^X;=Ij(u9Yf88(=CLc`Hnvv|>xJwE)L& zpalTM_7rGIU``0xJuVAsQE_Soa_RC=eQcmc1a~=MJ<-%dXxfCi{|HFEK2?XM7|}=g zU;_k1eK702O~_vBM(DZTTgGRm^<Hdzbi&|o#UEhh_eN+a03$d{>7)bverqlr5KTVb z#_9IOfKL;Q30B@%Bk<q~2b>-P072ovJtA~u_TjRx4n#+JhGYHXE{qT&59-M#6G-%} zhyoc!qW>Tgy;4U9ufSL_&^9or<Wu>`2NT{in{G*fB@J1}3iYl=UUBL|jz*?wVXhsq zwSK1MS?Gd8B*ub-{2`p#fRhDWQ>@J6RL@tKZ!TvAGyki&VhNGRG}DM;GTB#%&SZbZ zLW~qKPWB`$y$#?j4al^8jJ0wm;+i;cCXTe}mpMBfZR%{@rd~UNJw!84bIs3cK<{rr zdEVMqcAOf?&^|h$KDrrp%4m8yMsym;3)J@j(OfzC{_m{*#ihMMKt}6EvKN^ZmZ*JB z{>7D@2u(&ZyA$1og!KF!;CJ@ii-sFM+_VuV_oEeZU_^(ja-fa0CtG=FF42_xS%GA? z@&E>G%;2kx*)E~RUQvQNv_@KHG{9~YJ4(MNv<YiRx;<b1W3xSv1u(NcCovn{o>8}) z2y=yM6k?j{Nx@<21+1V$O@`#8-ECAqY&@1Ew0V-%woh3H8@L`Zm0EldX`oAs2~b-} zG6a<$AXxLWL{!fj;byT$*D`MUZij9q6l`)+TCQ+*f_(gT@tb&%Tf7Vw0?CA$DqjR9 zfO$a4$de2?=x7k*9=_gC^8w#J-!-6Zf`JZiLW>CL7P0#nqKY;UTC20gld{ZeAIwkl zCvK5UM2^wisTJuYf2!Lg%dBUuo&QsZ?fn!W3~gIaa>E5$p|7oE+)mjg)9QFoD`D?; zg>Fg4@=TW}MOF_?8^(V^o~@n~;gzx$K}0z5kUlQ$*VZAYBBX2%?8Z=JslY4LVxOpJ zp2bDwq^&<gVvD~%i?yMi?W6)UvqoXRcw9zeATc8@5TBFTnB4FQS3d6shv&A(G><E; zn`*b}4UQ6TOe=B4y-6j6|K19k<9#`%*KH|ta5z!ai`%l}#;H{S)&dHL;wOb_feN)q zJv336G76X1cFKLLnmmn(@Ew;J#MBZe=T7ka$~;V=>^}1xO2vGB*u*|ljdDewzqo2! z0fsJD)0Z*9*x$!q)mo5%r%yGYj>JTq=1)gR!zQR#2ZNDO75lKk;d&+YYGaSyzc@%0 zR7-74)?6v#0^dB4j9SGY)N~LkHhd;kj}xP!P^mIGJf?jeIJzv{W7wfrm&e6Ttz1qE zpOwJ~Dw+`RUF<zZhq@ZX(PLV_UGR?|u`BZpj=NJ(e7xJ8kAfG)5g4kyQ$2;$HmQyv z4dYgACaEsF#Uj<UosspVQCwyi;x`YlDgO;7pNz(R7OU$Ua68B8Z8|iWFbJ!kY&NyY zG2VuOdt>yy6ciM;4}p&3MZj<(a4?$)$)y%Pbq$!C)YFE*P(Sx$S_T~q&TNFu<MTw5 zV~i<FM<B!Q!0-kT9x`>`cjP@(9$U;jQt%#F?io99<{yvFqXhRY`75IH7z*Z#faP|d zT7Jh)(9$lyzhYrc-O8J^=(&CItS@#}K&=GJ;|YNKU`$}d%j%o%(2kG8u`jDDf}ga+ z<b-xPn@@5DJouKW6KC?f(EJ;a)Daw`9z(mrWfF9%F<8$vy20`$8?RP2f6#}ulh%aF zSuZC&@rsdh7c<)xPMGzo@pfSr^ysj+rpE>0Tdx{_!D^%WF~Efm_o2nxybB#SbZl7C zZ9fK<p@UBDyk+i9`n~}t)J2-URJ1$O6AWgx=Euk3GFiC#f-9hQ7KaPcotVBtbrz?t zk{+KIj|uKI@iDtTOc;4wK4W)%m^|`0<+@<pw2i$-yV0Z_f%q?8-Ud)2?#0Dz>@{B6 z=8897!ZI1WWB8Gbk60|Sgk!RR%I#q46hom-hRq!ri!F)acjRwx17+%_wxfX<-W1+i z?8P~h6j<MDfk`KCGR~V|OpP9iF|1y@I|VYAK2Qto=ngbH$ldHUsu`Ots$(s3g`~<s zVtn6~Jai!PHRn)~Hsfv#z&wn*T3_3PAj;X)0S3qvv@{Fkbb?%MgM^;B6ELYbgk1W* z7ADPb?}NIlCj~64GIUEKOn7l;#RY|PAZE%aSl`EpY0>6~jUb1m<D3i%b*j73bs#Q4 zz4YABMx1dutE4J`CQLh`qPJJz!cKd49~6Lbz#cZoc;0LbEQw(Nfg-jZC~>B>tXFG7 z%8^74o?;gg6Pd$e-44kh<|m&j&Z7>g;OrvZQE8Bi)pTGal{Wz&rr<N4h*R*vm;s@* zE#yuH>n}-Dmr(M99AheC;xGvF33*bSZ9kMaSEliV2t5r?T8t-!<9Zq;8p^j^tNaqV z9)zCHeB-@#5dm`2rtQsqdlPK5wcQynFrI;`<BZkVH@YsZc~crAL5}TGK(BAw@wo8T zzRh~e8fAD3n`fIQKoJ>Ta->1^<6i?qsA7&(-$!)h9@j7LeUf*Uaa8B+Nk!hDA@9%H zO5@z3F8o9dwX{>4Z%LJmN3~s<+E(I5%@N+TlX0IQd#y$c+JyET0(GnyNQuKGoK_7} z>wre+mNdsEo;snOLJXxK3@Wn?ddczyWo%Ch#6gHX*k!n@V;j~Bxrp9Q;YLx{0)Yv7 zw-Y`VUE$%<m245(gnX3?3+uYhtTR6E1ZF}HeKdN|Ur=E5EB_`4Y<-)?!H1?8V)hy@ z>41C$0Mo~AG-WpQam*{_{3~`4aA^WGn8riE8?P$Yp=7Yk4*Tq@PdKlHS+Hvp?7+NJ z0-@o8`Lw#>Ce1)Np%cExdAfCU#o%ET7cjj9)0L^~QE=}O%*k~V?^anLpWFfAGS1-n z>~1xkKAq0O;7c$cXr}uNS@%zua7wx_SSvc6*A?eYfB^}dH^n+RPq@5=K(l{vxETC* z!ylm$i}7OM*jD-{tOq^a<fzBvz_+V(d4xr=?c?0%0i-QamqEYb{))F?D)orCsqb)q z72PMqJ&EobxI^<9%MlnGn$KWNR6_IV4-pwNir9x^uoaq$O^R`h#y4Z}%}C^H75>T^ zu*SUF>cI6Zjp?@D-dZe52rm~)^|PL`r7W-O=;~zkgDNx$NYnaUdf3(DtVfS}NBxLQ zUf+-4VtO!nwGna6xjN>+NAv=1==cdtkp2gUV{j9)@g@`?M=dnEGE)N?7+9_deqr55 zq*Wkry5o;P!D82sAes6T`aI?(ri6&@)yFC9%{A34=DIDpNw2U>cYAO_qrJ{z;L_*z zIf$!D(4xCN?gW7D_N3?HCA>(N+hWuQ!EN+>vM-q07fiv5LSGOJ7qfSqn?~Ch0hzaD zZ7RMl2hagSnVwY2SVo@OrRoqzSZWtqy~$ELnT0u*1WRoKZwSt7^SH&_Xq#tgizlPo zGlMpoZk$u~ELxD^N%bMz*Jsr)7k+T_%a75jyTDs9|3@~LOrJUZ61<z%r9lg#D=W<r z>R=kS0pYovdd-+mxEs&j$rnz>mMqo7Sifv#t=wEo04G=iVz=DlZfQ&pUx1|rLBwoe zCL&|ly>6L7=G>{U#S2HeWAm#6#zvV)V(nh9<8><9jpm@>=AU$M>Q1#3X<?4Ne-_x< zq>hKBHLdPP@5~Ky+Iu0Q<CTaPm;HubZ*_G*)*Pg-rtHR=EuQqwCP&9E+9g^T)mecn z`s#M1Em3zshyMP0kh1Clao<XJfbK`d-9Yy`xI^<9OZqB<rLWTel)lPn?4yjuHzTnk z7cQT9{fe6{mccGN&~Knyx^Gnf{TvvXQ(oPFU#<Y1qWf<)1}OC3w=fAE*ngiw+(G*9 zSLnY7fA%l;-whz9)qg)nGIf%TzF+^HgeqO}H60lAm;Q_1fO`fi*?-fYMd`XdQxcHF zApLhLI{9h)Z{9!uo&LKL8B70-2U|1yZyd82(0{)j>A$`f&x~%*Z0Wz0<?PODR=C+` z?u~R_qhny7Wm~ZO?CgPk)@SwEsH_I`*_G%LW}m&#>a%QUFt4q<64=LC(rahyUV8@; zNUwc)uwHBT*^!7gSf7O{C-NFIi#Sk?z1E4hbzI>$9B_M`!9SzJP6iab;_-^~+a2hG z1AouMFCCto^A4Opj+V$Q4dod(UMZ#d%L^7*J;$5@Z)b$Te(pWkvq8YX@%zy?ARWC6 zdwhSz-p=dX$LJ4rFj(}f-($kVI~vz$cw7F4eH4K=GlC{$f}wuT0v6XE2AiWhUjTjx zKZNH9p0ftvsdvDZ)HUFe<DMm0*GE1*Mdo{vegpKNzpQ68-FNKiUzTT)XFZ<TFTyq+ zp7cL+eSq}Q`IJ_{QeK7T!*>J5z~BGCFBP5x;qKXs9Zoz`UIw3j1@;0#_x|;pf>dLp zax!;bQKr7h?|y)pJ$ZH4unlPAj;fk2vh4S;Q*(b4JgU}-`z5-!(7jFEPt(1P?z_eP zJGyU!J2aoEFe3}iXLRA^j3>OD5u$i`V1&*Ty1``POvpFW@y%p>GZmOSDRn(r`Yeb3 z#xAm~(^zhA?MetQaGBv??Q}p!i8`nD70}iEy*;H{FK(R!_KHO=C~SU3Ml0J^GJRfn z514N=n3pBJRXNQhOECs?_Dn~Rb%agNf8&u~&CRRJ=encv72|N+Me`%I&KueJFztN_ z9r=BX`CRHR6YgMIFRC%~ISk3Cv!`oSBp=ij=1VwNFZwGu$UIvvmKX^sFaZmQE{kXE zcoZNMgn4Yc^R%JHkL_Y|qr0*k`)U>LDU*X2Iyj%Cdeb8@?Mt79yo5WZ4B7NZ=pG(} z=;0OZRoeed+dr26SG2Fw{(Y@h{5bm0Y~P~&KeGMF%fb`e@6`S;+5W@m4~2WZzyk-+ z6@9ZxTpJ9hxJlF6x`x%|HQLQgR+q1nFaikH1RBcCxWg^?rL!F+Tn)e`mpZ=*6z188 z#2wE91N9_$w*eD@W}1<Bo5pe1zyzwu0>-t;C71`}dJ&!qbSgKHz&;RX48wMCT7y*= zkh%kH>nf>B#Kgv+jyy{u2XJvAwtrByvh^o%+iZYE(Ez!C%2gbr1I--^95@lpKR6Q& z_^52w5Y|7qn}kE&1PcQvxYz>6Ym>hJpGYh_KEU<Fli=r$X{q61oC}_X^Iscqv>?`a zZ-@BDXYRu!eV@cW2MTq#E2cCS$qr+sApTn3CyQpO6sFAKb9Hbwf^l~J1@+N2q}kDZ zJQC?s&mf8sAJ>V&6<ZC|JB|;>#!Q-aJm%UXG1n5U+pAHN*qE|sf<{O2Rc*NmIOsP8 zAsnCS#=RwSHj!>AEA}9``+%i8C<$|idD9YO63TH^=Cvm_#j#X53GGrCYqg^^-bD>- zS08q+h~Q#%0kOl;T@yXn)yC>sI4<V8gbS}d5p%78-TW(TN$8ch1oA(7@An(!NR0W1 z2ridg52-1~354--@ik!1LP-X-V@-g1Zb0J5hT3P>QCxBkNW*!KSzaWiQJ(8DDpd5* zD32P6u4QqXaAMCsV590FRm#~mu@4osPkl48lcWDYwo_pR5%Rwro2p88xY794w>JYH zoJPjv9wO)}sGgs?mL&&p^*UB)6PD6o?Z#=~GTNs$0UYS)!u_xW!;f9qD<L&qMou#K zP$9LDIfK}6jjD1q;eJ^peI7}LexpDDQ}9b9X=E)-+e9(vxBIZk=EK(YZh#{H#|@q* zV}a|FP}=5}7}T-M`+A|C2JM2q7&z6>u@`e=8g^)tk&2@Qa!=gR%b+9#q2tSz@y>am zs~pPoL;58hus8xHkcxp<J&uUxgcuzNq?0+ZJ;qopa&2{>%FSU#&xsk2qp8HR#vd~- zyaf*V$wL3C>RLUZJ9f-rerquG)$6X45w1skcR+@GH+C*oSJz^Vp~4-k^{=akDwMyX zW<BCTcHD35gW&lZ7#An{R8@66C*Ll7CuityC{sF(<d#zCu0bC&J3TFYF-VZ?<3bq! zU<NM4;*g4ixGf7|sl{nzxqa#lR4K@J#*KYKH8*a;QDZk^k{I|CRK_?jL?h*_Q%14H z>X#BfIF{*A)&B|Sj$v7jCY-vW4^}mKK+uGiKxlgqC8S~+oPiPHkvp7>i}g%cYt#_R zEC|cYIj-;ltZQLeOWU=OB?NLtF@?H$P2!Fvj^Rx`w}L+C#9)SKC~Kr)r_i9DCt(;D z9kGe~V{)=&?HB5Ru@$urKH%eXCH8n?kn1vhspvi9QL_k{5uO47p*fBqc9{{HVE9rH zO8cV-9UD%>26;^Ew8JsXHP|`}3hrD9CJzDLWYj_@Dp;i8T-eP*+~Jx+<IGz!rMEIa zl&K^I+<?0Qr>0N!sU9riv7hx%FDC|hHlOKJ?eu0nVOv|}Azv<`O!K%yy%h~hh)$YM z{kR`EPfMel%D@}WHHLFBdJ!9r6Z@794A<(ruK)y=MpM!;8VM<q4IlMwKgL{y8K?26 zXjGj=@ud&0j^<16qNhQ9MYE(Eofwt-)O`?4*dddpL*5PPRZTwH*Jnk-E!AwVDn`no z`B&nOM;Yzp7eg{Jv<LRjF?j3ooZ3SL<@NP2-D!r6!W%w|tNm+>Dj5v-AiQrE2xaoV z(L{l~?-}fQn7ohNF5ahJKrGD&;rJzkxp^~Tna%UYgANg%hxVaQEOB9ki!yCu;?}1^ zBt~bOn99{Ba>`ahtBEQb{n`{K#8^wil@Mw_a`UMM{6(uw+;Ja7e{}$pbF(oB9g<MC z>|lLO^-6FSZ6=#zY*j2f$MaP5C_bTn0)lDV2B<&dQ`!0F8ICyhGD4P>wc%0?9DCVg zI>0s()DxzI`|s+1Ob5DivbxuFfE}f%?WQ9Yvv`H+fk4B)Mw(h<I@|^p?kFfMlR?Om z0dC{42%AjzwOo6TIhsOv{{Cy0@GP<cni1|&!+5s=yW?n4g#aq&-C%MeamNFQtX@6B z8Y`=+u~SMCHZBS=4}f|iWb`sc2UGkEDZo;?Wo|3FRxtDcUg_;!yrgZNOYTd>S(ED+ zCo7*Vy3PA2mPoTfYBd8Ae7E;ees_EKH{sRheE|1iJ&NZ(xj)pvdoik($6nCKpoT>e zwat5vuiJYYn_`!DJE|CVYVYjw-i>Xj+vFhRj(x-p*Tw<2d(=1rFczgK7eCZ>L9-1U zVWj<^>mobsB3DsZQV$~*^dQ<`Ev@VU^-FYN5}~&(7q<sKU@S^jKZIAA_)GyKU?kD0 zGQ1D^)cqiB7D(j6#8PdN9L&Y+Z}of&tz9Dh65<Dxn^0o)Ys5$I;pbj_%E$K*tcuYe z)X&%{ybrW2g5U|@wFs~To~lNmEhiR702QCQQBtF-@(`)B=jr8O=lku*cOf!pr_bkq z1W5z>PmEz1kVU)tw|N26j73FMH*ywty?-6YefNxYlh<k9LjIw7i#dmen`vBl7yBE7 ztNrGn4>!i{BgVc`bP}J+LIJ=uCSetiOqQA+JOf3ErixVE`za7dKjwEnz9E^|^OK7J z%aj-D8|qd<Ut%bM!99hTVoE1CW&IoJ%n4zj&b`VXaQoL)2Sn&0DDn*MVOcWnu*Il9 zYd1C_dZ8c3;$>(%|9!{=;BOAK{xftj59}zaI{CtCwerhXI=-%!uPOMtO1?65qHJ-@ z(2j43W43lo6~`RyI9nX^OtW=*7Bo=p66_F@uN232&9Gw|&`7Y~sP}BM)y*X+O3pkv zt8L`WQE#9ojhxx~e)*gks!QA%>QC~Xq8^uby85lW-RhU}PE$X{TX_H30BFj)6TuBM z?+5*GKF8!~@3veE+hZrRltAXRXP?E^LMLN33=5qcwrOhnyYR$~gKFzFSed|;S6%Az zjR04MYmeVmORvQz-s%6~vc-O|pET0?_da+#AKL<U$eXpCk9EkG!q?sMb*S5W7>F{` zL*j9y+uJK1-R)dIRF4z``;Nf1I5{NlC*g(^k>lin?KlF>NoesNz-VZCC_VZi=nxLQ zfX4Vj{8asQ#K=k0UofC|!dUE9kE82zP8YbS?aDN)aBq7Cx$Zj3Tv{5lp<f~%*~m83 z0a5ORT7U%M$xZWRWeOZ9?JXq8_ypya^fQ>g=QFmkYy<ys9>tT@R<OUd1Y=IN7_PIq z#S22xeVSYB1fKv->IZmt_N+pS4u6QY!Vy>Zo!Ox1fF;4{y5GB3)degq32c^W1*Yn{ z+I;^Se~lZ-r0<=FH|GfM?EHLpWw3T-08tv<wUV|vP+eYAeY3v;JYv>6H#&;dudqQ! z5qZQ#G3Yme<goLR7_fr?i#z{g(1)uPtg3GSZeF98>lB!M%ylm*uMXtYHIzWYsqyQR zruJ+EElxKxs)(sOkQ$XcWwCk@`;Q_uD1!ejz%NmIEx+Wq;rC<sfgC0+&PJXk<$>zP z%JrHJG1IwjuseT1Ffq$~*5L7gr;cUhrW?K)xTX~27WLDN+$n}{Hr(hmbZfm&*a?~g z>ElC)w=mbWWeb4nMfD=XlLZY04E~f-A=>&Vw3^cDqupo(jXta~A%2rqCyDy(!x<^9 zBl;ds$cVOy;hE!89d#xxdRgwD9|Ea88JOo<-f8c^+km&Ilj^#ih%CzLD<D*13|K|| zwf@9FX+#fZU>uteq?5^mvWzCqRnSeoIiH&zxL1=e@(^*uT)~=@zBMpCo7KFVG4D{X zqxpj&{0RgK{|O&FXNI~0{kR>P>j+kXP@FB{@i}oWkN9BrqwZrv@?^>6Nc|8FkkXUS zKfW$co}<fytF1iqeCnZElO_r8qVV4jGZiL^zp=ch(0eVs%{F-^%M&PX2<Y|Ke#Btj z;|7LD5dvc*R6p2RsYt{M^~{s{^~}Kw(&h}jAZO0TD>*W$9H#1k4SP&tU~Fzk#WkdH zJ}FRO0uaSv_j#0vp6o%yJ<xlV{&NX%G5d^e%hELMepG<9#OivhCt2&HQeR>V2hu3D zhPAzxtzRU4zYSqcx8ykj&`iz>txMq2h2y(IXL2L+(qC>k@3;?JB1!=pBp(B5OJ;FL z@IkHPEImE#K}$o|Oh%NyoRFCBu$s@Cb~vurxG6sl=U8{CWTPa1*TLjW+)IaezeK#2 zoAQCo?TsL|X;X)E=iqHIsJU)gvCuU%#M*|vPxT0q@?_zBCm@6;A(I6fndNv1+VdHs zQ(Xq+r1bBK?*;G`0br5_016m;LkD9T&btEYt;5wvTTqtq{fKhS-$0aC6}RGZ9o)`B zj>P=}ymP8+s~fAn9&?!^S<=a>0$_&ayRMwnm}uFA6DJv>r(?Joupoz3Dbb<Bv@H9* zCTxCua3eM|wqvQJYN@ziq5Dp{E5yB<?z`a*&1Wn}U=ob#$j7+QeEP#4N#8gI<>ClD zHaEDgD{j6SlW#_3f%8f{4eRRzi~NDbyoal<7G=kgxSYCRgKS`%-x3Kyj;o5X>O~;v z^DH|Qhf2gx0P3{_oUO+~T%Y8@wZ^z4eO9gj+^T$)KQEhA>v$K>gDBCs)s3qbtf&ie zObON(_-li_>MCV`ucRE)&$F;D;2+!1r?fgy<DW>c3M^^)8miY|lD*2`SnU5!uo_CL z0<>OFN;xE=l(iL-|3J@~Nr1Ajydt~0p|E_lf0pH5)KC|!r;mjDG3xp&^2=BFYY2K_ zL*3d&e>TR~x>bXE3Vx#)GZ+Ze)h;Ywd6U4=E=e76d&+B9`fDO?-6E6i)Ooc~nyjfI z1vI!q|Jt0o8k_}-<WPt+Vk09F>LRHN>q_eu)YL=*i>@RgG^8cfH<ve5=;F9+-(~(r zR)CHIhX9}tFokU4sjCfC*9QHQY#$TD(z-%_U@dktvr!@b38w~^6?%N-fhv~7Q&nEO z3M6d2NoX~iURXo8Nf(~Dh?C_a#XU83js68ul{cQAkc-M!2F%<cJJi(*mhi5trR)Of z=aN%=W}a;(l{k$=p#)(31q-Dr&yvvE%Ib#I*{Jk@zoe=hEsCo+GtU`1OiIBz1a+8J z+-F4GWwq718cBS;?>i80G{NjTe`9UHyAJoJv4H)31SBZ~Z;2wcWIH67rG*b0ZfRXz zeqHS<;xMp`{rr}cHvqR)snPLFKLIHLsPa>)fC1jxK*M@;>V`nEA76Q^u!ZJlg^9Ag zR5D;M2m~6~9JJ@aswCBPNL~GU#3pvyjh$+=G!`fV()26!udWvasEF@f=U*9QOc9mJ zSCe)EA;*-7b7UtnZE)|xI%=bxJ9yv{tjwG2jD1R=f?rCxNo><Yp9+}C$`v18VF`SA zWOKEjO-g*}gs)T{%jItj*eT4g67b`d5egRjSLq4CmHzd1so=?b6dOwX4Qu=jXGWlF z@6z@4{`~3{>}6)ItBB432qkM8X3f-eu?Y^qqK%KJHo=SiwdLTkt4MJ691~=HP5H{G zqOg0AADf|ISPiTX_Rt_OjY3_5iv3LQC;yTZ($MS{f|grQUb~(!8}n+d+GnQ#Ncw^S zn&po2Bms+RYt~C?u(V)~GWK`^s%t;Vj8r42fo+#<YB2wq#FYWM=dmpaCUsyxz;LF9 zM^VCG!K329RM?4*sQtwwI-+<K*5$3l5Ebo@Ne>Aq!K8|2iv9}I-)xU8Xil)ECYq1X z&mOu=4#29+gVI7n19p6T<&BMC(G{$byxPjT1(m2CVYQMQo3!n1<4d1~{z`Q1NK7`b zh`&T-=JdiQI(f0sSx1ur%p!@-V+|&!)~HJkkf)CX$k3qyNesI%QGUMi2JkoF%~8Wl z$8m*G^0B2aP0Az^%b8!%V2)f3yquOTnKZGz$v)^wT=T0}`fD-NtX%1@$MzU8GrgpU ztj=inEcRd117eDmjF=QuH#VZkONy3UI(vaHuaPkea8)B%hrhut76IDhIoUSbL1CTA z$RwJl%D?ianTg_GjFweL<dInsw*IOceb5>v$qBx&&K_n=4$eM#s;|x0*<VD20)6bH zWLFFze9XS1?IuVetguMlM96Ab-im77a9Pckr_fG@;(k7}IGVBMB%JbuuMR!CtkI97 zQ3GW<Qp(rhuP^5vX<(fzC4Pf{O?6!mY(knCs6v**VY`BjgFIoq&YU$Fan39s;9kLo zBH=v7Pas-6u%po%9i64Jqe=Dj^C>NFys43x+HuH@NgvyTrDHD<$iZ3}N!S7<lIbp~ z^4HYRldYiyV#rD<mnpHJ?Bogq{iU43h;#_B)smeA5GmWA<coktL}XCcpee;(U`Lds zv)G(1ug05nKBSlS%ZDTvgt#yMr+Q0cJKv67Le56vUyHC&7;<>l5C_DuDtpjCjbQ|7 zsR5=SJ#`B4(pZz|GB60=_X``;?wSU+mEvG6$8Aj;%u*n7nqI<GG!eDGluJ_v9vloj zV6nma07prI8Rb{hu%rRP7^YtRQkXnK*CwEVB}v&iJ(7XTj=iM1wxVvW<S8V!g;Mei zDI2?bL{`nO!+so?umlNps_NFV4X*YJKamQl3I+hQR*vBztg)`v>_;F0N<LX2o)X7q z6grmBS)`UI={4e+*JzT(Um+EY^IyS6%91*D4fhQ>MU#^1K-5G4Q-g*^ffD5>1Emlv z+EYto)&52@1dxyL1%#H98rHLmA($Le2Yc5+musaM)o2uIN+L_FVzo6=)Yp;CL3aSU z?Db}NT}{mjOz<c<XrGeuHHdAKDN-^tC6lp7aIvEy34xY2l-D+br`I)rnfVFSj)5xS zcrT5Bq=^m?Pm;#=%q|a<+oUICJH%gs2_ai)v`=kCq2FJD8FV8%C|gWaXhB_LfWw0A zHK1Sg!v=WEe4CxfPM`-3wBk!=v+NOn>#p~Hu{9l~?e?R9X{SecCfmCWrmVIxSYMB6 zh`$1TjJ@1qvt$L)ZflIS!s)h_4LD?2{zVN^9hMWaHm3XR|4aNeE9=ZYcga8xnOy3= z+DP#n(u5Cf!^(g}H$%-;7!a$(!kpEIP%{M5TW<BLD&adMLcfswy0sF(deW144k;qc zvAIROwAdEyhx)ClL1PotW&Ur<FKi<^p*2WHpxXm4Nu(o@nXHe*(5x1{R+ob73fe0& zma+xuv^peO$YBeL4ilcumZClFiZ*+R>1z(9T-?Aqg$PGjt7_hJAC?TcF@e+bU0$5~ z#SYk!&#fIWEGa(m-(2?(j<WV`dhW(b)j-1;h3#1Lqz%!sst@hNZDl)lW??}KJIAu~ z6Y9+hj;?IpxT9csFrMe$f@4+L{K#f=&t-rt7jX8fzwg9;&|NgJx^qtyi1~B`N4Lo( z#LaW^y;#^AtCFLEe2EyLjSsulj#a($qJY0oFl7$`8MRG-D+1>>F}(`l)$|m-`hsUv zhMwxdS28SlJ{6`H@^~m3)?LiwDPEDB+nA(&5ET^O*mf5wx--`Vd}K#oU(yp>=@;tF z-Ea}Ue=gs%H=Nu2)T8)(%K49z!EuX?lWmXDxsyBEpa0@IR7T`F*@GY|(OiBhx5sib zv1|*4OmojavB&dmY~#NT-&U`A(odhk=9yhl-t6)o$Mz+R7I&#t3$Y&CyF`72JvQp# zZd!{<-gF7;4<O5`?muEzzW1;X3aCeXOVl3_8CxP3<8o8zP8{-8y@*&)Q}w9_b;vm0 zj!HFA<Cs|hWEsJ~Lq}KBkxysOwz<S#n>~+#$z7zw*)l9qZ}T2+^&YqP{jLEeum=7j zmXBXk(@+oCE*k}_cnK|M;IFHt1Qr)(<18=Qag;uJ!9T46v{&GhyNWMeCcBH!C;!dm zD7Drn&&NXdXRATDOMs3=%&Jl|Ndl5|_WTWm?XOSHy%jKi8N}T|*>ute_2#;<hXlR6 zKSERW9a-2u7iu|FDbSrjPBbU54_wv+eY}F;x9}RaJU9c}U|Ej9g(wltq#t@52%4vm z<*+l7ID;db=cW75*n_dSeHk{Bvbh<EeRJ-C>~DdgKd6gCX}e3U*Hl_2`BE<ur&Omv z5jWJE63k9|B0D{0{(krd=O99=c?cVOJaC9P%QUK%y}6T7^ik^s9eqS)^W`I9enaPO z*{u`)@fzAJn;CAB#ZHXuHcUYo+RBcZ7BbYQkM;GT+aD`f4xP{gM?v;0k*0kfGwD>v z5o(`_?Noc<6yA`yBcT^j-H1w_(5YULh=;A4a()75^TxxZ3czMCF86NQ%HGw6{W{fp z#7KI=dq|3aI6lVN%Q#xGOG??PiV>}{`6*hi9vOpZ0Y>{3qJ^HS0X2C{;wfy#!q7nC zj=LGwhA?9*!&-(zHwZfi$w^NH|HjLR7v!|vMS_TlJ>dMsqlh{@bL)Qi1<wsVbpUS~ zMaJ&?U1T;OIyBVpqIXMjIIb|*fgtKSVy}!@orkP+cYs2o?88h1)hKnjs~c-C2)N5@ z-QJ~McO`wMT!IZIU?qE<(Q(|q=onuYXQt?woF2}se<99nJ5DliF06AmnBAsPW2*5u zHB9G^wuPo`HY{u(wUzDH1~t3X&mLjDZaf4l@EgupMAHBXY)V~f8v=@gpOD!h{1b*> z79C!N@GbA)=1=e8Oz(-{IbV2>HsO5wT(1k4UwM!49M@)O;kCq)cZK7Mf}J)u5`9wX z-~06zzNqlF<;yvCSaMK@u@i@G#Lo+n4fH#y?Q81aTnxw<LlbwbJBCUvIIg3{frlab zu|Gtjza;&Kl_=5gX7ow@qth;vC<a4I`#IU=dl{`qqVHhze;n%v{T@U|Ur*M=>r@qR z8$d17nckSV<6WkBiYeeV&6yqt29b$vUTE~5U=a1XQL5x=De1tLh0E9JQ=p1W9whCJ zJQ1rRXpWVbdfD|X)y#G@WH_pt;i*HVpLOAM1W6q7GIRZ^e+H)wx7$+lo>XK+g-V!X zDCljwi%#_<iia^}oKbc+hLo~<TE<fevu!EDS`xJ$v8e~#yeCD{TZRL0C3o9h^g^=> zl1Tfog*m-t<DKZgEnb+6PiWa%iePXy;j&k`bo8D3fv;w**i*K<w(J{5jbUR>*kjlf zd~ysMIS0_dH(pge_=+0CrsFJ<T0JXj3`;eWWPgie*hB>V>tmRVrBRqXX=7r%N;I|r zCf@C@!Czgkaq_8&*yM%n4mA~|gI42G<<%kW`x$Kx5k}fn5X2s6cMFo{Wj^hf64Uyb zz?8~@yxq&JR~~F~Ptk3FTcl(vm7(79hD7|md9AZDq}<$3Mc<?dTM12-zp`3-D`7G3 zReV)u_VU7uFl?K^9z8BJi-n2t@SFOABj~&&f3X`zu|m(sEo@2F`?t^%6utwKXS5dg z4p2{e!V!mx?GAZQP*oL9D7n)i9&fO4w;(U-$20*!xP593Xp$Az5#v2Uy4{K3#cGB2 zi#uEyg28r}k?Do-qX&VqBQ43$G0FxbGLzt>NniLP9HhY!9~>8u3&sIyIlPy#y#+ar z02MPjh({`CcEe6^q-6;o#Tg!BUx_-9k9LhFgds-7!GPP+EXwR(REFj?P6>J|LmL`n zJ;C{WJ1-1=v$EUS_$x<SP7F{C9gLf{cf;s~l}5hDS=r+9;D)Eq0jIJ%+jGLr^78AX z+mX{(&>Q@%uEB`iO7q%uL{t0Fekf+9^;s>Pg`;e0-k>h`qthCG;*Qyfqdp{KrS9oB zfITSD%L7m9uiq5M33WH%L3<ZRYt~#T5#{{6-OA1f2$KKXv)RCsW|&<eqE|-!tup(F zhkK3Q@Q<(<y+p4^ETJW3Y8dBe+j#gFzc4;++t`a28Xl`jq~n4^qTTf<Ms8gS#ZsIt zr8v|)htfWTj8sRnLnUZWHUZp<NddYSXUyc|2<&vr$Ke)Vvdt!dD=JxZ&i)mg$^HJF z_#D-xj661B+A!ItZ+_u0&9SN%G{#tb2zFLzzXx}&cBuszIME$gs|#Y9&GVF$+5UnQ zM}7@8=Jrzf8wF`-+v+0{rmVd~e9(fAsMod6>{!M@sgI~m?Q@^_KtwvCey@F!;}{3D zI->qd`)m*&5bcP_Wy`2CjlOcC{SX7-y9lG>GHCR4sviIq6D`h1lkG;5OI#3jdpaA* z!HXh|1R7rWEq0VRuE$@mqZnU#jv_}P+<Ew$gKx}H905mzquNpHSOuSIM~%ae&{{{O zqYj}n?0>TzEAWl668@_l^^S7HSq~`XaQWfS-~aEtEPS$&L!)D*;8_oRtAPXcTKN0F z%5yRDY(TF6mwDwQk5!;xjZn27^khw}!Yvko|C6%$0Kd*r;Ru43f&b&W>z~)D)cm@7 zBLUE#VX~~!C`+k?0%C{gUc+xOSXgCuJnFtG+1X4DCfv;4*N5vZsIG+ZRQP~C`$>5k zO2Y9CR~UPn<`x9wn{JL-9+;o>1kNtJwd+G?s52gCLDy!qEsWp#+?sQ-2C&#=yd8I4 zLgw2IXBs{iZvD+HJF(Uk>PXJp`rO+0C|yIa)`NuP^DcSn+dM2{UWJypV|xM^<VRm{ zuz-d$&t$HHk3N$*aP?^~mZ)01iVSG+Fq;8+mHJQUgF{QYdE<VbxqwjHL8w0fRKvSp zwYV92z$iOl6zqp7GL;KBHdDA3km&i5FooAIBvUZT5buEEY)%HK{RFoV;CK!Qc9XHX z!ErX-L%=xID(6@nBM|8qEC~v6alb;8s1^{Nq6AmN5_e2t)SJzylOj<^S7jpvEXt>R zfNdU~Udq_{h%JjWDhHs<kaY~1$q<!GUtV8@$t!)+;M?Z?#J7_W+j;t&obMo*sh&bG zPW?Ywq8lBR1|mw<H;$GexDmiaQF%Y3y^Lr{Ppoxv;#;0G>m7nMI&rtcw9cd_@)wP5 zk29g)W<hr*BH7qz=yv?<MPq$8#z`)ttXwh}{U${B6b63|!Y4hE<-Dn5bf_b~#rrN5 z?z<<EdN>(eR^_m%RcQ>z3F*p~*h*tjtb8rx3+XG3EC??Pok>p|CeE3_+00*#RL4DM zY&_7m;iY&ZsU?45yiw%DD-i~F@fs~L7F6PMEU<YNQ^=$z>ZR!U1amwNP3nM=-8&lM z3EyMmya#+$BQR@^WP$aUg?1?~Kt&2IeJthHBT~vIP$~d8tW!plz8A}O5<S4^ixJ&! zsl!opq){)Q&Ead>1#GEy;A9Cz!?|DqLq{?6A6961Vow4FZ=Mo@fb~=sCK6eQpl-(> zHfeZ12v5oPZsz;9&!h6)ET9jlWs>hB--ryG5Z*1hgPR#{d&9w9SL-$x_1%S~SiPul zm#?T>gTasS$D_S)-%2lMRO3`lU7fq8ykV6YE_1->@al+dM5dpF^m5KuD|*|@bmm!_ ze(NLob>$V%{Ano1p4U1{|5jq)JmP}9!aPq=A;1Y<oWJH^W;+-_=F4!xJAF8}Hq3Ry zD1<D$p=@deTbsoFuwuLk$mcXg6I@Ay)4{T2!qdQ#N%Pm_CksGd6Gs++7>7a>On(fD zI)aA$9YT|1oe#7ZGkbKiV+x+(rM{AUs5%V=V9Lm5xoKix`an`MY-9OKO0d@n-6KFS zItU|x_yd3c0l(Ss90+5^RNRelcC+KQbDB-tF64H!-GeSKZ@2kQ$2$qRVW((ic?}eD zuoJ_x73PZV85mh`@zL4({?ZqAy+3?cc*4jRXykN!U)&4ETMKi8%IGxLd%4gn_u;|v zc6`%@)IN96y~KDS&xqH?jh~wecHd>*MyZa&6;AVDCj1-Ncz~^m7sS$G2f8=p_Q`m0 z4TtkI^BgRWc|K=O);OBp;j%_ky<`d@`kFM1AF_VRX;m!1B0C%mssS*ItyKL8=@{Gz zp3vFzqw}IT1MV$X>3|X96}fS+8@n9q*jLF4|0v5l*60-bXAv6^=beLmunH*a>KB3E zKq|;_b?3+>QT$Hckp(iV$FanKJF8ArCl~wT&-0|fkB-t(=gFkseVO?lj97MM9qkFn z8e#&1QV8sd!5C?~8_;knMLmP&%NvBVHV%85IT+nAt*DBS4S<xmc=>Vi!dV^0l}^Le z+~WGK%!^ABV1kl|bT215jn0-^#Ed%6xpAgQli3LkV?&+<H%|T|DlGY{41&b@_7Ydi z?Cr4G4NKX5p5$g24#x_J7~8y#sEEA=&gKCH8#1#pcdxm4+HT|7UGFo)w(RXrqtV%x z@*nD1!0WqmAdHFdM2$nf!>YB<C39u_{M}+f8<tbIoe2W-<n()IK`hW$AiN8rOYTU! z*r<oyhCpKGXKUgyq_()WU)P!Gb2Sc!!*Fhgc0KI8<1@=8us_AOdY9OX$rr%=b-F$w z(`B5YW?=vVN+^@Wd(?~v>-8|@sa`f?qQ8hu95L#tZ&{C@Mu>>@roe-#OQ8NEh-T8J zO<Kzpfj0mqh?S@<f_}g*BL3WN)BS48D_9xYb6B;b3EJ)K8Bhyn;uHtI?|d~>!vZ~! z7usfcgwQO+0^o$+I+tVfCs?0_?T&=Lt9a=^m%1GgO?uwOoLHMWJ=+B@{ho~SqPw2t zi<@(2o45V`7jFA?0m5VGQB5`I_P82-^M^=|-1^9Q78GU+{~yNh;^GC%@Maj-&lZ&E zZ-y=OF3RJ;#xQa!&w>&!Ug9PkPj0ad$CJOH1W6<AqQa6=(=9f7=q@hvloshUw3?Ic zwY_YZ*?EiQo48~bX?U1=;Co47sp%#z-u(W!c+D~~u6L=&>qF)i-rl8oL`B>>+*ed= zhI2c>yR_6>T(}_LiZdJ^IeGBNUuNT#W8y7gMa4@N6l)qXeGU}xOY<T!0P$N?L~M1Q zEK6RF{-zY2SK!O{7I+Iw7wA;PQ{sTw{2swLg}L71yi#wr2}An<&zuDwR)U=-s=o3U zEcCJv3}gKi6lom!U6_||`xh3K+Ubi-yqG_VXvZls%g3}uWja2~TC~_(T%4C}w*%6{ zSDd$aL8({L5>H=ok;j`|R&3#^;}k6_UQi%$2nTU|-r`a=z36nMUQeXVtSevH!u&i> zR2;fXa&5XWPO;ZRbOnxf`@9Rx`X&A)UX8ze=SJvIVzyt_S81-7O<iD+7FJthn$lw3 z4kX?(?jq`Vbe9!I+SV{}mx9t!;U!*n3xP{mix=qjPns;wD=sZVvtxZR?ULL)YAJ}D zu$SbO=Hg|iU5W~VMU!bh*Fs$3C;I^UVp%T1VLcEF&|hF~+3MKlJ^J)zNSJvt>9+6U z-In&Pm&0vad5xiw^4EPhKfJRK-f9V0N2~YfTnPzYj<jueF%k{BFHpZZ0~?Xa5685o z{PkTV!J_iEG2wZ3BsBuzYlgKo#^7@0<3(YvFze*%A7ibMID`O;wwqBzv4UjU#n8J3 zUkd+(@bGquEj-A!#q#rI=RkdSE->E9eb1~DIFJ?xX+=#0aEK<5Bht?yP}Atz`v5^X z;+9F2Bd!AXv^Fxd%t8$e(21rg4%1YIkPBJ+Aed>hZkU>FJYj$eW^PH3JLiOYZ%O(d z1;f^+Z;xws^rdfo3@>gj$S)P*sx13i9;Ua$5s%6qHZpO1%II-PXFBcQ8DmEbPjDp1 z4*7FAMvaMe3>h3dAp`iHJ-*qIf#)qeW6x}M9LLj;3L$qwvm+JH6?lGv=OH||O>B1D zi|4m^p2qVjp4hXR9cSQ4$FmsEDm?4(wBYH(b6Z-o0~eTLQpXMJp3!KmZHr=H24CA9 zF^UsfQ(~KT?`=Am*br{o{bkd^i47k%9dri%*0lR19dArS1@*RI{{!pw1y~E|HO8WO z;JB~@)v!#a*a@MIUR6#}fdubW$55L_Z#dD(@hh(BV)vrf;aF!l+_sffCpq`(W_ur6 zh3Wf-I(mZ35lLIC(eu0F<9f>R{u*TCf$Z-8Z8{j=@J?6!SthDIQwYF&6k=O=TBM*& z^J1q5&uZFu)DgtiAFZyS^i3OLW2OftAoidn*=0v0nGSk!SHVGdup#1G8XIF$FQdQb z!D);e8_bFJHYweB$*K8S@nf<g7)MtP&<+giicby4b;X})74&lO8c-;bMM^AWn#+uW z1S9W+k(bbPY*b)Ilq)fCUX<&C;21k4>2N{NnUxj(L&R@h>;*yOIU&qHkHk*v25M*u zJ<o!rMQ01jrU&O_ovu~&tEh<<{;+!F7__)H4nl&b*$_vuRVL_G**N?WkYOTeVZ)jQ zSY7d>(9-pR*`D*@VRL|{4Rd1V2gh{9Crbp53q3KCA}NyMFnYS30$0Mv%#$Q&?|>;u z{=yhm+nIM60dkGZ41E}(UGcczz(V1_#DhjuOq{+Soda>2nzZ#v;KF8piw&5CJ~kD{ zkL`Ng5EFA@V0FZOY*cWHj^4KrhP9#^b0Tg%Zu7<Hs4Z8y!skb&O0-%&Qbk9K)B&mz zR|++N$48*TE6Dqdu}>L~SEvImK{te_L6oj|Y{OXP`>l8+Mm+8nkC73N+r(p7#N!rt z*hD8urlVO}B<+fy)U#Yt#79!(i3hfotX$`a$Jr5&3&aC=by+dS!=qm&QnA=kLIeak zdj5%lper7VJywbX;sFH_%i~q?;O4Dam%GJde8l7T@aUJx#lf;u`4>89T2z&c!e#Gv zH6Ke1zS^Je=y}jd!5@p{`I0LX?<_PjnQM3Wn&@=@dh1A!PWJW9L%QQp@U@2R_!BUi z4xSPCZdbhBAbxAM<>gUj`qz>9_nInj0WG7cw=uXax;S>L)%4TMD?IuUC&+2j&z3rt zU^H&Sdg`$8lseuSL#e~sQIFhhgHcrEjke$kE|qM=I*=AQjChzGaNq{4c+Rm?^()1Q zrw#j_J**>4np2JOF$+`5jQF<PH2h&SSXfctILeWfx+Is`$(fF!ZWS1Z&WNvcb))`T zH^q^(<vRp<87yv&Hx^~|Et%4DgXGbgm3H#kz*%^zPd=Np<qOn@^H9dHq+5T*Rz5}I zG_9Kf0MujyP8x@F^@j;oF1cKj*h_R%jL{fG+MF?br>dJ^!a`6&p2g`Z1K9K&1XwId zt-AyeA*e+|yupU}1y&XYg*c%<#J5ub@os@=<2BKS^6*elULD>KuR8%H3>w=Y-eiG< zfUAcBvE2p%b(RtWK-H1tM<E$YnbpVmvKz}5)H|;(+Xv6ip5G=}A}Tak%=I3u?qDG! z0idu#)8e7ESWhbdq~Nv#=v(6koNiAt>H|9kFuF0;ToZsD#Jtd#jtygtrOwP0Bj_}C zUEK+vzThWVHIsD%BpLMQb~g`s$5)EiS3)&&C=B8(Fi-B`L<!a)_^Uy>fxqv<F9n{1 zt$%Xf>kzIPz3$1GV6v=tnnw?_{VQv>OVmOBylCP&5dJm4yA`&$xoT=cX(SlEPMdP> zsd!!rzcj!f2xs25TL-Mq5<lY0Qt?e$KM^_MObfK^SDLg~H%K0L!0+Fu#W;bDGo?5f z@2{!gA-8OQB{P3_kUYMCUk1VkmP38lDhEd?;%$|~4JTK^30TvI5eELU&(m<3XS6+c z!hPt8TOGZ4O7ZN&GaAqq<LqF0ZGb?Bth;T1NqvTaFz@-^t+Kve>}RP@kJpPsz#v{O z;NhvkDO`du>t$fM=uSR=a6AZu)Gw>W4KdZVxRA{PHZ+~CISnkfYPp@I5(l!s2B!yx zfK&6Z*{*3gt|Hh_UUPc-92x?SMV|!?4dv^<2A3J>&5k*s6JZUk`>`k!j}TR_v>^>y z-|GNpu=*x0>_IrmM@)uHzvDFNM<P8F=U3O>G*}(eulH-xduxNM31g`Ab0!bIAC%v! z+Zww+>*RE8Z3AGqkio$IdE(a^2JJUgufRe6)3n!)A@G>-8{Kbg7>&A}I=^u$zncWV z^g;08zEpp{Z1D+V&01n9(YsHB-wlAx*rZo<dm)`t00CzL<z~l$^m=FzJpTf}>_K2P zwOITN6CvSe%#nPJ9G34ayqKGHACjG$w6D|)PNm6Q_+=o~z`BXh#L6q0Cd`XtKs@q_ z&}H2q@b7>hu^R~g9?+#f%`u;}%fyxqOD8x>R%`Av?jHp9G58USfv|~t%9Liu_W!um zk%o8wd@PzJBV{V`(R+;6_--DI-QIHnE+;~L_nf2OL~gKO1>kcGeGRxo*E?}IV%#b? zq~3Nb?xh@<lN_)cvfuylG;r^^Q^W1Ro4mSz3396~nhl0;%7sJYyX7to_d&c*rHpyx z|1^D|0<Z_Gk9@PA%RyisBs5_>i1-74yWzJ1o&)Q&zHDH7nZl%KhwLd@>fv6oRgVlD z?3XaL8EQ?Z!e@OYfR>BPYl5faL%B#lSbMJdvB?iD+3PfPx(zVcn+BHA@e|F<BJ$hN zWA5G|V6YrAt^`-m{MC@{D|wpcSA;XL-BN}q39cv%u3q6k9nUKr0!HqSZgsE+1BQ@u zuzH~1ok&kwvQDCLc-TxYiNRimO8*+tv%L|{!1Qbpl73N5-HP%WKpC2rX&FPqq5L9n zc;cO4PE)TH{|X$b+|$E(2yn<#h*xyET=(4Sm|)?9GuAwV@2`L)vht?WmhS}M3`XaQ zyLFqD^6@<PY08#$QM1DhoCem_qkut84S`|W-9fZLe_H^9<r)a%u!%=mtw1TNKMfww z4uMB1+6?tm7UF<2yKqtc(Dm(_u6e*fJlJ>GZUsPLb<LoKfM-6^4@OU>w`swl*B2PF z?QRE*!Dx|f@)5y-Fit~@*8sx}d<ZMLoe+kekAM(_QCK%5A4t7;Xc+y<0)&R5$2EX4 z7(E^``I(eOL}gtk_aXkk-yh&N1D*qUV*Py<-;ZIEWPKaf8K@<b)0bAm<OJs^8up1n zV2__M__&nydkgl!`5|QlO8GF+R$o;u;K@x-Qx`WN57sC1kFE>m!Lf7zqym4Ss;=TR z@E!&{%Bq9Gn|LZb)N;MQA+UbPdUjl*@gtrC@jLrecp`i?1ZlQK)3p@o2mUJIHyfS< z>uk;=7G146%RnrSD)vlJ@O*F(n7iS}au0-=!8x`dVAYi+FLDH6UD>d0+G3lt3_GjP z1XHVHctjRUjJW@{y>uqDQ{IflvJ=h{w%<V4b8s2Ys1G*8;PMtKy3WX%MVqG2s7`n_ zK`{kurDoiFt&{@icDNQ524B6FDl~eJT1pM9u%g$;Z$8i$(|f&d8*=3TA>^vpKCxK~ zC6;%AAog;NwaINcE;ScG?d7sZ5S2T+zXHI{p3OLPYwhTw{YV)<H4Z`-=9Xk*kxLyV zpuKT#wBh@#VO&5<hEkE*Pw(DoC*g#ZR`s(uY#pY|kz0;m{`_R0V1HE$Zzhz(!s-Fw zz8rh&T2IG_GkjB^O7k`sDdT3n(&}@CjwNosENKh(&qK#XBz=$T_kHPi`DQgcj?Hd% zJZ3)Kc=LJ7e7X_-7M?Jk(6Q9b=LI%}4vtOQ@;$;i7?-qVIpBm2#%iCQtKn)s*o?rW zEugOBilnW%@S@(9Z;E;CwcKmM6~Gdw<@3MTDK&j4XaRGcFgAUtas!{;5g#+o!x10k z!8kwFKFCh}7pRXrSe>epO=YjqwM;cdLa|>go@xjD7`@(#{w+KDRc3TwM)NVYiOsnF z*}2oqX*L4G^$0+S4q!V63cRB+yd<h@i5g5)+FmGHnPoE*{cpsF-Gt>o#b>waBW)<k z#`f~bF}x)#$+Ssd1bTO6jf-LPMthU92M0_Af&(qr9%?B#q8Ih46F(iTj4S&$&b3-M zl)-97qJuqj<RmrEcq*N`UCvfd+Pta3_%83~j_}lZm&jL4*o~`jJwcb;p1`o!FnXQ3 z8);{~)AJ(~MKAXvRvi1I+N49c6N-!FjgoYf6Zy!RFd`)+ZT%F}SKB=zY0EosGw<_* zt}bub3<{@Xuaa(PQF1vsoHFkkal>$cxSfn^=bE5%rJ_0vJM7$o!ZPdUPFh)q=h#_l zJl{YULkZqQ=6%6KeU0f=OoYUu@2}!8$Fx%n3+zTt!=-#b)#<nss>6x8J8A1O)U%!7 zVu{+QqXz7#0CIkC!p`l;sQn?L2o^FHZO7>C`3aNbB6IlEoDYr%%@UlE#1Jm09!S{9 z8rnAi4L67^g01|slD_vk+A1_ZW_=5qAKz|v+>iGk@w|@b6FkG`K$O7qZ9K(zZo;z# z593<Ty{7wd^Zn9*a4R0)Dk|>IXIYH>W-+cr(?u~}13o)@8IY2x%QsU8Jjs9z__gPn z0TXn<&lzw71J;=V4js_Kfb9%;$PD-h`V`2co&kFpu-^<2o7TNOOBm40faG~P^T%|G z%NURWzxHf1;2s@-euc~#u)z!n=>Qi4?qR^AX26X);B)ldoqHLe%z&$Oz}pOP&PRY7 ze^`5SbighK%ws^Q8E}pcc#r}047kk<h}QwPBLEdX`%`J5-vlb?8_rpM;q_(<x#C>3 z5T1sqLbOpj+Gs?>=}pxhMA+e0Z+Kgds||-YjIu*J*s|3!_JwEjw1T$xkn*!z;?Pi+ z`d%Q$(Xt8K?q<x3B__K9U^>(WiD-tMfv~L|o9~LW{Skq)=Q*XlhoB9EF11C_XD98M z%mV4IzwvWNaF+C<kwAK>M8zhr1e(QabeqLG4>2y)F>s^S=ds{?P}2cPuaX$JAPSl} zu9kJUm`{yHJc)x{`-CnBw)ExgcqC%B<vS=oNTH77wk?!OeJ<}KDvWn$&n~cz@P2D& z6t^#0GQtLwgWqT1UC#AscU`6X`s=Uv)nPfu-ymUQ5Oyxq1q(%4wI~P2Eo|M=QPJsE ztPgNOm+&YvMW-p7qx}iX&ZndbrmY}94Uwi~&@{Np61G9DG)V*Vx#UvGzaL((R$pP} zF))6K8NVN19$0z8m2#YTuq*@9l+Btc{>ccp%R-~XAQ`*{O;ci~AuKyh363=27A@w% zdvl`cRgzb@h{}jo{&t$|y5Nc-(qtDwInzwjuRL4?#=eS012Eivc~SqiFk4hQPt8vs zycitE(qdq#ab$hlIQn2A88cAgKCtchJh{-o)M5STw?=PbAxP4(Jx0?5dYgF*3bh_- zzq-{~NgBe7PGe?ehuQd*>dQWc%B!?!;T6z>6&V+o_fb0SHJs_{$e*ED&igYKr5a0J zSB8!|HZ0~h)aPg44Hokd3{cJI!g?^x_ylqRtaCVn(+zJ5uFX&%L9sJ<uF)CZWYnS; zJ0%c0GrS~DJ<mXx><E_wYG3ewaH*7)Lq3${am7^bUN9MDrMtvTcL&p@L)PIofZA~- zxnc{zzX7z=w_idMqUXvDj}W+zVmI2n<G`L5K%1SC)2EkNl2e<QcuIL0iSY%yI2^li zu_O?j^-lO3RL4(MI|&;K{q2(R6DT-rbMSsMpv^mJ?MXy0;BpdC0S46BGZ%c!RM5bt zJLeErZ3A_2?M<4o&P5|Ivlq?!*mxaowOF!f^|<Cb)1jf!sR|B)yxhMGjs#6$Tc#Hm zEO@;|!IwY)`m3TvAb_@O^e{eKo$1?T!=4S1oA<a&3H$jxeUPTk`U^@xFv|gExy(ak zPV*Ly?X2aMpPYB4W&!Ga^3Fss@x=-15_}uoYGxfWQUzN--jL&k&hH!WIs;yuuSvRe zru&%bIMbU!*LzIKhzDztHVgLwlCeJr-<*QrQ<6W?<X|)d55Fl?yR)Lc&xJ0vzWb!J z{Tc%OIm9JExe|5MG6RCLjtlwF{)ya-v%#Wx+q<oxPs~rD!Y^HDRd{Gqsv|glrw<+= zBoz|WchAGg!e>6gNY?=~Wue{)oAZ*k><7?L$3H{8Ba^<D0z4s-bpeTz1<j6?cwUWq z9*O$4{4auEBOZtWn1h_9t#5?X#H1}xz#}(l%YAtDP_OQy5dK)<8v?04zl0m8ai3Ow zPV(*R`I+|OHl<qX6|e7WFYa`!uf!|738}b~s=le+wQzHXRZZ6J>)_^2r5dN*g>ZA1 zTMg6h%i!jYwfbi^vj|Uzdp5)WuHBR1<}S2)UAsraEiLgGal_0CD*QRH4G!&{>MTHQ z^SE&e<`<A>K-r<2=Y|)eX5#ZvHB?+V2dO%H{&^_UiNyE{+X^ncanNqEeP5D$CG1Vr z@kHkeKfY^tWp!mk-D)>4Wv#Bo?WuluQ7!C1Ho9>QgbZBLR`#>4;9%MQmV(1AFp$Bc z-eeH>EV9}QWR%c4X)=$(4<(i+Q{qOGxdW)dLuOtxKSHB~(Ue!AwIx$81W<!Som&G* zj7PxD!{T)UnHTsXCRCyH{Oo8<_)<MTJL(8$w4XqvHXH<h7#sv|h;gb7)WB(Q3xQY8 z0Rm%y0P}-fhF8-%%-14m1Cg{>^-udBO#3>x7$hfF6%?fwA#y)RnA9!e{3RMXCUzOx zk9c1b90{XqIy~%#I6IOCX#|<@7|irWJ_3bo?c}xHr{MS6KkTyop1DWL_QfRN_f5g? z@XqwyW~j3Yl7ERH8Ror;gO__l1n#o_aDPg;e+6Id3m!)DzWVekLWf43o*;e@fv?dW z7Wk3=7#^674;B3T$v(SoQX=_$iq9zgFJ(SK<byOOj)u=oVYgx&I@V!az_WELTCff3 zIq)8{nt$0JRQPOwnhH>1TnMYw!_`RNyX|^R1NLJYaCistSH+(pD|;GnSY5~JhCzUC z)l`MXw-(a?Gv*YD$pV9;IaE+0nqe-4VH$9E1Zmdth`>Bd1tP6#QUulG_>3xb7E#>{ z^OPol9xjHM-_&RiY=Q%Aba)iBy&u~J|4n~rpQQoXB@t)@q-p2|Hzo~(Gi>^`M8H(` z2lH!!IS7Mx7^ZPrMYYr?pa)S+OTi=zI_3c!iVt<9vWNAdH^G=2jN2&Zb7W%pJfMDs zXn1#JB}0cDBFO=+^KDs0Pu#|ewN7+BKuBqy!K(NOnBaOT?K6))ufvB`_c4>~!{N9M z-}cBL3co+YPgXrG7?R@tXcz+Z2k^<cGWa~25XaK81M14ID2BNP+=5xW@qrLu{RQvN zo<D*kg_Uvb0b4q`-{dM?y6fxv?cRc;v*&h3{?M8+$=SXCA3T=4n(OstwdD}wacUms zi}d{#5zdWZ8UNWLt@#<h`D1#1^8vr+-IC^@j#_+p3dr03KFYjL2A5Q0aR!DRXAy@T z7lxhbEGHIb%M#T2_@pE>TaCfNSt%!Od$jC{^oP5Ya95lH_n|@y?i=WjCfpa;%LVSv zJzobm0h{hB@f5hFHr!1SxQ#a4@_}$c0~k8W$yR;n9c?*N)KT`5oY|&GIernCtzZ;~ zlB(S>3F0XVe#{6QCUUAQQF|O?RjI!MzPbmoL}m^%0^*tLkmgy{xTMFkusAhh^W3B@ z+fWsu-h`y@?PUF=Z+#~Z9Q2B2$0YN)0B=4s%_kG@Y&@afGdGV8YzV2uz}k>X2vmn} z38~aTNk~-(#)s=#J<e@8P6&0CSl6w@NojoIYtRn}-Yq!^b_DH2Iv3Kp26)41gKoo# z*Ak~X6ZC>N%651MCsAr5Zcd|kkLxkTeaBy=Qo9sZNzhhwT%LoqW7H!?(<axM!Ko0b zpST`9doLHQ$FQ&C{T6bNRqXrF>}EZ;TxB7C%PatD<2taF@6X?se0k;KPtedMC)#~$ zEp{~>OAHKaI(BAoRH(zLPX|8$&L-)3{5Eg~61{>%f-$~p0qg3{t*->*aK^dmW>;Tu zn6WSeORc+^CO0F#G4A0QIsfeZG9#|RnK3$OdgNw|h<0vg`;x+{=ShcNlyDb5GJAuU zBA>_cIiG3`n3i}FGIJ7OrZRjE0`6r1brqrm;$hw{RvWY<+%gmJcPzkF0yt^w9#jLS z4pcEvOaI2{RnnG+#ZP$&mpTYROt?}qb5a5ek=w=e<<7nB%dS6xzSIw}eaFK$j=tRO z4_>1o1WS$M7#vp>pxzXUcO5=5mDu9Tf`5_tbGkFdE8A0DDjQxtG1WB}U(3}#Gz?4u zX}xdsqJrQ%4`YprMTHq7_MGiTLek@TuF#jmHYW#W<pt960+aFr?!3Tx;Y&k3@qzSE zk1KF~sHZM)et0tama{YIPy7QbGM!0J;}0g;@<<pRU9ngp{=b8Z6Xq7msY%~E3Cg#& zJXydKh;6Uo<%o%ma}JA77{RmE^5cP0DD6E|*z9oPnSf_Ho-90hc#82{jpsXfZpIVB zb0;2_2WtwhclgXp|4GjSfWor(^Sqs&phdK2c;kCnP9_Nl-Z4LJvOZR{W;rKwi>zOQ z{I|?_p1+zObKkjW50H4T%K5kF1k{Cw&&l-;UqTCPh*rWPR3$zV!efNoE&2lH%KyjO zn}AnUB>n$^gb*NbBLoQ$6%Z8#6~!G?lnDWqMIbEhE8;RE>b=T{$dY6vTyb}FM#ptV z9cSFoQDI!rXo5S63koU<YF~pIHEP6+`G3CE=bU>J!o2VAef~V0+;h6CtE;Q3tM_WK z=B*ntu>6IB>LF+L{&ae;C*J(_a2uO`i%rO0GBSTi=lFI*@)CWLHA}EBm(WW@2{<*+ z$Jcn!<pYE$+BpBgdY^5e&tFp9Ij=a+w$3+r+hF0{2>)?SzaZv2`BRSI!%z=Tn<x`) zv3-^lcUw}JH{gRqK45M_6Q@~q+Nj^0_}sqQ>FUCqES*m!O+wjbUDjhsao!=t*cuLC z)^#%IuQ+<*L2X^~{p70hPdYxM7I@9)&pDccoc24{$8OA)o=>*ON87!%k(j*V_PSft z@asBRJP%Nt_QXjnr$)NT^;V5r_XSewSl5AzfvY-dxSdy3nnRUo*%l|?UtA{3Q*AzD zmvsisGhbsM>le(!NpYb~EL;mFmQ<?UDO*^&>qJ<!E8|s%8fftM<yKhmS|e{XdEc43 zjrtdPnw*#CZU2t%$ObQ%_Y3zhQo-q?A0)($oFA!n9l%E`S>qZSd8u)y>ia!jHvh~^ zt|Z?v-kXCg({+&LdRR0h7OPmrZ>lp4Gu;@`E}l0cJDxM5L!vjXr@{I$9Ko~Jx{`+X zPs+I^wE=J+u_IIK84<NaYy-uu5sD9m;x7@3buA+*+CZ_r&um5nx$g3uTk1~qp|`XQ zEp45Du?H)Tz}9xnpG1`siatJWdK+<+x&)RX5Kd&HgjpktM+bU>+uLO0g1PxU6M4fw zidAT7gs-l#iotrjTyHFmD2z#zUjD5hR?*eR5|-`X2>Y4RGK1#2krmdtU<qsd?d?5Q z`C$<EE0Sy-_Z)HH?-tMHZ|6iIxpt0K{6nFa=XZ-$+}Sd|Goh@dCw*wXrP@BR6QO#) zJb(K{4_s7@ACjCr1jXe95*a2=0d;pA)R8nkh4)_e-YY(a_b&F{B|d`ph4#KMK6C;5 zDB|5!oWniIO1m&#WZ~QEJyD?8{ysK`Cg?D}NAyl`2ksEg^-Q18E~{?vh(6(W!D)Q= zC5!Sz50aNBx~jhnC=11fYPy1Ih+Jq6Xsva4y+P;KH7SzBr|Z0ani`pVPB=9pcX{$~ z_Sdr&VpAHb6YkHP6@$k+Bs=PBf&Ypnb0@Oc&HPA{`z?yD%3oOC*gbZ|#oYQ!M{?kl zg;}$CN~bQ&dScqbtUYEd%(~+^MmEROuAIRB;u9BUy})znNei>CC&!^Dv*+QIg;^(^ zwlM3((-&q<IEy{jXZpCah);I(z1F<>2gEAs5mtF)$JiB*p)F)~Eg2m~MqlyU%(Gn? z8)A44<QdCzJdb*;17j8KNKx*X`*<E4Ox%^(cV4WbfS1%6_Ei+CcuG0Ymz|J0mY}6& zzhEYQpy*kpIjNgjgYY54k(NUK5QV%6%*=KKT@(dv50C|&5(WJOC;^R+LcR?`MnoY8 zl5A~h&if~05q6D2r621{b3RmPK@{4B&~@kMeDvJ9`GhyJ{^05R9;|D-UW14~R_w=$ z{eakH?(mLGOLufHPodMaDmj&9fgHC#l`HjcqUDG&wM<y>K8=y9bsv#|_nnJV)-CYj zH3FE2nC@Pne<z25p)%xQR8tp+X~nj?476b>Iot$rYDSpDL|&3Rp*f=%jdYy9Z>-`q zlWT75ieq3pay=WFK8W%>$?wZN>v_K6X-`-ok7SC?U=kc*A;Y`9OqcPK>a?{ebvDs6 zW)Hj*4nhF0v2^7_W(OhvjzV$?nYlYa_eDWRhe0<+K^uPHzGZ;QqmW$zQpg2S$a#dU zJ>QG+_$YKLq3h50qAZC*M-nPgeqy5BGYTIh9FZtLF;T{d9loQjFSMJSA;=2Ep8Af} zD-&cYeA&QD#BVx=$HAc`3*Ls0u=*>0f{tOwJUL=X|LfAZKb3cf>5Kw-N_kG=N$@P; zxt-@<Jg@L<<oSiiv-HJ==H?&I&shvF&LnFem<PXtz==`dEkMrv>3l|tz#be0ug?q~ z5C#91V1NbNH41z<9oWdQ&u8{Mfomst#(x@xen{y037+w<MxnKYit#TQ;~$H{A0k|} z=OttLt%L_GzY5C`)t%iDPij7q#`259m*4UdS}r(#l5u=A+=SyN^Ro?(XLY_wrV@a^ z^VINc;%QIVPCUbTj^#OvXFiWF>$LCLYei)$%{ealGS0`u_ODs7^|99~Hug+r<eO1s zu|+-+Mw%2Jjbf)-?6WOmZ;WC$d<SBz2bm6g>!)uelsQpkUnTXCP^7pMqBzmJcD|R* z=qU6ELf6mtvKbnM4klEx`PO7p6ovO7T(bGrWRpd>vHvF)bVIIVOxB>v@cVICwTRZ| zEq?2Hy7E4lXDrW59?z%(l_!&p({fVxg3reurPvHM61gObeCJz5X0Vai^P<?8CCy+X zvE!rIKPhbn8;RT}ihMgADK-+<lQ=7CJ}((XRo9WC-brx|q>+7^-#2+a<JrO!BW!0L zUzlA$n_TtQSvjd1R;7K|*-_ZCDC|G=f}6Ppz`sO+BMs037e|3>3{rscD6E$OD(n=( zjOb~+WDxzhCweM`b)ZLZp$O!;m*;t&4|%@j@dVDcEKERaoOHZ%l+yziCF%H>dUhoH zM8kayqFLiiyWfeT=J+V&5=5<tqB>aAn)7o~_e5c1qp<4;v(i-Y5|$>18G>nJ;ya9q z4;d35p1O{bmAeiK;{JfS@rzOm2=O%C`%QCmKj=Ry!u?eca!?dfPRPvu0PPY5tqOy> zM?ohNBp{uo^SJL0LcV5%??bK)Le>*vRIlOX|3LM(4BYa_>xKyPfnZk1qA27wU}knA z==><CJ3tn6LKJi_Py#wC3i&DsIVcKQ7liCeh*7-*FaHOshl6J*d40q-R?m-xLCC97 zNH0QW?gP;BDCmSR=$<I(+pn6N1$09cav(qoSrmor5`@eq#Hc=tmyl{&f%B~uIED@{ zRrO4Mw$Tc7>HHua;u`^Yh-VegCp=qt3JBkoX9UkAo^yB>^Z2rjgGRO+Ps<tpeC)Q8 zEh!DDd`yy<*fUYYmyt5|QN$Bb#G6sX3`IN}MLZcrxXn2FEX|4ikqqvNLiYe%q008k zDD*r+*Pfj7@rK(3UU#u4W-6iU)1jyM(2<17)W0w2>wzBQ!v_gR)c=WM@lHxtw$IX% zEfeX^{xa5@WG05E<+ukCLtSSHppLDmzho^DOfY2G6@5&tW()IHV%Z2A5la(4+Z0O) zW0WDMF3cLub285yo@;sT<$0QC4Nr=v9dJAG_!2x`mln%kT8O2Am_RIwNQ<Rh5ne2c zNQ>opMR>6&A}y9<iI4!`T!vV#4?+c-7Rx(?24WGT1F<|yXdo7a24eX;p^;c5#6T?9 z3P($^D7K|o&KQ%?Q|g5vw<VUViAx>av4vO;x7u<kY(y;A^Ro@HFn!6e@mT=g=lPDO z3*Q5I4&*tC=M<icd9LE|BH8)Nv`B7+H}6F%dnz%3NEGo*6j7gwM52hlMG<=|g%^n; z(rkW)6cWjG@a6YD-)vwN1Yq4vA2f!bKo|m?=tK7<G!TYD5AmVJghs-+iSPkFJV!WM z3PZ75Y5ySVZtATLZLs+hSOc54@Uu-e_h3}M>luvVd1mlj$dlx`jpq@bTAmMie&F$R zJ>}ADzP$yTw-6JsSrKVAS1H14z9Q0WUZn`nW<{jgJdFtPR3#4Bd}|N{V94fA2nyIN zz<|xK5E`&qp#hu!MQFrku|Ht*UxcG2n-#kio1a4*sdJeg3yqA;UGzbpZSJC;7kE7m zb{@cF#{>M<@@(MwnWy_qoKN!{#uLn4T%)9#yZ8pJWA5TW`)1s$;d1H@`(o~5GqKEF z#42(WT*V(RhW)=ti{VCicTp5`5ix-n6rq8kPtslyUJQyjB8oUd5nc?67!*aU{@jZ} zq1~g<?tn`;3T=w2%oIWcVJKo_6fvBLKpu*CIf@uSL?jYLJrqTC6tb355x`Xuz*T9= z>gL+ahGr*n5T;I8FgwxijbEEZA+x6?4K$zbve*3F23`m~JKiG?oAr42^#F8VYkvj= z?a$m%8HVmOFw^Gj*KRQ=x6uyW225&<cHv}BZ$&ENU?3_o8}&GrIk46Ie#w(Pi*so_ z`|}*lb1KjON=0r4AIr3@Rb*jWPM@V!<OaBRZWJ?-m_S7oF)51pcvGYzia0om*ik9G ziYTIA6!8Elqznqx#JcD0HyNP~k<j)5NuVMEUl&Cb5fP|}A~c)l@ic=cQV~Vn8%1p* zs+Ece;13bNxoH~eE{as-6S4|a<fB)SJ8A050u`C@N-Gt4%z&8~do%=X*%nTx4n?yD zhoh3)QjK!O4V9-WW|wzNjvhikr<aOY>(1NAY}~jlOxwBLTVWU$xHL`ukwT@Wz3{6! zUtT?KLDp+1P~n6HS)cQJ!}tYR&HOGnW<gdTW(U<hIw$LqU2q=FeD3m(*hA3pB3no< zZ5eTgBGxJ5R7J3oIq{KQeVR%|tyI+LC@SWo&Qa9g6gAl0#*bEK68*@on~y(=cs$eU zA}ZGJxEGZ5yNP(O3VgFJf<A3=qLO5}EvvM><zb3dSC_ssQF~If2B9@+_B=24_msk@ z<~u;`lC>-H&toaNKe9@6e7IfeP?YY+oPq7)BeZun*bO~Y@A4~t^YB?YY=REIa2?C$ zlh0lb(zYY5?X6f1hW7D9a&)wx`fR-$2G$sJxaly*O?^g-)w?oV)=%HVXB8w4P1bVL zVNP;Vp}R&%_k^H-Lcik4OPTix-hI~Rgjq{ZE$f@eIwyW`a`eEE_&xO=5#KxdVs{h7 z4-y6~DU@3BH6+hd^1_Vdg<<kM<`aoAWIlQ7r675pPd;pAun(KHkmg*7np85m?3gK9 zL!HJ_+sXOb7S+>li>h@;--Y-)!w0rJeJz<hZA*F4xj5Ui$=bvQ&c!9)Py5#0VRpDM z!I>0)>aCsH*zdJ#)AnNCc%*Il(war%`O%t%Kg?q1*mjp;4ZmqNd+^=XIkuMP)(Tsl zYa`F#9NRA1_Srxc89seTq8l2_dWkB`;&l}9d(K9tJ|hRVVJ<%i;&r_3%UaBXQBXG_ zq9i-MEkuV4(fvYnD~RmWTfbStrK3LCaN2dH0z`;9#Q$OEb+$s+#nV;)0qBkwx^bDD z*mnNUD#0E~P^<+0wA<zMC;TqQg;G;r`hw)Bf!qrkl%HhA8u#^cq}@OjVb7d<b0ns& zQ3st$gB^~WpHyMoY!oWJ!*R2_Oog%?j<?a<w;hfF<Y<Fb>A{)ht~bCSZV%#GA9UJ} z-Hp3s2&khc@Qe3D0>_C!4JkYmQ(tLUqgN5mKgB9;B^%Gv3@iaV?~Jf?6c(*dMxxj@ zPtPTldv_%Xw2~a~bdNe-wd--Ww)lBal+kTUcTJR$-}bo4Z+o;I<#&q5^iDRgqtX@2 z-0@oDe#g@4($W3cY3qKf{<XPgbbe1Z%W!=KN13azQrshZw=NpM%;80NlUsBcXtW)% zn5D+2|3XxPd-ehg+)U+?JWE!{_zrs(<D0(sXP{~41~-yykdr%z-|AF10kOTZ!LJcl zqs;u13@_ucHOW_lHOW_5lhl#e6P;>*6L)X0D!JwNVdb|oudKK4!_~R3=uk(Edyyq+ zP8lA{D#eKXW0iT4G!fk1@j~il5n``#-@b>`n^U_3mmw#`tKQbQH+_63#iQyq?uHcG z8G`$?05kQjarb+$Pc>VhJ>K~v7P1GRJ2bUR%=L(|NOK0F*hw}7SCzcIwCq)w>6YFm zaq#-K`$#*5OWrPDiAdNtObz3!W@LUZev*@E``Bd4OM(1&R=X*f%w*ZyRY&4+_HATX zH4!1bt%Dx}ZY5^k+o>{$30lw^*U1xj1YvN1t=@Y@92uq^?RH3@zA%%t?+|f7+Nc(! zy@Y0a(iXN!+VVRi(mX}i+`>f>I$GR&_(?+&T_fhk-!<m{lfgXKRmv7F1GRC+xr==E zOS<M?ifYxkQ7jR%#N1aX@Q&;zKGNAFw6{lcmSzOT!3k~ey58|IvY={CPN`?UG^A5} z(1;Fc61sZ%zvJbv)K<k)lTkwdI)Tzv%^4zIb|PNqgL`0LeI(`S9ILz{;^HGa+P0CB zAF_1FyCXXF4$WS&Aolnqj`ZhVGMzL0g%>T%I+JH8&mlacc#h#I<2jK>=l^r6$~M&f zCiaYf86JDWzw8@(*1y;WCP4bDBgAiS_YtCv<lNtvX9jt@7m0w(9ZlW+g&^&H^dTb6 ziu;H^YIGI7>45AVTaaA>*{?uar})CGFZlh6=X;)?d76202#-BJC#P=z*fadyJN5*B zcaJ^G-<^~E*-?LbyF)T*ocFfz{9jBixc)>8p0}ZtlTmpKRsVOoT$NAVz8W{h16~Or z<>+GN=xs5F_?QbdKVjvllPlAb4drjB#CxZu>}z=!4?ZdaPrhPkZo*20l{wVSphmA< zV?-8^g!=}w5|@{AhT!+MpS>_EKHIu}`D3`a_RNu0C97*oG#ug7LW64HWq%UdwaJpT zbj<S;!+A-L95TG5F)?&$$*U9XGjF*poo}-4unP6+iXt@K-HthDH`lzisT-IUXfA1J z9=AGi54p#64$cnujM+~0RQR#vRTGC+&Ec%VT1>_Eb=w1D2Z9DhFofp^)@G+a2UU8l zn@v240&DXl9WJ2@%nUDqnfc0U;aW2@<mS!HS{3r&H-QT(zotsS^ZjC#PedIEh_IV# zYX2xkY$7^4-e1kbudM90v;ni<GCto27JBg5Soa{bG$))6^ACg}SO(v%Ie_-U3tJb= zjk!^%>1b(pzT}__gjd_<P4d|y;zs5VFKI{|qCH-lxPMV0d5p~6p&&}^?Cl6Wl)#RB z@g@KO9uJAs-d+$?D%L+J+tD#T6x-21BwdX?_um95cK0dNuk-Y!x<oc4P_(^%HjOBs zw>C@0Ym@t-!E$*-Y09{6$L)uTB2!qE<5{%^h%i5OQEFTX`9aydD4)8sXiYg3;+_<v z+@WYry36F;STT&|_D~6T)e&N(bk1EsI1-XqS@+vzI>fY|!w|Z|@Qnf~1z&5`+LUpx z;U>2RMn_qEKvMcsiy?DRta2cN@+AhH9ZQ=TGtCUt?P2j;joVt+j)=6nUGZ;GCXK}h zdmCDJ2@QsbP~#TL_lQjS_A$kRzP0X+ZeXS^tj8eIF6IYC!1{9zfHFP$$gj;N$QM<b zzwsr8qrh8kAQKdLPna?yJ61`B@Xb&^H`wTNZsT>PWHK#{=^8&aq6940m>#~ZhHzw# z^o_11uPB;xZ$E{i^$c{Drm)71N87<wmunO~ZMSmnG)!`iRsKx|MEaO-(w_DP(>~V{ zCi4@&5Dwc}z+<{*a(Fy^2snH@5or$ZLO;xNSU+3W>z-x_+N#$ZuQ#^T^-j)ftSdCy zGMen?UPlMRPG38#p0B!D%hj(7s_9%ls#E*?i_YCfyUNVpZ!OJ}eb;aQjQ6Oor@O4R z|IC^1lSXy(8rid|p5Dcmg*`o3IN@58NwQ|eH3Ylah$_+X(RQgX!JKh$`Rw4}a?Z_M z$|-~K&4b}E8%tDA??A#jR2Rn8Yn(kuc=iI%UBV*(E)6k(_71-|cI?`P+06ya540tp zSVcKy3VO%EWWm9~XD~`OTsyT4%Ln5_NXiPZdx){tfQsA$!=%|{l6BcxJ_vtCS1J&c z@4Ab_g!N=?q<m0!c(ODa?+?>^X6D5i0m^y*5P>F04Z&;J6O9K3KZ*3lAySOX<|pqE zpEsyVL?_NRyUnIx4m4jQ@I(&RFq|6!KWf0ykSt4|A)=f3z=YhDERCiXhUz__G*4pb zoe>~PlVKKqc42kK`RjQQC*8v+X1V6arF;Lvrq$JjC!5%ND!rpu6U{+{dKl>5u$PY2 zKlD#ZXQ#!#m>+7K%~Y{vQYUFf4Y324-GdHnwR`jx>gcDk$3Tqi$6enI{!IBE|FO<$ zFAEQvm}*xc@J9pii36D)T%NT6-nu6^GxB5k++(uhC05&aNsh8(?Gr71A$Q6LdNU?J z`}Jiw(`lZ3OkJOIIC(<07CmYpKH9Ti$8so6;SikC!Q)KI!>)I=`}t*Rc`Kq5?9rr$ z-HPZpfK2_0ZZ;<xNTDN?A{yd-vwS<mkN*FkcCv!m9by$Dke2`G7#HW&_Ex)tMb#`- zRbSNP(L*f!#czSu9`Q3ctR(L$u?l8@vQpaqNB;tSZg|poUVuua^|`?nqw-PY_xf0+ zB9b=CjpWlhfyZHm<?PoT@DBhul4bpg<&SC5LIYawp1FqXd988rF4R*KPZeWqy)dXQ z=EeP)cBg9eK>2FH)xbb^;Z;oH9uH=@R(9*}_n7n5Q#m<}`HTqjb)9GdNE{$9YJvPv zL*6e?mv>!HkVnN*87o)DuI5mEz|x#}43?^UQSClo1s#Sht?RLh0cbLHAnk|cYpRB7 zHvOY4ch#e+aKCv-6)u`<t<J1p)T**%N{8|(p=LSV76#+VwM$2hWY+O=(&G)G+C5F7 zG|w=yuxivn_Cou;A204)+M}vbBXo4F$c<hK<<)lLW@+Fvt08DN8ZxE^-dz}0Ur_Iu zv^JN+M)d@{!)ck!-tH*v(R@ZBW_9;4R5Jxjx;6r7<GI&Zn59mrf%#gMN$^Fk2cu{2 z&Tcokv$H@-Q%_eyc5IFN0Kr)%Ix>eBJ9;WMaWXq!KJX3>6BUzaf{LV;rZK@?F$VRX zJH!I>z;ul;$+}($8h;#gh#RbEbEkJ4s91!sghRmAn;6*@h7Q5tqMVWu;yUu1%u+V2 zL}db;rU-h{YuvyvuUzu_dxnwy5OxU1e0opSsj>$Ucls6*->zrcSN5A}{zlh!d*6J4 z502dONGw6E4J>Ln-%{;Pt)YLhF7*Hy<iC&o^ppCzTh(bB*JKAi^3Yub!WB48zUN-; z_Ovv0m#HG4x-0sTjl2n*sbtKt>`(<y${O6APs6pc21V^l6Tz=0T6W`=HczTH@JaxT zq?|;qP~i>4o1yr2RFj@oO`d&G6yiV4=axDMZO?F1)YUQ%Y~%S4i(k9^GqXLa_WY87 zR8RQvb6uhDH~K%`{acfc&Z+w|y&{us*bxZFj!eQLXawZ#KuJB7(tSitET4NuR=fw| znn(z@qctw2heNAy#){b>qOEktKo-9kDz`g4QuBEkQLfm3u;49+QWriYc5RyOIt0O{ zWcluErDi^GQW*c4M`y{ffro_QuVscex&dMMzcRxcT<0+SFNACUrrHhPB==~+)Z)oT z^(Jp{cA$XOsWlkMy1K3A4MU#FXzOWlu7L@}hUCxbwS#*qL#~QH=)|IbQ(jhavHDLD z=O&4qlZ(pdaw?+_jo++Qgw9&aAAy+pyIUZfKi;EVmWH5%M^;r2`%&$r`KS4W9$oY7 zyp~C3lY~`{4}@@&aQVzTkU2gIBFtljxzrY(SSZ<@g^~bmvD*=KZl0ar5^e7Qtq|0U z`iU?KWtaYc^=Sq-A29lZrLs4u$<?XKzh`h$Iw{_%Kc#o8*JoaoI4|zML*6P*Fj+7{ z?+VvH+52OYTdHyfihOVHMvOL}H>Jhyw8ik4L2hAIVrLGM`qcp~f^GLa5tECxv^TjQ zOMA)5MJ)D}j8D`qm_H~hu_wKG9lehaoVEB5Oq6L+LCHRNj%3sJQ?h9zlx*5TB=g>G zwx+*@O|psPdHJefyDtt^fn~to@ZtKvJ+t4Xl#2n}doC{w*<T@WH8u!iZ>RhB4o>$s zxo>v!4ZwTueMTFGAQy0qkBrVs70nX;+h%wQT#d{Eb(C`vWsOfxQMPj>^{A8G=&q0u zsp9Xsst}(x!bb2%8$9@YKjmhVd4Owg;^=4JZr)kt*=Rmz0yTNh@C20_D58D9yY7`g zz(%-N>-sAnH8;mX>Bj~z#66|x$dLgS#fQ@|zn>Vg&uDH6jpRm1ei!93RJovfIioch zN>Qb!QXh8=J*nzc`+GA@B<|bNx)-b)hB_9F7p>jLj|*Nhg9U;2(qg3P@WniIl%Eo6 za$i(hH=z0A{8{xPKy{;0z7<9ea#uV7`a}aBVtu`S1<{lqov4Xy&_|wRcR7ZqIyL1U zsI8C8Po)2BJPq{!JLx}HK;OSJ3ehOPPosiE`Z?}4g^kQ9pEDvWzPq|LIWDQ7S#%uq zak)NLVM1~SHkXayAeqh_=W?Qd<-_f~W}97mD(Lq-6|Id_ae*p_D6P$S`r1&XZH_^H zeRR`@n*nmQALg#-?YFYBz^{w#+?98*1jOx>sZTT&Zmpg<5B<@0M*i3iZJ|N5`zwP+ zyH7L>`sXv~2RO!nBXy_J&mF=Dj#UmkdsUUZ%EX-J_NEPVZ((X^m6Fr?xmsRpOXzcw z){l0upi`MzSy@~10*pk<Um(KmO|4-jpw{hmdpLj}q~RfrR~+5p?#%hv1@6u?=yrm} zoWD?2vZ^kxx#WfBaVr!5lIxHqU01^sb<V5ZPaj(+g4v};cRgs6G?X?CSnW2@Nl1OD zIdI>;!#G<=K4zd8w|>}5WwWj~-tKcoRe#SXR#R?6m(v5SPW}KM{7O|4v0&bh?Gl}8 zOE$<x)^)InYEmwlSiE4%&Ixw?th2Or0~TyK!9Lqr-=oKZEr;4?d;4UG8MuJ=y&~QZ zg<f~dUtzrN7uC9m2xlxhHHmX0rtqp=2WGkHGHLLU92pHpf1=rSrzzn#nieNcBT~0~ zJ*9I~5sr=N`gqx73`FI$#|D|rcq#HcveT&P;%CRx<Xx*=n(ii-D&^7^c{8^dc}k-d zooaWY(yUUNGR?kgSp46~V73@aG%^+O>dsi}+<`&_6!POolT%II^wH6%^rOi-T3<I+ zIc}s65vB=-loxJ9r8K16?jKtE+f+VpQ&!?Ex0}Ep6F8HMod-~78<&<mg)Mha8VeuN zKrXW7&iz}|ls$zaf7lP#Z6)hi@n%M{3Qu@plFKZK=$EFrmn=nq?iAuM=hs1;cha*P z%h=+XAH40Z65MbXB=t|1AoWKEZ$W8H38#BLWEQ=C1qqK=LI=}Y75$P=gQ9PLf4b<M z-4KB<7r5q%H>uq<{$>(%v+!mM@R~GUxk1`V?WciHj#X;+Uzn$b^|mtgH9aU3ij{YQ zVjL)7OE4T*`Zw#dPLu<jQ!&MyNKdu5)<hwb?`tLXOsd)o<!^;@i)yS_-}1R*vJz=l zezY8zv4VM5FjCo|CN)nUV-8ydJJ3j6CfFSWdq1$)3Ue1&@C)hi`Iqwu4ul%r1&lPS zE|=3n%vr_du=G8a*xjXi(;4=cSRCL+ZTF7M=V_iU6m&}LhLxR5n83ITWvKko7?WqY zj!>@m3VJ`FbwVC5jJ_<MvzbMX3HVY0cl4;OqN+rU3fzf0t5R=ts_m)S0jJcX^KkO@ zcGc*El9+Cs$ds(sJEnvI_&myDL>C4`_Y>v^5F<ABBx97&=C(w8K4=33BZQze_7On~ zfYCPOPuN;-VuYF-_Y4L)b+i;^YLV*Ncr=Jst1m(rWbD}UNlj4zd4nMP14$7A9V<&* znl?<CY-yy)cc&|XrcVRz)s16cPcI{3Q=P0*VuU+fFs}kLVrmf8pE)L?`n!ROdW0xQ z@shbqSi36t&mODlYX8LFldmVsR>7BZzK7jYiy2)V^b>DK&p~B$yN`RWw+u*4X(6m% zRaKg=4KD9VH}0?|x*KNW%bR~~c8}af*W(Dj*7IeACRr!4m#Oz=>0<V%&+=zAckpYO zAZh6C=eIg_^It%KZ@OS`^@179r`+Gr;mB}4$wzhScY@r=_3cqdCq|jnUc+JAqd^bE z+`F*QGN&k6npe3p-fnz3%a{4=UwhYmQcRgf7LeTh-A_x(^`x}pjGJi5b!my5wiKoM zNVe5(yh3#ii9(B0+L%n}K?*%#Z$kU5m~uTOs&U(`A_hnCZUIXssr6!XwJQ*uE@Vk` zrg9~@-PFQY=nfC}6OpulmfJslxH+Er*oW^-`eQoEJNxBD$?rjYI3LN?NAY&3-bUu& zw7J?n@JF&RzchG6FJ%9myM8XbA6Za$Jh4|R);!VVE0*)n%v2z%>J@TY<KjN69*V={ zkHr6Hka$NDPf}uC1%r3Zql?Vp1RD|M!c1rMt07r@=M-Dk6mF!^Wr#<}moeXxf#<8d zRD6y8(OHrMi;a3+JN)B#PUSl5LIz%W!g({D_Yd!>*Zs5%Y1ZD&KoP%v_|oWWBih)N z?Xem3$?EZ2-EI_E6YyjB+Ica{Vm2S;b8@ocpAmDs#az~ty0AOd5_C5{rnREf773Cy z*gUryNjJ|fu(bODew<brE#`5H$+wt3idj6-d~@WvTZxgwG_Hmf9+m88##G3}`wl9G zb5zE0WZTDQyCc~KJb1%HvX)a-s@`>tdpZosuPSAFjgWtYAsiMigj};Uinz`q=)X3U z&uhqv@6ABWmh)+M8p`Jk$x4)3`f~*~1`i~Rike(cT3mzL!y?DGh-_@q0Z!pQfN+&Q zb(6F)Ks?2w`nE{&B1sJ2ffo5|hs@0GBa)2;4D*K{IV3&-76jX6`#x%%Um)bluC_(8 z3zTeCFgfrP1XDFMvmPY=Xqgh%jUL4sWqqu&BYKGQq#AcANX87V)hq{{d1>2hLQMWj z9SHpnpE^&86YrZNDDMCy)H|E!vT@ru?`J|I@SkrAhby+;Vp}@GA<I46tLII7#SD9s z>sMn2ksH-FyS3M2XcMS~mgx6kv(+A~wvOBE)!@DF)T;iHDkI)DAgI9zHe>$s2xS7n zO+v6A0KwLSVVFEdrrL=#h*$O=-Mo;7i}6I0t6pP_+QF7+)lntv(E!f`;n^&18|7rz zHLmP>d9W)3ut5TQF#^+GHJhL*cpq}K)6YuPUQo9KrB->f%*;?Ypx+aE`gx|Kkie$e z5;i%JBNJvsjU~zkl_Rs_I|pI=D{Ky$$tJtaZa00Yc`a#bo;I?%#5IrGlz2`t*Ivhl zYwbHIfaG8|<ogd}eRlB05qG&j<UAB%1YT0k;J3w!Ko(4bfqp!H*)3{2_Ql#|t_W}| zEVRmTQF3kh-04~Iu1WeU?B-@(a=QG5p@LnL;|t_6sM>AjP>lH+nmUcCq|kTT%%!wr zYnOFG@$S9{hN(+F6>Uqtjj?@zq2Ri?IkzOMkMr#fV`N*=V<rGWeT_7wXRkwQbURGO z4xE!{Rt5LvMc`uq9kh<`Sjn2)6@ONtPQ=s%^WM0n_4=$llHXPNTownpEc#PME|`lZ zw*szYc2k?&KY>-u9g4xd+vW7Ln%s4KVP1FUeZgf#&AYJ@%G-#d-4X>%ha17n(?3kw zqnX5+|EiX+o7`oP7tvfr=5k2A=1-#e?>CBOSOUfJ0~O85i{wOJd5!tLz3<Oyf*akR zNSV41d5!2DyP+EQGBb3-fZ2*7O`4SUb2+p{sIKO;Qe<6+e<2IsEK}jb-y~d@b^C== zz0jlWo!DP<RV&HOJ*<Sg3fm;5VuGN-4OJqa{@Tp+IFsUH@(>48@yXmrIt+Wu?f0Nf z#qUDgoFPj}i=nq-4782F=kiF=NEzvW_oh4<GxQIUeKh^_nstiGZ-AI+#W-5O+6^Aq zT#Naa4(?c&8eMQp$S=-#G&%;+%`<3(G|M*AJDFO(L}FF9>sfLilh|!pcggq5yH!@b zy>KgaS1Nq{Ln5?sN!H>~Idy~Zd_`n+1ooE@>^#8C(N&`x3(b+Z=Rk^R*hG!1POZRp zgevNFRQkCkxz<y)v#6@aDAl^c3&^%{SuPZm`P{1AP@h?iYlg8^m**sFqPip(h8Sd9 zqCEI2Up8hFS+4SHcJ$1nPgd@jSqVPfKP~~+sD5Nx?cT#iR$WwJk$<Ik?Qot>L zeeU4@z!vyssoBz6?S9c<O5c`XP1TXCj2COqSJjc25B!LkUPGT!O(em1BtL_Grlncd z#eJX+Odi4HL2kBo%+x4Z;J3^msiewrSywkk`)ZMpKHW~YFbu!V@M#ZCfJJkL#qK7k zuA(zzBp5EU1zXG(<RvFIdK|1<xhyt_`9ejZZ@4=3+w1Y`h%fe7<s2Fz-gRfj=qu?9 z%IUVbnd(W85P$3n)Af4s-53eV1!cbssLOGswY~JFO9*C1SSEX%dw}!1WQbFj&}`C| z+<+VIclBks_XhXA;C>+ky2d>oL0ca8hTxXRH&hYmRvuSnq^foc^d;BgmdAx*qIj6c zDH+f;Zc+qod5j9dEsrF5sC0WORCfd>c7o8pc(m$Cdruu7<28x}LbuBXrr1t|V_6Y! zG4vJT1gmGFdvZbuxyJqSF_6RP=<H2=AL4r@=(VrVP{Y-dm=;OLVPtJg85qK?afi^c z^2Ri>3so#k`qgb+8|aEjnp|5ox3KD>s1g)G*sSvz8J<i1^GAL921rLL?ik`&R#rE4 zR8d`vWcyeY%9!tCNyZeDt}U4GyR57kba0qX97RQNuYlVx!OsY6z4^amQrITQxoX99 z5<E@Gae3}Mx<{syz8n1xsj*<Ysk8!7XVATUpH!Tw)+Q~mX!B<tYqL6vXzbLY_;5bt zgRC>#-Mhsq|6roZXH|pou*+k>BD>g;RNVnI)Qv=xUPtC7`4ce;3=6(01kA@RYv%_0 zxE91d`z`QXlqS*|-2(x{NTIqTKt+!3JRyRpdr*9Hj0RDCVwLYe6s_0+YNbXEaos!F z{K1JWikiB&t)iZ&uAxs=K=)}Y20hwls@+J1J=1NpZaF7FurM|5O1;QLRpG6$l`J+e zTf%O|no;@qPlqcnsh8H^{zTV&2E7sO{p`R6X2af+7;4-ni)o*qSE0&dl{fS2Nt9Q& zqOC|QXp_VWQiUXLACjm|GTS2Y(6&kZk)cFL;%VRsNjwY^>jt#o@D=pgwo)cpPd_}c z`lK}-+k>@WZc&%mqO)x(v%u|lMPQ*4?1Mx9sgIE%J-X1{`3+U8k@+ZZ^_ltR#=Z&p z$!U4X(j51_NQ5l~aPD3ZX@HUH$y_<**NEGF%9edCFxZ~w!m8OtRU{u(=$`q*f62AL z4OXs;TI5=o&UIc!uKR?!-p+J(nCp2_t~%9dxmx>@E?9wE^|cNDkn&ZiRO@2jPi!k* z6u27+q)lc^$Z^S`%~ShP@J?3ZoqgVBqvlYupn+_{1F8_y*zJ1*jq~WDP%WDAgjU5N zztP3EZ%KZc@wbe-W$%2M^MCG1K;Rt5g&18=K&{hqarqFUxoyC%4ZsT90Q>AK14G^g zi9N|$vqEldCG=@B%+7gbU`@X69<u~RxH<ln{LB{Cx=UtyTS#u0g!jqME8^(F6)+Ba z9);ApyM>(T*N-a@Z!qP;gwgCmS4E6^C&>Q!Ffvy8rA=QK3SgE26xwxj%A9UC*$v1u zD;FPc^kh<tZgzlNd5SJ@zc2zq596HXYOTTr?jyV{2&~Y(?ZE=6{Z^SvJdMlp-FEEl zkte(&yQBoqhJh!ibN{w5E6MX`p1<=v$y3YoE>8o`XFMJW)V|6dmpWA=;cVxg*5~x# zv%PyzpJRj1Y<Igp4+%ayxNGz|IQYzQ3-#$+D>{<yLVYrVHOw8|>3s5GHoggm1itjU zDu@Ln81f_Agv1cG^7x=ax6ua$g`aIr25biSTEz%ZJgSI3=oMUIAAodY=CP$fpClv@ z=(mf4$XI1hp{2=0pf?#nVM?=HhTH^tEXF|=!&jUyRrMy*Z)kEu{$>-uY}4|JN2dQd zJrnkspqh?sS}^AbrmS8<`2bdvJGt2XfD0D6xqg&Tq&T8u;#iApT$bndXOo)$uqEky zw^*ZH--lE)x7^2zbrAAzHLNYbX9&E$?&J}95z>xs!;)4=hqXj{Mhm1fw?dlZk#-)& z?$kQ2uCpBjElm!++X0N$z3vuaW73S%#CTA?cCHLkmP{`4->%dX7U;%T`IanG5kBxi zy1f$DJm-+i1fNu};V=frNBVa$_h$CGqD*@Y|B241=^%{MjjS<7E7`S1wI4#@pmZ?( z<iRz^Rngp9Eq40~u_iUrn;66SD#m`+Bn6<zVjr3%6;s`sJ<*&cqY8(#yRb*B;zmj= zx4@tBo63<+(NjZ78W>XmuRfm{EP`G<HH{+`Xia4LUvaNH@zl!E<eq-qipIGSt6DLa z#}1&VruB3`FE%j;x^X+Z5TGtrSq@q#ObWZF<GiiuI5dNfQv*6M3<d75Es)9qmmy{2 zqmUjT(2I(2w>zSHq9+cIb<x*ETG$J|qqSv&fiCcC(nbRXLw8iRagFX<dC0)n6}T_p z5op`6iGaQA!5G`F^k9j;cB#zplBQV2zf8Fr-8=JxxeCu5q*Hf==Z5;0jqcjcK8MK2 z6u8TMP@*uz7C%>zNifx&Dtbj(e*qCpX7PSj2v`VI*Ha8%BHt3bsY*1&5)rwXQ=(xa zCe$0<fkgYrCijLSxju&;k2>g+>1kEF<1WW6*^)vBOcLuP)vi=Q=I0)F`-Rk~tW!qT z?N7vBim(NSE*O%mQwEPJ9E16-c0Cng-tIF}WOEf-;G5g~_O)3msW`2y)=AujBnvD| zlbdn7Z?0MUU_Fe@Y_Th~HIa$N21=?q<h==J{!ls?iBp!%4fq^}mo;e$+WOQ65R4$M zyA`y|77M}Gj1@JGDXXtK(oemww-D{2t~%0B&%bOTj5P?+8p@CJf)3lm5Mx;G17d~I zKLGmCouL+dttBkL_l0};4th=UAJGW}{{lhX#mQ*}$w@hGBoiGRoUC=X6B>-`R0JFB zd~u6SYi8Ar8Pz<lfq8F+{b6VA**bDB%d0w)jWc=4NexLRb4bX5h`~`_6^mbGd3Ifl zg?gB(_FLN$+_0;E3sZHEQbUscIF}(i>xJ~OfCY03XgAKF6Tn1R^T^`V480oYUIMk@ z?}fG*y(lPwCw~y+Q!)1dJQVP?Bv3c6$<6%>B5Ks8abdzR(i02Iw((0X?Nd=3{e?Fa z&UZ)!%b2eq^)Bt9C*dD+Awg3GvC3-@NE>9_`DY{JZcC!7-{elBCm8k2E&nleIYkHi z20T4EZX6>#+0<?*N;~MLC?|s>B=WHTk;r`_B6CHghVik=voIWO5ZUx6Bl1@&7X-4r z(ks!U41OoOyVv}HCiQ6)SD-ltY02`(9@7zBx9cCI(^vyvy!rI-g5r5Nx<c94FgBQ} z2yX&W6%rm>o@tqWQe)}Wh<@1qK8|ci{=(G&YPc&MbI(|ml;y9RA$WBVd~cYdaap$e zaZ!Z2#{DG&a|gH1M}c|8Y6{>wUIl1~<g_%B9QTMpHoAqE+WA0T`QgU#ZU?Arrq5SY z)<bICP$c4&q8n71!Fb*qjLq5+U$1*zO}Ov5AE-UsXbL|6M8s(Ra(yshk^*FrDGG3s zhJP?xbI18zb#7ApShl^(gV3=3gRehxaF{stCTiRrzHyE^6QEuiwAVuYx8ED;Y(uTK zztJ6_XqKxs$0~nAoi{8eamqi`z30F9pDM_|td}kcEt!Mv*~<2LqDbd~I*IJC`Ex&P zKr@bEZ$YFostE78YuOGU{a2r2Cg{S<Oa8~q4~jDHs?2Qx{i3!rpQFs*pu5&8^92m< z!^&3y5@^t&rjUl`KL4K>@EFi0ZNJ>U7#vvUGmQ#g!;9Rst@B+u9nJ@pKHukiPDZ|C z|HphsMETlseu3p1tJozBb{E4w+A{O%;<fb*LdqN4v3M)O(4OOs!}U77^XkPga0+T4 ztNhgZLiNenc^ot}<d0rrg^Hm>{Q|5{`wmkZV(#`aoc;@EM?9ycw%y#Z^Sz$Zhp%ys zqz$S+L>ypI(x6Q!LR3Agqu>YNg;g^4j;U3)N+#8L&;8lhWCiG=0@zhOlcaT)>$=M` zYR95<uFKlHm5QRzmYL;5%d*~Vvzed62}s?c=GP1!VNJ_Axc&?sTm`+<z`{)o4oR}y z^5s-7Rc3M<-TqKS7JKo7R$b}Qc*2g%B#inNvIBFrn<s4Tj~Tpp!oV9{b!OmQLE!5N zJLF3h{`}W;vz@oeE3Pa%#Q0{-x6{693(p8v`~4LK5E0#>+v>hvMwwZYOQzTj(Z`gG zFP$>R)-$;c#@!f)>(++%PiCtDkM~YyH;*Y!W|z+?&SEbpQ>fW)FeKWAP|;d}HtW{Y z5vXyKBMdnEz-){zT2jV+jm^@ZwJDut2(@reuxJcv{oh~d%G^L1@!X(sHEczd>Mk>( z-l{c+(9F-BhYXif0*qU&JDVh$@N(-f3f0B#+eKa4yMOxRCuSxeL2}KeSr%?DzUt2R zAINI1PcS4iK^G+`&2zmn1Ahdt?m$X=rm|HRF0q^4?xOLuRHB{RTezkc1R1@r1i7rK z=`zXc^ctqEvot0<u29F>^@Vrh$ib@g)<#6eRz8<h`*$RYCZunyvd}Dpbl9&Z=Eo|7 z*;<<zI~mHf{L3`F(ZKAOmZ0W*V%o1J^vNg5@&)w(qBSl9DFXz1X>-0WZba=y74m8Q z)XqXm^|YGP*?pn$i5E<hdu9Q%Qy*RrI^6Db)PlHyu}#+<I1M;@NTV6W=D0HT<(T>? z5$@SJViMgn&nat~*=$VOi4W(vnd4NIw4DHy?y(E0c`K_rrr2PnX%Ckz4C=l#36H0$ zz#W@O)gY+Sr2mmZa1jWqc1nGK_D~{Y(?JB;M6ql^f$N!>cJq7{z6JXZ-Vm{Gt=Lzo zo%k);w>=;s`~L803--NoK@0ZX2k#^H%_lQ=8!G@?v#+r%lYQIMCsg5cg*$_N9o-F} zuiD8g7xk^V7v=0fe!`ToqsNXqV#?SF<AaO2sry;~Exwd^=CC!a6HfybWBcEbym-!# zo{8Tjadlu3fqDwUeZJOaczecet~^L*!;$Ig17^D)W}Eo3wO*Nlm&NoQ*yyIgNS^I) zw77{RSUUmfR~h`uj5+m2FLJltB$!3ZhiRVlI%2W22}4Sm*<s0nb8!k=%RH}6VQ<Gw zFKXbrqI+E4T~pU_^n}EFj4R=m4)tq4LHP^o8Pk|0OLl9cfE_5Hwl~Bo*5(F_GF;)o ztJdgWRM2E@zT+mJ<-9N0!bKeq>xC<8ViouB)~e9B+_{n7E%ChlE}Qt)EO@w!JM$=2 z0M7nW0dn1==NkueQ`6GuGDMJk!=3sbb5qO;y+p5_-pJtABg5C2cg0$s10wL99^&hm z#^=|;eHDykkBl%c+8P@bVnyRh=|A09WWcU6JPyptdoGxrl|txXlRMGpx8--1-}n4b zfpb$gQSh(^KCZY7L#4FdR=vu8NV+y*{YpnXN<>)2c4qBUtA^BwhL3n<gwAWqUUfYx zj+3^QC7e3&T{yvpZwv$Q%YmmI$<?%eTe9y2G)n+ArTOivc8qwS9Rm@kWUn5lB~6Pf zCoJxLbj#Z$V%a-ZXS&A+BaL@{>$!t`Ugov6=(;lr9gHIwk+fZ?)4*pF4h5<G(s^R* zi;#?4yC73ogSHaZ!<s{_b>qk!az+Q_q_k=f3agXi(q>^<cejxdiy6r_<kSWKrJ<bW za)(tQr(^WWiHlsh{9(4FEr#Fxwn{=Ydha`}zn*8ER>mM3aJJIEuA_gkhF}W{QN;%S zlJ(o-%oxMB9(+|hriv&L^)5f&nZMh|Ds9#>$mS-?CRXuIrn0vZbQky9=uAQPC5`Fz zvtgSY4U<f1-*7Ln<4*N*AL>I}^>TmBBG<aN&NbG*!jIuQU-<ALc~02NI1zT*V0Hl@ z8i>NfMt44ZR!I`<UaDhDuDgzb@!(NIHRo|87Xk*M12tT>AaI_gtk}4w?;Lt&+T?9G z&LInpyxb0!#b&nE)r>4+j%Rb#oC4ykBhXH%8>5QAK!4qQdeI-DL0Tyz>uCkTt3<vd zAVvW87+`D#tU9tdId3!AG(>TaQog7#chNknhs&TlO<t6f@9T7l56r9{IMQ<8YmztD zT>~m(owh<|rcy;sm2Q!Lu_#zO1l<asa9Ws<JvwO!pIt7B!pVeK1-8bYQOIboU|N@0 z<vp!ZB}evSkHu)#RFjQNOe79A1eLdK4K^_%$1LVxPtK~deL3pRuPJG6L5~U&YQd#I zMT|T9{fKeeZoh9WpSo|^1dOUo&q<Yvo?Le>$y&4FQF=aNT+kq@e?X&<HF?S;br-C^ zVBhfzC!ZP5_?|LJ-G$8fQpH<)DnB^7vk;R}J{<P7S1Z?6-{Jn%zIXeH^t~;BDgfyA z_KsCPvn`OBfQT0@yB4&qSCRsk*60+{MBx2Dv2C|4G^i8dkElDA?Z(eC&S$5lkd8&Q z_|Xx{@;RK}8WDbiE<Y_inF#!s%sSzPs12N>iM5~&eVtKI^R#0SoE^b?iHRn4q(zbr zRMfjGJ|$#0@zyQ9^DG3L&6oAU4_`}M4^1OylZVUKXV^=kqy2C@_xmHUN6b_7p9;vB zu*PNd4cr>ogXP(gs(&8HHFnWYwmXR*1fOk}!C40I;#9KGMrGCCwws!tUWZ$%$OY*_ z+RjKi3jdUrZ`GUOKC~l3tJ#bEKbvX!f5eaF&rmMQ7jW=<%H45ZDV;l=f~k3K2CBs- zU~)B25yn24ca9h7Ah2Eyx=h_3Kxy97Ny=;&4|1xTM>b^*RTGP~v|fbkF?pQ`aXm;S zhf%^csuiyO;7WR2gF;;Ugt#);z#MvmJMt(pRp*(FK6#Q}5g5Nc)4TzDKT@h=tfXWe z|C=*sp31586M2vNxpse{_YV5qi{TbcHI;@=lC>8)-oJf~jI3XZKPB04Hd*Y>n;kpR zg^TK4=SRKkAepyp+3~#u5vyz@Z?P?i)$Ve4hh|iB-J#HICiQJ#w58l5o79w?WG*dU zqMM_G)UwtM$%C4w<)erPN2sLXn5?DjEi-$bENa#gv@)8=J*CX5&mM_dROOZ*mKBfJ z?QRq^<;Yp`kQy_L-90rAo#Cme8(UMt$*8s%a>A>gA@N<s3|vu%czl_2V-=q>v*OFW zp0{WN>d!D*n|DvAms6cO7%LebjmGm*a1ZO-*tEd67rrevWFAz$`Q=DX*f8T{rkq}U z1+o~+#wv!;H)G2m)@%T8ssE@u^1qbRx4^cRQ==x0nY%eXs7S8?qa%i`<kX*1$qvc| zu5)wgGax7C4$}%DIn|bMV2%B`R0#p%2gsTgFD{lI8{Bh;NnF`x(N80*RH5>V5I=8- z=|EvV)5!5Xs#DbKm(uU^ba90GYWht9NUiebe0OvF96OZSb!o{a`hV^`K<bK`6Pso| z40oFo8wmGDV!u;YG$h_E^U&}!u*~bxpiQ9`$ry(v9oN{>8V_d@l->;GeM2Q~(zqiV z^A}p<9;anm<3~7Zo?(qI*JrJJ<#SD5#i#pR7`}SLykSIOn5PjU!@QMR9D-V4Z+61g zy0=cHOyJT_wtImevy4sDW|EK8j-Xnyt14NW<UiJzO>|pf<k*Ot@e(SrIx4a2e?A!G zg|HwB^OXT>{S?)@wSmxJCN*4gF4<f@Z!>2~A!|QR)}A3*XNF|COWzbxZzuWhiP8*P zz-{-p-w8kNea&WjrCM%E;>V`}+#|Bod(MY$#y_VR1FHEk2K*utGi^37_Yj$)(bTP- zfvSFws)oJm5UXtVdzxCUb#agNw;|TQWnhiS)#g>KcLnPwt*m#g8%D~sfpVd01!LU{ zluNej7N8FdR9lwd-?czu2{2Gtfwm0PSHFY?Y9nuvfx4YKKn?O0;6pkp)v4>ThoS$N zz&{*f$=Zvjbz71=(OeL|^lD_L+OnQIia7H&_HPg^Db3gP#&x`oU}|HDe*4BM@8CBz zk3SXb{%h+pq+(sH@*?0`+pOPcS~b^wa+0^^sR_U+uL6!f^-cV?MKg08mk|$ir%~KM zN_H}diPW~pKe<Nad%%f6a3-(89b&4SD;H{1)2s#a^Vv&FEzh!<<QAFvHth#GMQYPZ z)uy@Kn9|=?n<j`xcd9IiX?)P8-Fk4;rd?9E8(g|z>lSUKrigRhhbMX-)Q#Upk*>r| zlOz(~)1<*pV9zBcA_6Us8a8Yq_m#&gX|mH=vl@Y`S-X-xOLgirj9EsrwsfS|6P=;- zOTni0!K5<&AdZ(E->Ng$$-R6aCA7I&E%Ys*4an#LvCLWAi6a1<zc`^~e+*yMu5>Qc ztxFw~PLt77Wn<(mFHm4ioYu2xBz26DmYlaEcpH8qdu9&eC7m4;dn3;wV0F+9p@&h7 z9Z>cQT4k@j;HxgR>|di`p@rWEFb-q|{p~ki1=%m0p=^=Ghi7BtN{ci$Eye#Nd-njV zDye6=D4c$7IqZMky;V&?w9;H4_$fjQcrYel>FJ)?#IKG*+@;E5bTrDo<#?!KuS3`a z_Y-5a?$MV(G`hf@j{<499b(iB=YgQW4@@}z4#yw96P9`(zMaEZJ`9$Nc{h}vRlu%e z$uYC{EO!0r_r|W<TCm*XgJHJI^}FN5zT_|Lb8WBV-VuHl6lz_L$ejk`f?VD8vy7Ae zd}<gP=y05!QJEBIWY!A`Qaf7yQi<}`FgpYD{TyJnP^F`6K<GQ3bne6Q5;U=2@<i*3 zvZpwQV((6^%Z$gZNc3$T&p!$C9c^L`JH04e9=x!rk<Vwqi~0x!QeOGHmQudqET;M& zMG2E1nPcCOI7IP#q9i?hR%`Y|F%$iC_R;&Ry3x&#(`U{|QA!Ht-=c*j4J|V3v|Lo_ z(sUB(L{UMLE##(7&YT|ftf#I&xQ)90(J*DMY3Po_eoXDWbz0T+TGxZ3XUa}>{rF4J zo*z@+v|ZQVa1X775A_*G9MrTdnaWIh?|7#LTd>nt6EOVySj83mT6;Mv&44wobS505 z;y2L;aIe2?9e^{T<%;PoX^|$sak0^IdYTq$)EbwQiDIrF{;4>>X#>TT9z{P;gtp^{ zX%cv7JFZ`)Dx6_C*0{f(sUY;f$!?%1bVmzDD;Evv@olCBe8c_eS-8Rw6~n=<^S;1m z&bD=Mzdf&|N*$prN+ZK@8YF2dyEMn_Q>ZS~Mz#hdUIZJHg!`b^fpLlyYK{Bp46lLg zjG2^HLe0qsCPX_DGEIoi5`9hA$1F&#i;;Dv4v6p562|vBtHB{LEiK5yQ^mxZ(bx}d z?FxaQm@`~2KvER6#!Z1l_?fz;6+YUW-1r4yJv_-Urqda!--F7ZAKZ8>8Tx%>L1xPq zx$Vzw$<{AVC+F3u!g9o(MzzMhNdyc|6-g&)ny^SeW|mqO>C`xO<EL%dji@-@B7HCI zUF)@XciWpBwZigq6lHA&DNl&Enn?`C*y>+5y3f#<kP&5NDrtlQgS7WKEsL2=Y1{x6 z@h7c5MzpPQsnfhROiio8M0Kgyw>>my{_$6pk>E)ZARD{6MMo}Wj-s_Srd!I^S22B4 zwrO!m^U`^C_sQWK!tSVzSy=`QCl+SYIb_<jU96%slr(F98_MTxU@p<m?{4sY^fBd) zS+Og-0p&++cK&jCHJ@4~5DYH19yy2t>S$VFvX|!44osd@h_99Q!w*b!DNEL}X8+Sh zj3b`~Whi)U@|7iJKe>+eTZc{i+QMQLizVFy%MZ_r3j;F$moVrX6pRWziWfLuvsGXZ z;b;wcR6`Kh33P7Gr@>b@zC5bGY3EV-E6qxn1Eq_S9hvh?UD^pcI=bs8)9o9l0b6sd z@(13n@Yn#)v&vU3$gP+T%U%1Ex!bLBe8gGJ6;CWGzm)l+T^V#SA11L{wGTDWujy5B zS~QiX9Lw_Ds%55V+RN+4JTLx->11pgUEXuRm9UwE9V^4u!EWFAXtDwOo|Z*0T8}dG zKBDuIv;FjGla;)A>M?10Q1xV@QQqL<`8u@><3|{;6tW$hC(QF}tZ{j(;6H8_8@CF6 zMLWJNxU(IG{%J$_9n-f*IY3*XBm$DhDzfruoDz+(N-Rfn>bs6AEhV8$1<C2=aFZqz zZf>sYSX;6gW?Ou<yY<~*6O;x%=4&&Z&JI$Z4**^eG*vU50Ya>j%K%iRjnf~k+?vz3 zJ!_n{0l4(KU6KpNOoab`^Lll}mKMDJux+O9Q5Q0?1@y_<C7Z$P<j3K62CpCgB9qrQ z<Yw~v4}3M3Y+hQ%oYE$D(7tj=8LNEUtGH{}2krO0Fq1{-EHZZGrSNeSvOp9WvLYT6 zan*iYR53fp4>>XfVv!dRX{N-v8oJ4`%3Z<K8t52++`0#eIB~O#%l}ydh`Lyn>icH` zQ8#+Y+E7du(mn8WkbT%Rx2_X|B9^w`{QhkVWRdChR(0YDGhPbzbz<X(ZOEzH=b3Wa zoRcZ1kN84P$mS}Ojj!kC+Mm4?SE^UnLL8K4pk&d0SRjkzLpFyo4q4mod*=>i;1R1l zxHUu#5bi^y02gg%m3Y<KH2s!|FHQSv#!3}NBKtp!%O?!_NTDEfg3R{icK;w`T4=AX zjM&&hHh*ec2%lR$*h)5iBkSg6Q@TFPCZi5rxG7UM6SD)^Oqabnk}oftg&DH3F_Kvh zcfmY(WRpQ!AV?Py-{vKo)i!Utt&k5RcOqsnwVocM_>0j@W59;9Pkl4Z+_B$7poG)P zq@Nv?rUi>G)=tf>ZFjY);8rYZjEs_J(ZF?K>I@c5uvR-X={g6MHt9R@m8P1(qi4*O zC!>RF%YR`;DHrYgU$9~lovzfI8JcRNQ_yL%ceOirH~Ld>!8a>^Ps90kbmj6i4_oo+ zh^R;{_%yz4ow?<+kO3{AS4T#{^Qr0m5G;dFyICU}@~Hzfruh_gbg89w8-^<Pb0|&g z%3Y|+z02OPuW|S#j5)8DVwL8rp*x>0d#rL10a`7OZ?hX>s@48%__?r!R-#j3r}vbj z{K~jVOWTR)i(K}kaw<sr9&VG%pH8=TFdC}4rpBu2^5(_3=tU6M4ffTdlv?s%J42Vv z5<uW%XEgn)rMRivnSPkoDNr5mSKy;MwRt?VZX3y_)%tpPmneN?_JT4)n>=3s%c}#I zHk$S~MWJBk&*9@0Sh8G#DO0Zd`x6vNAdG#w#447Op~wvuo+rBHy-ll{?BqxnW;$}+ z@5VyOg{H>-z~DQ5fMN8;6hV`lNGw2O`C+%}(b`|q<W43}%SA2#yTte4{wST;$$mr| zFD^X`2Ijh6J_Xx_!-3*O@GklaPK$+e6WSQSE?K|W{n!}tL<F=9{(sYo`cG*32A!a- zMa7vB;Suiu&W&Y*HnSgKvW4>PsU^w!s*4I4HGVE>*Jn(gWlqjnBlL#b_hE7vUBG>j zxVu6!CssqVt;zO3V)Ep%rQ=I}14ogK=+zM4Hpb*^MX%qlR{S`1bW~9^@LFGr4ze{Z zqhRcSSw^Yczfc>-WZY3Xr=Yephnf^Qld+<uX9JAV*WKcWJTE+zfxnjwnr4$%OCEZf z7PGq=nxd0(W7?!?N72;(|COeO2e+ch_A@8)k{8Pz6UsAvh)#JImpAsFcW(L0|CBfO zj9t-(p#!&kPu<9^-c;bTH@AGg_{@KQOML6Nt-d!=;dsLE%RgV3^)yd;<6iUo#V3`o z{G!~ok1d)@MT}MGPB(6m9|N;ff27-9?xx2o#?m_>us021xyy-FWGfc$>{(^*>?Ta0 zPM<O)(m~OS`3Ww-!f3m0XbJ|~S1nC}PbD4|u?f*nN=zKNUI^Kbk<x1cg3Xm5ohKg< z?}}<h6%y0LG+@<<O{wi#=5Sw+bmfgzHZZmzmwF8`Yykv}6J13HjGeeyO?*hj@hzyB z_vlts>>E+Ruq>n^8RY;Tose@qz$2q##lc7n15?Tl_IW}Ae^%ML)ewJH+B<N@>Da|} zsUtl#I_l?M`%OzMUomt9rJn%Fb%)R+kp?$mh-p`Gs&8=`d*<4-$9ABUiFyD$p#FmX zKc7i<jssZa-Wp`-tKFNU*e$2)S@0g$3dQTEc@*b(6n_;81EJ+eU9Yb+XD=^IbKf|7 zaR_Z|8<-`|iy9s)wB|a`2YqTn2&T#B)M0$VMw=Oa6~Z#vxS3<+Sk5yaOBb9*v$Bg2 zfc!<kDQ9zsG=?RuFx+n#A{MR_CcoJ|D%H~&$&YT8{M?qwr$4fF^2<pcvB+L1eO{cg zyp>uj(!W2IQqO1sC(S&pwPqd=f~5KP>5(d8#J|0TDJHO%l_hz9uuXPKtB4DI#KQRS zRuMCZ(0<G3&>5OG6ILRfnI<KlKZVThqWXumWl!Q!z@W}f;FvD8vwbp`3A10P!kN{` z>V3APQ*9BCud)$qQe|L@zS?HgMCCZN1)LbwvwJH=>l%Wj8MXX~7L3Xjrq8iit%`lx z-+i%PMiIkeU!G2?V!v`SN&i98u-FF>pDy<FhoWM4cOAoGe>#3!#Xd<y$Y&ky?^axc zDR=iDqfXopv}jCPQ3cxO#cxE$K%dxma45<|*J-;}ylA&|A?Mwv&4TfRT9th!!4moF zC=q4fzg2W8(X1UU#Qh$1>+F#cKgE>CPlB31(msU5cJg3HromLduNIj0<dzA?XPh-t z17K;avL7o9qx!A5LwvaF=!g$3tYpi|GeRis_VKXB8Xwwmeyc^}@-yvHs}d#dZIcft z5iCB`pd)SY;c%kUd^q*+7JPW{M5wt+S&5po`W=!66CbV+*ja!XA9UufB_GCy7}y27 z;$bo4M!Ms%O7(LB3mf2X$&9^)Hx?z9@|Yo*IBcbRBGsz7{X!bn(oURyk8vd2uo<?s z#}KTQ<Y*^n7%|L8bc^rX3Q->)(V5e42zta}EtphAXQ}SIG=~hPC=DYHohg_x#-46J zv|>-4pY~+jx6*y$GD_8x9=C5n<q>iKC<w^bYGrU@j1tr7XvREbO)eWXil69v;w0;; z+Bdz3tc>ofU*BI#7k2TuU*!LzF<n~EKW2H~aJ%9WCR(>l_doHl*5o=XZY>*D^3*_8 zfS+;u*&}FY)jx=HRISM!7k(yA;k*`}n%N7*8d?;}jiz`ys#!9TrM+(P!UbD8$75RL z>&zlwyu*SmJrn%{x*#X;<fP88oq=J4dR}Mi|FrWzTj)g6wJiCiys>-iiZA(Evf!bw z*daEs@_ByRwQt`(CnqO6JG)Z{{^jQ8b-ePYg;`$`b?P?@vnuNsW?l3>E`@lG`(a_$ zzQj%7Ig5uS#sb_GUY_4Ku@6f-1@VFW?Hk{bzn#tbUblF6-n+;1S+sPQp|WfZ>6rW| zbrwWef?Op?94SPx3SHYSWGrI%H{8x1>fgG>Du(&D?y(A8+l~(sH`oxyDtr5wUWx6% z)+^Cv_(ut4(mnulXb1WB5Dn}7yP`KDdtv#^2korr_x*b>g+FcYv5J4Ir}<IpF@7Mf z7cLh^<*m4b(!09RoRAW#n-!<5dn88(ac>Y8tKg0jCF&N>=Wl0YRd@Ec&$SRSN#*aJ z*e#Ogvd-@53D$sy>gKK;L;h=1`+<rs&Ym7)$o8E`Utmn`>zUjuUBLDpv{zyWqpcTg z>4Argc4Rv5m-a^Z$MiX^Py?buZLdPLhI>MAD&Wph0l%iBn<x~%SjEkX24}3|Di0{~ zB-nu<N3e5zHVF22yotH9kC#khl_v$?zp-yGql5gr7<+gSeS{A(8SU@iO-8-#Jyy{R zIKT_|fk(QwT^Sp{`zE&H(R;^5iue&7NMm6OdRHmb6!96}MDJfM39J6W_YEF}>D1yh zx~qwfWXbvdpMR%C_E<$3tsU#~mE+XveMDWKeo$~s#jdn-W5dr_<uS^8-Y*^L+{(Jw zx;?|V#5|^47Rd4XA+w%D|Dud+6mju1MoBD`<KJA1;Vft~PsEG7;n_=J>RY;tvtG?i zX@i9kma^Vbvj4`X<i)4tr7-n`bu^i-3iDr|iN*5&kq!_OorZ<2?j8#-9t$spsSDc9 z|0zr9EG663eM(+@N?r<62a*z|Fa@@!D5-Tt2ZqOdGMG}INt6}sR71VVP;-9Gqvpk< z=A|&To+e^eR%2^+?q(@BSV}v2C3f=SQ}R-19b&9`nkif7{|P4<bl6Hl;XswopBImX zm%`Ku%D-@{{O`4tYb_;vQGH5Yd`eylQ`!)Xw)f@dziE34@djqMo*v@X+Wvt;P1{%V zCT)M*lEf-k2H*F16sGNePNTb%XbAYTPajsd;g-XHZ3!;)IOILb=CO2bS8B3H(~INb zvNZiMS34l{E@rOsbzM~k@U8-u>GSn=xG_N1My-!bZ4rOf`dn_U4`tH01U9rp^D*^N z1%A;-?w~ecd0T*w2Y^pz0RFQrz@-2h0csYzo9PX$e9NrQ@PIPjqB=jLG%W##0|=M* z3*mix`@i6Fep~c?g;62HUR<ChF874XEwg)70RK;%{VS@v6=y3!BhH@dBaO2sw*`1Y z0C-Xc;H0(yhk44wR#c5z+nnv}0ei7oIBcnppi|zeoSW#G84LPFO<Lcrp;%EAyB4;= zsJnes??f-q^lpXy4?eOj>9P|yt;lt!&~H7#=;$&0q9Hg!%8VRE<l#gvY85`1aMhAU z37pHx0424#J;3Tt8HtHp+rou{9imZx7-xUnC33{1u}6&ePA&LWI6cLz0aGqaoZ0Wx z-<>hQhhb^6MxT1#MQ3Kh5ZzC30SvY$OP~Ct@mQjM=U*7W81C~g>}SD*`T6^45IoT} zd`YL?PI^>+2?{Ra=!W!yJ+#blS(*IUSl}-jxHi|xtIr$zFxXgWSHaM~tuAlebN=@6 zy~|zC_`osozU8h{d{DXT5bsrYaJf4mK446ImvXm#eAl`?I49V?ZV-R7>jv;Qr>>a4 z9qYE|Z-=@9{^r(kKU;I>I&NQU*682nvJWCVd^}%NfSczfCC!V?-ND2q<8-l8jeFjf z=9s^oi}R12n5PNlVdwf6s8d(%b})(=)qEdCdmr}6)eD}lU$EuyOFEZ-IzM)I&*?wo zj%HDVRvNW62+wg@S*I*0=(jQ}t6wJnxa~3IAA1_azZ5^)<e!!<{pLjR@9Lq(Kh{OE z7S#2K7ySAP#;C41-eW;sLA<c8NQF11v@@pU8B;p7WXjIq*fvuh&@K_yCE8}nx#Nu~ zc}7Ovur`_U)q*dXl^%?WF8GrE;{bc1OWB*3kTre}r_HBJN!F)%^0nuQww`U1Cl9pX z$=tn-C!bqF>C|@fyT^x>yRPy5#>5XCBQ5GtcSO1C9`9c6`oss9y8-bbbwgoQm%6?9 zn{Rs6)%2>H=~c{FSYRydZY<ocB?~v~_1{={jy8X6lZAuE84F(o1wPH&X5se>zRZm+ zYND76zT~Qe@9kwktl~>vLKX(=Hu$w!VY>bl2-R`@OxgrfacZ-&z`YC8b#&72kR_<l zX%$E-Vw%-o$ACktSOxC)dj{RJSmg^rV4*uB9r%y}hp{gkU|n<1CQx3Mj4sk)ppiND zSDCgrHahGj_MMel*TJ$o4<zAy@vY!yM6Sg0Sj=x;71y*2fqWP9tE{wRPp{fy#hbf| zR8_-L{f)#Gwi;1QkP6;aVNt<9l#T?Y{6S+4VR6?FiAwpA0(&euGH?mH8n($L=z}O; z>VCzsI~5X!4ttCJy5(DP=68)>a8!K8QSq5a#i!R@Q2u3y__U+qXOw?AH*tnGF^9JN z$<ypOMbEGVOD5+0_|}3?+by1$Q#ZA>k?DK1EhJ1KzaNP|VCGN!9jZTr^}VZo_tQ7G z)I@ohecEu8CGG9YHap_bc@z;2>3nlggo4=PlPEz^><VqGTyovd|Itjsjop7;$nDEH z?K@=WcGQNq%zvGi5P2BSD4wxA<9R0Y%-}hR=WL!h&wQRAr{~n2HuER`o}fR|^gYSG zkI{GO`y+GS-|+tQoLlNfe5ltC^}5fxS-h^B!|Sde>-A&3ZdJ-HW380KRGRE$x|Dwy zY^Cf?c&JcE6XX@D$PGJ&iemd;dnAu6iakCu-)2(oqk&wq;Ad!NCMCaF<!_&z(*Y#W zzm7NLEXo=}R6WmQS&Op%&~8!I^!AIg`e!f7`jV$5Q<<L8vh<Sc#sdyhPZd(biCm(8 z?OrE%A<vaOH}TxX^8nA2Jk>l)M&>ML!|iUO&%YL@U$;xY=B8hNp&<`o>(j5F@!DEb z9v>sC;U@2a#aWkfKy0H7-6<|**oB`q%5WXQB|H;(j^~-la{<p~JXi1p#GIZcW_tQ{ zT>ACM^y`7?SDhLSFz8~;)@Asv)XH%6?pB6@Kx|cpTTBk`LJ4I^@zX{b&On%*c(&)+ znP(`^p*%<NOyfaQa%O7l^IsUPL?5~sGxkgnQ_jasjFy32ocVEf=En({9~1a!U7~)z zL{AU05={bP8zs6Ax+u}V`Dvp>2cVkkh;lqX@U-VU##79*yWYbRz0y9TMDjBbmFN*Z zq7wZz^W&z>k0qHO^Z008qVc0mMs>Sci538{Rf(=M8C?oplxQhGZIq~);0Jh?^SsFO zCeMdFDV_!%l}IAmf~5}Mzt%evQuwEOf5N}NtM_O9`^&tmu>s`S^y_21wk}9zi4|mk zFUS)D_KiVcNvZU{AfvDc6l5wtZ4_h`!58x^;<<|F&ph|=EaQ2aCnSC!G6>&y(R)yk z-g*xT(pB$4LE7;i6y!(v8NA}VbE|?prE{J&ZpN-A5p}Iv737jjmt2>J!J`m;`DvpN z34(|7jN&<(XEM(TJZJL!mdDrGy4k_+tl;+)DHJBHZd&*<J_r~c{2tbt>oJIB4^NG| ze;4-f{HAqu{iq;1spwtk3oPQLYFJ(9UY7>gd)Tcp$h!90m1Emp<p1i}GPmRh^~-`i z4czWb7oCmIO>WtbzN^57M((ZwsYUStKyWTz_eyDTVP0N&Z4=$8yoVWW{L-Z^_u)K# zJ0*LuW%ZCFiy7QKZ>xeGSzzMY=tIhWN#rYl`)N++IaxUjz7a8KpfvH}PL8EajRvYN z%F(g{9l{ZKmy6QoDsA0v7Q}j0hqx}e>G()b7EnGp5_YV_xvIbo>~6cmFMX$sr`h`x z6L0M7Z<AY`$8MP9&h&${i$K>AWkjA!Bv*vi$-7}XNtr^~y)-932!78^-NzbUbLa6E z$S4p4Bs&6BN<XeB0Aw3ijr;UkgS9<OlWt(Gb#$TaaKr^pq1%A~fF~xWa;KxaI_R}^ zVdQl;Xc;w6o|Zh?b{Pe$Huz$@QnMEc!OZtCdmFyp!3Sr`g^|tCjp|lXj4)jiSLHh; zncbsHX-iIsH#|#bzFgj~!kbJ<6a5Jz_1^0tl?yfBDw}m!r$yXGx9=HM1B}#wH(EmM z%-z2_RsZgPybf&-QC|*_3RQ6?^`98`)FxHej3oJqks8?`*_x7XbYMWo(T`JlJ8vos z_eB`a5r(@AL%sVJtHWVTjYYmux5v0Y1z7S*&f~-tXE!rAU+ZRFlji(d5~FCB6tc)w zA=83n?hwKfb44=U^Qs9Xx}Qc{^Miw(b1h-m%lfQ8*?GoFrSjb>6cOo<&S7WEl9F$@ z94#y?{dhYWdWaC{_^Is^`Ku6wKrEgtH~@Vt7ZQA%<#18gQn0fvFJIj`V;exn1EkZ0 zoHN~wHW@bCF!-QK;IT~%Y3Jsig5*VzQSZ)I*5*2Ik5X*Q8ik#%FlJxy5u-N?o4}if z7&)URB;HS+$n`^o6O}nQIeQ07hBj}{h%VX-S%N|cS93pYfBZ@o35{zAwm+J^k;P!9 zM@Sk2j<D8v+hPhjn+=;*z20@*_A&_-?akuU5|F{kUzpu8IW}<;H&n(xl-eKJoyh%W z)RZ%S@d~F}@Ou(cQwB_JT~nT_vYOHfm@<P2*IGlpmyOV+SY~%G-U*|iAr*dfR3nkz zd)~Kc1;eXlv>sg9^ba*6HSQ?EYTTL7B@O{B`!j6J<p-OL5Z`lu491_AJld}AqR=<$ zcF<zekD7&9aD>f8P6c2R0Co*<J=g&_QpW@Ti4NmX_p<#*vVXX?q>22!!2myMawE~S zC}gD>2Mu*|z?9d_<(cCe6WrRZxfp7?_kqY2TY*8e`yJRe`_;9c=CBp<O-T8nvaYE+ zRZaYT0`HGBGCMxp&R^6}(&R}k@uc=NF8HfuPon2DBXy>)_SzwjQM%_&pAE-l>|ijv z!_kT+cX43wn9*(W<M@UhRd!8IHu>@GMhl3m?eGw9`2a0JQVK(J7JR1cvC7Zj4mrBc z$bzgkgv|0_Z{He#X_8c68}BnPHkQKE0R2TC{eD{C*KTJH+^r6*TfdAf8*cO^x>$H_ zF+6o~i*KRwjqV?ns64L2o7|mu_#|rQg1c*A&Bk4brzmU`2U8W8Bt_F9e~HS)KFFHK z?!vPt0m^k3ejjcp>3V&ZGOLBg<t&7|3$LP7_2VmlyzH>iD7eBn&3Oi)<?Mls7lt8| z1UHhqly{*11yF|(CWDYSYJB2FJlI+VodE!(bxw9HUs>$#Wv>Zzm(OY9fSg`dHo5CF z!p0M(Hnc2n_>m2E14{WEt|#_&AIXVL*lfYLlLH3Fpwox^tr(l4BNmFjnUAP96V_ex zX~23R)`|afnEU%ai)q$ky99arp!?MHNDo;2*dc5^`4F|l&BB2eUu4;n(nuWF;5t-r zAf++59;DVyx(YF1zeECAG}X~x;zv8J<2#WGwbqqNZ`|f3nqTHFlP0I;kO|~?e(es~ z@GEFE8(|trZcQg)Q#DCSd=g1)<&`F}@?Sacc!|{?jyDyuD*KQkbk;iy*E?RP(`NPP z99LQ{9Scfxbb-5?(vb5(5f`)%>cN8nnw-N06C8=Lmpr+cQAj?LE_2Hzh19=-ira!i z<gsxP4b_E90ja{>s#x&<@%A=wQC8U>_#mjLC}e14woOKfibZ8*N`}IKqyh?Pnw12D zPzVGwiRB9lY~n<(yKP%-xovH=S?f#f#`Ll#1--AO8D%e4w%u{8sHmt={@?Gp&-2U- z;O_o^pZ)*&e1_-VbI(2Z+;iX0J@?+!2vB|f4}hS-LIkTMzFWuFcV`be&8pm~k!lMp zO?a0$>w0R0`UAb7qL#wpUsrcS46mX=kys-Jk}X5B9MDp+ksCF_J%Q1Qg9`_Ts#Kmd zF!HU&B)}m5_m~`!L4S-O;)RqO4T$)2G3km>9Y0$<^WEyjz84@<J_sM((1<cYExAaN z;EM%m<E$K@=^c7d$2=Kt6*Fc@dkjZHva>B3(zpc2Q1Oh1Sp&w8ks6?FU%K#W=MSf9 zYOJy;7~RzGNzkuv9qocK;yZ%S<;fYVIZ!1?9}MZH(6v26?Epr;8qU-q_Cc)noDqG8 zCxN~*24IW?G%U3xB_*AG9=@3W*S%=IXMM17-eElq@P*ic$8&0zRMcq4P@6Ce!|-WG z(GBR9p%2$3s-h!!8Wv+v5yl|Z=I8`TT+DM=b4V>Arr@|q#R0S?Ty*5Xe86MFi!@b} z=sn-?cC8!>Z!^@CHZSUkP2I)-IVF^fm_3fpo_Wgsa1hlbb*NiXj=t#v#5iW^Nld*B zs7$Uc-bg)q!>`FFKu;Q=u9Yi8Ifw=aY}g&xpkIgho_4%eym~_Fxj!_`I|!|2o4S@z z$3Y%zc><Gd_mDP62buRrq|b4`U$>^ihC2-4w_4gMs0C@5uA#qbQy-sz>1%`Lq8UmX zBjb00AA=5%23ZM@4@$V}7c1fOn6Ml)?T}<YV6yJ9AxXY<o{?l3lJt+#!i;X%3%MeR zMF5_=-<rNfq0o7*@={DhD4!gBTYP7XMNB0#hTwZ9cqf`(__1WrGzY5>(7j;i0BbR0 z@g)u{2g3P2J632k62BN6`FII3qUGQg!#yvc##(2fR_g$v$CXLLS}|;#oj9m!jF4cD z)y+eh80hXA4KZHA7)%i9M7cB)w7%+H1F4!wr<+JzUr54dsG~gO&C50TY<ZWOL%bu@ zpph64y<Esv^tH`DDftX>h51hv7Dj{mDuenc#KJUk1S9V>BU_1_u71x%P?4l)uwKL5 zVwA-A03YAYW(@Ftx@&?^9|`Iw3H1*3ca6K1A4GkGah8~I%v3nnX;D*t&<!8`Lzh~o z<JCyK4pqr`G_n9*k-*Sb;<olElv(#Uw745?6fX6!t6Mj0Nil_ML=|V3E|ayNekV!j zIS3w12c!SeAUCeS?^HvCbe9S<lKm+b$<peW6$JO=<1Mq3v30ZNYcU=q2o$=<qGvRF zu`u-|yiAd^o=$bg{W?YS)jedb)&N-(p$@e|gESNMNR%R2E#D61A`>*S0K;k+FgZgC z$CvArMS>*EMXD;Dv~i9bOSqRX;}eYpK;D{#Q%0)qLb&_>K5(b=CY@cBx&twA@SZhj zDXeACb*iE0I%|IbAzVMOlmW{c9bEKDz;YvC8L7<X*{Grkz<0?~9rt2{Bf>t_aFSeb zl7dyipO0tmI@Nvh?NWF0OQPx~!?jdx&@Pzi<S;>80GG4O7th&5t16aw%&@`nCz!j* zQr9fxSUqKSU&v%G5cDo}mO*@(I^A$BRVQgzXfk|JB)EXL$ElM}3M$|eR1~~s0e7kG z#w<Zndu1du*QH+IS2Fc?!?jdBu3e$2@fbaea|)>Fa==lm$Htf*Ba27Tf8o;aNxSO~ z={0zlnxvTsh~a(UOhUo&%BwEifr6<|_#Qm3M=m^-QJgH#N^f)QMOQ8T!!q1$r}9~P z?I9K5cG77HCexHRrn_-Kk7I9^yOrdY8sw$~lUqu1gA8)&m<0A}sr>OcEuW?8ciI&q z6_(pN!XcQI@--$#W|4n&5&|(fI-t6L)XfXs9QMa)B7n()c{{#2pXM<*>C|;E&!*h1 zzD2hz8OKsc)NCx$t*5KM_}L`Tr$*N|m<^vO(!ZUI?&tFu>!z6QZS3ljFjey{*0{z5 z&NKwZ{Qp<zoIb)#j{`)ApeG;`RPP8o(%N`ZPa4(8?~p$hWH(!!fq+)Wn;iw=n{NXM zY<aR;#2e%6sxft%4K`<hO$zXQ`7+CFV+ldNrD{yThugl;)^t)lS-#A7Bimbx`XQQh zbbM1zsC9TSGa}Bcrn+mn%kmr5HUo1+sa?_+cBvch*6ih%w2uv$TYfc}l)BWWptP2$ z)j__csyyK9%j<qLBQhE2fWE`jMK0zEH<;h2Y$r%3G#j1BsY0wvofser;S3A%EmcQG zSQ+n|;MGj9RlR56nA3W7?`l&fXvd$8Ha&(w&OZ?(^E-pvap4KQa7F@WQVVQl`Zhtc z7|iyJ#jjN~%b+K@k+mYUHNP0we{0U*;@2ouvppvTky{FKQw?&R{k3KgfPT%aR&Ncr zWR<d1wFG>9B*$X@lMdHy#cb1Kz$w~vi<;0WwZzqLlkUMECPFg*zW`sE|5L}?r+tsS z!4Pav`<6z4Va;kskABSp>D$nh+0ZryA?Svt^K3oYybh<3)lu{%ecE>>W~Q8fhg8d@ z*i-hj<ABycLwI{sX{=E#ThykgfEZE#gM6s}0Uz6^)m9bSDutSba38nzAi`Mz+@QWK zLcRGf@G0}fnSrt!6@<K04G#GFP3DVXNG6HNP!ML}T|V0E%Z#3=<gjk)?1`R46mqyl zzGjuVFUYr4-5T)qN!IrQ8(WJiGjZ7Y+<3g%Zgl5!QmpAW+S;p}!m%+JozGBXR*+wE zuRWymxpo3$;$2abymXX3Ljy&zRDBch^<{6I(fL@?$Y#>{9g{FZ1!UBe7T4VvV~O1u zLwh&j7r!#N4#<{s(POm0|Ja1x2D$&D36BV55lz?@@b$?sg>_(vh$plO%Ul$h?oduW z5dG&ie7@O+MPDr{K55CuHkF#YvTrNS**aB495iY&tb@$TXpGWRT^yw^27_3PNNe48 z97gF)<1tEqqKitiZ5`L?R?VZ)il?H-z)lUT3>L^O>Or5b!^gwj5sCb^Djz<+dv$gE zkf6cak5k<-!XxWhtNPO&I+DF4^0bg@HWcY2{9#g9LJEVSBYA;QTh;BF)JV0B{=vFN zXC6nlQJcFtc_eGnh3RoP+MH|;ZUi}YD&_{w9u*rSok|o~KaVLY&ic@|G9i-)W;ElY z8y;rJV2oDh1*QFlxQ(=Hkv1nUCNGunPip1PC?}asdFNnuXc3hqoyFOTjRt4tD7;5q zA1$15=i;8hSeDO+<90YK^2d=pk~8RI3Eh-86iN6`vrxXmq;OJe-Ohm=CPVlLOaQ4o z4%p68Uo=(MwX1CyE~p?{9&aj$0^FzA)wK%D1W(lx)eJwSk12HYO+SJNbk4lEG0?aZ zp?w|)9H>r%bRk^NP^le*@ARqB4NoF!D8|)XfIt^7Bam?|{WxSlx&d;79;$a5&mSUw zpihyxsHcO8JjOyw3JOf*{?;C~!;I2<803U@uzSQasEXJLkzGr_`2<$?wqa;7m&RiY zVZVQPYF0E%s(N~!K|_O8t8r;aIi$ygzrqx##rGom3v84b2mZ`^9<<KenjEde)f(V1 zXX^m9d8@QF-YWk&88BXWd}|=JiqZ9`&_>%ewIU~5jX4IaJxAqht6Bndy>DgKX;Y(s zjn_{;W)iedjsoggM6K0i*}U7-OP}kO8iUZ|5DL&xeEe6yAEy03N5DVV+`F0rAXLvM zG7HkyvlUZl2mV_`JiX+>(?gp437X3%5ePZTGkTV;ADnP5Ly?}7B=Z<tqrwFMUoli~ zRk7VjX-bR7ZhMPz0oYiLyB9{HDf7|~y}qFm3mbj3GVpxtpN0HJcs}w^11Yf{9f8z? zNx=v+bu6ydprV^w|5z6Y_0d9|_S8~}=DwO-A>x*6F@TSv9HgGU7Q!DCylOg2xjup@ z3>6p^dcMC?S3@LJv$I^(=ndKyhms2yrE{0MKb-nW->oK^S#acvsZet^=NjncA8-q0 zHU-Qr@aa;+*!g3bgF&KOEd(I~voyhrNf6$P;Wa05EuXUkqf!@lGH_`&NWF~yQDtb- zp*o}6F*(JwO=i|PTL-JVKMcy*8K@+m4`70w>O=W<t9RskSiONSa`ZeFf~M?mXHYxS zWcfW=DR-Jgn>?g}2b2Z4#V&xHx&7e?(@Kra$KG|Dg6fhL80cD=H`wLC4L0YBDA_)r zwxb-{RKBF&spiSITRG%=SY3oK_&JjcQ?s;u7=%L04$BeHX#P}76x#Yu6+r@R>PQ&# zd02gqFX;S>!)%-SLZIw|FbNwl6x3La4CT_DmfsjU9Gp#Bldw+Jz#R+52rSet*#Np- zxPdtWT)wL=gS{$>mV#a_Np&ihe7jYdd=IN4e8CXU@d0b0K!u?}>e?Zp3=QnfkjzDQ zGh1s9GJA|?@cMhq|BkirGAeQenijRMh8Lsfz3fr6LN+K**R4156fSwX5gP+Wo*uC= z)lRipzS#eh?_qT-zR1&hP7K=A215H!Gr^T86@VLVfBzM8+o^I5Vsi{)shXHvHEK{v zh;EpO%B5L7411sKhMv`FhULUzH4nnb36X{e9r}_<yK-nnaac{JusBK?nx&?+0o_X) zV_;M94>Is}&k-=vtzMPyVYQ22q`VaO9b9ZAb^#M341>}~pJ7CFbX1*U0^R_i7yVya zZDT<Hb)qcmht4w4xigp!0S*6#4qJb4c|Xc2EUE%@)OsXvarb(F*jjOyfOZ8}WB0?F zFYHJRo-bIV+M{Jgo$E8gdN7+f?Eq2<olSIn3J|wrqHlT^)kk(lLPz?2YA<j?=L$1W zJvrX)Lcwr00R?NX*~D02pcF!86MK<KcbVinguO0I_|gW2HkNkF@4=m7IDK~`W{XWQ z67XZK1tn!p6Z(o)^&wYY`JI=lN=_zeet@0FBy}}7hJD5vyv;I^y$oe7X@*|IIsgjj zpbZ-@go;c4_0tf$25~M?gZ{_ww{~k-4#s&BjtoLpO~KGWXP_S$uok^3a_{JFO@Y?g zO5NBkfniM|j0&_RmK^*)`N$DAxfyJ7z&1(a9{)W>av#HRIrBfvbvlpx+pYNr??}E# zw6ERjy>6lLGs?mox<_9FdhGJ7k@eZD0l^*f$Az_Kj0}UF76PRz1|_)+Nvgk>gF$WR z1zRA#yL2iCA9Niw9b194kUQnnX>tdUrHvtckJ|Pzi{218%oA&WKHWXUoYh@`klLRI zx&l)uYAvr9C3CkLE#&;utmy0`e6L{aF(5F-X~h@<E~1$HzkXqs{X^+~A8u`%XxLM7 zE~4!;OlG9V8NB^?wJ#hL%_YQS6tt%!9p)CV_NZkM454eG<(g}`X3=FWD8{a)bg|SK zWN^1fO%Udy>ko50Xi@3l3G10y<&*@G)1`En{9rmVA4lC;=z7v?@$`F4@35#)(LpPU zaI9>sv^U>iq&?V5`*Ebn`KpcdTGXpQ8)^FnFiUvL`2Zbe+T4*_5Z&+qOU{(UY5k-+ zI5^dby;HR`I;>!O)I?zc7F8{34wE+%Lq-$au!MmmF4NqEs|9fQ9ac@|7*Y+TEn2|` zIs-#M0lqi2c#;$3zC5A0jmYU5`L7H%(~;_OgOUHAB>FAE;ot*#mKAR=fhS;Q+FRf~ z!C61+`aS|r25AbslQL{ki;<vYu_jCe9;PbjFnOcEQQ9&{n*!e+-Zxbivl&M!tX1Y) zR`p?lCRJDlT#V%3@9JORhcLI7;{OB=e{zVx2SDMA_EV1N_aHi)g{X-T^{5cE{m>mF zEF*+3Kl=fvjx`z1CE7X8s!g1W_7>@|Mm?sP>xH@(1NOsB?k<kXn^Izv!(5TbRYdXt zJdDF`#nAQB1rv5$g*RzkUUWV0M6K%@w{CKD{Uda$u;>lELW=j*)hj@7DP0-Ls7{?6 zUC+b6zDp!@e02S@@FDa^G*^6nVAz=q>zcW40$xTDYUf7R(`>&^MdFG(afG9+8PS#Q zvk9dfmvgq<j#rOz;N5o(3Ka8IR+n^@(e=xLrn7{5@jgIUGHC3@*LNm{rF`}HPX^+Q zV8k5;A~$<|0|hbh7XxurFybZyaRU)QU^gk^!|QC73>h3<UxM$|HZ~ackt0Vz@3aRX z&j<_=vN^hFC48Ln4$ybfF9#LrUfa}0ECGBE5gYSgxPyv9l0lY+Fd1ZtS4{bEp>uyY zpF^6&`4C^<1;l|hc(*!QNOo&$Vh2Xo??Mo`ggpa8%Ah{=O=h}gG7lIe?k0&&&K(&M z={JT%JeLtW0m@gETn@8wGIfj25_rhU0(^a2Kqp_V`^Z3iHW=}2191Wo>jZJeK?CuQ zV8loR(MCj?SL@83ip*^vg0)>4Ol|^l^Gy{}XYuGJnVTI<ikrP;j+SA*XhAIJ{vQ$L z23=DczcCPRBI3WgnTu^-0#O>k_W(xM?*`OJ7S~5rUVxK33o#LQR{&U7v&`l`9^(F$ z7Wa{nklOQzwtWy7ey00qkLdj1ro9lSys$iqQiC{;#uOEeaG84J-Qa9l^5xuvS@;%T zAJs+y9%{)0=jJ%a*q4V@<YAi0!v#S+{1a}AhYd$99+s-i{&;X*pB(PG&L5qx27P77 z?lbbCW#?Lo&`W*W(U>%3u<H_ZH0j9$T(goRTr<$|OasRGfx37AicjAkK>?saT3&Au z1jEgs8tVnfzg9>}zZC{SOC>+Cz^DgBVrOJ^WvsriEz;t_s5HnGg9PwS4<M?H)RLr% zhXvt82o9dxCC+T(a1La2j)pEr6piRGWM6950>{ib;FEr=`fRD$S$UaR`3^X#cFgyD z>rtL7a2=H^3M;FZR0`lc9NVg9NvFVNS%O}cwW`wy!r|DL)QLdjQmj=)1GWSwX0bHd ze>sfeaE?Xjz7Op%!z(yDr$rEzFg%7{dqXS?xp4C(@107Gs@wT}U00NG%&B(bRGtuO zxB#C4s0sQnA}su`0L;N}DSp4f?;-qPzP^ZuK42%=)0mOy&&2?ATQ)dU^BTTf?QlS2 z!uNZt2m;fsstAaDb)!XH0T`LinCIT_KglGNW)K?c$tB$n*-f>m>$4C)-PM?y(39@+ zv>15|UW<9Y#XO%1+-EPe7G!va<oEBO*2;;13<!`<YVG0cB%1)Hg~cXJ_v@zixX*wm z$WreMfT4lO*><un<icn!Py8j2@3WrtB$Z04?Q`mWv8`TU&`eV28#K=+&7IH*=(qgT zuLRzyenp~FnQAOtlf*TYFq>y#6xYs;Q$exE{ltziOP|_;%y1!u?#ZT_F|TRyReXOW zcp(HCnDgsy%$IBOY`DMc1kd1}1$mqR)TlWfNJ8d0+TJ71FpiGFH1V3fM|;#nAi(U| zFGy;vfgWq@MVaWdrA{XLFJA}HW7U`NF=Bi#^mw2TC;IC_=<(`#L8qm4JY&W6iWP@g z@9sgYJA-1ysf|{wIK~>=E7n-V`Xgg43yL*XEs$8AluF!PBSi(N(6>jqh<q-BMczIE ztJ4hhvJmt#pgV{j5rST(I=|8xw}+tHfj*k(?;top-L75|bY|R+_G#)7SaR*Gw7aL9 zl@_ac(0CqmIMHij^~MEU-OdCxTISJ)qWxV&;KIM*N7jkUzC)ep;L!(jK1a&$L(jc` z%>cv3T(1KYR2xZmG{v4PlSq^JCtM(Lwrc_^G3jrLP2yWEYV)BZw4O0(&qqrGE^WfS zm;~7r^mje%@K_hMVvncc6Vz_PJ>fV~pMwMGL)XoSu0IYPO5M*xqHp{V4je<gB^hT6 zXKb*=8ovqn@;AfyMP9VQb~1kF;D<Bq>&}1y4w9@pgj?otMg|Uya_dMGw@}nm{o$*F zZ~dY5a7Nef!T(F58!7=J$1sK_UsK5!vLl&DjnJ8BLr)V7WJj&G_X6^!6!nK*K*8MD z3y2hLsyYZrL+m*yE!vT*ktoY0Dz8^?B7)UD1RBh$F=m8MP-;tHt8DO?leqq8E-%+{ zOOzC~g)vq!u<qV~q!Enpb)r>Zuyh~?F_&5FFE*n{*~wXtAXy0C&k!*PD6#+C3n<ZV z>kqiv0HQt^>k3_AI9?`|LoR<O0)6A)gQa!!O%H+R6l@j9c!7Z95WsUjDM@NHXS~#% z@X5C|IwsujGX9|z7TOMo3N6PLitq{$)PrUCmns1g>q!D{0Z<<o8OI)x<R$QTB)Lb` zFwP{#LErdE22K}6H((CIcEGAG`X}8E&}ITnVLj%1W_aC;v_X-hf!sSlGrxJ3+04yd zh>PBkT?n2!ER#Uv)S+&Oo=O)@^hTs}7&@#D06EM39e6c@t*-Da(@KZUmp$aW>XtV- zMsc8rG5u?v+yqi61`tL%d*RldX!K1ykHOf;{9(1kh%^e3U|8zOjZ}YU-x5hH(-Yys znT$FdN@(%MoQ55#3(zrOo^_%Jk6}}#hFPh>n(C&Ky&ZFljgDXNKY4?^g$nbXUk3V5 zPhOAvF;f#Sk}6DCnE$woq{7k@PLsV~2GX=xA5g)~m=U$mqd>G`Qkw&SdWK$79^)P( zrI(tB8&JI1KC!7^80Mo1M)Ha7WFwSw=U0&hbs?8<LBOW~MAv}mQEC-N*Cm>^?^BRU z9_5}v4QFbix~~HQWi^3rdjsiw!&FR2C5iB1(hG#bD&b%=Deyu{U3oi8z?<;xqoR(? zM?oy3-KSgJB&d5B6Jj3ic53JpwUHqI!sKD@1!w~2q#HWTplUZ%SZPtC5yq1X6VaA% zazRed;p`bMT~%LWx+yD&1eL;SEl1{*`x6oKnK~OC>d|kJu{fb7S?y520|XiCP*-5R zw?u8`LRm8wuTElZ&%jRb^Pp%=TB=czJ*Z4?eZjHmABQ<MS%JSrAgJjM=?hFYT6}*X zh93>fcwf!b>*{?-Of6(%BKoF-kXc6HNTAsU;*me~$JbCe9kpu{Y<#sksC^h?e{KkH zkGdB4IAAjz@2W~ZgJR%KJ`%$?5yQOt<76EFhjGFNrz8>b1N91ZYvXJ#sa-JlPb5TW zrN^nlZy?3DgCX+)!Li9W6@_}T1Ued0#<BsM#yeF9?Nw18+0hO0Mi*m_wRJCc8huC? zJCFhCW(N|KpEy%MF=)#D2ncULcdOc0*&T2YdIGf&TPJ8~KSr>n;jN$+Rr>i6eL_6C zVLQYeeA5%Mdk4y?F+HB_ZgTt>H9*ZE#|HO@g4`dOZXV^l9I@2v!4S?xA%$2q2$c%s zAHz6*whC-voNAed<fTly)JdeU$)bR%^AJ+t9C|kdx<rj+nD2YdaXJp?VOdju54{Gf z;p&bb$ZC3IZB2~LHA5(4X@&EDoQo>Agfck|d=$XbdqBVhER}TrLNu$qQbHodDi<kz z)(dzgfSO3GIzfmyg$OTn7Ac0QuJ6fOAn`<@(+hY)Z;oDt2$rZgNe;#Naj_I9j~Z}( zqi$r?(v=BwhCr(vf~rHo<$lRFH^FDj7>zck$7#?oTa__2kG|;ugaMmw=}JPvQK=@q zES0K7P5jKNK7Xe4f2ms+WpfX2%82sXGoWuc6Nv^zPEa#3AEx<`nII>)N03v`qWGq~ zm@qEKWPWk_0f~s5MXBM4lY?7R)yqI!qDC8nGC59Ahmp!8Y@GL^`;bL<phfqMk0BdJ zH@dEbz@QFS59dF;9m!f(dDig~h~U+VdAyXXl?j+Os>Dx?+~eVUS=H=O#{rJBjNV(B z`yw!oP2v{+U>+~6ds$DW19nKK&YPKu1uoOH_7&fmZMJkyvk$|kCZnIU1jfY^`nHDs ztJh$!Fa*3$-O-BFyPz$+{S%Y3sW?pU?IM|dkdix^R3kItmHzp>9(Q-o%9Ij97y_N2 zO<fK||49hJ9j85&aiM`J2*i=FUlTi)bXJCPXS|8FdP*pF@i_PK{Y&IdQj82G>IV%F z{il`XaUn!e<C;$ivNrkv*#WAm#WbYFxA0#^m9}iWSeE=_xemnFl(SjR45ypZTTVqF ze-R`!b2&EG33T(80knzko&`Bj#$qoRs~kOV&wn~IJttQk<^_8BPs3EurVfZ(NARS$ z)b0>}948>pg@ED-`ip>YUkOKLb+7m^DBK|q^(1R~zWRnkQNH?!jXPh>;kdgsEabit z&NF3<SOen;eZ<ks3|_(HDS7A|nU%n@dud3!mH>!&;fqG2&PN;3w}wn+Cyl*FiLd5; z4+Pz7*BIjQ?CDt)DFWIrhw-!ATY|J0_27tIPrG6{J%MG2X%%LzSFJsDyc&h~qBz!_ zG1tlmR+D;yNe8ra`f-+UId|6v-6-z4N<#UeE_jX?i@A7ZLkGu+8>+_(%n+R6n}$yX zO?BHTa$1<T(}!;xiXE(aP2x+GAs4P8Ne!2GV8XYZz&%5a_fjuB*ztsKi%_4AMRZzR z4F)@ZG;zRfgh2utLv^Aiu>rwY0@RGhBznU~Xx3d#yac*i4TOjcwuc&Qx2c$m&4+$} zeouFsm{E4AZ+LPQTkWmtV^F2V5Z(g=|GbFdsTTl&EnE*iy|aWB^A0Q&g9>Oe#3FN7 z%-GnV&XSqiKy>Os2PAE_5#U<-s37}?<SeU{jM^pQL+0dk?Mu73zUlVn0gYv`7=E)F z>XNiuJ6t?P`IA=9s^5NyU9kPWYAIDbYe;K+!xr)kFh^3)GmCP7HC3!7I$^*E@LvhW z2^yFv9ELDC!RwNZbsSk{VgJrZ;ar^p6%y!jc8bjc`WK1KW>Qx(6?2J=$TAmaYvwVV z=HhI&S?y6*%vbb!=1)ZfK&R2I+CL!k=9Jg>1Zfx+lKyGFwHVTnsI7Kxt?g!z#WL6A zFCP5;_%r#(-2y^HC17mvSEy6*vE(LeEmPXu&Wv!K&+WqC-F#NIEg;3EZMRAXF+b0e zOZ%4+^0`q57&Z}MAt6B(BNfGF=^rn|9I?gsHP{a_#9;q92)W5!oSWyEC-uXaOS~`3 z<8JD_Tu7%i<sv+s_>0tn7M;h|lq7oD;`YcbH0G*!{PU0j-~Qn#Z8_UC%7pNFG=YSh zkXRG)&2vVqcoXum3E{;m66*~U!so>W@{9>7Ga-+fkV;-?sdwj^FGJ&Q2eXZr*1*uf z*1S7!gUx#Y|0u%0CP9=~Wi6;_oE76`5TWONCHx3ftRyNSC<Y`!bB`};n9I%D^;))7 zyXJL!J9T_rp<?sZiHFeJn-$2{jd_vj@n7IeLhoVLrVl`dwP_pb5!2bybrf4t@6%#k z9YAL;CwbLAxTIF-zSPDAa(8V_65k(Ij}zH<7t#>m#n>fSg2_N&)8$g3`D;PDR-<V; z=eR5C_q(sb{)ZUXuvDd|#>r)KKXI(Yy+q=kXT=S{kKjq?ZN}cp;UCHW7{MPHg73Qs z)eao$L@vW!*}p`%2G;&E(0$wv7=cKYqQ%PSV6-Lfm|8rmFl>j|>-kUz10=BYqIq%s z{^*AF_)6weY_6IeumNDz#l=k~QSIuTw-n*EoV%UIvA;g}A$f}t{278zW0e4XUqLWq z$?l}uU&5=9w+Qzc{1>rfAnrN~&sSAkrDIRB;cVdNtM9&G(jQ?iLsFHAo6^T7pY4iF zo(K)YQ1@I*Kz3GYps1`1I1ENNU@3;^PfGOr5q(EEZ{{aPqJgnnFm4x&HNZ$-=pMfV z)>O!04R>{b`VfvglGsCnx?E7Xxtn~E+YW+4Zo)*3vtDpg1?NoSoaR268Ty`!ITBeW z2;&4{I1#3ii0<BVQZ<oe!8yvaOFkbOK=P^Xxwur!U<x<M=1i3qnTP`kjX6^Uo~Zt| zQ#Z*aHJ)6&0-ub22h4YWM4E0_zIsCF{T}pm1e9`udluZaH8X55o}%L-n=46&hSc0a zt|@_?!*ei2%2&&T+8j_rNTe1*oP?xH2yX%uN~RPi!R8Q*pdFqr2z(}65R4`M>LuI- zq};joc-)K3bYPU<@{T!CJHK`<uDVI`e8d~AwvE?GKGX@k+^KR4$`rW*C0Xu2d4U#= zzAdQk*w=a#d)J(5>g4|{K~%6yYK97Cb(NVsw|CA&^0Iq+se!XcokWgOqH@d%wC6kF zkPI_McQb?SxDd{Y;S<nUxnj(~+9#lRY=DBT+wxU0kN!c6n6F~U6?A`w4z}NUJ=bpY z3QEiEIaL*faQ7acpiQZN+Z9>&BJNk)hk*~9B#=^@>fU>Vrr~A05~Kre-kp}%xHhpZ zJt3zSmpB@uMbqCgpUEg`%1BT{(es+%>jXTde!pvI(JfqR*y>)4^0a|b+T+8BpF6Rw z>NUzEy+r+;38YU^f0b{ddKh1DfipjFfXHAtZy|TB#$GOVh@rbdn&`WsyNUL+LZPeL zF@@P029$Gm3Z5rrin{A*SW6;JxKR=<w<7KKZDHP>i!d~_sNzFMdzyE{?Nu63FdjvW z`v{|2(?^AETkq}C;2FScOQFT)x@{x9QI|^O2>@;z;2o=dC(#$~P13&M^hJ16w6Dhp z-ym<E_I*R&aBq?JeFh&C#jsQQq^D=wKyQr(zYcKoO>lef)qp>pVY4-FAz-Hl+z!CD zq29gPcQ1(!_8!!}o9T=6c4}WOeM7tvi-qkf`r^EC+E+y12ydeHEu=5To2-4a={w0g zSNo>H=Yb_YwoP$E(drY?|D=vpQ&G~w{yhhJdU%J9`-^Q+-ZC9!Frw7$Ow94tYd=?( zOBx4wf1|yzewcK;2)Ftu33sEkYv@sk&KtP|(3c5KfD6)5gys>t9Z(dnQI|0c+GeeC zIa$Y8w}<1KAQ$&1%C-L!3^?y2o>fs%<}4@|yh!-xR+KL%3{HWOR%%HB&Uk1)adJy4 zs$7}nE)zzaMHN*=reAPY6qJ<(;V>=ICWt(7m+Z<bugs|^Eq6IVoiH=~U|JF{J1ZkI zD^GCf2My<PM6%)_d{Op-wBYnp3#y7r%L}Z0aQ<2CswypCuG6AF7rrt`iFD{st8ias z`pJu<#^o$8a)#t9)m>HPEH8w0pN_|doMQ-xbjaVrf~wL2BcHMGpPE(SDlIN8EO3=p zl$(J@e3ng~0h?J>RY1ZP9sR_E_{RfY>@F`P3H!|I>eA)q&Z30OX?6+~GMq5YZWQHo z!Dk;A{H8Byl13%EJZF)+%4xqcFCnX7g>#x+i)Fg~x@mTUkqMf{38aygotK%OnL0Bs zGds(8b0XKF%i^?Po_di3KL)XXPb&kouwK;bfpcGJgwBB7E!Ot7%gj|{-MTnvCtzHW z2cvS-``D+@zOcBpZIgwgC&OxhXVZ->!LeJR=EQAF*!IE2Tv+A}+>d46a17;b>et+( zY4=A;!~ADp4OTK32~q`--_AA6By_VuDhT0G^z8c^aT(-KjhM>Ie%<#0Hlgcxk8X}x zDno(Yj#1+M!BG93$R3>c8b&c?o-0fAUJ4|xrq>`Xe7US&f_1xRUMGeNiF!YyezZr% z577aveG}pB*r+9P7~^Tx#h@oa70wnFb(X0E_~8|;1HgtI?la^XL(U4(uq9SK2eFx} zgOYB^bf;SOE;D^T(latmr7y~t^#<E+w!D(kYP(ed3k%Ba73F2C>{mJMg=px`B71RF z#R~h%QdbGaRac4Ao?V__?X0#tuX9RAK{`-=*z(H@(8lbp3VW4vd1*D;zP+%byxN8K zVn?v93p7_@UBIPWc)gF6;nOS3%HYZ1nqjDGFm9ea4SlCfummO=A6ZAVsdvzgLN_n~ z2)NCO_D2isDh7Gvrqjz$u-<e)C7NNGW=w!=GVE#%WP@QieJW0wpuVKz8ZF>M*sjQP ze~?X{ccHz3T1ciZZEA&1=Wb5IGGxt+$(QIDZiML)v~4(iO6#f#(A|1)#ax@Z@qHNV z|M^QKvzvuekAPG`83b2t4XV(aI*WKJ5>rB4UyDeCbTWKB$4CY=eOO9QZ;x(z4`TDZ zgn!$HFr%>lMCXbNLU^m6D4M93XAMDeqmT%cDP-wRMEA_bG^-O2#J8!FFayNIj%nha zDFANA=mHVa6fD)qMIoa|E?#&Kxj1mx%*FEvNCnM>!qS>(N#HzqBttC-N!B4rI&X4q zF)uAfIuj)w|B^t)Vgxt(COHivMLUGo9B;!zlfeHO11S1}i6*`v3=;%A&klt5G{O)A zAxKr>LoMRvUe#!kExt^wS%NCNXD4#n?_a`|8*JP&PL8Rybxo|by*Q!Pb{M}TxTEt@ zS$(rBomJAk_e%i4GSG;_m$ZUuJovi}w&U{h%R{Lgo0lgMpY5nOo!3EUWZtaOUW9Hv z7C+sf!?CG1oo>(>s`Hdq;40wU5cA6E)ls+{6VD<}S%%rh(^yNmaQh=>95S_J+m^8# z<M6EP?72)+bbzugnO|~zf!TPeeWjjGtLp4(E&3bG^VRu}p(a^7Jvdk=re&N`T_I{G z=%fU=Pkrz>Fx#i!5b2(Q{T_CO6Tyx9?59~k>gbE0*MW->QKef|Cue7vk;SM_6<pM8 ziE<08e*akM{vR+Di=;1a&HdpERIVSa-f;{#r?PX_+pI8g=z&pTjJJG@v&vd6rY+s$ z)=i48uSFxRQ&6DNHW=s3qw608Yjr9LFM|+#3c$X9GR%0b{Q!ca>mvpGc%1fzLlf0& zM?8je2L!CI-=N<3&p_ZZ1SP0SUp~^)ni6AcyfhZiOVY@=S5$Hnh<Z&>)H8L|FdcP% z->9_44n(E$T+>GPJH&Mg$6-*A*Q_boE;dhf`M+>ldZ2~M9Qb%6J@{pfQ_XE0#7GCb zCN0W~s~Cl7m&%?hms<K>4#M_?V&7z9<K(g3h}N#7Y0f0M8-oa35=vlBKLm2m)0b&# zy(g<irpatnXzbyLov%)VQbDd~kHJ9jE97AWu+SgDNL#bCjgQ&pf6h)ypSGqQ5LyC4 za}>s9#Ks&Ty5VN<2~*oPeAp&LDA;)c2ZDLOP6vsMK%e$#D-zl1yIbP$MWgt2$GOJU z;gzhDXS+u8m8_Hf<LlI9K4>(=H3~3)+>QbM(L2KZBX>mjN9-8v9}1<=pdEw!F!n<R z*^j76pxRgy*H{_55eN5l`|F0X*n@|x{PJegRj7Hjhj6H3u{cnfbHp(O&%4sG>qkMG z4!102O`8NWzc^H*^Xskv`<`Rubw9LI`heXq<n_6im{)&+`J7b@pR<bQb5<k#F_82K z>{AWh5sAzU3C_$Fh<2>Z@Byl-20T9Hs;xbQho@E^i{F_hztIg%x_s_G2G1u5Ciim4 z^AOFmTb?l6`CVPtz?B!kKKc^p23r+=*Wq_HeplgFj$bi;JBFcnqEI};k)sjFQ8aQC z6P%-)(3>4ANBTV|oLuND_jZ_GN%205_|TP!H6-hlCpAvBTWr(LdoCwX5)!MPH?uC! zvZb*C@AORq0-h*Zv?(<P(Xk1UN-|M;GeUQn*JCb&iNh##xY39NVMOY<U$Yy)czqDS zR(*p?i&uKB(+tMqbw`l{!){#TevxKvQ$|c;Sk<uT`g%y-cbMWIgzgp3^$c2>51HOq zyuo%DKQDfJ@Y{voe*9j;?;w6ZER68Ih*-rx!to3o{L+k_0gssh4;TS#QC7?41)KML zLUvUexMu#zp_P0pl0SL*2HRr%F2pYrzZv*t;g^PA9)3Su5#gU*{3HI);=haNpDO-y z=${;t*qJ)9cR!QFcm+3-entDXiqH2bKP_JAJ;Phjdv<wN#_+sB)KGVx8E|M90@5SY zh&PV(%ywU-2g7fklfh6r=j|ia#CMUg-Jt*Br*Ie)w=p8N1XCh5**4;q{Z@anj{KyK zY@ls2&^W5z7Zkn9fbUbak`pMi%=;g3Rt&Ru%z*RNz1)hHvjq|7{@@>(k4|&G?%m+} z=L_HfIxJd5YCRa{8%?QcFantU`jH;YF^oBgCpAr-35coNN>kmhhU&K1>9l(z%SAcz z+IvurOx5mx&|RY4JLrByyC0_euy)@=x4lB*-a>bgcGn5McCUn+tAi-@jsvCA;oVDk zt7=Qb1r6y@1H1<`UbcnzIPtnPUYoj~co|UxNZ}4mA)-<!G#~^=dRkQdJ6M~f$9Q82 zZ&3r8dY*Rw)DHKp+WjTnd$s!$x}&ZY{CDV1)9zR3uF>x2=-#5;+vslB?uY1(tdh9D zr#nTvo9M38?)7wU)^0c5yS2NNZd<j)y`1hO?VeBfGVONIU8~&}(!Eu?C)0gUyHBM% z&Lwn4(Ve5+L+IY9-A7P)y*su08@ju-`*XOPlilbI=Hed&_T)&Y1O>261MWW#C6E$R z+?EnyhPZS{Lm(u~h*Pgat_g$;FhcIqA@c(v;YP?79dbb+B*F;UsY6Z<gbXx7_Ue%E zK*%5?MClM8rn3gugN=|b9rDjWNTd-Gb)97WsX)jOBgC#l?g@kpHA1H7koAF(VMfSo z9kM(S5@m!e)gki&A;XQ3N*!`;AjB4?OQBweoEQk{iPj-^>5!giE2lQQ4%wnZJ`V~> z@$S^XuH&KqRN8%*Zu?5f`~kXCw0kezHQN0$+|66z_ExSE#5=%=ccXScjK=2Os@?a{ z-KpKT&>erh;MdWeqund%Uaj5N(EW&ZUrBeDcIU!Plbszik<Qo~Fw1&01&>1~!qvR{ z$p%;opq7ptg-l~5q4H<L(W<iaCj+07ln_jXMVeqv(kSuzb22gWfaxV+Q0ykf-OUG( z0({%eSl?#|{jc=r3;j8OkC%~wS$i1wR;P>#^Ok7;U1&etlE7Hp17&(Z=Lj96s{*RR zgwkN0qoF(0dZG|~gt(~OO{g|Cj8F+0%F5{)|AJupCVr8#I1pvJ9bPM1Fah#+VQ~Dy zipo{N5lg9%O0<_2R=CSu!6Yn}MYly=xTV&rtf)??c3%aIM0@{iOB~(@7SN*>Im?_b zXTo&_Re?Cu?Z-$SIoEloBS53HyxLh6Bq}IlN$wm|bf5>`0=dvS)l)&k;(fW(RY3i5 znX`Pkt7MuTqNkFa=}=bT_##}~Cx)b59TL&R9|#-~oe_TuzUij^IoDN{;dDusbM4dY z@IsS5-JS_|rcQPOoYab2`8~UD{Bsiii^$|XRNhD}7l{{|DFi2L$j#zuf|Y(^aQZXL zt4s4Mp|U9~sCFh)106+<ERbvMI(EFd6)XRncnQJj{g-Kl#Q87Np$^_Em%OUd701X9 z<;eDF;m(zMBG|h8nEBB5c^2>kbreE3;;?S!28w;I6%XR>lMXgn5}Y7yZl*99(+w&2 z!B0gS{15o!gY%JlEgH_TBanUw{sQy|MSUVz8SjIShq22G|2=+)T+smfVE4)|_f@QN z$SDmGNFRC3yy`#7Bcu;QVdhn&msJ!5btmXJgIExmPYUKi(DNz~wGZpMZs>AleF*Sf zP*fIF*QRG88)bTfk40Rq`vgg=cf6|qW4!DC%XsGm^SQuTS;nn5r}P+w?30ecs_+UO zPauyv^V!Ah$^LV6iH}KUpS@7-@8zwkbRtM_BJo8Va;&Iyal21ogEcJ6T~;RkVcMT- zZlkhZaL*L+j4oEk<31l?=2oV}HDKm;W-vW#`;zpGG@<8p2FJ@Tb0XuQOB{obw9@Lz z0#{*)z)b$Dsw#*kFoQR9J2@DJ+{<=oFf70Pn(~U3<)L|yDifM6#Wt^?`kLT$&27?P z*sN6xoW&+DC&N)}j#b!jGImRYb|iJWtd|xZxXi4UB1w=9Df>bTAI&FZZ<X!WipLVO zFm*dQGdNu666xQPmAp*u6_1(kFP2%KI7qRKsAx`bRAp5-SR#pbXH{xJd3l8^b44XK z>gmrczpkLHw1@-~?GC9yRoEQ2@Qv`<&VnMR5HJAQm4y{Wh+<LDfSiIV>>Ok7jv-kU zw57?xzA}B;ZdZ13Mp?yG1!c&2^@4)(<q}`uL^2=_jTsuA>nbR`#zK&?FRfm|dPmav z<<6Q)XQ9hk<ftenV4<_B8r$JUE*w>9rPq}fIcKd};;gD*Hs=+%N^~G3QsFKu!ajT| zb}NH;ttejLEQIMoC?E5jD=Mm1F$qUap|g^E?)0z}4TFU~aHEn3NfhEKE+}*&&0KdS z3&L4MBB}0bSH%j!W53Pvi^3P1>=sRU1<raL7=ITOlvX?E7F4?|JhS|98mc#*g_Gc@ znPv|rKHV;*XZFyXA(4mELBp!kR%{kQujmGE_I~k0NRvIG9Wqa~XtNYBNi^&<%)A_f zE+@ais6rPylm2+-IEKkwg0rd@>%DSriooKN^I}T|xuw@Tvjb}nlRx(F+!(`0cwk?c zY4v6r#=bC<y|h#S4P&32Y4xHS<^s%0&k97-tGLFQkn1c%>J}8mR#kx+t7{eJVS)Zg zZ=Tz=A&1Vl6!0{=EC%cq#av0S`$Z>axFo-NU$5>4F<D4l9WYrK{{;@J74HzcgJoyH zhT-UN>?RMw6)DgjZ@3MM+f<%XnQg2Q{};9a)Z6_e=4-t3<Esy$(|#HIb}i~g7+qTS zaf>|P;JVs&gXPX3mR&g2qjqeE9+8p$%=5|A%a3kOUK7YyHj!=y(l&kF$hsCN+A0&x zweJ5SA7)!NI!`-W4~m%gw*=*HL?D0T5yQw|zy=2PC0&iUf|+k{!t%ks*4#YhSyE(b zDgfBP5hIc7KS!pTw*|}+7jJ<S+G*9=qTg(NO)O8Y{#F#1Evf+F5X~fSEvV4grTZxw zpmgCl$oqdo)Omb}M@XMS(pP}AwHZ3zh;kmHwD^W0$lMHt>Xv!`U&)aB<o(!*xFAlu zA<ujWw7vHFs8KF%V>||^rz(*(^Ihe=1%@-v{lzqQjn>cy0p&BsG1~iEda)af_lwgb zr)Nas!n;=0g$V(K*QUOPV|u$>>zNDq0m9|7np6ii^=Lft0zjK!#R^ZGdJ>)`({iG4 z{}00+B6<q;OBi++!=~rN2(dw_^V~aeCad2v_q^x%nFW3lOi7KiSt}!D`>(}21u!-L zNl1JssHP{V+in8?Z7Lnqd6s)2&T@Cdo`u&_p8*(l2W;5JY4N5oq74OxgQ+dvx%7Pt zGJ<#n^AvsBn|F0yOp0P&^%fA)d**e!w^~I%4iQ;frlDVG@x}a=MUPBSXAjY{?6FT| zn~X)i>9(f?xiJ9X97ovES6oB!8;Rc-e>@C224KI1=R;fIh5@)b#c=Zx#p4Y(cT)$` zZM?f3unn5m$v%T3J8gq0GSuGJX?V35d6TnllnXF^S#M&%+6uc@xRccJU5@8X(Z(gi zf(koWlf22GL;H{~&`r>6XrFos8TQQMvmeqZhJK1hk@<wQx7bsW&Rc_+PInWY?1MGe z4L4JUaCR#@CfE4Z?TmxvjatCYiH8JY!t@~`Y6!oCPJ*Tiv|*s|9bJ5c)Q#<5M2qzn zff?mM`aD%GkV-<%B}XWVIhZZ#qfHm`_#|wO@U|0REP9toLt=yl(-5j(gB=`bdeti5 z0ia9*vmRmjCOyvb^;{0g8CS_nGz2pZjh<#}=iuAoizHs)bv!BiW7v3E!yKxK;9<%t zf2=Qb^Cx|v+=qcaP<g&-T60)V_<r}0Sli)(P!?rgomrGdhgb=KSwN*Yd88g;CrE?4 zKfQ~g1b14w&P3&3%G)R&eOPXz_?72|#6?Z+!*y*jMhaK5&umi{CgB~!ncK!l^rbxH zgMImKRF=cI#8$CAOG&AmT+f?GGw*EByqxVFJ*X$WQWb2%sB%N1CAiDLTa!bnu&or> zyN`)rY4Z*9x?P-0F#rFHep6(}_g`r@*8ww1%XF@;-jWyXC`UKn3xFxF3t=p-YQPpP zD^YEmJyH?XLpRbyuG5oY-HbFI9ZyE3T8a!pADx~w-O)({IlOY&r5;9gaGfLOaqoE# zf;{hncmTZwzO3HskbBQOUQ#cu=tWq?t8gT0iD{D&=Y2FS_A_te+v0l!ojB?j?QO&w z@qZ;N(!sU>#u!<IimFtmYSZkx4qA4eh8$%e-riuzQ4hqg17K$98<^RvB=F1T-Kt&% zb*XqG<au1Y``e8t$^GfuPSoK8o`Dp*7A_JK&MuWop^E9}X1@BJJch9wuT0d@*yER} z!5dK`S0=V*j0#-+)eH{U9RGxd*y3CDsMIb#rJ#*B|5x&ox+OBv_PIu%ddII#foQYb zHI2INls4$P!y_GK#ywn<<nkE-ysP4n6|}3=7+r^G#?_??QC(bvaPdrgkV)>{NP_iY z7g}_S?=JLC=$Fh4Vqe%irg6zbkUY*$pgYH&%Acfv-g!Dic{+4+xRnAYG$@Q-XD@hi z!Z>%49<S07P2!&ohjGB-OwuKqu?O7*YvO&Xp8ZR!T3?TRrbZyNDFx$OY?!fs%_k0P zI5@oi0Ps4{HK!)3*}q1fNeQ?CzHfgph;O`QW*rvEqzuy&`(aq(^WrWv!bINcQP*Qz zJ&L_gqWT9CQEQPZfIYaa4WLT+Bv-iJ&&<`OOqHz)V=7L^sf~z6zTh^_gP3yt7NW4^ zdgPBHR~cV_61heli$Bd?l=>D?B=ryBFl72ZY4(w661oEzm#9P>m(W6$@m}saFo*e% zHd+-9R?z!YH`-ehy6sjq0NoWj8WfNEf{hU0&o+=yl-0$2j>t6STZ!-%-@HGwDnSI8 z!Gx48`y57pP@=PNJv#$sYs%$)maJLdK15?jk;_TZ+sJ-8kCMvK=0my|P49m3Cc!I0 zd=iW9#`L&;geZ42Y9Yp{$2TLf^symjJyz{O?NhfS$Smuzs$LM2)N1)ADi^*Y{Tslc zA^oM~+$j6jlmxTRip>R|)qVt>2o8p+2iH@4F_Qm4ef<>0XyyA$n5ZEu($1b6$E-y3 zlNG72Ix9H;jwr&>8*msLy-J!P^&tv;*vUt$I$7B0+s35&$Ef>oR!``y3DCQ~UwXUI zcYxj-waiwe(GKT(X2&$VqVI(BoEZJL%cAOjiCj0@l{Tl&KcH$d|Bd6nIM*5eC3XHG zcq!c<?V3^NFLlppoFCzL^Iv5#|6jck|D27n@%tm<-&-7UkAJate@OQ{?cTo%?wQ)% zK76xhgY9EN&T8HQCnPC@<HImgSN}pAS#nuR^WLC<n;Gzi4nTRPj7?{k#`%`m4%2{s zVL_SODa%g#JVSAYV3}j!HObz1FzAPp&~B<nu}(!X;nuF3Fw6WL^Cas$(Llr%g%!TK zzl51vdR$%Cgy<VLV`C9kQRgDke*AvIZ)np7+e!E(;&%~#S@>OvUnPF)@w*+rt@yow z-^ciM;1_oD2HPq4CE+&{zXkXe;^)Gz0lz!(dl<i`@p}co_wn=N*NxwpTQ=Ax;g^ix zJp3-huN1$P_|@Te8-DlWw-vwV@hdrue?8a5ltkUiEpUC2$!}0Ud>>;K13(<$>NE5Z zzBe^s3IT5u@SFzBCEx`DwrD^R0b2>UM+0gIxSxPc8gMHCHxsZ*1GW;dhJX?c*h@ee z0gE)CgMiBjNC%)K=C;0Ue~5DOC1~^{gsViNpFs4Se$byF`cIf^BbOyaKY{_yr!-(A z0fz~A7l4w@M*L^-HKkO}_{|#qWuiYv^hY${AOTwl_?-rH6L1d!zt(`*+X2`_fLj9+ z2v|ixkp|2qpoD;24JadE5dpI_pq_wq0_13Hi+3{t=MiAn7*7)rPe8N=d_chQ1RO;T zMqauI7(l?68W3{_0N-F(^nCz8NdmmAAXD)*vtCWXiiIB5(L~=x^v8AlA_BG%aIXfe zCSWrG9u3$`z%2my*MQ=)^sT3_0={<os_83$+Gb&lT2432<h-2>SxjFBd{MuFZw`GI z0xv7ZYbT%>`S2$oIEB7M29JTSh`wLZ$Cdw0^u@r3h{vnJaG(oh{{cghz&yAJXLWE; z4QFz=WooU{=pioW%$WfkQyVW~!x5HRv0?=%K*_B)h8TysZLOEIz=BU5DYw;3sD-<# z+*MFxLUp>lI47X|x8qD6^_s<{=2<=Ji*lVSVCsPlNPEKg>EkEZE#?qL+OYbuji2Sf zIl}RM!eBaMgKD+3q6m@C42{gVOh3(SY$MvS#SkPVhEs-S+S5X#OWGq4Zmu;%i3Ne0 z@lwkws-5;KZc6vzi!!AS(Y_+knKK^qBI;#q;b=+OX*wV@QR8jqz5>fj9~IQaV(gv> zUNpkS=goEmi-WY8=J>Si5Frsx{dE=(ZB@I=sJAAJa)(a3++aUpe8Tt%z2&ZDvtmU7 zM4Q-;Y$UzBzUjd-&V~UhVf;m*k(jQ;$xiRXBlY)Mo>!Gs6kd}s{_?(YNmur2cnZy7 zN<`;}GBN6^6~gpbe&ZckX~78+4i%4WZoyT~GBg+ZDWmZ+royHMZo<ebwt%q4v=?B1 zyrR;8vt5{a;;Y>&2o`+i0f&jo?X#E#<o~k1d0@FNsw#CkC(9W;Y!S)EfW(LSmTdvH z@p=VG7~`duVZ66XEwqY?d@_%E|IB{XDm!=3G(T*o+(*N9nlx(SvP|>Kt8w0`8l6Rv zJ-wo8CAM+w082VpzS>NfwN)52BOwjWTg?2IyH{L=J_l{O(%e|AHfd3QX4^6Q6+KUR znqAsOnD<%p6zWrEm&$QN&Qma_-IN*!Tk=TPxT7z-ruiKuQ+|t%y*j33HokbB4|5lr zx*M}(bcQ9%`UzXB!+4ZFM!j{PAR?X%sA`w?f&}wJIa&3}Xx}Vj)CU}atg^eS1Luf| zn{Mt;2jQCe#1TqXA7ehYnTh2iF)N>}cZ&+D%CX56lFt)d<B`wvj=t<p(Hx&*a_pHC z<Bhu$bS{LvIHzxIPJ@@Z8gD|pONns!4`wE7>HSc9bsp_V7yGA$?lL**W-lmPS+I&n zJTdKr4FRfE1yMvEtWS1hhFR`($|-8f=_J5m(&DNrD0JC%Wt8b_m0ONBOI)@?Qx>RL zl27O$&V6M*{<xW9sD01)ow*(?Nrsb4LGF4Shil_XW&_Yu9aWMi0bRWH@NzefnYg=3 zmI(;=wMME-1k_nlCLpL5xM>pE<A!Obm!+iEK!Vm1ax$@SFDdJp%D$KD$bolZfHm(W zW&YUzUWOmtn1$Icw`(`y?4(T`?%C4KDu}H)qa1NO7q9qv(qpg$#%g8KYIC*1Geo$Y zqj5G)|3>0w4k{11Zk2UVtlD(Dv95B%VXUjFeiO8=61+Hd6@qyLc!`Pc2;k4^gCC=2 z;1V!dU!5Gl8xxF&k`SIFgl9fSu<{1-9ED0|tgCy4FA51a)^YoAiMFKk)NL03+wU;> zH&@+7fV8HJ3~NgnOK}1mbdv_w=~^DOYmc+JBAH7Uh}EtgDZV&W44<SiKafV2m4+!x z<k`fV5WqX5AH2~BW-230{GV>Mc>jTNHrKS0$4K=r1WWpF1@PVs!ZUNZmN3K-+(zJH zWhlCZ^Qs})^q6C<vGGQPmZqm9iVrJ{)(<PB$EZhKP!%i(B|M|>B??MiX0nnVU?o*p z(XS@RBO)!gVsl89A+FX9#i)8Pp!HYM1gY4HQFDL*?YFoe0|Ip9-M7eH@Rn{ZMjZl# zvicNXqk8V4_$VT?+^`X+b_ret_V5f@Jrs!WfEj`HiaNI06QN@(VGPl+MW};S{pr}w zWIR)z7Xsas=jYc_p2yT#7&^9y5WP!;x(s<#V?f5#yF{oc_@uOcyxGcLCnRg?S$HD> z?^(fDjWuLQ*-in!q58lLjAioL1ZpO)7YeV(E_<`+gY|(i>aR#Zm4l4QYm8b3pYS>- z!0YS~UU3*mc#Tn&7Ju?kfF~mkXK&8;<c#&~!u!pas2s|>17O}Jo&&&R;1XRxcN224 zGOj5-%ImrpgGenpNu=4P7U9&76n~rA%W{*;ZvuTH`&D%B`SU$KcJU2AxQ?$~8+D>< zIR1~3joux=@TA)7x_Vqg8y&W-Vfqrqz0|Ny{1^v09X9XMKVV>k|J8@UOqVAjzOg3K z(}rEdCOpssuN(r7QpaPagp)ZgVz;S*m>1&m9Nvy-VSGbam$z19e1=)~_JJh)$sa*@ zH(k%%%@<813ew1kYOIWG!WF8wB8Iy1PGrzwYfQCo4O=43O8R@w2?91f1=HcR#)0gr z<>JPkqRjiVj5!#``$Ep!rcLUzKhZ7K1>0hu-DeJlwQI-PTqAJKEIm<nSWm^_YFJI+ z$mt;vqOLwYQFYS_0q3)D7Aeu&jkxOW2Sr}ED8i7}<+xK0n}S+ip4?cK3=x#X-cRvH z^i)Qb#KXxkmfw;j{KH;^m&~j5-y!qWv30m<ir2_?dKs!}AQC_BjPLX&(_2ajwW<xE z%02A!QW{(3j(KPwuL4XqG9|KLPq!iqtweaSS-?9Kz##TZxy|b5(1dLVNIlMvcZ$1l zA!%bw&;<a8kWr+sI5xKUSnvIT{e*v8KFpRbgFt;<4VXEe!)duWII$k%Qj^B0c+Vk> zkuRy-GW0fS@e!V18hTv0IPYj)8kB;*6Q>`;D<FOz-L!E}G0cOWWT)#_+$2FHoUX(! z$vbKWa*Zp-P^aUzhWVrA4Es*cx(M7U^7y$s7wdXvzI$m7D3fo(F;W<maCCqI{65g& zKI;6<W`&Xd;FL|2U1Vc=LR-3>xoS)2MdSFy@q@<9oxDa4ggCv{aE**bX7_YAGsi2t zqOfUU&6h4k3RJmAAX1C(eRMefj^3k}sNi=+QeL_biw)^-W0ije`mnz=2KumAbuWCv z^NnyA!$~~^X7;y%{VLwo!mP^%-gkdAGwgZ4PkT6wYdNg;5cL46=O#9DY>Ha#VID4< z3uzCDSe%r^1J`H|Q{ZHK;I||N|E%_KJ}YK$dtj(4fn0QZm`m?snPjLcQ0?6w762A# z4}v|(iY&Co!rP}k?B~$;@7lx95DDAERX}X<O+~-`|66-VE&ccH;XBkYX%EYi&>p_I zvETM^CUX6s+XL)`PIQHzyR!wi!#2F_8ZmvBJA7*xd=U+AyT1jzDWz9?ZTQliC=GR- z=gK%dxa2yXyWg?u3NjTN--w41{nzSt_Ysb&7o&Ywm;C$uoMz@{EAw+||M|HBld%7s zAF1Dbi}76Aiop^}s`qan3{>yh8|(w*>X#?c6~W>O17>u?gK%?=gx>!s3?mu`d$%GA zz4zaTZ1FBt=`&Ms4WU|g5S1NE5!gr}3NP%4LU75;jG=q~b~stv`7Jq!f7qziz5i^f zc3rBL^NJ4c-=-s9O=(HpI6EGzZo|qd1y`Q2W*S|0mrCM%U@-gb0gbrY$Ld4w)r8ef z^d2p~JJCrQH8jZf=vZUwzw5I(*D(JupZo@$PcCwssBXC(8Hck~&4WHi?l<XQ-d{Zw zBJVJf_a8tLSHOw9o8UI&ee*t%cjTY7ywCbWA9;6t+S5~FXSkMb5}cH7GQJcn_h8i5 z6cWTao?j8{mk_Zf*r{N+k6_>BWDJ5G+e@(DgMAjwa)h_|E<#TlB3SnM{};JZ<|!N) z@h5WYU_BMP0b|vE=EJ7kFnY*7=oT2!!q|j^(s5QGc!Ql*r(vh%$&KQK>vkAe!BT5j ztE0!J3dnOs?V9hx+#@}&ftZY(7o&E0I$$$Ji1Zzk1)>cvnjs=yg@m<8Ii^*{;KtQU zta_;UXb%Vn>Rud}p;=dA9Yr)|BSmCY%<~XP`Hjcu+TuHc_U!N2<e)hxjW0L`>-);} z4)%MP(8@(t8IPE`M`YZ0xf;<u{{*YjEo>lr?VB8t8&mCVsWR}krH*A;fW;Q|3k21a zF9kof2vx|@0Rs{>5Iqm`l#!^mZwDrAUxxtOy#YKGB4=V&HV~6j|4cO&xrY6QcNzF# z&)>~)6PfQu!GW|Ax=f-|y+YP_Z4};aM)kwDu`;G^O_wdYLGI6x9<kENs|yS>u`D6l zq4jEKf^v)R;IF}ip&+5b6Z68lESf&Ej!0joZA-M2G9R_1BqoXDmNU0qYD6JAS#%qL z*^^7po?ZeQ7%ga0((PWt$r4OTVo<f+^Dw0n**>vehLG{h?Fi(yVJB>%mLVYsUv^$6 zd$GY<27Vh?#`(`_t_=zr$)NcNk{Q=c&36Tb{m_iC^AKi<AqSzX8d2!2T6~{2uxfCg zLu*OqpZg8e3F8tqZKZ8#aJ77>JCksGAb{~ODYo=tIi}JVFto7wG>!J8#&cyfsBtic zr*e<1ielfEo+srm>{$}kQ+Gj59h^W`LRo`;z6K`NfhEsTln|~pxRltfssqX?Y)3KP zTX?(?x(AI(>%<bEs2k7%*|)@FiGvKbfEV(4tbT*#4jn0%HG&sd*G$H>Vu_nBiGpQl zbgl0=*U(yD1@2Xum6+1<G))6>dnxn;3ZoWQUh6+a#M)H@FR6RAYZk`y@VcFY8+NYZ z=Y_6ttxte)Or-hh-YGPoic}Av?x=!w;8?spR~^-_?|owEAQqYP<s-Gg;eeoTeI0}- zjVmKiOGFFv*8)_*46ODd<RXfcsK$&ac(9(wO0d`LR@S$cexp?tl7FzWf2}crZH2>_ zz_u_|OCLhLn%E5;2AkBSnYKB4HAa7=+Kn({?qc#jGnDsBK;LBihh@SzveGY?p!XoM zX6koDl|=h!s16MKqDXZm5>ylKKWga{B2|o;m0#9aS?QvX4I2~G&3vqYg3Du+E`X6F z_912-VmAn5rAU4EQG{IdD@o%`Q@dOz9EqOtQ*fug=g7I6GW-$Q!R5c78Si|WIu?xO zhU_BLR>Yv}s4w!o`t)iTgl!K~I3B<z0O>}k?I2?6=}ZwGMUJ=>krl=e<jNG_Q&&QO z|F88$lgRd=)q(X(g!%wJq230EQT#75)gYN+?YMC+R*OG3LLY(ZWxP?fnDfvGwU2yv z)UJ+?u;FDjYAk3Ebr1~d@No$DkN0G;)-u})cT4u*0oi?+s9w$d>nQK2ZHOZBf7n<& z%D9C>Gj;44Pgp&%*uHH<Z>DXoZbrs1H{?@=)c{((Ulw9;)i(k_^#7=krlA$<0@uW` z@nFSa<!Kb%d(;5%tX{amcoWl4An(E=r;&}g#D)$uvnZ~Ol2aP7Duyk-2JTTWG3#B( zT{8L>l<p#`qH*JX&!&v1jaa&7#Gv;|?SVwyuNgU|?OTMp2@zT6gX#};i)Az-j{-Ah zP1$$_5@7R`wSrk!-bMjhb>+kB19heG^8ZU+=|Ljud5|&nb*RJeNnN=I4x_Hz#Z-gp z3g;G3mW@T0ahVy%!8XOa6Q{Skp$F&j2J0xpD29g~W%vR0!8*!-8}oXCjxxN@x?&z> zc!Od69c2jEhwY-o%(inmCcO})Oz~bp+<#-w$T(bx>{?~y)`_@AZvR4>qD${xH^15% zS~m}4!lUcvw=6Bz%_#LQfS3=cJxfp`sWDbH{T`87O_w7a^ItSSvzns6u*QOKAoZZJ z;O821ERbA%hgQ{?5!+vXiatm36sx{M94W!~;4t#Ek7OlJY!d-}XF${W9P4q2rc(~N zU`&rtDX$_~XgYJY%W^>-xK%2DK-2jrNKZE$v==pjZNJM~LTudgiOZO<^%bJ&9IP>1 z8sjIteMn7bg!+-j?$C5bsJ9xJ(-_@rz6cLi!Jg|QJ&U+1q|UP*an&`LV*P)m^W?b? zv)NsSYT|Ln;C#S*!+d|S=ckSNtoiOJ$Qt)ctvu4xmTE_B$4B&7)NLW#H$*Ii-G9>! zrrrM)p8Qzg&xE+me*TTctSJdic(8Jxx=V&-_1jAcOR8PdV+-DNGHsD}#n{j<H0DHM z&%@ATC4`Kf3F@@V(6&FlF3`3U)L!_cX8Z#Vqh>sdN@BL{pf!Z7A}meTJ5QPwAC(OA zdrbPMoogI`J8_R7C!*txP;oD#oV1QN!rOs3>Tf)t60Fl&wHGM3_bWG2-3goFAoW(H znuo_DN+O>^t!Yu8U@w!)gA-9Busw?N5Sy@fJRQR6fi$7fm96w_mVb3*K<yic*lIn8 z08#tK(_5t_>H+moHCLp%2C#sdOR&?d$U^Hpc>AciIyrV~HCJqq>fi(97>sJxHUkIm zf1%w4Jxl{pv4$LLzRI;Mw&IJYovHDt*X1AM(9Iv)Z-}1vnuVw-rk*#|laXNRd6Uq1 zG7{8Ds9mV1sZpk0Hv)RyVq~kg-e<RGT@>`X&js|lm>}2wbfW04YJVEjuSP4%&}iMt zN0zw)euUcOcflyzae{hb(NWkD$QahonxTqoh6r`wB{cTI-kQJZ?qxlDf#5Ym8rBqn z?&Z}k_&VhJvs)RXRXzP9Ai0qw_51Z86})cP3>1}$S=Ik&-4N6(INYEbn73zD%Wy0m z^(EjDllI1yW7{&MQ|PbDrp)SYu=ltp@=E`d1k6dEr&2G~F8(OY_hURc3DAUv<=WA) zVgcEKE;?|AAW{uLn$n`btg>44As5)veZA-X=GA}4olSS)9~#wNYovQ^QPs6QwC-TN z;u^2_(OrNfjP^UHX6HDvW-eGTb8&XMaUDDLES_E7mqAp04hwTRSVUUUz|Ty}%*~mZ zmpVH$Yhm^rhYg4wMBMm5Pmj4?<2uZw1=||$*r$a(Cs0spTGZZk!k+K|1x0`++{S#n zRo#I}NnKai>S5EC4(f3YM$>kGZ@f7H{&YW0jYy{Zr};O|>t;WRGrz`Bk^|3}9oo73 zTOEhcY;h$z)*Br9^E;pJMz9)#RRxIRjlpL(*v#jPzQj3BT!}jf-A|L_U=EPCrl=C+ z-Scv$ymw9gO*gAs{y{9so8u8zP2v0r>+=I7|1x_owq!Mm-3U@kBF+|g8gO^!5O#c; zvJSX|SV6?^2k{>F!4gu2bqNyD9Zo6}F{xc4k*t&+6NZeGX6ck}J{e5Fx`cVqDNSIc z-LsmJn{~{_d5G2II1oUH?8Qnf$vO@+<sVev<fCda%bjWr=NkDPn&vw|Y1p~;VjgI- zfIAt_%2J1VU063_{7C|7_98;+K$!n{L`Q7(4~)YIQK#{nf6(JNtZJCB<DfU0Lc9e6 zmS+X08lg*!&>V(d%TPQqdnn8wTBvatrBJA}@8!$G(G3?t1pd)Nqf?CzWbI<k15kV} zk{f4`^N0H>E^j@7!%g4-|J4NkhQKaJgbDj?FtP>k5duFmfnolXlBWSNtJtO{;pR`M zB0cWTKIMEF;!(_}VBp?-?|TiljShdw2Z%3~;ozoxzlsH$s3IskbSZ<ybD+ub!KVB} z>L<kNaevU1-;REB*>xOT+gXJ;^e7uhqYIaVrX{bVPUBuo>~nUha844ifQ`ai%mDM$ z{8ogwrp8#$ewBQIHq+#2*TzZ@U^>L1kXmo`TX<T0bI?`!Ke8q;41ttoTuU+B?2Akr zJ>DP0D?<RX@PgfT1J3>-%`tc8;<?!~(+n7G8tGk>nKygp+&squM_R69=7QAO=$K|3 zIP8OR^U_jh&YdgtsVhoNbEM8S!lC)JEr9thUXWV=r{GXXIWuz+NBe1aX!6T@K42eb zhjAHSAixbC8i)BT!i_EXz`m}%Ep_%>^mg8u=cLQK6WynGs&;RJTiZzU>_lMCKEE87 zD;1^TLYKf5ahmq2z_Sjzrp=v;JJRI74q8rHcVq#lbs+1BttEVD9xiimSLV8$m26x# zPNIsCdQ^3FPL(s0&mxqS4XLg+T*Cpz6?}$oP<3@$MY$7WdH4uiAdf5Lh#f*}3ur~V zt7leL&U3q*HK`@e!fS@Pt1V=Nk)Y)t<Q9^kms{d2D@(5^!*wv3X~G+n=(cXq8&X}I z=B&QPRZ%&tx)>L>RJrCk%iTk(i=mNRj%#76fgoUaWh7iM*3PRKTwR=AQSM?8c;WRK zgFvOCuo@)toGU8JXgvsbdck!Sv}>&%QC&Q@qOhRMz}E8>Lv_Gw6VJeenUgHs+1}&H zi^o3RTKm&va}x%iTK}n4Lyo@Y8dB>Y>K?c)%paDKa*6x%`d8dBm`_D<=CV&kV6xz! z<$*#V{GW9%3;+<y(CM5(V8?z)YuLD%2Hlf{ZtdzpJ>%RFgfoeaC(Z=PL+~yZ#iwyL z-Q4TI`P<IMd^|ENXU~uR!yMc=NsZ}Q5Hs67u4x_>Oz_9`<VLZVb4O!H^2Y8&S5$%- z1C9b<gnAW?)Qsfm$ZGgu^(E=&?nhjxc@TGM&mue;D4PHupzCPZj}y7rRluIW=_G+S z@4I@EO6;JCo{QvJ!PKM3B_0`WwwA&Jfxr%)_KIpHl5Fu!u0Z@?yGDkM8>j0z1)Ydr zf9n&dp}CLq-3w-(@#gGc@LJr42>P7pMYJ@_?|M3F7xJ2h&PYzmrgBJX${k<~ci1yT z8FNI*;@&y-G*(BhKiUH#YX_=D4;<-v;a}XWEN)El?74)>_EZuA)i_f9ig9sr8~0lv zJJ5p+RHq?M!~W>{edL3q-)rUsp-b&&xg)91?l6)XSa)<C()n7Bl5NZgM*`q2%;N1Y zj9@0VUJ?WC-#Wg-Zj=p*Yb0F9qH9O4u!R*Avl1~$Ejan5l6;q<eWT<Q$rmE|N+bCJ zr0Ti|LzS9oqEHx+2CyyxR&nD6{*#&Nsb;v5gUMzNtit{oC4>B{ifd)u(uKYO9_;_G zK%svIMZP{hEPX7?y}B|`?pO*1%3UvZWnb&mmOz2$m%M>O(05p%_`^N#KAntUbt&_S zl5|}_sd(Nr3ZPA0#woI+6V*f2=)L2nc}Fo;-h;uhxNgl+n`@vd+${X&G%YlWp-sgH zqRlj-&53NvjZlS%7gz}TFZ5k~HTGyq?>mCKi|5wb)Ss4PcD~bnyjn=m(j0(p6%h1f z`~3q|T^Z2d#y?AH3E&@0YiZ?GQd&b1-ghl&wvF6o7owm~dF%xa+}?WlFiiWf&FkH) z-5<hj?U``=%gdg1i6d3NtwcM1xrdB~(G^wp)G8;hX_GP;fv~`MlwRco9AlaHpr$)- z7gF5a+^Kz&kiIwaMTmbz-}J7!8uw`lP2TgCm*ZHF%MsRiYwProbo5D*gxm^uRUt2h z%Hi!>c)$l&3jvSm&wfer_y%*lyLqYhJ+@QwU#We*Pr%I<?fww%t8L8+K5w@MwNgA$ ztwQE`q9$qgcDi%4`_FXWq}_MZ{jzr74ENPx%@J)NXU9KCdnL#LG=-ov4JsnYra?<J zXuigB5vyK<W@xN?3EHATlQd{2LAy05E(q&@1`PzrDpM^}OH3kX4x@Rg+4FL;vnXbP zodcLPZ%8jKFTz2pN(}9|NpfcJ6J4+q$IC265G)5dUrR#VzV#$wX7<W*x&O+-pMbkj zORHS&f-=kIQ1fCE)bs{|p2WqM^iRS!P}kBNxp@n+7hC-23QlZ)IGI@)089AUA>ru@ z9FE{e#S&&(<fa8A!#ZW=FOYs_R<2_~0O{CK`-!{2F)w?e!%FKv#AW*nBxJ|)bB+wo zJjoN~X3@#jFt%S4i8ySd7EWq*zFF2G@XV|<$E7+x=cU1K_J!c(=FQA=1k#xs^d260 zL8)YBWMyWhXKNhJi&0Ke0_26Xvu4f%1s%>=K;Fy@w%O+Rmr<Xe#XmHcnx}etn%fEJ z(tzaz#JmE)Z2SYpLICuf_-4>ZD6F1~sW7J5iT1*3o;os|Je*`WF;{d|Rjdm5@Nk{s znOR<lKwel_Se;*4gfk_YP<m;NyRw>4c5T=Qx8BYpEVCT*dR!@3SPjx3CbMBsLWN;o zxn>D85==y0PAlKMw-G0^c+jX13gc2=(knn{o(XuBToY)Y>nz5Fig^{4iS`Ah%S+&% zRe^i4S6CMxPv`MOqiwP+<>7uo7rwdkH$r3H?p^k(2=dWqrH^!J-;K|(k8DjH8|K}p zAuoJ@j_pb9ev0l7jCgd%ye2gMKzE{c-$wVP+TB3+t=hc`ZuEdJ!{=?+psPNV9#9d~ zr9s(2pvc#Scrrk>$?-N<oOi5-oJq1d+C7eBZO!%YdGFPrVTfS5$A2WjTNwPJ4nB++ zIMFWh?5|(s`YumbTC^x#mZ#!t^@}r$iV|??FlrO333|fJ(EF{&0yof4VBLUX2*S7e zyo6A^q9T3ZuR6i_qKh?L6RbF_QvuqkcrP<>uQhoLgr(`bz%%h`B(7aFSQJ96Uz{^r z`4OD#V&i_#{&Hpqy2xuXzJWAQ;dxhhXd2UbA+sTy>5Rzqq)*af5<lxB?!mO)<CA{E zxOA2H>?iV^HLR|J&$T?y^cEOE;!FfAzzdsyI__Cd$64G2{tFqd$Oz+v$~?E=Iwx)@ zK4uIZhy9-}2vdxKJQ)Qfw582v%RI(HWSY#o23O16Wa%4Ht<T039&?jQ?Tda|<|g&p zH}5^v;GNn%6K+)ScKE!9HE1F%gaNX>2~Z6Fp*uW5gX{!N)u4zV&|D4r2DGd>L4WmJ z+Jmn9b20srd~wXQ>Pk8W3RGr|G9A}AVm!jgG0hloCQRe2YmS*&h{L>7c7Za=&0b*4 zGbEj~|A)M{0gv-2&xK_$-~<B#0+^D*0wySl0wy+KVgp)9D@*a}C)$;N5<@IYYfD&v zXeIxE0fjgvMoux{6t|dST9@O1DQO5GZB364F~OXZ76%L%a2wOQ?efJmF1TR8pmX2P z{l4?gyIMJ>f%f~Z&$*(Vxu2P5o_Xe(|9NLR+R}W^Go`-U`i}^*_|#p<k^Ia~z$H~L z{&PXkS{J@LwZcX*!kM?$mb%7d%QDyIl7E0%f5dU(IqBsuzG!7J`|GC5+rQx2z$=7& z3CDd3ZF2t=-8<#}3%ZZW{l|3AK4u*5qPs@!+u%lFjloygCFpG@B51#$m4JdaiFx+N z-{yzHQ^{u2No<S;w7#mgqoE<y9u|sq@izoL^VOk4dRYkGt}Iu!H)T_o7MZ$_*+C|i zT3*%K(0~V6!xWaZwm0FU_8a*At(UB`p~wy>v}C?$>X4P`GQUw=6Z(=OGw$pC{MNO$ zt!`*<ZLZ3+cC^=}ZeSx1r7oF4VT@1R`(qs1Ra<MOiBHhNY4WkH$~4_<c4juE61@on z6x8q851U22`hKh5SIXD_Ef~P8$wv4Js|2mUM!Ci_rR9wS_Z3*JY^hIk$V)3wx-Z9X zY`hH`$}_2;u11=S<mrzIS&tMBvZEgCmJlDKl*c9y%J<IC!HN&VUHlUEW?j26lRQ?Z z8=9Py)F1ncGBPq0hk>EVHn-NNWH$)UvEa7j(9BN!LDSarDF{_lx$ql!3|@r&BD9Kt z=X5yL73q*jiyVoo29w9g?vzL`6zRblyp3b{S>dxBK1=xQZ&~s`yvLG9_$LXUC;VZD zKUsLS@JWXU(k>PL3E_~It0j`QO{6~%$;)B42>mWjl*26|wL6mK&=j^yq}NYlcR+*} zyEq(2NQ5IIJ=u{Gj&w?-;sH|t1m_G-vCfP1w~kcfNR{6<wcY1PV|dU}vF3~P5l5<6 zbJbHsS}f8wN4oj$%PS_+Knr6c<sjkYZUUzTWC@%naOHO_$vOfH;4Z8Ya6N$`0=opf zlz^#fzko^t_cO!^0aFmbYlnl!7_1Jlf6otcj8TjCf(PtdaN0QQgK%AG&p``uj#-4K z2D$@`Z3XWd!H<REIA~-r)!GpF*}jYnX14aPi{3pCu<%NH$9rTj7}W)FS;t58-hzc; zy!HLzYK_ukAGp4sw>of+B#iY|nBC-HahcaBT!b^P>-#gvL5|b;&M>dErvS&T+I^$> z-c30`#>=DC=LWWlSwK@d#*Z`;in=SoTd)LSyeNMr*OkYLPdy(fXINs*0DX+Q$Krkt zqhPxro8d4mtEd|3<h<!d+<e}<9@namblTj>^VeamBR9;jA@6Lm50g9ITOw>3Xs!>f zvQg<k_YDa?6~83G9R;_+qBmf;|I?W38**1=W6BUdPT<mDfRrAnCdU0E*XK<em`e_8 zZ?Un1F=!huFgJM<h*#A;I@GjbU~m{yQ#g}dyf@yQc5w!?W??l33onz&8+HZb4-RQy zU!52nYRCQan>eHO^a1k;Ul^vW)?Wpk3H|YP8r&X^DG2XB*BJO}OGo22&ZoBqxmG`v zIAJyUd4FmB&?5PMa?plLY4{4=_*1;*>tSDMc_>*cr0ryvwI|yeo9Z&&I_9O071<xw zeAnc->oX?DD)}}-4$yk!yXS9Bs_pO<b_@E@-x;)@(EWnmBgjG>5!5H>I76Klv|7+P zLbJbTNjG>AuMo7*gXRlL2wDnXp-s>;0J*+ex)|;p>gnyus{l;@Y<IE^ty~H+KhJZ- z`e|F^)f*BvcJStIHg@P7=nn5Zq91D&eSCp~<xk#$*ZdYf$0Z8U>DT;Fezu96tl`JP z)9<f8kzZRcU;K#Zyb>Q?3(q#Gt#?bVkF7$}fD31~!OgzR2%e&neUq1Y`HQmL`+ZaP zUwqoi`Cj>M=Sbj0;jn!F>;GUBRB_V6eV*=mx$mKSi`*Zh`+(dZr2CxQchH^qdyBi3 z?zG(fbnleAlkOvOchG%G?k2hu|6p<7NOxB5*U-IF?pMH#xy51l3daOJ6T9z#P7$hj z#A5%Fp=M21!dFNLDk|avLN$WErBGQy-GaU>XoS#qL7xQ_^pC20@ik>@3+j?BE0UVi zas2Jtu|#sXt7_G2suQd6|ElZpi~m<G#4r9|wFtk9{FMsY(i>v&>w3_}{stUmAJ@is zq_7!3gr~ORa+IcfRV)rx2>Q5q7Bs|kqCMje7gQ)`T|7K)SL$Y@s#VC8<Gmzd)xws} zQCpTI7{sg*9m3X;9GH<;BE~C?CC2PvoRKZ#lnL96rh4YE@v>;^E!Dx}l?BK0QCTwg zcu@t5Ei-FUx_M4Xy!E)bt0&MK-#GGk^6oKHbev}>nbV{xfVyJYy1tleLygwZRMF{H zp<J}+?WibChQy07aRo0)#26^vHKl2-?Cl=unK3CVpT}!ExegqR;=(nf@YmwAtyJ44 zUDBVe9Ujf2F=YPPo&{d>m$sc81J>a=!e+dk1E-6VWxE*o87J^M9@tVF2*Y!Yo?f<> zb5B`|GWtntFXzjb`3q|=7s>a*2dx2WgRihw&^x|r&=8^Rf;I@+P3VB2te^=(M+GGT zmGouP`*q5X{X#b%r@h7cGMg8B`m1YAx3)*R2)vee>WjQMA%)ZF!}nhngvn%Arx_?L z2j6ey9&FTv^p#EZcE*T$tp0)N@j7bm*krwYPv38P%*xk<qpxVlhu|xW3A$dY-9>1> zpqBs&+T)qVJ+hhhj!dIueIoj?Houm<l-n?GVcwCq$;y9)cnSQ$-2LF6AWJos_Tp{D zm`IC6`k*6WZX1x&B5iUc%xwcww@9}*63j9njfqs_NU(^2v`eH{I1(yMK-w?T<&FeB z1*AhFJ@&_;@F>oJbWEh<js%MdNJWt*9SMdKkSdC%jX!lH%vk~wUb3O0Zg(W8I3O(& zsmGBpf(=M%k(wO|gP?%4R;24432U$cX^TiNa3q*aK-wwNg*{=GF>4D*`$YPIBjGZd zfONk|4>}TTD<B;e>C=vcA!a}-inPm-FzX0N6+bj>j5-oNPz^})M7r6La2IAksut<Z zj)Z14Ak~O8-;r=rWI)P_beTw6d@<YY7UAqiLS2lZmdkdxi1aN-ssK%-J4Gru(wHOd z5$WTO1Q~)@2SnQLNMnw4NTgmzssKl&^^iy{jx^>-Cq-K5NQVy}4q}}ZX`UnT43ijE z{6D7mU;R;-<qED*nKmj#`bS5y<tro27wM~xga#&vwMe9cjx^;+jUs)}k<fw$u~vz+ z$&n)A`$W3Mk)kY*iB#iAXq5tnyF_}0PkM>+wNIqW9SO=vOx_Q)a7Lt`fHYb0D1a;R z2bGjMm|Q?$jev&<3=udY;4py`1nxXzQ9esxFWiOMKQiD?3Cx4LP$l3l0;bNz0=7Az zQNTt3K^tE>o?v_2)tBiS9_;I@#j+CHW6pEC;OpAB!7g)!*Kqa^U42PhZn!B|*J)45 z8II}<ylDW}AbJ$VVc*f!$77Z9vw!UBTZw}qgPY;B_?&-*SOZ_<3vjN>C@u$63M<(Z zU#QO`kSZWBFKD~KLo(N5@Shu2c&;f$GKUn=f;dA%SdrP78N$PN!lkQ5OhmDsgUKlQ zOD7Jql!>#ChYm*u8Z5enReWGru448XPI+90$Bv^sy0~6G_?>+u?@ajwZzqammcAC& z*KZ6G1)oU1h4pDot36qo2G$QovZ%a>)ow&o3r8D5-uhr5=2w{J&f!6xO!mVp!=Z-( zFHUP8m-U#w?4qS}Q?Ldn9&Mw;LtGUQ4~5C*cv3rxLtV+QIGNr)TuK_oLH7*V+U<hU zC{DVUMn%8ktj3Ap$o`a0E$*9F80o)Zw5uoI+ZmH3`Swu&5ufykr17!(jXow_t?a=` zU@s509BF=~Ri9hm8Qn!(jWnwoGPSMg`szdj_KK3&<)o_vJEiUErj`^v+(BKQYVF8g z9p;_3WNR|PV2X0GZieSXxLgyCvq+;oM&UKzP5`S~KNJX5omf8<-ULfGj<e*tOVYzU zAXr=>&nCtn%4Y`gL}ztkC|}>1$Ag#n9mEQvym4pXvy%u6ft5qtN^Q*m6C%&c@XPr` zxb8yila@}u86l$en}+FV;dvJRFui_GT>@|DY|agD$bnlBf-kaqJ`zCz!e}IVJ`w|N z#w83AVhBy=DxL!}5#T~5C@<}fdGO~^YnX?1p{~~D10Af(H{#^@JD}IjzUsufJe~#} z!K=UKZm93=+%Sl57f7h}J$1u_c^ouamnUc*s?XB4a<)mHG)Q@9m%Sxxa{d||>5a8b z+2&-MlONwWq*Ga*-qPCFIrT30aQt&@a?Zb5_w+sv4o(!Vl<zAOSZi7(_axj{McM^l zVV|Hso3ts)y@U=6`hXw{bxhDUFVty4y@Jj$;@rn9;T3?i|7rQfQeJSR)5)Jj#pF6B z<);o7;I|D6-?{G5;T+xz_s)MLZ2rgfmD~V2B=-ok)9I^XalLaO7l|3_-Cw(Bdlf#O z9MZ#G8T#2aX-OioBiImcw(kbX@<AT9lo0sY=4WBH{@OTs(FR)wuzQ4eY~gh0xE7x^ z1^xh|1e9Z1zW;eQ%P}}MwMN*_zJSu)CHJFnqco4eS2!-{_!q4-PZK&P=zjq!%>H-d zKgrk$xj#eqQn^1t_ddDrru&@SJLs<YvBiBC-F<Suo$fty=itU1clJ+^<Q4dXF;<JD zs3Npf&=NrwDlMpr(5%UBh8hv{JU~3wHKV<-PGoC)NBTR5EX=j=Pq!cJrsO*Ns}lN! z<?s*|5baygfTB3Eo0(%s7E8CT6Ym~t4VpF)cukJdx@tD#t*^5Wh|;Vd9PY;hE5K+I zT(^&CJfzsv-wE>|4aYe>T3A2ou>84h5O<{GT6DZ;T$M=5ft+dwE6FV^=DX2kSdvJ# zb@t^(Mp%o&CdAdF<z>@o&*klCHdpnlu%3m_fp9F+=c)RMa0~(hbjY)GCU@;cc{bIT z=LlX+_23lLK1fI%B*3d7yx+VXN8&p3IpvGF2^vU*Vc3_I2|GRO3cD6zBfZNGrfHU^ zqe_%Zs8qkiE~aDJhu`LKoX|WtFxb_Dt!T6al$~uuSU7MR#(07J=I1zF`+^~=aI`nS z@8H-vJKQ;dXV!<Y=^1Y2*!o}Pe^@0Q{gAaa^X1EY(E5zU@_q0=)bAd-@1Xlmxwq22 zPwsxYkILOi_i4F1=$`XaOQVVID!JcCca7Yyp}Sk|SHO+-V=sJ#gMyxkLn|S4NYF36 zP)7w7J?Mm>ZwV^GS2!=|%Yx?o4A4CMLG$!kK~;nn3)<^JZGv_P>Sm}BL7P12PC;FQ z_At}|L2ZI22ptu~yt_3}8zZ`d^ikR4e0U3v!>3VnR@Se?Z)^?J_Vdb~#kcTWhaPf$ zX)P-w4n_`R5Tmtk&XXc~BZhdwe?Nu?Up!*peTjF#pZ3W$$0+`A&ff!w?R6*Gb3>gN z*?0^XpYx|EzCPvS43`IENsr5y=^5NC`Cb@{XGgoI$;PpO&wHen+YtGxE!A7AH&^#W zO-hMOtY3a#KO24?F2Ik;#C3BV&o*~yA745ypkHmE;*wYRegyMpb=1xwh)#Zi*Z5Nw z|Evnf5NMB3eZ$d*;&E&xTq6$hW?a90VOv5C`sp*wir#!Lo+@$a`R6i8$BC}mG!ABl zJhOEj?Ktsie##$s`JMjR!v6E9P7fBV|Iiwe3HdI^)ovJk2DD1hP?H}5t#Ar|iVHt$ zo&H$@6+gG?m=IJ6Um+pr8H6e(7Z9ou^ozeV$U<cW{VSkCx7?3lm%nhQ+~0&71B-+3 z6^;rz#MrYYPZByK=pI10fJr*Fxj`MO3Kn6IP0O#1VOKV_gw>Kd5!O2p1|>$lv{^H& zc%|h?y85e#?w1wAv#d~Go!)($G}$`WwQA)g;*srKm%(?l7Ke4j?V(}swxPAIBU5sY zm+$MiFcu(H?*%bF)^7wEj=oY+nv^3TW#Eit_4Y{2X4Q-ZU#TE(Fo*fSu%e!|(@bTt ze2=`}t%;S>Kih-w3`kf8<Ta$&pC30~+vWRk#H(BxaXksPoXNH}hpZ^q<l-q9#2Egd zTR8e&EaL4UaKC^r5;#iWjDSxPm|byuMPWYvAj;hY78B?Zu${m*0(%7H2^=Iaca}w2 zM<4-rp+~??1jYy)6;MOqB!S8&S(H~3sDit&Q^1P}>?d$az%vM(Cot#97UjZi0OrA6 z$O?FrKp%mF0=`G!5P_nAuMxOFVBT!wF+rdj?!r<5|HA=U0e?iGn<4HLaEA-AN5Ie+ z3MoAIX}k`Iuu_EZ+^3NyL|W=db}G_H4~g_rM`FV);ZBP5R7YaFE7BQ}9(|7qfwb7< zid69w%i}ReVl5S^Ql!s25-X@k36cK9k!ZIfEfDEFj&zwL)r-{aNE`tu)+&*jMAH6+ zWw=j-1uo7M{wdBjk)G#B_;fcQ?G))3?+!EkD@WQZ(j$&^!I2J%bi|Q<;Yf!?y2p`z z?nuW)`a?%L??^?F@{aT~N4g-=Do6UMBUL`tisX%s^dF8iU!<2g(m6+3B+}Cy=_iiV zDAJjCh1&SBBdrnXVMqFRM;a383yyTwk+zHUQAc{rk@kp$8@+<P(tmTL10v-d=|_%q zNTeGb=?q9=pY%ppNmV|d>FMQ1V)=Zs&wlDghOzXN&+FT<d_MSaET3=g?Z$a7lIjOX z(aCdy2X?lXfbTQN#y(&JY&hqg;ku+xW*lony(q+ZCa|i1ozm@J7o^+2PU(7Q0-Fa% z^SRnle8}e3qB%CL>c(Q;0KOQ-ImZ6vC_Zz;H+o%)$I6neAMV@`EY2~#t1M2QXo}}K z5zRd596tF8Jv=TG%oA-~&Co$E$%Fk_Rrf}sh_MluL~Nv5EdMUe<=6@dunzo2<H*u; zk4qBD6(-hR9`Ughb<0%-r{g7w*r_3R*2VN{adl*pGQP=Ab9$1O#GHJrzck)dO2q%o zKL5n@1UPqHp4%F(9ZXLzIMZbMLcs8_C)2#f=Y0{@JTFZpFpl-b;Db9!^7()n@zrH` zRVUmB;yU?QqFCsj-(*7fuHbcGS0`rOAzc=_OPfJkv0>q*&2>mu?m<4LryVa-M2YjP z$0f=h&(d+A%?DPt)Q9n2Q#Q?PCsw#=Ol9*M=7Z}1SsY1cR{Zi<1iY%VkDD9Scu>v0 zEbZ*mN2LT*c{}@p%G=qei3HhNUf2ujthD@GPpRtMC_Wp5*c-#x8^sv0savyce1(ex zepaK1an2aFF&@dn+n7&a9>ENw&it`2$CIdQ-H<qZD$<3^;;4Qe2UeL5$G^k+rWR8^ z@9;JbE{F3=%UjzZCZ<td`*D3Vj-?w9mQVk1>qh*TpYrt&W0kKf=jH^IuYWkXZg5z8 zkMg(YMuxX~akN4c^5LMPe|R-culniOwbd3!^kg3sVO}n?@GXPc!3bm9W;_Bg4A(Ur z-?w5OySzM6zOLaUt_;#%r~I}zVQI<VRExz?^D~{UVV=xwNo7_>dI&H#?)Sp2%%n=g ztppO~rE9ojND>I6opcR1Vs&vDUm>z|B{!|v=hZUEDi!i#c_3Z}FQ>Zsxv&*6O#GX% znb&I!BVA=~O0Vp+$i!IQ)K$n|dBV58Xi`wTo?JZGuX)S`b=Yrs54!ndlXIVDBbFCn z>@k^uyU;D*-J8OF5b8Im$;Qv>h_ye_T^WlJ#<e{&w9iqLps5QF;v+8eVr{?4&5&vl zI9J*$fp&0obZqi|`8Hs<fkB3g7o4*XCq~4r-f6y+PS&Q<)DihjTxL0bgZLej?*$yb zoWOkj6#RvA0&o1d&DZB#4rm_!V7BynLDhto3Ysq{O=yjvXA9~hv`x^j|I~QxBD7!7 zqk<*~JtXLapwooT3Hpkl*-r;F4}T!UeS%D`DnTFjprwL#dQh97tsc}PXuSuG3CeiT zZb3DI4!~D9Ea*B9Iwt7%1f6E63xb{|sB$i#D*S=;=RRhdSV|}>=m&y&2yGMecY<~i zIw0t;y-<e)9T0Skp^Ad;2IST$%h|vb{#iR3SOxv8H>Ka#unohO`LdQ~ebCErtPB3S z2kUOKBa1IF_1z`Ikhi~v#yEA!Hv3dFr2FgKY&-q4pA7G>p;5N__T;i~-HJRYTj^Mn zvM`)~M%3ymj=A`2J=949*H*&H0zY|Dj%nv{u?_+_s`ot7k?!0&II6ybdBx3kI6e@C zX-l?4VagHtQhs6j(1RGqPr@>dtt)X8XAqxb0wT$}x>OpUO}E3(@RpDEWD73tBy+=< zUw-4e5=U|2G|bAo%$_B6if^uQ0Ajg?qfD(W^|fh1hS`{oO;5=fC<qJ9*0;AJrBHs; zf5{ju3X6+XAUwm)G|pie^2(cf7Fr;`<+EgLO{^6sfjcs(`qq^##&f1|vKN+DyI5GI zWAQtvD9Ti>ttGDbxLl<@Yf`bj-1iKtwwG;H`zznSZf1K~I4a*O{unElr{sPi-Ls!* zah?G;+SCMmg$06sDyW`NR?t6rP>-Nvg0?Z#PC;K1w3pC9L7xKT?bVlC=T!Tjs&A6b zFyB!>Rfih_v@Xnb#S%P|O5^4!@B3=bHKQ;hhj%m5zWjA)+9v8@Q$rJP2$0Sh#{c%2 z<pM7F0(qIc^O5m@SpmRlWo7M&cXti>AWSy3N_iqZUwUT+i42D_>Z`P}Xkv*Sn;etx zmFV8BzuN_WVV^*rX+?1vbibfwf{rrODM5<_og*~&*~a^&f)el*76^K#pc+DLf`0jt zi2YhYML}B_>P|sC(;5n~SJ0O|=w3me6?B9Vj|<xCg*qc>hoFk*AXFv(p!eA%C_!kk zpe_$e3u^PAHG<ygK|_MB@t`q5FA%f~zQTS%vjt5MIwt7f|44ZxbXw3q0P<|P#BQx^ zHY<*7$?u2Q?pQx$MyoKirP991+D9Ez439yXjj`U>qAkU3XZAG#+XA&)-Mu56_|{>= z8exc&FPrANBuCAWjb5xzd%V7dX*D+C)+VpgF)gbz-uWWdndaoGSe>Elm(u5Otn7dD zOkLov)C~KOpsR8D!>1bctu1Lz=Up9~sg6<3nfe{-s`UO3=IQbJB85Ruhfak2S;x^= ztU@zpe(E7xvW}s4etBxO^%4p<(>jIvDTHlnPh~J8Vj4;l7<vh|8}pxQ73SG_Yd03l z_t@Lba?|h?*5Xg`s@)f}Tb50*XVHwy#w;D`r1V}R+6PZ0a&pGB6VJ1>?;f_a7s;1L z+SX>(!(Uh>@RJ`lf%*t-7xZC4dk7s6G$v?*&{0ACf=&=B3c6WP#q$AG;t!gOWnQTH zf);tuVnHwUptPW83R(+aVT+(&e#k_%6n6?LdeA;W-}0dQ1$|l2QTPg{1bx<n&I#J< zL9<_A((mw~d4e{1P?exAL5txlqy@DJT1#k)pf`G<b_%)%(6lzom9y1(^U1zwbC)v4 z{!Q8_){7_7?$GA_cJ#lZ9isi0wl9`v9iNZ2%hXw>4hJgIwaNCNp0ZA@OyZbDD%;WC zqVu-oNi3VJWfgMu>{7?a|6gvW&dV5k2du4_J5TktKWHoF!(Uh=@Esqp3fM?!ji3#J z`Uq_klm!&-Us(H9GOo0-v-)RTXIR@>+q%lNpZ*w-aXDjXOVzt^`%G;gE<kE#!G-N` z={S+};A%u`ALsm@<#Lp{JT{q-FVh#~c@g}Dw7@_3L(B6TLVberg0>ObDQK;r{e<op z)a->iBIpJ|Cm5<I=#?IHLC_T*RQV#4bC#e4e1!#q{_QT4tA@}jLErbFK0!x4Xq%wV zd(bXHf965^1%1GS?iaL8&=L3wCj|8hIzwpol_u&6FVs9ib%6Y}rZQ!3{jswKm812& zI3u-guy$}uP^($KY#06W^N-htv5oTAli5bmu4q)@0fmt7#pdtj#!jW}A8qzh#!{4- zx2T2ppV9wcIX=?(CDcMxZ|n-$|Hd&>qb%m{d#zrsk?*g2oc)w*Ps~ngJF-~}3d7TL z90S$-z8T~P#cP#(gWzRjpdR=OTLk_Y4vt{TbSI%bf<7R~LLCsaP0$2G9Tn6o=mepn zpcR5H5Ssg9lb}ve0=~jxK?^*nQPA&u&?-Tf1Jd}QTpq)=E~~t|w$E=vX;(N3gvB70 zvDuwB*QNdXYisn^ry7zSY0ZrvZ{ET1{=I4}AI#g6X$*@)9;J1Jwx>E0t!K?N{%2f& ztS^80aXriYPATqV8_a(8$@k9n&VFXnqu(brrs|fnPa?m=FR>DA7QYknT?>9@LucSG zR3t3OTkkX*x&pq!d_l_vEhf|`Xt5V+m7rG$>S3rYf}SJjPC|PGO}#H-e?ZU~4>~01 zyMm4}Vo}h8g3c4Fe5r~0IS)z*+UG$F1l<M5tpk_S5A9FwcBnDg*rkqBOYMTTgY}@+ zmDr0|9h^VB6nm{>@?Q8SGM>HE_FH`uAHT4^3ER)gyZR=(TG{I3Z_BP1z06APE8S+- zY5D#fkH4B7cEexTBJkUHn4#<>v{%prf({ZoB<Nm24-q;k=wpJ;5V|1f{etGc9MF~c zgZbQM4_Y9oTTneitr2vS2lWYhlLw6ny4Hhs37Q8e96QcbS52qw$@-?&py7kv&=zHP z(S}24pQU>cmts?X8%jI<ZQ58lyT6n%!=>6%(6`6d<{z)!tekJ9n_Fl0HDA8E&cMEw z!e3|;xCw9ip|4y^Xh={Op;>~q3u;rSJq&fPpf>_??a7S&xW<OOvzAS;mFsU~%uib& zAFPjsLq6lpb}cAtchuDjiv?`0KeI2GeU<4bNv#~4yi&fGtPOOu0RBRwz;+zPgpSq_ z>J#*4LE8xJ6jUu}FQJ2iUg$xG1wGY+jtlw;PFRAyMJx(BCFneSh00f&oPR4Q0bgOU zpn?ZA3gUTA@Ul>A1nu^qK0&t$+6G@?m!JVb`w1Nqbc+}2n4m^LvHCny`MMHUnVYR& z;yNqq^Al<F%hktb3|^YFm}+)%sr`brE#A1^)_~J^(;}L}7{Agv%<rmhhi%~Rc&&5t z{wkQkY5YMKvAqLFAubSDaJ2z>0*!DN_6b-=V1mHhYb?Y~1m?qC7!goIU>AWy0$xqv zIDyJ*Ey{}tRKZ=?CEytZ_7gZS;6fHaWi@~a{DEMP5;#uaf`IQ?i0c3>z#oM88UWWu z&4*o8<+@t<eI3p#=DIp?1-vcf(~}<DEYH;lW@Tz+otnPhe+~KM^E!`}k9}2~_r5C5 z=W&v%2i#a@W)Ef7vzo~Z?-bxjO#R?yd>q}C&-CK8E1dL-P}&>)_UHySWH;OQ;xS}J z=WuVQcRp0(ndx)wCZy-~>~Ke>eH?+~C()Mpl0@mX@x1s8LHOg2=GnDqfu1Zaiq$ld z>-Wyeaii}yO^fFi^<_--c@Nl_4*9)hwi#av;<I8eDWln$wyt#@IH`s)Tn^vJcdfIx z%;e<N0rrJG%VMUn-a_!N>cjUJ_`VX~VOA&l)|G19Ln4in=S=Owt>l^S;$?9i_<&w6 zm2|$V4PS%`rOTm%c|46V2wTW^;d8$(eESXuKflj+g@^v~T{tHwbJAH`>wg8*@k%ku zbR*J^^j~t_CrYx5my<9w3ODlD-SP6`;Wxh&$kVgq@Q9+N^>OBNusee<IlD%v^TBTE zoUZ!bJZ;lZS17oMZ?FqziVb!5A`Esn4vyI68H^a-eL{E3Adi2d-qLANX^`~d6k%?7 zQ?47A7e*f3U^vJ}a%{1Ql~{VJgq+!wD^@#b3dr)nZ|15JBRXI?(x(e&aTRTF)H1<_ zfjTf<mz?|HS?KUgWGQ>bvH4a>vK)i#RXg>iRW=5>SH6#~<QSxIOup}Ku^xT)tI(_^ z@CVJ>m$ydHVnLq;gqF_9SF%QX1?0<W;T(7Dd&D45%$u{7L>O>IQ)(q2!Ld&m`SOlA zLOoc03^2DQAMj&+Xl!l2xg3szAb}`Y!$&ykVfO;d*yovZoN1Hq!z)Y=N922WGtN<* zm-{PpSH8yLOwwH?_h;y?k^2*LcguY@+!)c0!B^NN=-pE5K0@~k+9>EDLZ=0-5_F!> z71vvODM3~66&4G+UXZbG6!a27YZ$6e&|E>=2<;T~bIOI0AEA2%{fi*ubwtoN1)X51 zGlC8as#pkU9{#{6n0N3ps9MmUc+gTo?-SI<h~0ul1dR~dC8*PjctB8#2OSc$#Dk6r zs`8+spyvrX4_{&KA`|sVf)el*77Ka|=Pw|=g-Q!LDabOkM$p$hXh_f(0BKF_@oZdc zU#;!zb6HQS@Y^+rkKn`i)9gON7MeU(lJRZ>3_f^-izaVzSdXK6QkQPUmOpv1Pl<5u z+$($>=SeQ%{I=G8w@26(*}}I06o&OH;@OUq06Jj6^lXe9yy!tc$Eiu2&cP9<8QTEX zNriFCsutE8n>SG(2<CX`3`7$mXkX3R&j#qwKO8YFd~{~Q#?K{Zb^P^7&TZ{XhVAJo zU5)=|z6&xaM|Vdu&oKm7CY#*kiTiijn}baS>gO^G;~*DKJN|6vls3a<y@w<im-9>y zigeb}nr&)`zi+~{TU$)avG=(AHBW_!pS80-#mq_1r7&I1@go~E-JAEOj#PU*U6vu! zfIS)!UXzou0}pQ6jPi)HetM@Z2&ee<sYvpuELvM4dp7+*Y2l+Tl#^I%3&3gTEP~?{ zL12be-lg?&=PVdTGGoEH<P0fn(CQERi^=V;MbmKzf6(xqZp1X;7=d#FzDZ#2>i{J1 zhy5ji#RTpY@K*%rF6<YukH8@UX9RqJ!0gupSc*U3@ooZb1WpR*CvcWPVzGr-Ltqiy zg>C`M32Y;9NWcvQjuDvq28(hvfhxEQYX!_BFhXFLfTs~SKwv_^PnU)5-K(JYsC_8^ zp$?z_^*@*i%OKl?&&s^9I@_bF{5t=Jr2M+@hNP=y3pQ@n$PicB=>w~<yfT<l;i|e3 zura%{@vsYv%fAC0%@glt(%cDmG~xSb&UNT|M~;KU;Hss*L44b_E}tD73@)_`!vqLK zvUJoQVMbSGZNY2TVrK|!9=I7YXdbv3AK4A`_9J}^Md9h(A`g>@>bkDRi;Wkl|El$l z&-#3GeN$aeZy(s0n^%m`iAY;p2QY#U^r-d;L~jrDz2r4CsQ2n92;FvhndiiKymg?D z7jK0`YAuAIZQKeMj#`ZupJ0xF=FZ*$$`m0sAdR3vzRMs>7HQcmB+$WCl27F}G}wmu zDn6INEQK>^`tb!0U+m&TpR@^U&kW6U;g%Z1Oz&Nt;?dQ~%PKHU>*VD){0&P196Y_( z^$q58yk{`_?r;(4&hE>by&_;<<3)FT)z*@)Dgfmz_uUqvhu>>)T8fW`jGJGbA{#W) zO{2MC_bHvx%tqGrX13xL)P7#q2s`c#b87Cu-00>fDZc(>)9jOtm;c?BM>3jc>#;tZ zeTaW{-oiDe(rp|9cxPhg-C*s}YtuIVULfCdmvj7$QCSWAg{;7aejBKD6WStZA)s3> z{_TnN>9yzx(w=>oKhv0O(-?~Vx_r~ZxHFg*Cb-|3^M(VG;9ZpT*yLgPZn@FPV{KM= zKEY-$zHQmv0d2{a=v$b1OHB{giQfYGo(_J}1N?=oz&GJ=2~^WVXq%vGJ!qGpd4l#c z)P$g?2zrRnX+b~UsKGCx$~T$>j|iF%Uty7;hXmCV$_knk)J<qa&?g0LC$wA8hdt<k zpfN#*80xs7eh)e==w=T(FKC$u&3TiFx(E=8Ke9vV+v%0{%gR4M=(jeo<o%Y*Q2wQR zJ8DNd2XcM2xlQ<FFN|xZ)6{}dy3!>-!|>%rh*?~V7Tu}h!UdOplb=_2!t35F9mdx% zSAk2y#`=^fY{}U7B75^1=a#(Bp<%D3uW>Gx=pYBvE*<BVTj&07-glbZ4U;GoWf$o; zW9V{$z?E+{Ls>##0o;Y{0<Iyjhrm$*FC=i1z!?E^98ghXJbv~jgqR0+VU>V?0igL` zBlJ|2AK|i)J%E4(vylvL7Ug?8fWtQooF}3MZ%>d?*E`&$&+MJ8;S=!Ap<H(BP)_B* zJC87iu?1sx)$8)@oxNDdVh1yYf05nEM2Ia{9PAn}yj{ad2L=UP8l+Q8d!dhC<%Vwi zGS@s9Ch^)_Tz*-S4h1yq6_(DXV0^VHl5vw{tX{XtSj1#)i`TExJ|oIcRF7t=Gp|MZ z7wMamcn(Tyn@Qv4FE5(>8aFCXxWLGEewPaS_iM1Gb3*QC!_8*L;_+SuH=owiTCIIK zb>G43Aa(pOmDk$&?@wT95|3qd@!1RGQ{(f&8&106_%~+7H7(2;KJ^8N+m<xL{a(HL zP525U_*48<&XeDC94*3|ET#3EV_n@z6u(2-^iykzj3N>AgZt&n)Un?x9Fp&YIBS3o z>ok0YbAsLh5dh7p12hkRAo2!5RfHA`$_m=Wh>e1hg4QzBkf2uyGWKJFUgSZ$1<moG z1A_j;lk2dce-v~azQP$nU-zI3f(`)+`<-(7v%bG2x0!?X-md8G<rn*9oa}zvXg;`% z%UPprp;Z5zm-31W|BWNI;hEAl-n+xQY#Xm8-^!Tv$QHAMtr&O>FWdI3D=<3qD_hVt zfNT%gw+Yj$A;egpcn_7Wod+L#5NBR^t>j8v-3q6ZrQH3d)C2A}?duKhrDi&<1NG~8 z&j29W`ea)JifTLlz=X1IfYtAl`*hL_azef@*O);bm#<<S!ri&d;+*S*`>fnWy0<hM zeiCk2=t=kr=LCHP(Xf^~y9v;I{6UKM5vrJ6L?|uj<AN;WT0uJ%afG3E3fihr`v^@4 zTJQ0CNKi)5DTX>Ls76r5jesig2SQxuK~;i&Ptan9Y7_J{K|O@V1TpWBem9~0f_@<A zenLkC{hc5a;<%u{_MoDm1A;8Y3xe+Upt;LU)b|QXz*kr#Xi!iip|yh6c%eoFH3>2y zwhMZl2kjB`azQ4<K|z%sbV$&z)_Uz9`y;f|!TuelgM+qF<Qyw|M|x~-jhipSzU#S& zleJ*n4U8VYqkU`KkD5K$AMDo4#%;X-ZGuH}6wy8ney$I}TjCZ5J$BH4B<obKs}sr0 z=sG4Db|kopHO<kfUW<ayVsdDZObrA(U&+Q!+`)|-Z!lvHGXlDWT-lQw2r9F7FWnRq zywr!ex#-nVBgK63u4`ZBWq4U&=r<R5=0w1s>Aa^To%YV|-a%cQ^P8tOO+A;MUmPKd z@@srp5P=A#8`rkD4-JOTB62-|3XYiz6dHc;66Dp+5Mkjd*ExW_@R8gGT!T*?upJCU zH$UDv3G6RCGw6aFoo#ryV8r;eN%a-+aBRydQea;eH^c(_F^qi$_uZq|Dx1rK_-2D} zGcD~mPJi>9ZMS7#S5?H)3ar|&(!S5;9)0$#sH6M3VLyXq4YGC@TT%}8f354+V{24$ z*|@P~`W@QDgFePo46mhQ;mfS;Q9nK$rZw%{kk{A#w))h^>klal%cSfXodJBL$esQm zf7VWwxi?9DY)FtUlrFFi-4Dq$*tc_Pz)c&bYyCQ|p~gLuZXZYS?7A%rV`Vas+QLgy z*mn=5(dO^PA9P}SUW4h?Ap)laybnO3qS=TqxWPK}E9Co+#q7+{aaF@#SSqmU7VFCl zY83Q556TL9k|3s8=n?eT%@&cV7PbgF2`C)jy&U<g8W`fru~u#Awr5kT6Lhw9@+g7k zMOPqf7HvEhDL3#sDlArq)zI>9cb+lQh|g>U4{f}CG>41FsK>HA@LDBU8=dy&9hx!B z>Rdcs!>NCN4erVCqpldu+?`v@&9d{BT@5R3L*$nr9QPlSs@}!2I5v4ozFS^zCG(`o z^Y9nuwpii);c8RxmGBj+1-%mx6wLfu-Dt*}vXFs(%S(H2R}YU)tmw_*Y?R@&%OswX zC>`^*XB%vQ&A7~O*rd`=U3KJhAvfFaKh<hNeT9-9n>;7qpT91!sJU$r@=E-HMSgpg z$!*XAK@SM3XQ(xT?iDmdXiU(@1nnZUPtf~4UiS*xEa)ghoe<RRg*qeXCJ(B($>e&I z2VEiPS`VrcG*8e{_zG!3PZ6|+(1@TPue3ZGbf=(4JZO)ghXfsD#KVFn1sx}JM$jj{ zP!;Va>W4jEm4e1RC?TjHkeg4Neb?Fei56gGZ*%iDOrkeq;$UdhF8SqcHo|$59R`Zp zrP8_6e`VWF*}35$nY5V@+N$4=u}#GeP&zlTVWbD{(0(svu4VN%P!FP7Tw?8b(VLqz zA;$I>hYol(u!UjYs@bXhGxd?=<-ao#%73xB8N>Wn^hFo#V|cIhE*jZ`#p4UD!ta;w zzUx`x3rA#tXEW$(5*ahu({Q6}>4vW`BIs{<xbsc|MFI~N&s?L+p2IRKZI8K5hx_C> z2WS}V!xL3m>@=}01I{>Y_(dNPyi<b7G2ZW}?;XbC)8O#ds^Gzq6`gp$$UTIxBtW&o zgtndoo;=8b{a+21#`}giZ@c9k!KblL2D^ME&n*}a+KJ!JvK$?QARQcA@bZAyG3-%q z2vj!Xx<(Ol#FFzbSM;+&9dXYI-%wI}?e=6#uqemAC!MvTn#DpqHrXfNBMX8yd^`Mw zy#k-3(!7_@LxQH-UElL~<z#(PNeNQ6-=v<*ln?Szy;Am&UF)9~by(hBfzc20mX+_x zmbbzd`I0x8iJpe9a6!;D$P}!$as{Aj{6Y8if=kaQ@7&2^q%u6hjlz-)gGO1`;y1F{ zOm3vDbEGF98fy~WEZ>~pfY;veXi*a9ANvOfJb-jdVHC$n19ISZHtuZrcd6gGD@{9J zd9~?xzI=cFs=#)Z!e2-W{C1n^bS<GFK@SMBP}>FFD`+=E?HBYhFXH`z-tR#V3EJ%O zDhlcrbRND!<tmf&CJ#yodJ`b+JD7b2Zy<%scq}XRZ}zT@9)AhSuylMx`z!4mS@-?9 z4C_8ueZxmT$e&@fmoM8OU;iB)(t~Gp%yuXbUU9(ta=DO=;an35a9d^xrc6d7PqaZf zzVhz!RA&CB_Wz=5goU$G+{4#dnOCef&3?8Tjs6vKe^HeA^4(3!V!1yiN?N{mlF}{r z?V@avualIWa`%d|SH5MW+$(phC`aVGj+B#fzgCoU@;w)nTfFhHH|AlPagGr{rkm0+ zbQmTWR$CaBBg$3BlHrbYiZ!VSHr(QutWnvx4C#h2<Ez|tH8cGje^IvZwq{~Vmx~`* zt0+x3f+Kmn1s()9-0U2DeG>bDoi|%a{`^`i*ZuN+2c2`_u-uP`a$LSIfr40P<oo4v zRPR}nZMUGZt;HWSnWxhRjS$)+=wU(?ljL1EAn0!ZdEZj2pAV~_$s4Zq!CZ6e1_w9t zkbRh!a`QK}cjz30@L|}S;b<5gu#GD`T{h6&f;<1ntSW)qYUyBq3&n&H2`x!1!zuOQ z&G?YO>r=}FjOuRbIFxMauxp8Fy5-0EhmvGU*Mew+j2Es4*jU`&4<(AaT$sHEdr!?) z2GD2%zQO|hf!_OA6gccbXqBMVg8B$;6Vw1mdcT-{OWQBX6*fAw$C-3Zn-A3pr{$aW zT~0T)+y@$M@LmZwdbQc$Vfivu@%qb?P61C#zoW_41p?Ukq~BtyxK4b!<$F5#AdM~Z zH8sJqcgy`oxM98L;4932t3|!)M$@7}R|<MAp&-;^K^1_|v{?Si$wD1jJw_KlIwT2+ zQRhR^m=*8HL~nGiC_~e;k3qEvmPzYIuu|;}mcv195Y}F&Nn*t6k7}7V%fX-Lu{{Vl z=Ns^P*$|%2V>phr=nrYFc$k&1f|AC1XZzXNL2hxI&bLS<ldrV0+bQ2iu7Z~L!Cm~W z9e6}M#xJK6Yum!ZZ9zD$&3fY`?trbs9i7(r(O%}~tguo_bFq9cN19mCnl+h*zpz%| z3LL-;p)G>yJZPt&1%mc5;)I~z_n>2fE*Df}sM+gHf}bIGU~kYoL8m>aTF}EDR4?dn zJZP1mPkYdipgkURr=UALXrG{A51J5ks|TGBl=h(Wg5Kakl^bOL9yDLjb3JIOpb8Jl z3i?rlX`&Cl!gfL56SSAmK|x;?bcoO~LH7$fP3VH4Pk6kp=rOteP*62|g?d5n^g^u> z)FWsML+upQA!r|=2|=}j9wKy7(5nTVAvC+!QoK@-Whf!&GC_;sE3^svX)4NgkDz}N zbSFdY5p+zDrFc-#m%NCF1bxbbjtlyTAd~BypzU6$E8b?JzTJbW1ie*I4Sa=Ff|h$w zpP<EpjQuu2ukd*75%e4nx>wLty=B`paa7P54>~F6yMj!G=L9_{sB$CZs>UC5T%Yqo z)eG9^K|O-*@}Mz6@9?1Af;I>`2w&ldpsW|_q@bh+ofGsb51Q9!a=pld77Lmq$h4Xj z^dC5-ffm4^5kdbb$g;g#(ANc--QO$dkQeG9LHBr}ih}+~kd;tHzsYsG7jeFzArD$A z=q(<!M$nCdOo%OlUN6XsW4ECB9&|v^vjthZIw9!SwU%vzjtP2HkcoOm&<PKkJ7Cg( zMUW|{TF`wSlos@HL8jF$f_8e)Zb4fGS#`fx(0V~f;VYaFlmS#YBlq$o+zSRxk~hPR zk{f}quw76Uf`<KixxOkGcfKQd=QHZlO2+FP6X=zKa1<Z)e;j^>XxJxmZs=n(jjy;4 z+B%9sgEz<`58_P&1Jm$}jq#Y5mASqyJa%b=OY&h~Y<x7_wER&P44ZrNJ-O}xc4L8b zZ&z+0AH`?baEaLu%Y8C?Ej_n>a9F_|Z!T((=7(o~wAPCiGfx)o>j=keYX~1l42)p! zD4G{=+#q_eYGNDe3c>tw%p-ahuTm>&m~XE0ZuQcl40sP^2%lyTZ18a9C68yQ`y7Eh zR0it@lj~7FCE+=};9%81$3#9jzqT>MGlA*Ob$ro+d^pz5dUI8d+n@zQNDt?w{@j)2 zW?A*(g*IdxvYIwJowp3yG4t47t>rgZ{|>~l@WiuWp_cG3fh|10d-HLhS15bwoZ58n z?O!?BOXk#8CvlQ9Z<B55%jPONUhMQ2cwK&jb(PpU4&_|g%c`tZmXJstGtWWYF!A|) z0dbo{hdW{3zFOSAl@W%gy+(F#>nou;jGxJF=QqWl<;bCM0J$)h9|%F7Dkr?hj<b*< zvoI~19X>+o8txt9In9u4@mM#MU;El8mTAVPZmk@GSj3oCSocF_#LKNE5NG+~RTW!e zfYZ{Y{k9AWVi?XZrs@6qC~v;r0lPd0ZH<W$mIvFg05_$RKV_!QtsZ(d#q&lE_lkmX z!gkUsM7TH;q|LI8S{o826X)|0URskChIVXam+KDIXZfMrY!62Bf<w8(m(|0-#6w+M zi>Cc>r;`v{);Vg8Aj4B$*LDVsi1QmU;YitEr1rvaEni`xocXd)PhR^Ol1v`jdQcX6 z=_%J8vx65zbo5^FAe4{wG3*OUZJX)(G{5chX|2N>Vlq*8VLZ?*8q?z2M6PYOa|p5O zVELgQT^LVC%x7398qsH<6NsfrI}6jy<Z!P?pU6y?wjZY{C#2atn7xur%w%BQX&)Uh zgkhK;^aZteJIFofMx45{_CH3E4N_ib5AkeT8d0Aq4*rTadB@{h%CY<=9RCu#k}R>X zl+)?dYbclw%hA!o1_Kyr*5-wMu~(<5pVGCZU{SBBK8X7U{Ca2XcwX3K(m|)Hq<L<L z_t0105OP)eJYPQK)@|@TBu@U<=ej}`!BPpnIM<CVOOpLu_zRinObXk2e?O4zE%Lhw zuN$FALBqPnks%wI_CMd&QclRX{CUB;#(DS)m2bBo?|!`vUaR0M)C<}u$U?0Ww8{%L zBq$~5PDb1#=z2j12^|si5)V2lXs)0O40Xk@3Gs8B_`nEy5qyPuLH{Dicx45BQ&0~> zjR`vJh1xCXGaj#lg8oF%Ax1nV=zV~KHT`nqbJ}vYW1tte0$_L+wvN&ITR5)phR@Ev z%8jdOlch_;fGkeAv9kJ}>Em#X4@{`onDJ8jf5welr&lM?-<P(Ptgjav2bd0KXa_Df zJ}4b$(eIB-%Jpe8^<4}bmJZH$nLcOgD>)wa$8%QhmoVS5_plQqFw_T&S3cJ&)FSzQ z@oZM8$wv4JLxOI-9H$d@5jZTMg}^BSRinn@jV?r^fNB6R{yz8$+Xy{S{NX}C6_a-o z+9T-O9&|v^1B7Nx9%85yg6<V$yo!Q8=0O#kjQ#t?iy{~13EC`(LKmt9bqlH@`$j=G zd7-)my-83bLyZZ#77$+FW_xQoc0&N!8_NvK&Kxk??1tg^Erx3sqi=bmP**Fi)yoJ) z_3K?9erZcSSAkF1Mweyd7PHIp)6_XQ+dzIZyx$o~5FDD&9NqTP2iErv<4AaP5`=t8 z<W_Jm9ge9yonWDSw68m}vA6Wi$*?yePrjhc&WUc;A-_*xe^%#xe?pym<9Um7u{MeE zGo!=nF{8AwY>xte>|8JFT7bvCnPj=Q4%k;y?haM<*{uW73PteQi1FuG2j`bM`5vPR zA=*P$ylAz<kH<XNzCxg`V7hF5;JnRd?7h#jDqAhzvS+f&7Si(FfpZ6_L3`mV91=9J zz@Uc+oe^}4pxIjhU5P)appAs^r3s<5pw|N8l8@!5oQ>Q0mZpKB(GmMTJhGu6P6K{J z+fCrRgYZB-+PD58+`Ojp4R>jh;nX-Xwdj)olflvpLveVR2(3plvOOdm?h%@e#?}|2 z2(&SlwPdl84x?E*GxaNMvvHO@FhdRB$cN#TmpFggupP4kXO3Y`ORx7l!^-cxeD9lU z<u`Au6~kAsPhV)0dlGJx<pg|%<AVMS2T4#$X9!&o^Z`P%Cg;5a&;tBHS#DFPMnY=^ z^#Z!(Vr6N%va)Qo39?_9%;R;)OS!TPlo1xD_Z5e9`PPznsnV}b!kEqsVqcte@fst1 zZL+1SZ#3V#$-DBS#5TgZUv8etaxRCLj*&SB(R?7+ZRHkh#D-;DZmcnrO%M-SOlK72 zQ)&|zR6ch<-E5-romPN(bfB=8YWe=^S}Wmh_zGi!{-oNVU4#w@dY_;PLMH@`2s%q> z&Nk!Bb0jdJ1bl_Xf?5EnZ!1^F*^Xt+E-)1LjDmTo2CbY;#Ors=B&>c>&(x*bMW-I4 zu}p;PtyQ+uw&oWFvvB`!uj@rA_e+;qxn7X(qjRiWuY8x4#don6kD5CKUty=9FJEKO zUPAW^`mCTMgiZ_EE9e5DE8cCqb`ZiB3-A@{1#J?PCDbRV3lLfXmR-5B=J;4;&D9pK zuz@p9BYtNtZ;TZX4J*8G1cyIUTSl-5j^(znlK=nD7O1zG+5)yqP5BHSh?m8~YyHIi zDy`d|X0~%wzFVJarcq>ZR=fwt2mYw)V)fR_5)(Ic&dvD^)5~(EK91{@h@j3bkY^2& zL$~tpkN{^!hvfVEQ)tVu-`(&R4hnn{WCC=A&`Cj$z4D?qXJ>z$oLs<|E-UqyondXc z1U5UJDR1T4YWB-xW0t>XD}TG?du+DV)d~5oyUH?l48B59(DRWo<kg@Hf}Sj>@-~F3 z!XGH@EFu<`%3XW~+*{;6N%ujykHO8(nYL1{UUE$?D;=R}wNHOyN@6_bdC0B9@QZ+p zk7aB<J-^{KVL_8efL-rnrhBy2VZz~@lya703u7|y3~wN9Fz^e%0jf^mO9c1qxz>QL zEse_$2ZDI8M_hr5zt_8V#FcZDXPw1Cc}|{&S_|i-+r7W|_0)Jx<yUKF&q507=Sus1 z_Q`mw8@J<H{hMstj`(Zw2j#c+m%qlnWdybhXaxZLPzvVpK=IkwDaFq_^z#$_9Bei4 z8R@C1`(}Z9p~3ubztMhfY_Xr8>1XM!m`(2?{{!Ox=+8reF@+jK>=n2!8b9CBPjQX; zu70cid}^ireEe-eN;mhJ|LdFW=lt#V^Z6nBsr?)Kd68&q^|Rxz47~AE_Otxc_H%r{ z{q%0PpZoOl{T=4pJ#If=`GEc0u*-gK-EBYVyY1)i_t?+N{@8w=^-=p-rJwKO&1Pig z`hE7(`U(5lTd<$zFWAqo^|S1Y<~wo7e*XPS_Vc#G_VbdX_H+De_H)Powx5B&v!5l$ z?5FZ!`|16L{j4}{Kd=0@{T%y_{e0|%{rrP|mVeKD6Z+ZlsQJF}Z}#(^AKTC3bM}+^ zsr@|vy!|Zyh5a1Y&u4yVzD>Uh+h*F9Kab@+vh+JMj%C`sI}BJ4+Zf2hN^O>Wy86O9 zg;m!V0dxH`Cyou6Xf@RbwWz7y4VlpmdvkLx;aYuqZE1WP|6YViF#QVe7(tU0rLQkZ zbb6Jtgp)t+0ehmjVSg}@u)%}drgQaun!s$Y#-^ti%|`#zX+nZ%lIIH$@s3(wr#s#g z?R2lad$XzEt}sgyZa!3<2=?UsNwdaqrSrHYR>t?tASXumzilCtSii?tJK*eu!)O2K zOY{W@S7)cGH#W%#?dsh#$jnjdZ&zqm3@f(y02qSM-uQi0Ng2D5%M+0UJ)5rx$I~}6 zrvIlGNuML9CnCdilXo@K#EaT2>d1*0AFu^_>Y7Q;a6I4(`ndIerh$*_`4xUzb|vGg zs#ShNSJFmJ55Kx<^+m#8<@5L3G;W<h6YdyukoQ49y!QDJQWhT$gG!dacn2fwUZ3ZM zh7fAsRToVWTunkL1j`H3!<~M*xZeqPLk!S}S<5bxZWyFA*`@(plG)kk#Hz;k0h-%g zWNPOGf-JPxQkgi@2^0M9lIbnJo?zKH{u7A80cWWia5oytSiyKtT39N<3dKe2CbsSs z-iyg^+PngxE(W|-Fyzi#j*u*WmT;(yk9Pf(f@M?b_%(ih$Pm{b<VW&Bo=VzSuYg!S z3;eh!>Pw7jW&1imF4JutzGMzeyV;KqdxgO%UxDQAJ~dnmQJrvC#+IrK)xfF4<id7w z)JBUhT7WW4UBuwaSC<3|t2#D8am7+nTu3{({UE6Oz0=dC#xFhbs7?n$mC0^N8K(R+ zp+u-FR*Z2y{-*qJvrlipA%!LTt)*Fce12(PJ~WmWFK1hIwYDZ!G5p33{AfSxr}MqE za<(L*lDiZ|GrbMd)4Rm74H68??Gh4XdT&O0(cHEkHx7*CpgUZ4f={@$D*iY{tA1f= zc|JkhQcly#6P7J~zY4!@?1Orh8rT#>h6_)|gw@Hfkj%%GCGqO|yR)6W_)aIPwpN~e zqr~yYr39V*_Jx>h_b3SYT{A5l7**Ls#f60odAo)nsF$zy<6s|(J9c?on%EO&Ka|E3 zo@rh0$7{y`3k!9Z5Y^<Q-d%o5;&u%5;j~)&;Gk=l$_Rk?l%aHu{iacT#1}U2nVI9o z@~re9H!9PMwd*Kntf~x;czqUIypmqUl_cZ8$j>+8<LXEB3!$8{$rqP|(IwKcV3zm9 z^l&Q&H@|LCJf!sW(&=GaaH@C{FFuG;SJ+aU%;x%e(8v#F>BrkHvnXArP{kpeQ@-mT zFs_3xsuS5k{Dj<KQ{E8N_`c1TRoW9@Y>xc~oWpc8qeHy2yuP*$A_dJ%ELE0EtbTRm zan=SU(~@-&!uk~(AF(;88ypH79P3yRlW=u{BU3oSe1_6ApmsN{S0CiKL!7YvL*6M5 z*9u+zz~Qh>x#5wv+%OK!k3b`FHTba^H#W9v&uy?4HrDI0ZlNcPR3EgunB@Sb{Z=O| zR*5M`LNc9q_%b3L+vQeyS>&Mk_)jIKV-|SfX|#_S4z=iK)$|m*pDvW48IgkF(tm{@ z)J12BF4QAInK<&-H_D@)(Cx<D*05>1h*A)0Mzvd>SIwB#dVdu1pH0HjxTz!!<m5NB zpt40~yi4s<x_ZJTHO)5OUXlkk*H#Er?<Euj^6VExaES`zV)l_7#?x}G>t*h-q%Ds_ z)6;ep>UWs5rTwmww5?v&^VZiVtYg1g8pj*(Ji;){yR&b)4&Gf(j#`8r-uhb=#M+10 z0!+M}ip@LFMywp}9mzexb_#Q@&JlbmJyZF|);Yp7Q(K0xiSj#3neEU(iOwyrzm4|r zA{l17Tgs*T+p;;0=cVxS=4N*P&T=yR*6hs}qP($D4}6c(_1jJPWOsk>KzeY)h8%7J z^E-Kljjf$E<=glWDbM)N6h5~9z}1gfi`;;tdwz2@y*?&<+0YnvG^KI%)hIR}qJaQ{ zm@Z4l)fjv94u&Vx+|Ukb$eKAkvUof@@AA+68QrK>I+F-TL(?WErDMTZKZN;lOSU1y z<E6ac5eFv%z8q-T0*jL;5e9NfpRSMBL)K^xiNhFpbaRA*-N9irQRL~dkEvGUbk0Ft zUdu%f8+xp3VOOWjDG%|9kM(#d3zkHi@v-I>^isiZm@z*Ww4s&04EV5MIM>f1A{3v) zE139{Ajm>f{&kCRblYhoECA+mz*}Q0<<B!Mk&e()cWza8U7{YJN60%n+{>;qDAKE) zjbIx&(i^z(dbU7Jt^kHv4cRp1G5O#c7w7m)7B^hUgWkNmcQ~Ky%MZGY`58bu)X{Q3 zy=6HZvd0lsob|`8pDfj?a*3iiryb1+O`SYn8Rt1dbF<HD!BF8`HcW=nd1G_^Yg^Y} zM2E;mn4HCr)qT`mi?0xY>QE_T&6105@fVlKYw@9jE<6KU%0_-)0_l<U#o0RtQ;o^j zTxuq$vr-)>erf9EGr{<=?{QrEm!1joh>Z!!gWu5NQhR((8|blq7_(xIom~k8lcT1A z=G=zPb-0KbMjehY5}c6gC9CWpJ{`H(c<ALN`eR#91C$0_a#mjK$D?|ONyHPa*kNr- z_Th$?ZVl#h-7X`noz%~`FJo#;t}D<=*iKX@Z1D+I5aY>>nAZ3U1K}(Zx2|9v%hmia z>6M*qfU@LDr$3g|Ys6to;iOXg_{XI(CG)Mry&E{_qzeC=C6wOo_GQfU<ofzN<>5WO zb<wKrZ(W7<8RCo@lze|)R=%=|{BM<(Hdy1!igD2}mh||zwAR5c-e`vP5-iM~V{Jxr z=f+$cw%mg?8r}TpZi&y^8R+~dwk=g7*<n$htS?XVV0Z8Ot!=#*YrI2)x3}S1?Z$0q z(q;OmKJbs~IwlL)p~7{IeA_xS?n~{y!<4zoREKF!Z&zoZnMc%Qv8F3uoBVur3=IFS z6LvZX+M4(pek1^gwqd1)lT9RQ4_sj*6c!M&!t!B;eEs2TxnaBpWfvX>d^oCOY>piA z#;1fwY_AW)uP%2ZEXFWZ*2v{;g|kfgebm>Z_Q0(L!2RrDrxHqT>4zWLS0`-sxN8(I zC<cuJMmWQ<wzWFJ`xe6Jq0nJ5lV(F`V-;(3A!lgC)KN=`j$~upvrYG|<8U`n)TJ64 zt%!VMYf(`VJ^{wQl_-ta+O-aS1g8rk4{d<*#MW`cyTQ0e-KjS)!*B_|%=Fk(G#LsN z7x1j{!#42-30)u(ehU$(&f%zQ;!ws`Vq>7DJTDU|VPp4;l;yzuy~dYC>j`!I1_W3C z2V!6x=u(d|!nn809M^qz;$nv;=I&R_k5uE@Ltd(Ei#KIbVH&adFXpEsb^t^t1pJa^ z*phKMW-aJ8gQFl&CT_5eVuWKb9MZ$HY%W|=eTkiS_<7{`E(%+_wJy_CpAOWdbf%3_ zRDE5#9(UPS#^;ZV^Z2!J>p-@rH;-=9n~`FdJOHW_yaT*8*EhI1Ks?pC?uz<|oxOqV zdU`fw9E~hP8;<W?PKyximbgT5q;a4dpZ^B{Yq0WkwV$VHY-B^B%wgKGa|GOBu?ace z@qMCaM%Y5y`?s!WPzKSe0QJOgC*3@xDUWQuZjmc72sllbL8BHF7kcpMJE<@~vHeJl zIJ&UDFgTnX?&`r>Vb{p$FrsA5mdg^IE@Smu)ukD%q641L4?DC_pT2=n?${imy+5O6 zjtqM=Z?vv{FE*D6hYhw4q1SJRhWgO|^E#J2Hc|#h(WwQ-kLeDdCu#tW33Q~ppqBAN zl^ItBq~F-MN_9MzO&(#DzJlz>YN~kL=$B(dKW@MF6*a9TN)B&8%i76x_r&1(GL0Pd z7vI;#YU^P5NKiYkd3UDd8x`Z##$-YE`Pf^aEx)`pX(7>P<*KpS-m}0f8jsZGaziSw z*qQ+rM?%Sv(|kC#kVD~l=HJ;l!}I3MsFg1pC$?_KICkmgMIs>$=Km#rT4)1s7Y1J3 z8u11`k}0-Ug>sL=In#nYInkVAm_}?3LVXtvjp_{|hhC3EsE|NTRy3y*@#tu&3*$XL z8_KaP&cl}d+Oe|5?QpII1zc)7^Cp|dj4}e3u~4is`7(Z#2+DhWfr5P9P(~)>!PSUM z;BqlJ&?H;}hcfj#Skt_8?OvRRr`wQa*@9+XV)aqG|BN#|E7dsc?Uw4M6_43=tgRxK zOs*3Rd!Q2*EQ+{ym?y<&l;@3p`Do%uP63bBzHYI>rhkc{xEdhc#MbemCC!=3rzC!? zebZniGBdBXqJ48Qsn1wEop-sUc(MA<5iS;%GdO^t-H;5vJIY+|Db01%Of&YqMG)8f zY-#4mL7mv>>l|$oHh^;3-f+Dv5FrFPBj}vAW=Cp<H}Q4iZ4aD0VeHV00Tq_Xy$+Z% z$I1r_4mNoXJEpP=Ezkzm6T)#sY)s2L!yB+bJ-zw`k+gb<P<Xo-{UyW0Ra$njb5;z) zs}bx7ND!fXRI`2dAyHq%@HRG>A-3B1c)x6V4ec{fvg%nlMJVZ*%`}jQAdu{SZAn=M zgV2`I{&g5PhwM?K2E4(MI@=&<a|UNpG{#P&$GpfsU~EqWb`wuas=t&Jy)jy>F7aFc zNT-=TbnpSY=3ZRwn9o52-59FyEEp=p)uC;?$=3mkLIZNlOTrh512)d@Nzk~mr5=oE zqct<}5kEFS0iy_*&Plvt^BF!O6WY2e_{sq+<66?e&=A8{EdAOVFutv^Uw2p(W$q6A zQqCA}eB4+v!23;k$I4)}uLH`hn_-@q^ezSICN?Js$JbJ6JRLRpGAv&Skdb<bwF#6J z-#v78cXgI3<Tuf6j3;&bpX2FrOgT&TT0J?-Dfe-tb)2PxCcnJW$bNk~oQcEbD^Qib zY*Xv3OFXyxJnJwK2Pe+X0^^5|->mWoUKlYjVg`yQDQh=#Mwe#4=+;~`Zu00XngdbJ zUKXvKWBncXgkpItk)=$0p52Yw6?N{m{TpP+7y0U-Er_@8t-1az9?<O^t{q*!K0GAo zZKy@_3NIZ5&kiEyMdKvmvJEnO9Rs6ydr|9$SS4jMXL{gVBI1wJ41xS;wSzh$Ik>JD zg{x&ZngwGl^d{L4VyS637q*=VgmvS7E&E~o5?hIK>BrWf6xJ>%EDcSYFT*#u;&yuZ z#>Rl+YcpRic7`?=U7_mYqokGXFfXzBN64qowm70S#OVytqXZV`abzB1W92wMTTHw} zR<7(y^qgU@jFFWy_i1`-%DbEMa^7kJip+S%%EN`6#@52d)_Q}<Wi(lc>oGP~t3z`t za&|Bng@zR%FgjOt!*Yo2XES~f&(0^q7z4efUBnW-^G=<}ev|8P$k^Fn=~^DXNX^;B zK|#+^Y7?BdN4(lQF^X_e0y)s&hOt=t%hff0<L{ycDXFf-*2S~AVH``s&={S&D^>AJ zgRd)pjGcJTWbfc;o`<gjIjkD7EpkhBhA@PaFLXFLOTR}c!`Fv!^wO=bgu_fP-Es*= z8KHf)`T1afBO~C)+TOfvnq}F59PO0XX2w)xHX2)Fj(F!UmHFeH9o^u|&W{2^yS}L8 z>cV2Ohnmxe#x5f;W2Y?Yiu;eQ%%k-3XpEyN?sQeT1mpR+ghY`Z(~X^xjiuX>ZCL!f zO*__>r|hxzU^Nu&aCERt6sIp=bIL=k4RLK-TX3;QuuWAKUsCbpr+c4H&Vo`Zo{aw+ zzjAxUGy2!@!fDQEA<HxS*VPT$EraHLTK_s59X$)Mzs0+&WBkl`^PKUf3m<&n!^N+D z@z+ytd4L$Mv;6TLKi&5HhVc{QsX5~{7sj7k{Mxo(P2K*$?3U3Vz4ey2JaAV{#SG#8 zqVVgo;X+o0#Sh}Dot3+BC&$r%`8SJa=&h;TF*KXZrKhJMXTflaX}zt2|7BLJ9RJ0R z)P;qIJ9?h-)!Qq&rxtYYNQ{5Ac*CbI;PRZYH$Qpwskgs#R>jEkC$9wgzF8Av>9LC9 zzP%TwijVYMn7S)<zR(RqvArMR^G`u8U)`|q`*(c*-OnIth@_VcAYAjg@o$3dWA`9f z$2ri7a{$-1j2>sWZ4CD_vXFY3&yROpDE`40em%AD@Xf1Nckig|nTsHIrOp+eglrUt z`Yud8@WZPhz@v}e`qo><{~4L2J=3Pxg$(0hN+LHrJczz9oHpQo^uE-<Xn$g0a3nE= z%kp#GiB7aOeZAcYJo?z57{MR{@yUm#Q02MVH-tF%YM{THptX*|iDS1{Oq|7^;;dg! zO|9-I%y}3<0)L8Ual;0H#RReh9ud$-;7$U6Ctx3e`w4u>1C9_lDBw6l6bXFP3vr&n z`#oUpHvnuEkbrw)0f8O@lQnP_w&Txu>O%3l&;NR=qd+sC*ux+{Qk)B4dT+(VK>{ZQ z9C&1`V&Vva|0AHAAx;t~2slXKEP;CjEINQFbG`{+kAP~pCwd4xa)E+ugR`*axCGgM zKklv>f~T<HTS7hrq+{aj{deH?Y$&?;H;mLVG5_-btmr=@U;zOZQxT@f5Q_=0Ehvr) znD>P+#5)8e2yo}B*ehTs0b{yKz#aluFvKzeX8<hxM)3{uos};m-#G?034Tw&1p+T% z?8^kK`62)|D8+<;J^~iyUvUcygdQQl&5Gi;1>6q+2_BViLcW50hZxx8zsG<AEb=`Q zjZj>%NMLdmoQ0l1k*WKBJ*BihcbKKkWGA*U@Lwx7Gd{74z^4RI(uw^9{#d|l0uu!8 z6z~)R#|Uf|@Kge)39J{uMrPtXferz42wd@P0QCYcBe00TLIIZ(NE3LOfTt5!L*Us0 zXb2NS1S$mZ%Dss@2|R{NZBWUcNnkI5e=uO-Hzw|-@0iGz_rnDKrvS_QaRPrS!18{U zz{dnw-sgM=z)k^{_bUm!(*Pu~h`xT2E0D%Sn!uU>KpGR>1bF`rWUN4tiERXK5MWa6 zA#k+-lj;D0c>+wTLj;~Cz@&PJz)yc}Oiikj1pZlomB?8F#|2o4RGa|tfPkqf2v$kp zJ^|3(*hCe9PdMPViFyLN9Pr+WZUXNS0MW-Lwi6g|z-<%z2)xAs@0~bIAT0oy8=E*q zV2J~6o47#W8V9_0;>zy=c%cAfe{5nYfjJJiZK939&v3O7bczt~o#-L(F9M*Tv57GP z-x2@?jZN$$aKr((O&lWdIS0IV;v|7T695&CO<W-GK>?<qE4~L{%mKGe%qKADfcH); zBJfrLrl5KP%?`M2B1>SY1E5m^*9tHNjS%=f2i!KXoxo)dc<;n+0_T4gW`AsAKY@RB zz-<%v68N?QPz(gVBEa-<jKKX4xNYJTfj@V^dne8k_>ciG^osApw_Rkj+DZa>0cN#T z1l9>KtF0$+lK?ZpwFGJenAL70@M;0ZbSHrq3oxb!2|Po9ET6yyTyBM;=hScF41q@l zBnVWV1n@lpH3SwA_?mz*0&N5)1X!gVBJe)~0O?NbCh$iAfOID&2;30>XwW835f}*o z2r@DI?*ViLKmx#g0__1%1E7sSQh?=lguns;mfKwfULwF$ct3$>dQl!C@T>o@>|2yG z1kMOB1<m~j0N)p2EpIh}|1H2Y)<$4b00ga==p%4I00hN|fWSutj1ib1@CO1+V<!lV z1^_j7o<Mg1P-9m-0w5Cr)L1ov+5n)&vIJg3V0AEdV>eiGw7|w(Y}@1W8;!--3ApfF zaf6>@H1-x@_y9JX*>~ZC*%u(AG3_u;NFuLToM3IDT%3@^IMh4G+5Fls3`>KrU)kDT zk6(siVRbaM@K~$)!#GSk#2BWwwKX03*>M_=TidejaEED;PXHO_kMkLZ{xAsrJOhBM zd>~yS(Y-l6xH;UvyCGrhmk@63-Oy8tW7!;0Ee*<oy|O;r3=A-K+um%-!dcmQ2f)I+ z(@o$0nH3Ny8^;1VvyvIf4Jj?-;pT4<{vsC^bG_+@g^VBf?W*`XFi*QzCvuzl+c7ZG z+ZQds#NZ|@R%3uqSuBs?NqO)g_8t6&y7Sk9p|j)&b|Kf{0~9P0hQ$w<=TxZ7X&@9I z!)&n`Q%!D=+HRth3l?dti}A^we7-!*J}{h4O7b=&E-{q|%5AT3B|Iy~5*97<M>`Dn zK;bm(^Io2tJKx4BRk-s9;c&{X1gRbE?Zc{;7l!Ak@z`7&Zl;*dz$Z@Q)sk()p%6~P z-2wp8M0t0Q;yW?S*8t;d5bAjpr^K3Zmh%RF7SU}vlKf_C+A|6d-dVmlQo_|msJaTr zdg9l8mVYl^x3dF=a8p0THV*}_T*a{9^`ro!9d8~AFM?NGwo99bq8G*BHJ%FFfzK#N z6UMr<c}T}nvB+-Wp5tNBBDKPE&Ju>Vm5<JTTW<$!aoJXebX$-PaOQdQki8sc;gl|x z0f+46Ji|h{O%GU;MHDZrdzH&D<pmaIFAgdk+rH-7TU(cV@yuVBY^h77E#7k#CRy9s zo^4NM+gCR&YiVsy8IAQH;a8_JEv-Qm!)dD_4yPa1SomR?e}t`1HPm)wv#l*W!^`q4 z#o1nz!+8dSIQs+e$)vIk5N}y~Yex&4bfdAoZmPFznxFDD)rV3jjJ3t}mQ4#IzlrO` z2{Iq>rT&`gk^R80bXr>BwK&ud_lIw-ZEsB?y$pI4%KB{L%TudwtxG2}nN;T1_SRN* zIHb{DrqOO)$n0N){<=jWJ>uQb-kw7L(~(KFPmAl(%JTN<5pUYL$(BZOr*Cae)-^V@ zq$Jn#%F@J~`I>=l%t@zx8gI%Ag%YC;L|DYD1a~}K8f~d|SV1$b_}2PlHVHoDM_ZO| zgZ$OCwlp*?GurdZ(=1WOor%uGNp~{UuWs?vq)jv~uVWEdIJRx{vqTv$^oM+c@Es-L zJ4(WL#KWhX<KffI@$l*9Fg(YvjmtYMZQ3u~W?Ymd@H42<16k_gyzA=XyzA;h-mEj3 zmA5uF)vJA=PT<cpwys2*(VXOfiRrMe26%H*OH*^x&8d1o(`d<6aT@I}ir3Pbtjjj7 z2<$INn`s#zuJ$xErBk;iv)T40v@NMy+f&K<)|T{YqtjMO=#aZU)e^{2hMrlS$)>1i z=3(CS`1MWgsk&@yJC9#j7}`up8p(FlnNa33Y1F4yG}R$XGszg!V;LDBU|VZ@GLnI- zQYA8E+LG;=)U8C74(~K73DcfZpte?TEd0Xh;p$qO+uBoT#8`mTOPM^kHZ-JNJMpsV zJX%__x1uIy*;+NV)TdUF*$g^PwbZq*Zp%jYLYr8TYQGh6F^XTF$tJT+ttiAWen6{l zZB90|STgOc>9jS87KSz&gh9gtSC9|d5AjS#6HF%q<4xCgWRQ(a#^SM^j_43Q)!x?L zlwr}8q1PtsmO~9H+L&zO4>dM-v^3S3@a#@3Oqe%?K?<lXtVGNk^%$ielMjZTfz8*M zmKe4~*5=w2481;@<HYG~FzYNsp&TqzFRiAQW$6@~>1@zW$K^!hn`w1&a*P+ntxYF` zwt;)D5uOTUiivLdq-{pwGO4<b_NMIWTa#^V=_a=CAlttKn6;MvD*)p;rKOc)73Z%R zt2lD?Sj8Fqzw2LauVCNIbwB(Al`Yb<vKjmMj3YSApN7W|lUQ+TI^UN8qg<tY7a$Gs zWh+a*Y(e?U5l5KLGlFz*KpUIl{(jGn<_qIL9zVeypQS$tcYLr3Gr0=B@s2sg&t<ts zbAF;5{$lOQ3sZL-e)p^IYMaF{>_Cg}U!ee77~rJ{Fn%<77b0w@|MMU|`X<KTP4ANw z|GFSP1ux#{$NvF6ihqz1Mg!tudXB(z$KjDHdQQUkSMwKs12?np+3>5Wh2MYl_wVXB zH;!$j-aO)`&b5srTi*uxy6<4?3%Lunjp`85Z5zFzo!dr_HFMi&`~htoeVN*${j!u2 zft%ytL_Rk%iqFjYwk90CCZMxFHS!ILOZ!WVhHn=}ai}f_2VpsOs)@k$u!1~DmPR#x zU*>4!^Rh%&=Ky!C*5wjB>yy~rJJOSQnPRbeVhfMOIsRZ_%|Ak81?*0Yz7%@+()WHn z_0_t@1+XIczWQ;y^}YU|r>5?mg@@waR<ZDFrp+7ILz{<zSo+LY*a5+2Za;Dg8-xqL zzvC^%9nI%<bes=%3fKKpXg4T<@wO|lr!-zOd%R}u_?)SmszcxG9jUVqrXItN)7kN% zIW5>4tZ7&{HU1s=i{H5$rH0K=i(NOnxNwLCJ^CVqpN0Lw@wz$1grGSO*3Fysxmk~{ zTGlf9z}UMUs~Ab&l`6I|YE8|K)Tswkr=NaT$Ek&1o7e`aikEMtITYK>Sg_Ugw%o61 z%;W7#+xc_jBJ(UR-iUoBSkaR{H_MqyFXDrB@h7dclCLd?m7EQ&<N=ir`?;n8?HLZ? zqv%2I87444O}z3I`B&P$V4$;a?C2=&=r|K7?8B!cg;7;IQs*8_{c;xUmU=VgJZtC2 z!Mx$Csk8Wj&WzG=w)mOd)YRBJ=T?kt9((7!iqW@^XJ&H~Z{%j=?ED>5BWv$!E>f!( ziletMvqfs}AF;a%g+7(qLv>7@TYvkOS5=HGxGQz0ZM+Twc#1m+>530;Mmlv@w2i;( z-1zd!@s2a&%N9(ntcI8sQ>n8p&$^=*b;RlFPY?yV((c(mwoqYvZe+E3f9jXPhAivU zB4%lH!1nVK&=PdkmFvc*T&6F20~Pk>6TJgnJlsCgi_fB{0<*ufw7;+IXg<HA<HEvk zboBheKU0y{ckg)F_^R3KZ-3{DD@Ho+N}X-v{&L3!82V39jROPv>knU;su@L7Wajk2 z57};Y@p%vy5uaZ%Qi*l}5wX>b0Q06YG-EU)V03=GE-{t45?1%r5*xV->2ve?>u5tB z_~BnP#cX8!a3nM8%z3u7-=oympeqQZ9)i^GzN%v6CMWe=ym46rsmXQ=*n(anT*JJn z6%g)h+rq=|e*l(WiT@#KYECF^L)FxZ`L1kUgVf0ET9a{>$r!YCb1TLVXI5<g#>kx8 zkDM*umqL+$Z~QEF^+)n!XglgIOzmix9eO`)-Z}6t9tCx;dFO8b{>bIsA9xB&==LL! z9Zd&$uIwPE@rJn;ZoFYmaW}$`H_RUInbUm7kG4HOWmUgncJbr~adu!ch|8Kse}n+V zjc|kO)1Zenl<2{?K-vd(h3#4!O7%FhGJb5;wa2zSr*>@Hlcz2ped@Ij)*w{PjiZlQ z^JTif338ay$IsV6MPIF8oBlWaGrp{H{M*HQV3LnM7ltzRq$i)f_JlyZ48lHU_L2v- z{WEmBV;)jp{T6f!ch$%S&l%UC`2$;5Ww)(ldnVvJ#o5Rgnlu{E>|)nOtA5u9#+Q}% z<zw%vtQZ+&WghK)ux{?GyXsKW<`y4DTf?O5u6VQ^&D=q#oFjtb)wN`KSKVxIEgnRm zyXxkEWAPJkzCTrYXWd+5`0Rkq`yHD=sBacO`hg2mUfD-&I@+hR<7YVtxcP@++w@>+ zY8Fdu%beCbrk=I)`_S96ucpr7$Ep;HDzS?KQT}IbzYj1Qq-Wi604`YVs{nokPHXeQ zre;p#9f!BQ4vlm%Ec;UsXGiM%l6RdOnP-jvY%1$@ZwuNgH2#l1b=g#NarBtA^e<s0 zDQ&GrAaC*I==CuKC_{dT<k=h)urXsx2CG~!wE`{KRK=s0Po>VaKI;y=TNt%vornQW z#b2VPJn+MZVS<mIegFUE?QOuLDz3Qk%@+g+BmyEL%7Q^rBBG!o9~ubDhZ2Z}AShS^ z2_zDdnCuE@fW=Leutrg_qQ#0|l~!xxN84o48VLrfR8gp=f=U(bESt7bQw$Qx|MxpH z_wFV{+xLCm=g-5<-I+Oa=FFLyGc#w-oa-`d)AM3Fs&#$tZ65f*&vDv@TBi!MrSSKZ z<AfGij7(&z&W6RaCDy_M5BNZWe6#R>!OI1J;6^@a!|jxdkTLrz7rjuqXnW<NCd|?P zul?Wah25%uMzpDe-Qy!wfa;-RZNFeW&cALw$#!7#PqsnPAeHkmwX`;*UWKU%udDTI zGGDt>$0cBaA;02ttX~;hFljc#ZT(w?BZkvXW)*uffaf2<3?aW}ZGp`6XC@(_wk<i? zUS5}2@iFQFA<Q207Jf3R_wtkN=r4))zKRI+nImJ4VLgWg1zH31M}X>$S3^+LC6;dh zgfzXR??F1&Ae;f})psxuz!ax0p3zClH`!8NuO6B!T?ZOmjSgK#IdD{E?c?$#-tXF1 z={nTlI*et-fm#ZWn$6&ms>XUmFEoJ*bL{B$%#={iY3=Dp5-YApTdJa|ZSBF|AOq;Y z)B{pIJ=Kkje3+3!?6>)3fM=vs-aUv@=nF*N5A<?PW@A=EnQ<XAW`U$u^>EoKIrlK< z-(afJG3P%ZPlLmd6NOw34j(fdeja5DhrhHr9OmL(NVK{5608l##o)A`;-Y#R$-XsB z4)?%zk81Zc<tY%vDsf|?4x>s{u6>xNS}I-D4X#(w%;0)WgX=ZJj6Nu{D(eMs{WQPp zg-TalgKJkW!>2qZZ8r_Fz0$R(!L=6+Qe8{jH7%_9kRmil);<)dUIP<^b>rGI$Lb~- ziYB2zv!}%w$U{c9P2?~?I+?@VPFyFHZ`bRYzNi-{S4SZVSREX3;@lO1`rs?f_Mt5u zxOw0>=C&rSsKB$L&^bJ3eD9vaOLaVVd@$kF9|&<Sg-e*+97IVT>ScJPE_bnKS!V#^ zWT`1m4a>7G_%g`_cDR7B3v%8xymXNhg@xB0SSvM$7wQ}T6_x|vq4t=&68uT+*C+WK zudO&(mXbE+SXFv6SuQE#+HXieBXPEQD#wz^-$jLDr(Ns$$mZ1pKuUS}4ti*P@X1sy zFTc~%O#LR=3B=cL0?Cd>fOh`(4dO;4^2hhJta;?Vmb;?U=4R%vDCYIkV)1iOR5%=V zERMvdqZ1#jtJiCVhP2pT{(8*w>p_{UON1|+zsF#{Yx9f1d+uwCC!v`3>B)f_g#FW# zH^L4IT*u%%%Fw_uA8g$3`#xpeS?)65(WsK~zN6<QmKS4GUE{v`8u#_Vf8eKY=RV)j zo{4uQ%kSg9qk~FveMe*6xA=CRWMF>qO{7#!Pf<@`Og2m(;Rx>65&r#ZD~Lo?6le&( zZpYrOW1|`SoE=-NV@YrD0mS;7@k^86Xp<j;1)`8YCwb(%C=`r{N4|jL8&)tyy|-AJ zv<C`}4PFZ@fdrHC`*2EJ@DipBG%3Fbr*sRR!IWf^vOb*BGx!6VA~4pZEQ?I}0x2l4 zdypbOg6xR`Os<bTmF(*@w|WGhMJBTEmMM^@)03r{{QJCUj|A`09_}IDqcQG5q0zND zz=pX^Y*S-Pu)a*Y3cd0#wc8`&n{Gq=NXGwu;`yFl8l89C`5s8&HvbLD8~dsrC>N_k zmUt_EhVBLB@u71!EW&QBHJaN6e8F^A1kSz0`O&1d@M7XcGzajh7a=I>gXKsHHJg!v zx}d6}XTZ;&_}3l-xJU3%-Q3|H<pKpD)&n9#_!}3j<Tpo6QHhop)M>a&Jh^yDS{&X> zvkOWkf{_kEBfmQTVHwm%WEJMFDwZoTFptflzXycP*mJJTgD7*-j~z|~%{@~rbhH~B zT_(>#aMW&JbTCjt4|TlOKDu=Eip50*dPCS@jRUi3S>rV6?Vn!R)U;Tmcg(S1IXdJ7 zPix}+*Wt&+?uiwg>H_-!;!jIapZ$#e9hS=q5mxW`3X_H!jwt|>^ru)Xc<&q$<vtJK zqO54?#TgNeJo-Q3EdOAZZzf2V=XI9&|B~fZW_bfy^iFe#?7FW_feEzUXkvHmYO9KE zR%yT&>Z1ex%oMSS1ZA|91ZC0gRX<5tI*XZ)VnP`c<2_hm5hu|!VFC|LoY=#IRd!p$ z)aF=W$WymS_pXfnCge2nQGvOrDY^C1&E!_%<~j_34YA)$3k|5viD1Hu&?l&Wju$5U z3fMti46xU$M-kYVHUgt^=W*}R*u=ZAj%)XSYR?vLfcacYJdTl9A1noi2(1eH8s|<( zb#!Bx*yE7dI*;dFU3{J1DcZCpxLX)rcn|9cKTMQj`Gv6R##cG$z{`m{!2HNM@$>w` z>TB+z<++6&yPCjs9xua@2etwED`+k*7o^$$ZS<uW3QKZxb7V4?Ic6LCD)kiH1#?;b z$}y{-Vk_>Sm!d8~{jtNn6_$+LiB!3^kNI;T1LdfqODR9H@_ue-@va^0aA$hgj)?N4 zBhTf?gT+uStq%~S9kss|snO_#)6j9ZHMpKZ$KA$`yBA2TzCLON+U!agFC)`8Fd+;@ zk7@U=jd!?X%MW_a#g45H?D|1S#+)1cp!`Gsw50ZV2^(DPp`Khhg<?CbpB@M1KfxNU zy=qa5cS0{u&#E-2WYl^f_J!i7c|!HUhsU9H586#1Kn^M*o{|;UDkes3tp1m_$(-lg zB`n=IZN$kv?w%<z?n!v&gl<HYhM;7Os0Jkq+(u!@fZ9#pg&A;sIT$bw<pSty*b#=N z<A=fz$@T;&7#rnp3|%5Y&O-<!lcllA4O5e2d(8zyw@2Xng!t4I90Ut)!~#S5PVdhB z3*rB*Zr5$-pX_hmh(8UgFS4NYVfZ;61fqd@;mfQI3Ll4U4<%@re+h-CXPmpyUrz!u z=SAY+`UN;f0HT|R>XaYQT+pm&O!p$y!sHc5!nr^2u7wh<8-90pH)yQT=aB7<+?$_+ zZd;j_jDcPaWZpZ^c6fS;;&?sLje!{G?oOtVieOnwYq$x1gT1}_{pIN4)ZOnx*F_e` zPi9%kEO#Nxf*Zl&|B07id6)mD9``vCkivyQ<k<|*P!e4;#g8>6GP%str`OyJ$`85O z#-kL>DfTiHx}cadjAfd>o&>WT{<uB2RN(x8b)&RFrErD}M`Ms&OL7aQdU&PQ*bwzI zNwag^E8)3SyxjJ&;)>`<u(ZDk()q0}pr~ZE1p_ZT^xu+5n3dV9;W-M@vcxSVGR&)o zVZ$K$Qt6Ncd~*uL)Q2B89Bg4>F0mDgNE~P-!YT=F$4iTFokn0tN^vnixB~C5dF}xc z#OlB}3_}q#He+`EVNLBvOtLbex5>VO9<oalOsLQer{CQrFf)g>D=s!JK2h7AI!ssG zJ>)0xXfiT9iy`Loa!XE=1Ur~@{Va`zm0cnJsx^f93{6H}QDLrzFfn$Htl}IP%#|Xn ziG$w?mS+d(UXGQHa7w0|J2z)&r)bmYGvOHxUcc$_tXF9%KhA{hTTuxx+P^PFtJ?w7 zt%?c_bY>CmC!Jmj&!}{sRXQ0y(U#=PB{X&x6N?XA<>S&exr$D9itDj6yNHAFCgw>r z2z!iK)e&JhG&hgSyHfC4--Ac9fVeZPV3u{-h5J>wD~fo#6J!?@Eu*tgvMwniUU=Ep zj<CB0s%P?|zljwbbAp;qv2#k6g^RI3VLyn^KoYC<dB7X8OF-K)maLtuA%$I@#Tc(^ z#z2j+V2+86G@N6K;1n-yGHUoC(N0l>LU%CvGdUVP#Xy4((UE#xn6VZlEV>~gm!}oL ziDPaFO+(QQ8IuV&apLa`+?FtwL#zXd10&OOOP1wM^=M~u+5!97rKS32Bq}$xD7Vyn zionzz-OB}s)vM*cGlrwMkur#v<XRd>&^Qg|l^taUD6(z(XyFSshHVxZfhMr7*jc@0 zR_^V&1)$aP-#Ha)Fgf!{&voY&<)D`t^GN1L0kdvQpFFu>SrP6|=B+T{DFsDKmXjr* zis@7H1q1w|G7_9)WO}xHNgfSYb4$>gjG66OAvsNNMFW}GX|S55ZD=W~&nWa4<98?* zEktWtVCaIeXaRF=yOh*|lVL}az&@vwCrMDNl{fTN#ten%x){4U5{+X6q-PiAFEy@j zA=ND7P^4$T!x(a6cv~$4A|T!AepspiN{z6`AVgQu;~zcG#LiqgTUMh}R$uQa1V6>H z+VWZpToUFtEzqS<UWbW-+@&aCq}_fPQAHM{*o*Q50aQShV%{KR7F;-&!oBZmIx)1e zl|uMr<}WME&9Q|;ZV9M7B@S!>2N*pU2Ja-8{l64b4f`m#EK<+vU68q8Xr_2iL{9X- zxq4GsfU!@*;?l`0;S&pmi*qS=_KM=`sfR~p(QWKF^xCYsX}~nM$g@O@+pXUOIjgi( z3xAt*@C)3gBm#kUEbEIZ*<lb&Hjvp}L^F36(d0SEwUMyjVBD8P##zk=ZrE@ji4zH? zbvw%R0P>0-Kfq|UlQP|_3#1rK;>L%7mf=JhjuSDA9u^U0H7H3B14=KV(RIiC(my)p zM<x;D82I?9dtXioI--?8VTe9w+(J>lumahIt5ITyNVCwu7><aB18K{FbH@Y>Y#N4> z>uAr2945iU4CyM3ZqZD7N2C!69Z5FO=wsTt98Hmb2m1$_QOC$Y%N8MwikUdh60)~M zC*X2NN6*VI<-xar-GT2p&0GN%*{cF6!;WTm0V&$ghycPpK`taCDs7yPtiXP`BMKXH zrkzGSXd;t^y(Q-Cxoms=VRncO5y9w~kt<!Ur{~9(JNgx1wP4!En(aHsv7;vyplf$n z5=2H2Vo-+&XaI7+fEl@5VfHPsCl$KaXTM1ZN6nntCmdj__bw<EZ<}+A=%_QX0Hfax zC#z;H5*cQ>rxlc%$=QPF7(*CspS3NnoST6T|6WEMdGX_V?8ps7kGT||?CHIuE^|X~ z_X&}~XiN0uj&7&o?~AzkP)z(Z{?|ao5nuv-G#ovE5N}2o_-;kqPt)63@6Jt759r;s zm?qw?{#65S5)x=a5V^<NzS8TMy2|UAKLF*<#dViyCE3fkE5Tms$Nsed7fbD2=e@wu z*TSKFaS+p{K8d)&Qkth@X1a4%bg^&yv9fOIuIcVvR_wrXSm}k)vLKYB&GtBC*pOtT z#V#oTEy=QfqHg<8URQNHJP34jLSJg|42(auUkvI|?r80zUwAJnH+F&a{=}}u()cbg z?_%?IoA)a7E;Dbhc}tndw+-R4?Ow-T6F&>35?_XS&oyuMQpPVd?_12<ZQiTQyUe`3 z=3Q>y8_fG&^WJ3Mo6UQhd2cuG!{*&&-cWB!`7L<&nJd!`rxP?)3HZ3wQy>gj!Wm|X z+p$DEsB66f73@n2rW9aXCVB>PY)L_Sc1clDA%04nhMA59P+>%PP64+55~j`El7iXU zx3AXl8b^kw1gBLN4h=IG9w;=74o`<4<;Xnn$8>uxH269$PVmA#v<d4xv#?f)%(DQF z*o#(Lc{I$F0&4!DpOO1YOA4l8y;GV`!N52TGx;_TA{f^7yMbP|B~07LB?aj2MFj;@ zaI2Cq2@=QYXjuuDR#th560e>2r|F4K;A!Kyq+n(t_zgB$DUs!;!{vq!Ykuij(85cd z+L8ht2eH8_3trk&qJ5B;v$BrUv}sr!tK&5eQ?^N9U8rwfQlM#`f~#WWIO8e9!Zcec zI?d!MF6Jk9<by>zUh|6g`wBQ)2_DT8J5EX_erj*g*W88tOdNhQPUlA)J{JbZ@DX)n z-w4;y&Kpq=o*#$l{jquiw@r#JQ}b)g)Tzr&p@tS+#+a$Iq$V0x^P96)m=@h$vL{@Q ztU|NyQ?sF0p*<>W!H)V{|8yY|cZ{p4aKJb*MqP(Pbr>Y}td8<$wpC_1Lh-)(_}QK> z#?*<q7j%x-LF0G;O2Qpr3~eXyvl-|5&@B36lc5U4SO#u?>nl-kB(w8;XknXuC!@;Z zyjL%DpXEClT{bW<u6Ma(V|R5N<`?C4?s)IIsPUfYF$cwp6RJe}9~7zG`PdQWN9Oun zZK7n&i^b$!1s!n4ll}KqI5O1bJTlrN^u2OkTl@N51Q41;|9_bJf1EKNHU^)M_9-{M zbfApS!Az(Y4HnZUD*CUq6K{=%6P_rTE(2=fZvYkgC81gfHNu911%-O~ag^T(MK$#4 zeb(VOO=n~M?=bClWU`g+7b6=ZPe*z6!I+^`x?72%Yl0`wk-X~IS$wy_&ZfboaCmT7 z-9p<g7b?)y;A%$9k&IiTYF`C5>p0;v*oCX3aAl&hfYrj8w+$f7|5`E&d=Tk4;BmFu zho0=`L&0Bs3$GwY?4qbwat<3_I&4($p1pgD@^w6|7>sR`eeMT)CNZCUGm*@s(I-z% zXi)j29b-7S$70}bz$atbv`K*I&!`GEVBi<5dtxUnYW7U<t!Z(1F2ku5j^Tejf<_)q zYBD?2J~Fgb4F?j&UBtNk>ib`{wNGgF#CA9ic?8%A`&)Q_sSo~QNC!Um4F3FV@aZBj z!{*Z-WFXSb=Q6{slEF44(KeL6U9aKv=pa<(4eHNZLBrhS*xFR^#oyqEZAQGW751#& zvgFuw&lPyZ-RK$ZD@#swxG(U}O-@Co&B)|GP|NucSzz^sEU}(m>nA2>xL}D6YiEDG zZ`V|`4ecv$@a?K$c_^k^=VImpf46i`I$qsx^i0E0nBsTfBEUrOs6nOZayaa5(z<z^ zRyk)Z^<(HPoir=T-81ozb(3=L)`d&OntuTrLB$MGfiW%PXKN;#wsT{C0#MVKg{N5q zsw%5S6N?sw)vhpQx_3=Yx@WR?P3?`kb={ZI-V4oh7f@7XZLOu{Hv53iG01cJ`ZZgH zCkac}uX(jsl)Gc=dQcp*zc-ML^*S0;j;_Shl$JxjU5z}x!9k3g0+B(xw9ilmc$rY! zpM}*M{`XI;Xh3-B`m*G~hhZ&QtD&3#py87{*@-;SwOmaiN;h+KV#R|dPjs)S#EJ^$ znU{jHUVaRR%Dbl~ckAZh3&L1hPg-1ZCsoax2DpuYLrQEXyq>G1X}lAY9qt}W*Uw6h zb$CPFm#)uAj%{DJbOKt<eW^w;vl9X^E(vGC+xmtD!ebfe<9~yk@$DMH#?*6x6SQho zimb#kTr)7-b4#Y>=N9CYM%X}6mh-TbhjT3uDCk^C0SHyc_=N-7JyFxA%<%ljzngfq zeerevzsY%7#W7F!F?GR*0f|$xv4I!*p{a1bceR}MI|DU3{C6Er3hdJ1_a*F!9a9%t z1n|31qF?!csAyk1YX?gW>;c@yspqt-9k5}<{Bw!#MAX{80cAx$qoW52?~<6<YeHyk zcW>D_?F-#R+bwO5r?xukMw!nvFR;)1Nm~sh%Rh9Wd%BvBbn1`WYGmTLFS<P@klY_U zh=DOp`@KSY6B+~fe$v*2({#{3&ObWT(|g=`dyIedw04I-eq)dFKf7bczYjC0cSpYG ze+!nQJ0Yu3DQO3N*91Z_8<E1e(B=Ma8>bFzpLnNdP@2D+w`^ehogSQHis>W(7Y@VV z>FXabT-$5KZG)|7X;d0O)epcip|R`@Y2)_cO`l_}P}e?OnfDQSi+qqd0q5&Y*43p$ zr(5#CH)$_0Iy^Vzfm_YDM$xTZ9;3vb3rmixRQ6ajc4OrtTt{hfRKfV7UVXk1Q7+ui zXl-z{X{(Q@+7=+SX1lM`(Yf2sq^yEj=7;LfecReI=RHZp8R{1BRxo!z74wF!FsEPx zYhiwbn4bb>dusRs<#K9R4LMUEoP(qYqan_p7o%!vROe4#B1XutlyGAKY(|s56U6U` zI!CV>K5E=5nN69GOEAfYZ?59&EBF-4PiArWGZK8?r>^bef4kz(t7Cj`#=LnvI&_-v z`}nopYq>rS#mU?f^S1wewGU=qdQE2CCs=$sxWysO`D;Z#ZElPmy~@UKTrB9~>VU{n z=JBnKb+{9eFAK%M2wi0%k046L4|6?W5)0ss1M~^l`b%HL8FfiEd5M)54Y@v4yCIQy z83ZX?Vevw1exXwiwEY?J6(69Ww_&Cj;HFh2p??x~3t)|`xz*u6F33M*!bqU!A{5eo zx4IR`Z=_JN?HpwuZAAvu0ydTLAb!I9__CpugT;uzK_h}AXGrrmm7u&Wu+mpgpMgSY zBOhB8y9Gn+JuJr-2wquF^WGx$4!9JPle@}U1cP$epDgCqtJFDSc+Le#NBvPEIQAR@ z!l?o1qJ~rb`WsHky$IvyQCm<w2mOX|^H>@`p)?kj0`;mNL|_$owp*pIBRdkXn4Q}U z>->Z&SPy}~Q6LcOMRg6CyN|z)V3Fj{On@~}ds@8Rm0tvQv44|gQTYINWq$)0hDLxK zXB)&*(j%vTPfa{@A`hzjWSLY+ER|`oRV-XZ_hxH!;%(f7n>#Uf;+ewO6kcDs`Wi6y z8kFeY?Vp$6pZjsFdJR+<whCW49y+OZ=;W3>9-iaGC8Q3V79P_I0_!e}iG39xU`*_c zdGmXYiB^mWaY7Y}3&`x-9P`b3%G~a22h{G1Aj=KAd-V!??uT!F9)sGc^AgaZO5vKb zo?~=mS2WRuFzt(+D~uIV0eeF!6p~yog?)E&v|+EX2|6U*rfkG|wP6j4LmO>H{dH?y zzEze|{<XZ@Q8sEiHbv7C{IQJ_T&<qLyh@4C)W%pfTXOO;l`2A$ySrmj`>XGru&jCn zMZpqM{RJx{HuPJvLiz>zTS(cr<-&K2W}gNMNF`;$g2b>)NXPG=kO{IjzzBf>-$-6a z@wGe324N!!$?%IsFlsGE&rv^MGlP_N&sU5;7Z|0OKKNnAK`$21?k9d&Vby{j#T!Dn zC&8gT&O%kgU9ox;_{@6q{j)5NjyZ-qc4x8|tcrJ_<Cezy=fz)x+Vn$a4Eba3GyL5! zLQ=tN56q`q{R5N(ObPYm?~haqhdKlkZck3(?FwHV?(oE`PY`X5n$Y0jQV=SY0)!e4 zI@DIkJr%+qbERnCO>&h7{<3z)QqO4QpNOap3&r5smPx2gm;dGt);i#>>|xG!(Q}VG zzYvE-#rlL)>pW$HCUS&JHW7@sI_9C5MWe<U5E<WN!pacOt?+F-*!*hG7+t#;#bMTC zscHrG|LO%uC^W_*?#0>nDd&EqRPDYM=`#N-6wUiC&Hk^$*6m-OZMBgU-WFlmeq)-s zxJ2`I?Nb(g+_G=~P|aB>+K7vgmO+!xN{?!AHQ|DR!bQ?H;8ky41<oTg?sK7+w_{{4 zz}=y1JuhN%aJ8b6Z7N#o4I3@Ab{F+``Wq__t~s4W)H=_>0!^dB#nbi$j1;T0@mL}* zu=+t>6H2COeKEvEeQ+B3M0g=Ue$j6B`rIWReCP1?T;7;0@L<x%)WF@e;b}j-=@Of& zYMyjkOKw|k$ZWttz-z;(#z>G)A@cqZi=E_1EtMm(9w*EVfWggxfC7w~hpwAgaTccx zS6diPl>o@Mrp@8Tg_Sn%IOpyCr0%WA1LMMa?K4*P;%#c}W$f6^lptqNHsbwnynU@P zW#AZc5A*b9<S$pXwIkr}gsO<nWh)MP`q8=)7i6x-|0I<Q456O5ijKl2A*1f5H-TI< zPpi6~KTP>2?~n?qt8^kdZil`*){lE7Evi3BqOw32-{dqkX@(t}w4q>YQPsBtn_Q%* zSF=bOZW*%K?W(`Q40ba&f+OIu%p2+%4DtHljgVO#eHoMgriEp!1QE9ESgFgVdfS;} zoy}2`GPj7g#CZbgbQkfqxLiH!2!|=o4U;LS8}>xb^UpN}oS))cUF2~VV$Q*ISXktg zts5L|S&{%(-A2sJ%*eQamfuVAI8~w-^80kS9?#op`PxrbZjR`5K#7TPGFJ*L#qDqy zJr<-eE!Xts<qD*;NKQ*fp{`bcClNF;)3#-iJ=(|yx!-}k0d8oTD;@`jT0I%9KzG|8 zQTLNF=GZ)RsV+t;w(%7Q-Sco|m*%R^eFHN}SF3m2xgIB55gh?TcZ%vxS)ATdHIMqo z7uld8XJ*y3D2l-EF#mOdc*L~Oy@mw2b+hjp69PFC?e6e7$YpQ41LM6un1Pj#J?bIn zMgDQ#;u2SGu)I4gqI$k@sh%Fd>RS~HZHw&4WN*w7{eTS!DJ++GKkCjIPTYO3wG*?f zL6o4*g@8ugu>gCLV#+450>B)OZy<kt@V8jNgs7-8UKT><2Y=NQ+d=9u)HVptfQbB$ z0gR1woO&Pd%87be8S?%LeB|{#NyN8E@X6{yPjA4}<-h*tmOC;acRHWhZ9sg#xjghK zfng5}MzmkM67UX;v-T%D<54;26mbve1GL#Y-N1{L@w@LC3ykb-VA6JOS6*hqbX>ZP z2h@{D?6h&AQi7AP=p|$kF6)%@taZxidY$s^T-5qL;F2Xus0vGz6iA(_yT<{g8j7E? zTDb)fX0@`21j=fK^E;$-y}BcgY9U2Mg6QmgyIK(c3Q=I?F~hrKB7QmCW2x(bDvl~n z>fW$l2~bh*_eo)88-Up81to^MsiZ2M_{eGqxm^kN8fhO`X04HS`~6d~x_$J!<NoGp z{@r+E`km>yK*mwpDqQX5v{~sfJ8PxyOExEii{2~HNygfM`x;ya0NB{zI>ZUoSC_p( zd=NzA-lZt1YGQ{Y*EPrm_KHV$-6}kn7+!kO@SIVL^9%8tEyZ&ai5p%ju`)(19YJ%1 zn&6J}?4eSx{>0_EkFD+7!M~2RBe5It)?CT;yJrX{c3iLCG!dc7EZ+EW;7(~^6EG-+ z4Ohi6t(0r<k>yk~KzZ*kjrY%UbIQK151JPGiHC?8tHYO27`!Mj=^V&*%ns;YqT}y= z4}z_gJJ>RT)R!w9wbD|%rA_ocHmj{x_7vf^LcDJVF@r=eN%X0NO5ZHRgs#&Rksea? zu2s$xcZbVCM_!0Nz=giXN!6pLrSg>yI7c>Ul=d)PkIF+ap>IH*z$mQ`zJxw%PgHD+ zMPMGyww$HLXwkU>C#;-_v~0(|3YR!|&c<1336%eCOj3o`1R=I;&Vp=MIGR}rJF&$y z++#l3@!*orCf0Oij|=2o9aTT3jyeEzRR5ZI-|jYlcmMnZi10)Vm0O}w?X36-Q(E0u z`@3Twn~{KIxY?K=f35F?qwGQ*+OION10XlhqwE~m3wN(9P6%}aWV`1>e|O(1T-A3; z4%LhB-81s;y%4ex@697A6EVLeiR7OFeKP{BFGsa!#AA$hubiKNB_4}b{h=w9b+4A^ z>vzpS@5qDzltHS_{3kDXV4*3Km6shu_X#Rpt11=(SjCmG`C4^IQq?d-Ngnv@LEGr> zKV-z446)4cFbgsf_uCP=AYa{R(NwEpe>8a75EY=TQDYD#gV6Z20IO{eF#bi@<+Q28 zX!jcSQV6dYY-&=mXPj^s+v)b65Nv>0ia8Q*zgLDtR$JwiWGden!zzmU8)q<CZ6oiJ zZb*ofz(kA)8%7TU3M)kUwi7#@pRiTo5kuZgVR*2455$}5A1nzs?&DbAK<^s<jR)lS zRQ%3TbzGwXZo_;hMQ@f`1~xIGA$0`Y<3RfCOprYm+A%Ewd(g{N?tNeq2H!)(R=J6o z{SOga<tAdT%1nx5oO%H3PQWP-&Yv67M%ZVB88uX(;oPtppT?QtIflYaH$W%;x@t|! zv(Iw<(p*(BpUpjh(?k0X-a_!LX?1wwCoF1#j&@NCdU<x$!}Cw#x;D<L+SKa1(9F}4 zplI!dlDSsdul~7`O-~q&&Hs)%1|jcV11B<lZ(!WX_LrgnIPTuI_Lvhkx@igO!YT~! z4OI_MwKJ<5WT_lq^?SzoTWc{RIlg^X3+bKldVSKADR-Z+v;a+5ORL+lp{`uiLfRAW zJA@pN`8Zlcs;`Ev=<t|MG8y;Bn8(Z539hEn7!BrK<#c!k@Dv9^mFd!D<P_o-C~nnD z-=DxrMzkOEF%XSLi{5RpNqk36f7qSXb+4j5_Md{p7I8n5QQWLn17Ce`e+*YPq_S=x zq__Gb7xu2ED6rMlbOH7n(qAu-ZZ37ZKN%uWMvB&L=}zEfHgtkwOjKH@Xsto6av;Uh zhs->Af{PAWnN7lP?R-VnAfqJM-&&Fkk>Efpm?Xi$RxnC}PAmA$4@8x01;3Es2rGC% zf+<$;EeVdcf`5?USS$FP1jkvyEfSn)1uG?(Y6b6*;8ZKPT!J&K;6e$`vV!Rn%s`Na zSn4VX&P9+mVCuPGJE|}rL1B(lQWqjfOF4C#1aCo5coi+d94q*38>^p(pd7p(Vesy1 zj7=-%1BrQ6#|Zv9iP@rK=;Td(SOWs?-inw`i$AKLd3H*FH_Bf@2=!}Z_g65x`lb9N zZuo#;EDKf}_|ugKL2{mPg*Cvq!pc*7skU4O0C;}+CxFyV0-U2V<$a5~R^AI$n!M+$ z3G$w+#>hKEjg<E+b*{W;sI%lfRrQm1s_G^0i7H0k<J5^0BxbDoR^FpkNZu*x3we)F z2j!it_RHI;-jVlURWI*>_<jiU_gAmTJ61i9Hw6A$>gV_&E7`ZyLueBJTXGU6YqKNZ z7=$zg99*+y<vn<@HDbM!cJcHkvEo_C1gaCZBgy{|O}o^ESQ%p|s>iU8$WUd25Ne(V zpBfM1m#;P2T^Mk9DOjM3#_d$9;ymZWnu1mhV#A>F0VuAvxRh%OyhhaZ>MW<jk*Dx` zo+<{w(|bUGZxa7HJZE766}E~<KN5%?EqVR{o4STLk{Wg>@hDJGe^C#aQ6GG?{X}@% z#&r=Fb=>@p%F*^`jHBLuns|ZWTBrb88n}ds*kj{!m7>bAbo|I~Cu?QgWLf`Gj~&Ld zEZ6PK&dK4{hq@rkKaDJ)v|>owAnXT0+TcUfOiNAgq&lg5zUDjY<U^hC4m1Hs-5e|J zAlz1~R~S~GeJj4p0S%bV;Ff^n5@A;09JES<+U=L^UqWDnj`kzEA&y0bdH4zNv%Ga! zg4GAJAjj;jFZtCI^~^85qac5=<|5;OC8F-a!!U?p9N|WHfcq&Pg|j1zp3ge*D*Dne zuios;s~bQ&c{LC~>QXQcJxKE^y&!^DhtBB0s}w+^Gu{UkD0np;s|#$E69RK}^v@98 z5XYjzyy}4@@+vcmyt)7*tP5T(z9YZ*zwpWe`M>0qmHo$fHEK+lS35iNY9weUuciV> zb>q6*;?+>xt(76nepQWAoQQrkAJE{{Vz|R(zk1N{%B!QtAi5!rMTL2F8Is7W^D*7l z2Y-NI>Vj7VcdW?%FTAoq{x5lDWhbxLCwa<{U&`1qmyXI^m3wOZ<zuaQNKD_ZL(sQF z(Sp^(@Vs$j%N=>M@JGD_wPc2zDPcxQnA^T@sc&L(51RMTL!3XMqP!Ms=-vLGix~X^ zJn-#G#)7RL{$^%l!-ek|uEq_t6*S^=EXP*@atlC@kyBmCis;M2ZCc;CO>cnYll~7N zbt%_3R-2~hN3`i7sK_GPGzHM?|1iu!n|}9etN-ihpCP&-jzxvrv<H%;|3gZk|6{$@ zp-rh1$S;*kZ&DTVo0iaFIca2t4Wb*BaF=v|`)OHWXGb1$2Gihwh_=Zp9h8B~X3x~j zIZw_k<ZPJp-dUGhe5B&ILA{2ueQTO=r`mt_3%~&WgyN_IfCb>jdZ_y<*R)~JUdw*t zmo<!90IgE{-Q0NDOW0w+N<G7Ph=lrJ((wq!P>+QDg*XUR_klbr9_o-8g{QHp_W9rQ z`(7pS4j^V93B%uP;CE^GejVZWWm@q5EnMW_V9eJru<~oam&C!*R9U~&F$Xt(JYhks zC#HRJyzk9~8J>Tk0HfRT9RXOzb=S8)r0~P1qDsziM~Awrfhj!s4YZ<C=pXaozCoXp zI>Cc9Tx(ejD`e3E<I0Ptq!2o89D(F(r<?#meSN!>zY)e!No-nhb82#b-;RAK#Np}T z+i`$D+<kpJ_DBqp_R5c50vR9dkA28z&l9|{_vUfs_)Wl1kE`eZ4fZuxx|8GApL8H< zZM+y@;g@$uBmTnGRwMqZH0n^BN4|0haqCZVJDqsf8%Xf`h?JHDKGFcPV*R`HcDvwK zWZ4DVg?sP=CVjCEPa=l2qpSx^UrB$6W%WmO)>S=3a;gNEI)VXKQMcx1Wa;m4FY^1C zCMB>=ETQTl7V6)n{?4&DH@W{c*6&>msR3OVm=sDf3|t2vm}DWt39NS2tmJs{@P*c) z&jjDDfoN3J&*7cgCuuGgESB*-Z=<9j9+|{GpBrGBT+ky2-;mq#9)Xt`GkZB^(EnAX zYcIRMtBJ!VVS+Vmpt-;v6N(eMO}rgqT{g$V{H}o+Sd!vN%E)s98gLnE01C#@b?|p+ zQJm~y2dcXB%r;8_f!YQE0!c;9P}n2ZMdA?)pc4O~IWbhw|Es|`e}&CYcmJosn}HB6 zu|C9xLUt?14`H*Qt#%iWw@5X{jOkDa)f}O1Z(=D0pzK($v!OyuL?zO!KEa-y``RGM z!g0jftF_}wSChAFbi2coLZjXdpR~89YTvCG@rUW~V=iio5_qDkCS8E7#Ek!(Xa{i( z*uFB$`=AXccWMRj!zTIxTWZV)4NPc4x2_L<+(M~gC58%ufBlB+!8t#BeFS^q5Djcb z%ZNg^%C%RWpF_&gT-5F22z8%U0((K2x^pPgl==uwg=}b)^*AIzqo~tBW@w=5iI?Ga zx_Dm24u3Q^3C4eOKVV@YH@9+<F}~PtlR&GQiFbW)2uasA-c;Ps_|iHjvpu$0AN<6s z8yz(AcvR-)q0Cc&E4cV<Xd&*4IG5miQn<VTm1I#NoXLpiHNa4yoQt>EG8di?s~j9n zLHOu%*rhmXljXbEUtu2Ab~kI1{GJ4M<H-}PzTsaK4|mA3VN@V}Z$k5$DX_}83a6xq zfeydF=p`RJ*xo*&b<Md|IIH~#0(&vS&}>zuC8;Oi=+KY%I_WK;L2y$$KwE|6%|$7~ zX}aqQpV8#aKs=|<{>TddcW7QHI_Lx&1_hj7eu`)M?i!`8tdCie4AiW=k0a{@^!}{= z>QfSjgEliv-(wKk&GaPEi+vj5dh_o>Q>)f5|Kb=4yN-nMqpmy&O44${E^YLr2o6eV z394Aox8aJxuW;?e?l@Nfl+_(BSWkS->gvkIJLH?ZXanz^{T-h3s?wn9Nl+tzrz&l* zKPyR{EfwfrndU^#hxe0)wEj^z@#)XKfo*%k79Dq01U-xh*#x3&&448JE=a(T(FchM z>J0{=*NR!73UF92EjmK|g##gNg!(P|bh!VAE)C9-0Z6k7E#p|JS8w64YQy&ktzmT` zr@Dh`2kL3F;A&6@g`jrFI0^XcgWoojyOy2K&ViQP75fUx-71er+;+QSmW(^SkunaN z)~vh_B$4*`)lt5~>nb@xz?SV@^g4fPo7fD<Hw^tZ$3k0qCWb9kjelnSD1_V8RX_!M z*<H39;rP%Q!Q6i#9f^xVC)(9Ekg5KSKXzTZUCp{EH4lTmKA6I4Gy@zh%A+FFE?m0E z-ZmlCZWp16raSH-KC{UmP@9Z&OK2WA7ecci5Q2Q)DyUjdGjK3txQtqXP~4xIa6*ge zt_KK*@mdL-MnmCIuipQNvb7a9SL$Z0Zb45V6`0j!XkkxZ<6->}fCNEkJOLIGpg#dd z8h{<dA|*kA(UG=sq-`ZSfX#<~$j);EIcm-SmdqG}bhN1$*)3QkHf6K{v2+hkoYk+$ z$Ehej-9-7tS@>L|b%3i{G5JB1r18#_orat3#R!A9>vt6+BS-uPl@G7NPbhM54hYx8 zu6qMputriLj2QO+=h7_3%jkqvMw|b^7R<xy63{9FLC49?<ZOwnfg`L`6r`5otGK&e zHT=EX^%|rXUUiPxxH#!pt?EH^p-R^-_L6(#=N?Y!W%6^c?tD}|FPDgYpbb7=ce@%7 zfWY0ZL(gC)+3h-929dMdb)-pNDiz~(x2tKD2#b3`2-hp>ldq&Vpfgtj$)e4I8w-yu z=rf`(+=LJA(x7+~hr<e~v-l)8J?Kni$WTvXp}xSshdqVY4n|i;g(gtFqz`$x+~<sl zLj2zC<j^bV+Bya{2>SPd4D}`4E{R_@IbG*9gY_Vh1@Mq%lgt*XjYZ*N#P#j_aAIMo z7-X<#wNz##S-+cc92T0wJ%@WDruU3?>_ce7b}<!aAf~mlq6`h(;PT?Iw!Fc$!BJJk z2%SGrhq|hdF<p4qY;(Aab!;5T_h)TaJs^Fof?lZH#47qd)fLCqURhPaZj({@dv>IT z3OD{bsvc$l_Exb|f%H14lKcWymGz9QAk?j3f`#rGH4CNU-U#*yV|*%FwhI4*{dj2j zt&YmaBhgkdVCWr8)E6SBJ%HS(0r_Uud^{06o!6=iCqG5g%i&)LQEDGT^}#<uB!%9w zF}w&2x;|<ThMqkJo<P5|hvvITf&WM5+;4;wnhk`BZ^f`y4~8{M3UadxJ;k=(PQE8V zz1^v{+QW0gdW5hW*xpo=3GVap4&#o%sCACwkXrUjK!kDa+a+h_*rPUWNdGQuSU1{b zjbiVb?;P%#7;*M8xtSkwxB}mJ=V7;w-*1-5ILd2P|CuApWO($IJp1)>rZKb>-+JGR z@xyD->d;>~naEN&h!)an$Skf#?}O(<+w26>!fcK-#83MYGeYH2{At7=A<HU48|lfq zagn`(&AS41piTX7%q#W56G53U!r%Nb`;8a0P{X~wtV8gKuD{qo0W&}*(yY86W?1Bj zW!w2x>4&T?*`^+cy!5*c;qw#fMV#>Zvkr4|o-Q+4ycb8uZrHHl2VL%A!i%ns+Tc1d zrp^rejp-*a_bWH{P-gScU>An%yqL8?dWvlL_Mi4p@N!sTrsm>2;Y0Lvwn*Z=w_!%W z*CURwEBLdHF!f__S;PTkj2@%?)Y34b%ve1{xdFjh)mGT&2(>40HAsG7OF4l4ofFG@ z0y#D(-f<HW%TGcu>(~&BV(d+c6`x75O*Q>zqIr8$4mA2s#FQm)OEUlrnb7DqGAQ6A z$Tv`rqj@s?@A!hzGMf>y8KXupUhG-M)LM*}b$03pl8Q;X1^ailLIzLe)OWqu<J`30 z;Drvl_3l-bet-a2jZ9=|_o6g}8&Xg3<*RE^eVR_R2gjf)f~T2yekXVkPTZV&LWA)L za1|kYXh`p>6As*Mp@40{nZ>ul04b)N#hi^|f}iS0?<%;)FaHAq=pHO2wN3p6=ls4k zhaI?2hs~Qr!Xx&s2G^cm8p3ZHcW;AhAM)+eJE<3l`w}iNY)m_F^)9q963Yt>uIf%$ zUTtvI0E_9cY7R<AZ>@B_*5IncKJ5i<c5{H(_tUn`#=Z#H*(HXuC+`DkRr3dvz!~T$ zvF-iZT}SXekVkNauBkTizghKwxHA>O*H1+L+fwr{=-b{kU|&4D=E}cwROUjwhK|}G zv7n^Nbx5ymsxZva1$4kGfi^WC@A}{<X8X{Rs+6f{9S7}D_*>RK<{K@g+JlMHovqhC zR{>_WwpPr~(R(#~=107oq=?&o*rmYMknkdf^WDys+3@y>Pm_4)$~M=?UurIRBbsX~ zWBo{c*%mS+3oX#%JK$81YcK7q+b-<XJ>^fr@my!P@$+rT>=xKLQD$LLj+NKUYb-(4 zfKRs2oNy#$9%O2g>KiFj^D+R)<OC$w2R}bT!Kit;bFlr*3+gU`n2otA30u>2d<deI zwPMVCi7!r|l|_tN1%n{yMTYp-w0f^H12eVN-z(69f>dD~6uI4^LZjMY^VPsR-*Y^> z%^@3&#xPPb__**0Bwq{o&mr7=@8JrE)x5&TWRwh#iez<OHY}f4cwndw{|frB%--df zl0x<YC*E0w{8I0-Lfo0aDVyyXwh-O~EOTi+2Oj1efI09m%***9g><ZK;j+FJHW_5B zFWq9S-@{$|>C<2U(-4END#WTiSh31A_J6~`s%Q@eM0f8v4Eqh}kgVA5m&dEkh?c4C zX$blSGz{{N8}A-W9-!@x$n|R+G;T#PT+aSI236<|bWVeAnEP5zwYy)Qpk^{EtEpx$ zVAXaEHi*4b5H%V^TY!jVO-QWROty3nR>_N#ViM>UQaz_+?>}49vA|>>=IH@)fM=NJ zEXW)G8Ss<+cV_2g*QBOkes1p`dYSd#&H8V2q(qgRmogp;v{)pZg5M(VxJ)T+$8hN+ z+I=P`6dGB#`4bugQw<51k_4B4#KL2!Rq@|J2%zE?bdG_J6=>X7YJ}xxlUf5I5nKwE z`#ni$wTsYdZNB<g|C)qjF;VW*y;nQnF!|cHz!sDJEzslJt(_8lVvD4WU?ys<KEv|E zmPX$oP#@e55f=Kwj2x^m+3$vf!<lfJoxe1{L#LC~TplC|OsnzrC~?e9c*?C|Y!&?D zd1ZQj=?c2ILuM=tv1@~GF?=w|d7Gz*2650ug*&n_`Io$0_aU#ynI#29@|HYZWMNrn z03PxNLxCzTp$?KP7k&#@3%(JjrZ3UM&(d`nibf3Mk+xlT%YR)bGDSv~T6_UKb@a{V zRN^&sCaSFW>Uq9iefAG3m6M=Urk+OY(B#$$N8{Kz)@Y=H1!}SMcxcA@bL|3YRIi>w z?d;Z@0AQ}jhC;~I2fzEwh&s7Jvndk>9PeO3N*}T6J<NZq&*2j|c{sJq?Om3+jV5<e z=F5>~{?3&7+b>wAuVb0&9)Rlep-%Nm$mptG6YVl~MwZbJz^vCyDPu^-G9b<9z1Q5+ zsl;Idd>P00g4#Y-Zee(VX@Oidlr^x{XBmy2v5p3xTWorK6L7ay-wpidESyf@f(NBW z<r>RGR?ql>gzF%b-oSv<HhyX=zvbj=!a<k%atc}1Op-4I$=DBL-FxVB{A%#`Q)eK` zZn6_nH8bs30)&~e@vaYE@o9L#)$2aTei}aC<GCID!O~NBQ335u@innL=Lp`39lJ{U zsqA^g7KP_>^3@#7qVO=yxo!>aA7<tK>Uygo{QIlNs~4w%bZ(Fb!NZ6rZDWku{MQrh zff_)m2eH+GN_`ZRT=?#U`q>V;0r2#}!RvlC1tbR#gFJ*_jn=9bp_ak-5P`Wj!~gC~ zeYK`u{eZrS6;a?YF}4B7GZKsc4BRr1#V_z4Bm`&4Hvgt3Opg$?Nkn!Ru_I>-bM9o$ ziJfvjDY%<6vh-f9YSUq4ufdFr?=s3{gq8p91!^Z~4P9|7C~F2~7GXI$bHo%CpUJ7A zO??b)gH&=6M4;VrzXcf-kr2ZePZ&z|!HPpbOkFPZ@+jK=hr)Ti<&=NunqoI&-ESd) z6^HvQB{@Y)>^Yumu&l!6g+(h1oz%R`#16gI()?BS{Eo4p2f_`0e=}LfYe?T=;R>3J z?+II<E6bfWbv78uesIZLs~?~T$~s&tHmi`1?ps}^?w^6Kfs+~>-hwHYfEWJ8G$;VD zr!lRI=yL$h7O%=Q?TNUa64$D(nJ)bYn}HT}mHrJCVf@C_c-b4wfVCmF4eUL4%1*P3 zq!x7xlJKQExVf>LVjO4(Qr#3&As*_3-+#=euoS<nJNe2siTrM~3G)tiM0)tU&um-k zyUqqSjj$M3WBz=d{IeF0ZEC;t4j6mQi{vD;X-=l0+mVwCl?#>UAWJOY!i5uAXbljs z>mcxmt!4QgNaY&oEmR2xU}bRf(dsRWJ~;-?g5+2GrSASF?sCr=CT=WllHofo_<l#L z+JQ3VeDMvAf*tqLP6CR|81*vF&asM(#|8&`>rgjYs2=gHQCQ8z7^3Vk38JR4xwBf) z4K^4F!EVs1E(B??Qo}$94`D=~LGTZ+AqnH8+O5?oYPQLlSpFo4=^z&XcLYPI!+1vA zK8b5lNsz6OJS&i{V)bu)2C+%C;(ITM$8xjFu5uY{B)Uv$R)c;lsY$g%z0|3LJ&Gpf zSQk<91x7jS-x@n~FqvCU?GtZ+Jse&6^Ska77o&pg6Zl>Nrw@#-#PXZ0J`pjjcC!c2 zwzzzfr1I!cy$eFvc_PQ!FWDZ_PKUu8Yq-KM%qNKFa8(iDt*VIN`=y;W2`Ox+UzwbV z<@=<aASG>5TGd2kk><8Xc&i#AaV;t@jqQPMt@Ek*CcHtyO=^aO-DN!4n5cgjciBKK zYITnvZM&O)EU8JQ{aBJxBaqaoS&PvsASHn9ze6P)WV7!4utT##ZrEczJko<;CR?>+ zL1e2Eiyr9<Fmt0}IO|^sthzliP~UKSe8YIQ2d2IVMt;U-((U2UJY_?F31LQ|*#qke zba#xlX7$5l`Q5buZBgT)n(30W&1wjeIx%83DgvYd3M&<Z(&~e?nD!$CXk`BmGvY9M zAQ|!4jggGtDAA0_Ky?fwh61Z*#B{EX%skSnf{Z_v5g!7xVZ?WWM0)(8ziCD|bmeo& zh?Z1g1a32QAp@G#C75_`jgmE*=%lVZh{>FaI6c>h0?H0-1p{hdMP+bass4>GNOa=U zlSs1Vz(GiW`rrcxI`B!)BYnUD?WEJ0s^2na$oD#_WoT2sLi>|*SKbuKxo{U6AY&VP zSzWs!UDgh^k;u`B##CVBB66^h_sxEgXPtX<t#4#hxD5vzO1@bbNeO2@-G=u{52lE^ z541?b^)_vqP8ryrA}A~%+SFM@cnlUD>wG7Blyx6-Fqj}RtIhw8#yH-_I57ev8n{iJ z_()^KlF=49ZR*cf|G%0|4R=TfgY+uZB~Mz^)#!iIDh{q&-{AU|FkDikF4PAgqRqe9 z(&k%99TfUoa8`+#u^V#ZlQ7WYAMmdE*5R3ntrOkis`9_E!-hMQ!XYU(;8c$shwzB( zS8(wWE}yGnITwrg1oLt5oby;QGTI9m9|HBkD?b1yzOWZC@Dqf8Y?acIC9+mwU%_v& zs<hJFD~ctJaM?J`wBlFdCZYAabakox#{S<?nxp$GM5BYAE{nOS#BaiK6fcF}9WFo_ zrfkStS%@4u%>2bm!)e7!$6RWq5w>{g<zuZdVV6X}F6jijBmx$y1qau|bnk7*v1!lA zF0y|wS)soJ25IKtS~(Jy2Sh93oVp}OQ%w335r?`HG#_@L0?v4j)rk0_l4ZJ1q@x2c z!i1;Yr4>(L3x^d){FdKS!C`$kBEtTaG#9{su_t>O*)2F22Rc?3tqk*x?Fi5Gc6v^c zyD-;%3C%Y<#a&8uio~(*8t&53Y!T8I8At4lV|f~GY!`XQc9D1NXe%%K9_wqhzZJIH zn0-h36W%P#;#p2^>2i0G?w44`3l90H3qIxHF|Zcji%W`@L1Sa@e=HmV?+N2TUs+KE zmo^%+E{|=k<HOiV2isc5hp{uBv_!xIyT-$Ml|n)8F6vkhj4gaPCEMmBc@eo+3*)mO zb$+&kp;vZxR@uxC`($Xpp!PClhwBhdAw2nmZ%1Sogi#9}7C)C}-_8$Bbb%+FLOk4% zLTzBzgKf4Lw^f(pEqa4Pm?NksK19_4lm_1z&3i?zHBmIUzH{gs_^+U+(lgwhP`=_P zR8*&7;+fF6Cc!)LoI5?;(t?{14frVk3GoBcFwV>+7jqweD5L5IvtMjb2Qj0{xy@nu z)_wZnz&4b~N%QwO(YY3Len!>wDE~Vn_aGBWdLHmR;7=?+0XYLLb7109$mwk$AhG;R zQsZj&jvMY7BU<U>%}@tnjatDEjvA%3UC<0<WI?k~Q1DX#khEG#Gnu(~Fgr<87jUzT zi73P14SsF#KGy}_a)Y;}33%`B67QElg<1z*Al@So{s!-}-x|Dgy1@II!Ml}sM_G8; zYi)X~4Bo@Udv6%;@c$UR-(hm@%!g)!cPjCID6=>Cz#d}bz0BYpu?%>}hVlN@!uv!Q zc*g;l{A~&W?^+9Q2YNpND)M0=@g92L=ELi-3z2r4-UZ$QgLgCWo@e1j(}(G;FnBi+ zZ+RGR(8Bv~KzHWDR)cpU@xBXyH_peOnpd%nmRp-Rv~KeERhI!>V)=_m^0}H~=Xkz) zqaVRC0tCasHNX_W`Uu!P0;UMo;5z1bV=JHta)$cXKGb&9M%S^4-B)&pp;_Y7uK1Fh zI@7e*(6s$1K1ep{r0bY(cdU2Kv1m`AGh~~ATuaD)^!0d(Pr?S3{~pI_;(hR9fd#3t zLcJFQ4qab0Vy(k9_CCDpgTMMSmLzJU%Y6EFXROE_I_{k89JXdygyEGl+YOH^yb&)S z(&SHm?u#Eg6kU}#P01>S-<FlQB99dK_~A7T=de46g>6xBp=+u5X~EY{obHm<JXM52 zYwn80I3mc#UHQUgJQ70|dRF0KS+-q_mbd5$j)izA?}p-S*?i`PKOkl2u#{+o<%loI zT{a#s$;&%fR$j!zH(AN*&Ka$I_|}r0kN%6Sd^2ay?3_h#v-is>2XYZdN<<#c6|9?_ zo`#P?I`9(Ul8>X4wk|B3cn0BZl`S?fopKR|W#`~)Jj}%KSrK_8z7xfS;iy`&V!Xg7 zN5E@8^Uf8xm4{VLr;LDO-r;!9?c5oh=BQ<Ht`qZMjuY;Bat%Bky<0lZ4&?v;(1BzQ zwC}XwZa3yY+vCpid}|JbINO-&#I8J%3-}F)SC_woae_TkOJECw=Od_(Qg7x_Dh}l~ z#!T$x5%^~a@Grto#KuOVY8Z8pQ5Q^%(ouUEwTDpyY7gT#wjyHx-s5}N2hC`}^j8np z;=krL7iX|)-d=8Tp|!b(rZaePTMJJ<R3!{r%T294&`W>~16*4j^n9D6yzVWOV{1-# za+xS?$MwP#e7*?ATN38j;=+;bN}%vgSI2Qr;Y^)X#P0#R4V;d%uxPmRkY;^g%W0fr zdyJkt+~wW)4o~NGiRBv&md)HsmoB&3gqqdkK<hmb<>_0M^(__&pI^?cV`4=j$o7W# z5p8Wbd+bPU`+cdKXKpw*=ug@0)$;@qJjH6C)h#aD-8C6x$Kh?a+%pmIvm?kNfG zJWgzYIR`d-_{e5f%Z4duOT=J(M~#3^M5qU<BIIln3Si`XlnMW5yTEzdqARp4IC<xZ zcG@Z8_JLlaKqUWq3>HqbYS9kdusXUI_2#7d$PxHa_ziJf#EOr&HL7M0l1yH~V&`cz zd6poL-5KscB&Gi6yGcz=J*f#FX0V;v-uCBlcw`%HAURZx_+oNyNl8(OadR$xgz`z; zY~f8@7vnA8o}{gZeAwNxUa_5g*(bI6=DHKcq<wzjKfWOg8*#S$ZwstO^!I~{aTOd1 z9znkjHF=EMum?>=4Yg?5{V`exaXb1tSOR~An{ghCu}bx|KSs`=)B;Itf%_44yBz(~ z!P;PO#fMY$I35r_Vl(Ykl+B@z#TUjX#$tVNEt<_b1~Psa<$f*J(k<+>=2G~S6&BU- zyW_8a*{RM3Tg3fZ4_Kez%&0wdDSnVyIMF|!H|Q5Zc?8`kd*43P%^{`%p18_2t)cGI zAz5a7KC>yC3H+c;^%J6kZ?ZX2W!<6?{vqW%zBX0e3d2;P+MtS_n&sM2cb;~(hZfUb z1${pij!oSuVvbif8!8oAmA0vW_5|;F$e`xHYygUsSpSL8#ZaRh4qY(j;GahD`v}nN z|ADQt4?dA6!7Rr>^+@wI#KMZs6aJcVZ%~7lQ*$7c>Vv~|9cU|q+Y*uI%G%2nx<ZXj zzVBqa=URWingfVY%gHhJh&T`*x*qy59=TYZA)mx#wQa=N`fing{jt9_Gom|OgXGXT z7AhxDq2dXF!$1u9fq#dzJ!y0O4WSsek{F2i{&SshT_`q3f^1I8&QWF@T!HswI0Vw# z04Mbl@Pewn%wbBj%?RioDBGG|;aD6;fUql|Q2{!nJHcNcm|BFIJ_%0Y!1+V91wVLE z%_@)U3YpVrPsO<m-e0hPla@?2UK&!^$Jn&V7#QdF;1-Qqs~F|O5gw0=8q%Cm+{M9n z!$&kq^^B-#M5)FB0gnZ6MXL!h))e*Fx0s@yg?OuuGNOcY1!>}5I1PFpd_+T(OpGIq z8J+Aj^kt(`x=^yF1uTnnHh}+Vokn!7(+JdQ4ve>~I{gj@Q@T!rJJ;!j;?8w?4KY@o z8ooiD-v3h<b)t-u@5ABE`f#`KKh(#aUAkP?L+sF`ZKN6c(}@$DERRSt?b080@WVZX zUmSIIQz4wQarD5}K4to~o`W?xw~=yfX@(^LT4NPrEXor|`5B<RQ(JIe=J&LykFxX+ zBmXzrt&Xedw{6Qh&CLf&EU6-Wa~}pWdTnC)-%*IT={e0`U)uzrKr8;J0tj#l_PgzD z*6iG^#-5!$cA`wQ_UznG-3IiC!__7_!^-L}_W?LLV=l$(Y|gn2se}1aQFlkofMr0* z$UT4L;QhmE9K6=Z4vh=G6tL%GZN~;nsWWkXH{vrQbfHnI=i~0Uyr>4fPCdWbRviR- zT34-yRHzT$Am~j?B-!KC+OJSXaE@d@`oEobJIt4Vql|AhW*@a6Qk$WRBd#{(N`|Kb zczblUzMP^qW76S71S>RfV;a~wiQj+0^<3V|JMR!R-k7pz>z)$&vt7SBAhqYh*JMpo zvI9H}n?zKlvY%MiH!^wO;SN(m`^s3HLyGPBGDzIbNK`LkC1OwKwcy>U)A@6laxty& zX40<D__Iwt13dm#*mB16)7`kf9H)K@``$>wej6uhd?enkz<Lx14(Q4J1jY&czoE^s z9Jb~h-5!?wmbyTkQVO%bUg5Fo!qDk<2=fhWWX=IccrwFpobxVGn`*`{d@v;OkNe;J zJgL{t%5IE2XeYnlDS29Kc<CNW2oA$oz#X_hf<n6nSD{QIIY)?ZsbvqALj;*GNvd4V z_hQNzg2u$5#cQ)p@=)cp+HzzKY{4Hi@pB(*n-SChD67Mth1EPb7jd0so3;+lrp;e| zj<Njfs>~TynXN3d|Ls!dn2u#80e|PO&mv03!~a?~#}4<n_%1g5vFf~(b=e+w9(Ask ztmB-7Z~B(3mM=PKIM%tiXk~7R0km*IM-PRphM~N-@W|ZCbsmRV>z`Qcj%TRb>4!x^ z8jkZIr{xMqYgK8i=oG(wHZ;sv-+#8}kY!#5>tLAp^H?g7uo69g7tWTnfY9^!Wk4Fi zb9_KnZn{B%0_{r|6J_SispBoZMo0QsN^t^~mC4iibAGFkxfLgKAQPUv+x)mLkwp6V z(W)-!dx7*NccO37{~>+ZOZZ`8CpUK;>D&W8Qun;aGFwx!`-Yh^?baxia?!y#$f{S{ zL+)5rI&QkRV99y_N>gpivKtgZ`&P3DU@8{_P!2E$Q&q-0_qcZep6?ADKr)3!ChjIy zxenlBTz_O#yM70g@+#M!h|@@=CZJ@$Yfn|y0Tqt{x<CNJhxkejvH*_A+8Gzs4q#=Z zeGe{$Jj8~Z7Q5f!=QQ6*XX1TR(YJ2Jy}Z3n6e?FCK+?cFG)Z;1^Aa2e2yvXzed+G* zScBgw%Y(sYi8Gw5Z!X&gL&_AigFMu^S^W|dj3;hs<&e-UtiM0i5Na&aYpCE-U*Y%` ziy>GiHmj>3L~IoFOXP1{f1-UI#AffnLPN<YPy%eWtob9D2Ii=jA!TSrAxPgspgwr# z?;&_BW8rvvZo3G@avY7r`@i>NEQ1S{7L}}kPDqT1?JgoXsOS1I9G#4JR}_^%fk+R~ z!wo7U3%CZyCz(-D;cBcd^KbJ&pV(nk72B&(Ap!Yh9EHzDFxWk!e(>LEcSLl{F?PuE zi(r5A?7K_o7onA%cbE+&j<xkCyXerb0S(!X=7T8Sf^LGH(mUKWl_9Im{tJ+qk!PWk z)(3mMN>OhmhNc8#UzQe)P#qMW%cY8~I-oy=sM=?M#abTz6PsPt`U?Im0X7R)-h%+4 zUf^w66>UR$XT88s@bUlnduL`Z+-lS}2g)q|q0&D?QP^|O=ZpTy#8LIhN2u3=qiQT1 zx1&U}T$!YXZqW;p2DK6yd{;T(SgHx=Ab9WCZ}LoX55l1DX6;nq9xY*wK->ZdT-M+& z^KlfQk-{PLUY5pH4*Z3JiWqe@rdwL!jrPazcEAOQN<oyrA58Mvhk4G-M8sK)*n=xx z*jkE4pikuFd=NBoN51|Kvi?H@MKF@%VgPDo*|mqYAo^sR>D14L^)IJd*-PKVH-T#M zP&cy;kog3=J^kSy+SSVZvI-C?=L6Ic_sNO-|B-&?I{1a;x6P`coT*pK(dDqXz=VPe z!Z)Lo1<=pvZ=--#+QZOZmCLp-e*?}ninVq8gm2fyPB^hf=NiFW))GdqAL)7$2&E=1 zVq=bzA<sZvGw+FuR}S-iu`cnIEzxKKe0(7s-;?pr+wpavfh6FgTw@Lfwy#Bh=!TC< z{braDodi?Y^I491mSR41mVb9lT~(~tKOpfBeSJqq$L#dCws%YOorv|+%ldFpJ(>sq ze*F7YC~y6)3}9oaU&~iH8njE?Za=5r+8iXQUc=!~eEvFg6$#h!<D%+3MEXB8F<h>w z{*0+tzlNlRC*1ue^GPn_A7&9Iq7q;?RQ;YYmM2qdMM3#l3WI}^oV2{$CCm8<U?7%0 zM4NGcV_=ULEU8x&IP1f*K<*%>wl#QP0GK1_#40$@s3Deg0TC5E2{2@T8{J*3jp<t+ zciBM-?ggzs@fuXhWl8H#OhA3sVN%Ce5H51-Mjr#4Wqf~v7q28wrsR?DU-tH$Oy~q1 z*9m&KK)3qZqsn^w+J_iuhr#_3PP!K0dykmpxyDqVJ$C}r+M**%D?MK=tz2^yBNSyG z$xu_E2Gpw|^noXtOZOzrfM^}4+)~Y2%Al&Oel`5NrUt(at2w@?KR4eHkok+VWuaMb zT4SLx5PO$!yx#{MIsO`e9YKXZf&LoeYaAv<wh1Akf(`f!j?YJ@h~W6?<PR^Xo?%!q z-mqdXZ^}imxk)MsHcwcq+u?Zvpk+2XFu-ERz-)e^m3LF8yw#EyOrOw+-^(-(N}UET z$+S6FM`{h{c7=b}?7?qv4qF!d_;0*hHSTi9Dj25ZXKT9|>A(Dbz=o_7!h<$-rOamd z;s;o#H@zFrK7!wY!8<CrTat^RDig<~zPf09L2~6+?a39Z0I&nkeRv+j^Aesv;0eh` zRMZ3T<GUdAI<I&_`9>+RPGX+-z7rk#mG_<4(39SG;zL{QS+o&(+5O9_Dg1AIfx=&l zHC<0sRgb+_K|9yJs&df*e4>FTPx{K^FSc6bOBaPn2GIRlw(7JDo{rPTz^j0vb?wV2 z1#jwM?|%sr0!v^wFaA7+`_Pyeu$F9>6M{Ox8&5`<TCK%GdShT85{Q2?4wE)wMe^<X zuds<`l<&3bc+PEZo-q7q{@BNL{wO(&!bu6PcJnx@a<k;7zqd(#U`f2^{()%Z<O=00 zcMQC{+;JYBv3RE7$-r|no;&bt!1HrF1$dsp^97!-@zmmZ7f(B$q4$(KF2^$u&ni4s zc%H)ZM?8D+{2k9RJOekBJ1)XA9Zxo%r}2D==aR~D$4opo;K{{Pibvt8zPH>FSA}mb z;2D8u2A)NDO7Pr+XDgnU@ce*h=6%SI=V?4I;dukkU+^5nbN>D1j#u!!gXgkM<&HEw z*WtMx&!c$C@w|v9`GIoBCOpsL*^TGlc+Pkbt&gV?&x?3&dk751^EjUP&8QEaMR=<4 z{1#6$p0bCrxWiM2=UqI5eh&KaT#n~1Je%<R63+{G-o<n6Bjt`Ycpk>{9-e>TIdcp6 zf+rQv96XEgl;F7s&sIF2;AzKm)uZK(-{7gi^BtbJ$G|T<L-AaUXA+)k@hrh}8=kxI z`~pukp11IPk0<dLs5_noc$VSu;PK&k0M8(F$V5E*@%u`==i|w$9;%wY!$1sPgQZhe z^(gpaVrZg-qSZbLjgn9=wNpY)37w^0l~7*^!IzSRVkLxc<4Ne)>BQMzZIqCb(3z@C zLLW<LkSdhWUW70*;u<+ZU^?84(H;DwiA=^k$;g9@e9A;}@?>NKBdY}2xoW5&TPLAp z)lWjVAtYx)@Y;ShZB<y#0aMNf=AL6vjxZ=o895%2;sdTly|P!vKl9NLS7kDNPz2fr zn(Q!nuR(hWAzHBmX5=9gIhc`On8?E>vO6Q+HIai20pDQO2y(m2>_-gbCyac?L~<fy z?e{S9eiPYbB41(T9f-85eV#?%J_GRpA?BNG%_g#pk!gs`qNA7=)pDG*%4*wi*D=r) zynrb$Qvs|#wo_>P6ih@4H)B;00D5*H(4ulK|Jy3>qGKLQhzGyuhYY`Y23i5NsRj7e zcq|@*e?crUyw?H4Sr&%6NDNOBL!MxmEf`vV1q^<~1}2KgY*7RBx+4+n^KOfQs9hIa z&h!kEeoRiFJd(bF>E7VANY7F~&{iyXHGi`Tg~Tr$7!Sc4JfHE^z10pz2hWtydFr<k z>LsBR^@N0e=o@DKuZa^IMDYW(VH;-;@tE~@h(*n<yd2VnE8EyCVZzt|SLV|5nv~}< zIM5d#SaJL$g8JL9BX*U=7{7Ewu@E@xgV#LE`4E~C5*`Hx_+1BpMg3Ba=BU<DpCLC= z1A9=M+KJZoz~c{=6dTb2*wx^yY11bB3|<BD3D`)$M+rFC21EyF+wCP7*JHtc2J{F) z3p;{hnPNbxG7KuL!-=(pplKaJV{FhEg1&A*V}A+IfgM5lIR{OEfIbLN%+no=3|mwq z@<2fq=uZS6VQ1vQktKkz7Fs8lkjN#D69D<%ZdWbn5qegSD(i;1y~kQei+|H15v6Gk zvEoql7#5vn70X?pvFU43*{0ZJ7JEylVyVz%u@l3^uIZ}SRUL{Y6T`(mlVob!q1dA+ ziM1WeVuNU9&-8F@tzzHOK)hc2@&wtRp^6C|%3>>o%Nl2uMGSTo*P61XvaB_o%3_yb z6&Hldnr4@^jfSH(JK2okvi2r&_^l;GunxZibAg_iuEp7VMO|X~^8~0(jijWF&@&P% zHX(_~yql4_JC#CIhqr{o!R5?f9i`f(h($U}Tnb<*M%Pn>%s`}(_-~?AGwyD|$XD4+ zA7L`J5I-`_Vq`xP*=i!MVC2a@LP1=TK|hR<K@&-LvCQ6^kq1oVKoi-DQ5<{&kv0Ra z!6`JhDU?+W-md}X2tI*ykx%db8yukJl${tIyh~%$uu;L%NL(jzq;BJC6<nDXuDd$m zVq$dgatjxOQNi;GTb-bG5HxsZB<5!#F&`Jq$9o$pM|8l<#OUB5Bnr_CMg{*u*y?^N zTQI*Np@Aw>LN75ircSve^t7anR98soVT45S*P_09lud@|CKU}vO)tOFa?!s)sq_tr zZH+4HHOb+{n)$w)kTZ}Yovcm$ybc=TnT*+Dy4?YsnCZ<SWX(iiba+Ot37!`&ZlzTm z6RqO@1gmFV9Alx&k9Dv>WKF#9XacWM!Mhw|8}LmlxRzrIOthhgYYaSNXnFAs(DFKf zrG=XWBj?~Nfid_j;!z!6%~;AlPd|a#W5Ya-NDh3nsSvk4vMJd`k3ltuQG}(k&w5Qe z^Jznz>bBSF?*7#IY99`CgA+(Wbr1C(kq0l5&~WvpgobD;sx}=#<8hFVhXZ5UhIJ#D zs%c`D?{VEAtNL_xpJZu52!zLFpcd@>Nl&Ane`F%(n#dDRA#x`o%`7&7$Ci2)Yvh46 z-SD=kGm#aA25xx*l(%6W;66=eG!k+)&Lh!mNhpew*}dRL@HSmam4pcNs<C97kAy7M zQ>dMV-+=;PB)~@~%pN8!(wS43?ltLu?3^AIOkg_aRpx)Bb9!{J35Q`>>X)#BUJyKt z-{i$CQ|(w*`yB$vt#Q5h8bY$rpZyO~id9aD4gOjn*n0waq@eGK@6E%w%WT8N2iJ$; z048uBoC=o|TmZPhCR3#&I21;eVK&vw`i6!Cwwjc;bxL<$f^H6BO#KbJeBH@O8AW(T zLNGxJbt1x^C>F8M2+H~g|AA#dR_$phz@CD~bpjd~+zFt-c2jt|E*uVR71`3J20qC} zB`m@r?peIA&Z%}`{S%rZL*aGO27$;7T&lLIe{4H7!$Zs<Cy6$W(TEBoUFC!};7Smp zs-bzC7?<cvLExu0>#qvIZEEgo7(2A)6mmw992zrX{BmptzeGx)|2B4$HsvJje#9V9 zwQ0K<ONFE4G#QL8#yXIU_SG;AuHgdZCg)c>P$_&4s^$eII2>__Res>P)lt&|h)Ngz zc;Qs;)qvwkUDWHy5X`fRdf5~eBSj@v%t1nyiehoWG!5jfsU+gWiZKXV+lbGUA*gPZ z%zsay-}bZMH)!~n2>9RG@NU8nCj1vzB3StDx6{j*-u6qR*PHaja(*Wkm5kd4#7zDK z$>h|ALqa}Sw#U@tAD|p5URlb=2EE8=kHua%O0>uFH)L1v7N*Y-&a|iy%u70?M+H-v zzR;w<(>Xml=wy0<Nq@d`dQ8xP^epu<oYE`^wqWgKCMefK6k(X4W?)!y#t<>(t6|WQ zSoJm_vs9Vn;@Njr^+oD>GALLrp&@Fjgq}i(40K=Oo3y#Q!V&$`TBI`519o8POKxta z=m0nGe;mx7Czwa5qf+V&2@Oz(Bs3l&dlB*$PSR{HeG4u|2L}<F(rzZf?L`O^9l;;4 zJVj{@UIwFr|3WaU+Ntgm%!eg(zH&?G0|{LKU#_g{E`+S^QT!ERNV69xN%O(2p!q34 zAW+kYimAVH*y1L%do<vDbp;W}%q{8w`kO=-N8Au^QLiI9bf$(U)(T+NVCq8s)1Og* z2(=3`JvFi75)!Ds_>$xeCwXrJyhZIq!$<BI264ymI-!tP7PeEt>fpEdBWxNbwV@=~ zN)8=Fyj9VAn2Yl^b8cwSEkp{|veESRuNkrG<6nRQPg)rFNnyk|0a3w9{4unhXVd18 z-ONPNHZ+p9?WExb3)9^;re_#`wH1G<w8>~I_=t4Cp$t}^rhd;%!F~vV)VR@TXmaxk zl6VrU6Gq0H$YG2Onn>C~5wbTU59r9MP2V#XZ2dQECefLk$nL9QBxKO<G?1@`o+J@| z0^uxm9W1XG1Ruh0i;q_`hUGd;5x;p1Mcf96h((e3oR84dW;M#JTXTf{=?API%=ChV z(C#&mn)E3anEI5S*<Z)mygd$NrVRFF`dpL#c<1z};5Se&1a2|uYdWV#2R}f1mMZ^( zm1*Gb>T}eMQnea{ev)vZS*TZ2I}qN7gs&E4eN=Bjwp>C<s$B|NB%uq{*An8zxUA~F z>I(@?me3jMuM!#~p|jO)2@Pk6%`}%mnb*dl0|a{u)L`|bK+!sv&9I7n11)_n*2=-7 zCbG;#_F?2-O{CXE9^ZmUYI~S{gNZ!C$mdPuCKLG{A^}vjselon=;goBnNniKT>#8d zV?QT9Z#S9lHJKhGrfd^gZXzofIm<-4O=Pi!KF6TXH0aM2^nZoP@`51!<!4oQSI<jf z^!S-o-Az3%p%dt-S=I6CehK|kLUC%ngy{N|+OF53hz;w@F1n3_9rMF3AhPvkuK+f9 z#{<-t-NHgu&&?pW(?b8$J{{3DE~ty_)8F0!<CpBL>S5|XL>HQ84W4KQ$@ck%1uGtb zoV>zH{^GDnUTBhMGkIXZZF=_8SSZ1$8*-+WkQV)UPeDlqdm#1R&*eBp?UuK(_Wu}x z`rxJqf$3oQOqJ(V=ueK)Qhjy>ncLys!w7^s_-g!#yAJ?$5Z^_3{{)yby8st=b5@6q z#Z5j;0S?@^b{8!!a=VLG2rkAI<Ss?HB!5|+TjFj)9Pee_Bo{OmS#CYUpIdhhOM{!e z+{wko1^G+l6Sk$(;7L8V1lRT8BOn{rb<S-1ALFHcn%an~P&Z6#3UC2P$^hf-^G?<Y zg2#c6ciCzD&K9EVFuxjQg~>yPFO5hC_{EXw%+Cnow&1NWCVQP95lkm7umLQx@{hz1 ze$zLt0H5;BEy;urP5Z09i*wy8bMe)SOXQZ}m`ks?e4OAQ{VTFp$?r={{!DNux69lx zJmN*Z;W;V1HZu$vhanGXf#%hbo{P@`PxWZ#=7O`Z!e-iyNRxIMUfN}&&}lZ^EG{O2 zrJiC~H0I{OTx#)Zb9IJo0Z)f8ZRA(NdDABRx%*MNd<<9n9v8Mj4tU77Jrj@y;T`Xr z=W2NN?J0A^zh|WB-{c3+Vwq<ie*ZVRBknlJwZD~lr~@tg^Ksj8867#^kYAWnw6fHB z<z*LNIqu^0+>2+=9jnXAG5FK<WkdGG+=$MK8W$}t#Z@&ozr4(=q0$X=OUR?*B3!l4 z8Rg6>rA-+6ylwa%W-+?68v_a)(&a718}_gHD?BS~sw|#{FKB@4VIx_)|BN2x9MQQZ zPTpwkimD63yu57GXyGM&_*!Mpo@+Pde=8Ov5Lfl^Vd~*V4q*!zwr4f<;y4l8SQFN5 zy)w7dt?9TP@&E7JQRDvq*n1!FsEVt9d=o;5f+i{|D(Z?LK?99KDN5A9W<wAH3n2&! z)<6;xj7gg83RKX=B$nl}N-HS7FKwx!r4}nyT9Yl>XlR0!T2xf5XsM!|b$M&56eC3P z`+Uyad-o>9R%^e{`@GNdL+|F^Gc#xYpL6ESnKK-BZZqF6GhTXjYWbo{nDxnR+y8Qm zvtDqQfaA#V_N^>gBJIm|sX}Kiq0<DjJdA%U&eGOY(s$?eg>*3aq0wPX8faQv4%X+L zCJj`d!%q^-EnicaSRna_z|iuqxb6oAvlR|Ul#v7EGi~bdRxrtyxi`o~p=Mq@r)!;Y zwPv0^1*AQmGJl<UnVI=TX69uo$jot}(`)KUa3LJEYKiqj3Er*S)fK;sl=fiDALhbZ zj)j;87v1f_2GHbqEh4EIEFw(8q;1G6I6bCU`$0Z5O(ISGH_q+ND4>;BS3L?WR$itB z$_=0vu<oL*M>re8ndPJZg-|~4wbwrS!Piv)6{OU0=OdQXAq&$^wHM}(Sg_Ev;+cE( z(E-!m4A(bz&DCd|I@Bo$)4nPw+W=#5`Jk?>)Q0=@mnwoiOSqu#_~)0y@`Zs(*O*0o znrOneC%|m`vQL+ffW36*>YQ<1>h`<f7;`O(qn35zB3R4HZ55;Ae3Y1|MH&ZAun zJ&#AxPMF+>Rr(lm5j_VXIEG+)mw45*Txv;<jW)}8$8ByoX{E2XU`IjA8QIBv--pb_ z(^!a^`fF6jgN1?NQuh;Cdw4eXUOH40+Kqo_AhSNLrJ-@m*^d}J^#2cJXUjTwOHoZ% zq{qW7Z>M@4e_NtkLy&PybKVw|UjOUrbBFcX<1cvt=l4)Nd{4%QMP{e*fLm=@RiHwj z**E0}ki*K66AC<&aZ290jH-4#2=>A<2f)3g9PUmR@B%#WX?VW`DR&D4B+n?Vsk&8Y z`s9M?Bgc*V=9MEakEexD<0oS*VovVD%5pgrF9MHd21Bwc@$Z@;aUTO#q<Dcc++b6n z-9s2vJRXpRj2T&6z6ie4%Sx6O6~h}c?3V2e?6lx*#U<b<GR7_YVe!UlIaaCqnKiT{ ztME!~acm8{L0n_)LQh~h(l{pxJ^w0p-e}MT@2QyG>k!-YTZ-PbO<Zv)g3RkJ2v*Cs zko3T-L|w;#)bAyMi^Jw--cMlzg6DBO&*6Co&&PPiY^itMif0R+7@oesa3P*dJlEmD z9gQ&3r418Ggwa*kJWzESknE|^D?|{k7T^M_BQ!B9x&bhqV1y$<ih7X=ZZ{MBNsPpp zATzp%31Ecx1@$UCsF%F^Q4n=9OuM8E=EP7hS7Pxv3>bndcn1;<{m~-(TfGOMQrvI0 zNY-OWy6C5LR1RBXJL`<-Aq-eacu}{6-u=D^)9B=LRfd^#sGT%D`pYku^zV-%SKS<^ z>eRXclhkikW0F;((dwShMzJzGgs99fRAa@kY?e+WcCu!p4^ZD@nyXlg2N_9Pd`xVF zjvC=MrWrL&&12M5My<4?j<YBKZR}MHxDPPXTcSG}5VyzKZ_0fYrYzALU-);{HUF>q zKF`)#bO(3Wk%?)+IPP)+VnGF+m&36LF59%v;mX|u@w4V{nkINx{M?$N9H6)ti`4Xz zmw9}H=jdRh->DY0V5Z63oPbXw+d9NK19vS#`#=cp=SoQZakFU55dOM)`VZ);UAnWB z%mrL&_)6@8LK%j{@v6Gd83*fC$1?Rw6bl84u#c2y6}#{=5C`kv9sT~{sIXXC8rg31 zQ0YY|PaO8T8V&qMvWF)4d73mC`M*25`6if8gD;bYQ&!BaC|ZOeAm8L-q~-Wy%L+Lq zxRAD7+F4+ft*rL9(h-k`_Qqy9t~ugjv&Mz3`(Dp};l5ie(6ErjKcS;LOk2qv;?kNr zceF!uWEM>wt3W#`F}(A*)n|)wzOLD~IJqeucAxsV`iDR2>T0B%ul8Z@+B}xA+D>82 zXAc{)y%8!%GuD#8g$f3i8f&-Vtu$0HsMRwJ8Zt2?-8uRNbxJd=NY!!wkUW3iJpWm- zgH4BlEt2#LQjbnG?O`Y|_5`O4O^E$IT(|@GNUGl;V*{@(s_AY}d)$bKlSRM4E8_dg z4p!G=XC&-_xqJTp$QTpNy*puK<H6b1gQ}j1rliT%f2TTk7Xqf7YsyAJd>!$iO9vII z4jKVNH+f1V&qQ+5LtR~)s`24NdYt!S`4YEtEE`h>M3$SeR$-sVA``I-qL1H+R(&C& zWta|i4Ls4SzpTWOkxYm~Y%7c}7@eN}dxxpd`)Gl%cZUjrte^*^n{*%5fd{li^N~LG zj>A^E=U5w#4sx9J;j*{4<8GxGo?kfbE&+}SZqrK*Pn^lh+0vZI3c481v@1)B5fT5a zG4C9!J<IiF=D=CN<z4EpDWZa*pc?lZShohm^O%L=So7mQJ!jw_T&h%qRb5ey-&I^* zTeJY~!*Rn4m$@K%ONwgnx(MYgS&ExIYvB(F@5RvTlvhI9Ddz<ZGF@Hr!qi1j>mZWM z!42jd+=dGV+M8JXuy?!e-a{ZooPs}p(w>4T2=pyZX)4xJuvL})H)bFgxoY-9oPl!X z;ti5O?wEtii@Ujl81h_X+%413GprPsL(BB@jEHQNsn;ln8`QlRtYX96Pi(lew!xMa z&rNu~gJ%hz6?p3Kgz(&pC-$wToyaY+7e8Q*kN+4G^s(TSZzjYx<2Nz(Bm5@CHsCiU z_5=K;#n!aK3qtJfaN#z?+pIc&!s)vW)AuN5KvU9Fz?Fs{03JESxq_YCKI+m1;w*na zWH5u^j|Oz-$$1EPzX;c1;Tq06hSuGg;=1DuBX_9bOSuk<#fRH~ID2rc4_0&8<2{2{ z42WcIm&A`CvCxTK>Tcv2T(R5bcZUlG8s0tX*1wC`a9UFkaU+{_f_+Tj-Dk{ptG;L< ztYq6rqYCnHYsnc+yBTx8j`<73jO{gY-ExKGSvVq`>sIHmBx#^Q%6JCBzY2S|83Ui8 zD-ZQ9XMN!|hE*}_!Pz#&8UTuQATr=rQsj4j%Oa;?cS602*&d#95k083s>NWI;VGAC zf#qd<9PxZJ%|9N$DgJLRPHbe?;3C3S@5cU(ZlDTzH??{<_ixOS_bsj7tq|)rM0`4z zbw30}TZMN}w2Mg5TGi!GXo8j&S*PPPKHZI;z5QLGXPnujf0b|$p-x)?dUi8@pwLEt zDDUqa#Oz6w2o0ci1WC-c%YfIT{nwzxEz#g|2QdRyi;g&X=U1g?80)qlGrn^TPP`}M z!$B9xjvbWI^qLc20@aG!tjT_ycU%SqTg5VqibC|M#_`C&t(ff#9q}`8C=yzb+J(@x z)MmJAD{w>z_p+paV?+iOYu|t>lh>2m@Ogk+dOe{wSg+wq3M{z-aN1TQ%DC>~z(6N) zW;8)W1!++n?<hB`RqGxO2XDhO+{2OYa6vS@ss=ALC2o|hq~<mfIkt%xZDactarhRC z9|8sGf^O`#5-ubws+P!#5lcy2Ji|q#)42%o{VV!?G4gZtf$*l@&cPEGN12n>f5~w` zZY6c=jW<wM>Wx-2KgM^`biybT_b9I^4a-$i*eNKJ7Ln71)Sk)<St~hId^~?$zQ}S< zqR(Nc&}ibPOlbEZvbE~+pOht??GmUI&en}jnvkl>g(bbV?^or82SE173l}z>zzcU; zyl~z+@Ir2KsOzx3Z1Td>B|#5fc)rC8FN*WRVUYnlc%I4Rg>}E`#tZYFu6O+e&tg0) z@YLZ6;kg&jdOZJ)2fT1Oa*M3N4`}C4aITiT@N(gWmkTevTzKK-!V51KUN|_;3)`_{ zt$E?!ZU-;iL0r3tt3^HdzRe3SxY6W=dv!LiKVb60H=zv-c?KDGq+7f&-Q<N2a2GIp zki`oJffuTXl<`3%HhJN9ktZ0DQMgA{;dORdUKOgF067_)XkR4bH<Dl$tP<i(DovPF zwhp=yL1E88GO1C-HRXKGq<#mU8J;p+GpP))xg(y-g-KnWAWVvFW-+N*KxHwhYI(Pr zRK3pSBOLYIv;*&8Qs-+XwFb%=2Z&cZQC~wrd|+gkPUiY$H@-E@FMNxdYVxgLCxCCw zy$yV83x0%erK>Qkhb+;(Y%vN+zLf-q*PU-2he+QN-4*!%`4)YM{%`TE@#snVj`}xP zmiUh%jr_87^Zx?R=!f>0;P=;*FVOoA)Hyj^Gidn-u%3KEcr4oStE{JB810%^0$&p) zll77a-)v791iL1bLem@v+xdQ3orNs3D(PLuUU0dJOSm^#M9k(I4EwHJjul}s1|Rj- z$_&}V|G2->UkVZIR>&y0@~#SdQUQ3(JrPQuwM7sGDwZ)_S$T1B3F12a)o{I98mOpX zIO}KbbCs7O1;1haC^+D%ej($?`mP@9J6YPXHNxJFTG%}e1d{CR{$`t<^+%v@asQ^F z;6mc$I~)c(qr9PRhuMdzLc7LJKyQZT(#~zMv!QWzmL91WcD6}2Ow{&YnCvWBmUd@9 zTkk5x^G!T?c&6c*h35u5H{*$2-n11tMRwo^<n;CLgO&XvIAv@?Yzux9V-MjsDYg;6 zDY5(Un-*J3Pbgc|7|_AU2FZDwJ{WwJm9st={C!~GjpwI$B6yndwBm^klgye9=^Trh z<FD(cfIV)*Z({5*{3gXVFHQ`5#`u~xvyloLQMCTTkSt!61cuZc>C`y3;HtgZWrM3V z8>0$nS0wE@sZdygEbS0E+@6SA2h|`*)>`}2B5;W?I4W*zo+q!u+-C4~id!=`1u-E! z<x<VurvIAEZEONpU}KYnxv>>P-g;b(-oJ4SGQbt_t=_f$8-4P=uGPB%E3o=Vwa)wW zwSpi;5Tu=eV4DNM?p_hRe6O`$JESqDJO)6bF=bGsQv*KznFb7u418Xi;sXFS4aGYc zsvCZcT2<Chy79`-Duh>(qL5dvJ_<HDvI;-T@nhs>7<nnM&u&%U3}9`{C0~Y`37;P} z>--^_0Ass}6F`st7nhP{uCD~k{NO*Rx9UmrdZXuGhQ6JFg7!vtIL8NCVZG2AhJT&) z0n_6|U9U8YVLI>LX&1v;H|M(ItI%a6CB2e+CP|p?#DLJ|X-}R0+Z~u~&+d5>(s5yD z>eKzyTig{zPq!-Xcd%y+x1()|$6pNm#qRREky`dYtJ%?8F@R)01l!ceW981y<M82O z{HZkLJr3FSmx#0&MsKUV$9-xmbY9OLNP{)m*fLsjhSzf+dZtg^j)34ZUHEVX&I>+6 zD6bE0(Gi*$SGAxtygktJZEAVS`<OYgR`2YzYPEVk0IOT-I!3M-Uf0}FrxI(*>Qo>9 z?RDzZ)cOXrMqTr<I(1U&U2E_z)_!#z6IPs8*ZeBtrrz~^K=bO<$*Fh!nBkvFg5TDu zb5rknNZyecfse`i(K<CK^{yuw@g@AgS<dKJR=;WtT)z!%s=TOw^mz?8&fHJX6$CwD zf%Xw}AwjerM(SWol8L~_pd<#Zw1Q4Cg9bAwiYXc^H#3CSmAdCM)eJ<B!R?k5qVB^9 zb<a;wR}(hDhTY6~BM2KQt)!|z;MC1)(e2{oFmf0TsTvt!0CsLl4exO^1U*7WxBjUZ z7jI*3AMti2;7a>e<IDknLQ!%N8=yoDN+W2r1|@0GK!V%=AqjNgXAyfp;QBsr*(2+H zWNh!%Jb)1BzZWB-=_C;<Fuix4i{`M#Gd#t>wNqhP+3&30AN>|arw>}fpOJ*^GLq%s ziuy6e50&t5sF$%_3|rr`pGrWadL5}%M~WblU7RYQ<Us$QTUnBpa+Jh&7|8o*VfsS- z?kjOij2NoL!pv;73xoTffWvI2NvHt!8InuuUP_4J%u{Ei0x?x)9Gn<?S)xl54sybq z1TO7Jfy6`uUmD^O@*AbUNs)cF7WGaiNwsXh{kN{^$;R>L{+d$S|5z-=Q@Zll?8Lxp zb|vSc02ms2f9ztZ>6>M2^IrTq-h_5X)<TP%I=h~_e#%O;JF9f;fstO@x)oDzLD=<G zHMc;w1lLV*xht>AKc&Q!yU183!w{k;KI(4>pA0SBQoOTV<Png0abu3Q-8>cFu*-xw zTTMPJ3@Rq)=y?Aw@Ax`2nB`->Uq?2En0zZu?RbwlP`MUDsP&gnsx2=qMSGVl#q|ql zTNn*u@0M5I*1C8HG@>8~`y1G|aDEeC(b70ReOE3FP-^_Rbi&k+Vdn?7BLL#2EEtAa zLOCSv+tAL{0Lli5(EfR-q~7xQAz$g#oA>E9k@1BaZU#up2p?h6ah|mO!I~#(-e(Y9 zPScTmi%)AhKp{}vW-qu4qVg<YP(JLyoBNP6?Ub;wfcci(B+_ZDmhF(dF~(}y4#^u= zYOL1VA$eJd(w03Hti%<meg^EWp%~>69kr^()}!o=^k4EGY(M6_Q12T2d&~>`{Ry7O z@HFB19iEr*yp1P{rvpzC;-%q<-V4M{2T-g?JANokt-x{1*nP-0m{*VxTdniw7>(YJ zoHaZ#T4lc{MHlM#)@)xw^m_X}F*-%RqxgN8Jj+g!5+&`>sM4ZC?RR&Sv;%NseFa|B zcR{@HMGyV!{REU-fD~i>asuX90PLLBtLyL;T(Js{Yz*%jm4+R4`W0(04b7QR3g2I+ zH@ROzMKkfkimq#ryy}{<iLp+dDrq;k{8zJ!pGVtRrtllprLeT%5t@m476FQ#9StnN zvSOZz>tH<!(^YI17c%)~^$h5d6h6}^+^U|CFKqwnWq||?f{edCvd%;ih8+ot<ug|Y z5@Rr8?1*eJW87lJ(2E3#;YN&|kw!DdWQl<W!)5ck)p)A}8Qg##X?>*|h5OZo`YW6_ zCR})ct??veZeR@OU1M%Mp9wJ?03)q&H?XUtw}?Ug=}r6a6;Wn}KGa(xZJVcZb_;_# zB{KMrx`F>#CxLZK^IU!yyS3LXO>@y>D$0i@Z#QPbFAIE0fp_xjboEDmG;j*~nn;X= zx$!K;e}SDE5)fGm-0FVx74CuX9*##-zeXI|R<s*=LnCX<68sR`M_6hQm=W1%0$0U> z>5=Uwu$CK5JMjS%4m83TvE0C!E9h^#fq}{=`|6MN7DAtAYHe>J@F>-(ZtE>1jUm(% zpO6o>|2oyg-a;}Nl8z92JYEoeA7)S3$ESo%^T6Bw2g{*zFh*4weh}Zt9*1Soll0%9 z&M!mH2(txLed{rY`0x_QfbInK^Ah$4>7S57O#~mpI6%v*dl1+XEiMAn-P8T71o@4V z&ko18%|k6Sc5F-IhBs{cU_;8h0^8c_rw+r(OTWr~Oh)&-Y*s6lefmNn?aG+uhKowT zy}urBC0!n3;^-+)(0-~%y?eMZ{Z60?*SfjWhm1f}kp*USPoww$ZiR_Vd}B{v3J=wm zZ0f-1u`&bK#beiPX%X(5E6Kq9Npe%)ih23V+-v}=e4J8Nkd@!pkqw+Uoc-OK97X<7 zP_mHrT2fCk1PV(STcWeF?o{RX{~0+)EBzo&)QEmg*5?{#UVLK7I=7TS)G4kisl}k9 zuw$;}yTvUp#dU#xA`+Q|+|5$caY~21>-79v3?fMmHD<5Hp%xE7pl|VjrVWq}L{0a> zGRPiq_ux`{v8QdS>Gr>BC2*+e(k(SzMqEvo8F4+!U8fCA>?NFwG^LEbqNaQH<$712 zSL$8+@Hd9%?|44N^EtmSYnqB;MdslLtEAC)K$3VeI3+7FwiUlg@S-;*D<QTCzbUc* zqH=DNdH@7Oc6+v{HS&txo^5I+UV|&PyKn~+ZK4`gH33ty(&Ae{+~;YItkF5m__0&1 zHV{F(BAay3SP8P!YGk>4BHMJ(c?b%_QloI6N|U_7H4mu1@(P<LrH<Z=!c9rnYPIjf zxGFs53awV_z{e3!R-%6bev|y;Vc5W$hZ@*#t=?e&#-02$wQL9EU9@cBFk?hIbqRij z4?*C;Z;Jow6Vd3TT3MI%nysu0OGZ8u&s<djMBH2&9Jv{h(Dn~wPl`&mp^<70_<;#< zM^<UTO72>1z&n&|>7rzN1KQm<M2szVb_a1E>zCa@0|5FFKn_lH<6PlHoX2D~hduxk zy7xx>yn`PjH;Zhj50X6qOBvD5WvT6OqG4eu8;{1pkZ$6**MokfFq=<r0JE{QbDCa$ zU0(C=(i-l!IOe-e1JJjkFLQ+1w18n>R~L6q_k2y<aoWK={$J2^^0t{(RiIqD-N~a1 z0t-Oc^f%YFa)yM)5M~@3MlRM9mQ#e=R(0C{tNTED9V=eMdr<doV?!dKs?PBu?dBLG z!XPaAFYtvh$*a*xxl2TI7~D~aHLIA8nEOqF#(dXtE34$1F1==!b+(Sfalt<PXM05q z=YA8*3LYeu#PspnwCfGf^!@lzMN7N7aFVD;pF8^U%gSoNZ|iky_t}g|44UgyLQNJ8 z*+x=#RG6}Q=BFxi9w-OYyNuAG?%|ggD*lj<pw{e9T`}$6HV5^LANKt&Faw8r7lZ@% zpUtK!46>@$`PS`}yLoUz0Wv)V=4TLzPG!tXl-iY>x!{VaJMQ=`#XPJF<djh1G=Sk` zKf~=mHK{%0<eJlxKFdh1xhyudPz_`DvFqS~7wWA<dO3IsDoD7<{`9#6Nx@j=$t|nA zpT;hAgx}`~Z#g*_o1mj0<uZog*wOb2)k}Oeg>0i4ZCAGw_fl{RPuTs#--X5-_kZ-G zAM@M&Sitexm6GW!zNp#Gly>WE+WICsvKc>W!)*{RLV?4r-VW&B4v&7J@esjb82{ZQ z>gxYMA9Ku6f*3k%DaVuO9qlrIw5(g1N7C57k6O7)Y#pugPW=<gdozBN;zrJ^(D<p` z7g$8z7DoIwjrsS+;L4qIfW*}O`0*P0VKsl@p%)%<MG2IO8iX4#?oB1ohw~v51Ue~# zjeOS{xQkEKQGAO}ZAydigl<VzHv?7U1SD6}me?AgU;f2PLre5z%Mg92Wr&_0H$=~f ztfCwyoL(z@?!peFL*X;|t$NoXJh$Vy2hVyu8}U4h=W#qw<9QCxi+Eng^A|j^?=<D0 z*pXTIK^fPg(y<3h>!w_r5L?SXiLns>q{QyxpR_0|&bOo}j^W6gJ6deMWk+G&(^a~1 z%C$jPbh`Np_bQx(gu*M!m3R${?#A%etD|TKqk-*A-TfTewO}RLI0r+aBQbSN5N$=k zPXWOC8(#R2j}Cl;ko7jC>x#hnf*XtQ!)gWLd+I(+<cf3?q>I?K1ee;;kB<$&yEFVl z*pRL<f%60b*6Q$m=tS^siYGX9QIED!S3rn?|0&Nn6e<||4&mzvKi7hTCIn;fP;fZ1 zneaplo=7+jiX4t?C;UU?Ab2npg0T^VHxvGf1qZth#!hS617PF;e$XpNYq)Q*#^pZ; zdaU5MdAQ4Gz<UTDj2{HQg<wk0Yt&qjwBU-h@D8;X#SE|K;5EGK)c4u64gAuLuMS~@ zSnJRrSgBGZL$t^o;8T;OAg!Kjv@($JGQuw>JQ?tW*mntBO5k7%m>4S|a1DX|EMVUl zv?uE#8wvdQdNX;S*mwfB68N?SOpaYb;0^+JS-_;&Y0?5sy8%W$Klu*I&(jkdRdpe? z4(-&d{S2?%a?kQLZR1oc+={3h9z?~HE$x~%5ZfL(pz(~pPX}7t?p!+Th#b~|XPJT4 z3W1A<osp!2Qi9KZz!G4$eYg7CEG|^AEZD2wlUJ-8aGx??rwpYIEm>7Tq7F|PMg3W_ zdL17}JlCf9efUlDUkA~i6ED<2iqk5}tp1IIkWEN5EUlu~?cbOw5U6JmhdR*y;V=_K ze7ZpO=u;bO(idP|djeLS&lh4HrLiVTSyR3M>z1#Ibsu!ZD67W$MP)q^t1kT)mh~=; zH6@S?+}ZxYk)3RrKI+LD(LN4{40vC<ZYJVkqtJ6rT}N{2_wK>;fQtO~1NE*%P~Zpf zm(ONA2hI1L_$$VS?JBVVl;oyDi*U88PzM;WIe%an|L#nLU*iZrAKL(q@aGwRfg?Qp zX}9o)5YE-wpvVqg*nh0jt2K9Iw+0+E0fQq4HQ-eMHXX)0R%=7CT1!?Vf=&olYsu;? zfKcPSjKrE0e`ZFa|LoY+n>wsS1u2N~$(<nh>6<#c0pB6;j5vCU`2v8}k_^X$?w%rx zIx<{JOJ~1{^;{$$KPOQhN;a~yxvXO;nhQAH2*8%<Tk9PQyD^vmVIfO;<8JW`%pT#b zO=Portv3PW08?GZ$U}^l=<%s&&sI|a5}gs(I8L3@SJg36*3FyZnTbDw&-^az{yjC{ z`lcL{H>J=S*JFh-t#fU3F}{1~{ov}rseIJ3I;OSOeL2=qnJ1>TPc|;XeW9jVy=|lK zPM<fzS&nJbr+KY!S)<LGIeFS7T}SHWymNdLrsWjS4T;o+db#|<sk0^n#PYCRbFQC0 zGsg_)_YB83aZa2(ZNkjCI=wA_Io5su?wXqWp550(IuAHD?*Z?=-u=33Y7V`gYc94$ zk2Su%j$>FB(iF@snB~o%=Lyu*VEymGE@e$s1&*K3GhgQwXzM<Aeo<u+bj|a;@k{EF zT-y6l{G~sRA>AuJM9xDD(F#JW;D)$MX|6AaBdTkv%E}kOwM8*qs_?XW+;a$`;t0gT zB5b8f2v&}P3V*G8i5$*fPy&}KwQwN<BmG)9F_~Kxa0A-{oc~&eduXAH$C+83r(3T4 z3-DOJcASDy#(Hx+d>wlpE~Ge@h>P>a95(j1sVb1~e|H>xoiegq%=gRgcXR)mcB%3g zXDe{^PB||j#IHR_W$m*`FEZwD3gvh5a>*v<683J^G;ck~99I<CQEPRu_#_1S7N69# zi!#pZut_=%Vs|6`5~(h1b(tH=&nhc{5$G`LWFI+quu&)b$hq!PqfYN5=R!o;WO%oz zB`|z~-ZhNZn?Y6SOrzC%#P!=jzeP3xene`%$LObS!)7<kO$My?9$A%}Nv9OC0mr>Z z>e`ZmD~|LDyecj%PHUQj5=YALgA#hcv}q`_O+5!@QD9l?=h6bQF|tladNhOumt_H& zOAE;6$QB)BNRTOr<<bIjSENw~RU;^zi(SJ#ssy;hxsb{BsT<@KyR8S*biPg-94<VF zf_$(Bv8P=^y={xihjJ3kc3N6wx5l+<r7+uRgChGiV2KGB7&)u~r2uS7`jE_a+F;`> zAlZR+kb@a6%MoTs>PcpJ@+;tjkLTj26F+k0)nLPuLx$KFiJzE?cES4AlcRRu15S3X z;mKoIGQ#e&!t&HMgjso%O+rb+-c4%wb>xPdWw_|Ea*>ZLG3Es#>x6CZ^XaSbq5qA! zhQ@<09!>_i9q;AIrau?l$CJD|2fkcx$7b>C#*2-`=m~WJWDO6z<eoK*x7MUS+;<a< z$!Zfk9!MOwp^?V#yJHt`$JT8@I&-`EPI};!6@)KV1!`~%NazfE5l5E%H0I&_C!gfE zlNJ%?sj6N^gB-lt>Hd{HJ9V46;0%*ZD|8FLm*;Y^0czo*y%5e6!#`0`1>KEVaGIcC zZwxNiCe+rJ+zLXiOGP~Y8+~Tw`(^1PwjWE&Yi@PAW752~hy8qcEj5qY_drd_BGGqp zbG8<qV@iriU8$RtlN>cA)fG5%4I0~v%{`6kk-}e&1BQO=hq4_@dF~loZ~mG<iPoMH zmnc#z$`{aHNVhxV*4|QHU0zx%qr<sjXIFs5G!62#1rs{a@3dkfZrlo13(mVh^8$Lc z0{gG2LWOWRyJ`uH{fkO*GF`I{-5zG;be-V8O01)tC2+a4e=O5W8OjRQjUB^sZT^IB zv6I3WWj#cks40<#w@O?K11ZUL!7^64QlC7aKS8+UK^n7RYoV>TGl4$2a$(If?EnIC zDyzC3TaY{v8Rre;^jvM=Rx|I)s(9Dwf|_<;XaT!r;8*erNHV}Xc8vZDA8+Nw3(&~7 z^lo$fMdu_Ob*toV!=j>vmdO|DWp~+s<P62B17_u-@1|lScV@{#&RkL(S6Yz2E~EL> z{<A<z%wP&R&fsvi&<>`WkTZLNZ}R9XM&(SM%9Na2gnOpvduC1T6`nJ7Qg=Az?@2jv zBo>Y--kH<9J#df~<rjFS&-8jFODpco$(}rKPItVFTacGC-81`oJFbR#r&?&4Uc;td zkBZpwNS6v{PR*Y_P1lU^1XkdkY2{+2Eu1qe&zm1F5Aj_;dD`S@-dWx7u}vmukljxC z1+yp4&i`hn&L!S{8b0;}`1GmX35Bz)62#*J?wdKiJ6!5DD+fVWjG8rdqSjw?zkv6+ zb>b2?<4rIwx$<?|$F>OOO$jdTa-}xRK#%LKibyd+)dvt4QX4u^H$a0+KXnCgg>Wa# zcoQC_BCa#yXRLN?JVWAw`o063qt8CVAh`hj40-Lu9flq1+MiQ?>zD(-BN7|dL)a2& zkJJ;xO*cW%Fmsq0$^HaVS(|!Lqn#)b57jMAclpOQxhoz`kH8HHw~F)57rR_INNSvg zB&Juna6WcL1obKaRezv<mMgU1ENzCQ$Sbh3HDWh}t3FmDZ@VwT_&VuawRb)=nJr1v z0)L2ITmP1SyuL+yn}y<YY_Oxs7dTPa`L;9P`z!>1v_+#rRMocq9X^55(A!y%hMe}+ z<ng!Tpwx<ax}P}>o#W(5e1ms$%S|tOsw=9NxiJylq>$S0Sk;oa$I1e^BOJ>o5O?@l zT_)%53rh4VYe=CGbT_F29GSpBE6&_wvCg$wSxH5;i4!(Da%8={l6N4B&sDDAmXs|+ zOlS!3e=%J1m2h<?>p#<{8kTKEw^fzH4XCaQ$0iAcHDx)M(!0YlY^RpfW{otLhYKxF zlZYyF=-c>fmRu@bj1z1Nv8=ob9wz@o^^<&>kk5&24W0-B3fF7Jx_O4-)^K=if?v;t zX49bgXyb%ssr2N3s7PPA$z27b-+FSMn!TAr)t}_aj{P0(4fT1Bx}CgNmA3Q;v2jRa zhaY1+awT`p5eHQ;vXzn6H4{fjQtzR&LatH}_u+>)mk)A>a_==1^E=gYBxg_={%ZSR zwF2E6f{7$2qehblJZqi;p6rlUwP6R3DD#0*Vt{%K>MDS};XyTo*g8hP6})y{pwCkY zlQ3z&0c_*Fhwr?F_N;}6>fZ`nV9Y;!8GP2?aT?s0;QFpxL0EwJ(3HSOqmRTcH3IGQ zXn#j4LR*!Ofkyk3z~AL_0zSD#>hIH<?1F0%B){}AZsGZpo=S+FsRQQWGUl#)l`5L= z(Qn!F*o`K_wX7=VYF+m%{B4PzekG=|l6y3HYzF)i>u268%!M;fO`s4S>{3Q{{0%n~ zl3l9J9u$JNp1+|c0|lBdgiQl)N(d*%Uq$peE01+ScQ|+c^GWpmX(BleXk<T;kT$4q z$B`rv2@_tZ6PjgMxpM=yVKoc*;YPfMen^0MpMCyeeV&4SpK;Xc`>sG|SD>RSaF`0s zKFr5JM;qQWBRd8D{lxnmUJisCHUSkjPuf-Gwa2=A$^{KEIu}>occs=JN5avs6qcoT z5U=<Rkoa5DQX3vdm{B+|_}#y{{O4~;Ol|l90Pss0UcVa{o9NtLU5g6EaF+8BHr3Q( zkV?agU5>(za09EM<^ZB!d5QfMti296?{jFa;RbV}(Xc~`XD1ofElC$qt|u-d+{|BZ znwlhk2ZA-JjB5!R7+i`X4zg>ieClFoJus9TMqy0aqv9%55_gCB)IVgM+vi&-`$tGl zOz&P}V)_6(USU+t!dBR6)@9B3cwIVFsa?!S4*EpRW<hn``k^0u>OtgTH**#cvitt< znbm#957{k8TGCSMqiEJ6Eok2Zc!}fzTeyKOtS-GtDp9|S@Tqb5=_Y&|;N9C>UBxnT z>^M8=zff{xy+Cyde@1|Q{Q)f5*%6Bbkr(?{-T}VVxS}@RiTCx2)Y}v3EW3RobJ!v| z5<$8yA0(zzoxwi0nw8yf2h0fAN$n`F-AQ}VMAAt<gtkO)`X)O`PFfAu&KC6$AMZUF zI7<)m@!kW0{#1f^2dE{T4pgJ1$yjf#@t=+PkD;nRCgY<e+BF8~O^58y4-lS$u5w+9 zXA~d&U<8SOQm}h1tL^1Ph0oaoq5S<JOinnTrKLxw5lE?PJ!Gs%scVx1So^!|&W5Yi z>=dD`r}q`wda%uV2>39+U<}it4z56l?BiwhLmCSJR!gu`5lUWsGNc#O62y03lfbW~ zZwqfq-O{~~1s@^;e(Z4tuEL9me;0DYu#Y<aH;m`}15E3KF#ygvs831$ZkKnMz8Et* zRA3w+<yOjX;-#w^V&Q(IKX)TD+7D#vDWK{K5LH+89!ak0&3PCXF)3Z%9%nxHA|E4p zW!^Lw)Z8$hk<25QYz7Dg_E|gCt&E|KY<A->%bnUV84Yjr3pUc>zbkOL(a*@91x}*U zFCdc=dgVWlP#DnT&f?`jQJ4~%xEuRHg(~FB0;0O5yMgFAq;I?qKk9OBM(arZR?FRw z#@Vax`Uf*&yX+Qh>b~0%%gXJ;^U!XR2|CO;3qDDW<lxeo2^eAQhTWxgd3h;eY>D;j zy9?A^%hD({k?PBx8EIu+UJ#Wz5=_RHz1#0dn=SQy(dEB@b=`<WF8>)OYNT?(KQD}q zUSt7-OMmZjCUpz!1xGG7=iSM63@+UTpI&&8^4*;G+ZZ<S*mUd1qGri$*;yRJ5|Itv ziad?vBiTNXoCx1_LL)n`^y0pUFlbASGu!!R{GQZ?2N5CcJwW~u^6qW*?(2^m%V5)k zt4my}34{n5QmAw%&44hjFX;)Kq)MRv&FWh_h)n0oGh_)cz~~ooyKv<3%$ZV@ux~#@ zFZ@(k`ejmv{W2_fhbCsr=K<?8$1EY5J|X64OPn__XTr~PH8>OeX>#ZT<9m;Klf>g> zn$`AE7d?owlCGiV)6xP1<gXj|l)n&5{3Y(KYKQrRs{WXpscesq$R?Kddl<HXX}Y!i zxpJQ6uzGX@Q5}eEV~q9Kribu$scs}(zwKzGW=2>y-)tl!dye|{AhRRdz-D%!)Q!{e zqgG*8Smcbecyi?(5G5K9<0DPIEFW%u3{*SiV<<lcsi);5ogahMWAc%yX3F0Tbshd< z5ctwV1!D|fMyLP>zkHeSL5cBf_^t>QTx0mgh6*MEdKI9#r9YXP&;TEmp8PgX9>;R4 zXDYnm3{(k3gb6X#cyaVA>fvSlda|Dy@-0*Z;7n+n0Z358#+m@twN$d^yxRw>w`8`b zZ=Xa~!x`33`H{NId#Ee_U~0o>@Gxsr|MxJg!ruLwL_a#3^xE96eGnfl(dpknkH&S= zlzaG(<NG}Pb-Ud&p^~9%E>q8h#ZqY%mmL!4HpH2Xs|{-4s7y{az!5W+23!WgQ6XQc z(dm|!LjBk=BcVfb!&mbnx;EqDi@GYT$*}I?2?`*<(LuL3K(p6JS7c^p(mz=RjwC`q z$1?W1c7z*Ls}3Q&SnDS2%DDrz$dM(GRTQ0TUFDv|J-u!UJH3VH^plP9V4qHQ@t6_| zK&>R!zH3>2>z09@t52L5ktNZP5#)bogM4WjIRvFbJI-1sXUz*FH@p%^+?HVEcdkAu z_?h|r%Y@Nyt=_ltFI1sl_9l+RoeNR@tcF+oIJ_N8@u~0Uq38GH!agw;F<Qh@QtS;! zzc2&;C_F=3PZ{YKi4E5IxIW{P1N}z773D<HmWQ`<TOX`GS$zj@7+Jxk16+RbwgfhM z3M>LJjeVv^)8p&-*?xn14zifBFP1p^ElH8$@{d3PhmkNKRln}3I;>QNq(a1OGh(ui zs4l^ju=4m=$5y8Uc7xgjS%XWOz$qe+bgD^$!yewhLftr`WnIvg$q~IG10y<SFG}Jz zm{^r`u+=+wrXtV*zS*a+<K+*r(E4?NqUGUOf~OFRi8l2pzA1nI0=ds^XkM;j3DXL( zz0s!Dm?7(Q$en8ZC(BPUUXoO9gn6co|71mEe4z6Vn1iK3?lWb-muL{%reGx1H5W>$ z@$)-U*T77YYaOhdp2xvzSvzSvSFTaP9K>$%he>wlkv1Q4`C$u}VpJcB2^px~cO=)B zlG^ZRbSOkZV`<9thOX2#d+<4_&3hPsAQ6eM_==x(?9d)z%DHp6PkNO;>v_MJp>;Ws zZCca?my=#58MD*W!=Mkew3$6nZIIUi#_T~VEU#(C?7`|Tc^#xKmA?bk5d1ZA(?c-7 z%FPIQ;8G?RRML}f<X#c-Tx#Tw4S7ZZ1{&$P0>sQSxU|hP23vSrQPEYNv8-HnyOEs% zpUYEfAxnD?Pfu+aho-Xod^2LA&sF0ncK1D(qPtCR*)6Ou=hw=e`_Vz>`Y#QMLq8-S zG`|_@z|j0Xq4_&P^BY6?ducb?-gE|1g&PJUp5C^5l5{d4GUw7W?DkJqr(Qu@zrC)& zIg3x%@qLR=ZyL(&SQ?R@mkU>F=4IV)4VBdjmxAXB3N8g{vb;~rqkjcQ$HJZA$4_S# zvQ%7g2+TzLJH9^MG&8*($9+tH$Jb|;woSq&WZ1h$MMk2Gm~2nV-yP~P`P---!rxYJ z8+MAhTl@i@E<C??jee`u`vTr};dv2jr_dxEkPS`BY4tvVk+YYE-2GGQ6$ond7=9u< zP^)kQxNBF_Ff@;PvJ`c1POR$~E(e&;Np5g0N`YSw{N0P^Z9E^~`3O%3o`il4u9NYc zf#*Uzm*E+M=W0BY@f6}I!m}99ZFug)W8irJ&%=10!1EhCZFpY7^9G*x@EpSP4?GFT z`xHFq;2DPJay(bz$;C4h&y9GZKLg)wT8rk7Y{CzED1S2i(_e%-)lHw4AP1Q7k{C?| z1Z|cOP1Zqa(a$kj5R@G~tY4C%G5wMfeHSk)r%wx_QKGNwckUWQf3G9BqtD@md+^al zGZZvGy48FKp^9>$3Jfkc-bqN%O$kxM1ZD$xrvSSWqPLkqWENd)z9X~fP1bv&D>~D9 zPjW?bt@jjH^eXE;%@xIEon24i5@!6tSV)LoV1;G7qNfXRS3>k8d3hlr>as$EuIOQ` zF<Dk##i;CeT*7R>Cq?(z?<vupc*g)si2lX~x}#6n@7d9ZCBhR4(f_i6!RS4Bhi__Q zy&D~%YA=JO>@!30D#B-nu|A#Pc>u>QIWozYf}>{eC$R^8swNSLv;6GjcHPNk@PT2h z&qNX&biV#RktR=Tat}m|G5EnS$VCjyAstC2Np_$?*bb<_8J!hgPm*B>)lnZ~zuFK$ zSOZ=I!HHB5k^X)kd*RTFS4t}-Va_nIuaPlA4IOOLhEDwUZ(J@AiY=`TN%*xODFPWl zNO(OHh~ulqb%?IEK)0lG2VsD?TYU-!@D2>O$e=Ur5-fC<Ai*vHV{|WphB!;0At#hT zGS~jMF6mK%zoDSft5||D@e=$6vWVRViFOGXqk9Ra3dC6g4f$s!*i6AhcZsw?1xwI~ z5g93tm*CsF1Oug+BJ~JRIgGcK@dlh_x7D|Fyj!HVz;?~vVvO!3)evV%HRPX_^eBZB zM@gUW4_i$PJs^*aVHuLui!iv4%xWfW%|?&wHlAH%($*xQt%3dxu5EY>JU_y-8P8*Q z;Ny&Rtm$TrDhO1ur|PC>C&V7dZ({7H_=UF?7+g=9>T9|gnHcNykO{IKTEP*&!&vXb zw>mwYyra=rU&gN_e3exbXTCDl&(R64UDSm+I1e8#f0oz}4Tx;l`EK?A*Y!Du*g~uC z-mhI=O9h)!&IX!f^**9#s*&cf^qvG|ShyM}BW@inw}geWyeNbxLDLyt%J4Bd{1P+V zG&7pS6QRLKjt)Etf#FH8>|UjgUxNBf!imte>Jxc&8-*K`;_Gyr2;GPh-HED(r{hHE zW_)~rkJum(9OXxx)=4uHe&Pet(4=Xk+Yn(jZFvg~<G;)tBH{<n^m5RlwvRwh%h-v` zLrS#`Q3FZf7%4|4O-o6wKMNBCZ%O`3uv1q-+@h3gZ6H5^oj5ggk$PQ`c@v?xoHUJ> z@wyt_gL=l5gg!I!Ts2C^PLtSK|0=di$979>-@l6e$^<D%w!|*}SFtxs>={9cz4Twj zz74U-Y>!Nukp$cINi($VI=OTAiMK{DIVavmfuvwyv^HQ)v;9aWBU=GSZw@Br6+55- zIx=Z`Lf{mP^T;6tsWW6O;E?hTwIAXb@(lV<uUpaR3Ji$2&XKhHFbN6q_YY5!!^=-0 zVsOO^uD~^5G(rD3T<|jwQ9}&}kYj7ZL3UrGUm!{#hX@IW85~)wks3hCDdUH}#@bA} zV?bo54lR+;4<v^fiIT&>b9?5HA&@W3VFYlXI&NvmY&isQVngN$4wp2W<~PLx`ND>L z^;)z0ud>Gc$)uhb$}TSJn$eu*n6C#SwPP5@e5xk68whw6;uD?nAA@n+D(_#V3EaUI zAK<i`5CgYs6Q`LElhP<`M$es2CD)2QuGIC-L%e_W!^Qr2(kl~D5Jyz5PX7wRW%6Yd zC85qDv=o6o7awy*he}m7BDzqm3&P<vw1Cd<2FwPNm!p^ikPPbJ>4PI{b++ft6=TEc zLnE6s;A9ivjx=h(XP}Od@V6vGSNGW<O7PpQ&kyBu8wL75*#f;3VG-_~*$#c*Hav%p zWY0)Mb$wP{n$?>PR<i=gRSKK%kO28L`jxrr()UG+wjDa}x{ic9h7}g9E_`C9v1>9f zw%@MK`#XYTsc?e#0_zD#;2_a#=QRR%Tp@*U<Aj4W1d!ir=V%meSIZPr4=BX@=w@{b zzfe|5dNNABO%)Tpi7l|e3=05)%1loT_<}32Sp+(Va`#5%_UNX&?P}26p<fuQL&x$V zmc7vX3)&Ic@y49GW3J`rVv&X7oK$LV2C7?zAL~L$SKtG}zkfE`(Yw7{?Ct8U5_A7i zUG0dyT`ffHmgtPZkRCVM8TJJ+f?F1jdTx*Y`KOFCl5wJToFNo4y-E!c1ZfP!Lh**V zbBjZ1Wp^Sl+`w*A=eogtghQxQdFAp_R+@T^nM~s3ZPc3oQy2q_y7w>S-wyRQ{<cJ) zIuFRVSw|^2k-M<j(ak<`IKF$HU#R>i{#uy+cK@x_EAW^2dfHQRsb}4g0_P<)u+M_7 zO*?`S|IF36VXYKbHks*ZYuVHOawK3q%GAS`ihU%44prn(1j|BQ9_;UMf155FT?+KH zn`1oMiVm?1JgJHN;%ivNlvGC%8xNRmSZd7fx3Rh>mcRi&)ttD`uDsMe#F26d@0_#k z_D4y(orW^>X7|VPr6Nqb_p~h$B@OG-P0fgJ#y{JRZ(1~>(W`2zDxgx8@Z|`1)K{ZE zA*y)IDK6nv3Q&*g3va*NEuC)MNr8r`G%sU-H?|@iM1TsGEmBoOwWXAUeeJYcWZ4O` zy26TgF<yG~zo7TK<)A`2)WJm+0ez<e$Dh+KmnS$KX)V*+FL%)~(y~n4sp^J9n~c&_ zcS!v54NIddH{Vi$JH)arHMPGeGgZDCCyf_+v-u^dfIq-$xWB8UUp(f|IYwXN_>}LH z@Yi{Ff(wntc%r-JT%4!BPer_*cC(DfC5)p!GBVL1MU|Y8a&3eZpYx!UI&NsUi?n`w zA*`F?8fuyMakD773prl<6D@Ry$Yse^kN0d9U1n;|#D2AhjWEm2dOPid31fRX?RhO& z+yGVMWjv={DC4nREgMwp+p<OF_t!mJL|ZL)`Yc!;^Q6lN>7yP#o=!CH#)vZaD{Klu z`oSKN&KMG}h0IVrqy#tVK~Ec9*5h=*+3G!Qbs2UU!Z-jlMYgh*tqJ6+bL2p<1~1ci zk;XB8;&aNn4Cc#E1u3^4r`_$QnGZInd$k*880*xV=V68oL|EVpe5x~?V}V;JORAQP z9RtQi*gb%e@4$Gs$2JXe;kJ`(y66-`cx|Y*@EZ~zXWhs1D7S4O=!{ZawGh|x;EHv* zys%d@L0IAyl~>e)O0rx$l;~({i#6KQ6-|A@I2lqPChS8T{1&G8`dW9~xLUlhsHWJW zC7c5u$NhaALtn*r{$RwPRwdM-7W;MBUjs$N6=URl+zmsp)Z;?@)y0bMl(}i*4mRP3 z`!YJlD&WP;`(~*|Xq;z>uVmE#mHgZrZfsf0wqRK~R;{v=SJ3QIjK0l$*td3jAtKWe z*3)MzY01n$<#gN!Gue_oIA77gC){~hfbI&^=GQJlIPpQ{>Y80rvjBf={9l!36VKOe zd)DjAp2Yw&E~2qLe*-uY0ZaRe5~RlsP!$#C1p!(F=zi{?r~lTT{#WT_bs@*kf~uu# zkLs#g+%t#c7r2(dc@K{%Ua+@N3hS%|`o30!aK8Z@wSE^P6ZAY#X<c^^FE4m59LZ7= zv1ztNs}a8lX8>?%FAmUvbaAs*U?3?xooRyfKF(A$yt$9#$E)#~T!uhW<8<_qaIUuG zynC3nTeCRT^74_|w2PWB8VP<k1IO~jKA;RcJmwCY%TD9)wKm4`wT4}O>$bZrYa`!# z40|X?@q7mBvgauA!=qPM6J<hW<YP(8ZIUxYm6v^CgUf$WgKIth{v6Nm@kH@_g6DHQ zC%GG3XX2^D^Dv$kJn!M@gEXh$IUCPdJQMIt#d8au=%2A7Z`z1rN4DYz^|~z+nojO5 z23H(|HA`f_1|Nd~DXk7#y~h%wuoCGJyk7?=O7Lg|!*@u2LUe@rmKePdZ>Te6v?z>D z_}+)_{qSDbl>ko{Qi#EqNFn|XbYXEA0_8VAA@P#X+E9kr{Tu5A0xcwzDAk07*B9fD zzD#%n0@X8O-X@)#J4b!*$Z;u8QuINrrX;rrGm<P(<vQfX@+L*;d*{UPg=Tn4bZ)QV z9y2^GdS$QS7n|Yk=s5^yPTA2^ym8AiFWMJx-P`(J7)GM4F(}a1A7DEJeoOMPfAW_3 zitQ6_lbl%42orjbCPaUUU<|2*=oY*Xc_8hGCqKatw;odyVo5~4+Iw_}_cKxVu;oJy zoE@zVKDKA$ZfW6J0-+MOf1?rzb-1mftA(112_i|urNa)6WIjis4GXUL48O=N368^2 zZdW2*mei|9Ps4JQPCeGB|CU$i($=Z9cx`}B*SZxOIoNVEwtIk08~|=qRfxcfBF1LM zSgT`HNDLeX-K_EjTN<71PQ)wg8Mr36Vw+3UVS5q3`{+>uagLraM^B_fV?I|f<80}6 z^+}rZ?kVk)cTBp}ci%Lp<3Trc$vY!?I_Mb*vfPRcMbPfZ93Au!g2LFohA)u^fIIBT zq%V;*@|wXbU{~^W3S9Fl49h{7X5lF~7DC(SJMn?41?j3|TEZ7}TLrQSH8{I%xj??K z+eT)@v0`}8S;>im;Y6&uQNIxD8<!C)N{O<5Ay!>7XIcLR)|J2tmCuy)$Qs?6jb2f) zP05UG)PSFwfQ-m?4Y(hGO*`=p=NV(f)#0HmCq!HwzS$i_SBI_LL3DNaRCmxIfHrjp zr2!P~4jKs1cLB0=I&i1)trR&yOj(O&x4YKk@bE1s<0pb2%!I*4?o^%;=4}I2X<$;Y z^~jy7)?nuh=ZABB3}X=stT3OdMwpdDSr~I!Q%-g86bvTqWrI9UtBT$_gW8}+P6E1p zrZxzJ{{;DJI1<>hlwKhG(|dZyc8@Qjnk}fBDY3e#@R!3?t$PSX5iK;Ea#~LJ^s?-* zbx(RNf)gR8ZUI+&1*)rYsuAl^OBG{#ThwwH*VsMf6V{V*o>NXCEFG};ItZ(sss%WX z2wl}EcOm>K$gPQ#YhZi^$z0<nf9_58AU-yBZ!!qOzV5ox1Kf^&nQ4i!($-k5!=Zz< z0z=E-2+fU!))iEUJKt?J6U#EbJ1&R#`vutCH=cllvb0l<B;KAfawg)$+qdUBv%0%t z&{}LF4RKM<{deW-f408=I`TJ)WUmFBXT>?@^5OcU2zH2En^^HU=BAb}#KGGV0kd9Q z_fCfKqh4?6*o2cV5H5F>nMh!RRJXHP3$F8b@s<MmkzftN-ragu=cj6!_0G#|nKcQ4 zzQsvRYo7zdq92JDE&?@y&FJT}*YXsrf8Z~Th&r^dx`(jqXiBkNms(h`A>rcw#9S8x zJH-DtNC$~hiyDIpkA8vM27A=N=y9C>!Cu$~lmKD7hjG&YUL5zR$B{s+e)p*l@LIRx zfXhE6?A?VOi~}KWbE|hJtd^T$wLC8al3SlEh<+DPe1E8*sB0eV3+L~mC3A~<Kb;hD z7pg(a))sXo#1)*Cu@R~`LP3XX+@HMMLYQqKbZdk-Y^2upK&Yk@VY`hGrgK&aErdlj z!jCRCOE^>`#C0pm(*xlHKxh%?*of%3M3e?f`OL1PIHZFvj8Jn&PVnr#U;;%+_}PXZ zwlMl?JuJIutcdPf%~z@SWLn|1s4&Krg}Ll*G&|Z<wfAFV@0QV_hsKBG0<fNb9U-{? zs1FGL>-IK)jANRaJ7@}rG?YFT_5J#H5A#eTFBtB212ONTwRA>uyx($hq%Ro$s&@r* zj={c|Ge+!*WzOt2=Zp%?->qFc>a%2G$+~`&J;<+yHDx~-?(jq#hVWK|pnXqb@4j@| zA31j4P)pdb5X;b#8N=BrxDV&BIup>vuzo!Zb6X@Ci``>PlZXO_F!pthB(v=m%|Bm7 zOeAXD^5>vSz2m`0M;+Ara!dpVXpRTY<8~G-)DN_J58@uS1ChhJ7^{as3Pi>&DlbJ3 z_5l2&D$E``a^V5Y9^W@GdwvI<334$!bJPzoBjqkAJMx}Z?_Nx`-9Ys@mR*K-H!KKS zz54;%qt{Mbh+}0O$28)23Qd~}8%g7J^(^Ycg8|P&h>5r|5qTgCm|$Q(pw)FsYj(oP zSgpoBkm_7wv>ELyKcK;};kh|nzwIF3aO~kneSyPsb8Aj!QbOzojBI`QX8H7NnlK(g z;x2#R@qv!OI8ZH&`_k(W|BaRJ5>vQ-t%c@#qLBz*M}*d#w4{XGuKYuRr|qe+Q95I{ zdJWTxo$?3yYZ|T}z(-5;evmiopizs=iP6X{zZ{n|QkQl05b#a%DVzWXd-X3VfeH|g zCdB@m8Ynrn3m5PD9v`l2Z-vH)^xQ{0&X}e&;m*-JBcsY|EA)nmAJ**)s}@!AwjB2Y z^Js9d8%#hcxTp4xTdUQ+EV5DV$&0X2hI-nv&8*(>R+^H~*TO%nlD=QWoLrp0>;*l- z7W?BQc^$u@b-?&zcZ|ZRp5=qOh6UVs$r@A{I2!`*4H$c^IfJ@zi<g?l_oP85dpzTh z-T4Zr8Siqd+o{a?eke2_Q~q%LsQ!`59do@^orehwRww>?;5YCJO!qc*?uD2V`JI=& z#QFZZ`W^~KKSG$~Sr?;lg@-ubhXJbR`-@02>1vtou$ng}4N{LxI@YBRre1#$@r%jt zV|LCk!3U>2tUmmU$tm-6z7Ji1d?yXEwwiOHTmrIcAj6qg5SC=M2k2lBcZp1m6eBlf zytgAT2z$#gFQmq%K7_cE>d{<t6FY)gN~&`?*o_dNPL;@(_A1m#-42a|oNeO`JL(i+ zNr>JN@}*d_1}l~Dv7@|KL^8pgzW}+Y=RQB$rP7WcMe=qQ^B-Qv(&KZ~6`ASdA>T`2 z&WF{v@wX-VO{9yx=U8uio%vOTYJ0FzQgv(hNl11g60o)2D5|K&DRL;?Yj7@qAw0?y z;h1}koU!kfANA&OPqQO^ws0567wqXFwun9b@G;h~qNtNS$T~)tj&TfXh9laCQB-nw z2BJIu3(W;82YUdRMBsq$CkTa-N5{ZPSA7cc4}c;$P9e54In{$Eit3bU4M&z=nL8Ri zDLCIylYkP3lYkV?8Pp@#>&H+z!|=ekgLKr}4p*+w2*r}%QTq3yp()Xap^zZt-PP*d zjWb)o1%*euI+_Dy01KxeP9HC}L7+NdhM4?fmo_WSMgyoB5F9C;G2$F`-h0QPc{-NR z<!zS(MAv`_igpWrx(~HwgN5Or_pqD`M^sxjDjNk{D47}s$*3iogu&;u#Am7>pfP&% zyHL|IY_oGGVFAf9cAU#AK|!s1QY1zN+$#himXE^8nu-c;#mc7I!tR5J7l-N1Hn?*0 z<7ALd#3kmEvhsyxZk#e&g1pQut`d3(su`y}yjxG-@AvdK?V*u7PkaE#0n;Dpu5C9* z2JPv?`8Yjt*gz~fy$=UxFi~lEYxyt_dif0_caSRfuvaiYRqOfEz39;{_UM$rJHZvW zgYsGvK}y$*fjEhA_ZA42xQ<+n=0x?Rgznx70L2R&gjKEHLl7@iWDiOR;?Z`F*&pqx z4Y%UeA^>I2BAn(UKf=^)iTZI6tY?34T{pqqqY=pti#4a{tzVFYzQ5?fyd|=EEQZfL zzz@A(WII1r;-k%zeiF({<!A;^i`;)RzSJTK$>hEdG=q_yj9nnGG3N^`EwY!eYXvrr zYcU*<)A247Se8yZSncj)j&8M6{ti_;@RuIMIL4@-HjNhSZ*S$Iit^er`R1x?LQOf% zO6+j#2f=?w5yt^{uB`va=46L~=cWdav&I9wJ>WRXe&(Hz1y$#h8S0}k6zn=+G5!vV zjl(k-My;xYr(M16kS^6p-{u^HH-QfI5L05n;Pp3z!msogAXksUzz65G*SCP`LO8U$ zx==wl%wdczLj?&ik3E~(OaEiIjo7uAHmbe?439rX<{%n^r=O0DTU7;aIGtTqhE-Yj zSQR?f2pua|V$Fdt*gaNI$LgbFxe+T03+DLvx)|a1X{))I?k&;OPcg_WZ!Wrh+1`|q z0%m*nl=InVvcAS-oi5(0^jSjowY3(<tMnDu+?syGLuBrXe;>?UxN>OM(|5*|R(Hi4 zpsWnQ#R-dDO(0uckyZFYBVBx&v{g1PfyDu~V=MnE5^wI!!R6zUT!Cx|3q10ME`39b z{y)W;Rdi|-P~53cn*9o+Q-t}BR&OV!W=CYBMxAk1SC=Pv?Cro7ds5Cp2pf$|Sq(kP zM*Gu0oQ=lz7>GdY1msl?ITK)Mhu+$z6k!v(vD1GtiAfP1cp*ZHVy>p-I|2B~`IpkG zv^no0HRh+(wcyGEGMGj1%fPo{H6L#dy~N343n~0|@l{r@SbB-)K03+;7gx)D)MlLU zvRVpD?LU0XcI{BVL!9nQ?SddgnInfG%6QRul0Pu0bb7#G5lCv!Ge4+km~8Zk>_y({ z+)g=V$4dyzw)|&pE%n@Q$_#Kru-_CLp2@PRp_wbqBLk_0iuS;;gzQwG96R0>*^5~G zSdHB>{Po$>RnwQc7qDYtM)~on5=H$6=_IN(XX8-^T&=PB&8TawsMf@dM|GP~C!0}A zbX1B6rhxJiDh~nWu<3#ZS(=R&$wCXZ$LB$C`87#6)4mGvgU5dDUyPv(XIA^2^Wgy; z&FnrO9>K7Na|3fFEXX08bg2164&g*|u)+g+$vO_DRWDtLAk1AYf^7KH@vd<Fvj>qY z2gb~sjdc-zsEa{gIH6J-Zsa_ncbdbg4G`klYHGz%OkvCTawnP=B~_b_fZ9U(-GIL> z(Mk-dn6k7d#Bnb0LhoP^6wVB7L?EUPdcJ)f`ouga?|%8Y`DFwjlcU-5T_hjpjMg&E z0gPRYS+fhw&c9L%w-8~(|BwXAjClqgCyaK?%;F_baST7inR%GJ@6a{Yc#m}c61%S1 zs1H{{dC+J<;=>vv4G?wFhh%IAn)t!s5eSYCB|~?pszXO)`>d}kJ1|!EAog5!bP7() zl3M<u&3oW&6UQ<DjeVi{2S0rkYeHgOL<nw<p#H?jPO5A6sl7`~shoiD((G{HfY6Ii z9x-c<!FK>oG3uIeW&|jP62&g2_a)6yH-UuM!{!rIl~HEII9#r6r_dzh4ARvrnBL~l zk#ody4-T9Xi8ktvYppgy18(XImFov+4g<`edZlUDz{XGx=O(FdgKWXgFGQkHZVF|I zH&i-_7~;KT)NKHqa%84mq6Q$QgQ+(@VTm3GEwrw}SzBQ2i|j@)G8mRh=e#NS&~$*m z=$At}^xBg#Lt50lPmg!e(JIH}S!iJEF#nAnI7f|dEl4=Z0lmHUnF>0nWg)1oajVYd zW-;j)Ykd2iLyXt2Ga*`jh2jXZ>k^cg=XVQILTP9<`f#%NhVgf~p#=xIXRw2U(ipfx z97FBFY^xa&657TPBR}QIlklZ3`iEnFZ$d;c2Q*vgF2-t!{@`zDnnQBKjLvK2&N5V# zQ$QS0?Slsy?9VL$&+kInvab%Jig%VVA2CZXyn{k=a|3+!gv2bt@TP^th5^2BLb4C1 zjXTh=Osg{giUBX?9?&=Z=1fcmIYZU74uMA9c9cpDn+%>-w*#+w<UBtRekPsm8Lksy zAL~Hjb}1nl8lvxi?GzbrY&oOZ$eyEuuO06)eOj5i639HAT(Zazob9#Su5Kf849ywT zmObz=hCpbJyDfWg7Md(HC%r9u=oWd)Y|GBbnLyaMw(K!W@#g5*hUPoZFa(Wy1jkh& znBH><^kUs&;228<^2Eq`bO5(@`CrpoKq8w6)~QE7a@-1PWYErd(4ctG0S0x%gFfGE zr%KC3PzHWXgzxqU%83WH#e?QCRed~YYdlC0Zi)weKOWS`RJ-Frx5a}FGN>~ibYnb7 zsyuL#UBc{mP&%NIrSYI)@gT`-Z9M4Yc#!0^EgtmI!**-vHjD@DjRze7G}0aqYKjM? z<sm2?KV}>LC>|sTbK*gD@gP4_t&Inj#e<~E+v7p`@gPCCCmwV~JgA)r2TZn$adtdN z5N5=KIv?s@<*D(YzaWTYRTE3l9GtA`RF{EP<1(V<xPq!vU4ResdZA7=0ka(oFJIW$ zgjqpCt4HQY48Mp!j`#APQL*PAfm2?Dnu1CrM+%gIt=_}3>|VtLEy_oddY>R{QD^*} z<eknEuEbmHtZ*Fz)KE|)Gq2B4W}BqX$2doU^djIwL~4n?76tLLR!*ePgFr*LZwg~S zXs~-yXidYp)}2^|o$exiH!IH?Os*{VV|5E9G%hp<R0}PqR+ejh;^n?~P6=*x?-omk zaqlwIojprZ7Whl5%`|%5RYQme`nW}w9XuJmnZG-GDqLMp*7kwShh>=th5E#R-(OYf zsVHA~i{wxE#G-|_^n}wE6?vOj+!tARtrrB_<@Xf9^0UH;L5H!N1!cT3p#a{Xeb5(a zIQO9AxZ`ng0R$s;tCN&Zx2ZcD7T#!m$(L;-wzj^aS{NVG)KTD+4X2fq6wlN?t_7A0 zm`-Y;_;>&6JXof}>SEYWl4CE+hj(bnhijLarZ-MsO$p9t1ZvIe)a<fJnG2vmg~o&Z z!aj?Sk?T#XO`Q+NlhuukOBrEOiC-_dWl(sRmgBw*N(BsOxy*Xn-9$L^KzXp?QZlP* zvT0BX7{h3nVwD+ZC~As46;-t*6RN8*Ld3AT7A+|z&{_|02I9y2&K@9w>l}ok56v8W zHC2mnVxrdWPKm?x@%q}f6cWb!Nt|;b9;(aAxx)Ei!yR*i=X8*Fw;(HL){}i>2Ra7` z;0&itbuZ<zDv^t$PZE#gi=){bs{-=@=DiKZvF=is>54VFLu&^EjLIr_W2HmdxSh=? zw+GIb{MhNzx;;CkX&3{P+}9~IqT*&Vw@lrSZA8ejKAI1ldjOPdAFco1P(K2xqFV1Y zwGMCCw?N!q!0LNGB%GGDBI8;9mfN{$tNrY>!*d@6yb)7uA*D_A0fL4jsrA1?=1&fV zU^WqZ-QwZr9IV+ORGms08tcL~H4AUiFyf8>1Xt3(XzlX+ghgnhYJN1Me&Pv^uf{P{ zKp-yyQrDUodn7o%G~n*~R#^`6hF4GdYqV+Q&2}?VFgX4@fq{TBlKKE>ku-{P??4~% z5%vmTxxw*6;UyZ-+~^ei+9W*_F>JlgR7H}WcrZ@VA;RGw5{R$EA&&Q<c$YQ{qV?&c zdV@HnL9@|mDrHu-+K_y!)yT-m;apgt7%#zR7+r;k#;{EtViUl*5blr{;0CUCLf*Bl z-gVd_UJEs17VxMd*eK#iJh;_IiA=i{@@x)@p>Ey}<*j!s-`l+V$Tdpay!-p2VjHpQ z-|92!4xt{Z0onK#yUGxrq=i1Nn5r~X{TAv?>|l&mrBsWxFHQ&rf~{Wo9Yc<->iq)b z?cEUau4?tJ0Y42!%1|T}#np$4_)R`F9qC!+j;U6a7hhqZ0H_oC1deIkBNI?G+%kF+ zl7&75zkMgNNh5g}^@;7Fl0s5YFN~rLi0szE^#~T*5ZS7SWe8ga>e{uD!#cw4h+ubV z7YZO~o)O*V=y%bbAK9TJkODVttLzUbTpZTCyZ|39(UTa{+$)ogXTQ7ATF^7V{tD(? zi`)e`jpv>PK0{Y$x5Ab}j2;k&aWn8Y7w1TziNoO)8u$k=aqT4HPua_B3EacFrDGn9 zb(Q;inCF3n6d<dLlIaT;!#%XSR4^in<U#tQ<ATClWF6FJAt<O7m1W`hv~xBCw512m zefUxO;u3e}Qd|^@e=?4-NQcv=PHeNSZNzAae{m6{zl`8Ej-!>-7)oR#D2t_P0NT8& zymo0Z9C#uM_Yk-Z3k@NEI>mm2*foYG3Q6jDnu^2Wu<6?id&st0axKw9BPjX7l<1F) zYJXxoH?wPY3Xz&Hjqpk{7K@MU8OX9j8N%0QdBvTlMsTORQvYdY@I@Fe1V(*3tEP{* z16KASJN3ftmFd<{m*$WP`utq<-v$~&9l@(=*87-EfNaOkIfT?Ph)I|A@JIpGBFHT6 zgT)-@eXt7H)QSP9DI{GsFY&1)=<n^p`zE3gecgK;uXF#5@oG8EVxM1xX3gOp9UQ5{ zFdVqARu%A92mJ99gSx+0?%W1aqpP!?uTa9T^2!80d!|(@930nmS{iO(9Q9-5t6w9T zh^3aGnuZSIap}3?hVA%+No+NR4lA>hiSJ5i2A8TVwvYrzvWY4qj_PeRnNL+g!-Vm} zz4z4mF`yhIE+5UX%63GuN=t2c4;8{h4zH*42JL>i8TnadSV|gqJvR00n^WtbMqD!> zd#U;*qqXNU!lQT{-=2E!{SpBep=NfC)aujR(Qn1z$y;ItCDxs1M)FW%BwL-6*`<Cv zU0kQ^hqL_~iRwlj={zg^f!B_9Mao#k^%B#ckgMzMldTA743OwjjuPD(YZ-MmHt#_J zd366U_U4>T+u?&gi1aa4{1Vw?;|Q9D8%k;vLR+F)Z+9bm7XYi-iMf9f%BQZu-<Ie= z#(Q5YIiO+^8iVQK8U^x&Kk`jWxsjKST2Nj|2>;17!}|3Le$g2eOHcU6aVq#tY@j_( zU*k7vF9Ad3q|d=&m<-^jZ>V$2@W#VGR|6#80_g1$y8)b+ARP2D+({=E#g;k8#ro@2 z^<$(^SG|GumEc#^QS8PEinpQNqWubHfw(8`q%+PW*)ulwiL-*?8uF?k3bJ;`R~C8V z>qj-BH&GVSF(Sf|0VjrwSZbZT!+OnvSoAY1?VpjhC7ewfjCPQ_nOf9%c&HV!*(v%^ z<TbJs4FIcov_`9P<3nn%)79-{6(l|^96FKPY1s0|+==XnYkfPZolMh%Kio)PrqA*| zrzY-6QQs;vR(2Zn91Y!7hBy|S78Vw~!T}%bfLA-<ZU@}&fDd)Rmpb6-4)}5hJi`GG zI^dZOc)bHY#sOdDfRA&)*Erx=4)|IJJlg?Z=YZ!p;2Rw9JO_NE13uLO-{gS%9PrIH zyze-^YA4j~n3uZs`_fIiKo6@w#i7|2v|a6tLvt)>r||>PWo$uM*}$Dat1E+R(BT$^ z4pQTZb26P+FYNwR(4{V2z=0>52c8=&QoH!P#q{nEZWLa-8wr}EKp;#*OE4(yk)y3A zF7=E)vN+jFz`d*2)!-qBx2I_W(vqJ2Pw}y?+$n)Kt)!OWg(OX+xr82!gOKzuFu_97 z0cO%Cdn6rf+H6Qt*-_U?2P5gDIw^?_b6wISsoR+p^01Yw8%b}`Nk^GUvw9>Q>P*@< zo^&XZX6mHZm`M|QBu#fFO^zo`N78?|rLI?)Nn00oZ>9`q(th!z8Auw@NqNYDbv1e< z&2%QE_jI#`Gm-R8owUGA>g$nooHOYu@uV;kRXIB8EHmkuJ(6ZQlR9$ELei6T(yPs+ zf5NzP4vB1M(v#x3W+SQWImSoRk9#D|aVB*%Qx1~e$L-2JO_!Uw7WYV+_XSDwkaSM> zq$7GHo$5^LXr`%1dcICN-OTlGMcwP_`+}rCBz^Y+DX^9FDQ8l-T;g}1aruQoFSgE4 zTVI{4gLJ))dx>jLmEeP1YHzTEEf?%M@BjmEm%zj7?3*2yh1Y=ya6ldXBV`4(mjb6A zJi*2*IkN(zzdUjI16+QCxWopTi_bXOc}j;+!s~aVMRu$~I>v0DOF&uTu-C;V3!QnL z*{uD)EzSBii(7zqTQE8m7zrFJbr>pj5Cc<-Q(orn027YieNwkm<a{h#gb?nxON4U6 z3dJk~1^vS+yibHF%^NA#7QZQgNC#4>>+xaa9|m>JdJNPxdj=ao_RD^2BLzB;;|?{t z15zHCxLxj6DR+mu<0ZCz#j9+4JMcXOGXG@|Y~cS}0>S&udZ0-tXNlaFspU2;C&6A( z2;{14be_@j;HRHKVDYA;KJj-3@EfkF`{KRN-;GuZHMU+zR2s%@TFweKZbcRe^cxmz z+`-q>`p@x)EBFHS2zH>kd^eIK)$`E`zxx<k_T<$;rpZXCNj|>IKP+|~GAV_V;8L#C z<n?2`eym@Q;PpssxRG3n6&g}WBz|nyA0JCdqy9KT+$@BNJ2M73oVYuXtV6#Z#p_Z1 z+KE@LuMpulUXSzgOJHu+$l#?6A3OEOQTf=VKRTgPIgT|o>!=q0k6pzrtm3=aKF~vm z?Vf=Y)Qm2h#f$!~lEV?Ra6#g%D(zRC?{NJBgUIe{`=06Iv1e8BfJJZV(62cD)30$U z*f(TQb}xH4_18iG>N=8^+<<G?6K`s8orULoJXheEgl8HaNfyhulc~PgEN`5(Bj}2a zivtJ03ZSbQz>6CxO2h^?7V{6bY|QK;ejro(;Sh0j^ZXXJ!KG*e>Y%X|Lgj8%ji&+% z_^aH7mAAkxLZ#aZ$S?7iRTYa4!jyl5x8uUJ8PE~^^7q)kJhD7Dx6RuLY<l9!@a1I} zo$7bzfH?Y6#usGZ@MhZhf}w#kjr+J#4Ed6bf<YnQV54Ag$mfQc__V<Dao_57J2!IS zi@Qqpgz|S<4%S~?*q!ib3YzpeNa!r7CzKZ(P>Q;xZkK-|{CvUJ`A%nmk?mHmh>_V& z)4n%cxC`t0LqMz^fl3Q!vUGg)jgM$A#Hs`vH?wMf-T~rMmq8a7!#%`!RnS_tdSk8v z#>=CCHt=F7bmzAm2MIYuN_l6G0$Vg4D^FsMq!)AU{msfr&E9LhnzS32ZD8?vNWI)D zhVf};x~WWe8cL|PQb|j36npjilgtk2Yz^+iJ8$GbF1&Zdv`={>QH+!Jws{Y-O7U<U zuRa&HWX8TDxI@8TElr1ZH`CAJ@#|c8SvI_Aw~ejdP5o1!_Dl?UH@AAXxbT`C@@{SQ zZsTh%T=lhj8~K_O^6qH$HbXtRQPxO}n_28@pz@11^REAalJVN!@_YShGe5Dz*8Q}H z2tKC`l-*C?0|H%6wGVsviy@pYP6+3l-DqS>*;f-+{vM0S-v}cW9PeQdUFzteLqXmH zc#XzpU2$^J5zpj=z<FqwAlwOF<&6bW@t%!$oD#TdqT7Ee9QqvusXPR`Rk2YMG=ZsR zidEj2*^DwYaq3$V`z+ul^n<T(wKt|-gE_-o8th1?ty(J`bV$ua*8{teJv7uu{=(UN z3SWF_A>3%@8yG4`L+cpceO$w06|gIWlW;h{<bmVW{ZJ;89qz-b*{3dqQ3a^JHHr?g zHD82ZO{>P6k)>SfvOnYjZ8;F~WWgarUQ+CouxFeYr>SD7VNnIQ|Kviz)JjMsFw2t? zZ`*>@uwmigE`L3E{{|Oh{QO#qM|>NJx8RDH%a5h+K2`9z><IT|2JpX-mnO~{Jvc2m zWgxDxW_xZ#&24UaIXa5z&S)byP1sFV+vPpjmA^N&VGOh{mLd#;-IpTWkuU8DJgb@= zc<vTFEU=y=Kzc|$+e)NcUj)+k%-YDDGFJ1doY1O0_%&AVmiN7Uml~@@Ai8z|{{+Ng z?@qNEG7QGEx=Uo4ImBsO#c7^D8tnvqb)g)fG7nFc@X~p$AcpRF>J9lY9yjT7IsA;J z53ALFvP_#gdwYv&MCWa^r0e;>KMVH+;-Y$O{9jU86<AaThe)_0m|n}oX_naW7nj%G zLPa<nm@RXY+re8OLv3@_Qt-4|;3Hn{t)Sc%TR_&-tOJrhEHKLYe}s;EdarSH*hL7l zkdSAB<$w*@+|y>b;G1<j#YPl-U_bZHIAb3zv6uh`cAF}A8Jb8aT&D1^S^>=-Mz~ky zP*=Hcai35?&J2cDh-D=1rGu>j2-1G=u3yn6kG7PiZSeu!tC1bZK<&oqKD%ol2ZRQX zPyB(yq~QgQJyVQhyHF<ZaBEynT1ZpM$qIVM!eRYh_Y|aVv>`O!)K_Kv5yWXNCD7w} zS^|ZC(|Z=Ns{bE*Zy#4h_5F(v3Wi2XMP_A5K80pBkLS!eGv^E{C>AOyC>fe47#JcU zD4Nw#v{0}}vB;>f%rwoY)R3%5$+WD<%*d>$tj07WqcWqs@3m*n0m;wT&+FdT?~nU? z-J^>&vu8g)tiASHYwyi2ECBbpBo_H?q8*FNM;*7WlrX=*B_7}{Frvd~KG}x==ASst zmQ*qMaoU&p14-J%k<9EpvZBBpJu6UbNVzYTYSSJf3v#ZoE|i@!K7(6&534L}u(aaC z#A5D3Y}%KzFV`kD<zG^~`}$p4?D7203-39O%YC_Af5I)4un%6xgHJAw3-%Z0GgcVJ zqu;{{!>28cY+D3m&g^k^AqHh2E*WuQM^=Khhq~F6&-OEg{Dd<<WNFx1Nb?mKBcevG zJa=h+`=L#<E=G=M)ls{XnsqY>ODp$&?DC@<-bNQfy|2M%^9a70(jIc5`h@r&y4Nn| z5`3!)vid?mAJq?)O4bCV+rbH0x#>f)(}vMmP`C+tcxHN5T0jeAjR(@($KaGE91ayZ z+aD$}H76%M6&te9i*Razz0;VDLkzM1F8;_Uk^E90r8F!%hx6x(_01~czu11Rq<wTt zN)n`%%+UO^JN@I2RfTzCDC@86rG`f`=8<8fYib^uos`WsW1zw;8ELC{vp6BkrlB3( zv`_Fz;XOy7LpX`xHvKL2;Tde!_9mof{suB?FYQK=87*6@l_4Ei5)o0z&O9qq)FrTW z2)m0Z$-p?yhc7x(_QP6g@Ym74)Zj@OzqAQW`b~>#${?;M7>5V2onFi>F2~OGvtP3{ zeL_ZP7NTUm0fyRUf8qeF@kst_GVs;R{H{%(+l<nX&p0f=b{%!IEYO~_>V5EPZ!V+5 z36_tl4s>cLomau)9*5Y{rFL(S@qKLLcCx%-M@E~am<-RcVY!hKum1(#Xgst0`zzIa z_FW2sd)98G(b8?nURK$SC_7ZQRl8%iK;cyd#<+#zD4{rL6C1^0c0U3WvDo9=`I%Jm zCUYX9@;A+Kf7ARqB+xXS&+ae(p=rWdy_lx_Ce=&tI%*oqU>+JCxjJs%Ne^Z$^l6~) zac0_=$P?od{sBW?{IS&|9*o9bWvK1`U65$x*4#y=Yk`7{`j&A%2^j^fBs8Ka#i_W} zi`uXk@lAo+7*%BzzedkSM4J&b(5o7ebu^jzFh~TFHkUGNU)ETGmt9B4?m~I&%Nnh{ zR9#Ww`Rw$O!RfeV8>f?6<CFw-n7c6{XX7^dJe;>;O~^zSptGjw*nLr#i@NliO@Gre zr%#6^N`7{F0nQ7?kuNynB(PJ@fAX7cZEwY&Y{ySjz*3Uu!j>(U;!e$`^9F6bGm_;8 zMNWlQ(qa~HFiqf8LUt5tD%6$jNEV`Iw5Bt#GFTZbM@FUk=}$P^tn%K_Z#Mo@sr~-1 z#{=;dWJE*!Om_NQMhB56D+m}9l#-R*e;*o{FwUwqE6p3MI4qtD#h}yn?)V>LvBGUf zxc@KedvIi8?mX;<v^Bj{iEWyY?TIJ;&N4wvy(2X<8#{%lsll?PGy8)a?8ZegaBCY* z1xm%POjv#4SRd9N;1#E4rO!m(iMBrvOzqjOzGjmB07aKgSHz{!fjv|wteLHodeO_$ z(r=)A(T6;kOau~3&C5&0uFiQd7yEZZ)11V*#jLEXS#v3@Wk|uUqHEVh=`0JYq_B^o zaxyuBb$6O|dm0(yKs88&`0ktl8Shk6h8J`FS43@EOc@k`eB9c`M{y|`GAxfhwY`?S zenj(ir^4zo>Kok_Z@}N;PG@rR=ubh$0eFEl&N>GCO7Qy_&j}E!(hR@yHw^h1k;DrG zW4tDq-9M+Hj1yX#%`r%rR{PbIMqq;t?He>H(HzimvZCr_{_`csNvC38T1TYY-Ljmg zy=}N>igE-WF+_0S7s<Q@cBZ%!8FFmGH@b(onQV)`0iCdfk&G4m6-FCa^mSTRs!<Fb z&53I$jo*D2U>)BfFN_soml;oD$pAT;f^5<5eY(G_#cceJ=+FK)K!1J=cv-~i!oJMy zG~<4%$cNuZ*6vrt?_0Kp)Wpn4kya^p;IQ&G4c<ED$HgWlB@B*b1DpCK=`CBSo8^z} z9x>J#D?+hmg3#e?a$4Tl`qc^8!a&wp7Drom7b^LgFHr1V=3;QJxRkMb@vvZ1CuSHI zHIgoh99{}Chrr2}bQ3dN>{p{%FJ)AiV&bxy7VQX51F#vIO-Lf`3^As~T}gk7TAK>C zmGEZZK&`z3f8_XZHC5?-uhSF-&W~N89pJHuj``PZ|5K$g9*gbs`>ZJGFDCA6G3VNy zd~>cpN7aLoZL<%V2$I$s61BVELVv_wmp%-KnO6Z@Q<Ht4+4yk#KC|%=f&0wH_wajp znPhL{uPiRz#vZPL7h)o&FCE`|S?pg$!}}IZ?q~arCN&!$(xwKsB40EZpJV*fJv;n0 z040B*Jj64yJB7&~x-$*hNwfXsp&JnK!QG!)k9PQ)KO-*NbxL2Vb=r4g?nS4}6Ugi3 zIFACeF=YzUJQiBD{Fz1QV{A|0+*iPyJMbsaR%u8PguyZ$>%p@7!E1I8ryYux%)FY` zUu+vPjqvg2L$CwEfh|)fbbFO%{_5SaJ0Qo3J!zeDM328)VncdFA?tBy3_YH<&WfSO z7HexBJ^o`+3#>M)x09H^x<?-RvH=6eV_{?rNpHV^-GNmKy(iQAUS!o?Sz6<T#$dm} za{dkd28-68NP2Py{tWInSi%Ni8gDf3M%fDm|GZ1IFfu7|7!ZvwYhM+1m{YTSixlmS zPplnrcW0_%h|=tySo|&&4bd=;y0p>mUyOmQrq4KX(!R78hwVM~$C<*Nsnn8dP!?i^ zcbOegia=BRh*aovE-1{dqj5F<PGiZSLCCo5Syui*IJtR{Hn6_5gVrCU-+}T0(p1#@ zQW8GGWrwYwxqGfZ`;7ez0u2SH$g&xiXFnt?upZ2Y&p|?%nkRZA7TLE#2y74k_&_w& zVao7k-iEBwY8kl>ZZ)KXWXZnuaVbX3h_f|ahdZF};-bf9h$0%l1PhtpoDo%kl4Az2 z@&rlbK{MzX7~SMIu}=_s1$SGulNR&CRP#>Au+HQkw*ny})MLzCR4Kd#<=x5(H!S)s zGkj_6zTL6)I5;R8$B2>X99`Rs*BJKg@b1_~da=J9*&S=51Mb^Sbz3bXL*^Tp5iqf# zu&kV9w97IIr(u1~DLB9@koTk}x<~iuAab(uoJ3l=j^@i`?&Qxc+;Hevu=#}LxW|sJ z4yP-apTM-?On#m1REyII%+)NqTH9&I@?kyA2bj|i=7i#saJ8`UzBBTYYMjqTtwPq~ zW_oL@WMjMQa9me8AGI0iXyedy)MUTBOdaj3SE-`~J}$yXy03`FgLwfc7hR{$UQUB9 z>^fRS-dnHdW#efn{Eo~{OE2hbozP7ZDl!J|OiCUcemyg%GmbZy4f$N>adAV0arrYl zkFif%raKTi4<`}ZI2hljcaBf>KOtOh-k9mrXQ$_N9+r`xedoCRsk7R=`e%=Hhz}4) zZ1%L=c{y~tvo%K0^EevkG~UU6-7j{7{LLCS=(RKi3h8!P$=~(D?SXM7Aq@1bCuAc` z=*7<0VBTxWsB26+_|KU(`?u)~#0jan#2mUKi4m|Ql#owOqkS>?IjuJGmdwsFUS)Qx z{cs#4#&KYuAWaJuOOwiJa$si(*rRXPqy9mRrh}%1nk4U{n!|9Ww!8s30^aST4?$$- z46e*aY@d0_)ihg_L%Cqyb|p<G75EmyK1~3Tq0keyve4%BIF*2C33M_{UI5BXPe<ra zBV8o)Fw2D{Xln`Chdk6QSnuP^u^?m=E4jdun~ZAAM>d~6lVoNczzFc?r-|~j2shN& z`FW4DURHjZ>C-#gSv0=tBE*B^h7o09ZC(vmjym7y|3<yd|E-`VoW4C|eS3#-GDIoC zy;Sc)zE&qt0#Nx7SA*Dgvn%3>b$Q1}dIK8me!tm%zoZ#sepRYV_C#zYJ-y@8@x<j{ ze-C>h%`=De*b7m7>UDS_el-rS%$=nDlqcJLJ^V2DP2`#5Lhw?2Sq~IrX=w-e!`19P z@iKjBDcvlOkGp**;S)EZw}epqHBnUJC%{{gOE|fx<Wg+AM374&xy-X%-tp~#6GnnR z2eo)*@t(qiRlYy%r;tH-sL7$wnjIe>a2a5^?Dn~-*ofgBUmZR|Q${Z#$#AV%KtVY> zXbQPhlFJED4e~RET=tR6VauhkHp^USe<XEh&0+fZrsa~5VJ^byB0*%SK>yIQPT?~m zGJkpB>aiES#&BVE0#$MTK<t|%FSc!eb?9UCOeXfQ^DnCDfmaHBIrI_0h1K<x{roG~ za}#^Ms3y_&bO`EWd?@x&)T|TH5~Q*MpFt&BmKWJAS<DQ{;9?$t#HY9cY|8a```t&a z8I<3P#c{Z895w6hB<5O46jmQ#Y4?EF5PBr;U<HjObL%#c+e=s!F>RwbS2kEkWMdSv z0l~GE30eUK=UJI(Kz9!mq^8Br#L18Ba%P<`0je!z#XQagLZ})2d?EUxNhw5)KScET zLPXjjiu@t?^Mz=zb2T0zieleqbrpBMKv8xw*ZPx5JYR^zb}~QXy4|AK4_GqE=L^(m z2dY6J79!<*A$t1D?+-EMd?Akb%kK}7cD@j%9ip#4M8^3-9JfQ9#JO{<969F;L8A#i z&02&giv5rUia%eVFuU-@{$#4o7oyot=2k02VKq5$`Os_H1F%EhpmsDNe)TzNLdOrG zV5gB5LQ&MD!I$a8Qi<h!%lYzg%Ff3}u-r$8!fJBhpa?>I^jMQe@%;df%Zjh<NIchA z4z_Dzp%ouYht3xw)DAJmA7aP(LeOl2+?ZGULsXxylr-B=h+_~ov2yG<UkI9wD8zPu zh}!do=wXL=zzX53X0uJ6MFVLjV-(Du!~B+eBGNd=+zj88`a8aJ&&|cmoyB+DN)_#f zTI2FF7Jr`4?rA0Z&j>NM0!6l16(6R7?M2j{51>7d>9jSix}5bYwxjH<StqH;I%1}p z{NG77bS#qM=wwsDRolp2VRaKrGu?O32V8z1x*e8MC3<5ndpMA40a7*BRRt34`*`a# z7tNlnX)dX#n$lvanx`AuCRn%9PO#aZ;QMV7Bsywd(VE}_N>FJ{Fu6^F1^+3*rDr8L z&Yxf?;^OkVqhKM6@yO=4Jc|F57ukp?tZrdhnudB0)BvmZqS8PO6j6Y+2w+!vX`2kS zo#@Z1fm5Hht%04?id5yLEJN2&O=GTImWJ1*MOpY;yexw~=g>3x48{Z3ZOI4t+ZwXl z65{Ic9#TU7Xu76ynVtN_Va!Cg#pUqjyXV6;wM-w(R~`x!io%;8f>k~?i}j-_Dik~U zV>dhY<HG6&=2C!l%x-qh$A#6WSixyWBQ7n;!3XOg#jpx=vCy;1yC2PYj8%IepHy;l zG7?1Y{bp8itYnqQ8keu*x!8BA?J#XeK(mm}Ihd-Qd+oYiz?$+>inAb#%j<#%UlEhU z(o;2Y)m(mW`!h@{DIb=g_M#de;)a7c$%?GlxBl#m;9GGKV^U4q=O6wVd=rvoV|f!2 zpabdPlQFNMPgrrjZ~62Klh0a|{6y+YYmwxj{lC^oXX_R51y)!7MM<yaqu2mVfas*f zd~Bb;C9zO3FMwA&+UPv<vDP?qFY(7o-WoTt7>nU26*nnBYBz-1o^l+WXB`Byo1FrK z=B49fAVZHt8O%WtyIDCix4-ibS@KW-bHg#V#A3O^>m0W2j@~G(JS(ljY9DJ|#$wVV z_1Up`W)eOh-GX<!RHf`23Re3bwPpoMV}8^%P&dzC>@P<Mc{ID*CGoMhGL#a98R0Js zb3J!?;;1|+uwS;za}*{_tUOjs2Y+lWlI2o);n^uyY-Dv<SREgXjO5)(b>WL>+XdKg zT7Y!Uor6-!!66tM+c~%cIe-WS3T0N2r4%nBHD870CcNONG<v(}q}|CASh6!&vZ4P< zcGJI-Wykv@R8y+b-ic;vYr-eqriAHyKPzF1nUeCJm2lZFcEX8m5)S@X!gc3M*xVl| zaXw2JhpE{KQ_Pg`+cfq9CBDi^*gtB>Lpe;+Si$>J2><CvtiBJQFa3<x^na_Pf@53v zC?>5ar3EBKAIrvm`MH~|83~wuS|h2VNbCamBM4>@RG3o=nSm+GD*vynhCbQ8YqV>l z*I_ATcaEFdWtCR8l-1RHs3y*p)oRKpw)+;eMiSB{tNsXXWf4@ETNhDQO~mQ1=p?d@ zJN+%jK}{5LN~zWDV)bs8yg)`3IL%KUzz&maT^^^{KKH+2`8=@^$IIl{j!W#|8(w6= z%}Fm?IQ=;b3tQ}HBQ~{Lb?>laxZ95QQAEo!Q2t^&pZjc|x7a>s`hBk5*3M_6?ejX@ z=P<v|g4f&mY_fg+{km1CEBro-_O$cKJ!MtY$F|R(pSSbb^P_e?!)>1%Y@cuYeJ(!K z&Sy{C=Y6)%$NfH!f8Wk0Z~IKLecp9$pNuoBiL*UN*`8zko(ryN*QQf!pa1Nziht#~ zeOl3G*`7bLJ^!=;!vm-F6LqA?&@?gO$U$9V_vKwuL!t~8j5^nZxpwPU1-Hw<Vmr=z z>^L7ooCskVm16@$XF&SVH$a9N2`Gd2v&U|`ag~luAojRAS<9mGE2t~X&g)3xTv0=j zm`Ct}Imj%(j|Rt)W0P6@o6Z-1NNfBn+Q+})Su1{u#9VC0uUhe=Og2N*ZSg99Y3k0G z+M}>_v`f>seQKJW8bxAuw^O?bGZ|*di)tF+N;Q91`(VLsgMEb;s)UvIQYADZ04$u@ zW$3UB!*e7%`Ev@$MMd#tQPoIjk`>~mpk<d)3!B@&0THpj52EiL`+Eob`(v%&dHQ~} z{k`L|%Y2o1pGV&*qsh-&go3jPN9l8zw5x*5f?CT%VZj0}FOnLGaz?tPmSR#YwU~?E zqIRw@=kLY_@)AT!j=xzWpDYhzTgdcall1`y7h=JTsSWa5WQ8<vd&|y}elr%b+mZ{> zp>2yQq*O$~{B~7qAY@(|dzivLQ0fnBaZ|Wy#xek3PP`SpkzM3rW&!8-aoF;~IxZAP z0qw|xhzowrZI6*IWbKn++ncB;_pf99*uNaTJW1M*tLsxfpo%y1-vv5K%kd;Llb(wk zlECX6Fy;5?r6~!Tzyb8w5sxT{FAlSddAa3Md=L>`YDF}N0&5N37Uv+YnjLmEim1k; zlPPuzY@2#im~TF9_4Ed6!qv~PPGl`qsABhijHt+x1IbannKEiR!5nT0(rw$2ynHs` znh?X;1KQ7(2CqTfkC2HR<Co1o7BRDJI|7V>Jw2D9SX5c*)EVqmE=&7xE-{#anGahN z$XcO&lYRi@h25khSNNM0zHFlpv`QMr@%dUX0YRw+n;)eX{HDU+f^}=pYQamamZ0q6 ze4CZ~sJ70XEhozs+ar<Prk6IDKVC(qh?Njp526ZwU=^w<q$g@@X>4V2NF;k$TO87t zJ*>x>H|WirKl`*t;o@Su|J5Qh4d$0@lr@~w#}*9l9blxY*^YpE?5#$I+xo<Q2RpJV zRGEL%%y?4l)KO=wGN0RnAk-NHJ#ZDdbi@%z=z$Nju9{R!8My&k8<wMZ%8}NPcUhn> zu7f!KSSR#tM2oW5L{Z7N_ojy1v;7X(uhoz>CPh+~j<Zlt4T1`bM+G2Ja|XgLPpaHb zwFMt+Jl3SxANSU<<|+0Spc66j;v+GP^+Zc=>xpC*))NT}tfvzDX}Pt&hvdFA4NjDa zU+<)jM|(cZ+6UTbNb}K<^!-D$8SGzI+nt0N<F=Ud=uG2=!oSYsDK$Pje*^saTa4VZ zbfYt16ma5OG`e;F0hz?Mn5(w6CUdOE(d=^Q$WXnG*HDw@dL(52fj{I^dYYA((bS$b zo9uMnf`%^1?AS<c1y5b!DakC_j#r%f0*5vD4ou>uiC`&l_QR6TyOofz0y|D?_8}Gw zY4aHnE}QF)PKLJq0`i(vPM>m~3XJ9?#D$H_dyi#7yNlzzEW;+!yF$O4I|%kWIrE^# z&B%+48a5zOaJif}h`hi@-h`9sU_3WAfA(zL4Lm3^0oHiX{myO|K;(Je3NQ+q-pm=< zk@2ZGL@+>WABV0n$xN^(A1aZ$kP6pms%2C~M@*jKdNYb)(~M;JIPBzE6=K6aGpDvp z1a9BKCNEr~fe{Iz0%wl$yYysC5XQOYcZq}_^byV+;CJZ@7up42Uha2^f(tV~2=TiN zf(soKV*ZNeWUau%g?haCwckZ1Lw$3<|5b&Di^xN*-$nNa+3a_Th6|~(%?iIu3|v@3 z%ls~JewPBjOFUdy%+viY*dt)MB>G(v%}iFM=r1W|7ZfAOr0|%tULr(A@Rg$;%oA3K z5Rzw^>75w44k@FTWW4M;x*F8<=$N)f2JfQva5j}y({Dabb5WBur@xGsT}LwzqP-mf z?b)%r7rP@PH4B!mY4h0jQc~<=x@P-;$FO67taoY?m<ZsMNu0ks<d5~&<h8orjjaLq zz@5U8Wdz;XPIozH;%+>$Pw;;WZ})9h?j7`rg(EhEY;7oxtMEL{?*8rxBPWg;6B9dj z^vF>|M#K&tIx2zri9DyDaifOB$G3WfABvB9Phx7uteL5;c^pWG)eIUqI1M9b;NWQ) ze%n<lCmVovSZaRk%N>nku(-%bc&z{I{M-7?4jiRypO%z4$G(J;E;$L@_->^;9AU|} z_coS5Ye;s>V&EQ}>`0_%+i^s~w!wO%474VJi14GbjRcO#oK2Rl%#tHNCjloo<>cZ1 zPF#zEjT&e)GLP+z%I%G-QE=;uT^wxTn3k2FhMV2V<S{Q5#@%+DvB0=Y6BZWin8|qm z-74*)%%0U6<4C&Q^FPE#w&nJL<uRGLtSVXFscwzfv17-KHP|~1z9`${06hEK&Z3Cc zJK1a6l|xrAwz&t>`i>?(XC0^EvI88S=x-f+BO10B=i|0=7$MU|F{!xnG;$8ECQnDj zO-rSlXRw{@-^C&uNXi@SDQlA#8d9m*^Q>=S_=bv3$e&8rk)-G1m4%6DAI7Hb{_l3U z0L}Niw<|XqIW2!$UTa-meRjO|_e7k^YUdE&DbMZVIm-imCo0<7|Ew@ca64DO{db+( zl}I&;K8MQtuj(-r@wYi@mE|+VPLu4&+1Ytyw{01fC$Vh`mJNO&3$p_k6xw~Bb#?S& zHrC?Pa>?@CKNiq&5j{)iGGObp%s{j_vh?P3G$Z>?q&@J3Mw#tS^&QwC(EhwM`+z^H zPwK}3e`ML-&M4k0z^vSPZNiWpRr@<giLTNfE~;9xXtzz2SsrP8{kQj%Ql7fOzjYey z$eF2kwBB<{>B3%^%*t49$S?I*%kQ|EsPfhTaHsE7K7YRaLujUThn{_yoIRlFVi-FN zjdMRy@zb1WxZz$)wj<y+`e<JeGigxdZT<@z@JzknwzKbr3D8lBisgxDc;dVq%qG@5 z^=TTMv$AOiOB+9_v+wl#Auc2a_HjUgI7Sj-wBKod8aa9-`$qlMI@dOrx(RcmeqtX^ z%Z}6Y_Y<n?K>xA7P`y!nI3SXRr7<7yLyq{7A1VhmhCdJFFLQQ&_WZ2OsWfr<{aNl) z@gXy(tvj`6CT_TZy&iL>IM=}qXDZX|MD(q7t8QSZjvP14AA-irOzUDrwrO<qtUUCL zMA{R=`k+lk=~!7Bj%k*?T`LniIC4lN&a`GbdS^||OT~p7w4Vn|D+cNGS-4}=zx%f} zOyu13so0v5hYF;H8s(Y#VCxtnCWIv)Xe(;Fwr9@~UB>a$>ABh1z-Vn=88=L@;-b1@ z`vT%)#@bs0SQ^wP?fnADv3RC*|EIkHxiMJ@dE?&y{?ofJ97uj65oSUz4&ucIDYB)E z%wwBRaE=8#;20&EPhEn=+XEQmEU@Qbj%BoonP&Pdzn?yqAEJ0P<QWw^*JcNQJ_GfG z14c8a<A7>bMOJ!Lwt(Fvo|!#!J=rs3A9KUfQ3u$m7RN2Se-h>7Jlkg7U(6Mr>VeH0 zNiBt^BJ$~W2D0VM55ta1YM`Ti(3PdV5D4`M#bFZ#OG$jj%(;i36-#tDwwf$mbOepX zSoSdXYSQbZmg3ujmwcWVf&FdFV3On~ADe$a4A!;JatLtVn?Vbb1Iv>d%ze$YZffxR zG+Rn(4bl|SL=lm$E!2D);V74CM7PCrkwuo{2<*U_K`)e8#L@A1tXYf<vTchH3}tO$ z8~J(_?t&h*2^u|QU;&G$X}7Nk<qSGX785n46y{RABa9jd10^iN6d+8TKg?1V<_P}Q ztfes22nZ8wg}JYA7tZWxK!D3BKvF|>H9VQ_GQ8ko+q}{EhyxA|z{BsXga?+755n^E z%zdV~l8VQ^!bd%P9AG}`i$54??Y|5sA4vz0r(4a4bvPzB)ov?OEW!FAm&&n&@<ap% zdCGZ(l^t8No6h9mo)XHI4{@H!Z^+mOf2?q!)~X^0**$i#KfZ5@5nper)?MZ`Fw%(b z*x=Kk#b3jgDE47U)7Q54rY3VP3|0MWPj<-j(T|GgDB@;XE0UZ9!bGxy#h)W)4Gg1e z>f?Q!*}McB6KeB$m`R&GPg4yXH%;UP{?RRvL-Qb6FvK=6*=>{mqLCx4uZ5$caPkD1 zfWqRK-EbIUKD`W5fM4iOPn6==?dErQMntxtuGos49LlSxa}5iosCSwBk5H;-MNEdS zh}d7Oj8RslnSU&%CD?aM5q+!W_gs8LyIIwF(Sx*NJ8piroP54UK5^hfb70E_XRX07 zGkG}sd1$J2HF-8x1Rl1}j`*V+P<uoR&=wrLawEqjB)HqS;Sn^^FI_l$KV)_7TT3{c zMOo<C_t_FCc_U_UYv?J#JeW;}%Fob?b>=SH1d)`Hu+HD4)%y_E{1U6oYC0Rz)X_HY zgsjIQlJpv=kqHQ}>*(ib>0@+o7Tcc#V{k0dXZ>~N3|)J&Jeo6SqX7Q1eVfhS&@A1S zY{W9woUsOfu7K#&tixdk=0nHvr>6VgXUt55*c~#sehC+3E`(2<$h9+!;`)ET|MME? zfV*g@E>HFHalUJPTytL^C-y3?6)!EWO%Z)uPe7^Q<8)xKEqQcAl{MXBc8g5Si-hEf z{Wx}lHO+bdN56}@AV1d62NVsc1+X9Wd!iu3R}o%{ttj-o3>c%AD+VTVR|1>{yc{?k z_(9+qzz+c*7~|s}1+E{3ash{r_HhpbCjhUY@4zd8BjB$LI1zXia2fC;z&#RtTsd$h z@MFLxa0PJIEk5pX;3(kLz?*=dw(&DIUTfnGHh$j58-bhPe-rSze$6X<%$XNNNmd+A z)s;GR8W{1`v2ODYbXi1X6m5g%2b?RSc5ZFL``K?RwDjME=D7J;Q?JZSn|)`hB$Bwv z2Z#pL0vKP{wymh`sI91-sEw$diBF>+eWM@Yw!mWKBH`)-uqF?V!~;Qe8^GgP;V6z% z-4=4afP=#qGXD|4qwpRHd@V2!+#5I=I2kw|cqniRa3A0-;9<Z%;27XC;J(0>!2N(X z0rv;q0el_sKHw<e2H;zOP2eHGr+|}yLoZ&)jRWopJQjEmFx9dOoCq8TJP<eqcmi-1 z@b$n2z_$UH0uKVN0FDK&0-gw52Rs_M9(X)(BQVVq$AKpSp8_UXM(`yIxf_AQfqCGb zz_$WN0n<8M295`g10D{X3=DRf%K{dG7XaS`TnaoAcrEY<;4Q#$z<YpY;09m`*aTL9 zn}Hp`+@%XSI)*e1SOxA0>;jGgP5_pHX)cQa9s`^ROnZUSfOX(JV4CxMz&8Vz0@Got zmB0pY6>v1L|5s~04CjJ7uqXffj>Uys3qW5|$ZZ0s_ZM=FfU*Y)xt>LZTm>LzX(3ky zXas~WE99a9)qwb7xB=oy@Evd*5VgFJ%K+2@^atS%;2tXE5&-J~JxU9?B0xQ$$HQ<3 z6aXp#2LNF!5Felvum`}cM0$WUKnb84a0C!m1~)(hfLnz$0c!zak030d$D@VZVt@&V zDM#4=QIEk7V9@G9ZVMplaik0AQGs#-BA-B+01E&+045;v$wDp%un!RSR3VoLC<QbD zVk!|2Aao7t4Nw562DAY5rx6dJ7N9?a`~eyPd25m0v+xH<TZj4qGy@W!LmGhi^{9J5 z10Z4p`~kwBM>s$wU=N@f5WTUG^8t1MA~zu%pc25nP{^eKN&p7{p_@?;fc1a|K;(;s z+!R0wAhZhM0F{6SK;M^;S3nk^63_tPUWOaM2dD!?yi&*|11bQGfWBK$Hoz9ZDM0jA z_ytr0ngD~gAwEDOAo5j|15gDx0#K{b9)RHONCU7KP!AYXgFXT{4v=5NGvF{l-GO`q zdcKY_0!jgOfK!0JZ=fuI0>D~8J)i{;^Cs#O&<F^vMSOrMfD*tyK-gR82Y_TiDWDqA z2vB#T&H%x?&`y8@fcQGpKOp>V<gxQ&P6p@z`o#nLfK%ul4>|M>>|@`3Tq*nR<0{#A zAGd{l_i=T=wY9a}0brW$O!|(8Q}hlT+6C`$=m~rV{|3=JK19<ya02_z`KADa&inF! zF~WT%z#W0t0tW-v0%M->)dP0|J^~C`w66s?6gd3C#k8l<7X{n}I2!mu;ACLTOTIkd zi-1djA$#*x0(S$h28NEqw+|TdI$t9&WD&k*U@RGZp<#=;2;eB-%YdVSy8|Z!Uk;oF z4B3Fs2aNLcDg)jjE#?jY;uERtoG%5K%9aI8Wm^DDWh(-vGKEb-9Dpc*42TBA1Cjx0 zfC4}fpd7Fkumw;Ds0TCxngF4bkxxJ*KnBDCrT_{6rGT}79e@J>6VL((y?rs)6Tkyv z0Lg$XfDcdxSPR$!r~@<rngF3w5C$Lv;sI%Z1%MJjC149+AD|I%3J{)(asi?N$$$)c zp2O+|j6(-55)~AQN=XQ~1yQ@PUz*=72(@Sb3jA(%*ggnb5^xKmwqw7FfSZ-ZweZ&y zJLVz*eE~%qtvr+iqb<1gHr`>o*W0+!#?3Yk-Gs7kw!&5bQ`k*5uC?78ZQNwzU|0gu zFT%!AHr9b-0P%nfKpvn7uy(8Ee+w|_Tk3!*od#eOgKM_Ghi<d{^|bLI8%NtX5qJt9 z3y=r!0m=XkuUX+tV2b~g{T{l*j?c!tjiYUxXyY^+FR*c$jn~_F2XH;$2%rTJ{yO>q zKnCc5c)*#UUZ8=Cxi^C@<+6Y`pyeKDDr#EVv<z2-mozPJda&uCrqZT|n^rWfY$|J7 z)$~ZyqfO;a1-q?076DV<%Wb^LcCQ5vhWi2g{fPbEV!wyKV}*~jv1;RZ8>iSf$HqPz zm)p3?#&tGs06q?A0Yt#&G7>NdpabFoDS!e%{fAb%jldZ5Tr)7WX>h&Ors2T!i?p$9 z;}{z!+c?9<J{y<Yc$1B5fe!#odWU7_+E1)_w*b>9s<ZI{+ugKri;cq%TK@amShaDS zjZ<u#W#h#*uCQ^Hjq89L0nLEmPeC&Pg8<QhctA2>3ZMXBfD#u0_d<=717Cq&9{RnN z-yXnJPf@`1(`_7Y<0&@Iv2l@&D{Z{R#(RM40gZs1AFa52z|@CIfib6Wl{VgDf8S%{ z1{)s-rt!xev%*K%cn~nT$Jy^GHqNrK&&H)TUT@=C8y~Q-3ETn*KaTnWL;++#3?Lbh z1@Hk%0Of!xKpo&P;5gtEAnYgfL4XX10VD#Z0P+AOfHJ^(Ks8_w;4q*W5PAaX0(t=Y z0#rZ(U<x1$Pyp}&N&z%>D}ib3Rsqx44gMK<2FQSTz!X3MpaifMPz~4zXaqC^LYv?p zzyo3cDS$jc31BTi@419(nu`afHkx9;=h?W(#uYZMvT>b_57^kW@hKaJU2VnN)5fxm z<83^}#(BUC040EOz$U;Bz&^lXfC*>@1j8gb0uTup1c(O20TKXdfcmH<tp7IJ_!Kbp zl`xp66Ygu{Q#j!yI3NBYX*>+zf<uT*uwN6s|8M-7zX{>?GzOw!F?@L>gp2<AY`0Tz zi)-gL^}7&mN;|iwe+=Qu5NF$86WrFeb1OL(!tHD4b_i~V+qrc(9>N`I=jM;Q!?z*a zl>iZN6JR<Z53m?e3V0H*1+WuP4>$z)9?${^LwR}vcz_NV4VVm=0hj|Q0+a*R0k!~k z0_p+u`_aaoQ2w5P!2mB{G=P3NzzYCHfF}XffZc$D026Q;(DnNeu0KEq3<snDG5`gD zBETbnrvcS~I=}(I5kM2*A3)b1Lbyl(4;Ts<3z!PX1^56D0xAHT05yPj0Y?DMfG%bT z*Bc-M;sBEYIRGD^6tEWXGN2Z45O5sO;b;ig9nc$~0)_*U0U3Y-z%sxifX#qCfNub& z0A0}bJpcm%(SXr_$$%Mv1%PD$`fUcT1st;9TY$TuKlB6)1b6`nfD}LmU_O9;<-pqj z`|Nkq#^LBUy#XqKes@A^n4X0b5N-XcrLrBCi#v3urDlyI8<JV1pp8#Yos<4=XD*iX zj^}U>9FTmDK;tuW^YT-(hUccIBWC+;2#&IwMmdU~g@o;I>^bmdLS`CWXq%fjYZNS3 zGKbD1r74$~H5=N(@nptgz2Pk5Hg9%J@D+$B5IS*|KT3o|Fghj165ZmRX&BQJGssp9 zul74M6Q~o|FAO2K38*K_o`6|Vk@7lWRwh*meMPonv(v^*Cue#eo0pZ8jpO<#I<g@M zxTj{$PLC~^mY!o*HsxhpURoTq|5ix6lV>`S24U?tQu*VJE;xkw3!Pn!H!IiVnKH;O zptYlc`a8F^ooylK&{+jTIJ#vyKd<%M_*7h}o1JG}`AVt879cLaE37kdC=VP0E(mUw zciwF4%G~&L>M|VeW?*&R>e#-wWzEjZ#hE@N<U6Y_&vC~i`LJ$&WX*>&8Lhh?snGsD z^dEYZ|9)XhHBI%Blsz*wXMAS*+(6?brsu*i3YW;XRwd;>FMTE*Hq?5z1f_;{r3$7G zt#4<yJ8OVET(OK3Jkw{hzCyi$F1EE}VEt?q&VQtL+zXtKR04es?`?dy?JMW*yQ5~! zVcn1t8r8037(;g=KBktZwEpw>il3EAcRjc9nVJ@#IW;#mcU~;I2@4x=Vecbn#|#}d z4zwZ79*o?GtXWf2(ap1vDuuA#$EN!SpY`6RXEXnl$5!8VGumMTAu+5i!vQNZ7zM4S zUNj~WaSu0+0k>)x@2$-@WOkeOI_nGN(C_oCq220g*~!HZ8yUlLn9c^<khHX1Yrs)> zG-G~Nx>YDvF9A17myFi@uB`IY$$0537rQG_TxZcBybsUM%1TJh%V-<R*`=Ykvnj)n zvwI$5AtFJSTes=maK**Tx#*ErzZ=QMbgOHtS8_|BJfi}boe4E=dKxHJ2HltrS86f4 zr_dWNcuvi;DGV#;a1cFz&msqU9}QbQ%DVrZoz~@dU_Kc2V!o}x*7j}~I5S%zYjm<| zZBr|;+4(d5=>;sWSWZBY|4k0Kn0)JwZo3T;w>1y?vtv<JyGB?%t#lUSEe9qm?Of^A z^1}wb^%bNu5F;5+=E8=RZeh2+(q-X+fiV<!pJ)For?%ycJz1ms-;$r6JCDtFEDp33 zC18&WYBK5=^y%MUhH(FRMzE;}o2FqK$l@mI(3)MuXN@mhPLrECjZtB^!83JKGP9&W zG+UEdt^b+Y-2WUuYi@e((ERDsS?uI92`8@mU0_3+)ykHPi=*^##4@gWA3iH9Ej^c7 z+&^2guQW!6!xVUAOgv8QMcT}DR4QXD+Rr=Z=*1Y(9G99lCp9OtbtYt%VI$JB$6_X) zH4~AdO<`R&7RL(1Dq$F%5nVuOG1no}?#c&uV7szXQHcNd`@gXU^d@#H8e3=5S~Cjo zJU|8HtOLIdh{N-3fFOK_72(XBtXwuSM~;ih%Ca{cjGLC5nUjala6%t$Gh_YVSS$ZO z&oh)6biHT~9%rw^kVEEGKAOLopUmg+i}^Bs9be7w;Xmh3@PG3c3%vzJxJgJ677D9{ zr-kQ*mxUT(r|_<@UpORuBm5|w6iy2r#4h3`;+0}=aiA!QZgHr1lQ>qKC{7h;h`Hi? zagn%8Tp_L&pBA4NUl9+8hs7A_W@)9|MY&aZN_km{a%4GPaD46f$r0*&-1(#0-!;rN z+I6cd)pe&U-*umBmFscW2G<VPZr487Ay=czbe(o}a$n}Y);+*2yWQ>)?osYL+}Z8| z_ab+RyWIVZdz*WQyUzWA`v><)cbImy=GMk)6SdV^m3Bt!rF--^Pm-s|^Pp#)=S5Go zXP0N6=VQ+|o}-=%y=mSo?~mRKjc}v8vB)Sg%8fO~_r}kpaE`PL9YXj%{EfVmpMkpC z%s22~^S|(a@@M!^p_>pPTq)cjID|xDqA*n`5mpFmg&o2kp<ehw_+98E_7}aZR&vBS z;(BqP_@j7Q<fKq(sx(uYBQ20hq*c=Q(ofRg(gpHG@@4W>^0ji5EXtqBK}s*>dPPzm zRLYbJ<qhSa@`n=c7~t?YZgvcI&U0O=57j5@EA(~xA-#j=8qZYEGoJT6k=}LQ{oYgF z5k|2=MgUnT#`k=%&|gRvQiUvGrBH{w9TFPRiWj2&yy9?ins}#ppSVOU79SQL71yB6 zc8I&g55yxPFB#HGN2n*tlj(WD^NZ(CPX}*TZ+GuC-oD-_??>L#-XJ5?c!%mL8uke2 zV;%Tg(2Fh-E){wTqTm(cgajc;m?`86bA?4hDf-k?!VBnAZwc=Sp9@EYKZP?w7cpGy zF7_04@n*46yhO^8HcC_EQaM^lRx*{vDE$k{Hl>4lk$RchQ|+S;RK049db2uKov2Pz zXQ_GWy=tMlO5Ln(Q{PZ`s~@Nb)i2fW)f4LP>OX2HS65ee*EO#GuE8#c%j+7Bo;Kb! z*)`pj?V97d*LA<^LDwU$Ctd4Yn_b&nZ=lb8;5z8~()GRTgzI<LKj?Q|-QC^Sxcj>Y zyB%(?d$@bFd%SzHdpi2x9QVEM``r(^A8|kFUgzG7UigN4H+tbg_m}SP-6!0?yZ>=_ z(z<HhwQIEg+F;G0d9~r%Xl=YUS(~nH)@ro9TD|tYmY}EUS$dA1rx)l8^kw=MeTQDF z*XeuoeR`9AN^j9QPp~J{BYSjDv?s<B=ZW{^c@}tlp2g_ZC7vyw9iCcGoo5gFb+f0% z!+C?fq24gB?A5)|-WYG3H{M&|^?4V2i@YV?Qg5}l)?4S@<K5@2M_=KLV6<WwMu2KW z8!<+l5pN_I1%}U9jPX!nlp57Wtx;#}G4>htMvFnl9Q)AZ!F(tm#)tC}peAvAJfFZP z^2wkmC44DHN;zM_@8b_(yd35m`6GN7#!3(Lib$a^`b07)%oHI_$UvVc7b=8GjGOhs z0pT!u<`KaZjtgPpAn`3ZPPt!sSP|Tc+vWDShqz<iBQf@GaVNQNbx(4qy3^g6?iy`? zXNYIG=Vi~U9@U%SeaQO+O8A!du=i(g2jfDczu_{58sm*Ll&REs%y_|g&G^vx!Z<_y zb_!(tKwbHsyq8bnC-JlRx%`8Cx=<uk30pCizZd=xR)|lEFNmF_D==oCl}<`m%4zbG zatr9$#fq-XQx++LBi=FB@v-9%M^|TzbF?$jne3eGoa(&8ndQuN&T%eq`kZT>gVAHN z)ExBK0(F79Rc%m%TsNcVZE@{)ee3$e73Gfcq<fBFoc-vX4N8QJ<-q<3<LVlII=`H! z(UfS{U5QW@sJVKfAy9MSVh@a^NU^UNB_@c;Vv0CLOcOK2Qn6gD5G%#CphNXy188z1 zMz|@4OFg8XQl!*ZijtD0DN>r0A!T6<=1B#hP8HHxX}z>bs*<)y)zS{BR{BEvT56HP z<OsQk+*6K}`+{B#l6hH{Rauv#<rq0mj+YbUL^)Ybk*A=hGUO~dN6wQA<OQ-%UMv^M zCGtA?dHGK{OzElgRiczZ3a`kDin@$eVw5-~UP(|AG5S-KDN34>p=2pJN}f`nEKq!) z2SrMWQVObA4$4retX0-4o0PrE`^qVWa|Am=9bt}eM}(t?qo*U;F~yPQ$iQrq<H&Oq zI2Jh8JE|O89Mz5;j#@{ZV~=B>quJ5o;GDtEP-mDk+!^8Q;f!-8u=Y!FPI0C=Gth!L z&Jt$`W}bW9tK3l-!^^ejwNJDY+NJsoeVhKK{=VJ|^l^_z^JaTjdq4KxgAs$a^Rey) zL$nk=n=j^H<3HkiV0O(EUKGN`Tg5_gmH0B+Awr6l?vNgrUXsG)8&F?c<zMAjl;4$u z>Lk}N_X77<?mpTZ+V5JX=Wfp<o)GV4UN2^?{svddlHj`VH}FB2xBCkNg~6b@4#5q| zJ5(5sd3>}mR;U%~#NWg-;^oq{(hZVJ8YbN&B}%tR>1gLUl23X-dRTf@S|=Ztw>mS_ zuT+Z`?sWa^`WdC&ubtLX^se4s-l5(U?^B={UwR$Ja4KIVY#M>?<psebj1uk;W($P^ zr$(TcuTWR3Ppi+XFRL}`PW4@Nzj{dhM*UGesh(ClxVpG5ab4-^?HcG3U2fM<*G;am zu8FRxt{JXe*L>F^*IL&mR~1G@HF$tpSDkAQ_<(v>q&vzz$jzf2RJZPqcE`Bm-0|)N zcOL4<=U(hC0xwYNE(1SM;jVP=ao4*KxEtJu-Hq-eZqt3--Q;d|pK|xr25Gz|YpSMe z(OQfar^RatTB7FDinJ1~R4dcUH4`n{Ti5lup8Gv3Jt`>TLMm?+Y~X;t61Ixz7!!3; zqZHYu_oub#=T&mGyhE;)>*PK1DVbA(l~5&230ESN9_aHa|LWCMO0}{>sa5KfJ&LLH zafps2$4cjF=l9N^oW<%%_l26ON9!?qoF1<y=!tr=o`TupK7FzNkY1)gr9Z20)?dYJ zaX>$;U*cKisqi#;{_s5M-Q;cbDxf4sjN?X=(QKR|`dtef9MBYw4+aH~<gW)$s4<T4 z7Jec>jW6JRd=bB&PXdju5?&QD#WL}z7%vr_MGbaJrzB1emP6$*IozfOasL|k74lkn zy}U`TlD7nEBmy-M*>2n?V~qcMgg>q9#JK)g`BM2-IidWj{G)Vqbj8@d+R@)}qhqLJ z6l!UbBi-?`<8{YpjwbL$$>1kHK&}1b?5+-0tJL9I2Yr-&mtLrs=uhff^?u-F@;wVZ zRb*&b51U7z;rvYg0pU)J$8zym@m+DcR4kQ)CmRELHB1?!40TR$u5ea3*EwHx?r}Ca zz3LeC4)7iKqJK|zz3%$RwHJNt3$0muLciV<jS=!WYW<kE$@>@hqb|m!Mo(jqAsf0e z&sc6$8at^kVc;YJ#fW!_3&n%d5cv-I5!6!$<sxMOs9>ezJ<KInIfr5v+3S4L^}egc zH5hZ>ZtWxOCoLF#AOkJGL0^wKyqmGYc#h)4imeQP@8uui*Yh=)eZS<J_|AeXi0FxX z<U{h$@)`LWWu!7wSph!$b>&^<Q{|Wv;<yTYrQsOsnC^H26!DbfW#{|Oubsa-!_`~W zJJo$>jiWFvLhGUR)FQRM7(oeIvX-Jv(bBXGElbPM?$z$s9@IwZOY}zX)dn^M;|$aU z<mnG-pu9|eUk-ugvZ8ENwj=eol(!k({z&;m`Aqpj`C9o-Ija1m{G$A({Hgq{1UW(+ zogEiBE_PhzxWX~aQ{c%lxX2)m4qFViIgcKgw{>tH$)K@Q_%uF)pTpnFS7Al7gRkZ5 zu&z16pW-<oSO^uugmB>+P|3mIN>do`ktO5^dEiTz37bGA_XzvI8y~=2`n_;M=wZ*H zgG64GMHSp>w3sF4i3Q>U(I+kztHf&X$+cpgxJPUjTfo%^gRc(*EsvApr36seWQ>?n zsSJIoLaLPNr3UFRD8>=Vlp@;9oGEQ)$hM>9uzW-|<>PXb+$^`9C8xBR57%Pmt5UWw z+HnAMqe*GTEZBm1u&blHBL+N4f+G>LU<ziwQb)O?!cpm1i#c$c;|<4dhl!c5b>8dk z9Ox7=_oW2pygcV3=Q40D)y`UH9eVygXT9?P`u}0)kIs`$9XxoP8m}g(iE6T%qE1oE z)C#pyU8}BFH(}&$QLEMCYO{JuZBaQ_uq)IR<_dSkxe{E7u4Gq=Yl^GDRpKghmAfij zm7w@9yJ}p=UCpjj=;@q07?i%1&gWpI=cn;ou+po=T5pegALx0Do6~}|P%RAfyp@_4 zfSND1>3OwQtJP_Hw0+>TIXzSl)5G-$y$2|%pN>w^OZ9TSLa)@<>g)AJ-PDhR>uv_$ z-Pbe7!-MNq!FOkPa=>#JFs^$OIPPkj=Wg<x3UJ)KR}FC7dENy9j=L?t-Qx9g+Y#Wl zEnYj(NH%i7Z4<9u25MblJP%&G(J%v4o5N{j7)o3xzAGOS;I&i0XIJo*{926nP3Y;z zG2WZe-&^>;f+|D{G3e>>;29?i1z4N5@{6>lZxa3y2BKf*iBEyHTm3cVEdFn-a=T)H zZ~DUVjpIhA<a9bUr{Nst9O1m#ImS5-RPi?F?apc7aqo1_a?W<nb>8i~&spevz*+2k z$hp$_C}{Ch=sz2ruRC`-4>~`0{_JdahGHFet=eC8tA;ubJts@OOI@NaQ=e3yQD0Se zsP*b6>QSuSMx%d}xkkA^@!X6xOP%+KSH`;JY2y%T1q3BJh&uq};qL*rzKY+;@8;j- zKftVYkUs>v_YMC&|05(CCwX2NCX5%R3v-0~g-3*S!Zu;Ia8MWke*P_t+|R_5;sw$m zX(YJbB~qx|Pj-T5y+>XJdikAvDfrSP<v!(ctiL~3!aya*fs-tDG&)W?`Z^uXi5MZb zs2jk=f9m?&^%Z#dA6&=4H~k7;{x6rNy{8?~`hbrZ3u=9@UWN6^0Z)VHu%{6`zUeuR zIl9^IJxj>YJt2r|1ZohPg+0<C@D~3aZ@pZ882NonenMU&KPzvLUywH{>5fdtOvhc0 ze8)V;J&uKrIhaN2!Atz&{LT5N^KWO68lrYaOI(aK^%bfH9_)74G}j%Fzsz#YcFlF& z4Jk~a>jBrxSku;ERl5`G+IO+CeL`EKJ*#cdUeI3Bwrbn8vHEy@BIFQL_37Y+v-Kh9 z(dkB}G1Iuq$j5wl4>+eK#!}3C4;$Q+AZ`oFHwSCNuh2(Zsd7YMWf&z~B+i1YWF;gK zkE3TkBR(f?6kmiC=~eMHakX?1>yOjYKT-#|liWq_DqkXZm#>tsk$Xd4GEy0(+=BMH zRhguuD(R3NJnA6cJ<nOd)?bUAMd0IW)E8VYxwg8tW9EL#^|ouTD-$dC>$Oz0(1ZFl zo*5peH`RNOcad?7`dLm8mjM(CX<4|iQ5cT(Qbd~-(;(>`={@N~>0{|r>2v8T>060c z#wl|_gNHa~IG@Bk`jc}EBv^6o+ubYN?|?@L$6CKe?}L8usCSF^6Yq_X)O=!az93qP zau@USuzIfH_hN-G7xT&p%pe=3;b`0K@`v&P`2uiGlM#QJk_0-w)iDV4y1;okxRG*j z*>^*hG0y#v`yKbE?yXubDA@I$5uRVEZ<PkoQj+U0+$%gITrEoCNURR;!aP<1`5cXb z8>QRjfsP@LosJ)zE7Z3@xAP%`yBxBO&)jKP1q{|T&lpdtXO8C~&l8@Fp4TC5I^_A) z6XfmYz1Djp)+CAEg(%U_-tNXagR2Z;dv5;W*9fB^Q`&{q$4aaqCHZOjP5BPxPGy!d z8|AngqpMJPK$(sC={iX5#(|4?OuH4bk0{SL&wNj%=b$Ind$;#PZ>jMHwMSJD+spD6 z{|E2I+`UuyRd7RowH0G|j&wKX%fZTM<yoaCR(_kX9zW>_a(?W*L>1I%^%AY0mIVI( zO?^KkX1eDdjKW3UV($rW7tmkCT^q#q%{<HxfIM>s&GhnjN?*q!%z3Aroz(l?@40vA zhcI$;yjPI_`XII+s2|@QtL+WqZPE+UHhH45S$W^l%ehp|gJfbO`D+Z~ih%k-HZnn& zC9DxH5N|~9-X)He#!C~W$&dz4mu5)WQZCkG^QC*GMbiD!GU-8Sh4hHDT6$7?T3RPP z4-TpdYY8uAd;=r8*72qD6Sbe~2De-5;knM^@vKFw?DXvRyzBYEvmf<#$nzy+oZown zK*F=#_}bu_f*8L$0CPhk_@5^sX}Lzs6z5@d{V7V)gIF1Vtj0jvdcF3h7OG#Z&(f>) z6Z#3yZ=Opa^}7;szuw;d-htl1UeW9Dx*<h6;r-1^lA{Qt2e{lwqpuNV3^Q&rQrl4h z+S*lxI=BGyS3iCLR;&WA@GjoN58>Yf)jrDq1gYw8kgNWUwQPv+1mr=l32zF!gm)k* z{80E<_*5XeupBbVRpMjf6X;XVqRv%FDBIWJ-%>E-sJ-Mq@^$j{@{O_tn*O`u!a5<` z8R>l0`IWOj`1h@<;9BT<!gZnB>7L;(c005Ou=3l0a`*O(^>X1ISleolY5fIBZ<9C- zT-0pGOOVt&3clk?kLD@%M1UXd!1hGl4Y}2Pv8OZ<a*Yv6He}p?E1Ywl^9l7XSG=}H z|4yIjc@I+A*Qr0?jt)|~SM!=sD$Rq>UYHM^s)iYHm^woJLVez~LffSkgTr5`KdL{D z_1!c2bNWX8Mg0|ho^ikNh`~j7VB<N4za9K&jnqT_O_>0SpM<%1t@CBfw0~lzy%Mn| zs3q#N>K^q=*C2Neq?D)KOSOx!ikz;`)+MZOmw5(yE4-W0misZs{_YJmt~3Ti3OLfZ z9W?tX<ABjXc~0oSl>>buU8UTpI6!HCRn92ESUK<xFZj%fkh08iEO$KSc+&B_<3+5; z-ouLQ2gh%Yj?Rmny_{nq3%kpC4|s!>&L_YTEOP(q9)R&aM7v#E0C|e3J*0nvp48fp z5-=uHj46=XWq>29G}apHjZH??*<29>EFHMM;EOH?Pt*zeiZ6t*;LhKIw4+gaK_0H$ z1Zpr=8LvzP)x1x6Q%QELMh>5LtV1q0W8JvTafS10=e5p$&H>IFoPtwvmLhlGI6H$! zsevqcKP1UNLXO-4Qsn-SACGorxP0JS%fYc$K{~O=bpX`;IJnkeceuMJBos0v6Y=h3 zcN%JY0b~+okVR~AzvO-$bLgj#M*IS)@P%49Xwg8;fc)WB$bx5U1*n4++H=|_?JaG$ z_PN%m{RX*9H*l&0^uhWtaI2Fr$IgXx_+kACtoyd=Z$av`U;k47QU4v(tgGirPk)aH zDQE&T9rHc+ff{T8zwtGs_FPT}M%RAA>=Obm_c{G-ND7vER(sY!X4(ku^-}Ox^Nj}~ z$;V6tp%V5-piaB;FJLD65TlZ`LW{sZ?#9~agwPe5osE!O?HBt?BcyjR?|mb=<q2}O ze2LOW83?NWEF>8BV<s`2^PN{>UGR}Ax`u%Bzuh&^Jyn~j<zbb$9Ob)FmvpDD=>|$T zLcdubqmR=k=(p*&>(lf*^gBU+W~0n^L(WmCKcJs`JiMyEroXB0(%;eF(?8Td)<1;= z<On3@7eOa-Bc$cGKr=EMa`Kg)$33rrKE4Z@_$%}nT|mnu$i|br)4g*c7k|wAy!SP% zroRA9``a60T#Zp+Kn_0H$ij##GoCeGG2VjQ81+-yfz54C%LnBz<&*Mh`D$gEvLEZ$ zUzHA6U%d$0yvOmm<Afu^`Jn3==mM5$BQWQidKb((FL{3QTmk*bAg|yZ<DCrN_Hpk) z)c!Y^GdqyTkQ)FF|6|a>0a&@~!VuwhAsZ6%jaZc~6DLY9OW#SCgWnkl%2p)z2EUUJ zsb~>WpXj&)GUzQ>*#)CVCu6)dIu%GM-dBGBKi$FA8CsBjF5UH^>u<=?BDD9lkM*vo zk5EwZGhVmBRdwJ>kp4|rPkhZsf&%XcC(4Vzi%&=&fj1s5C&`8K3VD~j2XYt%>&m^3 zWalJMo6nss&TMtL`ndY3`j;Bv5?mu)>Cmk_1#0;NMn*LBB{}XF*a$cdoyZkT6H<)6 z{-gf0{+B-4Gtcw3=Q8ij#$4k)ta*@$+74VDkO6trcD}#x8S>#3$3Sj<Ozb8N#d;+L z66u}N2a+rgh14lUo*~bY@0K5sSISSx8^JBTA@7qvlE1<#`lS2^<PKdRdAk}KHC{2n zll=(^Q5UtFnhZTqforj=6syqnkT}*t`}48uYiNI(U4LS3xZK^(JrH`I7|34gG1`uU zr|RUn&~pWP*C3DJF`$h}@y@_nugF{Gt%SU-+PmBPp7%3INx6CmDlm?!_%|SnIRu_J z4SKM9QKx@`%e@5h`5VMxVw`vzB=obvZ4^UB{|uz_uR*GCQ2bo{8T?-tshiYK8Yp=o zwY?RbLY_2FdI&Ow=cN~=w=wn_(Hs7P94<`0SiTy)VlZYq12Xsov{kA+T|VwS%~o7_ z>LRt2t+8H$maI<Qi<UYJ%J#GRH+n|6>oQj#SClISGhqQFsilyhu6J+2I(r`^s7D|< zZE=S}?$cYlPE$a&<FrxQZIJq8gK{mzSS~SEgF0`6US+TGfpHkT#?O#7a*dc9QT_v1 zjWzNA@EwJVh3-tN@*d<Y-wVftAh8p471xSRNLR*+6U3R&9v5Mbr&@Re{LyFPm#Bk3 z(c%%PgBzt-NUo<qZhbeT){iiW`8H`E`sNSPajXa~U^Sr19(f#e4_WeE=nW;{H=mPV zmv_ny@)wY+pOU*OmqNle7<z`0Sl^~8^D!^1QdWbj+N!*#)GOaZA{ON61nt4K4yQwh zRE*};T*tkRLdQdnGDuLKb-aXmW2fUC@RtpaBaWk(<xV@2J<}l{@IlAC5_EMPBm~<% z??4}S$n%va60~HfF>(sxiyRgJ!J+bJ|+WW;>u&JAkqOgYlbjn)-cH2QCqH7Rq15 zUj^B03HZPD=;^g6X9HwMP0+oBLfYCJyp1Bep=%i>--Z=ywme&2DBmxaVIBA!<cKxk zvfr2Y%Z*sYQmH?2ev7r=8E3E>jul@YHA;1W-x#TmhOB-%^ilKF2f!zA&~?VUCqjb$ zgnI*4MK$g>!SmK**81B06Ey4pxI1dy&<`RpdkGlBL$wj$*pngs%hd9<`RED7+M`;9 zwjS%l?a*1gt9{7kvg6t>n0dPBk$OK+`)I5gZ-Y#B4rH<qV>a5P?*#S!LjMM1>u>#1 zPY*V-MnK0o)pG~9^hKU>tT<kQ#N`8M?T>m+c!Is1p^xYbx@CZVPxR(^^TEfLLifE9 zdcWP!{C(~H!`tG$#JHU56uT`B<L@5FK}a%wa1=Q2hcxRTq{PP<9SFlJxR=^j6~QgV zsy9I<F$q%79Hv!%SbYQ%tqn{v@vizIc(ZTRCiOS9Bjj1#U01mVK&z}{ZW{xs)>N#Y z^P#^eaxI7bLZyo+MT933rE!B!jPi{2Oo4W9He^WmgLfo4aS)Q?qnK}6ASdny-lw;5 zouL?Rtf5C4w}JP`HfCe}Ota5pknnCYYK%9H_l^DFfxa_-g)AS13h&72=r5i43;8Sf zYhd3Y@CN3OvHS$SN&H6)lP-pqXFgUF4@pm89Z@B1m3B#cu#Wy*Ix3w&ZwivT{crTA zPRfN!IV9rSoUcK$@Bw6kUpq^n^Lbu<QGFd6AClsHtD4}P{!%-Gck1c7)^(#xhMZx9 zD+#)u4A)G^7<^c-u5_(o8qn>ocbK)uSFWF2CtZDY5&Cdik+0O(z{X*Vz8!sJA8Z}I z(tpxVLLVODp`Oy;bG;|cn~QblPVldvdcT7$$0^L;WY2Mp(Z>)B2jgWYVC>Dn*t-Wd z9;L=A;~CH^F0v!z9d+o*CSsN)D+Qmh1U3@okP~ebwhM1SBK(o?71l{7p#=_s)k_cY zYOw;;w?=wXdLO5j6aD=anvh!g1MmXh%D>3J%fU)#<#Oma27*)eC_|ykOj4#nYC8w3 z-KDVSs8H4@FG6a&Q+WrH??aH={-jX-{RFA%KhBPrl_JzgwI9~34s|Hj10*F&Q!~|k zb-sGPTC6?_Icp5-P1)#83(=e6F$OZcd5|}jc+0(Oy)S!T^}g+W*V_PYhV&5scsm*w z!@i}jF~D#_4{?(*#+YPGh0HPED1?sx5#w=VgRvRZh&Y_H=n>zM>H7WjXfQ8f#WozP zqFebp_$+=te;>a9lxI2kf+yu?<QJjmsg>Wx%zIG&M*e}(9;%Palq;3~n0=kl@y22G za4Y!n8IS>xeb0}OnEmbQfO%&HG!5T?&ivsH(Yip(aJ6<lbah^Bn05<nCWy++#cE-h z_K^03_B3pJwqljEM>_}_a}?Ux7A;7R@Lu8VhZU;Bt9eJj>LJ-X$(sqS?0oNiUM{*L zvxCZlhU+@$Vcn34u7=gYHmo%F3Lij&{<ZKkX6Fv#1>$9}Zld{FgVcYtI8ICzr$bUY zPqgOQ>t&Z5E8ikdlJA6O`(AKG4?}yi7P7Zjq4j$glA142`X>1|xg+#`-Ic4@jH4?< zpiN3trYd)UXPXb6Z8;>1m5>*_0$s>%<p8uGKPbnQ(^y$u<haBU>FDQ>9I9gvIJM8T zFSQ@FQ&^o|q+bO(IvAYu5Pdi_fw$_5Ju5s<d!F-b_0)KD?@j0nw|i$|O!&M@yerWk zh$?RPz5(9$BkxyO<DCR;41r#%2YB4;4c_o##eNI3kH`f7wZK?rJY+lpNo$p{)!2pk ziA(6nwSd%6ZHyF?U@w%x>Vkv(?Ha7I1=#`J@sF5gh$>v6T%+iYo3J9hoz0s*#}da% z=pNQNHafOL@37DDk>e}OnkS*(;$g`{^fpb+1+^`K3~L=U#<l7`Xp2K(b<-Q#UN2^( zTOd74bLYC}y0<}=zgPQIJB-@+Su4?3L*w}kr1dS}t-E=y_Vk9lUh%|v$9t!GcVGk@ zLWzGui8&(#dbl321-Ty9AYMq4Z^8OD&B#TGm!QPuDDg&=_zjf!BjX_SrALiFNLM<g zBZ=OjWADaa&G&|;RN;rg+GRX{8=ncS{sMj>{}80`PxH_5Td`W&!@mzpx<*Kze}x>Q z6Kr0t5Uvvjp|2UxkdKAUOFFdV1&~D-3y(npvq^XfQjR)s+Mf#F!Mg60@HgzT!o_RE zKB6Ex#2D201lVxQfK>Dz*wvLn`a#^$HgJi1VWV|e{F?EJ9i$7S%cLt|!*PS8K?gNj z8YiVfszm(a1F+**Ej<P4)XU%_-iEBQ0XApHq(31?rT*Lta%K@Sl34jB@J;`7pFV-r zPAGJgW#}I-8?PE~8}C9s@C9V0O~yYoALVr9jstb%FXp@ReIe;_LO*vCKL(aHQ~4Y| zpD%=N`4Rqcegkajz7u~HgQQN<CDP?mALLzzb;1Z}&n8N@!#*w-T;38$4a*_@+9++8 z-eA1mSKxw9N`FWpkpEJz+QK-oPaKD!&-%&n7i>9_8Asz&A5>SWYtW;%sN2<d(5JH8 z^RXU(#QiwqZFacda(~F^%@6JvNa&|PdOcfTsNWBL`eTeMslmFE*4RGpgOHG{@zRVk z*pQ4Nuzp~r^>t+D^@Q<P^1UF@5}`wnh5g$k^o&~JZGjU*#EW6sb{FJUTx~}#2K{I< zv<OMisoV`&$$Ce<<5$O0=Y!DmKjqx$ta9#fz6FW#e&?6q)<{>vK}vtI+Fk9fUKij_ z#;dnMdX)tWqI=Y(DC27NDRm?CZLeY6ybpOrqxuUt`b%AXT?%a7CSazWgZ0fS%(1UR zTJagyW4~ct)7^a)tSCl;*Six^isi6hdlB6JN1(pHx`VaLv_7zqhy~5P1CojR!PBh= zKld)^>~ZaHt*hQk=RtkOVwIi;P46S9t!jNQ=H_GPSa+`iFZ?QOV?Oiz==sYN=Dixy zL&KW@8T%|ysE55zdtZU{;S=xoph}^}6~;hA!|0p@-se8d)N9boc40>P&iLKn>N}E| zA!LX>(68LEU`>JM{$7l~O8zBifC|7>TiP>{7QGBxwX>`qAcyV9<gi`%OVDB?VC|L8 z-;cidEObW)`EMbA94K4{i`M(Z%cLZ5N~1Ba{VC7GTz$3U7RZxlIlghmLz{V(YZTVc zn)_zh|M}d@uv&TsYujJkv!G+_1bH0?jo~exDCiK@g9iES><)Op0dJzCY+O@EW|w&( z`pgJEmA{+mufm1Pg(%@hVF7GtRtu-atEIt`f-#(d)!yS+<8_d4#(Hih*0xWBYq%1t zlRWhPtDL<d@ym5S2^rr<uqTUh@!+yl@TAeMOxQI-Q;rL!A<~g^U^!J1u$y`wyhpuq z1hb7_XWRwzjg0k9H1x)COrkf{QG)eOtJZjvqXC+)BN%7LVQX<M?A+o5mQqWd4?DM@ z|N1q>CL{vEYN#59^+p8x??CilH@KObnAPS~bp|N@e5^^A{TG%(&+9!rSy)qT_Phc8 z*%8lGn9*~<>6`#nzs%?d4rUAN41&4EDCalO_@zP;yAYgjPw4d$r8{9&wS!4&zK3;1 zSLIq|0(g)4%1h9if2cg~7=dy3Dzw?FAtUXKm2jo&Iaj#*Zs@!^V3j)+b4^>zo9AF> z)5$X#Qk(`)l6Ri>1#p{l!ArhLv@bH4$xnKLm-t7x4pswX-LVGJ$WsC9fN-qhpOQb3 z2S5W-4f~5o$W8BYE^!`KyJ|OUA821-g#D#;(XY^>AQ>C3CqY{@TVI5AQYECnZ-5>h z#wa_jcLwi!oyX<5*)z#gi<$j%*kldGs$m?sT$<5f+rzCzmSSKVk;y*_TKgKmm(M}( zS_PT<Ay_B>CRAV^c?+{gC+SjHhW)Sh&OJWL>dfOW5|SV&H)$fE3<?@VaFR?WnVBSn z0vZ(MB5Sc)B|w0bKw=UgsVLbR7i_g+)fGf7-P%eows>j94|c(oDpu=Kv6i-KvC=NR ztfH$0yuf~c=gi6b&P;-^`_KNd1CulF`=0A_p8NBhnGcAoh0tbJ5=(rBT#^4kd)ZQQ zYV@t>qEeT|^-kFtv9HAL#q+rx9x@QG$b<2}Ad`ocN61>;iT!pq`KaqF&Vjm@R^Eu* z4Vj$Mi?C(t&^GTK{|G*U-FOJzlC@ivWqjDThS!J3;_FI~vo?ij_4S3f6}BPUMkC2? zApUi2WNYMw$l2(Nzb?5K&+-_uao&a!A0y9q5Sd`#j{hoNpV&>N_b}|rt$1k;mG=cQ zbrm00o(sJ#MZ0}j*`Cw0%=e7VMPC0ld=(k)yYa&;C%b80@o=K1)g|rGr=y=kzn%jY zEJ0TMHhw-@=j!r3<=&hu6Fa$$eB}$!f9}Lb^Vgz$yfTeY=T2;Z5cJs^xjpg|bfLa@ z$fuLDcn6l_ma^ZF2XVBl4>@mF#zw($7ox{}6TiwC<Sfh}4|q5p{$G`sR4m39cNlMc zdFATLyV2RsArIh(=wM!Bme;~wHio|(z6BmtPDJ}@<3BlsO){9-JY4h~v80E{FF9Pi zh<vM`M9w4r`9<`}H%hi3W9}>+3hmX9jd3G9;lcQ$WKZmg55|WxmyDf#iDK~Vx$;6H zZnf-LEBoZNvtH!YU&!0N2>o|<AoFDnIWO7xV<sb~o6#&DGdV4P!#D9hme9u;Sz*T; z$8Jo^5nYQnV_oFF$i^;m$ado0+eJKd576El$doxmR&IK>T_`Qr?0=eL>N0J%n=HK- z;h(RR>?wJzWG{Sle}Iz)vrucx9wHMxn^^jt<e0w_I|W~24S9-Bkcrqp=J(9<N6H_q zI8rg2sA&N@l{t5?Hp}FO^}?dxjn{Bg;bgSNd`?>Yh<NZEw7F-=Av#$6Ze&17ArbFa znZe<b(&)?4tk_wx@p#!+5!-$>c6VYAewQoD+w|pn8!Zk!T{Ho$uutS(JVXP*kv~P> zjrJuzQ;EO$>Oj70YRvp#>0shW9cA0f=EiP`hZ12<R7}S^|IPBB;=B0>Zgg42Rd~O) z!Ji)^SA6&Qcf}7kXL)-lhH>7c9NlPAAWQsOa<#rsp4JP*)*^*5GF0ZlnI6Ux`;b!; z1MvxtEt*_(E8KG%7Q^qOpF|6gH`M`&Glx8-#YFd?K<fOu^fcqUnMoFsw4o<V<mQj~ zHYY)IU&HhNLp*T@iF4#t4#jhHcICO1V~APHO1!S}Hnfnt@&DhCj<*SpzPs|R%6GAu z`=X7Ui#@akt>Rlm?w%()vJXF<w>`_`jAw`QI2p2veD_Gv1kO=3;jO(FEqgn@mA@BX zj`naDzPK0Bm#@OZxQXb~uS?!3sfupKL$asrU|C6LCe(biwE9?MtOZ~6O1vT+#xJr0 z%}jZ$9}+JbmKcj2JPp6vR`Qu%PsE6kw3Oe1?)5N~`zCuZm}tkn*nj|hmxX%?{PZ8N zHXb0`=U<7GKg%hem#{Q`Q}_lk^J-(sH5T1iw7cjJMQ<aah7^xR<EVzJ7jrUYO>!+~ z5NUWAAAeu8>gD)sz8*U#J|_O-_|M|Miyw}kgO)f2IXQ#K`jv?<Bx(}1Sm{d=*WnLb ziEsFRB2~X2`uPc2sd@Ozqj)PGz?ZkP;`NI6Dsr&a&#b%<D}4bTyqhY&jtBjN${gTc zIQ|lJz=rXw(EuOA%6J`X%-fsg&1ZSN@r)Lu{ar<-{`J8BrtoUAt8WkA2`-&Z4s?{P zr^R@3?&bu}XNpcP%_Fm|8vR6msy~v|=#`yXHneOs{*-@$*MF;Q1aZBw@rm)5*>&%L zrM(x3NcSt8L6rO+Y_zTT296Yt#7q5VB#XS$)#OB#5ZSs8Ps}zv={Lo;#ZHdj60fY7 zj2HNN_Mw`Xz*j5FY`oXwJ2Bv;+mX086ffXp%YQ~biG+wmRFU8Q_Y!3{o`F6$iu|In z(Ly3CF;4kRh)#}9A;WbB_QI89xz-TBPR;4LIeH6L#2wMQiMrk&{U(0t?{cc@5wb$I zk=wq`_${9;dx3aNl)SsolhyOjWK{n=_8PH`d`?kKB`UK#esBCS;xhY)O6KC%oxu5& znP&Ie5;w4aH<J^6N8*XZ9}~UH&n-WnGe?&bhm=OLmR)_Hy!QzeS5_=xS2y7CexBIc z!HWKPU@GyuG>{Ln-sHG=;|HSGSL1PNK}Y`%+3`PDysJNF4%yE^*ojlai`mWZ5GnXC zPAd&898p+UIKHSBkIP*}|Hi4QQ;WwG&nSMt_;-I#W@&lgq>8fVT%@=jEu)2V9xFRf zugJIcC^kI<g?bsfm0!IWOKmRF^lQcreV)v*KV!3>iG}_-@a7?Wf4?jo4pm=AR`3S$ zBc3+4_MeLmk}G!&GJg%e)W_k&Zy@nbCYv*Y^?U_6yv>oDky+m-`t(brQVk~-X2Oq~ zV&5je@y*yUtgWZwv!Rc#kZbs-@*a3EKMy^;P|>U$oiN{#La`i7J`nB$&i$h3CC-}c zk9?)%dw7I~pqF1w{@Ed-{42<0dH|~2L2k-lh-5v4HuMx3Kp&G4GCo!jzc~IRcHDW1 z1hlyT8}5$8w-SBJXOQ2xkDRlk6~C{{M{~Xo3+sM#3<j<0<!z$47VCTiK8dZ^um29G z=m#f02fUwPybw*~B;CfzzD;Nx&yaERM$ubDXO3`!;dG)i5u!8Gh|YY`*zFt0dHqT8 zR-!Yn5}kRM^KE@i)S`lToxBXqXiK{ye<C{9gILVFu_|+d@6GrJ@w~)xVh1zI>)>ub zE`OB>cW%WjWaG~?&*{Ak4>%9Kb^~_XrNq;|i{I{O;RnToBA=9ufPSLrST_>G*aYW{ zlass(f8nD<B9@n5NwoV2vEOW>zo%9XL>io5If2tr)9{#$82=?QvtJ(n9zLI5#y&fb zDCk*mfR@5Wtg%}B59g4nw4UhD0C>RG=u6QzqB*5wkU`%m`%G+1EW!E3HglF|AO6f~ z@jHp2Jj+?IkK+~ONVk$V_eA0({QM*F@PA?a1LJ?B^)y<z_r<4L7e0-Q&4rwl`$l1J zB;Rj}F2TS2HeQ-W?3W8l7T`hdK<iM(b`5!bw?@AaeJmMi?om3B+{~*>SEA$fAqH_< z>_Dt9vCA3p-Q=bpiT5XVHz(1Q*nkAtX1r$~CC)5AuRKQX-VNjuWRW>gTX7E*{82?1 z-`PEt&y&4A*5rUZt4KpT-?_tdi#R29DYCmg{CId*_#|Za0=(rvFYJI$Hx@l!)QfmS zh%BZrbEYIGGKd|2E%G)RSsvM5tMGmQj=5ieM*2+Y7-B8|g4bdw_UZ<p_Hpb&ynNp# z*4R5SByj<=y$(<BhQ#BEpW*v_2hZo}!~`aC?qLZ&ntRGOlOy&z*-1GSLpcw3O+^EA z^hCv5>~CJ>M9y^HT=_`lbCvrmhroH_c)UN4WwZ@n75lrE^Ukd0%<wq;*V&xkY$&{? z@Li&j<wPIX;aS^J^oyde6I=dkaZTi__^@L{1s^Q+HrjTFu>i(%dg?S}<q~x6tjI+~ z8e?Rc{JG>kGXHu*siRnBoXnU@;K|<RUfxq#is|XJ+%UM$$Z!D^uDtYIa?<lT6IW0e zHW|A*;WZmC;UY5ATajUFh{Eq-to=m?j1`$%tn*qSd}ZO{GLvgQ-JIH51W#&(?v!!9 z4$9kv|6&W8$WD`Yz88J*fH|*`%UO+lPHh!%VylePS~{^YoA}`(EWcJxXRSdxtwZD9 zM6THuJo!6K{`vnkty*WhLeY`Yg6R3=A4Twy`+f_T@jfT*<X3yNBf18fS)1n5*qnAA zY*+LZ{2Z?ZJRR@DansL;4I`6mWNAU^`K95~NNHJVd1+M_`l&rTma0pyExoIBUFm(L z8_Cn!RQdzF508^!?|V*Mj{V-!eWm+L|5kbcKj0y}DPEcHPs!&TY>0?uLD~6b;j%Jv z8>`XJXQTZtB5v7Q)?T)TX#YC0@i*Za+=6FtClR?l_y+eAy*xxdelDJl{8)&Xe;993 zmC4JWO-}wIw9r<gfvz#x`S+Q#SdXWj#Cj#R2Q6Z6Y#+ITe}mKbS^K&1zT`oj7SAUa zDij~t&55m9<VRf{pMy_-QM{hakd{DxfA9>~gYhk7AnYaIE;o7Nq=0ykGX1N~$rGJB zsVAFgCE5PBlG%A*;z2T~Hp4TvB%U&P|1Tz9f!poFtMWeap{&mA|6#;XMxxI|$j+Wb zHry=uiq7D+kYUwPzJ|#3TKvH4lBWWGK>ShX0(2JF;~Z{(ye}b6MTa>VPzCpyUNM{4 zZt#RahdGzKw&E^g*BdJ~ao%VPCv<mK?80xfmkd&!8t{^*bo*E4SB5xGt<wWlNTccK z!*ht|HJUTKYw&cfCAVZ9KIo0a_BN4YvY9NC?VR7;MTBoJJnn!w#hXja(`8}W^G1{K ze#}BQnokZ>3p$Zb7~F+d;Xz`_j}z_N-g&C`6*%K-#Fh62&KwZ^KxyTB+9>Q<G4Zd{ z@V+`8c7F2P1k$ZLoyA#%x4)J6NIO}tYXWD2HzrRjY(|1?={%*gi=6Pi;r-omMV(@p z1!ufEd1|=coZM-}pVeO20hhehoFm>yG;ed^7EbMQ=8=;;n)v^}1c6t2Uo*i%BFocv zr-nVRUEgn7P04p(>o{6_e@e~;wo?S^_fQIx@&VKC5Au5OW!ZeMMEgmU(<ysWE~3n$ zY^Ur+xsEcMax-NP<xa|6%Dt4mDGyPeOxd5*w?32wlzl0yC{LlBO?jBIk@7>zHIyGw zZlwH#atq}VN>Z)b^@Di(DVc8P{55ynDeWve<-QWL^en%N`@OS(kATF>hns3MuWs&7 z@8<rTZtgdBbHBZt`)j+ozp<P9o4dKcy_@^Hy1Bo%oBId4x$glxz0%><znlA^ZtjP> zxnI@I{psD@pVP&C?Qdf@_uIMu;H+%nQRnN{&t-d?lIzvY$W_^1b>MpCHQC+|0@np| zv%NnAuKO;?_9B7)supE?zYSauTb%8E7`V<~n(dtwxE|J+ZO$FL3GL%r-?iahyPC4S zF9qsPU6$>AFEIY0)@<)aSDCW4E!%r9P``d<w%0dMzjal%_fp__^_R2F85q~aX0COP z$Gzs?l<ob{T~MCZk*)8??|c<-?eI%CbNQ8)3H-vyWxOZyOCXnVuYh-mcNOm*UUG8+ zbKrL1)$V!x_uAWS!CyY|Za2R>V18`iD9`yV0aNgokNPftZl=9f=sO@^<Yn*YtXkb} zE|WKMRv&8Z`{GpdPc?E5Q9;#tZP$%esxZ~Qbp5Fno(uG#22%q)R1vP*VJhq}ukCy( z@Kh=sT#+0?&#BP5qR}%I%yTNN=KGLytEWyi&v!g`u(h$(YwzgTVV_TJU6Hdow{1;z z^7)R{t5-FyesX>1^NUs-Ty_0NPp<2H-r9O_+mq|p(cYWHt9r%l*MIcUlk1TZX55a} zgIl+4+hDG<^t`og+t#h?*MEcOOmIiX!S!1YZ=eG;(DUl`Tx~GVJvHb!ynX}q>f1 z_3NLs&rOStL)1t<*Nv)a{chi|{&u?Sd>yjmcV72%&69Tyo9T5v_WG&yGa$h~9_V+p zeS6QN?VtqjRoh83-s^e8nQXu0JBMq%dmige-5k9SQIB^Ia%6fQp#;l%9^FoPpt|SL zqaWuSJ$j@c<#5XJL%{eNZz=y8i0Op*+|0i^Zy|Sd74k-L9pYI-;CgUct9f3NS4-^{ z{)W5-w68ax)OJu>-3EMYwWjyfdIR{aqLySoOX$V+IG<0od~Ra=CceWvwayCe)g?#u zYmI@1mvJ{ln+5z`LJvz!`!=ptz&qUhYQ0uwqxH|{-cnYbUb{Ikr}L64IoI?Z9NUME zoAp@6TM863qV6?wy^K%u_#EQOU+Fl0d&#Y0nm3nU4XdS=W<QUa)f-3(3N6gMF4=y8 zS&i;3O7>S{Rv9v@Q14ok#u~_+>$%ddy1jIJtzMRywGW2#E%lb0@#=s@>I}7`g8mYo zx9|%iGwC;VJr+kY`yJ73-8wTLyFY^bJTrnI<<{<IozHJXskR`Zn)9jC%4f~p-{ZNR zYiZ^;tfm<pYclh#<B4$D&CbHK0ch5mmD;CTPZRywdv<>uM${+AAC<(u^!p+DX`rPb zoH>e~E@M9GMLVi7n)zLpS$v**+-o`;2_=kZU>6$AibO+N|5Ex9hHKaCK4^sw4~2h% zmxW-nH<DitJJ-}xDTt=dI+TJ1#~N>Vaz<{SPIM+`pU_MMb3tw)?<VGLadjD2rx^TL z$|uXE#HZ>FgckBEI8$gB#Op>{TMne%7IgfcGN~Z5wz!3;E{|`KNbe~V3w+2A?xMbh zz1u0DW8`_0>DzKVpAR~$(;kmAI~Zs7x*Ez(SZWvE3XdJdhC27!$4sB<Pv_U?#63mV zjkKvVp9JA_yzn8I2SkMxqNwAkKN#JrmN9AqQXv)R{J#5T%tyE>-rYzKZTyB_s;rvF zK8VlR8T-7j&ij&CgXJ!&p}E>wkK~u}mU@eMiv#FMqj}b1xO1xX((Vc8mI7nPMGBIz zAMFh@JvAHJ7Df8pW1gY)MyR`i`865J406!CH2Kub+O%_8X{NMj_RdJITaXe&GV#pk zX?iNYCs`rL49uW_;I3(1f>l4bQ3L-Z{RA)3g<r3kU)P%wzzxYtaU35mZdN{)Sy`bS z3ic$*w46xu%<N@A#%%p@ofOD3a2M~iI);_Kl1bvRHSDu?(QhY=P2~apGuNl;JIOLK zh5CHW#?haJtoC39<477UXC-!2i(}eJVa{+Pd+WHeoZ8~!EN_z8A?X@UTBvVPVjc4r zgtRB~q3a+Y__Ub_>#Up~d;;ypq|ub{bRIaZ9hLT{U25i&g|=jj<u97C)-4QjI}wD8 zXjNQ7dQJl~3vwb+t@_vMMSr3Z2cuvg4(}b5q_+v)nwco~QXn~naw1qJjZU+>(9CZM zzjJvkUU5a*%(a>jRJjxhzla{Rvv!@jSDhU9th7Fb<BOB?ksRqB8ltNP=BM2q&KTND zL8TtpY4w6ax-?1EZ$#6U)8!|n{PDNQGdy@HyDD0Ac%H67`6CQUtKZBTeeUM#p?R!i z87ml@<Oa5Xx3f-Pvl_KVABtsdtqkq9*0<2`2jRW=NmCN*#OJi14(mo3*{PX}vIH$b z+NU1jtK_A{A**u>I<|%WF2w$qybj*6uyBxHXxd9l9ulbOM*DP_osrQ>P!oreK5MnJ z)LHv-FE_cPR;o&(SMfWi!UyS%Qvy3C{n5A8=F+b?YAr1U4@p2v8KPW4!15;bqvw`q z+g-BK=3H~XtFemGa9uqwH{)4LN+bK@Y391)DAGwg&BDS^8b(kDw(^wU3r`!z=W^=L z^)rso!kx?!v@Xj(q#bACf#iYkOLIRnLlTHzr|Z*#+Cqb2;$71A>|DdinTl?lWoN0n zj(JLATG$JhYv@7q*Ax8}EjZaA+?M3D{B^E*suqp>7O&IsgM2e}&;5N+uNKENhUKXC zo}ljY)RW+Amw4I9*-K8<ds+OB@RfXO_ImP3kmc8a;B$J`NZoU&Egf3@=WsQJ^@w5x z8$F##Dd@D(ZUP*@YCr0A0`2OJ)fvQ8tCL9L2{YZU4uxi9!=+liR-RkCw3fPpmZKkw zwfW3WIBhw;<|X)QzBNV$Ok@@_kqwult4+c>n2H@RiTXkO)9y$@NIRQiT4`2x)U#+W zc_7Rc6^i3%<yJ>@vsqxCNn@MDzsZy#yoMu*WQ;=kkLH(;-Tlebbp4E_mc;~Nq&S|B zVLnIG&PZpLWEIztl`rWQ>_40$<t4R!{8wH1Im8kD`B@I1&iBO?EKLiCgCm^PrKV+P zFDO_`-L0~_Rh@)P{;a3J7xDMA{5?B~i<vtonJ5V_h&%W=&D&{DlF*`-T7FCQQvL>Q zi)JuyGHbScP`EBgWY+4%p4<60gWo|bs2ROp{Lp$qgp1am6sB03w%98uTHY4izf3J! z`@Vu5RDG>Vqt=6GOPHnZYPI6vRz~o>A%W3_`Fft|?eJxFA#kmuhFxi}cRQ9aTGX+G zF@;kha7wt}mDK32^_Y|~?21mj_sn*uq{uyCx|JfMSoI)7l~$sQi%N?Y`~(fb-AUDc zP`Nmf+KRtqKEKRBTdVH6eX2hsy?vkL9MkV-`U<4sh?X>$dCbJhcX=o>EfDR5KWB%D z!es5%iFqwf15&B>jbw_vLgLS<^O(jQTiAOCX_XGc95woUP(BV{j%4DHg^A{@KIV5J zUws%jt}na^N@*({#evAX%vg!$*J$P(Tu13~)|1u{f`>_p2{W1*+j5SO(c1+bD{aJS z?K-Ru7W6DM<MEurJbZo4anP>dIK<S|j#`b>@<>se_?he=Yol2YyYNLjo@w_6wMWYV z`xz=!PeEBHe6zCUSbnfG;ej<!j&u`YY32&FgYvS-Ue~^gcWO`d&cQ=1JdlklD(e-H zJblc1okaI}VUCf}OAY19bDXJhbfuT@bIa%uP7fK7)cGXGq?ZVG+J&HPkkwgRdWo-# zq-rVYI*hNWWWoIx!$TU;gl5tAT*}D?Q?yF$jUe31)UdvVEU023Sk=gy^l1{c)J9aG z*+`?T<<nIDE};EMrY^sb$h>9mwD4>awd8&3X`m-9Y?4`HHsi>aRl6~aI+3!8wU42V zG%MZhjf_t9VU0#7D=@GU{~V2lc?Bzxlo76^bAE9`*>KulX$RuAf~@9mugcTpbE-~m zy#iWW4I^ky*0K=p$i|fx<DwBxR;u?9wPm~b-fB@vs`foRgVL<rwVc&TGE1?trL{N0 zRvSGKt{#7TXLF{uA96xIX*Y)xYvo2hG5@z4%ik&2Po}i+<7y7tA#8N(D;{L<NPNiE zk`_{c?J<t`X!5=7r=H1rr+e};U&UKJNJfYgI~~UIB2kUyZL0GH<el(ScP+QFJ0{*C zt|m`{Rv|8?d$nE>lqVWj)XB<rC-H?%@<2)Z7AF-~71z%6fQn~HQ*L1$((Kj3VTi0E zlKY`8t7}=FJSn5!{!n4&Sh9~S&c?|Um;{%R<Q6w?1~#W~o!&~iihCyQOi<8u5YBz* zwU)M`M6GHu^VUDnyr8Rl{n>-haxLpZ+H*D3aWS^sRJi$NSWVNBnfVzM^J(5^K}V2J z^-pI)G}W^$52@2ra+pz&{)e!Cg1`1PC_98%;)Sv<B=;qI#Y43pZ9r}!96>uKE}&Vt zb$?m}FLh>;P?BfjFhQwl@B4lrVcxhTrU^Twd1!_fr^P*j94)n7y4GTSOzEQy?h@}a z<HVyFH!o>*Xa=GJjejgX|Kuds7u8FH)9Oa!tC~XFpk`wEgs4j}7B%^rmy7%5flXG5 zS{PaSOy%<OYl_k|*P&h3*Xp(7{)mp-yK%a1CoAgM?P5@B8|#u5Cf!DQhmGh6hx~}R zZ{f;+A}EHCd=sG$>zlGXK-giQ2`bWL1i=gG*V<#Y$8efV4H<c@8BAt{YGExNL0g#Q zM}!<7wYV>t<i|xs@itaB8d|-;SfbVs>tN)tP_uCJ72L&9HEY>4q7u7PbIqPen#$)P zo~boB?TaCf`5F<32Ku<Kl?gIIEYiqYiS|k(*k{rw3XZ#v1*}LO8DXqlhoWS*=U|Wd z$K9iofydv%$;jhhxf>%>&i-$8i{o$a&mpMWoC3!WW;{5~Dv8(^K5zlgg@eu>u)5r- zV7iq+zIRFZB3*1g5@rfzaOWL1JI!Gb95X#Kn3=&Nzl%SPc)aWf>y;K~69o%{^Ni=v zdg+AWZS-yRPSvq|T;5DKi{3`IHX|K%PugaE7uHz1<t-euRwH@5rUw_Bu~NcPkvNLD z%K+viin87vQM_~wjp)PD!YN1*4M{#=v0U+@Oh_IJ|1-Tu!-3$jT8IlBYaQb1$7-KG z<NQylZ!ttLaBDn0V~svVtDdBAx=$=qJN4s~zKjxImnINK;|b!9)+?>Rw<|@LmSfEa zU&Jw8W>X`a*2*i*!}`QC>zs;gk)Orxa5_w+lL$v-b!ptOT!+92@&C`DZ&}UH(v$GT z$rjDM3H+31X|44EP-8kQG<WAKSKCp@7HetC@^*esNn9tfY<xj@FF9_X*!7R1_i^6I z=AP~k0CHVLSVD~9ID&kIl6sPsf?-ewrE&o)8%0Ob`DCNn9dH`GqO{gmkZzyZ7@t-u ze`(Nevr@{JR;hEy<c{J>g12Z>v-R~EtB0n_;Y{32Z=Z>qXBj&=IEHwtZ^t@q!)b|{ zMW*hV)ydO(1v2?Yr@`7{s<W3xr<UW0YBZv?kRwn)%!_i*dZ6Uz6;6q|n!&)-{j*r7 zU6Pg{EzbI?ZQsKJJFot%cHv9obodC`8m|p5eFbF@F6r8WG%dgWh>ZIFvtwzu!JIwi zEZA%t`I)2*`L;wVbtpgDzItK}32r@sOD&Yu(|Ea>C`Ah@<@IW#yx7P)Th^QBiaqx< z7NI;p(+re*8XwAXu4UiMbHm{Ovg0f>Yi`2|wBw25wNgdFG?KDA7xCGSE-v9_kd>T) z{6d<G?1yaXX%^N7>Ybd6_IioY{+bxq&Z{ALotvDWUqkk&X6oN@lh)eA!8HTngS=bP z-+F?h;yt=v#2vv-JFWVnNO_<v=NII%ldYwZv@svsM>Fkp-8<QrY<PDsH`%Z7)z->R zj$p5HljFz-Z11=k>-<Y7lx4E*b=si^Ir<SEUO|g%`8ydpyBrCm{QPSvFQeaSrtwd+ z-cg#f>!`CFpZt_Xnf`Q~IbR@Ipw)|loc<y?E?&iV?3p@YzE59NsdBRUZv9F;-93z? zu$)o(QqD)9Aup!2U7hG;Ch(MulJB8jkC7t<w0Gla2j!X8JbX-7J<Y^gr<YSl(MS0} zC80E~l|oI_3!~-u{ary_-#$@4VI+nB_Pi0)?qPbjoW;^xa0Q<CGAAf{7$4?B_PXAT z+Q>RJOY6n-y0|BMXCiiK$SVY5F|QN}TEy64&NqjS2^Y!k=>~325{m0;t*N8>BiMe! zDI-`aR1aSSav|nl!@s4hU$4<--BW>&UDGU9BVAO~BkEnuKDd{yJ1x0hVThpM_Dolj z74{W{GwWByq%$bjR~$PC&93%QEhA>%Qro5Pp1*I}Lk|t`8pg6XpczOuYSvwiA<ad& zBHcj}TpEkKQ1U^ya3_w<Z~^`&{Tm0&EVfy@Ubr@nm8iX5lgwW$7aSBcrlk~*xVNax TLR9u|P-j!q-dX!p!My$(h-D<= diff --git a/distribution/windows/setup/inno/ISPP.dll b/distribution/windows/setup/inno/ISPP.dll deleted file mode 100644 index 87551fb89789e01abe1be014cdbfbab4a6b4259c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 187904 zcmdSC4R}<=^*?_1CCMf%>;mB(B<iAsfF@v-kfbDp4dH!BNC<&|D8zsWG`S0?glycT z=H_-awYBZH+Ha+3t4M7WD-o@3vXFrI0s%=NAPA_lT&e+5SRk_h&zXBSyi|qX^ZcLR z^Zd~4nb$LC&di)SGjnF{^n8b)7X-m5ScG6u5bEHjf2qPi)$vomIziZG6?zPPJMxp; z>vYpTxxJ=lcG1$3m{r9qA1Pk+Sj=P25;5kXB{9X$6*0~gi<cC~%vri(%;@e>wg-L+ z?f=a<hg}e+=^}&y3nq*Rm3vHhW<xifet;l?Glgns>QiuA;jSTWxpdqOr%}rkf<la; zD^M?hL0$ilneyWw2VT7}lRUM0p??o@AYTl@8~*Ll3-e=d2>buRn?7?QYAy(Q#ag|n zu3eQ-3y2Yf2PdY@P9vW=5<gV;D8RLV*ZfNr1n-3GY#!n_0lcKe6VI;y=e=j?;zi;j zL9H|D&Y5vTx>Vr1XNj7Q^9Z~W2-S1f<3l>fJ;h6wuY6cgc?4bw)QZ3Tp>!q1NT%^v z<MjvsosN=p{iC*|e_z}roto<Z$zP+@rHcyB7K@jzcq9+*pQ;4Khq}n-B$uuZfA8bZ zi@&$=7Z~f(MJKv+4*W&Tp83$SB@c^>ktZVLxmrMY_TweulE(z00`Zop$&*)zONt8@ zJ-md<?;^shQj?*jHb6ps?4D>d2K-;m5Cqj_Ko3z}-QoK9<2QluJ^by!Ul$_a3E|p{ zaO$J<&yy-l>*>-RL692o-@g=ZMz9%asLtX-m(GR1P@QYw4%NBm?5=7oR%<VNgTsFN z=2JR?H5&Yt2CFn!p+T1h*J*IA21O07(%^Cp7HRNR4KCK;%Nl%8gYz|*r@`48bZBsz z1~WA{QG=-(OxEC74c@20moyl!!I2squE9DDzOBJp4casqqrsgT+^#{d1_x`fzXqc< zXyq{5z5V_7NEXdzbA!R)`H8lXIx)<$b-pcL_PMuDoaZB+o3%V94H`8lXt1+ZZJU4w zJ2cqNA<F1@@7OC(>D)<zb8gYZa6womu)m@>X`;>KUS~52&WJHy$!Jp?GD74&hmlya zl6xaL$9UyEhGu!1&E%QA*C@@l8D;wGCPfjHdZ)Sri=BsM1JD_f$tVkwfuLlx$wr%d zyLp~Z5~Nfk>XM!7-X4(8%B`$WE#HXpje^rS#;c5z!#TbQCOLzbAWbj>DUcA(Xd9=< zDCHS}lqYoX(j-HzZf^d9d0<ySb{M5-n{4GY!Z8g*a3W>1O`2kq`w$x>>qY`|^Eo|p zawy+Hxn1s*!=(sW585XfrF5elfqGEM{p2i@{E>XGVLHf3+Ue{sN3a@Dj|8bEqy{kS z(v3=AL%K0(kJEzaUue-3&N&g0^nmjXd7s?KE?o%*E4)-;$uKv+U?B*{_|48GI@+nS z9Ux<(%`8WO9jT_IotCG5iT)wC%0D+OG|LwaPZ*Pq7Ow^!w}Vc(hc3-Tux~7w74BYZ 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 diff --git a/distribution/windows/setup/inno/Setup.e32 b/distribution/windows/setup/inno/Setup.e32 deleted file mode 100644 index 09cc13598ecf4f407bbc5e87d835190861908641..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 707072 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�vY~wZh&~(KdL(ww<Igc4#-1 z^2<z*Xk%yWqnP>GSG=h>F^V6D6HfVkK8&$ulyx3KOMvHqw}Fp<uYg0qF+kfH)<<1; z9{ZJipJNO%7t>s0)--l8wKQf!2y@Ia!;W1@5{JE>eU2wTMEnsb5yu4kbY>g0VAj<t z!k*1|mL#5sBup;9`4Sc!xdXj$mn3)+_Q&%Qa}_aNO$_s-EwTOwdk~{#{8YodbcAF* zK|6qNfZu>9aDJdUa1LOYhp3Qi*;S|PG$lJA4r+w3PE&lQ5yCl*Sg#NdAG-`{ZM<ps za|$meo1t6+Msw{ac%-@Zm2TK}FGiyza0?`1TzmNo%Kp~vaBZlhcM@E?MPkk(rpq;~ zws`aw_CMu@YrFX|jjzg;)*ESDF+elm93Tnk2Mhzo0#kumz#`xgAf!$ATq-^B^VmnO zF4d?df-;&^qvnYfRa3jOaAPs3*poc&QMj=fE|gRUDtEDR%M~qH42u3Dg-3t>sck)> zJwxGOv;7v#)$D#3ttprp3|NIG0-7*>C+>o4X*1xr7;h)T?+A$*M@%ojWm`{v_Bm@6 zzti|RF28%C$Zmt+F5pSvEnpL{8#n}%0Ode!=vo3Heq*QpD%R!&UK`CITYIfEgRBEm zS;;EiKT*Q>;!8tTa!_Fm^*(%9$rs8uK3DEy<^E8p#7b7FtWhDM8W8HI6;Aj)7Jlm* zxL7L;d(Z-HBhQ5<tOnM84j(t&Mh%Q5=wxbOuEfkIrnd&P#J>i|koc|q9JdBm(T$Wr z5XWyT;5^_`;0j<UFb0?c+yUGTgleGpQn7^I#1e8PUZdpU4p-te>K;&7Y$`?$ZsEMd zp6+qW6)jk77YhDb<t|q4!9vqn)Av&N5Wj`CtHKGtH!<$l{QgL*8hZhQT%qwp6UOg8 zJK)-oEcjiDu$~OR{SvboF}?h5sU*JDyNci4`8h7XyU=A%gkTPEKkx$Z7O)A}3G4?B z17$!Qv>|?Dh5ah_Q8M3hIc|`$sOj?DAe(|z_L_=U2cNRnl<yyUl92Bg@geP!{&&h< ztlYB4Tur0>DIwdGFT{Pp$*#JhPQv{(c&)kLPir2odDPaLENX^v|Km^L;qF_pyKZ+^ zF}GahT5DrjtsKiKHtsn&O)qGUXQG+3#c=yY8kI8K27(OoERB3THAHZSOVC9KoJGwc zk9e%J23T8SynT-$q>Z-=yurU?lexxQynkUjO)@|GA8LcvRBydoyA(_R)l7OHOPhcz zfN{V);8Eb~4d^byw2>CeN4!Q_LZB`w>#*KWh8bxIf!`2W9rXF~a3d`tu-gr*ucC#F zv;=+f<0N{_%RZqlu9)VLXV*ykg%VKWNDAS|vnj9`X&XSd11<vk0;7PNfmuKv@Cab+ z3}vJx1X@bIWkSd?$r1u_8si#i34y;5Q)pZxEkR$L#MB!`T0)>m1v?(K*Hul*xe2~Q zxJY4wJ%@P%EsvR6FW7q+pJ8r11WA}U_Sg;!dfkFDm@TQF1oI*#W?f>s$^ho=f=l_? z9XBfGUB*u}%=-=W^*|P|0C*610eA!02<!w5^Tgsx2z*Pb9wRM5-*YRIj@r^n2yE08 z#z;#DyrvLhm?Z?B_P8HZ?vRm|pzbEsT<gu)UvuqJ-Jb2I7@OwB1jmK3tk%aAyx~;Z zSAVw!*BIiqV5e2SMt4VI(rio61-jWT18G|2`iDHNauyb{v`U$&)2;GxZ}2E(Ks$Rw zX_fLCQ-1dSv@T@y8Gb6Wx#pM;(5nP|1sn$c2I9cA06GG?c}?RZ*4CZv0#6BB)I{|= zk2<J(TvR_rHGWsS;2cf!prR4PO&W2wqQE~&`)^YO_(L4}Zct?o6==~E4*h$l;m{0_ zhC`1$=;6=^I3pZ72Ln!XXtp;vQ5nl24wWhny-7*o&}M$BaOjaj_F_ml&=_|YAPpD_ zj0bc{()ozBm7XYOm(9rX4VNkRqtL9a3@sJ@5f|S|MPOXH%a$=^jvFvWN7$eP4ChKX z8DwqU)yZ(KhoZtC;@pb^D|2qJ7Ej^a4r%GCOAwhgoEt-`?lu;g&J@o59%VR}><t!+ z*sJkn7f*inFK__P`8HL<xm6%r1Lp!gfq}qiU<xn`(40%)BdyUmE(5MZmxEa7B1#`% zt>d&9v$^MT!o@pD$KOpTzN@vbErIw#T)98JGFL8<W~N(QzO-b;mG&SFSNf5n%N2Rh zQMj@XEv)6~9B;5##8tUc<3q)j1b(W>(^in(fL_2bU;=O(kPF-g=yLe@NUWDDeU~Xj zh%5V-z=m2bS2_?bUWY3i3B~7dr5=I!LR^_WpfXp^l%}P*l1(3=xzYfn;Yv4Bbh%Or zH-sx&=nOPh8heAkB)BS9nr~KI>BvtNuIvZd4;TeZ0cHbt0n30F0L_)d_g7SO@p9#Y zhZQ2km90>WKiB0-Bf`b&aOEXJ@i|;6LmS}>ab?1lmAO)1caYM8ZbQdwu9PD+hAXW} z(dEj1xFKAT!xx$>5#Hbps^^T?$4*jpA6kQhUq!sr!8Lwz^2E*^$`#eAak33Qvz8`l zsz^F=!*zdkUEc6j>cVu-ZnWhb(Qz{|TxBAwi_So{H|SD=x)$jZClkB@XGnl^Q=7hl zZ{>J8uVXiOPn-nsg>K+0!gt&o_@27{f4qV3hDq2GvWwr`z&Az5@!r7Kfr&%Arx509 zLUr0CRTFw|;ENQ(rVxg1;A<5|rB0d@bFYg1`$VX^dvD<TV~onI=LWvj5PELldj>BT z*R3U{Vba9NZF0`!3%dzypxLa;jZgBeMe2F08B?b)Fm?i;*>7G8{6IaKQo&zcNGjjS zCudB&_wvcz@&gxfv%K8Kojj78oD-9W&5B=Dn^Pz&7fV$Ku94}<<RRAJk^Z-$<12WE zZ}1SS@5rdnt&4M#M@Hw^5!0Ibb64}R-u~QXs4#xMM}Y@g5pi=`tZ$w?>6kS8bSt?> z;*7Xy@vGz!n87-6HTRj!6N=GRkGF&8SjnS_>3bq-i&bVNr-aDcYVw^jWtg0z$+Nlf zJ@Xu^raI7Y2KPs&$L0-<w$h{XcuK%O{~2gkHR4nDJ*pf_CGHk09vXGmd>}_9cE0`y z4+q#AG~rDeFCXdnww0V@&EPiehEZSTd{8sz+j1V&wgx9zgIXk}H<?qzUj4M>D9K8P z!1~Kdj{`leQBG2m)(YF?{cj`rn*GJq2(*xKyJd7<kHxqvcs5f0jpyHaGva;JDCylg zkVe_LpqE^RUz2x)VPJ$chZCFmy|_lMv45fLP|nZ(`y-{_PWc%978w~86&)R;4;{dB zNvVb};_gqlw~z1%z$3tJAbvYr;en;VZlEPJ)_@kY_d@%DyQQuB=ii87r|TaCd9yb? zBP}*C6g(n=d`xSi!WTQ?&*<=ODqQ3wKRVt@SQLq<1X}4xNg`D`)(9uo6dg<U4r=L& z`d~b7JS1?JB4QO8_+G3hk;te}+?Gz<^K{%zibTH1djLdLF{1-7R}=G4fi6oK)kRtI ztHe}K4ya2+V>s2X9)Li&1J_oQ)<aHOujsTct&)~Bi@+HsX3bFkuW@2d(=nsHF%zuV zyxLap=)5bUi60w~CZx(=D-^$_6aPFNf0H6{%I}Fk-s;UQxmU!JPVK;>CLIqSci*MC zari04jalAwx=Ze5tiv70U)jAy5y#lypznCd`!mF33UNhDWad+eL7tP?qdKw9f|u5G zi-Vu9@r}VBR~w{4OSSwSEoDBjHmF0=37UM9B6qZbqX$l_qzAHEC>?OfQXjZaVt8~w zNWiqpdry<ypb~Z%s~IvSIzKh8W1Y<U|8C9f+p)GkcODHb@GAfC{sSuHHl4sMoxs_W z0FQttao4ZiVn9VjR1ED|5KTbT0YTFaWJ~NXdDOyZe}OHTScYyC#e1Pn<ohUs3A9jZ zgPK@_8mfmcOgbbG?3p;bg%c-A$9Y}HIc|)2RW-Zw6*qDr7A5M>ogvZEqD7PPCb>#O zF7@~E5y?Sb4DXH49}HeG^FbXw75{N-^j1xCnxyp~YBWWYt63JK-%nhl4Rnl+D7)|) z^;VnH^|TA?diLb0(#zgK?iNn&Vb7FXiOYiLRqB0s*Eey?^!QaGanI;DgPb@ib}tpj zs;SRL*7YwGyN1z8!47t9ea^-3{C*A;13v=40e=A!Rvkow7bPEUm8qR`{`Jav01@%8 zQO+;Kxj{L%iQvqQ4!rOD${UhauUIN6mn)@wI!}$JXXR&~PO{|cB7Q2{!4T3<ScGH% z*8-D(TY=d?F2Hrh@-A#yaHP1_i))a$)`+XOxHgFEQe0N|;D!1}jKM-XlQYdUXjytt z{;}FGn?;m=i1tU~w@lNjOVdi>sjxYL7sy#yvpPeQ%T$irtUl~psad@NLR!TgPMgZc z=2jIbZR)#)Dnl~&dEz$JL)uhb)ec`%ae||XaNGt}S2d{lnzEZRNjf<#iJM~ROTt@G zR(;iiGBkaRzKB6TIkuQHzH+)(|0g&9eyz^-=3lNKDEO1C=VzDhR25oxmsDtUWQ{1N z-zU(lS=T;D;3Yr`&<_|4i~z;}lYnW!OduC10FE{fyhQx*$C|527k-xG1-rz--o-E2 z`TXpS+Ivu5KAg1=hr9xKYf*>22j#WH$p>)A({tB#-I+1*ebOCUao*UxHr6g)thc*n zit&2HzMg4jhB(y7X<&?v%LCajjVP}`G&rE%eSuV!{pKhc`q;0^Pdy#dQiaGhJNi7e z^KNrho@GqD@Jn+7npPzoWQxir|M}V7zEB+O#gD^5(E6`tePT@@AQM;sECrqbUIX3* zvJ-v&B^!BD@?|27=NTS+T>H!uYk`NsxCs1t_zih*ZWwKFs)sOmy&Ty7jl`W-cv6pa z-D#)aXxP*Z8{fa=0~j_0oQGkz4>t^}IUj}<*|{SX!)D8m!?2$?OT?HjlDBG{A=ku9 zDWX)wOUyAB2HInnhVJv`t!-;hesaGak=#m~+%Mwl!X8ms4a6lzcYH+y%t86Nx^S@7 zd!)5Dr!XpU*s$3RtYJe6;_6tn@@nTKjf`GNysjKuN1k&w*$8r8|5E1;>(uh>8U5&Q zo|bMwMxotB$)=W0KV=mo&~p0{^1C_pcVA!u1Ua+Ie3{qFH3-Av`pz$!H7uDI{nXtx zAN9h1DVtxBRZ9^Mhge@cFD~p9Njb&7aT%V*>UF|;yc@u?0s7H~U>zQCNRKU0FF2(2 z&3akWTT?~)tfch3)FU|Zllm=64Jr(o<RSY~D|)frWk`9&C3{-2e4o3B3YOsXCW<J< zE=L3ywrs(4N{7DO8Z=VADUQ*382&0(l(#piyq=>gC9RO@+<mVcLsTeUo|cDr7+y(s zB){?~IzP6&n6fDK_rP*=sI<6=U%4$#KAAE|B@xOy13ba=EPJ%ozf^OncMpgv1~(*~ z?AgEjcr#0CXcmu!t>Q=;_tM`fO;KN~9ypH=1){EEuzm$17P=my2font5S{RaT@SHF z_~cv<@yB3uJ;d+FzaHXU1UoQadIsluhz&Xx*F*dsx*p;Vs@lF+Naey6NY#LSNp++H zgmk=+%5@izsv9CERU%d6_O?QrD5SEn-Fr#I#hTo6NkkdOfaj8k0A9(VT|SKHA5v=j zH(aU~Qe<Gb`?jIna$S$<ev#eGKJxrQd1B8dS(iC9h(^IR5gqo-_4m~nyAQ<4S-&Zp zmPfhr297imp~WY~J`)PnP)?VIGBxhXoPT|@^bAi*&J1RD>e$hcfUd|2<Rj1-<%@du zvk-BSt90H<Xn8!D3r0(E@>73zl<mMFvaDlc$NNSU79{yp`!1t>FY5ny9->udjViZ# zoiCZ_@cXQmY2w~xw@l%lsr0yuGycw^ys>%Bf-%WgW_{OnBdHEoZ`{gUR9P~Qb$Qe5 zx-GB2JbG3p+Hv~Vu6E?k@Iw19(xkX{y(F2z;-lS7$uq=FYi+R-vYd1pYme3}>om2J zIcHhUIm_fGT)<=xL`buut^L9Fkc|{FY10xMFTv-T;981rFXw#hwt|Us$V&m=&PPZJ z19pb1KPe3QlWv<!IjlWzGl}4{SM+7Erc2(8XqsDcNBijI6%`a)-bRD&FJ5#@>nO@C z=WpMv)3`e-t)u-*PmGos(OGfY+a7N)27-#L0}``pyr!CPjl}DoRfEC@V-@|6ipBa{ z8DxsL1LboFSz^uEk$E+(R`S^vI{FNW-ad<$FQfbBwF=f#DID5TQ|6JnZdC8nEzX%S z)|Xks+EFoRtk&(+y*vud%XC{(%Y@QO6Mf!0r_492sWnt-nud2K4o%Ohk(XK)j3J;R z>&Kiq4Sksjynv8S6{cHhBh!&=a<RE$Xv4wCJ!pci97#p+x`SL8V+2LZhk1({_N~i4 zgWYKH!s(gU($sk5wLCAXAUT#n*2U8Hl4I?|mmnj_(IlFete85{z8SF*=^MoZjigC0 zWY3^x9QiZW#AJDR(QAWYK}ffspFN{kSrB>rRIwlu_HiDHfEB<h;4NSsumLCpj-C>n zKK|G#!D+x0Jd?#U4p3IpF(|xN(?657)wDu>mDLo)Wi&EYQ|3Tp1Vql3nzHB8L18t` zkRQhguxCk#$7<4iTsyW%=DK4OKgwd{pzklVJ{ZND9;O{`hXFLNEva9q%2l0rMAn5$ zH?=n{uBGEujc#2F7(|o$q<49RYC7LKp%@LCuQ}T)az0W@QEFChr_nv_E{y-W9V7Js zCUBo5lUklLqjyD?yq^<)n)1{2MXCgKuSRdyn@(A4GKEjK@9Ae6bHXZ~Z7R19&lFuD zy=FvUTWggJef;rs9+X>>Mmxn-J#J9?1^IALGO|#o!1FSe4?)FT7;CTmSG3S}hb&Oi zN;L9zU#8r)RFNTgD+y^v)eoEIXJA35GRRcm3kX%<5CSn4WO@}>MbD8rW%cG>>Cc_S zJ03Y@j4khnl2Ke>KP%G**j)S#n}`pwo#A_=<p-X;|B+?F!)${C?hUe#aRgoVFZ(rr z#+v;**%$p6Z+MqAntQH4H-W~Iv+>uQvKsz{m*`Y4BgKecpa3=jaldkF53u()iPdy& z8-MO)?7+ye6a2Y*6V&u>tETE_LK6&vW1Mcvv77mGCqQ)0_f(ue_a|_H{rppqQS!P} zvAraqW{q+Wg3QLQ^XH1aY^9d6LJ@tmWAwDRj**$Myb&GUF`8$LFt$=l?8~lJRc9rs zdDGs}R_49s9i}#{=&fxjHFqk^b*E43D0U{<oqCvvc~f~xNl0YoMYx>Qp=XQtZN>wU za}0G!0p_E+8f*RSRLdnQ--mR*i*23n_8`eERc@oM4p|u`QmUQI$H`pSYm_B>_7O_u zQ*`!mN@ZKz3^i$l$(-)X$&;95nRk}!oKiyV_@B#}mS~bXK{@?*-@v&vounO2Sp!$& z*V#=`At%i4y5Z&<GI@OxmGI)lCgKS*_dY7a$=n3SnSs}hzfzNFGlRN$(gZq9rfX4t z3u&JfNh4iRJL^YXWm(YvXHolNn91x(ma_076Y&J4bVY5xWkhZ8bc(aHxik?+)Nc7f z=lea7M$`s}WbLojm1S*-B0OQ`{d1Mc-TztEzV2?4Izd7GcUPdZoa%fipX&Stzm~N< zD&&OOy)u;DlasYe{#)iULYe!U@p&K>zsvt$4{82iB19Q9Rn!LdH8P3ev{{ynQcJ8D z-ZI;qTIN<zsD3sxLl~|LO3{+&ixcUBQ7pk~ZvCI@=i&=ZQYWmRYgML1Bidz*U;_j2 z>-y>bKWF#V4D*eXY$cC&GZ9aixi{%h9O1cIGWRTgw|)llL=z0oeH5hRIJ22U+7>y} z`upEoX;iZb*RuhAf9I<^oQk{#Dk?J7R?CH_qKWnNcIqK#j!vG1PKyhitMYJ2X1;mB zF3rI<S6Gn<8B}HYnG{C<-!0#(>jnu^FoQA|m$T-}qt|@NCB0rqzisT4FU9Eg6j}dM zl4h0wb+43SPrkrmS&Fs0L%Qw~Qe^QlraFO&V+l`W)UGqcjh5b|Lwbw%5A(=br2p;_ zeA<p#2vgHdCS+|*n<cXxvt<1=GI@y!cXTXkYhB2q%<QO~c2ArdhaIElYYHSnoQV(` zdDTib(<JkA7)PraE{qgC!==lcE<ema?BbUh2yV=2jmtav(1pZ}sT+76%fs~);0fHG z#!SRU23Te$qP4vWpOsB#?6aoE+RwN?G34Cm`&LM>^L*bp^2xT=HtPAlN>^2?$NReU zVJv?ipEFwry6PC-tpg>$RaDqDg>aH4R5KB^s}gPz!u^=Wfh0|+<{`f6sq)~YDAHg* zCWLPaVPgor8wlRe#GVZV)1dWiAh=$l-XT%58d2j@#dQrX;kG+dH3&JVR;eN2=}Pi( zj70b)R?=vig>tac=9#?88>Xu8gtoM@pac6G>hGgYXDo1>RfX^JsmRhsLt3ryMNAzT zxYtmm*d0t_DRyh)teS4%X40K#VjVZ#iws586rPt9+L`d<rf`g%A&O5`Qy3>H95Ufm zQ&=5=n$vf^PUeLnQFCu8YFn@6#7v(c_CNN0AME=YKs?YKI1}g!TneDmvb+2I4-~R< z&vh~lcxZf%MyGk)7vpx&ykBdaZCTDh0N<QaQK5T<&L-1I_Pe>Xx>op=_BGb?b70ws zl=~+;SBNTA^s{zaNmUs!l7s_ACj5kqxNe_j#0o_n#)#i2>>vg?^?;^8Tc8Wj1Ly@% z9%00i5F>E9jKJ+O0=HoVPQwVC4kKQ<$uOdw$#jyvItNB1;16TOqhN&*CG}lKe6O7_ zqIX{E7tCHub80U=i2v>=nTk|?)AhHPVZg{c%hlXr&dm6Kvl1$gnY&k96&viNqDf;+ zOpd*+wd?C`&5Z3(Hr+o!V;JQ4e7%@FWb#8#ILkwX6`2i{Z{(KbI2q=yCmX)t?Kv|W zR%AA|lHI_Dp}>)5RDZ0yGo9Jq&g|@TGpaP17gb*pYcNyI<%t7F`*S;zp3X^P&(XKl zA|w9!O~CP>>iqQ#N<)(jIWtCAWYx=0-9<i`stl|k)F~q~i{hFwx>tvP=ep%=d#5g^ zFjKgq`n1v0JxNRsB_T8U3<F17=P#C(L^TO&q3Fah(n8T`R;je?kLIaQ=gdg=d2`g< zBzN3tgh0^mWV&h-7=8myV2=r}+5}Wt&!>~U&956{dx`M8iEzG{7!6lyj@XOHVPFnn z?(paAuXVGz4WtZzGEGDMCz~uW@vn!jg^sm50J6X(-UI@BbpjVuPT<|J1a=<LWc4J0 zavmCTbMS(bKq<(u9Lx+$psr)jeF9nF9d7~?oCH>bROK{7!M1w#r14~Flro8Muc1h? zTatKSp7A?u^}lt#bf^pu8BsZ^)W48Hm`ta1FJVy+7y^s~ZUYtp%Yc^wrXZ9$-H1#q z>KPxLSs5`IgjTJFgms!q7&J|ZQnQBSg31U-)AXEV3iWPXr`Sn$pScw375vx$^(aVw zQvCTmUn|+s49E%5o+`Ar8h=%}`(`3yG}?q$D|gv!L-Xf$)-<BY+v0qiakS6=?tEu{ z)xtuM^(PCvK&DllM#uZe1%t&*u)k6Dn$=v_)eU^r=#Mp|5!lcE#Dc-f%vlpgdAWzO zKq%i(lw$eX1!0tpJ(SlAWxk@6bvXO_Fv_1MguZ@}P>zN&XJ%Z5Y<MN-BO}m>Gvhtp zc%=#5(1tlPn|MN-sJL}3W|Gx>-mP6#Y!EVY#{}Q4ZB%>^4IM;%l>$3ZWd2E}03F5* z@?`C?u4L`QI#jz@!*mh$_Oqz0=LDm&=|pwR^u|ODEH!~uL_O!{2>+d1sWgA?BWU+4 zGvk;`oEeF9WDuuvmm<@!`lHUsMomz@F`iF!HJ@l-xr^exTPH7;5Y~opOLDw)8LIe= zDt9D-A|?l|Tbme3SaF`)lblUSb7p^0A@cnN<wOk!RtPmy`AFbX+6hmNpNE=~hXoL- z+Tr6`i<>SkaE%J0gY)J~<u;Hk$%pdQD3q`J+N&N;1|+(Bn>v*&i9svB`AM_Vg=^Vp z9bfuTarT}e|E6ckzrxhOkG05ArIPIe2Z5Aqt9G8SWao^dWUpvKm6Owyyfqi=KuRN0 z2gBe!bI_Rl@<r*%y#-Z0d0>Pj5-MoNbKMGf@y!2gLH~`dT2OWSr!MFLf`ut3s=}19 zWMADw70TnHE^Z!c{GanUqMAIiH`!E1B2GH6uG`3{{o_vEwaNYLssl4K4eM?<GYw0w zC%>nt_@y$Tkm=Vm5VHjTH+x#K=XGMsoW$fRP*MFGW9beud0_%)G!Hy5spPY7Ns~HI zQxpFA4<S<8BG0^4ej)SOU4<f}BoFgkWANmB5G{U5bBj;xI44nAnK<Mmy;kt{IgCGK za!U5~gc+^&3`(Tb_6K9g`Q<v3NV#N;FS{<aC6+DkskZ$>s+$#6h78-Gc5}fTxfDx% z+u|vrSF!qKfFJhho7_+Ll231r(OL87zJ^Q53;iE7fyeQ?#zkLVL6YIogNhvU#?(zq zNlwk;mt9A4(^Vp-&!2uB{eAl~?*9f-fGdGv!1cfsU<N>*|BVftt0Ic)Ozj$95gTX` za@N;QkTqS`KdgysF3yr~|Bctp@Uk5`!#{uw6Q-M{n+*4oNSg@{87V5md&yMSKa+ib z@LK`Y!rc&P1)K#)hJAr-6;WKbY1jA)U*Lw2bF_AX9O}CI;nErYn8mKZ6?k3g4}7LG zd;!R?48MDu$?#H%)JUZkCjD~+{||d#UFm<sNz4YRYTs1X&2D0SB+^#G&D>lokzS@? zs}c6V{fe#xp)wN6RBc{-V5a)0v)FW|^U+%svE;B(CbH+Tg@4U*%YUtu-$}Jg7}0i! z<{!;EU$q3)YR}S6we+V%pK(K}XpC>JmD4=_+z1j1{1WBJugsL)DxGWM)ZX-$VpP~y z%lE!^Da4ppdlkOwY}PG1D%nq=35Cy(`R6Ysn%<YwNK#qoq~cEN%p}7y#fhr@|6mrU ziOICF#vKbF?;7$FYXTi>By3@3k6ue#{D~H<VoZ_j*#|LC9#%T5xVi~V)&PsG)IE0M zWvX{N`8B|^Tbqa{m~wU(W{%uqWP9BxigOWJbSIwoY}fg2tB{V26>6ks=}$kGcf#rZ zDVLf&8Dr*uz4X_&l}YLZ#q-}i74@$KBFU~r5d))@e-FYXI$G8<i_=+Tk_H8teLI^7 zqz(9U^HtTHaC!ELOH39{ay8(dmL}o}^6pm6z^Phw_;Z)4Je`okasS&q{e9|x$&=n# zm1MtnGm|E@SJe=n<>^)G>>2&oy%2TKNk-3$)P+C?>_4Ca@I+)Ksv1c#J1AtQoyFYf zNGeEen)t;DmkpN^zrK&v1Zd(b2FYkh3_<3$%z-c2i!*R7ibt9DeX{;s*uPvhZZOTU z$I4>;B4c8#FU33e9xG?IYGw{o#}{&D#`@GAi>HOVL*sG|M{?i8M3`RCzhqT}J^ljF zvrE{phW-*=8n4a>&fuK6Y~<K%-wvt8-V_dps2v@_Q8{R1b^rZf(z^nZW;!)Ck2N8+ zoY^Jnz+ot{4kWhj-wHUi**;q*SJ1y$(u<a3kZc7g?Nwf}IznEYGK&Bc{S=DhaP~I@ z$%fWH8AKHZuEJ;x+J-l5@Ub?keQHNwN!OyhQ6+h!j-Vq)DZX4)%jHYY*qpMn{0qfw z#Z(wf+J6J5MWp!p0P}$NfY`_s-$>vsplei$uNw)h=Jx<lCpyJ<A#g45EU+E;9cWx5 z#di^KHE<{J1h5JC6=)fg;u`@h1$F{4HB)>$fTKX0Skedj0;7PNffs?DfP7crZ`_)3 zoZp(FI&u4~X7I6piBwLZ-DMh$zNr|u{YwntRtSZsquEbvZPj$=i*k^Q>pgT&Xu9-u z|47Xg+UJXZ$1uCMe87oUPHhF&I`JI3iB3GXQVZ=2g*r0AUfC`5&5aUww!}>>N%s)9 z*Tm`T%Jp~Oy@?@~$;4}TtR2IL*>_$*N~V~7B>U%y@j4iRE3{vPs-S-<;`{u0AhSxD zKS6xU5Z~IFvX4ieNi|81ROu`6E3^lw^sUXq?d$kJV87USgH@y8%%Yp>!0J<#tG8gF zX6bd35+yUA`Qt|XTdm#0>;aN;t~cdB3DfyKcCIv#Qq@30*_FM%CY=?MPFYSx#4JY4 zr3?)+8MG#r&1tkY6Ny;Wgf>*~Di+I%0;kI-grw`X{C?flzN<p}3RIUiU8Pu2Fl(0k z@jI&hcrk{ak)1A;KYomXWcbJL9qRL~jtD$QEX|1W8>m0>VK1kJj#xCLJEjYPo*M5a zsiq#m1hrc=_ek$F$?MhOw6#ODoxQYaLMw;QJn8P|%TBt<Z9M5V6WS<6>$ZwjinhdV zCnIA=x?3WNfg&*uwO9>;MpsjM7m!uO>UC%ht7=GsJE)ClnRt4@6VjXzyW8okTy82Y z>d|(&W>X{i*c1<0>14=$Y*UHsXT&Pd%R}}FWPAS#OX?$`Io(6^q9j#9Ql?}nLLt_w z$?Za+*zKWcBNPWP>kP#>p_o`XJJ$-?+mKE4CGpQwU;DRByx@b0r|B|XE}_djiL{o? zeiN42Q-$U>XgsRt49G-9)o;Y)ke5j%)PA6kC&AAqA!eEaHDYfStIxE+u99*Km9o>l z6xts{k4U(!@>=ol;M2qGSG;kL$%hV##b>&vLi?UdaZeA$9etYTyYEQcXTswSt`zsj ziPe91uEd>4T+`gwLzr&r;B`FYb%fnrCaO$1`%0YiiQ{Uj7Zsh-f9HS}K~;TxeIZIM z(=*}CrccVxPNAov!@HIrUqpl)CB_Vh_SFE~zZx~3Ab2`37gz)=1|9;kFJ-xLW3c`B z9PMc3{5E!e{m!qb+y^i{S!-{oW(Bl(tf!g-Gr@P=rV%RyF<ETXw5d!z44s-kbk-ni zX*O9I#Gc?8*3e96PjDawDv!kcK0!)WlCIOq6CZ7FxE(c!6y-Ssbl{b<bZ9U6itO*V z?v|7_GKNMO_yw<ZWv0f6tOoWe%nXgGCzy}Hh)_7a-5u(~2$a)-)Wff;sL$CRk$6F3 z-s{A4D3f$d(RvwUJk>c1+TcWw+%*mnj`R`^7Q)NiN`GU#e7O`WYgGqfMj5+$>lx09 z`~^?3dN<T1NfEDH2jM*$bPfFnmXv<T@}slGoQgdYb1LXDrzirwas{ivz5!X8tp|*6 zJvejPq$v|x54vv3gmL;zK<VJ27+7w;TIhVy88?%Bd9`ModW*OT2kh8&zhg8Eb2RTW z2=K}X{b;6Z!@2277r%L&DlMsQI=k9bo0%G!1tlHtX8FcSzTr)GvTyB<WNfG*wNrfd z<IF7;>hg*7PnwcR&V4@4L~&-MWOW~(ebXi773w`sjXNl~;U1h!uCFa;>+QN1>ZQm= z=p;5lPL43hts2=ukV4r46LX!dkqL%UA<H!~LXeS$GTyJ!Ji?a4$x#N`RwKU>WVAtc z(Z~-3S;HWcG;)O?V+=A~BOelEO@kb*kvW2lHOQ$NIYp4Q4KiCJhYPZfK`znA6hX!r z<O>?vS&(%N@@<W5CP*5WX2@2JtRYChK^ALd2^;+;#~Y-rkwt>6Z;+)Lxml2GI@f7N z$1B#oF33|1vY|#kBFKgY*;XSL3bK(wcG1Xbf@D!%r`bazM+vgALH<A5-UU9Y;(P-> zAqy-JNQ404QjHod3R)DZl%P%6-H>Q5OD<d#6eNM52x+oWtRTTnkmV3f6<cq$sHmt| zsiKAjHL#d~qN1Wkp&Ai&mPCy<YJ|vs&ogt*+0BLa|NFk*ho0;?&&<3t^UnLuecnk| zU^>AB6P%;K2?R%&V2J`xCpgjsD-_s|;3yNUQD7T(_+3BR1UD-1vrgbP1-?P>H>S`1 z3Ve~E<}ZPyZ*Nl219LfO^v9*cph%m7?oiMi`m&!UndVW@MEXil(0m2O5E`eTYz4)8 z5O9iuk|l&>tVPA*&sX4uG8q7y2rg0J2!f}Z39eM2jo=w3xKV-MVJG4BsF_s})GF{3 zf@hlG0R_HJ@GKJ)3fxNYY!lQ5%M3n9Fv$cH6u5>U`XMT!i3<D^!E;S8Q-N~`o@auE z3Y-QI`v1_05Go8+r(m0$c4l@?enwh`BQ-xGCwoR}ZboW$ex55|)~Tm*pJuq*5k4b3 zKR+igAB~!#NerL)IdCws0TGzfl_qJkRd?s)$#>RmjvV)F(?3QDn$wl(%6BQ6{LaYE zbLD~}>w1184kjb=o5_~n{or2UcDr&Nsd*q_VVOBIJ7J7BKQ|)_KNg)#SN630^l%su zH6iJT>CVf@w%#2PdB~g26soYj@td1dknN24&d)8#b{OBJLl!YV=mTl)3>A)e>Qu#- z{&<(XOv}tkHS$JGei~e7c;>^M>deHCq-T6vWnz3^WxA6;xh{7mOWov83^2r%kv%OZ z&5@pJg{9v!Q}gmNre(X#yf6&~*<p}rAV%@Yb7i^nQIcl5vI{b;bdi?yV}SJ2S7G_H z-7Xm>7T+1pj68R0z9T&&dq&Qc3LgX<1)iFln>yPp5QZm?GU|p82A-RW<YcDi<-2A% zTy6@uN*BXOw=VcV;1(oP6!vf7?$q2=NDSld<lmi}W0oy>8TJnW!9V&xEfSaI2X-57 zq?MYTm(f*jO}wk@N*&0!%9WFbvf#Pq7Cme97Z`vi=yADTVaw>Zulz^Y(9#Ry^sM+$ zf&I`*?DqOe9wk1GjpGY-*U5$0JAUZK7TyD%V4bl7ojB5oiJ<d8gU48DI8|5>{qZU$ z>iB<2MT|z91JnOUPV}rq?=PAMf1*77y}$JG48obP=F=|Pw{{m!|25k$+PBchH$5xq zi(WoXX5wI7qMCOD?VeHy7X2SdCWJ}G8$A2}Of&9_fwL5AvO1ARua#D?0%F-U94Mp1 z_`ax2><Ho5CHdst(`3vc3d|wOnZ!2zdpXU@Io6n=)?6Z|bK`O15oZqdln$7f^|_k# zlR3VXN2^^;+bOPo3_djRB<4e^LMtwv<~undRGlTTn2*>Y?HDJ?`O`CIULRF0XX+&( zF&Q%n-aT>AbK9q7m%klxsDB6|hez=NhJ}G(-Y9h1Tg^^8=ZDp%5A!c)ht;`FCj6@5 zX2P+nV<cx%2mBb4rwuW=y#fR=ne#EyTX8Gy4euv+nd=GqB`~YN{e;6}?|2E07((8G zG+Y8&DZ`vv86Gd5d+<Dl=XpG@;&}tl_jrEAL%%;5Vfx{n-(MKtiN-fEJ|p3uGvFVJ zW=zin(-C6<_R3t2>){{ZhWEXCUIN}{U}QC$>)gME2MjrBeuVz|2#@8fUW_+=MJZn$ zU^q^S`aOt9T#5o$$KW}l-7P-DFeunaAKd)0ZkTw9K!XBeUmYf%;P=bM_she?U-|u{ z@%`E`v4-D&Q{OOydow@RTA#)EY+muPT({o9_Y$V0k|}xi45TFH-_q$XbShBqH}XB> z(1l2ln9uji$eCf{d%j;(jgu>V#6=jKsxvI&6T&0c^;zrsvfg!+hw-qmB}#~P9skWo zw3MRfMynb1J200X2=*QUuhxuuK-H~mN2ccFWV%vS+sw8m---4uKO>86oc=~NY#?ZN zi&aR8aR%ADr(OSktt|=rF0tY_CB`#g$}l+@n~D}$?J`?A2%6VeAFcVyZ0l@EYq4qS zHe1E2m|^Ap^=YGh*za<A^I#b5p~<92a(S>f4)2qsO_&6^5973YhaCq6aMss%YrMSu z1whoR>?irkU~nz&=WoSu#v*(-#Opumd2zANVc%N)gngnV4)6_eSykV}uKy=Q!=*RK zy%(?+k)LGqu1LbF#=!bCTW^r>6I=x!Y93`o>>Z`}fC{WjaB4q}aB3xZR^ho5&)@NE z!Q;mhjmM4WY&?7M(69L%ig+jXgF(x5kNge79SP~BJCkhdG}wUs0oel(UCVxfxO5;* z1k>?j7`r(%>A~Q8o!o~j_dYtZrT6#Q^($<?blXDx3Rn$Gw+A2Z<oQ^PN$lSSu`1=R zF#^~J^7U!H3302>SNXZf`h1z6v#ih8_?cmT(yml<a;L8g@HGGxFB3Lc+&q$^3rOZg zdXK?ZUq;L?Z$nIUSxgozQ$eHkz-+^g4yw0;>G~%XSlEiKJc^RhZ;j{HW4Ep1&yXaW zKE4^jaj3;8>*r-z^YjeRVZQhzt5|iotgBcwQcjVr#*bk`$=;7U-sC?j0{+E(Im)TM z2p@0a`5ezLcuoWMTRfNH$;0y}Ja^&o<7vcGaccrn$U7f(ThhAWYvY0=@vcx_8DOHE zs#552L<MxAK71iIJ+$CU;YT{*2QB;!g+qelg0EWWwg_~yg+8oMnU1>+)YD(@duR+| z{5au3KV?hrE57fKQt>ce%k|%3*Z1i<L%I$}I2ar4CSWF^&Gb6fAVjZXO#(Eq!M`Fd zMH9zPhwDJ;+E)_t#d+&vqHkq+=dir<VxYNk*l8%P1tD{1VIJNMIl%N+^n|*AD))iq zae5p!OzDGZoFxuFahAOaxi<KouYgu+^j5Zsub*YMi4zWChkE5S^#3Yuqdfha<zm@m zj9WE4w(@E~>0U7)_I6%(?l~hk0=~UsaBO8NzP)uFUeP=DcHXQR4E4sO6_?$o*|(FO zsvqz&<Q(fG{wBmKUP5&nTlFD4vism}*Wcb6C0;p>47V~RuNV#~ZD<Ui2%SVg`?{3> zjEgF@dxql-eNyuTJq>$L?Y^lka5|atA6V)#0AT=^ngG`PrH^y*tEc1qu^p-Pw=o$v zuqfoWIEobMGvc}7#)>KdQJvd-iJlgh-YKptEyRrM4;Es^_S^2U{W{!=?Isyp+!ek! z^gG_cSW1V50V`fJi?HS}%gA4FGd&S7q744c1dJGiYZTBWi)+J?Mj=vPLhu^+t9OMW z3~r8$z2h~E5mC1<JRQrm;LN3Gs%I8{`TW^<K2JpBiKjQd-^8;F?|(c)g?Rwq3`@+U z!CyYY@cSO<zYKSV<pUcdsw7?<3f|Ck;OKPEfOO9&h+41G^P7`tgd~HdG;G~qR2|%& zL+BC-Ez}3IhTv>I!80XDp%1pAu_ZJ}LI6IKKv$VOo6e?8o&`?DR!s#l79C|0mL|?? zH)ZlX!$HdA;9viLlgW?B2_=(mmfioqGPyV$+mT_6&5+4t#Xwa!3GwVIwTn9X7zS?s z1!@k!Z#x@BdwfU-%vpsbzaN%9!nI*=QKZiU5k5U#eO_kxl#2O8gwHFKPZsM4_%WjL zCot~Y;EyRgw+l6^ng1H~59%U{k9Z57v6T(}w~uGw8<DMGz4Ty6;qMG`vJ8e9;<YK# z$3Vk}l-FTW)+!_2zZr};`sfK5WyCRI)!=V~=Da^cYrdA>EAj11XwJjC;_XfZphF=G zLK1AggpQK6|Da=53kb4W(o@<+0ml3E{(E{aXhC&_9fWS!FbZL}SxEDgz@J%Do{sA4 z;^uUE??dm{z!FhmUPb&{u)x60s%$Fp55u@wp`FhZnAIm&87>4Xnz2=<GnxQ2V$8N5 z$`Agl)s{J@v8(+6I%eV3mH@cNc?>obXXdzF*>cuJVW_CAfAqutZR9^<9B6j^M;zKJ z|H(1!L1RqY;mbPgD`?`V6;^;&#;_F}Gr?>H>s^PiE8#HOzsE6SRE?2`j?VJ)QMI)r zaGz&R`$-r;X~R;t&!`hT(rz)Wk`0hFXa^7jMpvA--4=VtaL_=FS_?_rk7wX{PVMb+ zc>kSK8-rhtms|Kp@Xt{iq4Hw8pr=3HFn&QATl8r$=~Z<rewV^yb%!{_YY;E~axx_B zNPze){$Lnb-d{Wdh6aDY1e7C`b+G&+HlX)_bsT}XV=8w4RB<f2G!}n6{VR_3^~B+= zd}IOg@#W8;&>ZVsKH7F$KLQ5{AQ*;#ZXBpavycip>+bd@v2S?q!}!s9_wLiDZ{J?g zw*LM5<3^VLSVYCYsD6F>zdQy*UwDZ<7i|WfNAMiObIETpOvdvLo>A~qibvM-gVQ}% zv!0K=oxQT)m-vIhyR@XT28^$&yCoWjw|BMo!oG?QQO1EwBTMBE)Cy+;Z73bZ!##d2 zcn-V8kZ)02!zgp`Lli$~$zz_AyVLruMe7@gWY4r3z9B6bY7Y7oF&k6yO>DP>eF8`& zY~v}3{aF$Nt;-ZGG%+3Gk?yqav}om@lGcTw75owPGil82PU8xTM%*cBoQ`vCdLQ(6 zgIf$j@!bhUS%ezEub#Q|K{E-VYaCo)5PB2i&Mrk)D+jzRy4y}kXuTxFVcbX%GUed5 z?!<1eh+T9_Vgr~x$^kFyG3DUm?zGOZXnl#i_MF4lm@p{^s}(UR2VX+xy5#abKuQko zJ0-DFNeptpjxrJ^Y2DwQ)*6de<|%2NYtjlraVQJZyVJScqGLNHox#UKp+gr;K^6At zzQ%#+_|^M-hH~KW2uYNrf5P~<OLo5iq_X=IxY#rAydd42CA5C1pr)gSH_1KOo!kbC z+*PL}HxcAeNk;{DU?v9jWVBI3o*!95-qVH}vOkPssLHX@j<`R7e_1&m#umBXuws-3 znW9VW<Dy}Vseiew{yu<Jf!VSW{taXmXL|klV1`IT$|$?L$xAdIajalxQ`*xoGmwJm zK~$7~#P_<2EvV#C=QrR-v)NcxM)iuequJ_<suEQx|MjtdI@YN*!^@cSomvr|NAVoN zb2jh=cpk^Y@?1Tj8`GBpQcRzS)EG=h#rIcX>hsSKECzOV4}6go_-AHG)u0GGTLz{M zbEL+=eY*#4!;n+O?C%tKv<ytW<vms?U|E0H!*>^XdBGxZOD6(5NPxP^4j{tII(tp` z@MTu`KXeLzs|?S2np2!0Aa%;soxsHwfp%msoc+m?0K)H#2;aMV_#Ys}iUYNs!XN({ z890FXNFO{j|JjuB0KU4gV5>#prcM-UL7_QSeB2wNdOqe_OcE8{N!)0Wn9zwtIY>y= z*oa{{RfBs$*`{l)Y}2n*<`<JxC!*wgsL0pfnJO}$@p4zEw1;@Oy9PKBDK(&u9Ha)A zT>cEo)g_Pn0Vyus4c}odAN&e^mOzS;%H!xYFqJYcOvf9l_FP{T(M&U<E(w3R6$!u4 zO890Q68;NFsf1H6i@NCLl~OOA7pVPT_=(g@TqqZ*m$##9=7pC!Jip?Zd?5zDcy{19 zfhPs-)Q%uh*(KK>0#dnth`h2?Yx0+-UPd!v2)w0x;QOt>*LDj0D^9Pgwzb~S%VpgI z&#?lZ)hTeD3{1WBMd;;)-3g4c2z-vB3n%?%CY^ej5uumg_UV@OLx5D)AL$hSQW>6l zX;%cKUOwBMzylV6d7TLS#2nzdi{Rb}y}Yq|_^Yh&iJii~#PHP1?<wD25TQP_qH8eQ zRIoF;Q;V^vy$8mG*-;E?(9z%b0xjBYHc1=?@h-x!50K)>U7bjr0}@h4J0J_P`Rc5e zAAbYsb~AmlTmMEBq8f#$PNkO5A|9&cc`QM*Vd_}{T;rtz%)`%rQ2_77POTDNcHudR zC;1|$b}OEpcslT;!kscKpm$yJ`~e`9=Lf;SFx!6poHERgrl|nWbPs%=75JJ?f$L;o zHcX}hEbSinYAf)WodSDh;I0aAL3aWpEdotssHMAS9qB;<zKQOZ^-ln)tZ(cT{s<Ew zJC2bGu%$bJ`z-?3b|UbIB+x|xmUIt4+X{b1r||O`o(j-Pp*0oYyI_O@oZg+<0E^nY zU`&`DLqH7*FfnujcB_>}N?|wz;$4JcFCfK{J3Em$(4-W=I^8muolT6XBdh~s2mQOp zPKMTDm>N~qAIZmTL>wA7sRW;KgMD`U3Ctqo|9T?S3=8baY<KbRK#98WvBoKeOX=9U z&UNTowYd_L1d;ba@qQ@I5g0u(WCr^^U<UVlnqr1I?B29QJb(*ecyQOk;D$ae^N~^x zz!TsX7zhVy^xb|=Nr*i^AVt+Fq=7Y=A7CT81<h}7TBF9DM$K6ba=XbY{VjhDGu$9@ zo<zwsdRJ;VZ<JhS!)i^S`M3NmKU6CzUImJJqc0gNgeuIN2vzk2LIsR@e|@lSyB%we z@^9S2)ssW#l#k-%KW^t7y!yCar)e-Titk?VX{-Yvebaro2CEhM+#~A2fz`M1;QXp` zcP&=KQH(3cd)t5XjMY!*@!sU)E6>v382e7uK8(Y6Meq8hS8{gz%Gj|VRlNsbcl55~ zy?is`Q!qo(V3O%ae#IlpeEN|_e3HkWlAIR5;s+EJnYMO1?eO-8$5imf7Zt!=Rnu)) zmhwgEsq$_XtYJjSWh(g4qp$=PrFg4<4A#c^hVbsIJWOra*TSX)UZ%$Adn<x5p57I~ z{^dDShQU1a)X|7N8q25G!M<G8Pb+N6^{X)1<HJe`%y}RcwAnK?0UH=%pR1SaWqqQf zebLQ*^dZr`VE6;;XekNs*~|=Cfu!B*o)U2@S8oTDpM}+1tXB*cm>b5$UZjD~XncZH zbh0lwf}E5elm~Y8)3kIgmzG6gD@wgx-w#2n7w>cV$Cd;W)>sJiO|z|YCfV0cvtzk- zPYgpt-eA|fzh8!&ijcI+jiS9qb@k#Uku_hVN%;UpE7hk3WaEB35u)tMd9kBN0ndva zRW}!KI?O-GoDQqT0c9)|<tB)PlSr5AsA$D6Y|5_WM)!ExpE-(!SywZB%Kh$Yp=S`< zE%=628E!GaOgauLx$NS^By@mUu{&ErJb(xAD+xkb21!GLBg*@DZ^HsKBX|M528^)e z=AxsboJlCK>wk_J+YZxDl6urMb8ha1qiSvrY0RX@MsIVk6@wfT-eY~S@XM2-E6e}G z4E#<xp6In=BG%Ut|3Vo*>8(fzaVrEkw2+M7tG_Rk*d~7W)ydE_urI27zlzs0ym}@E zId*X#0%K?PCGd~UPt9C0cgcmd!4?ludr5;MXTm5wrl@!nwG~f0?yll#LR46DIErs< zKCi0>UXjouFs;qBD6bbuuV$4Oyd5GFoc+^@kl1(v<x-1JEX<7*cjGI3Q$Z!Zkgzmb z20VmW=@@mkdi$BE&8J|;w^oQ{NXLIpz}|pobe;)Z0RU!jan1@!{P9uvjmz795ZO}5 z7eH_qM>}d_9$@isBL+CV0>5VRig&>`1Vc<i0s_Iue`bwr?$+6DlXJe@U+-8}zN9d5 z=`v5^g8569B$kveTcGxRH5#(n6qe0h$);>}5~4>gp=3dblr_rUa=XQ?y#V4u8>D~r zMivmpHHVdC&7%{pYfiC?=bNP9u;eiR-OdBcII9i|T&OfIO`C8ijJ+==L&%_=)9kp) zqkI_e0m7-xT-aXkKx@%QpB4uiF#5mWyHcol+9AQ%3uP$L`^U+wCh-gl%TS^ZDdVmt zD$&>6HHA-OwR9g^F#2A}!VJrO6SWF*FVEyo{|AOt`O(ZA+LA^UDJ@arNO?mF*V7@M zYV!K-&zVo$xx&-tRoJe}hP6dpd4$VYO=37>Y4v^!rAeco7I6_=vZ*vp;y4rD=!Mc; ztd!;=9+qu|Q-so7M4C_<sCtX&KwzaZZ_^hnftV`u(?qE<(eT|_Wlpn-cAe{MXb2~C z!<vG!=@1uloZe{4mlFT0AgAIHh+$a#@1am`Mcy_28oQ{%R}bRvKRr_Xov1xKiT{<X zh)wbT32dhLA4U?D_#XuV@&5%?DaF5>>(<EjO8MI;zKn`cgS`laq7^AfNFexdTNgF> zf29ZSU*4l0+&_Wk(nSxd!g_Ga-#hEU^<h1D`rrR|J-8UM)RP_@`Q;RP&<pW|_25m^ z1Qe^sSZanIG@Vipb{Sez&Qd*v9%MWOJ;($nBlV!VM?F~gX@nlE<T{Sj1IK4d4`LZh zCp|b1E`}cbz=TKY!Fd;V*8{m;Z0bQ90{5&3-{K4^nvN4#aOtcEXIn+vRS(!82r=*{ zsb|u1vq<C+yNgDoLv+Pmkj$_~tfrh=8c~L?9yDU}s7Q^t_?s>o@dp5wMjQphsS&M6 ztkQ`0fIuU@X15g@u>kp^M%*BO8_}0J8EzOpK`3g(g-A#sxc>XD8ll$y{%hMH?`*(6 zQXX-aC$M<J_W_(%#hEmm47(4VS?geySHedDuU0V6RV|fZBZ^=N!MUyI^(T2(9@RXj zvnKVR-Q&Ui-sQ3S5It?8xEykm>^h8=r7oB(C5vW^MwaKI9g!~?`rJl68XdAexHTc< zra@)ck2}hRU=pJ(io@Qz1el?S4#n{byZ@kq+TNHV8CWl-j>J~Zx?mG)EomWXL~PYt z@`L2@Q71oIu?}1>{&hd4=74wQ0ap2S@>(<9b%5>Jk&h|g``MlyM4j2SJwu_G*hk`e z=sb1;JJ6o(M|+0;YQX`vXCu+2Kzrsudv*{zaM7L}q@jblW*3(_pGK06%R7_-n}gyv z%_#MPMqe+pZf+hC+y!~T_K6Q6jm-naJNzLD>r%7b9DAW(8XAgU$NZ(L15oBk#Cf!$ z(uMOE6aklg)V4fT$Sk&(FJuw(#OI5c;Fl-Jv8%kD8!bn8>{CX{gLc??!!zY0%ZKW7 z+q#xXGp@_P;Xz*<?(gCrb(^(E-Ry5P8n<|@l*SVtb(mFcwF_5E$?kAJc8<`FevV(W z2Kz=;H*Cp2gU^VTJVfntHL~FzuFphYxIwgDz-$PJ<hNLIXeP|gW`p?1a^PA7Bmn|7 z2)#cHQAU>c_JRa^#$1QOun0X1Bw`K|b92nt)@&n^s5G<D|GN|hnC@v5m(W+IUa|WV zqgUK0Mkq%#@V~>&V+~?DQi1ZUSTRy|iA4c;9nm2^{m{u!n(Pq2tD^J_tDX^sa3c^7 zMRP8^V?|r_hmUehaeS)D#C5LEpb6{-bLF;)TMxieJMIsL0d7=q$Wn*MXbMGaAy5td zpCDtR7Ge~x)}F>!xLSJ%Up-W7?+%Ns)~*&^s<rC?Sk>CV`&6~I6J@TdwG)4n)mq%Q z@P)4IdRZuKVgr6nSucJHzER@hS|lJ4e5IvJbw(NgFLjx5{|>oyhtuQ|CNi+qTRZ}a zc-@W(ZlhQD0wr!`hq60z9e7nS>B90^^aGJF{M^OT1Q#8sSiS9iR&xLIr45ewS*c8C zhd9AHTB9XP1fv$JQQIs8tCr>)#h2fm=xT=KPNa>2{|u)<un~n}bmnKz#T*2OvDi~s zJtgV!$7?xLl59&V@2mC_Q|r}U))d=p%m7&X5iNbwadf1^uvL<Jg~<cfHBV*mi`y!^ zt6)vIN-i-gBL&Z%Z&votU^xJ74m717HupeNMtEYw22|8-yW?>(e1sbK)M3IS!ucRL zU^Nx9ETS_=bf#S&Trt^RJ{}UwDh5}}PZ?T%7LB&R@LL?2T#vPQe#2|M7&;r%Y_+l? zKoujmP+-^eeE_g|q7EmWrcZNfS!r10!?PSuHJ(TDyoBcsJV)>x$1?=}=+}IbBHm3J zrknXY2I2Ugf(P{*MvUpBd6^Pg<6oOl;z%Jj64i@|1xVx&nMfD{T!-5Nne@|%{t97$ z|JYXzupdETfG-<hTRy<|4e&Js{EQ&C-jXo}_9n5XJ7X^sQwEM&KQ=8Is1#^3v3PbH z!vDK7E@lA7!6F<ka@%u5CAQFb72q8@WJN?cjKCCGO}AoS^$GS^vKp1=<H$;LVua@l zkdo#|Ie8PERP4q4J^RF_DU|dvrjVs^|Hi3>>`sP?5VETWcM`H?iYQyKAAf6-{15ji zfca9yGCPUb<<+=+N0!U&$P)+A4|KqDBU0c)ha$F0b#7br1KjJIC2%8U9V$;)iwl;q zWaqXS=T;zoc>vZ`xYE@E7=ASD-RaHyRIT0JC?o9P(PDI{+dc5{0-gpuhw!xG=?#1Y zp7Zfc!IO<=9-cqrQOR7Ei(PHluyo~UY)9kansuLImY93*lzR@`;ey2^DLFE0$rkpS z<?pu&<D!w29O-dz7`)f=`RjB^5gu1tSkT09zC?!1L?MG`Sbcy^M~O^U$iIPPDrAg8 zuujlCx!M$$d-6z~{1%PJP}e0YziX`sA|;0g55ha%RCBfaD4MH&2pVp#P6Q#3RxkV; zeD%;=odtuf;c1yIpLc1lUI1V<SJ(VSHCJ;`XR78Z69{_Y^S>r-V`4lVu56y_5MdyA z`d3!Xt$IKId;G~cLZeHB&Nk;r62#ZcS-VY61fHaDD|iDMKYe_4T9ke(E|tEGeH9uP zLC*xUVBA-J1EupL_H_cHImzq<1+gNb`Z}n=+1D8%XK)@TVRUnjvR{rXh2>qHQL)To z&<8iOoAc5EId+BCQo%NWEIJ{NV5<nnc5PzOyXfY^SZ=%byXdj?*lsqqVbz)GzIx1M z1jIu4MmMa?^8E++&Pgjj!Up+~E6v7;n_$}9{Htc}j<W85^dst|$!JyXZyZ6npN39F zxZI=J#jwi#M_D%ArsK{Z6j|=uKI>BMI{;YazVI$p?pw0Va?b~Xa$o!<d?Cj_f}e8Z zt-+GjXPcZ}#VHiotL(&SIil&x>Aww>oIV3ZW^y|79h1{zKU9TyE=Yra6Ig<h+rPkz z!R=mS>(e87ef%uxx3A^*E%-HgJrJ2G42>`JC3fO9j+#ndU-DshUS9)c5RXHk!@T|* zzQVlr;j0H7do?DK*XgLKI?es$0I+y{yt*r|1rYH1*Dn;WedK5W^YMl{{cnBZ`O2>P z^fyR_sZTSbEq!vb%Ah_aJ7T0ZCBrSOO%G6;%(m*GGg-(S=01R(7U-?24w10bi6_G4 zsKG4F+ukxulX^1;;h{H+vDBtY@^^1rCD~nXE`)DHm2CNrf^U|kvWNciI?TxUza{-v zX$bEeRHa<gVQ)W9R6<ZW&DbiAGp$l^>W~^L-LRY<1;HE}TyPKpx+q-%v_m|E8aFHm zcj7B72o?D1K@eW-A1MfbJlsVP(g0Y3@V%}CA%D85be{o%AhfYcMowC>cu(b9jvNK= zQ6)pZ+7iuj>BZTa?&ZQA@}0`%t2fPZQ98E!3|TVoFt}vZz5A__>8fLYg<q7*W0v2= z@Eb0dGkhqQvyjrB%cTWEt;*#(i@+EVV7dI$-D9~xL7P|^-uqtna(U(7C>I-OhRfwA z)Q{nE5%}t%Tz=CpvRt10q)WN{6M$7Nvmt4miVBy@G$1IKIqdYJTxPYXa%tjjkO)Qn zALBCb9*$4C>gjjPjM47x4D0Dbtav-Odk=Tg)DKw3M!WZ)-<Y-W_uOF6y*6Gz!g6@8 zTD09N0F<*%253=ZkpWYN%4TvRyg!eIxkIGhfzow0vvgIP$p(0+OeX3DoD$$4yQ%)G z_DL~&9!ptAMJX;6P{K9o4NJJXtNo=&3dGB4`R)(jW)*%Qw?_#vHMa~VqPuGDgNGm? zM^I8>2|37evzp6#eDxq9C;CK6NL6DO30V)ol8{T+DhZiaU~29;Kp-KLS<&OP`ZSwJ z{vK&-MOpaRi66?|9@c~QdUx4y)PE*cr|mo!c2o?&&IBs?Jt&Ca4q2$w@kCr6q2_Z= z=a!4^MOtI(xK&+$gKG^{kY>zwaLI^Q19U0c*$AeJc3~BYc5$$C(N2alyR1kmQipx< zpD}VQ+BV9o*$+n)_T3G#u&LZfMHLe%YmzJXT7})UCdotsQPi_7zh}U&S=2l7dn{_R zGFbaIBIr^{Z~YiW{WDk|F6tl)z$)rP`0Amk<9bIH^#dPvDe6Z6SVf(=rfX4827;o_ zVO5TtU&*C;l;8W{c|>LKKkEWvtVPnUDsJqCIRsXT>9b8Pz$hQh8epmX8{`6C+p(L{ zm{<v^2EsoNzQwDMXI#L|`*-78F_VfBXTDU>R{s*ZKTLO84~M($kK7#7fi~0Uj)BLq z@QAUM8w07@<@B7v%5-mroWEgJS0H0*5gF_)?oCB9)YQ&O1Ajdrg`nQmtnrp6^yF>k z&YSVZ=ldcbk^)soldGJV`$n7HBKk5}eGo9JSzXh8pkigSnvA>`-HJ}Bl4F#JRK13< zTnl)Cr5%x~uYr4c!y)dYY7zI+6`lVTy+SGFzhM%It|EE><mLR9*oGjyuf3UjjJ<U@ z`_v*Pp^>3iv0G-2mm8_wM6v6ipw_()M69Yurm%Et!_sYRRV8s;)7~O}2TsLSdH79& zxV)rQd<|K_@Oc_c<@Sxe!wom==)P^HQyV=C!(TiNc&^6tFtFF~G~xLRzE!D-NvhOl z#z6h7;tR&8I9Tjh5G3BkLo<i5vfPW&#UOimeR$X#>+YD~>&lm`$fau>(dVqNnU{1X zu0q{)O815oCQQSCSw>xg!J>>ByEM8)&8Zf7F^J66OvcMg#VDwC=)0dP6m3a&POUV^ za2?DXU&B2qu~k=byG2@@nD+h&Y(Vm)@jV&uET6Hd+*{_k5X#jsHGVH9A@Sy$YL~Ia z$k<i-nJAf8(CtHmf8i;<;vDD-L`WS$`xu>vKydg+5G2dsUx4~gHemi*_TTvqBYxKV z3cTlT_n-ms-$%upbGtO5C*3(YyI{%uvNHTi8ziVISoaka54p;$9x86d^(ueV9VN(1 ze<U-nL}VcadAh^n)*Z`X7Pv#drve1lIaY|D8zHM%9cZSvB;nYZeK0l#odMtGK(lxx z=yERhThyq5U?wWS=2i?qFcW({>V(y_M3FKHD?i*1G*ia~@_Jgaspq4p54am1HGv+N z{1LWFrNlJb<>sI-C)9z8y7Ru(sPEcP*%_C^7Zl%lwV59tsKoqq6nKf(h`Hw>QW@Js z1G{Lf5S`|Roi=0Rg0UZ=*DhJhpelZdUggTfK<?M67cax<%5tn)w22DkhJ}eqC|^Cr zi5u^?#bf^+s#~njnOk;H^*#Rygvi*lQ!iGaE>P>Pd+87R4@Sr>J0u~>KmdKI3WjKh zpuk)l*p!8CN;@JE`x}5aVm0F*^iVH0<HutCy<h=yEXvTq2n63f*kv*W<-d9lj-P}K z_O<)wwpG68v3vKlijsGc&+pe3khoe}x_OStPvjdmncq1P@|DF^g~~6lzL!K0`7>{W z!}5c%{ssk({8Z!Y<)_FY5?t-DiA&kp!SC0vpaOK*n-k%V<nIjo7;5-<UHLFOfVaKI z05Mn^fcUSn@^~APh1it3JPpAM1O?Qwxmlhs?O%8oB_4CMF%b=@+WW|jY^;Bm$K-fJ z+KQ2wVL{y+jq>zsXG4_VMQsk3Q2AHH??B#UftTW?@{p%5@_WYt<fWcssP?C|gORGe z1?81?Nv0O%hr49hGQf-xB;pdJ5gGn^C$nRtAru`_3+byD129E{EUHG}8swLH0>e!< zX%h;I7FIz)1EDEY+xod?u|!1IOGZb|LPX|Mc<~w#JJ|b(7E7$CZN6KL*jitWSn_@g zG<mEx8U6#o``<HF7CI}}ID1M*_BB1E<IhyEMk5^`*O}><pwe-4hsgrXN=I>IItoCO z>3HD-rsK5#Q#ua!l#U<Rp;GCvi|JN6o&jC(V~&-MXr==fB*B7>Y=}RB2wIZ%g^`+b zWNN%n5LJ=M0y-sMO0VsKFV}_B(;;@DpjG*dQt8<bBdJO>dc%PK46dPnk9h=3GMtgA zx&`#fqr0Hpf#5fgNHbNZE~`HCdPvjT7~EK8b%B+pJ3tpanq;LZ%1qPT$TV$*Oj(>7 z2>MLZ2`FM9IQ##UrVTx%X>vGCc5y#ML-FZ9Y;U8*rtK!5`gAF`vm#UTpplvzWoq6; zy=8J}w~cM!>OD9rE$hI2u)xJ8#89nEu{5YA`Ks@w7ijIieXQa5A@zg2akW<$bcha= ziBjS>a3V@?#MVVv1=Zg{?bXV5vF5m}ry*4~Q3-jocy&1<0WDR39fODmf@7G(aC0x) zMfL{SDpnm@G0cJP@Q3&oGm%a4Es~UWW%)PsfXgXZ8_D|3tjV8v6NyAsCo8Y};n}QE zFJO_T*-)27){^yRcv(Hxi&dy?ndmzZQq_NWG3!5)W&pkJdTn~H?}&GI+-&hBD!kcx zd{WdNnC<cH4b&Kmi^EpMd&XViJ=U*ul=qm;GmL*uYd*_+Y`AA2rjD=y{aA7NkgZVx z@A7zC?89}|FYLvbGzPC4A!+m}Jr{QJJ!dl9X#N@AJjQ!$m}k@#9_%4M38WO{7M_Zn zUdN;6#|C&tRUGT>8BlSok7vZmH$1(YN14(8!-ziOmu73~ATNhj+UM?$G4HV0W7Nre zr2V;rzPSf{S+rS$MPgRZe=9a+h+P6$xxrr?C!Zu91ow4!JbHSfm~E{KA@-X^b9XHq z+pBr^9>zy-t}fVvFY(n&Ct<??#n2%B2;n!-13=}jm#=WZ)I6b&v8fAdTarTGFojL< ztIrkaLTRz<xvpAWfC0-vv7Wf=05^mjs&*ZS=p=nhWpf=6@4XBk7=|PL;?r^nMQg>% zL+5x-!{0M;pJ}~#3R;1w>3pnz^je8&UwC|eptu@d#Wiwk2iBnv`%18|dl<DV&Icd| z80GTb6PqWlc@_7#!rYJB7Q$|fKgln<@wEWtk7Ktk$j_4Ga{=@-h#KTBi6l3wdHjrO zUIT?)Og1$ddo>D@49dgdfc|&b;c?}ly7!oDglbE!y$dxoIK1>lCRM<^LG1dUA>JuI z*WL+-4Awm*9eZNk3s7g7)qkQq5w_}I2uohBA-4@)-tFmumvdESQ%o)ng(s2F2!#cc zI&txj6cyKgZcRDtn+o~bj~qjkyslPTvlDDO@{tN<uqhV)XGCOQFW4_0!_WY~us{@z zCE953kq%!0$V7XaI-*>yIElPBwh9YbCSz*Z%~N7iu#K@F@Na{diyBn)v6WRu9v>xJ zj6D9cjCn+2zQ;~loEEdB<1#pi6q&*%eQuKvH*;Zvwn5C7;%LZ5|K>RKBYD2zB5b7Q z?|CxEc$2vt1;QO4GM7y%^w|il_VY9;6L$XBP!O#RX;?}Lg&NYZYRR8?^^?FKs0)qy zQ8(wIQZ!zj7;hLiuESvrjz{cet}us%YrqUoABoMlNzVu{2IeVuA@<}}oNiI%7-}*g zWelrcq#-RlM;cqXmz-)4uSof6f?B<gMuIn%Jt<k(q{rc~$dtaGm??Jb7E8c(j(+9K z$My9Lf}xbt@mx4A*7L{anb?^0af;2jZ$VrQ4mUf1{X2|JBZhg4CTvQG!KMT|_9cjm z364B;K`n|7PM;OqKHX;$83s3C;*Ag3Qh~3{!?AU+-78o;Sj1Nvwd5oVze#L@FXL$Y zNTnH4=(i(ZVlCV#K;<pSsUyIuq(h&y?%EY-Lax-Oafmq>(uzo?m7q|?(Y<K<E~cmP zGxRi!H`6%Y+@t@kf;<U`wVdzG+JlNx4ma<|B$L>RFjjl|FtSta+9Ot>Z9+w++SR+| zM~k=~zk%T12E>8A@*IXnu7hD}NV@<#T_ew4p?1d^sbiRpd0kBW7i0`J(a_Lh%f0uc zw&Hx%4!=V!kXsY6kqFk$Z2AYn`xfS)cu>kNuaEi=37l)R&9bj(&d~{D(q372S$e(M zT)^fdJ3E-8%U~-D3y^2-=Zr&nzk1itTCiP;h!8OV<$gN&kYiSBJ6-nk)QDDw{F)RZ zw$rtWs27awbV9tL9Ifqiy)YMut-IECx<30M3&vO#L)Ui@(%MePC~>bTcj3K>aTdm@ zjc;-{U5nDb7Pf%Xtt_o`+1=ne9&VSHOVjx4W{+FgwueG%T|ZmJI18aTPqr8II9YfA zzk%SOdXyY2&={Kq%HfH&G4DZ_BoO@mbvWV_-Oom`+Ks)E+>n`feJ@dks{LvXroexN zVO-V?ixP9YVbLNZ0#ke7exY4j=I`tqtRll8u0i|&1|dgoncKI~RtE$&(O|o*k?8Z` zpYtJ~LTUrSDKgPWu^dIn{zVu1-&yoQ5hmqgJY%5y^YC2WeA7%cW-t*KBUUihf{yL? zk#7Mp7j0wnEX(y8!*z>t{Uco`TdpaFYn^gEldhvJ*Ru@QO63|2S1T_+8F?8j^HQ>h z1)%a`SN)^B8D=;1j9rjHvm5#?%&6+FI2^u1+I?wptk%<Fy7xp?KMNDTVxmpcRKIqn zN%5^ZP?TpNWryh1S1}=Ra|~*RVs^MkL7Q<5tqaWtsvyptAtCJ4K94X6Trd8P7o$`A zJjt?C%kycC`kNr==5zoi(b$H4$jOV{&w<;9A1ghVbxzNPAZhmJcK;K)IL+p}+1_({ zW*P}H=OTu3F2W{m-ijJ@5a`Hhh-N~Xnd0VGtQ2c9#mt#rXXXv37ID64MvVBV*2p4m zfYOXCzQg8F_1jUunfzQyG|bPXh(Ldv6)khmw(=D0B%cg^UWYJ}pIPD5U1vsC!$krl z0>&Q`^jsWebdUDA<B?`vz0}}$*RhzXyN<+&fvDF}PBX!9<AC7rk$c^CAKH$Y%1D%r zMxuJrNK_x3r95UUAE@@1HQX&8#3HbqBz%+oAMhT{OWJ6eux$_vB?D%**MOszV2*h9 zWT;k)L!)xX%Mhou_=dCueo6ve%FZl*nfcq)B$7&HEn4o}|DH-%;r$T{=dxhm)Mq51 z?<K||N}0%HB-tpcB&JSIF`;a$-dh<H?T!(+*c3y|=DvbuiZMGHoFU?EEcT&~d2gLM zYx&;F{`86iOj>hq!Kq@y`0u$`VGh)Qlyv9p6x;`f-H&`n_hffWsWjAyMHgF5pawky zGYFR0(7O_tXbc%7p94wWnRRGf5+>THU*DTa-A1ipQlF78`r9h8vtb#-lvgyIG3h+v zI`MYYT+eNxYUu~Y=EeK+M#B)^sThe(gf>`MevTaiN5WXg=v@M~ZF=3-7et;%_Zj4k zc|IBtcZ^08ejs{AymxnB_HXk>C+8(dziZ$Z21}zG;DLLrzIp}(Kl4q{1B~E9)YJIp zN_-%1y8f}rgu`eMzy$PeLiM(!D3sO^m<7*FvKcIygA6v~`jZGK15m}3B&~ed_9=hD z;%-!}Jj{3mhDOCVP?D?6J1JNg`L~o5CEmEW?8f<?1;zM=F7T*!V{+N(mBY5TMTCEp z;h#l#ZW=~Lp!fqh-Tmn{NE6Nv<7~4J8>Q>TivZYtkzP{aMZa})@<%IsVY(weNq<LF zy$Dg8k~Efvd1KPO?b?ddSSm5MN5A8Xxg9{L{5yt%ao5{Hiidq2@xHPIc}^Oo8^W?O z&PJ5XU$EG7OJZ5EJSllyQR3y7C1w^aUF2alv`8M_2hM|sf58uVm>0pTAl8lzUKN*y zc||*{Vi#26zw;`hoF=L`F6beS%f7eb*dGx`F5{T{zv4h2V!9~{2e8`}`Phda7&eSr zi2DX|VI@3NZm-TVRb)T3iZjwI{IYO{zJx_j(Td6v&A&7aNIv#h{t<bar{cr*?e2UF z=V@a^G`BGtAENm`^R0uUgWlpt{B$jw)fgiiWn;s|GNv4lWE|)GuQ+7icPpfs=eW1| z=5EzLUR!X&m@N7G%~n^+RXbsyKM?{Wj#1Wd&m+1RJQ9i?*M7vR=H=w!f??Zh5zb7; zJupHl9^T2$f2+F~_Htn2i3`5P6aSWh9wn^s;k*--WZ3q`h+uOVY!QN4eVg|Y3wx^K zFEddg2JhK{&dqnwB^S<!a1=f_#^IaWRI%~|Rz4RtxY})615CLi#SN~*=`^6(hiEht zCJi#a`ULyqI7L%Xe5=eS4+`jkT}?JI>R-rWtFIj6%9s@Wz^)@UY5TnO1-1tT#Z$uG z%VS_QX#FFIMV|JJ85_{squG_JwzV%@JxPlycj$rWI=!HAVS{Zqdcdx2kjCox<6@>9 zMQjrTF!<5mkA4q(&3(>y?S^kXe>dhtga{&$uw5S}5tHJtgyrX2w1Jv<2A$O&!a5OF zMREiaO^)o?s_P)dSd?*ByK2$Xx8t|bjZN|Gsz8jQ;6OkXM}q1}e{z#qt|;&18E6CR z%9pG@(NF7DQJz*^uuXUE6k{*~K&Jey;E5QHS`Q!Y>VmDht4_qgO)uCwON7{HW^FS? zqGBk@R`;X)PA8RsSVcQ}VfT4-zX9%6*?*3dAU3zSw*ZyDtIjRf%a=WF;l)cJShXG0 z{%!epAT>J6X2tJWE(ZHnPuU%lQho*s!@B}yfq{~8(7`atRk0L3W}Lx(J6!JA`h3oF z92lI<7@o0WxScUzNNAWI8HN!yifaan%Pm^-jqc7dVxK~40>Pu`_BF#IurcV^gy7Y# zt!gw}2{8`@chg5R+BFV=t-5D8$~ikDGcm(F*Ous7zM!bYvv}E3xqi%hV+xkuuyonY zOB1t-JjKfj)w(ms&XW@%{3-FI6~LqAFL&~%)4zqlHUnu#r*ho56s_s}6wN+1MZ53M zDEmVWZL7nfHKpR2<<M-mz>d#l4lVryhjw7LLrcUr<LB;wO`}2bP52$0@6L0SmwA@m z=q$Rfe35H;(E_ylr}}pg@z=p|Jbt^zU%T3A#lH#fX8dC+omwKE8elPqEi#@#1M}U> z$`+G9&iS7C>`s}9V-jlQopj==*D*u8V*?Q^9Kwc3C^wPgkeLNMiA0mCRqNr#-?jMF zt7`C9#5@k+t70e-g;%=XXZU)^_}z%#>MF89+zA2Jt19t|Nh{1$u2`1hgDH*%TM{6U zlrHf};;c=e%08E2H(*rSgb+GDju>Hwi~lGXBR<4n4QD9@(K}f=Va&5e{@TTD`1P|o zfFk{Q3)%-;QV9K?^1mBVU=6}B`X3(rodub+`q<OK4CG~vk(V__Ue;^`&FVEWFS{Z9 zX1%%Q5!9P&n0f{xd-zLs!AJWDj7>D8+qZ@+Gm&o}BSOyg+-H|v_IegWoGwX=&0CQ| zNkjZyzDl;=jaSCT57{&S9BDUt=IfqE2x|<0;p8Na-f(ry$Z4nou+TF}y!<F;0@K`b z8mO-$r#$H0%Ozd*OZ6J&pz1vj47=E17pN;{H?fo{qNELT9}JT|Z|oZx`n%i~Fei*f zzmcl2bOYnK={Qc-D|0>zuzD?fbMdq<G5Yr8WSO2!*`aGu75f8EBQLPuWAc3PM)1$U zv9x6HKadZs)tjF+^3#Sq){9#BRK4TKJH4@xhK*;f`VU6K{_HBNX2;APr5{y)#qvx{ zf-c5L?={tI;(WWDh;_9Eoj}()FAq&SCj>T01I51ugsn}pS2(pB@$AEM&Pu0t5RdmZ zRF0n^H78N0B{#<26%W77f0z<geh!;{{mrrOK*H<A7gP~xoJ6mX8kP;&s=hVK0k?n= z^kdXy>zt>v?RgDOK~|ZP_M?V}S^z!Jz9WLRl${^I8H4sBBk0O5w67uUdXWz2>Y29W z-LdPh22zcD>j~U!RGEp-<hkvh3w(3Al+TSa?~D0l`2l`bP%Fehj6q=Ona7J`D@P)P zx4|Y;+=}rexzPt$^CjTMS)I7?0hCN~qm2_Rj&O2ojc~L^Yp`NBS@9gck=*;?Y$SIJ zkci~|9iQEj`}{vTC-)k3#jWJ>gpHZpR3qA%z<NmTxe>{=iw&S^aJQckjz>Qtlgo-& z@<F_$_;3>3YCa!)7{<P#B^7Ux{kKLnCr}J_8h+n{UxV1&fFB2J<e7$RBJ%tcKAGq9 zB8%wNhdbx_dUVx|JbP|se(Ob^q!^dHd&Tv#&Q<$FGSD<*Ku-z4nO967bBmu112aG{ z5QU8ic<IX*J6;CxCC1wjhvgAe`jCzD{*L}zf64}xtT`4D9Yg5k_Sie0MH;OBz&0o( zghBNOJm_Hug3qI_Gy4O^ewJ3FpWdolvz-YQrY2(!6aBh&JnZLzpYLF9EFdO;AJ83X zT?i|nM*rgs1cN6Ll%11ljH(r>RJ{+@ZE{?|vnCuDv~m-TT0dQZHdpoaxd)UQAm$^F z@-(@j0LHTTSq`*grcz*^&187P^iiK=SCgmDgrBBeS^hby@<=1*G{CtN$wdW8OX<q6 z8_p}P*8!3mY%aBlA0Co)(y$q`z0{3A<+v;fdpYBMy|C>R9bf)pD{%~dVJm8wC_o;Y z&(>Y>P%iGnhF`&79uDF!!nBI<@Py5OQ$dO+5!37#8pw3uI<i&}$%p&2D`Tscqe?s# zDTI&QIOqkd$m1$BOo8AR|CBs7j}XLRK34Tb*1*U`y_bD3jdPsn3IxQ(Sb>Yc<eCTZ zhi8XE6+6fyR4sj}PY!pomu;{o$0vWmQZHLF-7EVS$`sKA)uoV-c>Y1~Pg9|=SN$X9 zQ#=S*1#PyWt8qY=WH2r(<eD3%De%9f7Q3D+ii)BwNh}~ap}TC!jydI6D2nrW*^%H3 zvX?yxPAGdf;-%Wlu7q9ydw1-)1jK2qSEeAYmzr@=nhM5WqyG^RNK8eD=F_}8wt<4? zIZY3Q?%`|24zexU^Oai4;W`2@RrUrtV7)EHtq)1QeG5Fm3I{&t@pCJ~7s}7(>9Ea_ z>%3b$(n8a9IR1^#gyc93L|1sj<Jb3L6jXfrEK+;`S3v0#lJArxPt&i6;Rgvy>lUZ! zFeEobznehvffbMO0_C{@*+)MIkZXBK(E?9VVPa{Kr@VA&;{3wG(xS4m#QC1YGSB=4 zHzZy+zpM!UIFFGBU4!PVt6=W1t`K)}Z~2)3>Ln1}JhVWZ1~G)0Ph2i!!Fco5vNF^> za=osCd~^fVD>j;MYgN&7=ryt|<}#YlJq*PCp9X#77jw+hRX<1Jy)aMg_SG==x_h3l zh8a~ZFv5p<Zgc*&elvJwE-d(99;JQ_1(s8CJ?v{4)IUFS+5EzyLg$htG4zIqBMBRR zVIPq{V$&l~Ak;}lKgz!qeScJ>LuYU*llSq}N^eE*rZ*~APBh<JfJ#2u=-)|L906qB zc!c?EB-3Gci<0-zgWf=*0kH(l0O##x{U`0)q3?u!tf&H8!n;WN-C@>(sBMj9!HY3W z#8-q(1Sb?<*2D#EwMhseK4KTu+S}eHzMvwYhWH3U<=*x-wc~yO{Q=M00Nuj26K>i! zNNngrVxuI{A~tj(u~*`-JJ9Q=#!+=YH^M?#gA0cZL#rnIgo7jgxGIicvCapMkcqKX z)M_5K<N1PiV`DcC0KEvfV&&JERN*bxOw~7NE!-jirokQ`>d#hjNFq;31hbwvi4rEz ze6wV2Eels1=iCwcwVZTDrMm-ag)IguF>f+CpXY@_=n%^_TX=XIxhjv=%j|3#T(atI z5jQfn8Diagq=l$_v+NLp&XGpm*d7Pgvu#BmR1*n^G7y~c6zY@kjxIQWw%o&wSJn1) zTMw4@T<kux;1MxR^T{(*_p&Bdhm>InNA2?5fo>JrU7n%33C`i=<NmBm3Pf!ZNQu{x z7kw`rRlyJDr|I@oXSbhN!kABZ8sSZ|F{5R~g1dyi1Ci~_qN23d@V$bu(Y_0Uc3zKu z^&U3cXl8|&Nly{$(QV>SkUVMhP>9LO(OQo#<)O`p_2`?P#kaX0-6sBcZ_n$|JnM<| z=ydqTDtLso!{AzzrR!YZp}wMZ7fwZSJsM*?2*vUTuqoy014!cmesT`f>d3SrG(~Vc zQ-R*WB>V<~H$92+72#9$#j#*ESEhf#z$y@&N#{swf}P7B*Br7M>at(c+Q{By$w1}4 z^6BVuVG>?Ud<MxYXs>N&seXsHo~7EZ%3=yXO}F<uyCw3ICWxYxp3=k->h%HGRy_uC zi!Q|w<CQZ^9ikAK51)-H{#xb>cUQ@Lt$M=B7q%%|=MoH=R$Yt#aO2}%?;D8KF0Mn3 z082(;J4Q51&Hq@{%I(avb+dG;v)YYNTX?#&UVQLQD8zwm?0R-U*k;L1)9<0xU?;}k zcn0PI#-LJ0e&)a=?6mmHn5A;|Q1zME|Bp0xt}ur{)XWOggNVfwl)Z=w^Lfl~ptQkE z@d6kwd$rT-p{x!}JmW0Lt+Iw_7o+ZCz1e`a4fP#PN2m&>UJQ3LX)vjE5$c$)xi18S zt|uYY5G;BN<T;AIJtt(f2v<Q3oBa{8G!H35Dph^57p+|&*ynNhvFelEXpSQ56EGf) z;}BeaJ_g0*-;3~QX=WfXWcBvMbpQ`4@b}wKDzJk-g#r@+nrl(i@WLfaBz>B0Ey%__ z+)k&w(3)|^0>c-srIwdW=jP_*YI*)WXi>!@2bp{Sc+Bo?pSWJ8;gWZe&shYV3V0R( zqmuNo@kDdvy5xo2q|H_~E!XA34{oY|3?#Eb(tr3xgfBsOG3tFNUpTC~jT=>Cip_`K z1NsOv)xZUvPUQa<-kHhf8J#wDr|=>P0ij<58xqFEOuWNwUCQXSq(>vW{PnpL0(pM- zQ%KM&NCEQLWJ}eyZ>*Mi`~(L_{o^$NwF>wgc`V+GcmHxEdcr=W<#O`D-3xv&)??v3 zjzGn2^iyH_8OdPwI|1EiLVXD(0@_{&$iD@D5cYe9okWj&O^=@va?@iYJswaV_X0J` zm1|6C8QD%pPL?|-+a)imC(pZ<L2vlWnVId%#V_4Y!>`kYTheo8TS4;-xBmEz1nHmi zwHD^UW$^imPA44caLwug&&#)DfwU1Xu3*o|PRrqXs46cxhv(}f%Mg7iRg)MybGCs2 z#{O;86an2HnvNrLJZSMe^v9~wcfcDr<YWO11fM|#Vr*hD#--CCNAgB#)`xEBAJ?Gz z+-1@xMM*o!qBszaq<CTzDb9|d$a5l{(m2ba!;L%vv1uGlxiF1`BGY)SLGdX`v2O%L zHFoZl#w}=Wn8v3q+A@uz_Tr9kuK#6FoGB^3xG|h-?B|Hk8*(k)(i`mIyyFc$A(WR0 zj>|r4r?Vgi<Hy&S%t0lt_=6xA|F$DvmmormQ<uUg+AZ<!W8~EDtW=;ikveI`H(KfK zC;myBpmu4HWWCj&Qj40P@-NVWdJ&7(!M~P3jRJDt0#HL>qXNFcG2h~Cc;DXidWz;x ze>{cZ9N6AgyoYE)eHgs}sDJIN2z*cl-pas7=}k0*y>V|`aT`$o90(CqyIw3nw8gf& z;c*Wje+m8o%_164v>1H%$KwysOMzmTa+ZI|YlvwKoB^gGCV$N?04WOiJ)_QN*c5Qf z-=xBxVAO>~50GN5LcatGPAOfAhR&d_w(8bYH}0!*DmUsA+@Q!A+0&rF)K%)b1Gh(; zy3V@5>B@BFqXwpXUwlhd%}KLpW@P8Nat)o9;gyO@ch=weu32zZ;n{wmF35sXOOQ0# zO=pXemYb86mXV2=!s*LPo#D#QQK%WenPBrfXX+I$M}D5RE@h~!qu08J2G*s-%Xg7? zsjR>C^aNjj*cbC%VWZ5#E-PwqPT06d&&9f2jh>!J_oPVoMCqO+-SecZh<8z1sOt|x zOt#Ot2W15to)i<?8vvFlz{gTqf%okm6peogOAu$}uz9h#hG+%R<qG`+(Tzkm5M8U# zL!_{c=r*F875X|*tDPiYS$CVf;&)ySOCiiVXMsC2!vRhkWy`Xp9~VNAcXoW|WINJR zv!`|9xq(3_!gZ`za0#1ES;vY+cvrfq+RzBMJb%&?P|l~2R=u%!^9JN$+*?o<&y&!! zfcSVXa#l;U<LxjSAi9@mVT9jjf%+@R*hV-ZaOFM#wFFueP)4AYfOfC+aUFo-c)V{v z2=4jo@CV@z5*-87e;9yle0Krr#7lHJEM8KEXXa*5<SiM_bGfd>r~Ibg(Erqev@|w~ z<mCWhGK>M5{B`8GXH%}tu;jTrCodyEBPZL$WZ7k0CCk9-xA-f`$N7*C$eV3H^5{`{ z{0XN$iz}I%@%STi^B-^uxnZ1L+irfNfSuGT|3Q)*1d@I?32sGr@g&Ga^q<VWm)W+8 zvtxd>%DwNvUs>+BgTUwm#fSS*AHi*{l8@<Y<CE55mGJ<et0*V_gZHFr;@&r8UXE@= zm#5^fvSiL@UMldueLpi)i$5r@B#J`~(ZfU!Ds&Lh%|zRXHYv0n6wJErzvZ30VSmS+ zG0T;i=XRmWbEM;&ILkXPf3~c6tbBhoBAo9lN6LJo-Uv5~IDN|=<rL`+J<9NSCKoGl zS$2^P7lO=x<zJb9$Q;VDax?OuexJ<g^Yti;rl$eqE8r0Vlb!)ksDK&*30nYo6tIfG zJOY&pSW4g_0{1CkE`b&TTNIE<An92EI~9;jz)fJk0?sGUM4(XtBM6N7Cx8|O*a?g$ z(4l~zUk6a~9Dum{WnR7_u#-NL6z~Coar7}!0eb)xr{jJ59u%X0EB=6kmw<BdETXMM z_bW6Js9CPE4a;>{W#vfE$)&Qg?5I1=+|-%)k>6~eT$z~}?mT&ciLB$$dSvFJg)sfF z4NA+*$#K%b2uIn;%*aMtqv-HED~D~5`eqv38Hy&ulOF0#DKkt5<IQzpq>`5|(;@w! z9dsHI(+}$nHhbx=jA`jcd&zLbatiXTaQvQ`;mkMXGg601hu=z$<-Cz>%P_2@^#-FY zv#~9+vn})IQ}sqt&o-0C^YF*-!5{JJ9x6WRu}+F?2mI|D5auhE__$3dzD9aqg`s^9 z^@RWMz3}U&-=mMiuk8W&&Fk5(+3ubyt?Xuwi)dHm`jye<&}~c?x6y{1sk8K-VAMf* z{^fr|!p=m(pmT@oku>{*Qr?as-~RCp01_4OF@WNUc=s0~@v=gF6d5RX0@|Jq$nVA< zNa}i``9#MNov6^8h!zr!A)2Vrc|cA1mHit`IH#2^yD@F?k|MBM@}2UKH~*%h{ACJd zS+Fj0-B{we#qcA`zG(5HVvh<#_nC_e<wi=Y?3Ox;=Pz9(>5AlJSyx5!B(n>j#HGKt z>NfcM#2<4%SoIUwpts7d=*IWKotTG^Y4oXggIy&b14vT9$z90r6ukS_Bh#|KTLwSH znSi#J0P-)#AB3C>)ar+Ftj9@r@*vMsS~UMgl^^m(@xVkC&V0kh_D%E4!r$rhmll$H z>r#?c-|m^so%<noJss|&Jc#!Qc@e*ha7$Kh>r&<_I@6w$e%Ga3s=jrslOn91k|^6b zwUq+ZeLbac3Je14b>cDQXI;u9879xa{z5SEUnq9U+f?w&`LL9lufQ+=o=gDw3V5Xs zKtc|HB?{O=z)oO=0;ZAYa|qNZU>$uF64<DKbLgXyM7JuSm_8EeV~+x65=bX-Pys(M z9VIRRM-}in3$h*W+c&W^A7b$a#FGeD9P<yLbBN|E^e;q56J1WUP@%UHok(;8(F%nY z5ltt$jp!DI<`A7lw2^3&LjORtnCKp&I~961&{OnhC@)hvUcsOsH%CrcXw(C?1L+w~ z7k=b7bt@x#Mrvk;)0#i%T1TsIcWMU6kcQMpjE?eirlva3+cW9rrRP}f3+1xF9j3{8 zKF^gul~uht2g3T4VbVz$|44^=i^NQ0r;p#vha)oslP+d!pm6ph6|PzU`eiz2WaMQ` zMQdYz<I-__hR1d8)Lc1%W9q$FaKzGubrlVu05PpjvF1#~7jTb#4JRI<qQFJo7fJ^z z_E>(!OofFzJ?!zM?d~>*wm?F1Y>?-Vy9j#lR2}u8c+*A{Y6*&0)~cDWqOi9Ssx+ZL z5ZVK1`({A?8vH>NXA^BCx|8Tug$@Mjcdv#33pl}>=M@0=5$I6B0szG^k08h%1d(wz z5=ta=*o0mO#Hv~HQr53V|JdX$%Z`H|ezPp|Q>UWCA*a7A{sYU)&v9FR9I2R+auiSm zEI$%3%7}Cvkk{OtOv{gy0fiZ}V(6pqoB;M+{~8+G8vojfc)v!zV?Nhke10mkodrOa zng5|CxL=M>e@qBms6aNwwL7hLTGp)&#E6c~j0~5Q;dK>5vCd$~f`7?T5cm~*1$EJD zDjK#&C1>y60h*cP0Hi3OAE^2}E&$+GKs$ZdE(9=70bdhv6DU!@hmyv40F?@O9YFC0 zy!&gAP+2;YLH24?nV}H%NR2(RWkQKjXB?S1=*cObcGYoyN9v~3MU-7ujx#mW2%~fy z6B<T;kma4~$j_JoqU32s&Q$XB7bz3a1OFWNRO~m$r#$<m#<%aZSYsP;0`HyLm2a)K zROI13((RpZ!fs#V9d76Yb(;Ijf6SUDlXHLDKtj#^4gO2S9NE?I#@WPYYdA+XpgKHL zhcts`r@6na_o%tQCoI}(?ym#1ty#Bc4T@Jwird$RDR!HmY`5sB`N_B^&H2ft2y9Ud z85H|Tii;vB_K?OHBaK&VGV`y}c=U;g`N`>UWUgPni@6>eL9qt&F$E~7R0t4Cal>CA zW^s>8*}Vp*Nc~$0Bq|__z<vUg6fgxqaVFlkAD}euRO0zhqVtHh5N%ZGeMCJ(?Z}?L zO`*3FT}!l(XdM1Ph?Wq&Px?i|{o52e1E`X5CC}lxHTH?*Tw5L{*dUXf5ioT@L8;dG zg!KpHIwLK^<-}{Gzf2ce!*m0qKZM1sd3Y{}Isi=0xRE~fMt<Pe@0kHM9`{q;^@@1Z z4e0W)J#hRa<<*}w7w(_Hy;v}3wfN)Tf<NN6T2?fq$9!?@#EOkNm2i#JsmBq>IDciV zt9<=SSdT(@hd$^P9SCK_Ip9QR{h=SD?<!(p`+>UUZ!AKBGC&*c%a$jQqy+r&+wccP z5PTU4ts^>)Xre;jCwhQrI?;&=eFdo14zS&I=H_5_)ak@phm|kP0%e))I_npH8%q_M zKXVb1@+!&~b@i+p@&3GePg#ohC)E3#GQ2;a-YY$Lzf--p--36_5&0g$gG2E+TOjAX zRo(O4U@Vy%^KOUmehRnFZS>tkPGT~K>s)udAzsG^)~dFxLWHLwLh!BaN$_Gk{`iyd z2Ymb2OW=@gGtf+;lN9<O(FCCWd;qe>UQ1{kJyy_TvGQ07G%Vx)jc1e>Lq@GOF9L%a zDEaocS0K69QO0WgO+Vv(hI-%g3*N6#@B5GA{c`!9H-o$Ac?6YfsgEAUeuZSMd}N-_ zlVq#MHI!O)ev)m%zS_-5x?I<veO0HiNlvCKv8c3kS!v=q7fxC($JMHymgl=|Pnorp zssZmrl9j<bd3^8eFJLJ2!nF}~;Q$0+&GqX#)?8QL5w2aKTe!2dw|EdFSeC2z;7A}g zFCl$#+bbYpVkoM{{Ay=Xyj%1?8;5@}<;=`@V)SSj;v1qaYsxFm$62Q9d*gJWGbzq3 z8qb2y$KZ4Io;WD6)H}2btM}koCam^-QhhI9R0P}Z=8|`dySj>)TWn(3MF@)&!(u$0 zL@hCFjFE?r`ajL=%S%mqP6t-Sn5;N)CPSDTK2Jk1!^Le61Pj)H3*Ygm3G=NtUJv~Q zo3>}tTR=Qf$F*ty3PObnx(ARk4u}P3RQ~`ar6&BPjt&Nng=f{Ihn>*Rt=#7s&O0j; z#=bdrq+V(t`=7Dj`^HDV?Mt_#<h_?|d?^Fl*7}Bq@`XF?YrL0jGBLhL46GAJktysa z=)3w#yH*nBt!#7Ut~qht%QX6E8tv#1=e~$m45zjVo-rB6b;B(WqTS>kZgDaE>y0$z zbh<L+1nk?FfPFO9J#MT!Nj!qvGhomO1`dtQvvWX+ArEdtH$B+DiUP%N!BCRYg%+hv zz*IN<^a{BXA{M)H;dec7;Xr0U`2$oASYWFG`{chBTV%5$-`#k>9uMz;W^dkkL#lN~ zXV2_Zt?s21?Py-A#zpw?FTld+i%xC))u~#1MyghfRq%OuJpXcPZRncE-wv!IRom=H z)#f-;wGQ|heSNC76POL|2Ueg5iubr{5zj)zgK+L5d>5u_E%@DlC;!G&Epb(<Rtf($ zt<Tm$TkTs1Z_Rw(sU61CiYFea7?ht~baS3(zGv}*{G#O^=vm(`&_VDp1>Ng&wSk?y z{zh9qHdRYTqZ)(ZF*41675vjr>z%q}@uH<#T#AM|I<y2iHQo8!U$du{dzR%b{&SHw z4jH*3RZF<C6N!oeT3^R}d3I`EO{#`wIy4T$_H;b>SAnLpB1Y@&ShfT;54!j40q`*+ z!D$XmTlaUC&R^sxFD+YEx)Uj#0uPh0OVjj3N`o{zJ!LH`EMj8e9I8NSOfUS6)%v=Y z&cAL+Q6ZTCr%+`?c9@ztEhcT*g7PxQvZbEVWlO|8C=(FchAh?Lp%*@<X|^=@U_3TZ zxvw)7ZLk)bwybnPQD%N_ZqfY0#Y-2_=VTCaBiE5B8lnww&o3=n>XG@UuRp-ofd~%L zcf8hL`7$HD2A*QNkQ%BDQl9dPm))F>8`;_hrD|>_K7tEO{4lMbds#_&NmkL)a>m#P zIoKJI1I9R98%Q##3l<bD!PHtQ{mlifR-|li1S1kOyBS@}*i^0JcJRm>&LYY#G(xlI z&%Z9Gw6I80*#jyG5nd3PHd5;gFL|D2C5-1%_;5y~ndup&^_{V}Y%z+CKKdfXO%W+3 zjnSHY=CablnWghf3jcwVbRfcqf$^_`&u_H8IZGW&7B9GgJ~qOYPo$62wf;Fvo!2dq zp4MNGsx5~HK9Qczke(oF&eCNiiSPvCAwH3w5=~DzHx-q}VPXvROo&gUr!%#FIZItj z3n{lT<4|qDolm5nv$O#@OS6`hmlZj2+HeVc6~hOgNMC1LzOt6xR76@O@WCh2R}$ls zv<gZNBH?S{&L`5(Ii!S2q}0Pyp$<VCs%&n;EFgNZ+`RDjO6=I;_SH(ChVs7ba7~8R zt9<e56DaOKu3F9mo+7K9CzadT24tc}Q;laHHr?Si#d>iDT0%6muzh<GHicsTJ{N<Z zT<$+~&lDG8|Cv?oUys0m#Zb@-1c$6r)jmz=bVy1cpdmn*UI@bqT^f+V-VJkK^gnL} zd2?U%D;TydeB>}FF7%~M^rs^6NXyL|&{%Ls58idW*RNq`G^&0L6hn&wcmyYhde}z| zPsi-&@2fpHJoPc+Umc<CPSnQo49GiMJ3_0oZPa)9{X)Ckn>w&!2jrLg*S*=cn2H^Y z1y;G?vjQ&_J5ZspRbIW&9{S9fKE~QyYJP?zqEBXQF?kDd8E3$E$a=+-UU4go5luD7 zdj6n#YxC|y8(Gk?khW7&9KW(HKSO^|rYrz^wH*WosS}yYVIPbsunOQH;$TN^B8oQ< zynAK1BPaVX$o8?<K^=Bg5zIPE@zdiHdj`iWCVP9sg(p4*uT|qdGhTTvr;_=DH49p3 zTLCxDE2CcopM!a8Q$Q>-Xu<}~t0{Olc;|`sz8z<>uFvYXdB7dMFGFm|$zbo>y$n8< z(^2b%qLp)VQkKpA<+KQ|j$Bu7Gug<#A1*n(a@>UXa1o~OCuQyYw&+k+3+=ZC#IV10 zz;0PPuIx5hd^)7FV$!+Tg3KE%qqOpY+=99ZB*jXw3?lv$wp?P*FE=C2wPMm8PO<Ns zjt~U74g0#eeLo=W%M8?PSlr@eV%*Y<`?)(JI+TS7&j6sh7P~S7!Cos+9^c@EehSK$ zXKz~N%T(OpXY`vkAP6@Xd7wIh;Cs*qxv`6#P}zS3SG7bu7(a0U(fE^NbX0jk#SSWg z=E+2=zQS>WwXzWPgZO+IU1t5(B)x2$Dak|iiAivH8vfWz)E(o-)<?I`&@t)&FUN41 zn7gGiXG<d)s8iHfrBN>%FDVw0B1R{m(f=<fcgOg#^>TE=G2O?q(s>gq)F5i^>IhZf zQunyzmnppE*d6Y>gKr$@f$roQrrHy`R{o+6=q=7cofPoZ&=by?_PJZ+Uy1%B)1Ws_ zzK6=@iC-&!5xWx#j31bfFvjilLj|QD{=zX)`FX38A8IuH@E3kMp!)csEy(aVWC>D| zH{no26<;<Woz?QqE!JS$7mmW5>wRSfTzZxN#`{VMUV5(@Y`l~Y@V?>!614(5?Dc>g zK-A>zD113X3-vC>Ukr|7t4g9Vbh;bfXgrVikra#V5W=;f?u(|6%4~vd0QG3MsC)E8 z=&{Y{<rmxh3i&6IEkxoC<RKzkiHtFjbwsuinPec#iPT0S3yJI`GRyFjPo$2>5(Ak^ zWDk)F0~t?bFOdxfaypUyM7A1843Psw_8Q1>Yyy1jAdyA`5kwk^2m|?$$YCNK2C|1p z6Op7HD(}w|IZ9-rfovoqh&T=8P9iNt@(pAKkyavw268=-HX<bkGK)w%kxBzeBho?S zJ_DIZL_<LqZ#Iy#h}ekK8b}-wJCVHxauOQ_AB!Q<Xdo>_;)t{w$R|YNiD)}jPWKW? zAQEpNFA*6{WQ>7qB9cfX#X#;Rl0?L9AQeQ$5SeEnONoplQeq%;h>RyvX&_e+nMh=V zflMMYiO41cIhV*3B3lh4o=6IjIs@rN#7X3^fwcYuNIH>r1NoFlCXu*TRNnU!aT6J1 zAbukGM5Y+XW+JnQ%rTI^5}89}xq(y?nFoYwMO#zQ=JMs9;-VXiF62J(oRXrY`TU|a z1h_etEGsLD0MNC%S$<B%A+$xM%gUD)Y8J+^8^TO0@^taSK?#Nmxj51m;f_wfM-IOt zFp_XBr{^#oVz5<Fx_CiZ543ZO7SXr`{-rPW<QJ87jT>`=W}01va-rS&&R8G=W|Ya~ zGC9tog^QOK6=JSXVc}fTb@BWqOK!<8oxilKL=Jr-(yc~8;WVrChQF~w&cReT{mYgu zVVX@|!Cr^;?pj)Y<Ba)B%8Mf0O(PYNVdR)9!jHjTi%!=3(nX7xhIxiKG8dPH<8fmY zP*m!<C8u;T{GlB!^2}Vkv~Za!;BeZw!(r+C8<`x7cHS)*X=32p6E?N9ysWsh->J;5 znOB6B#UAl3vl8)bvMVwSS!9+=>H^Q=o0y=Cvec3iS$u``+bR8O#4H`1D7s~fC`jd{ zG9O0ycEXJjwiPER8!TE}RED^~A4#k$j(9P^=U7-eXOmTCUYr<{-v}2>Z7f@AG90ul z8H8NHIV@*z3#VI(42CIeFR8BRql^p<Wd(y)w|{6TD<7Os<fX?r2gJSs{|V@N*MG-> zO##T09g%iZGRLNLvB?q-U;XnlJVn^+G2c^U&?LRW*TQt`UUh1@_+E={181ir=b38W zfQ^=y!t+d-Hp~q<Q@hPGt=)U-d8VVUPCey3)24m6&lqv+#V_ZX*28b)JkyHz5dS+) zEdldQBe#y)+847<r*9p*^Y*C9s5`XFIDOKqf3Hfduhv@|89gTIXy}X3H=*WG{MJqT z5$Y|c){bY~+u#_U8a!M0+w9bi;+fRqL?h+Y=HU0>H?TPKExy0Qy*zl@@Qj07CZ3(2 zAxsl6JP&=2Zu$|Y7RPxmM{&`D8>om=mo2a9+YOom&aS`&`gkq2i|2DsIoH+SnCnVB zk}4;M4(yo9ZX^Fy@OOYVU@E2<ic0f5{||5P0v}a%E&flENeB=~kf5khqecZmK!X(t z)Mzq1gup-u4*?M&aX?;@8N^Cp;*d%>jzz_4TkS=q_u8wi&$c1>2u@72Qst$fU`3^N zkAoUDg$RN9eb+wc%uEoty}#f8^G7G=oc&mP?X}lld+)W^Ui+>E<^Pj1OB5AvvbgSl z4{8{G0!4n^P<DA2<QJbx+135uQFdki&&sZ>n6gVSDM4j2OvQC~f{tjh7R>gZO38JG zspNWgqpA7JdL>Q`sYg$)7>2zo2LpW)(B)@SD~kl#j&3FM7D<v(+ImaUO(o4^30OEu z*UOPMzM`VC+<Pju&6yq4HZuSrKf5SF<t#^rrP$G2aVqUj?|(<TbGEIxIh}Ur96QnJ zv^(b}Xm<pqgD`{q5;4z_y1B&5l%!}SR(^>o&VxLQT+8Qq>rm?KB2s>d3C@>d#+2VB z>Y-NB>?2-&iD|UTiZpIH{VsqGkU)NkiE;%O5|u4El`iVSn3m~ux~RCu>U6rOi~kK> zR9**Nl(6xMI#gQUfyT-d|1lkE6E&Mbm$Pdp&r4&er1J@^lWAHn`*$?0eg0idYu^(z zt#jd9`Pq00_Ln<)O)S5|H*abAL^Q>VOUoB9y_2aJ7|x^~Cu&^##Wk*yq#SV1C-f)* z-QUq!l(J))gH@hND|<ypt?bEkt^+#gTo+J~{1R~=h|YC3<Mr%YD~$%J%*p=sc@rOE zM4W8Q98BCWe#QJcPa18xR5KdFDRbDMD|Cd9-fBL-H=ieiFJX^aW#sTYaa>L;<7wib z=U2zCfgdAu@jRxXco$t4{)JW6z1DM;^}O@+WiMzl>*ojF|EBB}<Xg?}K7Q-@J;rY% zzi0Wq%<mO`jr_Lq+r@7mzXSXZ@@wVS&d=G5FE)PJ{Bq=d(r8iHS87eU&~Ni>lYTE* z&u6UXQ`Yl0*7G6jX;{yI^}O49R$9;7t>+x;Io*1eTF)`ov&ecDSkHXx+0S}jY(394 zpQmcqx2ThhCG98B_W5s%9ggpc9aH&v_^si$p5F$3&+_xPLfh|)9k=kC!Mo!S?auq7 zyx;OKXvljO??d?Q;(ZihkMSJF?*RF;c{cK_<M#@A-{RM05~Lk}>wLQBy67eDJ^0aV zC=Cqv%B0da*)x`Dn95;aSs!&C=9$WOshW-n(^D%*;#r`-$H=#z@4#>gb$ELQhRdhJ z+od^mIWN+^no|X+ygea7hqWsSy~bR;pnUe6IeLld7>g|TE%1stv56Jwi!dwpmX~_x z#<?ICr*)sPo6UYX_h{5|IjT?l|M8n+;%iRZK`(M*bYki&FJp3ODwsWoSK&m|q3(Kw zDsB_S<W3H^@YFWyH4S&Aa8<^Zwq#L5-ZKj1t*D$$D4iU?I{br<C?+DNnH&Ic0dy4| zEEFDcn`kD%Vb_xw-yDK5bPkUO)!yu9exZ2*#ecJ(iG&s^d^GuyfsUjX(S5e7f!_&E zBtQ|XwVV25nDwFElqR}EVei`9i;wH@r+p6uQRX{86|LuLvYNU@=r_T15fk-`u3FT& zsmz~E@<`#w$r`I%22lh?*GSq>_@)YK_l@i~vtRHbR^~grXB$6XLL6(5On0=G=-tp} z>L4~7`m3?uYi;Ve9*;n3QtR0<C!J{Q%v2H4e(Llfh)uA==kW61VuxPFi++<@yvsKF z3rXA;98v*PgW8|F_*ri=?j2$l-c8+jnbf9M2N?GX!NIA&u|)1{aIEMJHFTg_`A>{I zYHm3i)pt24E7VIs{@aw$Y}!7^wLF8dv!fE7c%4V%8rtDJ@<?ciPFHr4aLs4T%<)%c zJMdqmcU**#vW#u{Z?6?UGRNQ=7HVg1y6>I1TcB4Oz@WJth_d^$*43N)1+w{N@ykGy zj=Gt<rpVnXQ|pA;4eAXX%?bT@>LE6F9&^&%IkOinTI|jBaQYy3?z~F9E1WyWGjG9M z9bc(&U0aedfnBO3`EjCYLjK!W6Ft-2;gC}%W_@h4qY@7GX5pG5Ie*8LwKKCzC+du{ zvju0qtCo=oCH2fVvLv6`HaDNa+*P(~GW^S(4sV)&dAjy$G(CiO2<;b>gZp0^EiWaN zjIa4>#RbOu)T}R=<SMDo1xI}8<Vf}ojii>;d{y-+Nv_aIZXk)F_&i^K9%gS#C+wj= z^Q_pa&%{TozKuhlbv|P3@o#2?M;6V5TOP*D0{Ty^;3{Q4(-6ZrQ#`cddTX1g;3er* zzRv#5g*s2x+K1%D|DCW}VFszC6ZOO9Q@{K&2e~#<?<`rmdLbN4;D1e*Y5E}ZzcyBY zWv+gXzw?t+E8?;Ovy%J%L%ut!1Lk*CkNmy!v(yJx?BflQ!ugk~X7h7J#{5gvW-DQu zc#w!(G{2AfeJu7e^>{q?`6Rj8RD1t8*Z+M|=?h8XZlg)P3j-nMn$$e3T_YDu)CpWl z-0$r~#Uzr`5o+`A+il;L=DuKzJoC>`ms-VgrFSG*cgfxu-D&dtf_(JiCco4_Np0iP z+M|GoYdNf8lolHSCy{FIr|ooOZAU94tjfaWF7CJRl^l9H$#<6VF7{u|>c9Wq9u1Zz z@zty<c-Op_A-w0W(**aX1%Br2?6s60f&Hs$ZxEmL;)}I~cG+XxnQkmfhl$3*HTaUJ zs+oT-?2OZ~$+$~aPx3AN>P>PP0g=WjT$ChY|L|8yBXVR{N1tUfb_GY|tTjZ6s@wO9 z8#P_H?_&S(1$x*!Up9d~eTfI?3ojz#)Hjgn=_Ic+P?7bGK4JJIay8JHrCF6R*YW{R z`U@irRCq|+Dl{~PL?7|PCb&#<PxfpuA<oherM(H(yHDclP0FOy`^_{3I?Y|AaeE#y zgZk*83WBWj{o5!t=9ACfHXOM<CjGVL^8NI2qeZq5_q)OF^<^~MTY4k0@FUsLUOS?* zf2EMD(AX>_Gj^x!NO?$zmigSaq_X`{*Z#oDY=?Jxv#T|iqniHBLO0n9E@@3>6O)U4 z+^VnCMLQeZ#<f7%st3|gziefMaa%l+vtJ1LHAd30#&PZG>r#=FzE#R@gA~f6q^wjY zC0RTn_^}sV(keTuKPn$zrc^Z0E>s>8ox+th;`ETp;tHsi359+sPQYXRCxS<X;L%pQ za)=R-LA;=?ihG>fYLg@B;sg>`QbYK2$dTkt<r$6755_@XaphO9=LfxKCG1?n$BZRN zS7TzkzuqKMSN+*~W4~?28;rBWOaIV58~s)32$fd^ZyXR7;+##o5~q0ajnwdddlU(u zG+7<GpY7Ug^$F-wlXyDyH#(48O)-u}r%a|{f6L-T8u%tn`ox4Ab;4zsY0u}s$!eoO z%u>N0LA+ZhOtm47wIHVd2;xMYFi#A>`|83kw32>o(mMgm%XHEofT=sX)4Y48x>5EL zP4<0UUX5>qRU0?SitPK})#8)U)gJWeOZxhJ7-Q!&f1OOK9Nu#cUcK^)cd#^d;4G+? z*5sFvq#!<I)68C;wswuQ0U<%xMs?3_N-0yMUm^0X&F<^x#`}7jdh?G$(-a6)>uNL| zQ#Df9a)!e${#6WzmSn<(8l~v=s&&-~I;I4<{E#a>$(u(Z`9NZ%I@=(+FuPtlj>_NJ z9&L7Qr9=87my_Q;%8XU#5TPBbbtYN{#z<G93%TM950qO4ysmiW>T9Ww&XXm!A%1oB zc6zg})JvR_(hhlRT{uG9qp!p3O6tN|*UJp4I!%By#?I;^;<xusXXaDx-kE`qd6%k4 zhi7Q%Zq#bI`F6_o%;$D)Z({<z&5^RrNK08K;kDcVheP+j8m_1Ny|w)ZVz)a|-l{Fx zRa>@CN-fyqyV)%3EXwjP@5BVcaP1PG{1&;~o~bBY33Hd(#oDECMckPw_ee1cJI&}c z*j-Y&_A3q_@TuOxUiU;e`^*%ptqf0_pFT6gugSm-XD?^g9A(qnze@Vs8&Xk_Ddvfs zSdTxw=lhjCZKU;ECqdhfP^le`6bZ4Y(mkbGkOG~J)B0@@5(%-?dG8B02|Tu5o&P>O zmKLa!88my}5At{I$Sf{~I@5QNz6jpPsae7O1J&<1VD(7P#IQ)}=5zw3u~Cb{<!PiU zgoxsBPu>X>lw^Wa;8MQxC8eI_aJvrSa=pBSOHxdOO6NOu<y>`Y<43~O<FJDcqxwaX zaU;FqtXTshwXRn*{45E~;&OtVH#f-r2zMuzG~^T|C1iR`GL47>c~riCBBT&>9aZNE zyyX^#3Hfxo?(ux<$tP&b53{USpn07-@FDmM03j=j4cYqdK=_U7clde=mTi>O_aHe> zh`pECsEgRGY6drfXrR9kpz3TazPK+kuqqqQcnVCLUEA_Ho2?+SLl1M?%wcY|Tit-! zcp07#OSV<NEiD)<Ta7C-b=eWvQxFt3VanmUuh!Ktc}mc?F<7<Q5^A$<HeC1hb2Zp3 zUh7)j0n63u(;d+$ePXR&M9D?2e{yxgYD$s<ntqT1Tn&9)&uYn_3*ti>#uPjZo7C_5 ze)P+cL#z&kJr07;tzM?(saIAK!q?8gyq?}5gX%UJR1ditlVwETCaYOV)Uoo^IT+Mp zno8<{7I~uG2G!`$I6XG1b2P4r{bHj^`%%?S15MhoggZ?!OoOQQ#Bhx8sn4b5>vhQ2 zot!a7z77WSB;NobwKhhvs4YWhutuy?-0EMnaqwYz7xwt)4%ox>mgWItx9~tO>;_{C z<bez~L0u{J;Z33dxMm82+*gcUautJ9?2%Zd{zbT&Wyf^?>t+u;*SJ^r%X_64a%Jx8 zS^}_nw>N@uOw+wORkKb59?@o<PTp4U@O5UM*sQv;lwomde%zl53pT6Im+Crp#`R&d z`hpM8Fz49X_E8qB7!d~WMt<Lu@M^+R0N3KdUl2r`uQRJ?Odj_}X6Z8+YvEfxP%tvI z6-92;fj&D>d?^1!*0Bk|km^<0GHu6KQbM{_&iuC{$uA@Uz?Bg#OD{^uLXMsqa85#o zs`aKRq;>xs*H#HNxyWAbm|@vXu@-mfH8+#G2R)Fp;D&S-+)wX|FSy6Nz=C`7WW;ZW z95oFqT^&P=Z8s929zoe-R+%;G&Vo0pa!;B}OqGm1MdG-bcym6%NCi@Y2A3fgxYK>T z14jz0GU^K<u3EJR-sqIFLoMS49g%F#svYA+q-eXk`n~qtWv%NdZd=#fkd9_Rzc9nZ z*K{k(8>Xvkrgr9Upn<4d_2Sf{QFI47RVoSu{gP%gXymN$3lpW{t?B^^QVYuXvzb36 zi=nFCWoQx`*9?ee+PK1FF<OZ`2l41=n&L(JhG%Jrv3jQ8sQxBn8)aM}Wu!|PQ}~0X zD%n@!uj=jajT9Y;_j(Oh-Ntys+Kg)h>gGZzhc6Yr^XAE)?!q1Is)iKw)*fd1Ih^(^ z^f{Ycy_43Kh$e>=1%&C#)TE!~Xx#`3AcyRwnyL|;42XMVZ@Kw72lEtf{1z_e)h0jX zi;v!l+Op%O&&o+3+f9(bopJ-mwZi`TGKeOX@{Lw%<pxVyLDy9K=#@lSD>vgDS5Ng8 z<5XW~rV?$wzXjfji;L-i$8V+j1I)<z&r(?o=qndQgBM#1Jg7QD7SVS2m`i3Q$)^5H z)G6kAz_eptQ*zWeqWeKQDzPeY=B&o-V*!u3Wn#C0$>%U$!cQ$JhsFh+KQ-DS$tlOV z+ky*t6BDwaxqyW#VDi4!)%ytX(ya_hG8efsjrzPzrZY~=v?4w5UNn-zAFUrVO_%lh z*7DaVuH?<dmJ9$QkrHf;AE(JM^n190V9_bcSvk?TFr?xh!bvD=B(p!MH+Mp_gf#yE zt+j=n%`^$&a?T3B<94`tAETTmdzpyLKQHfG6J2?sT$;V&TrF}Q*TIFI3))tqBZ_p^ zw+;Toy51uJu1}Yj6^E-AWg6X^q)2x*wDQ3AW*q~K`*n5nvR=*o*is=CkW|YS;~_oz zTWjaTUnZdf=%9m0;ZiniPvt<FrH9b3jg}(fGu$u*HtTT%`l0%8bArq%E4o2X$}ly~ zkJ)dd`1UKEJYh{no*+{Z_-Srt&GQiVkTWkiv*tf}BSX)Rj>)m7`ySyluvyQ*GJ|W) zxWgZU_%;%CKd8B4nZ3%MX(@$#bBWwes@j0$YzoNOCF-+R?VS2xTuA+a?}C6#>bzG5 zHp?^W?PJvdL+*zpglumx^TsuFNLAVSb7g|{!CI;iQcpkF9+eY+9qZ(~-o|Q(t*RPm zRb<7bjE49aV0K{W!nykn+iH_=44+c9@f2wnQ1p;lfVnm|WyG2iZGFFbug@!8UalO^ zQ0H(_E!UDWo^hW!1T@;{hu%`HK>O@VO{)=>TF^V#ukF4azQH6Oe!Gm)zRp_3TgXT4 zYeKl%*JLiBv%h`}5_HzDoOonNF}1>LK|}a>pE<IN;Is9&A``?@tnXHv5Yz1DaodC# zsU0|K+;4tMaBl;5{Fj1zfo{6Yhu`4)M$FGoNvTV~Odn5>G1=-HnyLj&-r=<`NfVmI zMSTNKLg+78W(AISpuhC?_XyT)Dm*Hh%aGb2Jxb!9L;pk^veEW!AK$oW{46G{W1<Wp zlVcB6o_9!qz_Pb5ep7<H{YIac<5Xe#3rVUM6Q>Y9o4d)A*+rRXs<ncdm7o?D#>ZMz zjM9`}sslw-thz=Au)jkp3Gn6W05<_zaG#|=xk687og!DtwOpwS&P+-eSqxRuFS25! zODE2b0b6yo4oHawSkS*?;h>@S((&k$Z0MbeN__Rmtb}{1X&z>KGH*at^nv;_d52ET zVhpxJHWIRCYF6xf6yO5GmuQXVxg#de$HTwmRr?=Do_M<W>9D;dRxT&d<EQuwHD_Z@ zt|N{n*AEa|msZxUMgm-ftueEm8_ad6xf0NGwU%-HzBl#ZBdo}ss+Z0ow9E|Fi10CU z?Nsfo5QNCVDM<xy_{wA92MAwVm_Dk1awXGqUBpf`1}H3`)4c<^{ou;THL-|4lUmcx zuJBIPm4097%LehJNO!7`6iJuA@@?OI=db#KI}!X<M;yNX7APt=--MOq>m3i9tiw{- z`)G0<bui#|aUJnqr1K}F8f52mKA#*(LvNp)-@tewF1OcdnzqOs_ahnDt57Vq3oHXg zW4k(p1QRNV-*sR62m<5u9M!KW^S+JHj7drhG2Cr$r7m!_X5OzwxrDxGg);fO0aD(s zlRi$M-nyB=fPb-{DO;uvuhHRYas`IuU8X;ol3Y!)b9K-hJ19eczCt%HloKRuV2PaS zPakI9;1z--jfj@CWY*jw-J1B-dqvnV*LWF$GL1oBSMe9X8@k8a(}F-W4z8lpBs=tk zOfpL{_Y7qEXtg-~8>jX%b!3|=e~0=LtvW5TA0{<rxa`%D+?O6`YG={CQ$34>Gbssc z+6z?8mTlwv9bIw9NS#XVR?%JC)xPp(9pbe@XbqvBO9##(P_q@<3t+qTCyKwz^yjO5 z4omW$qdy*_e-+AQ1L<zPZ;~O1a+TORVSu=<SGPMISBPFkewiPI^w&VXSid1ar_%<k z1R!*iI$OxB-zCQwE5{qeOo1{GH`ZP+9kOt>vvRGxl~vk{K>@<u3pTocLpM3LBCM!q z+&(*Z4+cV6sa{Y<ro{rHOt<$ivn?g`N{v&<tk=+WqM-72U8A4+q?E{7>r9L+X3qii z(5X)A`uPmL)=cHTUSeM69fWlH_<ZY2&gj%G*ON)wxIn8Ky<Kbd(}X{CooGO%OnJu2 zWM62%H7}LH<w@Y6ZRLic4GayLtDhCIBN1}<h^()6tI{!Y`f0M~2?2u-QqG{c)fvlK z?zHKY`CkA+nVUCi<xa-ZW8O(5T(yJOmK8T7Oy4+3<V<O1PM2+-^>17zCuV#X%uh47 zatO_J_xnZ^Mj>^(F6dWxQV?@53PC|(&F|bgY7x1a-^KQmVsq!ewQ8}5_)FvGj!e^d z{zZq1ZZX~4lkl9#^)Dprm>#rXWH4SKq~cEbxXg+<OoK90>21X+J|kVNxV?N-1UBCc zSsZ%R7Py7i=tDF3YmV2t+sV4X?x=;JV6;?!A?oB2MG;ipRu8_62t6k*Xz?W*M}ItC zpdJvhA_Lh@^#djaR_c|nuq5Hm5goHz?IfnDuoIj3HV>QgH(}w}1VK8wEa<LAR<@cK zL$#}4k#kCLdGFVjVAZ>cITzasv&_}dN)xDKWVEE!xBbU(#+h(rq0~up{T?&lL>o=k zjlnyU`u!ar0gxD>)}I)*j$(TCXWYFx$^W@7pbpGM%7MXY{|Rxe#gc4Zv;;P<ke2XW zZ7g%5Xc}Myv?^ptdey}gsz21~CW~v$&$H#TS^exfbH!q=+3XXIf!9oULyVtmWyaKW zJq_whN7n)B8WWiPx%EvA><WPCdCqR>wDisR`bnc{&rUfQnz0IMktnto+U9@V+`sEo z5m@QWMNo<WsJyp58XimCUg9$55zdN$>g??iXgI)2^3q)WH#>4Z+f(;5Ig?%X$DMh| zrv7r%apY3|IwHB2*3BzZZfrSN$Y{{L1@yO2ZS5nnW|2+*W;KRbc2$!dNe<6tgc7u$ z<Fsydz84=1dodMwy-`|*otn_#B==gb%dDr*2qkZ65&mW^{4V!*SKX1{Kyoo28QfWx zSKLK2G8dDS3+E@5k_)%9DxYJRVvgYLR&bo9h(1KRJaVgC$SfDk0^Z!nZ&s-$=<{@- zaj#aX>JbY=6H533g#;sp&}-FJwwW0ra`e|0^6Am38-swUE8KyUxAu_rKDp9-w2N!Y z)H_s>HGv$D?DH-w8n{YUCXN+X*^7z31utoh<%Nb`F%$&!m$RS=t)#4^Qolto>m+o1 zL8AgRLTbmydZIdwTfx(HK$(DlW-7o_zDjv!lu+N=Q_t7&y}(=d@xx!Gum&!0=B<(n zaVC+P>WIQv%*tfrI9(3EP4ufkV{a`HO}<m%`7j0PD*|n)=Kji|5zdTE^Jdl&&Mhhn z-+4&^zcjS|`>Xsn`n?foTfSmx<UGC6CvMh&y^nRLTb%=s1)h=A%LAMBqv|7_F3Dr1 zds(OZ?hevvcviYKD?b8Sx}EBNooXwoqytbd-8py{8x}ELu=OBiu&CW<CUK@U%Qr5t zG9$@1ieV*PnyhyvD>-@J3X(mi!cV*Os?Gx&7;Q+$ZkjX`_GwAp!(3byeTPbUM8>s) zSgkc?Nl#tJS!S`r(u6S2G~dja3r}%J<aR(M*f#Cak|0wL`B#4uHT(OwB=qoM)<N*M z?6r1&sC!$ihH;soug)z_ti3s3Gxb~Mg;{K+2bQO|n>S3U(%qVkRv<(Jbwg+chi|MH zu)WO@3(J75q#eELR17Xv1<~5}P7>NH!bnc|$>B&Ueb166y82@wi^9R`zj$cjF3DL= zv>Am?w`T$SOVM6p<S2XnH)ODz63+_Z^t_!m!w@c=c2lXtfby+arfD7gp=)WKkr^f& z)>GKOt%HxEy~J7)S%6&_HlSdv-4AX2HG0$Mkf619I_a*7CVtxV3@H=MrB<i3kIb!@ z&GD?cBoVnQi@y<0O6i8Xp>-w|YDYM^nUJtF)BO-wHmL<*NqL=ktu6q6Ib}{3w{yP3 zt#-e!{Ts11ks+rli@Va9N_)mam{QdR-2oGX^F1^4=TS5^d}eC0m8ygK)0<Iy&154j z>Xxl=*<0vTmt5%ZLp-^v8n_JK(LzRWoE|&nn|-|WC=P%0)m)tr*^F;or=dM_%NnUJ ziR_~Kh`(ngy!TFc&(rTITsl7Ujcj?BsX|#cZW^-qWlTg(sOfNvShNXjDcaX3>dTAz za-+T+qpUaSew=>l%s2Av^yuIxk~He;9ra~LF)&DgJ3~~{F}NpBGfAxbtTaYh4zMgh zQ7ob?{J6UyAx#|bT<s@X<DEl`Wz|Wa=#cj0@CJ2A6Nfh{4i7q=Jnyg$c~4#U!i2h? z3RZCkSSK&9Plq&dT+RC)sJrkbn?b(xie}l6S?T1m<Sv_2VUlnFa#RGWGE%&qHcxSM z@<)6DG1bg!E=s>xqMB1u9J0|RLSz8e)0Pk^%f6A3v?iQ5kM0^dgIxW|6_M;$$V(?) z`o`hJgiL05I9*DYsK$##kefTD8hY)jc`#m&u{O<h|H{D#Zb}ChC^A`e2m+cNnlCh# z;=+r|@<!;o`L2^nd9SSqT$kd@58Tb-^9q>uM!D#Fi=qzhtmA)WE$~-wdZbHWe0o;I z$=_UA^5eZ@d^)y;*3M35xMs-F=xahL^@x@PiFliS)aVp5^>uc?$C})v7kxU-xLe5H zNs~QN-ht**G|fASV+}{-Mj`d;SXPZE>p#%c8Xoi<M_AX$EP22P1YuhK-URIad5ulg zABHCE!9EW-@$E4c$sP*-8PZ2uG|9E$tfqOaW56%5_v*$4NYtiOZNq2#e>sm!*4KmS zB=si@wvdz=ffaeq)Xc|qvg$^OW6l~FzFO<a(xScO1(Wi$_m4%@1pYj^h5(uS`iIM# z1NRNz?ZWBdy1GWBr26|rHpYezex4X#_7k~0pArbosq&h2n2}5NTh!;T;h=9FpPmg8 z)_|tbt#<JDDN(_N#x3^FtGJ6JuC8Sq83j~j`O^HWOq=?YY&lxU0n^*$pwtbsIqAnX zn2=u#Jsi&hugjt(w^oi@ymaC01)b&9B`))HpnEo;=B_&l3{DGb81knD7+oc!*94NG z-#KJ_hp)U`3X*@VZN=sbfA{fzfL{i=|0iE$r#d5g;0Ml({9pJYD?DQQB3sY%WWLCf zIOXSTFLq>}K(<aN2HZjg#OGF~qkBgJr*SynJYSf8w8QB{e`iMu=LaR$!Lg&96Jom% zJA1jrI*A?BF_x2>>Gn}?X|r^aY&anaKF4(9N_((p7(I{>FYUxJO?}K$4q2V-bX51) z=_oxfv!^jX&8H7Cf6&u|l392b`X#`aAM_ZDnPIki5DP!%`%UUXzGdDh3zFuaQ$>f& zK2Dgt$b7<@kJof#hAQ*;mpwQc^3x#tYd&B25lZq8zfboVybH+=C>x)Iikm;j!pb?` z1(mawSWKON6~&nL=S%0|4yj(e%cyHSbP^VC7_P{iy$_RT>^3XF)pm^{yt(!vC@Jx8 z@nM&E(R@}Qy3EY=dNa+_#RT&C&jrYZ0MYB&TJ4j?SVwy~6n2Cn3rxQ(Rv1H&go!Yh zNxa_qENH26vM|gr0z#pJ7FH}RwJ!+>usCOpHrg0!74N+g^^Z<xXy-Nkn%$l#8k2s9 zC#%rS)X$S_B6g!jYz-}ekQVyVUjE@hO}{JG{8rbIJJ6v4D%jllV#XE1ifbD($nD7z z7)>fo!zcy@AlBKm=s9$qP(qYv@>H$!O*`(mzoVN&&8h1sNra(CUeubIT38Ma3}4S@ z8sbtgvGDPoX$GhIItPY7N_bM0Wf%FRw71Ag``_SW#rCTsi}yT!eLzBd(H1{^L(G4n z=Xl3+<-2}E+)2)r4<g<Fjm&tAe9M73IBLp_-1QyLm8UqmJ)igdxK|33T$~$r!E-L; z$HaMaJg&L(yp!jZ-&wvC`Oz_8JwoO&Dl*v7y<-Fwq=V+sf%j1!U-Hi{&wNMMvdVHh zwTwIaXh4T=On$>td3ACEOa3~1XE&$z;YH-T=KwTQQ)Vz!oFs(+^|VTgtL+rgRDl_C zOdMS_%2j;TpaJHUkk&V&iuG-kz4F3nH_2e5a>f%<j9Zms|72k$>sVWsd^aFLmR$YV zF+7t|(No>&Z1S;|JGG?szjlcr?9FKUxqea085^y&%KHL1E?fMY1uTja|7M-km(diE zmn8KT`WY=|<_JV9S>M2LO)y{9rfg`g<3FF%9*vy0DcAnqDc{}d`|}+fF;*$mBRbu4 z&*+7&-6~fNy56GI=t*GU7-;!Ep)PWG>B{x2pF;|7hlm&x$B9<qD@JP_LxI_&m)|3z z=Ff6wtVJAtIh>ObW-c>wx{mx6kz`5oOgBSaI#kX%iVTpmFJ=LKC~!+acm4B>qEYJM z4S)t%k(sT#&Nh~8rv6Q2$I#zOR_~>2^b_H5tb+V|eZ79v2Cb-mMP4wMl0AZ%*k_7{ z)rUgDS+ED;wudzkJ09<-<Ch+dCY|5+W~`U8YuN>Bmkj}yT6#_vXk@8pZR4n2KM^aa zHkli<<CuK4e6=46C3!F8de&qtHFQMgUmU}u$6@!bfp@Y3uD0aB!uDj`g4MbX3JxuG z*$$TjwXV3nE%l6+%1XXAbzZfQcKR)l*43gFtT9~!{?l~9ZT>n<JGQ&9B*WF%g*VFB z7Ws(>_E`n(uGZkV-_S3xGJ#cAC;d$gf+wfROtDN)Emf|3i)Mf_)FXVzc%WI~<~tew zLaG#qqU+INlb7qT>&!4{8fet_M~hvO>DX;_vddnX+>nkd-0E=GPGT<n8w#&po{<a^ znKk$GVYqvvHZj~e;uFr*hLZd40#|$0GAh)M;{=6)wxpHwuvvIeZHL^XsC6kC1?q|I z)&x!T7OpxLP8nlz%7Il<*^6e8e47|9JxazvRjWhPn8Le~u{Rkp(*{fG_L9yp@2?4m z2;Ia;-nuJgetst1HtxF(uQQ9l9APp_<k-rzXg7HY3@?^XugePe4SPZY+{!Uo3mN%9 z*7P?YgUrWZ^D)GH3^N~vJfMFxH34j9&F?8vZ3UL498Al+M`k#lH7PF6zhc7ql$2m& zvC{J>;T8tt$fXPRJRJ|bRssbL&nxl3JP8z}Ja5GVGbK<^^z4cU9>HqpDM8q?KOXoG z2^91#G_dkPMpt^5dKccd)ST&a7EnC1;5tc8ON#@ei3`OCQYEe!CYDz&_Tj#@k}y2b zXm39{y~pRBi<bp6Ef#W1Sw4^k51uh7(jK}2q)hxNn{CrwO@>LWuT|fL>h?1VsP3%O z;{JyL)#0DV>2knHCp|asC2j@3)%@<`x1L|uNkzU&uX(>xICL@UGdcflJzuh(&sfi= z%x8xJ6FwC1IKt<c#53_s`}$5UM^?JaF^b=Ees%KR+2v>?Jav+II5HX%z;t*Wmg;i! z#`JdE{{m*_BpDC{uK3Z#f$S;%Jqm0<|J$$+c9A)U4SUK`PK2Hk_C5=?C>j%KAwGY) zxCA%71YB2&_7$<j7J#VToU-<H_%aR^=cV|4shmEGq}CzOR!zIfl>c!XN=%DoX<wUW z%PP}n=Y5~C9Z}Ve3wLo!UOTh3$<>A#d@C;8H;`04ibmb^z%Cf7Cu$J<Q!~`>FHczC zuOp$X@0VX8^5cWPiSh$v^gYH>gWS;r$J@@|=R!y1tGb2NwrS%<LXo-5%fHnp19x+( zP>$P8NiS&eX4GFw1|voFA(_mlAp@47Z0^)%=Rpl<kugo*foR$&HmO;NG1+}TcaT}Y zG_h|N<3K&OF)qgDKbMdIqh*fNGpz}!&tO_P=ew5O`?V!mGNCXAMJH$1a;12YsB2RS z*)>X0KLwMfqVyzxRg}X-bAN$_lBnx5485z4>Xf?ZIlmmn>&(#WRs~oe>8aDNDZ`p2 zJtxJ-{DzW+Eq%nhA7IvsApO?}R=qx8taR42(W%{HF`B{0LHVGTR}ZANsw?nCk;Of$ zX4wq7MNT%Ri<|(^DEOhb_-RBDst%Bx`gFqj{tg6(rj40TGU((lki<^@r+D%k%;fZa z+G~QjVb75Q+5hJF7@5`n33~7REdSk{O6a2QB5$B=A!VhgR5HiUNt*sZzY7k_``z#4 z%p^dtn$Uj)&Nko_g6j~w@D%kX)0=5G2@^>96J!kLc;@_MT|Cv4Y`?OyCB?JdPd0jm z<e>veq8TQRg3}#DTKl2YM>C*RANWzyJ{?c%B5lFoJb3av8i~woKbkvsnjQi?qo62j z>1F=A(Pds3EbX;P#D>X6>9s{N9V^NR+?^$+NJZI6Cf)U1<286{ZBe%F2eCaSVJw?( z&Ak_~iH`e~{X1gDQjCVw3Lr?i-gCu&Y-Y_9WVZXxL3S3y>jdY@j7Yb&#reJZcky=V zpW;m$QBaw+^lO<^_2~yY;(fVaQASF$zChv0YC=BfSDKNsTO7PzL%)*ed;NK44>8{D zHztD$2a8jBspoQpm#G}p&kQUAm1vPf`d6f6ck{6!t3H;t*YTBI2<_Fymm*1+otCw! ztw;`Ao9OumwUTl!CNLDPrk9vEg)?oFd99dymSp&UNb)7WkUU{6r{=M~RQ0q36Ijjv z?9;Uh4gGg#IDEdi#2l8#F&Qm4z0-}xdRddG`Htgk%+W$3M`XKhlLUkBLP)k2W`s}! zAXIYXEV<;OOF|NnP+5^4^*Qv?O)}jCiUc(kWr*eJ9?&=5(n3V!5As16mwWA|LmX2U zb-1Ufb4IK&KM<K(*GI_RUY|?2dPsmVb;Nd;+%ZyR5hrQeE)!Bs&a+7+RtnMvf>k$; z@15%3RPxI>e6q2pyQ^sN!X=`oG{>J)!FbGqA+Syyzs`uk5J#1#hjZXGaL$au!M$Ml z(nYfuoF3M&Zf3ns<`ZaYrpw_bek#A7)|{ree2!Ju#Y@BgJja~dd}2ONRqqW}8H0G9 zSZ^ugQGSjrDFeszOUvgbmT@YW3RpQvj1%!5(!=FAbCTU2<#TUXuz1ex=9FdK<orXM z+{{Idrh2iC;beQ~?ds~>K;2i7<n8K4-`BNCBLZ8T)yGA9;rsArEeGwfHZXiFSslI} z>QAr>t5^9{!*7J!nz4Sk#MoI;{TWB5-(H(uk-t6jFFTCvho!JBI0xBjd^E0*y$-xQ z2xl{Xh+1u@@h--$>eqk^w8+S!*G<|UwImuilA3wnufa0#C2F_)hJtOG_Zxh!%}DeA zpuDO6AHqIg;o7ljDOdsX74_Z9o<_=^K*(ABIS?JSGutx%JdC}EwKLL^wtSx6^{9SL z-tu`?*P}8X`%?N<wH<C|LC;akL)+H?N)OX1DOGL8duuY%jQ6&L(+N(Jmn>eA0}akd zQX#1P!bcHQ#XKni-tnnI^LbFjR=d`p%ZDpnc5Gc4wIkAhtW*_2q{qh(#eKkcHG5YM zL=X(iGu|;qrbnkRm++mr=>QDE2D9`ZRkVT)=5ZGuji$8p!}0y9?Ru2ceOMfflr1V> zz68fW<#Th(7tPIGT*3JnT=6U<O6%w}jrUWcJ+(PY@J*Q7bOPnt%5*HtH_4nIgBF=y z1=^gx>|j~TCK+gAVX16>_lDtY-2UrsaC<RVq)|(~q*P*;#__Tf(yfwoYb6~=3dK^P z2MboCtVNx}rBgwU8*A$YCvSwS?MKA)W@X2sh6#v~fbh#gHmlS#<P5<BVn?%N7UpVU zh-oUyI?2?Fb`!IEr>2<<&+*=pd#iMp+<BF`a~3aM>RSRCiI3lBgwy&=`nrE*mcx4< zgTaV&LEdOICTFOdLDLSJkfEn=yU&hI;SNGp!*nIiyo(7*;O>mnD(a-sHk;P-GwM`% z0SR}Rv@c3mSz^R^dxn$Yn0`rzUzz%vJc6Y;%za7l4R&{ZD>G!ikX>8ZJ6ME`jl$JV z6nh&XdjkA)f!`DO=5<T|i~3I~lL;K%P?+>f&fZ)XSjmB~ZrHIny!i}aed!OzC&q~0 z1$&l>?&y6SLIjJ`a?l^WhDm(V&Dni#?wu0pcQh#{uO_-`i_GmT8y|ZvujkEOv2=M? zX5r4rCHgg_Rsx#Y{h6EgCsbwlT~uY%`KI2S1krz|9X0Q_!272EjG3+045<Y(ZCUqx z*)uk-HmmpGt(rrbt3{>o;w4n^W;AW$QOkEG+zpLCq7TBeY%=Fw#Atd)!S|R5ztits zv?RnXk=SNzv{f>(#`i__?Lc3fqI&KY`wH)+%+6B+>PkAts&kBH&M5X|31zH*U>KEA z?~*&vlpOiF(OjRGO|O5IfD!(JOYp5u{D|;;{>H}kZ-Fd5PAjsm0q;=Q$1E!niE%o0 z(EpCh&c;dq0Z%*ByM$OR&n$lxbSPO!$gYF?6$E~Z)aC=@J@p(t8~E1wSZjViMXvZ_ z;=?IXCLk{ZGd2gG{L;s-2?QwVg#`mm&g1X+zSHxZO?6b!HlUe<wX9kM`sSSgBf$qR zyt#Pg^exG)V1-zji-+BK{~VC(#uZs*dG6v{y|d>n%AK9NsQgZ%m)s@7&r4Rl-!yyS z0Fkrs@exeoqVAPF83ngJ%6zPl64dW{a&9qIEd^tvDbP?@8)8Opl%^lvfsuFyCqvS! z3qB?xX~s#KP@o~J_RW+^XD#;)IP?0w$@=t7bukA63W_qYqjTo@m$T$c)p|s$<^}!p zmZqvq$^NDq#9oWcp^f*9_f-)D8JY5pNs~Qh$6%eH`Sr2V$uf^+z*KcIF%GF|f6*2? z7uU{wtjV>ZYtZ!=3%5-(&Wh8pbQv_f9EmeOSrpC2I}lft9qLjs?K7`JDJFgVm?(2~ zto4FrFKcoz$(KHe)Gwq8GbuLcdO3kwcb=iCRV)!@8#f`2&>`AcvdD6|U|RO<VH~<W zU9ip9J<#S}*}1xEqeVhFvjGz^bDu`3q``j?qmFri_RBM4y>O-+%`ACZV6(bTFK|5# zY^)BUf>HLg>JONBCm@?BGVcTu{Ey^~wCM5tn)=4qX=X9@h$DFgfNB6#Cvo*ztdO<A zuzI|QuGxH|Vvxr`DZ#ZDf-Dq1S3`~&_|lqD*%c^Z_B;DFm{V9Z_o7QGFOpGY;XG7& zi*AeYsEjHM&Nf?eiO|AaE}QzFSr?^2+k8hYi)UF|IIzKV8gJAqFjE6&A7!b_G+xW| zG@gT&oA>4^_6@D|g9tq&TwZURwspCzMbw#BC9J0U5g7^>^oDY6(z8P{|7&(6UF^E8 zxzJhr%-_CgE=)hZul~{I!i;5;uF4YgGW{o;HH!2t*2H`0Ubkl@Rc0AQSp{!avT(}| z{NuX1La?HbsDiJT^$eEw4!lv=?|r1>yXuMVly-YU(BIVk1O<zF*9%vvyC5&IaQ#s} zQ;zlfSERpuH=Et|*2J_Wv9#}zHqcxc__{D~ys+{;oq@szliEI8Wz9j0vI6_BBR*wY zQ?mbtO>D0_`n_drVNrW|pdmf~?FZFS_$h|Ym%{NHodu-it!@ZUNw&*M)}3z^68<jA z+Oj{Tw#aQ1W%FW`W^MWMysmH57ELk%h!Z#?R4;QZ^^n;gLb@lZU^heq2ioeVO5EK5 z)^lcLmyEugpzLhq<QdbQa@EN)v^{xPm>EN>o0o5#zuQpxUtb)_S1HF*-ZOsK^3P6N z!e@8=A>}Ay=4a08=E;9)R>s%)k&DCmUz4QSXxsA7j4dj=Yg@_>w8ziVtDE;O$;~q& z`QeLIeuN~4jpJMX*<;JsnO%>kv>AtupJh}xfBo*OTa0kNy7=q-FiAc!j&AwqnOh=V zx*knA&LrSxS=G(YWv=+w>2S%eZoa(f-jS!nrFV66&k=*3J{>MO)y+u{k2rQZTym?M z_dM#KcRF11K=*L5aXMW3R5!oCV*GTt^sjDyZTF1Y)8R6xy7{6W>ux_CE`zI^AG+hw zW2eJqNOkl5MR)z@>2MiV-F#vC%cD<+3(RoqCFdW~1;H~mzoc#npKJ3A4N&+}VS_FR zp0W9*^A>fM%`a4X!c8|{stbZ=Y<}s!<?Aynet|FlyZO&yU1wOvW|!<Okqnz%;Dwo4 z13x$&D$u_)yEyrDs8HwXFP_+Q8dQWY-#WVUpQpnGUiji~pI&%6T%i94ovsO;4j1~! zz1`k#JsmFa<yYA^xlV@*ypS6H{P(BBh5p+1)Hm&?!-YQbVe;bJPKOJ8xpwU3!PDVF z8{Kg2k*MGj7cR~%;T)S;s898wJMI-s;-aPN7S$_(RW6$S_(H)WE?Ba*e4S+r7U-HW z<R8Zbi?~=hYfGfF%_p#I@t3b{JT(rq@9*FH`<PSX04;7Av-!}eae&X3yz=^Mr^bOc zX<GT4KBvS1c0Y326JMSh1z4kI&^NnIjRL(c^}IFCQ=<TjUb}7Aho?m0XEf(Oezo_D zQ{zBaX<PB+1*gUVwkn_eY~v|$pq9lK^=&oO;rF{n;=&_sOZXg{A0YK3(aVdBuSpV) z3y&^a)R{I%(BS`d@%m?s2uW02cw}z*x`)jZu-&yA9%?tjB>6fnJ$h}4bhWvH+J>f0 zFFzeF(EP!z8NWCkE;M{q>o*AaQ{w{rZJ)Wi=5)Bw3C6E{dhzLSf%f~q=zsilxWEC~ zMM+Pc4j0()i5}_WPKOJf;hvSHhfjwK();S~hQ4|_T;PPwJ9b}w8eAskRlo7T&Ywq& z9}e&CdOW`^Wp~O)#?CFD={DM#@&UTA?7XBd^5-U}{9T$Ze{aZ$t^Wg!Pg}=18&wc> z2Xp>LW@~bX8!CWCHG$)!fySv!NzHlY>w3NMmhs)%vxlCqo%3}Xas7DTx6da@61~5I zUVp#QY9&PPclMTubM0^XGv!@#{)n|_`#;Y_NyzLf7DoO(#vABea%Il-5~~1?WePaf zVAYKqn4dAhl|@*SOWZ=1dD`>rnKX0L=HKfTSvPyh5PlQ|>WOQw|3)n-YcDcKVwr<w zbtkU4eBCRmtLjQ_@}-H5hVKlO#I!XA`KLhEZhx?c0buaqR&d+Y2-f!EX1IL#x(90{ zrh3R&7pvAY)GJIXV?cf&MWE{Wj62Uz8xzAn6)<Jb%3`PCGXbsyxTyUlsD>c_s}dCT z^{fcI8s;sFvvjXUB#1JmCc=7H%6L`WhK#DrRKpXZB2~eMg`%5AS%CWkIP)(x5*BD1 zwc-lipVaSzS6o>A>dU;o>ip)ouh(Sbc<@j1xv3jDzyICMG)Bzu-SZtp6*L#6$uiB` zRThADjU!#ci#xL>{&|M%+lt;o&S&cNwb<#1sZ9$f)X}1}%1&ul*0)C66m{88c%t%I zc_)pWmLyA5K$dx)xg^&3t`_lG*UG)0-(f++PU%3gy%F0b&n{A-hjc4t#`NNDMA@0a zsjXE3ITUZB=y}UbuKw&0{9o=O_?rgpN#1Ufk8|2AOV_xL#?R3^95bK<`~6$#X1i2B z+5z2CH*PRYukFd-jM`FXpm8vJg(N%azfqU|@9Y&C2fFY-FFW-U%jeEpdP=w(fGhhG zd8r-uJWge|@#r9zBRggXVQyIH66nvT`sciiJVg5c%`!Y!CYE8^TG(Z5Xh#ts^2PY5 zDFt^%KBsuT_79g}&WXxqceGb4AEpm{sNB6NB`MMw*U+;uw9e<|wRL{+7%E53qP^M# zn&vO`jUqQNmw<<Us~gDI2}P=_Ju*&s={+i8?#!|+-K5sB+;gkRgM`=GRmGJS&sjHU zen4We!g>%mq42tN;StSZAG46xrg<^G7ComaR?VU>?of1v6n$$SyJ*q!nI3AgcxLnK z%`b;vF26iB>{Vo-iPBDuTC8Vz<^e=diqbDb;bWa*DBWnHWcIZ;a&3FT6Y(<02e~bh zOclHicEqb$-Him4epx9`b)|*L=o2vc-onJEF{zAW(f}19j)jRnpT;@A#CA#RfP_Ae zSl%~A9DD;IzTB#9fJuUF8i6<o7LZg(&`$RZg^wVAtX3Im7Hmoz%U-fWxngfX<<n$T z5m%aJo(~d>edwuU^!KQmbwYt3TLl`rz}k3$A3zf1n^~aPcAikr^M6#{h|3eId5u-x zH@c$n3YL&aDtN9g@9cPa6(=pP1K&M^4vH$`<dzqF50pqPL$Ok)(5#OkmEG!%D@^Jx zJ)!WwT7~~slv&}&Qe)H&LzP&w%DDgI`VKguaNV-k^-HL7t}govtL#Ji8L#*Vl1jxd z(q-qy%U)=foiL8bzNKjtVqVYt5>^4!yDKW*-RevRAKWug^FPE3my_Oqcs9Yt@?~9G zn|hh7q40}NsVPhw_ba1)Cu$EGW}hB!mSM8bH3B}ff2?le1pYG=(lAhLj5(8Nsn0}R zf?Jnx!gxp-ae4Likp%v{S_)VcFQ7@C^@Qfn7<iur{(G{8!r!Jy1!C+N=l>4;VVFf& z{eO~_q2gt57M_7n`u?5rR6eVrO0X=^gRvzTzp+ZbOP747E?Eo4Ml!^iBxbWLvQb~U zjKwo&-ZBn1i6V~4r1<P=R$VB}Xk)(<nf)a+v;|aKWV|4_`U;!Mz(Gv!rFq@zQ;k!b zdI9qoZOm-pW{{fg8TB!MLgBs1CIcUIt3Dbx(Y2cUkw50&MP}Iv^5IadXlOG2KTP>> zoh~uXw#Rgdt?G7N;ykNFW+HzE#aM%!L_QqHd5>M!_K5B+3kTSBrNHkPaolQ%u4ub@ z>++6`;3cVWS1V9L;qRC)S#t0?GC-#j<zNRs!23@^(OOD`V?~RUSf<O~r>oko#-31i zi&ge=UG}ng*&#B-86Z|?Yfr`ON1e>FA@gxZWVE#KElhLFQF$#!e@*INn}pKG)%#f2 zB=X&Dq?0Nq>0+Zy-K;8)rP#Hu<7Smj*%Y@Cc<LCc6l?_6jLWcZ3=vC0qa<5z8~f#m ze8;on82=^M-0LwE8$e;v*0m!u)Clb`C@y3tN*%6XN@dl-GF8N=K!i>m@MU(9enMpi zlR+vo7-*sJRq@KKg4i({Vz6*xeRj56^|@cnYEM?BKYVbiDkaEm%bSqY>0SY(7PIn8 z96NNioXp}*TCGnhL#lNp=1_@k)RhcUt(iazg{Mc4*lqMQ^-ru8{V(1|(W7=7Wu2@- z``$lQg%aglyp6K7pQ0aCX8WlsGwegNGIO!lO03Ktt1|0Y9f!jAACFaLFSSmrj7e8* zHzv$bdzDQ!&!fD0>iDAu0^F^x=kHT8we`Fei|M6fE|VCU$_9o@JSM7v;qr-5B8Mut zq4Y_a9@jhk4o6*!037gw*l)Dg9UZ!StSb9+!q~QsXl?&X&&2+h4q%RLVt+Pe@tr>z z%<X4#^NoHVQK_fp*7b9a+p*&+Utph%wbD;4U&dXxCrhsP!EpEQsPvRCNXSOWkN*wI zH`hNW+EKO6aXETSDxJ4*$pUV%lDmGz_+GcIX^V$NX_@Cia+|yuWb=OK^TSokezX?a zfrWMl@i2~k)dp%C8zX;379qr9z0CU?J;x@5$R-oE9^wUlI1XRjGqdl`fYjHeTUy=0 zbSeh6#RA(~gI$&Y*5XI|JW6|Q$-&wZrA?G5!5AE?f!KEYTI4Q;kh=C-DdV6V!@)!c zUt0KhGhAHJAcLYdVSK(o?fRrcU4PG!3-vN3$B=pu;4Ftt!-U_`@ucF*c!t8e=w6Y} z&7n{0Y}nskj#Z+z^BzOZSWoHk@Dz9#U42r#-$#{@i1+rFPJ(w%N4&q~G>2*jpBUaZ z0z8KI7xXc~`!$}SaLx&M$J$Ku!;^8WG(QYg`~Tj7Mm18_y2P@6ughvzvo!cuk0kJe zX?G;1a-mc>*B@w0%e=RSw`g9?HnJV$cZ6U1Pq6vpm&flaeuez7ZdlGkJth)j5nt=& zOUsK}_<CNx{1P{judVX6RKAM&+Am*o<?APWIj-SrvV8U7D@VRY$=5lPYiHQI(c0jn zZm`7NcZ2Lkqc{^Z`NxeFj!|P=(`FToy}q>6RXS_p`0;YUu47!;#EGtPlV+8bx+Yq2 zXW041jxV}??5vXOi$;wehbl|*iJ7W~Dd|hiuwHhU+cj~-_=zRgk1KM`D!zWw^%lII zc6^alR?+xzBSw$Z@I;%W;T2CCmzYPUgwrosK9h&6EzG`&`H1w)4OG_b`3$H}!StJ@ ziQp6CgTQAOtbK5pY_I=D#(9EvYg1vhg1))s>(ntmc*U9<{uf|`xn=_)6n?!8!s;o% z?e|cQXPN(rn#wZh2BexwFA_X{JH*CAW~)T>ybq2q;{;f{+5pfxuu4{wzXg#N<M_yG zp<mL<<osyCVPAjg>!jQGkYqU+ENOXutQxpa7*=k-(*kT)DGd7wctw5fo;nJXVw%-g zESRIdmZ-0dk=5M9-XWFMT8`CNnK05lh*m)ipw3Pd3BMB%u7mX{;H3;Yf*?AFXDGbo zFtxWt0@itEyGpuwl~<T+J6jfr0IMx&vE2)`s~h1+p~j(W<J8bqOJ#{HRilsxDdhFZ zgU@gnhx7L~xehx<R7)j<7>5du3o+yzoqFU!$)SQJ2O-8qdxaPWZDKUDZc;lyQ;3l@ zRETkq$>DyM#ZliuPmY9Ohb6eH5Vd9nqTYkJ5TocNY!h45<9w}g9rjlpc6bL_M>w>i z*x?~lgCw~hI=a<dY}=R;<290*V47Ry@r}dH)gviNG`$#0Rv{~5jC72ei^$S+%_l~x z+?8i2JnxXub*<~LC2cj&OS)O}eEMDR9pGKKgon^M|LqCZKUvahZtqzTqbs9?nB2d` z(gS<^P5p`C)cyoWAO{KC@dGUAKa5o=rmKt8M({TFR3H5du)S}P(;Z~+DQkcJC+bb6 zIC@Mu7%V%$81tr97#(1?BPO6B)$5NG;o7gqpo8X^<59Orrjj<hMXsJeixg79@Ejpb z6Oh&Ke@LLqIpD{|P$pf@B?c7C@u)i=q43y$L7czalreek1bW2!pBy<7E<2V;4fV^% z&C^ldyM!(?_!2F&6VlV;uv?)R%opWgLyLZ`nh=~UKAXQ=V=@LE$Zfo<&lnK84K78W zEJq#6)@qk?7fAxLY@&jzNbyHW!Ld?|3)@u~kg{UMrQ(Zp(il59he@?t&1&Zn6AItj zN>a-tP>-z%k_APfc2`ULMKxEIc`h6tYjTdGhE%?;CdWlqzd%z0TiwA)Y`qoHuKv4L zqnas5aXy6d!lM7zBB@pR@0Emzq*m39D6!J|hdi~s+RGdC;czg#qu;Aag+P36BOhI- zm_8Mw5W#;C(qe*%Xt~NP7ZSC&P5Nl(jE1BrK~4!aO#qE_G0Am5eK$s<KGZPQT^+=P z!aqfG(Sb%2Hi=jlN{#mYFyY>k_7lYLcIYq7{Wecwjf%oJ)pki8?xPWnvR%>}dr*WN zxbdDDEF-Q>EwSU;)W2Y1<^HYIH?!s{3^|2Z2YxNHX_B_8;Xk*)v}{^I5$aoD$tJ_5 zb$meyy5PG%$aJvG^X7Fn3Zi9J^5=krFOG$al<5P)m<`H*sts$)`6;||v!n=q(b=n` zZ^;6LQ!jEx*pz{yXIG!=@B>Y*z2bF=`)c;nht(bLM58Zp57$1qxv3bvMxbh+gF^wX zef}ZSedpD05Hwx;)NnKb$OTr~dy^t*{;IurJun2s0d*!m|K$=6rLqBrf_<Zo?q=mZ zp#HU${UM=WH(d_&`xO@=b_=@p)xRt>d4aBMl<f<;cB%j5m1li}gjYjbK0tMww8&6$ z8D-n1Dv^scjg<XsKqF@_wooznjL=HDYQMxszZG6dxFA?b5D5M~#!Abet-$#%BJ7~l zmpnt^mKL~4&CeBj*U@0co>G+~cHn$Bpg@GTyVPwJ6pv%X%{J0O^#IA->KE9UL!~Zt z`z7*IBJGkQ3&Q`2QcjYt1cI8)z^<O>Po$J%{#R*k!EZO}J&Wlcqt|y}I`k4|T$}O} zH$N3=D!WS|_36Q=S!%14dV4~to`r;P=btG!-=~uZ(Y3kpTl(W*y>t_`nU7HThi^b< zyCqT)T2WbxO&L9o|0WIK&yU6&Nh1eRrY|jDG<#vWo^MH*j8Wst#_IHJdpd^mlW>{; z6_+n4_m;~(lo=-Z<&t+ZB%aO=b1m0nTWl{E6Y$4n!?AW|OYO{qwKET_DLKr1LMuzl zJoQC(A8K+P;s`+wVy`Rp)#G+gqzXzj^*4P%K<4W2z)eS-r{!InT6Yiq)^%{x9-zoT zT`ZCpc0%5@ai5uv6v^Ze+66a)1ydA(xLN5w7pPMBG5!r;rQeQ-;SzKm2tK@x<eQwt zsamqbboB>Fpf*xQ=4$bkAwew?^neaJLxLWcLc|lp&_kgtoa1zH_4W=Fk*qge)t&gH zH(!mi18Rc6)jPDtJAqG+3t~6I8i#5GNS1FIzStbzVe#D8cF5f`p1XvbZ@AtnLu8tq z-GP>l@IAc5^B#kB<0bC~l3B78T86`9dch>g78xfu(0E759Zz!6uE9mS_LT~8XwP+k zRvUx%0(qk97;_Z59G=V%(Ow*XME)FdczXwR#Q>+=%GFDHUS`b$RMqZto)T$Ci9L(h zQ26YxXwGlIVsKIy*CFrKy6p!BsyGvJCRg*C+!5sp-Ui><8h4vv?t@{dkVYT|d<(#> zW|)DzppDfe{XA%Pu-o_ug@1RDGWV=?9WuKWZs_<YeSy|>T%Pbgz<QU?Ie-u5bJdNq zXU@RIk<g&Lihf@>E5&7VdGKK!-lX1N1$WlSM|}>l$^}IY9T^N-=I3Y9Ea(9cDlptH zC`LeiQfz~gJ^4d5k~YiQ*K*hA0xDQ@fH1Whsl_h&IrVw*uq9@gspY;Xs58?XZRo2p z%ZFmmshQYb2indMH}nbDa(+pvI^9arg~EQMZseN|DZ1!Vq(166ax)a3A!)vX9TMb| zO+%rbMYBL-oe*qq?aV#3Gq={xe5H0~UG2>MT5BvW{6Zt8zT(2q97ARJWZ!2Zy32{1 zb`dF!=U0m!Wvsz~AanI2zz(|hFbHiGha-M<fwp|#TI<?Ympw`xp6p_L((A<Mi`CEG z#rndvr+yMKY76pIXLW6L*Ui;w8-iu8Ah91pKgWf6Tw9493E!VTNpY?^F1HJoHP~93 z0l+fKwoX-d0mmrWV^5urphi-uGGH~Sb7*GnYm~Xd!DiP1nE*?xMn~AKDibVfsNIS% zj+?FH?_qY9Uy+>tG0NKwf6m?kqrA6<e=gN6+0Sq+GVi@#%EZR&mB~RSIGd#i*(0|E zs#=m(+{9n!s!39c%xZ+Du~N>_rC_gr9teY+j0%yy&8`-~@}xObmgcck6)BDzy+ks@ z3;rpSGzwQMzm!q&pra~Pf6FUU@gi5$%bj`$`5z%V%G)K-a9li8UmY2%=K=@SMVAV} z_p3|cr9z0XU+sseyc_`M7{*H|KXSI*#dz?<s4}87$2xh5$$-DYFhN(H+2NPb)q~tx zI8HzJs1f?PU;UIP`=1K_-5Fo6lrFCD-pPTO871@PEL~j5*9;sA;v1xLMv-qR1FCm& z`BHH!GNaT(vbnf{s)TM@b`0kE|B_!Cpj#L7)Ue1Rv3<vLiRs#QO!-~bm>Xz(#S}gz z`)W(J)s{5Wmb_A1vY+iY=}E<7?4BeBIJA6<?n6@vHv7=64@(~k98Jz#J)WKu?@aq- zMrU@W9gI(gYa5-Y?ol#w9V#;+yE9$EbW-Lkdx%k9O--_LgK?eGY3V!-be<8SeRRPd zbROwkzmyfObgr$zvPQczeX1veOdk6K$0*rnccwp}_EL44zsfw_0BdQ5HDlP_rd_?r z(7`NF42IMV7&9OVyQm9k(y-iP+vNJ5Zl|{n%REzVw1LFC*5#wT)3rZTW2ba3)&)MT zUGOdyR{RqVBghPtq{!?*)q$iH)A{RMRmPZ-(5>)Y4;C;cIK0+P%h!CJ=L)OmpP2j@ zRW+0U!c2}3{yt{6glSdw0VbjSsJy@GdvWC8<~973Fj>h#=~}CLi=mUuy<d!h$^lel zuCAKh&4xrKS>0^&MP@g9oo;G&v%4gtUWou@K@3WoKsn#;Y2x!pN*NoA{~{xymu1r| zy4Gt54TUHELq>~O9~?t$(DjPh2fw39;1Km!{j{dKAM?TaAIbJXq6yajQy=>Ox(|x6 z9(`~;E}5(zNFT3mY+wY$YsgkL_3vV27xkX!R-+*USBPc#dKg@1QJccw-W;9fKAW!j z4IJ+2$*<H|-B<`~YP(A267D+o<s8+GPDU^HDBmH-9cbKGI$5rz6e}m!2K86E+hncN zO3??;24M-Nj-i*g4xYU`*6#3_0b(_@NxW(z6ZMHRIz$gMI9Rgb0rj82io~_0?~_%= z6XWmF5)XV%OP~g5ms0z)G)vfDJ_(-HjkiFAII1->WLDsAIQC;~$H%c<RT9T`#_=Cx zn;m>uf`dVU_JFz)aFO?8O!aee3&J0LEC}!a%tqKOdjpAWoUQXnA@vTOhfNUt+Nk}z zq)y`RMrcdGbMZKLNb+huj$3;$JE2X)R7B=`ZJ$8+V5|PyB7bQpON}*Zye(n;!yOHy z+10xvSR-lFBchnlufc~Ut9s2R(?WTzzlB_CfFPp3)hF}{+=|smL8|Es371#BDX7jD z*)5kNWO+Q~o2=gN!j7Vo!kSX0$fUq<`CxVBhpoihP_w$}E+z|meL2C01&;LR<s#kn zm#9(xN(b~rGf7_4P68xTyZR;N>X!*%qo)sQPFEa*HLrF_8gU@~s($hIv~tbICA<_Z z^KtYTX)nnwPBA~lp7CI762nxXeTs;a!Z+~@h0pqwhD1d<%WS<U|8VB!sH~WyU3!&P z%o$xN3sKzndi7a+JrCD+7~xl*J!<Q~aWvin+}M;I{b2r8)W)skeC6<Dx}Eo+|7eo$ z+~@}$u~z0LcSKY>a!|d>^kJ0upV1G*{)BriFhHRuY0YwbNqk<B<`(uN{)<i`@ow1< z+TVaQ?oXVyJs#&v^*nb2$4T*-fRH%CB3K*&x_YbcpsP#-(<a)i!hz&mKGa}he3@uG z(L4@;C}9PHp8iBl(SM0CDYu#Cs@dy3ldS^J5TZ+CF;5T^EZabn&sr`+?S}edfqafu zet6F{ql&GlNfH(1>?PG)qAo?P&xG<CtEk7+KSagodW<~kj7rvdz73wa<d8xICn-~F zD6SCcJt&s#o_MysOU-O6%xscF<~Qmnl?%x2r(J?&oI6z0@09iX%N)-umgs%Ek1#2H zS>Bsn`(;YY?V(u}=-hOs^dM9mMJeVoL6rP><QLNZ7nm?AzszqVtlOr3Nr3Sd2f<mY z4#kwg*mHRAxqA=qr7v_=Gikuuv<U7OpLVO>7~oCDv(4JFY{RutVT2WL@@~4ekD0?* zKLidHQ7QV_TOEaOL*Z#i&xq-YL+p;SW9!JDf}QY>)Z(Iq_gw2;=rQ2d*<Kzxo&KJ) zaIXC=`)GU)C|_QFQSQK^TpNZA8Aanu*pn+Bz*EOb9>$YEqnsSIgp$Q{RZv`*&R1$P zohD^(lm2@VMRC%8#Ub9HtAW-S20%6L18I#0d2e<#7SiOfUKb?iwZLR1NBa%bZ`<e= zDo?+n0PL;K)~`6S%wib?K)0$y40ULNkFfru3C?a#OMyVN7-Ln2)eP!93<P6Re+7t3 zyWdBD3x&Vj2f0mO<|er<pOK%@7{<1m9V>IR$4NXLMf>|QaPR2t#{2OZzO=#{ePJ;y zhE68?2&oVrpgxVUPiW+yWYb9BU#y;>`9$FQQeWe36<TC8=cCQd1+pzA8&e=ws_H+^ z5+yC#)T`l;O^*Vnej|U>f9NjJraF-nNeahiIn?=ZoXl0->M=~~kd<d6hpbHtHItO$ z9xk)yXOtPE!o5JFd{YWM@rjV)lf954(m`$tul46gPVIwe1|OO)@GJU}EajO=aERS_ zi<!1Q!anCkb0$IMCzRQh*BhB_;+e@=U3KsdfUYR1p95IwSpRx~`G47A(_ItaukwA! zbvO&Zh+I^6q2G5nE0*@{j%l?&IMHatYBiNI1!y{)77BNl3W<rMK2Lxh{y}38zUPJE zCut{TY8do_a%UJJaf@Ic@ZAP6BAwvM+v$mcMqGJecV6At#tcGdPXd1{`>UACBxIKu z^?;qdKiR7r#Yyz^Q1p_idvLDM01D=zfn?wGN%Q-ttr-8g)z38;ZM9<p_S`brC93~& zBAPi>4h#p+EEZU@2ID`_&yx8xQ$x45TUQ?f3S7kWCzBM(%8f;yX%0^%Ld-MEOD(^Y z?xpjVG5+0FE^R5}o@s0O?KrNr8aX0A8i*!g8H-h#8YVWV-T7Y0b=c`{)t_%u9X)x6 z)|T~Fvne;wmhA1Wrs%g6uXE%$-z(-gX5A}p&3*!n_sMX!qxRu-+%Z)9@O|=^8@J0^ z=r__|o|_tD8P|Gs!4~+HHRxg;D%u>ib+z7u(TXi9nMCJsZ)zZ3FGksB*~w0fXb7_* z85hacw-P4|aTrO&kd#CBQk`fR<a(=mm!=Y*tLvw!y$x_7>9eMp>6;VM?`C?a)BiS} z{u$B(*R4K^GP?dJ?Gmh!>Zo`92qyg+)U{L>E+9a^q7B(J1o+(5B>lWa4M13e)a`mY zZtd>qUUc4b(u)pC<!_EvKKSr@3NRhfp#l*P5VSY*aS0BVtbahA2~r93@p4`FgX-uG z=?qDGq%+t(g>_;3`>YFleh4ZuM_;ejklT*-{F%IFjm)uX6<rDZ&5xyggu>4=wnp|^ zlPm~OI<0h)tHjo86fIulUAlNdX}NcX^*Y1yeVSV`d(rIMOh1}#ydYt`Wgb|O-33-g zOJ{pgh*UaG6L%HGIYcI%xOZX6Vz|uKq8^6eaT_r4i+?bnslGr2b%V47<4U{wjyiFF z_xA<gFPrEuxX_nWRG)s6%VB!@3E6u-eFGt<zW~>~FdkDYpJbBl{&Ztvx^W{e@bt^X zw&->Wir}lEFlA4{_jmp=M%Uw@Ltc}PmwzO5^dPJBuBKR$Q?D7<T_?webl)_2yxqOY z4=y&3e?tYBXX$%Byo8(8E31E*cd5!@B-OOC`fb*y90{8iL*Q;R6o322r0@t#5cx(I z{Qr0R(N?xCgGdFs|0^@>%Ak``tE*(vs2Dud#~xm_oyewLq)`t*IH~DZIDKUMV)ae* zb^-8<7y!FV$z4@?!}PDu#0I97u~hkc!+(d;=J=$>{89Qe<_@hYmkGR_@5@~M8u17X z|B!;r)i2ub(|u>vE1-xp>6|HYH*<X`{1DM%1R|R$Z2H!<3##`pzmOq+<#JJm#z*^B zwHoF@vFh+%RG&UmV6~`MO{J5*ZgCVdiFCu=MtF3)<c%2_Q0S;1=dC_fUJ-w{{6RKX zGFP8LpNX+TjjlnP+WW3>!lye=kPrK|BOkusB{Lbz94bTxv0{;#rCLb$mo=A*XDIxX z<hBh4Pu@4Bzsf$~iTj8$xY>J$DZI;`BD{f171M%9?Ov%nZ09l+W*#>!(y2_bG>`fJ z{`YmHBalgzr_l%Hj+<nQFIz2ZX2Cbn1To2!an+nS6oC^L!W$ViGcYByduAEJpPqRx zI{OL)t2jZ$@#uSO=Hmy%t^O!4AvH##)Q87ec{O;mfa#cjo=29!>I$YKVx4E&R_>E- z!5+u{+L`<0teCa?IcApKOFXym>hbbNr5qKQz4)sSv&kxD8>Rqka&;E7`S5!XR(eR^ zSZ1c)SIJr@-91G%?3<K-p7ghUDEZXFa(Ugao?y&yM|YaD2n_5ai%jjKd4y6kCA;uV z%B8dJ2aZafAA@q41!cNGQAt>R!~prLjw3{|mvtRHybvXkQXg^DMz-gyfCK97#IrYp zKwC!aA=D`p{t28JAIdxvb)=;R`~Zdxg|j6^1Pgz2c+&Q2c<9E8`SuY@%galb%$`&3 zT7LbHY?rO^;{-e3vu?2|E>m7PK-8qVGpy$yiVPJ3QV(r}GXhD=crH6-Ns<22?;b<E z8ZAf^`FLGRu~x*t+6a~sw1RkUWUY^NvGXZPrsXozQ(bgjMr||eV(p1(-N1xNo;BD^ z&QJD?B?Am}j>$j=uwfKuL#{>3<}F>kXrWwOr0XOjV$5#&i&%Y357O_lCYL3Gw*aB) zA2QIF&y)ab>5rsY*&p*>JlS|Bwo2K`cr_(hYFRuX0XEA3*2A>!x)(XXGHwu$Se?Go zb!u1V5*P~K^`11Io*r6!uFq!uAnu!6peED9EMeK2sCNLWp9>(9kp;*nOeIQplGLKH zKAs$Y1sWAeYlNa7!02dw<yvy5mwUuiGn@QITcoSH0sA6eFsZDlVMlb0^n<;TfdaL# zPv&2C<3Q{}J_5`8W4WSo4wJg9t>A|KG66OVN{UQQD5Z(qkV$f1A|?>VZgH%cf=A7c zkaiq88KjH^NcARrnocT%g_g{dJ|FW9EMr_ZSVVg6OSjrgC{-rnK53mYEIiv)88bX9 zw99RT%9NyC4TOE<%5Je9xu99Irjy0tKr7|`3Z0+GdyvfVt(EjZqqz@mo*|IEXiNOp zgF$TWvWOlQ3P1Zd;Z5@<FeVYUE>zqDr~9tJLD|agvWUJbCGbYdmLtiL9)Y&>m7TQn zs7R_FM^d(dz_qlB>Cr9dT!(wU>j54ul3R(Oi=|(csoMjjE5v`Beg|n1h;J*cfBj&~ zXUUucR#$`|JP5R`Jj*C`2D9(MzcD_ew(L(9M^Nv)iKd}4Lu9P>AuUtrEYcZo)vd@X zbUdj32s5+GQv@GU;06k@{2G|u2SYUyXTPXEqgTSjrq2WX)_rNTv9u(4)VMQU7E<Sq zV9h_$X*eInh1^CO$d_81lNWIojq@o+1KYoX3@eC}#bnf{i*9H>BDPL)Q{<Glsfp=V zyn6W9MijA*q}0rZ8Yt8L<{F?5-$^HYCtKghfa=CpY>Q0x3byfz-dX;dTLZ#jh2=Jf zp%Oj=1fB$I&d;Yr-FcAdE*Ysj4hH{VO*=Ww7;d`cs?-_*6?|BNH%SU*Kpw*imBQ3T zbKtfbc}3=^m*oq_E$mRjS;EVk5JnPpNjxgXfg{1tEXx#-VP-CpXN#V}T<{LexZjlc z(8!!aSYxQxoSN3MXI0qMq=D}xr)=u60%~{bJ2Z23dqn6Qbcyq{SUd}jO&9!LP|{Hm z=%TZIk_3SQhfl6Ctf0@4xGR3|cB{967#SQaX{#SZLB!_Fk_xq{LNiqsqST5>CI<6R z$@P%N!|G_~lTk*AFX>&O@TkAq0@GX{2#?7OY`~Iv6+BG2vB#?C9${0_Ld`_^*hg)n z8Kh}HpJ&%u8|t7RYIA$Mk8rCV=7S!uSi^5&wC3u8)Ix`!#_reT>Mb}Vq?$`|^&3(V zondUNYX_z}EM|ewkA<an5NNGhU(@Buk{tp}2MN)k>U%(W8Kg!hhV&Pd5VvJ|#GJ^? zE>P9S;r*$9_)y__?*%OL%l6duo=<U)&PZlz%|=$AO?~8hk7kxUfc8<X3@ou?ip{g} zW|_m_XT~SBBQZq|Hz?+CuR020IZ1D(9IResiYYVY=}b%6%zhYStSny_KSotpcZ*U1 zot<Yc1hcYaS=1OM=!DtklBC`N70s@FUAg_zbpVFPBE$2n&Vs(r5q0;r^7tjspUA@y zJ5O?;E(xheWp2<?>pLKNLiGjP#-az9?U5D~ifVAHPXew{z*PV))?Yki66*)mPJau9 zk0V<m-}uE8s^UioK6(;}?E*0yi0T<SE-XG!vh_rJdq8IG8k2^T<QscC`S!6p$O1{% zILE5-I*AAoA#+DhF&uRQ8K0K~Pm)0M>BY=zb-CvROXO+?I^et0r8n(SOPNf-Y}^)1 zV7d7ryV;QJrHe3_WkXxcJ6Lih5L^lLV!=xc!B}9ms1GP0Mz1$vTLHpl59C%&x5~T- z2gZDw^+?wXHa<<bOjk|5Ne_jeXo9$J#6W!sD9nP?rSx9dRh`c>6kZ{TlqsU#K$j|g zS?k{yn`RlK7jaw6qB&SinsKskb@!5r{Hv;F=(O2<U!t#_oV`$#CY61b5BW*oOSHZ~ zV2O>?=u$aYH+J5l+lLOF;45Exmv*&Y!Hl=h=+VWqMw1;Si}x<=&AhK!&QQtMA!6uI zR5z1nFYuN3amxXr>z6Fymb9fMi|3XvnB`u|@xDdg|HIz9$46CN58o%r1Oh}7HA+;} zvBnk}#3<BK13wdz2?2uyLJ%z~mn0?{NSe$5N|3}!l;JRzR<PP?)oNSY+7_!~xTpz9 z6TDQpsZeid`RN{mHYyK9q0IYT`<yeG1hD@4ywCG_|9H{KIcM*+*S@X2_S$Q&y>?;6 zqD5$LY#ci8Z;oSfuAOeu|159M(gl^ilG41Is)a@6RZAu>;+{y|Y?YNGbsPN;>!L6B zp(fL+MeSsl>C6+92|v^eE7)C;b{3uZzinr+?5Wk4(ty=UC+DUn7xqTb%JUY}+j_3j zo5DL$h+6i4`zsxuE$avNn>FPhR7+u=aCm*?OT6m9Ij!)AP7Q7G2WV2JsHC~QyqZ{b z6^kbU{apl9)_)vagoxG0%tiJfO<oA_c>?T6e(OmQMd}+6v7&4<Ue&Q=crQ5GLihEJ z?IKo|Zs)>$+Cs}DQlx)2TUe(^TZ#^^plV*p%v-BV3o7R8F!qndPD0<Z<b>-slC#yU z5Q@94xx8tS(?;cMc`bjOKk6`6bA@UUW+rA&;D}sR+}tAJ-$w=(Gv5xi?mA&2-Rfc{ zgx;oH#$gy~pK^_~PgAzv5NVw~g317ufKG`5g+tifz~OcW1oZU|3v^Tj6lP);a^rPj z@{BUG@ND^$I)i1l-TaAFq<TnFIn6(Yq?!ZS_%qr<W46+cT@i@s8Y04r&XCw%<C!WQ zO9%b0>!pJZxAuu$O)TtK)gc<Uh5jy)kq#<e)V~)DV_JbHyLe{rorTheVq3=gn$f=? zyQD<!nmBpi3J;rXcj^^a=zFu~XM4Rh1na(+Gl?h4SNFeMMJ@f$PL9YmmsUIdACW&; zZOakazs!~{KA@%`Ls|B)GBw=CSqe#)5=p0?#FCzwZH|9Jg4jBE*#T#UKgg^mqoW6J zK@zV1K1a)VY{xNi?Uz`QoObh~?jlNUvf}X~C3Ij-56H$zYdzsEF^lcpqdJGY^^m)X zB>m=-ezQ$m=&BaFV@IT)$B`DhMYWw_)D{{ok+Q!Pk$L5ADfW%t5mq54DWj}XUBJo% z&%`ccCa$PggTpb5+s1hZ^$=*}wkf;)hx5#-n!KpOTQRS);<i%z%6s<+%W<*hWy((u z$k@%UU(f)HP-rPRyI8&-+}gIJIpIf8@pJ6j7pfIleLO0S*k%;v+w+{abfIwY!g=t> zMK@iI=0Cy<zR9`pe6WiQ-2Ys-+_g1iX0C7H!dr7H=hfCiEo`~1<btX07lu;;y@VM6 z$C;&`{3rZ@qi=>QKHfVfa$1&cwnPb{xst8xkZz9I=&tE)vUM0hsLB_<;#TWKFvbMF zm&&7AN>o_B)<><M;_Ao1K>w8(B{X|Usmj>MdR~gVc`UB1&C|_+DjmZKf1B%S-)FdQ zM>l8=EG*|XV&f4(R;W@a9J_Y(tL10?D(RDXixyRR-6f^-eYmX7l?S^hZqC_@0jYaL znz)r7=`N|l&9wk7oabFo?q(LpGkZTE-PY%WGjAS3M2Xv5<zB!w6y8z`ZBAtcv->rR zO0WZxI^tkJip7mYy8U8$%USuUtS=swSpNiRV8eUrBl1);Xar*9-C2w6w$~`T#gIkc zY0+a}be`vRhOuaV@bFbXLFb#)n1r0!5$_hvv*gCCaN#v}6Mcr6B;%{`6RJTf)(Ab1 zjMzZV8LvssYWgyI!SY#tu+~Apsf3*52-1bHIiBcGlmWBkIF6M#lf+$@OEtxqXHTJe ziOIyT!rt_Jt`0)j+{e61&Ryr|*aGUWUuv<1te>FE>1}=Z0?NBGE;4G5kUxAu)lejI zv~t?<Dp&r7ZrK8^f7sRarm4F)WTsVaXQ6{EkMC{iSTZeAWBD6FJJqgB8^kEf#mzi9 z{~#DuU)87X??E)w53Re$uXpo4ePb->e{$DL>IU?dZEL1)jI+P5*58r!Gk%kt<A?RM zmGIBQkq#39Vq*+)s(FU=weB1>h*|_aN7(K#cQw1fs*Xfk!5q^CKdJ`n0+(+VE(WQ~ z{ulb5!i}ze=r%nFvk{%R-mA7uEDq6uQj#i0oV5X_OA^~J=?aoY8f-DJqAvL9^U_e= zo1A>FZ!6pw*Dqn7lV?Nw95|bhF7|rzD(AeXvT3b%tgpY-$zH^P3-p&>_FjL~JcoM- z)D-V+7jK{iyr<-Q$B6;{b)kW%4efztj~$D`V>;r6a5U`+{i$C<RH37&g6()}=wIrJ zNm{GnEFuMLiGaNh81drYP7Q@-L+wsLf|=a#vBA!Z_v|T2jUUnTJa#j#czhe6(9iiJ zrJuM&>Y_`}+9==E^kVCmthSGuh1f~;sPVL#w78+cGD-sOaQsqM=o0qdi=Ae$b>06g zh$X_-XB;3le2T!fg>KtOtA9>OaZ@jANC&8Ec<7dAg^mxZw{WCr0Z=eQRnt#0t8O&< zb<v~0=<VCk>mUn_1cS-~KGead)aml2PMw15=F)j`i$_+%#<haD?ax+)4n`{EpU@~O z2k!Lo(v!|4S;grVCFM5t^&W-6CLx31Ixl}W)(fTwpOZ)l6+3}KGgv8EtwSdtenc>; z2lmEE?;Ky}B^#_df3&Dio$DmG6V>_896EKHEc8BkhrR~}RRDZwC!bR1pGNB3oD4mw zM;Tz6G`QI|x>K##QuxL3MGG|v?!C`|yStelyHyaYUc@Pac*@BT>)6B-BJR2*<QJ?z z7pxar#X?}xgv+By&mM*93oO1My}-mor?y>ZhNh5k%ub7a-u<_uoIwML6JK6Jmswq- zo`eMG2un%W&PQ7)7Sf0)2Q@zwrL#S!mM&(YE7RZNc{LT{=f*w1biq6y*OvS+hXwET zTo$qDJ6?B<Pp@~~x0bRD)HsAdudcG*8P&$M+y!f`Q$%;Bo_SBoA*W{eD97vs5uam- z=<K^y>rbS|y94o~XiEAz5T7A0EQ{cQHt!XaZBi}*%_aepVfYB?#7eVJoex6IG|_>J zM_r96z=Z=EliWt3@5rljJ(b>d##0v`PDwkAk&|;_-c-rIeUp*bcA*OJzH&}l0zyw> ztlVMHx_Lac8ME{77obTdIK?nqH`-yJ1!ktD5;okBOZ1v|--ell9;vgCas2IWTW0wV z7z(Oxa?Ab0r6r@?BW6}CEOp;jwW#z8ck#@ei)t?#eVOkH`7_e0uRe!@Y`;bJeWT5S zs_Pu?!d>h%1Ga3#8Q;<x@3AlwHOtFPSu*sJp7rbrcv?C<?FO$*TiZH3ugL4W9Odfp z>}L1QI(pT-5~QjQBZyAV0g!=hi_oE!n2G+Nm6kXB?DS3guq4eUsX28ET`59DSP$54 zb<cEJCirS)Iih6D#OksOQ<cM!&KYifR{Q&=m?Urn++vem7lbZ;>ML#DDHpY#PD20E z#6pf%oh<{Vf<GKRHN3+xig;9-p?QQ53@2Dmld+V*xv0?h;W+A_(R1w*&`>q?OU+!n zEqlKw`DhFMlid34*~>caqS0f07fZM3KNfAX*JxZ+>z3~1ap6Uy$M{BjmwM$MPP<Ed z-(^0M`pIoJx_Yx$g~L(h+@*xSE79-jd(=^TpCJ`c_Yo}nDCYJ@q*m&&yOBnmF|giV z@8R1>&$oZLy+0{5=4(<optc>AC3A84)e#Um*+bXUf9pFuPYV@%8t^oCc(%wZT5^X> z?5>v3Lv~;D%GKR_Iy`Sn=vM*Hz7EfRh-dvqxx%HnojlZ)vfGZKN)C<wf{+m8qkd0q zw7o~>W;>|9E;T&ZH$n=-1yrwP<24(&J2k;5HGssyWiibM1>=`cG5bR=3BWuMW%jJN zP^aU2x**;bNuOt@?;uHY>IxEX;VnW-mxs<>Z_RGLNOLsn<~<7yegtfA=n#{jIt5Bl z3H)&cQ52g;)kk<_b0EwA0vd{<W<iGdKYkL@iD(Hd8oB5=+HprlxE|)Cg>2kzH*i!s zd^S(MPV&!!5w;>H*x-l#_T-mPWlQdJ2yl>7c-cmBym9^FOX;Jd>d(<*;&#%C9JuOf zsf(haEcx^LHXD~WrTGbIQjCnlR;&F(6zEo&5au*rTToe53tyA636Vm1p-7pUQ)OK| z3!Sg}<jbg5>;|GOv{-T!$C6RJUg#Tk;j4G#6>FNir~N3$DacVy7f=y7U2r3Y%VLQ9 zP8JKy)g(~YKP}u(tNlz?kAK=DGYygJB{GZ1NH^9I0vds;ep71yG5z253Hk_aeJ1^K z7P(EWz3G~H72dq6nyJ1@Z$))w>9qMbb5;Vij_y0rW1_k7EUoa$1SxtSt@F|I7Q4XO zZiNF2_p#LDMrv6>*w!m^?{NA}*!L^f{3~3(l%Qbo1C&7>oJfoN9w={=Ajdj+7$m3f zio%)1!A%bkr3&b|u<u~`<9y7r5D+CxY!xDk4b*RKYSuU&P~)I$Zs8J#BxexEIRy0x zO8+kRrnhZ~GkYPv;8h@201@=8cg_*4{jJOs>vPG#61y?HwvGy5!$I+w;n(wfm>C4W zo&?BI0rW4)ztMZ?gPRRMrQU#XG)Dr^!@Vv=dRWCUWc6w<Gw8XGtGm~9c-GPsYq+{Q zRT8|TjR@`wPJLj#M~(fdh_4SgQt4joA=LgqMF~JR>FV5PNj<MJLL(wjD<5s4@E_^w zUS~Se*TSN{#ZTVld_Ya<O|^?_(Cx_~0Xtme8uulZFQRz;UK=?(AY&L~nkBLg;J$q9 z#q%q?ZZw8Pg5wIeg|`pPn9EKGBY9hzp$IAIGD(l3cEUS^<^gE8*zLE7i9SBv-Xet3 zACTrchS@C5v;NbGh8l|MNshEJESre4mx!!K#Wboonj5SpT4--KeT@F|3E>9L-J#Mh zmrL0!-3!g5RnksX<+!dJ-HW%J+r%6l3-{XDXMCm9C;pev=rQuMj@Ms3+~hF^&de{Z zWQT^i_2K#lCL5z-eM7m5YCK6)C7gq~vQ53lu(jnZ*+0tn6yRCyM$c@|joDLkFCQzp zlD>JINC>;sXBwJ0l{t2-%(1)aNPCW*&QTS93DeC}BuexFFTvvE=2N|g-fJHY$E^R0 zHL1KsVeBSlLAA?5dSznoa<2RXAcV($o2=VHjen3<l{NnL+%L;rWFfieuPMA@aC1IY zR=Hw&`B$}&>dAP}hrZITnN>vCxnzl@JL}v_7&Q`0qH0N$M53}z7x%mAYr~|kv`(v{ zvhtdWlF}SbR8RDkm6g_9;hww*3BRJm&9|m2*{fpz>^L~h?IzypEuC5Aps>}Sw5Prc zUK?qwgD&;U+FwVkHGT*AXlo64U_*NWg|S2zy$TGhD<ME{?L0r8Rt_%Ll(}`K(~Qk~ zcvXXN?b=JzMu4F2V!7#`ApI!n#9Rp)Mo@Twn!5|lc23GQ+Rg`dKj0eWAxNZPRfq9J zph;Gt9eT}bm;(Y$vR>_ITFPIHZBhbFb@J`0H?UF(cp5uAD-CmCz_Yr;v&IOnleF6S zxw%^MEczU0G;~6_;pQNj{6W|oP#$L_WC_b#O2-wd8!+3!6abxe*mu6lrwkKB-H_CH zHOQLR3!bMad+16&WnkVOslH~aaph^unv#e1wT54BjkRaHV3niFvXiq-uq*_NAXped z(CJYkD+nG-U}F2Wiq_E6;M<bs2c+RJm&4JwJ|Z0bG2!SKzr(v9D-1Ttf?bV6gg33% zM<8BkPYRSseFb@wbYx*?(@Y)}gm*N}<_!jNAfOch9ZhrPJGf2&^r4n!))a<1?K8+j zCstPp)<>jERhGP}(bP~EG-VZ#Yo4H6a$GSTIq{%fizyNlQXnT;7K=G7hiPGx*+Q*< z4U9R-fhM7~j;2B@Tlrx67$ulGq6IiFZKZd$my!<u&yZ{H7E#xEp-&*?-rWc_11R;# z<NWF7Pegur5iC|4Skuf+3~VS)UCFa8^q?ShEO01@9*=s1HEMofcN*>{_kN1ZFj|kt zsI|DyTcLLy?AfFYwX}~7rLSkRl9$X^b|O0q*r9vLJiT-;UFxlwC-*K}bJF*Koik_j zoa&0|(m9jSt7|p+<zpvScrE73+GpI-et)cM8+Cb;NN>$ovUO2X2pSzOzK^VM*`2rY z8b%oCBY^qy7L|zCTJ#M%jjXxs0$)_(wq`r2&&lRQ*_*Zs>9nD{aB}Vy?u&fFqx|g$ z#iXqMb{FHW6VQ&l_!u)US=0fn+3^l-xdX-6hI>^H!gljG=Tq`G>El3NV%HhXb0ucQ z=W>fUHz*gXEU2?Qnbo}hx{fdF@ar2hbwD<jOQ<z6{NvLMUt;qbNu5n<9Fn@y`scb{ zVlN@ruEEVp-iHCH(R}cVRRXU14df+v<hd}V_YN-qiW;a5(4xOxjP|5mMiPYWLUr}Y zY05pqZV`c%G-*8THnUYZrM1;n`s_)j`xYhw!BydvX+guEpp8qBbw%9Q@fY{vv+3Av z#k-eOc+2&a0nxe_ARAv{cd1S{=49zcx##=5&Q2TKF*lWZHAam>uQB}Xj*Zvb;`YW` z4&QLMGl3w~hqJKxLXnnYUVk)@<K{h3m?nSoM~rC+&Q6TmD=Um6K}n(&62dOwYU=Kn zg~J}y7a9$2UJ6b%<Z;*t&}$;lxM_rU%I2-Q^8q-IC`h^qgmv~5-YhxCkIga+tOC(e zx3~*=aPwuMI#tt0Qq#SXaxA?(;lGh6y{ud$pGSXd<ugB$PyO-)!~0!Qm-&~TZFt?H zfSx!!JR>!-43Zg+WzcNcd%kyHgf&%w!a5NqrE;?WoVww>cry>~Klv5>=`G|7v0r;! z@?U{~9>MT4Fi@{TRm{SzE%cf|vy0AU!rTMB<P80WvL}5z$TQbuQCq69N6<9>8ZxHB z_0j~CICG+#sDvLARbfT>o5v9)b9jb?77^;?+m#=xepp)cXh&9j%%<7IV_Bu@e<Q4Q zk9tLRvc=}@ZB;BX2G93D6+xE-Y6waX^%VtGlOK&@)1?%Ov=)zUgR^t~OKKB+=d_Fq zS<71d$|D9nnnq>+eP+$PMYZtD2-6}=;AM?}T-+tB1g9bWR?e%gE-jf+TFa8rh8G>6 zHSVrpT_8gao$5l^{=Az?-R1LY-Ak}izsX(8HnYZmZWR1AR#fSae5F`Kxfl5s&My@s z0V#*bc@AE&%Ymi3ODanAz9&nU1wNa%ik%JyL#5ib$GxN+rp$<1xX`z#Vgbj@$Xbur zay=zoVfo6@Ygn<x(Yriofv^)hTEEn#&A@nxH@qoU<KN99R61cW^Q?9CM2Nn#<l>vT zcQ#@&KS8UeY&GAvLwEcV&%YUKAcNFToQ|Am<9hyo(V@!`PDE8Gjz%Sef3X@xc<!~C zk#@yq=_Z?FWV)>ya1VFs!dltREyt{g7P0jcT86h=OPCyDJ{D6K??2|g9paTjbp8s_ zblIptZHAb<=Zp>JjANT*lQ?lu(`1Htwe|hjU}7M6&p0>K?MYUFd%p^AT+M{535?~) zHd)B}$7kWSR{JktC7}CBe4knUGzp6GV)>-+T&`NwE0RNYHMi0!KFH6}dt3Sgw%Lwq z^JrRNAcH|9zB7L6G_Y;O{?g?#I?$*eRnzncSk)HD8x_pUh*V+q7s6t&`gxCAAU3+F zf>sm|aGGe$B<8Qgn0Lwm&G!z;_nw{a9h>jX>AK#$SE|%JicHlhkJ8D-=A9DK)RMGr z>)^k8^I#)c64^}?c8#;aXG_St67p>a+~>kiKq}BnC2p(44Q^g5?^8Gv?l6M#;e^0W ztznzUfNcv+fmV7?2MX<5`lo+yFD0<TuKyET8%f(c$Mv%Ts+m`F>lJPhV0^Wr{c%@V zt1I$q)~m}6h4y}}tbpjWQ|@s(tvN&VV*iCIlXbc*g4N~sVH_f<B8`v&H2!}cq}~x7 z8K_VAuMk+Fwf=S>tMB(1r_Ic+tu0+Rzw*|cc?-%*Cod|i63x_faj;^3;s0=jfBZ99 zdR;Y5=0Sa~YvVo;O7qu4)OSr0qc7jN!9)$W$+ed0!Ih>SnheRwd9HV{!igXm+?-0h zy6quIsnbl+Nz@kj`gIHmREI{<w7i+uWY6$K`2rh#wP$8t4HD#%s+wD*g0>;!jH)V& z7mFi70dhy6G>a=^v>?e^V@&ijmyW(vk2iV0Y;;ECeJt;qpJ^2(XUR~-$w3=!Jaz58 zPPb^w3Vd7airX1XdA)!}@sGcQU6wWIhb-emxicHhiR;*?*xDO)b2000EC++rTG!Gl zwAMs{KjQyrh3R@uT320gi40I&;F8>YE$+o&;@>2LpsQiy!z5RK)l(naS!=ekhxrN> z0B}@{*M;6=P9&!%qH_9YzRu~&{y9B6`lLDSmz;j+<n(QF>MA80?7m#1;(XUdvgwY> zW~G(Qg#OtSo;;foKO>ui56L7=g<il!A!);MhWDzrxR#*nuU5l08@^1`nQ`895oBnl z@r(%;xE-GEA=s|5cpEQh-v2<*98@D8)Xbt>!p`O0?4YBHS>vsGIntPB%1_jE7)4|Z z&7~f)EPI?$)D{}>bLtz>*8e*?oKsj;S+U^OIg5pO_$RzT);01ydQ8TcOIfUaV;n+^ z(Kz@X{k@FuU&dAL-x!Aww~b>E&&7O?9y{i;%j~cVdG;G4jw+75DzSvJhKtnW-;F0d zR<s{`87tcRY)|7(Zvq#!snzS~ki9Z`wC?7v`y!)fCx;vs-Gj7-f95zC$10|KR_hRs zx^R@HNtpV^^(0Vl(jlU3oFqiDUApK}9ddA!QO|U{`YOP?14~@k{$HfYL$;w*hvxvK zp&*TRLDI3$B8{QHz~t@#A!u;$I|I4N&J!YL0_;z9|6H8D2PY*IhTrh7ND$F;wuJ8? zJVGdUlbS6|Yg_Q=zYuEK^D~)ow8DLG$&XPK%BF6j+35%%4n5@g#O_SHRMIr^Z2)`i z$ttnvb@%HQ)TQokT~v$QV9A_)__M~5+Xsg%g63J~q;9mT{ji+?hr7(TXn~k<OQEHl zLL>i!Wc_q~EKFJ14$wyk^tv>`%%h>-d!CUdV#B>ZiD>`+K=<2cwV<Kta<*)%dX*X6 zUZ{=uxkD}XHcqUW!@*I`CJfhxn!nwqSJ8>sON|FqJrvzZmk@#&Sg5{t853*h`$%71 z{}ffKuA}H8?0Lg!P~rJ@8K(4>;ZIRzuuFj=&?-fuF2x1CrD&H@oE2S)XPi>}`BEvx zlMDyD6jobXcDogFf}yf9QWEJ2!$|#w$9jqSdl_M}F7H2g*FVA?Da0kVa`z9vp*jt7 zvLPq*M52+WjO0^h7PIl7^J8Z^ba*vGP}@%Ey+V;Z?gNh{kIM}}a-RO^`i<&ibf8hU z0R6a|<<rlpPGnR(L^6>mD-cfFLY-@E_G#It>9(C^?iHsg-I@+Ay9Io^HnuQZatbyh zJS$;>yn8vQF6a8LHJ{qTXTz~m`N#Hs+a~!`Yiq*dS|6Y(8mMhk;eC@0ec!NpnyQG8 zuY?Y~seX$TYa&ti_eRCYQTS6Nu@<^r#+ruq@l4b+g9T{`N)(X6#<W86T7^%*cAk+t zPxTqoZu`a(eTPK)gOQf9)*Kbzffd22_R<DsPgD5zn;8!IO)Yivv&5|OEtnlg;yTp( zSgOP9SoEsr@2Avq#5CK9Y_}rST99P+EWf}Bf5J{A2dCAr0&Q9?2@`U{QxEzci*ogL z8RZglnRg+2xTt!AXIp42!>x;(k8GY~otM{V1Nxku-9dqb4BqKqxwYRFwyakTXTk0e z&T#;)ms-D<Db|V!lhw_xF)xY+qD{^FvEIr%M^$6>gzBTia}e368=ia+?CQGrqqypR zU1(d5&($Tq<ENC^x!*yLThR;l`agGcKO-(G8ENZ#9GQ*#RJ8j>sma|BIo+fW!9Kp4 z()Redpt<o<`uA|BYzA45#<?ttA~J1A5uYHLdUjtpe7F-Z!#nwKr`S*XPSIEvql`cl z`mXsJ4#jmykFKmYvH2BASo1C-$eGOt<-JVa2RElZEOq8xgHH$CIop4ve)$nZ$KQ~R z@?d&J@#JXvm4W3^P1Y#Mze9O2W*510)lUm#VK7K{@&Qf&-@+RnKV<QH6s=zuE{IVJ zjUzWtf?~<1%j>vOx}Xp47Qy}Udv?)20Jdv*AAm#{jQTwQVwfLw#q&DqC&u-)jQ6(C zjx{psBc4RH3jy74q8rry?PdMVCChA!SIL6tBKypP=rH6?GEs)Ov8pb)xN1@5t?qdo zai~DaSBeTz;}PE1J73mHij#qB_?f_8jWnYnwes@>$Rmbp-f~(0+lA{j3Ktd4yc*FE z%rAA9F0A(6D#g+GWv=Wk568Ul;2(uT6DB*Gm6eoImh6=%uxm&Sn+fN9<FqzjHce6L zd*{`7-6JZ>tdc<Yg3J94Z~<ccj$e#7z9TlaE3P9p<|2~T2V&$5x+Agu-GqoxhHEDM zw*Vg<s)LC{G|N$vjU2IN-mv!f0C^M;on!+^fR(e@FAFN`EH?a~Wu!h1etkmITXhMX zAux=D+r{(NnW7^+Ev`)sVJ0mLR3`_PCIn_D!lo>rj+pNvhnX)0@?C-a1nkN469Us+ zfx&^ogm6}(wsB@HV*f`jWr1RBkF@2J@6pJ}U!I67gVi#^CgBh=PF*g-M|Z=qe-W}A z>lYb7&%<xD%bbJid|{S1$#qJGvEtH*w3nd=TesQ<xpx@<5+?f`uUTb*3?xsnEBjD* z)@Vr}QlJVmMGDl<bb@2@x>^!M;5Ps-Nl#Z#@aAuGO-pLJo^By*(;AAe)=8m|d7F4@ z4J}ufB$S!OU#Z_xI=%DDR=z-vS;O~LiNT`N1pcf>(&_Wpn*~nHpxqhE2lLXI<(35o zZ)TQzf@1w!cj|;xSep|o?~!@E4%9S{CG9@J0LT7?>D1xNY<crfXi%6Wt)<_EPv_3_ z&MT6$Fle#RT$Z9zEG=O($)*Knj%0IBYgcN+k$Rwg!vh`lp;+I5hFAGQPn*Ee@~Mc> zYB<H$#E@t}r{-Yuv!)ll1I+7Ofoomn6pVAdF7xcbS($|{-vGWLlgz>dU%WXOY6<5j zB2!*|2TdV_DE<pLJTC4N{z8cn<XC;nG3=bgU`~qq(~s$koK*E2o)4Ei<}p_0oU7Fk z5SKYf{Q|2bZ0;g=*agPw142X0-OLud0at;)gH#+XR5m)y-Q2@Od5)@jnhDTl9VpW9 z-2#8Dz_;0#%SjuGJQ(4VWoTY47OC4*7Ieq)8ev%im&r~Hr&n$j7FDsxEoQjZtO#HA zx9>OK?n*3DJFzY<Qb(IbQECmCB2~uBOe1{YZy)aX&=KDvwwS|J!iVZk%`-WCf<G^G zw-D&nzAwfc8Y2`HoPAoRFJZ;3RdMF_`j7urljuF;*h}8C`Q>z-ZT2*LB;=6Om6Vh8 zY^J|0wrfC+$<x&oUY^+8{cGyq5M)A0LShQK*5eRnmrA7N<KD{y>+QccJLq-G(}%AA z<skD|Taq(M7YKD>6N^q-v}q-LxqXXjebv=fHEcP#=ih1>n9TQ8RF-HRDePx?qFGIa zylG{bvyy$OnO7(HxX2=523fyhGFBlpTtz3Cm$M*zdrZrXH;6%p$VrwRotF7Jf8(*G zV_a3-o`A=dQDqG)l2;qP^H?|{bi8Q}P|sK+PMyL2x#&xf(gv7Ua;kE7WLUil9ub$X z2+D}M53Xr@)I?ym{V+JP4Ax)=<eCQI%7`;-f9I6IKEea5?Y=+@o}1Par~ZJ7jV_(S z0MkYw;#Z-C2;kb!)o{pXyVQNq+qKa!+bx)fqhP!O(}mVZ-1nGvCi^6lJS!9S%6c>D zwh-JHg<y;zu#y+p$&KHWe4v$Fris~{3)O?>wI*q;q{au~Bz+{YWJz%`SN!UIt}G4w z!5yR$DbAZ=%V#5cMX`l<irk4PHcC={v>PfL+&oj>-{M`Tf2m$TlA44>)sFQrh#t#f z!A=6GRQ=L0Lg8Qe@Q35QgZyE4Qq!{%CBwUv%pZ@j1hzh6QlsSI$JMQL)Mt-79YuRf zvfI~^Ib1KRrz2}Php*(Oz5hC2dISe*J!+S{7NaOx)n-mjHgg-g)!0qF5^|`C>_fLT zVb{KmY(%jC2{WunU++wil-vo}qsrjTvIO~jml&!X!yo2KNNZ}JQYtCsJFi;+U6*RL zMLI05L+yte#VNf@m0gIDxbF7xR<U%!52#;l>@89GFX(W|-?vK2(W4gfYzw`7Cpku) zrecPG3M~H{<(1XcqWAlz3PxwtcbPVq?2TVgzOYaHg7PJOzAG1L9kAg4I^OwzO1{jb zFf(ly?6%}Yy_M9D3tJ-Kablb$yUFUjcfZZv=(G3Lq+b6i--mB;j<aZ%b`qug*!5Iw zSL{=qsui`etEn)eLuI%f?C|u6D%CQ-S^WnnWHThB>2|QJ@0iEfp4}o5_wL}kEqZTF z^jNv23u;QmdzQ%fwfbrfYl})|BC%i`*(>jB`^IPx#PS8@@a@}5YpRfsb=jS@=|L{W zbX-%0o^ZyLr7%Z5k=wi<+3okwhQnD&O^;F#3Yr@5^>lcSQlTE^X5)_(`jee-fiwGr zkCO1$3765@7{Sag;;Y<z9HX9RAd3RT%3<aP46<fRl6$xJj)ATzp^q9El66ENv#Dcu z$x!H4Q?8I9$!7mSwTlrb64{L;Q*R)a^()51g7a!!4Eyj`H)RnKQWQ9992l{G_LHv9 zTG&lw@gm2(QX1X1<UwV4$+Vo=w&<Y8(($miQRxX_rEeU(mS0hKt#5(Y9hLbi?X`<& zlKR1v>0_}`bSpY$S$p~Vl+n)6J@2M@73^rT06b}5|ME{xUmw?_PZOoifeiaK<$ei| zBV2lPdUX0B<{R|rTzV8g#U1J&&(oPHe+K%+SED-fve4P}bmllBq~|V$lSyYT9~bG& z0rZA+=1)nc2GJ>z8U5E}7wI%VY?}LDp^QkU$ymN9s@+QE3T~&*yf|`jS60lo_6cQK zto!YFc)Q<D0{{O;-#L84@);3v8*ur0r#H~@Tg>7hW2=B*^^@1E77x*Gmg;cKi)>cP zPNRC~BRR37mt%V((bmFb)yKU}U;ZAE$dsyKnY7$pbVC>7j=leXS?G@2>6dCUlm57$ zK_v6ef9s8G=DlvUhz3WcroMWGe)$pY?xZcBpcC15k9E;wZK08Z-5E^MFJiwR(ThsA zlyT7BJt;dUO8&NJ-qxLJf4jE+sn-S~qC-u7(rF0cA6fg5JH@}*6dXm{N>#$%RC`&4 zQ0Mw_m*NW*X;3p?Z2_VF4(Vx00Qb1LcXSszDz!7Qe!y4s#z^&sk(CINpRvek3r$-g z?Iwb=b526+7;YYfm>ZnZtbOhFn5X?zoqo{j6|Or;2rg}wzq8k5`i?Fi!a@6YY0E%d z7mM>iT%Nzp<?nR)j}7*Tks@fJkB0VK8V$s9=ippk0}o0-;6bnaow}MS2RrhOvI8cU zK#A^I?O@=@sC@Hzr)iqIc~z5fEfmxSpz8B)Gt8{lms?n1dra1WA}euNeHANGEN<n` ze)+=@FcgaNhiy`h8bNMy@x40xR?#$SH_&(JoWyF&iTu}6iEMN}Kh>Z6ozM65r*b~G z>rc5oR3mQHpBQ|tHoQqr;1fD<AEm@@E8wX&x0%KD@+F?8WzJ1%^s~O!@d=jou>U!+ zAtvHxiO>ecWerP{>y4zQ3519NS<5rhL{ji#3qXx!L2<2rdAos+x#D)y)2KGB*YjN+ zQv~-gYcw3veVjdDoGlJ`Jk}fgRP6JzB!4`?JMj5|ymX!Vcrvf#VE~Zj<&x;fT}e%D zfHt{bfQYP?pTO9$Ud`fWHB6SyR>Z?EikGo1hIizqtX}Y;QQ%vY;>!mA5#V;YmL?qT zbd#<3EL5muhleo1{obvXy#HgOxTdPGXjXX|tHPjlV%SQ1C~HuRfKS~bDb9UBQusz& zhl&H*jJQLa5Mw+%n`VU}l~6WiKva;A5t>YPTsV@{l*P-}C0i-UUVI5l>ob9Deq28P zgg>9qKt4BZ@2&8;@Q&X0In0+`;d-F$_UY*b|C9mgfNxRTdcmgy?$j~CjYCCGvkIh& zRzImRAT6T%^iWnpy^m{LPS8HONlec+br<3pt&;wA)pNH{pO5JhX_c<a<qnohzYbnE z$0p!eIOR&(U$IKl1US(qKo4u%uJ4(i_CQlUE#IL{syX@D9MERf9opJ^NN}A*T0*5) z@RWhm;ay!LLVsWYNs-hQyW#JJB`}I@J~W6ezJW4mlEbH|$CwbzbuwrOQD4FTtbru) zsCRnDTh~yV-i*E@t?6F9x6BajKLq0$JsnNUKpiy_#fak(I^BwhkpcPov;7C;qhB!~ zWq|vVBOL{mWspvX4iHMvw-dy!k6GDto0L8>NE56((9b;7?!qQYI=&Egyt0Y$fOOKK zpCZLxUH_Z}!7JW_AnKnJEQW8Kli?un=z(<aVj%$U`H_fN(QClet@|T{qJ9YiyQcl{ z2-isVCKn%SchIe%FxU2$Hp@G-H*VS?ry@|M%X_h0FBdfo>2G@&J|>-gt1Rt>U$v-D z*)NHdFB#W@5bjSox*_$|9S}tn_b#@HLi|};MDbK@U!wRiY`*?EozVN8Ug~(e>wiui z;$}md>Nx6{9FI_7m03O2Lz@UG6h7yWf)!I{&Q4Bxwrzqe&R1N6vs_4OLW6vaN^0E7 zGv8a|Z}|)_7D;!kMX%~tL-BU5U*;w?-oZ=gyZpKM4nUI{$3Q>%NsYG<!eb=3LW#V` zOV9gz1|;2e4E7yPYdYHOF{W<z80+{A-r_N?=l2G`Px$3g!cFZof3Qg=WmU=ev0jCR z=GDn)l89hXX72S{RniY>0R6$VX2=kHl6F^HmS9`-KKUI_<}VX!6Ugj@Lv2uTOW~n5 zp&vQ<QI2Y}+{+)aDL&K|o3yU=P@CJP)hTybOn+rB3J8#!5SI|}cydx>6;Ih|Un6>m zWcBW8=pigO6pWMgLy-{duLJ7L-^sxk;Dh>{j#<1#t+>rP_vjnse@=uE!#C84Y*zD~ z$V7({6JmVV^s8QMQquw2-R^i(>Q}Gp*C`Vb^`R!MhdQb3R#RuIrX7Gb7-UUPlTOb% zf8fP#A1aq11IQWaW!*9kq-fF`E%Z%NqfFxegZ$ou$aQ|XPJWq^-&DlA7Or<xH=X&f zaA-uN2n^I1uf-3xs4r5i8D@|~3yavI8U_4I2rn2c7qVDaC53aCm3r~N`I@@M^31WS zNg|a8<q*oV#x_z3WjBh<s%!q_N%1s*2c>gt&^is&ALZ5G(kPp%L2z?S`D}C(qNL_9 zPoZ@Ls8DtNLfd<=0cp~@B@~2v#R&_IKWV0kCn)^ecHsw*N*7+XfG!pxgp05FtLqWs z<;3l=alfud+)3(jCt6O?D?Sbavv{q2e5u*3x9d}*t8?Jz$5*F?u&(M}>a?eaOR-(= zx)vcgrmM&r%AC<}i)OsN^3U7Cc=v2RZj_I_hJNfb%3tP`fqDbR8pV3g`H{_ffB%ZZ zddDs5%X(A1(ev@mAD)!sI+AV^rmLuKR~feBetkA9LAjC`%buP?S?4C>ui*yld$nvm zI9$BCSpE5P;kS-6oYhG3xRFw&3(1<r_x1YOt%~*YfW5jZ!h5vE)MR;iKrPc#jxaej zoV=JJFGfYLo4^9Nt{0#SIi#>W22+4?Zih0|O)wg~3al4j1^=v+T=%Pw^s`aDr=JJZ zn>^b>@6ckQ8_9&xOv~SfVj)uQcPY2cg=Zku*b??6{VFU#jh9zXvtB7#%cS{mgtpL1 zkaqobmB(bsB^K<!>hm}l5Z7q^n(X^vkZ&3CSc}of;V>vq;AIbPhV6aDgMGi=Ct8Hz zEQgFGUe>&Q;;ZM0SuGpXwLn-nM4w>UjM-<5`<h&6JZAvo#L9sllzwu8M~+tMc+tJe z$u7O2E-qmJs`ZX`7u~{kKWlANN*Ydl=sD#n!ZyFMf1z!-^G*oYxA0QGbAXHB!G^%I zv~S@BM$QCC*)Hk3?SH~j3VfR2w9D<Lu+unYF}Xw==tVWJR^RA4iQR*vC$scDW!$G> zDHR0YP~v@FaT1$bT2_I}mn*EcU`{jAIKnM37ib(O>S{|bC!4C$hU?kKkN5zQJv_Mw z1E+CfbG1AHomY+w+&%1Aooc=|8AT|24We*a`IoQ4IgUGeOg603;uvM^QkTLU*fzEI zqYiRRDZ$@-^q)+t-djYmQ7`YTzz=U{xi0~0B!HKAgK18ESRk=S#TZzCdx+a8mgo8o zG6`B~g9q0Ld<4je$7!WTsE2^;!%-;|!98r@%{Si#JiJ~IG|Py+E`4j}p4;O^!?8yr z(x}mTtc}&UJI$BXfKnOA2{HHC*)~{pAvN{|a#hzEH21YJ@1=ji2H-CldX5gozKg4& zJ&koZg;*IpEcN6#HoAu<!M5r_390`g2C;p(Omj?KuOUw9tEuil+zK>F^}Eg{rcYd1 zBu=EuzqLEk<*Ft@I9Bj|H`p|a34pUPVj-u-m%%gENr+`VrxEKW>$>c?aP_Mk3cAh< zE>i=ljS^tJe(d4(1{a>ROUgJETNY?KAaFS>lRniiiGilic_|L+h)tr;Q9e;c6bExo zGm8>cxqPsW1PCj)ffH!I6?Gg_q#Ek6D!z1-`9t#XJy5KkLDarBxGs&dTSef0yHowo zjo@33g(duzWD7~wAH-~uB%H=3AFNEQ(sxf3PP-~ExpiOMtl-$ciX~w1Io&SwsPV<G zZz!+l$+2w7?&=iwW#4BZ=rrtLPlERh8{&Y5NCn~rSt{naGn*>O>UIu*%QM)tl)tNt z!FlHf*U9Tjq!`J_GD-|jma-|r?Mh`~@cJ$WB**oJ?xo1=u$xx0>#~|YZ43SM7P$T= z7R&EzJ9V{hA$#7n{Y@z}e-OQ-XHm(tva(uifBP9*5XZQQ=q0_h@bR{tL#I*nsdDX; zmj0jWKrVQmvP4R{jAWu?3?d3}|JBX?b&US@{YA5azWsXOHPR5;iv&ZT01oldQmm=Z z7AXx^!omv1N`uq)qAwSYpuX_v?MBh$KFw=W%k9>Pyi!Ian@~=o2>(d%_at%;ri|Ki z1m*;o%`?>l;4<@Ehqs&OWw!Z-VRZy)EJ<QpNOGDIozv@@l+lAaJj^cTQ0cUU%mH?0 zf3m^M`V8uT@Dl4gk5a^ImU5>0ViE?bc?mYK*blMAF88yn5qgnooEcan4Z^F_GL0Vs zX3g{ccw7X==1)J-_=NLi-X};F%MF93ewCMcod-OxF;*AnO?cjEb8Vhy=RZ<Ie;toY zAro7*n@S#m2UFzl)T4oQ(rbYxsdw-hxBPuh-bJZ<>5C3s2}6{u<f-d9kfWf5!Qgnp z#3-~$kf;M}Eg~L5DH*qaCm57`h+N;M{7f09{&uMGqIRe;qe7%7DM)Z#9e+303(;IB z;@>(QYM~g2B5A^xU|6Ryl68t2iInCfJsL@R{)v*t_DPzmK4lC9n^scFRfaii<-~K% z2kZIZii5lF)dQ=;Vu^Bx(Y0nCM(-5BygIfF${V~_+G;o%`k#}(h7Y^rAHiLaYVrNJ z&1o;zeHy6cG;^K2m@^X9Az_ow;Oja&bf?T)8cf}CJ+1Ly<@^cq$4)X(?b#C!UzOB! zGb6!CS3ZtDu_|uuBX%=v@qc_1gV*+^uWjcV+DG+vcm}V52PHu4XZ4AvXI^rOis2_p z_~P<lB*eZk?j=3V{Ut`-&jg?q^2OzK5uo5Y(Oz3~6^3rTrrxKiFDZ;u-cTn^YWgtA z(<a|3!6r#&aah@1;L4}#tT2pUi;`PEh~wB*ul4ta8?dAP0c@E>xS5n3HH}<OADZiQ zXi#d0>EAi1oy;cvQIw)4Kp);DwJ5467`%Au>GI;ED`Tm2uN!JVm6G+xI}EC}&_C#w zs6DE|p?4S1FaHZx?$oJ#3kj?;S$$9m9k+#kF9|V_IAXDSOTLnQ8nXv`w+HAaeI`XT z`J=^7YZjqXD5mAoWezq{V)l1CMwImTmCUzmUS{GP%j!Lt6BE~>M*mQ@IrNs>O~hCX zpIQDQ1UR{|rBfZHRV-{n!Irs)$yej(zKN#c7<s2_cCQIw*RYU_nu)A<;5usf0>xKD zsU{)RfGr_C4~?S#vMVdA7C2sDFzCI){dL}9^xWic7azyin`wu+j(KvD`fCtt(2K&{ zbKVnQo7m|&$n;@^MCDPQ|0>n>5N~#u&*ps=cdPNyQ(mn<a`<3xsC=dV`kwwefY_U; zU3H+D<;Dv^xIz$q0a{FRmO&b}_rc3ZX6?Sn#?l_Sy^Uofsw{0X=aMF5Rah8)6H3>< z#|NuRX_3(Hz$7x<8Ikl{2iv+YUX9_j5{OJB?&XQonlMBC897g4vFh1vA*GMyKXEG| zjvZFPN@gi9#x$65rKvHiCB5ZpU?AnbhSci$5;|cce?nr!Znkk(69?YStCItXTY2fs z-KuZEm9VJ^fr72v-LVI6yaiiRoR?G`x0|5h{*II!>`p5oC%K=5r8d7k{1OYp#kc~r z>Y1b_OQyM!=@!Z$ykN`U9Qva8B<<Hma!W1ybGBJS8^8jjengG9|8PFTpx5L6aN5nk zd=J+*o7X2^<v(K7rA4ZhyLEWLv)jLXw?0t5yHMSP!5lDQ-`jGrN%3qU#{Hb<(uk)B z;-@3o{s6?Xj=uz`w$Q~A+07`n<t%N#I<I8$yy^;kc$HLEQZs|o`T7`t5y#?dD!g0= zQdT9+?)W4*LAZxA*%hU=lNV(#s1#63?vnP91p@{*Owbr0`jW@IRa`#vHEFgnC4md^ zcB$XRyNXc~kPUyWaP=l#Q)qVl<fkh53`25H*D3brOCq4cnC*@6?}sXGl#Ow41lb*_ zhY-bZ;gw;?J;nOkykb32d(`{v*K9r??5c<sa1fOLP^YxrzW$A_Z3_*VM+-&nwB9Q6 z8H5oQ8=qb~CCe`W5~o&2;GD)jq+Y9c!;xdO-?8X5D9f^=s#dev;_`9Z9l8-CGa@eU z(SE)~%G^vTtn(xPx=z&IoR5JMUMjnn&9X4&V!D=DVz*f+=hcNRFo5qC-oB?u{YFO3 zTS;qMdK;<yN;0E$EEXJsm9>Sw0|)QDgbiU^uW>Cq&(ExhFLj4gL|j4BDc&Jdyu+q= zFP!4Nq-#9o+%y&dHI%}3jg!v;`3!@-YovUZ$Y-~Fo-LnV`FvkKhunOPGAJc=ni%#S zEpH@dmVijz)D85Yj62As@aEY1Be7Bys>v>Zp?-&8AeC%|`ukV%e9(YJh3MV3&?KlL zVo=&^qb+@zQ;=O$<SDvw#<Xd2JVN)a4lkZD!*lh_8;grPGn{bQH=dfElRx=tyixOy z9T7v~i|lmL_;dJSS6y!G^cY2|<1Wso*Kt_6JVk$Rknei=cI)ro$af>({s{tQc+c}s zkZ8ku2A-t#OJev8iOQ$uKWrP*g7B=r<tdQz6hN`eo?Mhub8EGi;X2E5=}%d*YZl~H z`D)}c2IpM^5oJv0&Jc~nnsbZrrC+4OG(zjV!3-I*fJu<(Q%?5pG3rymc6P=o9%Iy~ zEMwnyvy6oFETen3$MEuVzwR*--ry|W%<C|Xt6Esi;f>m=8nHny&)+3&_47Mvi<M+k zK3jjUlJC{>Jy(C<Cf{r1yHbDOEZ=MS_D_&h+%4drAmCU9_$LS)+|fTl03utDY^1uS z!318O0xnO1mZt#IkQIx{Dmj`WZFZy7*Zy{%EH5KrxFpf8oQ1#1GJ#3px0KEjGN9bU z3zO9!XF$ZgOe!(dj@&TjEwvZvRco5AhpUhtaCJYh+Rhqe;)qG#xamJ~l$%G+Yi8mb zo@Tz;w6pG%iDpM;s&|yX#WlruD01}#9td1aIvX=+a8?Za6B%XSA(=Whhpb#_oWh0A zYyGL{A#cOPO5A9m<Xkkb(p_3pQ<CtsOF4L=}aO%{CM*<9JuQX5#KF$6ZJ5I&;#t z@X%*oC^xd2b6)26Oe$iT9rh)1`cNN%dEpAC(Y$2!X9i3#Z!)f#5G3+aZXQ>zC?zov zm)#%SB92e|7nKaIj=V(C_VhbtbFH)uz6vhW2fD5EHubl2UD{v^k=2oC_a@AW9K4w! zWwOpYa0uJn6DS%UxXK;6pGws)%Qw7dZrl%T(p(QnbG2`vxn4tL^e;;>e8Yk{lX09D zESkKLV;FMQHC*JvWga3>juhM`pp-N&{m>Ey&ji>~SS|q(dDPs!Q8TiOVaR@U#G5P* z{D=6J%Qw6uCqJgEZ|0LE^BFpGw~_SY>p|dePu7Pnc-8*NtUkkIjUGUyC6=*2&LbC8 z)ztW^wSTgr>A3yY1*fTVQmmp1ZA0T+WWoUr^&o|$00x(~m@Tx#3I8o+yq;)GuioP^ z_Pyybs`v8yyT?eHIkC^6mN9*lwD7+>7^C-*b9oBzMQVe5KOo;D^!IP%`(eKQ69h^R zU5VC1SHh!*ZmJAX0h6ad$y0!&fhJye*^TpW>t!vP;Zdvp;Zo85VKSimj<<g?-v0FT zHy&>fQyFKxJxelm_qF}Uo9OB1|C<3PJfJu+>CeT<%y%l5=|nh#o{OEc7qTvL2HS*U zJ=l;4?7`NlW_(|quGuaYjk&OH^%hNxLx5*<p<fia@#>AI2)Ii=19#=i-xcFKCyi~P z3Z0Y2?couelpUBPqjVB<4y8{LO1InH8KQrKo;xNTH$>%#zaFD<HVHluJvODM%sX{4 zTD+%}8}+iYU8r&>pJo)RV10~uu}6IfUSpq?1JCEMp$`APIL<H((ldYh_PEbYzmz@Q zFZkj*CKyz9@tGS7ph%}9zCx3);u-umyYw#BEGtQ&dJ(fMmJ;z}T11<#@x(kO*!a}* zy1TcpW>!_X7y7sbXJP3=&S-Mv5NA@gdX&K*@s+0;iaT&sTIfkq)i28uhEl+wa2QIh z6yx@5Y=$x>n3Js;N_G@Op?hjm=$pO?uaJZu5?bTeCU}e0i2Nh02J!beR>KMZu)if9 zMpFZ$87Pb<OBhXbq27HG+#z_Re_0xg2F<rH8mImj_SXMv8I8qfq&`u6Mt8IBmVj<r zO+uPk+9YIiAd|9FGT}gEcfx<Jw>+HEKVGId@V3X8o#Zi6-tic7-}M;7flK2zir=uA z1=k^?`D(pY3wyaiRZZxeskCI45jx#|4zZpm%$UG>aIGZo19WAyJkvk#1LR-Hua4ho zI`2!Pvt4sC{QJQF*f+rc_<Q&;;FrPA!hcyG{BmCxbDDKK*N~Y^{v&7|XAFFoqdY1G zKA~^tk~u{7*eY*ZIIlztVb<PT9~}CIuSyGto)JI%GdP}OL`HCkU#DmsUq>YR;2rQy zJH4q5U-6Q>B-tL2h?Z&shRjH{ZEJ{kc)|>IiG*stCo-vQPbYE)NX?uATWGWPp)CHw zzFcy6MzZD~Q?8Eij~fdk`~#lq7k#{5dmXUkDUs4HqrWUEt$x`l+}FZMM~9BNR{*3b z9XY4O1bj!$!%c^h?tYGvYl+}H^~(|s-vt(UuqZWZ7&Fys5LZV|A}M>sMJ_5nXrDzW zzwScLp6R8WIWBxnqNun0DyHT#u7yg}OF2~wSMB0@)&qrs<@-B4iXDRe7;)xPR(1L> zs1y76Lqw9`N>N|3e|e9%WD#DVen4nCS$cY6WS`;S$Q=AB9*oIJrtm*zkE?fy`vZ`P zwfJjL1?zv9Zp5*V(8n;a34xX1z!+c0(VN6ZN7gC)67@P@(;RG4;$?KI5VB;OMMH=? zvM93TBve&s(qvJjxN|1lP?sj}$%_X!3yivxu$$w{1&?@}2>J!trfP{wcZ)GfOwE~c zW!6BI_D2dixEW=ap>PbQ36Xw<Hj?=z7NKlm<zf}4kd1SWN+%kO^{6t&v$x%5Zrc&^ zw+`{|i}7!Z-L<bx_!lLXQduR=cgp)Q%&C5S+KAdy*;B(|*H&7FIi|PpF9Ki{T^D;* zL7HpRYAN4b6a!N9VN&!2Rq+JwyMEYam3=LV_|SW|Cn|emT5s8**y4tE(Ln`h9PUeT z$-ON6Uzp5CqFk|(JvPAADkl7N$~b^hbnJM!T1CfZ5j$MR=4!P7AZ`K4PuTUr6rj>9 zWr2jatPt_HY6|*M8bJyOGBkn_q#Y}fg=xf&)3Kw79Y3Z;$7c{P+2!i5RKD^Bx_Y?$ z&2pPF)5c#&hNLYt3n((r*7sd;JL6uAD@aR>d#T|VO&3G50-_6&o;|hpbYAjX_a!84 z7}WY<!jRT*E+}7Z4Gl^9^GliAlI}cDEVe$|D3?;DztkFvFN=E#tOaF(!8{ThwpPOD z$gY6<YqHpE;4$9tW`lH;U6>KOKG-PAu5^Nk9cOS{dQRHdE*F2tnRRIyNgL*zAKrB& zZddCE3Bi;ZaXVuybjbsg{HsVvqGVU?08l1(#cLsdB(K&j9zZ5Nn{t~~t$$OO#pi66 zT9}`u{~cTftzFdR?`47Ex5kCLQqw<6Z#8xO(sxK~Ss>-sVBM854PnNLQFCwTFeRZz z<A@xWJ~J&P6FSg^8jD`&#kd_NbTT<5X+z4Xw8l(ChS`!(%09Supw_W;#cvt_l94m* z!tW?an+e95bl7at%mMRkzUR<aJL#<g8v0G%di!iH5Oe>1pDj*1zQ5+uUvXi<et72v z<kxk6zX}6zs?=9N1i-3y(j8cDg~>L9@NwpQD~F#7eT?HbK9q{`CUiP~`eCB!P6axd zqH6-Frx}Dm2&1n~`(|A=`uHjc$@v+Ei6DaRN@z<#8+rr+JwXv@dFb&}9^-{~3+oBR zP}=CC-S;09E$PmG2qm0sL?qK#g{>dBbSF~KxE&2!_mPb~@Os<f-w|v1NwYXP3DQri zQcl&~#n@Vza+cFsLWTn&!$A}sG8DIzv|Vy&CZ-i9XuHq|N_>Lw=(bz`AGF=#3r||9 zRLWBldYFR!n|!zZC;7Thn(uJQx9h?aXX=(nDlI^6npODiaK2OcPUX9V?-ZwPg~vs; zEzyY$t>rW@Kn3tRi2w9&M*QFFSK6|`5YiX6{v$5#tvC?*+gvQjXQoxcWy&Sn<Jzq( zaJuA(^Mh}k>G%IlrsP#Ac{zDDw22y~Yh-lG+1U!Hn8FCCFhM{WqkQG^Ap<ZMo?Z0K z+Twy2Y@YoU4Vv5fPk8oMWr6Wm2^Qvw+^!3v3m`CXZXFBv$(=|m<qBx#%(U{FCZfwn z0zycoB$lpAOuEAlE8#WQnq+eANv8Gv0oJV9&^kBH>c#&{a}LG(KRm1b|2ce<x&Qxs zEBXJK<qx}(?syCWGv5r<rB(0v*#A+?6#r|nP_7rEtR9-=*A@x|Y2IBQ;pL+sty+t7 zdJ>$Ae4oC<zx5c<1q`sIGQfD&*#k|aygCNkly5fJE_%)$Y#)=Zp!Jh@m`Gh&+{a~s zQP<KKb&Q!hXT(dCh=UPvNkcH`>SWN>4XI08ih#2;Ou3VqeuNYedI2WjuT1m0?82mw zN&c9f$eswEt4<xVRYcDnpQht9)!Y^rZVjEEz9X<Ut)42yZP5>NwSHXq>ZG_<LF{{m zQXvcEGJsn@a_L5BOlu^8uD|fzwfd7LnEuV0VDxcK@PNkPw1R~%#(H#(wV01-!Srhm z3ntEbO!U7NLuI6F(zgF!Dp&0PN6Y2<-zk^->-(|myp!~t|Fr}rkZb*1S$0|jGuCNP z5=5Jv7|P-ea_b`t1gD9>ti=Ia6hP)o&P3*{IolFB?<N)BSv9r@db{9b+BqF*Om;bu z7!VP(G=^}S8w+u`SXzv8MAoaVTwUqN-?Ya{p`X?I0aR}7AP7mqSWU@HM?%KsxOBvl z%sF~}A}cM<amKyO*d0F-nBefiM2%f?g)F_|SdRfbF0eXnwP1cJ?loRTl?M1Ya7*Z_ zlwm7}P0HM&!+js)<8lt`0aBZlY2#K6ACkRt_$4A}QlPP%8GUhz?_CNrjw#nwJCwJ4 z-V&1TnEM%;3BCNRJ>keVSwI0Cm@bRzz>j1>9hj)s(Nr{$uh+TK2;7qaBrA|W_9$Se zb4p;!I9dN9lm!aMTd~6f*;!VsJ1`~JicJm_jvdp|(7u*R>1(LaonKQdYQ5R{m?_mZ z9Fg9xy~WH=36MoT>*^5!FW0bsVJ;nK{ylwf<`;`&aYw#1Lylh-CZ-pT%KW@$0B?c9 zjF{?CBdhbtGHyrLx#r&V_cFg+Jb)H*(fpspy<?6_%U(6-Tw~?g6U}%19c-if{vOCr zyY@O=5GjYf1Gy{%hd917uyQs(O)nZ{UX_*}%6z@nWwyp`#bK2A5St>#fGxfsm^q1= zIir@u1#&X9zm(B%+05Fs#X~cfr7j-Suq<DyQ}ajrW%0ny933*I#mUp({z{-%-@zNp z*x9x!frtcY%IOg;$n>#<B@<?;GbW?m;A6^#(?=1WO6$woC$;a|=ZKI}(zAnWrFUFH z2sH!8w1ggoVM~D4JDk?~j|9#9UFNRVkI_5qFtz4kgOL7Sz-%o8nfY&}=?CeTQHJ+A zUc#4Z<-!f=ubN}i{I_$jO#(0G;t_bhl4qJZKFwUgy4?Hy@UCMdFekgT7`N-AX?$IH ztJc5_+VxS~VYxdYA(%KBsc(l2(Sfx$=#%V8&nDJrzkxB-qK;bB*|m6w*;fK|Ev}SW zbTSTH=8@KaQj0Im*D|+30(;{QbtR<lO>Yf)FOOjWNS{2Rou^A_DBWb%>*-6z@tQep zT&-^O$s@E<;WJ%c3ZHmsfR%?X4YRvja4@+Jr@e<?h_Z=D83%3(lSb*oag1a07|++N zawk1Is9({)^$m)iEJX)x+Tk4+fV?Z&sf2_{h*g=SJ7jjJSSggs2>l5ysnA0D-ngCV zt-UG$rzHJJ;XVug>queo`A7tNHSs|Vk`t1IVW|K@KO<KOLV_|(ug>=n`FhdZz0t5$ zR`@5&`MiIhbJCrf;R<Q*g|Ml3sv~?w7WOA0@fH#3zMjMvUu5pJ2}?94y~CrCv|3Lc zx{Wt!_Rue-dT*rfZP+Rc@ATG_Rci7#$kt`<?V4^OlhyReksYO-|6LsfnM;aDCnP6I zDfNJrg|GQ}(z8SD3Z~IFu1v2p{sl1sdgNR#Bd0@;oG)5GW#oKjzRJkCkg@NDpL`e> zcPQ?2e}}c^9Yr=HWE~pv^CwsnD_J{@F%&9~&Sv~K$mSx+gx>uy4$Pwjvt;Mw($Jw- zxo1n9ENShEj*t-;{EIAWH8X@o%!*Vrnng(LH(?PwZ5A=}v>2G=h?+m8^OwOR8q;J~ zl7BXM{9n0h;<YBR^@9PL7dR?5S)ZPiOMU+v79omD`HyAQ{Mr9$mj4)QlXs}L`Nocq zr}&QzWejH2UdS+D!ts9)<9{i3*9Vb8z*6E4rN6;yq-!=JQ-;fKk&A#AnZ{!Mj|)18 zeawp@`2Qne)nKi2cJ1ggx2MDZ&!2MPuJo-)_Zhwygp_Fc3<fI0U8MZ}4EcfxLl&2= z)4oYlN7Ym3@}yl%5ml@qD5zXW7%Betv0}xuW=#=Zu3ubrUF@nUF|GedZhb#>$jf8i zT6JAq(uNr>q28B=;3n2R=Ecse;qbz6Aiscnv&X#EnN>jJ8-dyRoQaz~o1M2)QQQ=c zl0O-pS%ngbAJKvKD^_Pjr0H!EO;)NIWMsdlXtN>X8lULNaqJ=dW6X;UZI>fHX6{{l zN?B*D;mY=Jjm_M<<O`h^Ecr-GS%LiVfqVp}v4XZx>Y?}O#C*#3vx#k_Z0Tk22qd!` zhhy-Ncv_e$F7#tUKY+gd%L)wdwOv^4vduPo)!=Z>?3D#^bHW_FD^3o_;$CR+0ROVt z@ip(t-`ZrIwljv}8lg1O*DsqRXRM^EA>rG>qB)2#e_$7lQWed{HkhlEa?&zAM{8#I zu@dr~>0jm+`Kp*QbjC{8hu$W&e>uB>PAGVcP=|zyU6DA`)ERWf>WDuQVH<AymlfjM zoeVe0X5O;doCkW0wEkl$H5g<cG`w^0xkk;})F;#%p=u-+o;@>ySIwEOKKg*3teq_v zDtMA(GT4DBPUwu)6}w6oh~%mMp4j8^znEC|2l43X>51#`w_t11V{Qu+rCKeVq;qoG zL^z3=L-Qu5v!xgt<LOE74z*B5bJ=V<fvYKIX3i0BSnO!F;<R+?fmO*_lUAM@_H=WL zyg!^$8=vXxUh+|3*=#=STIEP9zecTwS+z<PFN($8F_;g~KX&ijDGecQaE4Sunl`Et zyKV{Q%n48~JPV0S_3OCn3bT-b8l>xL!GBe1`b+6wj$DpWvxVH8+8r~sC*AUFJKGjJ zlbSY(nS}JIc!TN`V;j1SPZ?(M8lP<vt!?xC?Q*Aw<L;goWS@+KoH(Y8p)qJlD2DS_ z$pI|OyQN+7(lYZ#U}Lf~Fe}ZxJ<ZG;0V8=cv-lvQ)E+{&cMUeVOQ$$7us!a*;M4== zuIbv!l^yM=DN6PqF~DcPH^zgB`hk(06eBM_W6T@U(%&mG^HSnE3u%NI>WzJ3ypb4l z{n3#ioZ1s}mVdc2yzv-$cMW3!F<4qNNqY#8s)c^Y=(Vesj1OURk674jHH(tNvtWOL ztHcb1u^kCdvBOiWaLXP?9C)^ZNK5$Jd67t3$lT-qGQQT@lnyo0rej`Y2X#v9s);d( zu|rznS5x9z-%qyQT*9+jC&)3h+IW3%72m_F2G@W2e$7C=uiceve)fWF4>Wuj=I=&% zH9PJ<jCD}p^!pEgX>NM~{x16-^00t(yxe&T+?UX5kxRHGWt$#AvfX12j+^3oUKrP| z4;wm!UHO+K(_ERgGrc2CR&H%dF)Bp_ej{!tOSJGX3<CnSGX=~yQ19d-2Dj)-nfmZ9 zjtH@_j(M{B0tAfO^Tny@)C4fzP74t*)I1XO9nhEJe(`H@sVirBF}H@7M)AO2Ji?Di zc0&Zu<rbc)VrRe!3Musn?`Q~^Jf=vgIod481EtKCF~X@<<QYU-ML#uAJAy)(M~*Ls zE<?RV=cafKH+{po_7@w5VS!>U0SF`ohC)p7wF8@(^o*`$V|LQM#cKneHRQr6p&4dz zs*vwTQWOs5;ETGA8_zHr^V9>!NDNGUT>ViFmK7fioQX^8<mqDGO|&o)9EN`;adLn2 zDTMpS#rfhlOIF-@9vCQ4#R-Z#wJft)X}eUr?WPy$BU=8is$m8~3ti^{J41YCYew;) z)sll~r_p3Fro}Q-!+-Vo5sNKa`(fL72CV-@Ow^f0_n0s5`0~~`{|-Ye2L2J_e>ry7 zKg^fS){a=0xosun97<R@CDz>58cJ?esVk?%t(*w!kfFmkkk$KV&{{i;YOA?J-D~yR zsk4I2=9Y;B<42n^Xxi)#Uv?t+y$-xgoJ%|F>#3%&t<HKGXx5u74CGDa<D$nZi@A+e z{NK&&rPyO6-8G+BT;^P2<QbFr-NWy<{9fkw9>23=@;E=RGP@2_X^tR+DfB&3JYMfR zmxE^8{U5CGe-+EMe=-n5=MY0#rhB`FGRU**{QJ&t-IpB5_G<PSItt8~oto-a$u9b! z>E4jiVXJoW9?te2%C4&?8|mTDtNgK67wuL$7Z05-FugjoUWZA#>Tq_o&aJg49-}}e z366Y8kB3An<liVQz~rh+*i~l{s;~Zta1_1ISYaM{UUL-fk9)J`D4ov<g8L62<KDH; z?>~Hmo;$Kxa}*6^cHV#ZUxDldc^)yh22(N+dT+P!ofWt=kj*MU=M?yfWY7E|Xl;Fl z5W=h(7z4%Sq!p?WZ&}>BHqDPt1<|1>5q*kQ*j$wuxGE#2c9iC`dMt|FQbZ<No@|Oq zHLef2WBXuWSYT-Adk7Y0QJTMJ5aZL)&5f17soj}VkNQs6;>jtU14IBp!Eu&E<v<7n zyqEcV2I8=47&DR&0FfU6=n?8bFkwPNlv;I~dJdWk<SY%nOaz>5%+7Qf!<eccOs5no zP`uyF@n(7sEE$ZO!A{S9z>GsVb@jOa;jKUV`-%21TROluseV~q3?~{e#bNqBU5k~0 zdxVSw_vjWp-M_h>uZWCxBPpr*_JAqDytS#znERRI$Q*SB=dy~G%zI8NjMfEKBIC5F zCBl!2F@)<er>YoStgDeZUjH($%=SCcb&AR}P_#7k-#m5s=0agPbq<BaC9U1cx&lWw z59t!`#GjH?Jl`p>XUZxikCgQ(-Wm68Y7MT#q{9OD)Dsji1*$V=spMwnRA+irZ5(aL zwOnQ!oNE7cggmDCp19%zDn!!g5*MqHMb&h5dU5y2BCokk`}uF}y2}4wao#*#?+coC z`p)(Lmy6purD90G)iMmEL%Px!rA136a)3n(ng|k-nqHuLJH_=6oo~-Z+$*4I@Bga2 zgMXQCEbn~y=KqeoL){wM=fGY?SovHA7t`GJI6L4tn#^>k(_Kh#!D>MCX&ZeGFmQT+ zi#Y-V83I-m0|3{VbloaXifU#?fez-#B&hu_&LBc_dG!vbYl+I1tJmX-5T|EcV}a=T z?w~pYK@V=j^f-V?Z?OMLXU4OknD4GbSk}ixWWGy@%y;4ge^0|#!t|Ue?`(t(F7|`+ zes7gXrn}c7)18(xR3_-6Z2q?o$OD7*ubKB2e%txnGA7#?UX&d<$CEgOxD8pxe!|{< zCd(*r5to~7RP#%joNbizJ(u5{!Ffj3q-^7{yli95)NJGN9KwJ(3QYBkY$IV>wo$^b z+LLYM^L#ilj|uCa;k7&yXL5V`!g<w`7tXt>6#Kn_eFElEvQcBR4Yx5Q3M|!Fnx1WB z!nP8@D3r{<dij%J#AjDl+_cER-|7>@AD{-&@q>(nY@fGEF6EfJCfi_!2_KCDNdnDa zW6;ET3vS7&s;sIJG|j-cb%7-VE1Mz4fE?U>m)5wyn{8YTfc%_%7{%d4V{mTGyqj`- zHJo?aLSe@Pz>%6`4v?Ta#YhmKsn}ggMns3}r}WlGK!+LwJ&WeeujJAYAZ`F6v7j$R zk}<S!UJZpQDz93SU$Mwra(}h~9}cJVEpvUcF~DlVgF~~8LI9qQ%1bJCsxhdrs@hjQ zwRDkBa=RXw?yItmZTuu&ey14;PCf$C4oG?5e2mkLfgF1-^)4uv7TyBHxF`tP=KK^R zaYku%<-7%@x{(E}1+c<?U}qS~HrO@Xjvncc?*p0}Rdi{lGmU|>DrzgFogT_E?gK)8 zQEgp6%osRrQ4Tj$-XahW6Dz-Hh*V?nv_-k|D>cySi?fZT0LU*I=qwFHr{&gERl5PI z2S9$&KxaEZa=mr(XvPEp@{0yK#~3ti5r<HO0uo0tj)<3EG|X^g$h1XMtGLP}w`$3v zN}$StkY6;^xe+M27ff(f10la?sPiO0jjOnNHw9<L4a+YY=6u1V9c)Rdv@LejIj^nX z`YLSQ0=p9ylU#QsT=qx;gQsjr&e*a*&e%@>dIRMjRDvaXB2=gvw;qvWC{Kx45V#?s zGtZR^e5W6xkTVzOclulGHz&mmQUv_l2;Ee{AM%-<c_i$-kK$c?74|tHh8KQ0f6vh8 zYz8uKw|S?eSD9{Xr|*=kRR*uxT>Q_=jyT6nGN_F{ZUWCC-JTBrD}WmHn_(Mp*BsL? zNyRAKjVqS1y`RJRyr}onUD*3RywJRA1QRy06h0mbdL!Iyj@7w)zlUe$WYi^>J))wT zugm^EyuIu~t3g3S_PL0Llq8Ga$~96rbGy2V)`OpCu8|h^o)XYc!sV_J!p(YJ_Jr{C zgtjZzG;5fZ`Uy;ulU8~`(#n(Y!^le-XNw&!Pr~1`!qE*}aS!9&@D5+8pERiMD4f_# z7jykKedmilA86&Te%*c~ENgJ~HD6)A+x$4GWi3R#NHeN_v!KJ};OqRY->jS8`)wPk zw0kD!>DYd>av@+i0m-%_SKV7Ny)EiScb=Hp;Y;fc(%`s(y+=1jZ&|zM_AR>ZXw}np zB&@#k0tCC=%29pmB|hHht)y5HC-;7iu)(e(p{|vwY3;znq<TsykZnIr`3;+;mxSKE ziPqT#O%C?Ekizl{Dbb`9wf26}-XqZR_3C{#;!d^Xmq)^fa)u{+zrz*slakese|Chc zumxzIB*__7Xy#<#ARRQF>ZOMmC7Y$!4KD}iH3^IQT6TcbUr*n@<13c9JB_&4&5xTt zS<aTQ1tZpk$?0s1_CoLxNJ;aLPcxRY*uxgRYv7nq^h?8LXAFCnHEeDnD_y@T^B#GZ zf+bUW8*w2=R8u1**(M4E735?C!6}R$!DPn{kK=rkfM@iA$NfzTX8u)OCrQLk{Z%UY zKK1SzI!pBV=IeZ4{J;?uVq>knbP(!)+mm|b90_RWTeb$hvnCq3>n29zoc3#(fi@g3 z=Vbh_ubh*A_eA4h17UZ-iR=5yIm2&evLnnz{PsGSAMeRGW*fO>$U<l28HJ_r<$ER? z2Y9;IPBdmN<hdf-XaqiC=GCQ3JS7!gk$)l|`INSYl3t2HQc+To<E^QbOA+jUPbBxP z+rxaPQMc3^`qs_(#l${!+s(JgaQ*96|MUN>ZcC}#QgD84-KKJoE>bu7NTak5P|`6c ztlI;p_O07$zGqUmf}5z@Exqz-^+SE@=E$eV)$NxjuiN(DPCRM9t+o5D`4Ow%_Wi0~ zzx|s0e?QS!`G<+dwudJo%hHb=jGA9Hv1+N*w@-jUE%sA`(I>2P<7s{Cyp->8)VZg= zZ=FYN{AP8Y-F)&o?|=T}bzX1R`M`5lomT@JO{<ApsVl!BQr809SW?x2(H{q?=E{ct zUAxAi+w#-<)^iTu3Dh%dQQvxg(=l27$CKC7Mcm28<STYPpZ=3o&$W!p=z1O`?O>_n zM4#7NwP?-2sE@bl8%239>eG|GXQ~TR`qnXvZx?lJ^!{gcOkMw<)v=p8KJny4qn@Ae zo&I%f1g}M+<)sU5=|i)2KnuN-?3-wOw@*!-z8nkw=znQ^OFesT{m<%|`_z9{&%`tH zjDt@@m;6pt&m`%`8S_diINc_lIk11g<8;siw@oxg_Nk_vXO?rwvhOi@InG(+rC{AL zd*34x_v<D*F5?7o9C_90QjU+C`dd4$XYFw~AH2_wdz-k1vV<^(RtSP}_hKa9>|fY0 z&Bv!-_)9zP0Xt6XK#qz|%#)b!jnDU<*M$x##qegCo)jF7mzTMixW$>^tDLy(!sDg@ zvptnus0ub5wJ+-R?^}VdiSkkh_E*5Nk%y8Z**de{(7pw=4nm)}UOi~JUe!+2&PmO) z&t8fXHSG}fD8B0c_4HBP^>i1iea{>XtEc#blVVP3%Wk8m9X}Lq2uxjd8prZ|?ZKuN z$`tUtLO+a0rVn_wcY1bb10mPq`35#j-EE-l?DXsz0Y&HyMXqBwsFF48+iLA3Npk@4 z<K{P6XLuBcQ56M{v!QE-IprhYLN$+)=zCUd$4x&YTD1d<9#QQh^&=xTaI`(kU8pup z)`v6;)gO6j3%!;~^X(RtUqw**m+v>c_;ZuCp-FMm^d+d!5e-y5X90dC{(pk&BzB{W zALTz+n$^xahL+QQyVxGtPwH-c0enhZs8n+L?>_F?z6Gp!Kl<<-DN3#Y^tp^!(~qo? z+Eg1LxRJfY{C~K67x1czt8aYgN<tD6F2SH!jv6sa)F7w`M8oBTpj-}y04h{af&q~r zoTF#~51v2?n`jg-XuVOfYHM3mtT9kT4oy%gMnMRYYN}W#CTi3O5mNH~erxvL=Op6g zeV_mH{J-a;jc3oynl)?I%&eJNvt~{3wWY{~2gGhgsc;VW@vn}xzqC|+^%5!cCRaf= zBUmp%-`CuYV6A8G8?kqqN-wbHhdA5BISag;<V4l_hZ(-F&9`9*R}H+E^*zSJN4W#( zk)r|2n{1vBkMFbvcCOd`<?#nTLhH_G#$%7r(P1msO64~gIrmh%ZOoo!E7t?+wf25s zQw>ThbFW7)8OL67b_%?exYzTWr?T$H#3N>!iU+xT7%3hVD|K(w7)srntKAibi?FTg zOH{qoy%P(`!}7HY&IfkIv8TClpLd_S*3ERhxTCV(XU{oIvW7ck9b9&T5phlgFWY_$ zHw2&#{=*W%$DE^8?3-R!*@LX6CPHoFfRqR@Z^fx-t{!Hv>_Mp_X;XKgm8#rFBlzg_ zQIOiCUItpHZzQ9{LmwZ!<wUSyYH#HJ)=3$K6!aH081#nvYFCT^^k9#Qz(=s*Eao}r z<XMP3Wh+UZdIsGRmCz2ODi8=Z97zRm{TlaCOKIFo{NLDjT6r6{sMpbvPzt7j?(V3V zT*-ypaqjF2OkcvpVz;ioKz|n)G?@G=Ij!S-;zc+O;~}pA^U42Wy`FOh=7s;odVLA< z{nUCrX|iY5;>EWYFPhCoyScqf$B0(2u?-{-G!nz%GH{hRhx21Q|4=Rd^Ygc>(N(mP zcs%<?FM*-}(1guKI8Z`Jb?N$e1W)|hje9$SBtlCHq6!z~d+(TExNq`EqYI$Y!=PAX zk`Xrw4-bx-wODkZdDy#ULaCUCKm7CK2+ZHjh;j67|6uyvP#NNn>HJGZx_ADd(LbjC zO!+11&+b33{_NqXKh-*Hr9jDMC?mIrDI|Lu(Yf#^PNv16u0z7=O6K)4lJe%xF3cCs z&MjUr7;tSsGcF7cU`DDDKYrGdafJ(R^1^ROju8u7C7ob;L#^i?KdN{Ew0ctDP$2Sv zYb*%={QS=;MuJwyI{btDY@ZI^*--pVbD+pY7I+z;YEZ9mC@32>F1v;&)Bm2@S^rCH z*yOf9g-#rf?KC6K?u|dD0q)yL0~`r750r=c7%O<X5qEXrtl1OsI6X@`nUeTdAtiCs z0H{b&c_R?28l*9#ciiMzH%w$-C6=A2eOed@>5ezL03_dAywHG3Q$gdK7RDa{_+3Wy z<iaJ=6em*(pV2`noQS&c&t?e`oQac(1sDr>ocqW0#%KMk-Z=f2=#9^|Rl+}|H|}o( z{gmGLoG`sHiEaYx_!nNU3=-|;`2-<akjlSsh;xltK;Wr@3h;Ix68RSnfCc}=1y>c` zLB(?mVCs<0zi^lVq!%zAx^*L>!vNr4I8Y{O0Z_rhAJcN5@93|8O3QtL1NBo{?hAi` zmOHD1mOJFf?BfK?jaVB&iB_e)nBUf3wTjB3lXxVfPrR^o`1x>Z?B7CI!y6r#5bcr$ z|5>H7s2^I+1aHD>`Bfv_(22(Nn4DWYAASGoLcT`fz75AWFiwiiFI<4g)XCbDjRu*# zsIYL#+``)<x?m4OkDRfK;bn8dO%bsp@FFQJUq%)e&o7*{0EHX7&&)OYo)wxyKSVeh zVa}l`10g_f4(U#Q>HfMl^M5yomY=WZ(5wq`Pr4@?oP~7IHVuExLvoFo`0d6@h|uDD ziTsE)jK5FVIw&F%lKgP{&I@tQcoBA_$eV-jX#CE`@5woadHLiC!@-su9CgMU-8%9Z zYr*XepG9NklVdb|Wc?n{zd{=RGdw-SU&du3O#Tw-|4sbOxgyu7xIEV=!7ur1<mAF< zTgUohAKWqGF*E`@P`A#Ui7|dmlH)}6=OlU8kR(U5o=j9HbP&~02etDLT;)GM{}Mx@ zdNU@r6eRO690co{i3{|ILi_Pw-PyT@tAEG#ibXi<|A+Q+jrjTTFnttg1Keo*snPa$ zh(=8~9@xwH+t>PaS-<J{O`9yoc09W6*rMfKel%$uxby!)W6Pel)*N)SDg~VKo)`E} zY~Vz!_sq(?bFiHmm8m`*N8fMW?v>-Lh<y@aIfL62AqQ+1AnyhEkLXD@WB0;6>3gLQ z@>6@mP0z4*p;hj7?2{^x;wjSrLACHPC^A+Ox-tiVsy+#`iG<aC$#6BUUd`ebvK0=T z+PwwbEk--|G%j^97Dmv1!~%UpBeVrl0CuMy6+m8S3l2CtwFKmqlxvU@Y`88CTeFZK z=>bU9w5We!QVTW=WBM0(^IUJ;c%H~r7&;C#dptK?vGXa`6SH3tcd11)k%VIyIN*ip zt*Yt93iRJ73IT3VahjwR6(1x5F^$@NC}+h^W&=0F@xiDnh?mx9!{bv@L=H}RI^p&T z?zf&6+_AXoz*~yA8EK&^&$mc}5=juvC!+415Tz8Qp9`LsoD|D-!5fE8cV0I_b#)sz zp~AY2VJs>tszbn`-Gh~_Y$iMQuJ%M!84+a<GE}ybIaGA}_wAKUfYjj^Bh`)*-?x`N z$V56HUJFK4yIZlvqr+uS*~%6qKx@;c)}Tjt)arrK856Q!#JHBHYUMq8OV{%;5d*e= zS2kNoEVv6@jooSy*l~bloTu)?VH~{41_z^)wZflz2@eg6cAW<%TzDbknv3?~dx{#$ zfGScFIA2m$et}090S(>H@_CU{+ut`^=S4aig7)`^ReR^)rb{%otLy^No~iBoF?z0s zRkX(eQ)4fNkHypJ=MP74E}YQ80^hQoje2Vm!Y(vrTIeXT29DoCxsP9RtQ~Lm1_L`Y z<-`s}!N_5e?R|WFF}&~=FUrLW)Klj!m|c83(&6CPil!&>5k|gM`m{v2vKnyk-Qzga z+-pP~%!jWlGbNmu@Ph9~!PoKq=D^N+oM;EKH^M<Bt^;t$HLON4YT+Omrto&J_}0j3 z_faT)hT)7C8cB}YngMnvLDg~QjpoK6ajMpyN{lM<(qop!6n@X0QF{P+{mYITUf507 zEBMHTE~Z)C59BhIZvjt(4fkTb(RdJJRloTJA8XBO%lT-=nmH>z=3@ZIVtlvGc|*nF zS%8Q|H@zG&nXd#EEyOyl2%XNa{xU#>#Y8kBU(RGB!rI#T4`5#aESjg6N8PVsd*g0b zbhIxSKZ()4IQ+!niDHaf7_VLk5DdvfY%RE@%`cwgy&VQe)5p)faZ&MNgr@5@T09-r zPBcWa{7_GKFIfl^s=`InN5Hi_UJ09R<ib7tg4y%$;F=bM8QtP1kM$PbGJ2MGRvdz$ zUM4suX?w(-q1E|l11zvt=lPj5K3R(;CaooMVSbW3xbhBUgRtt-2L>av^!I7_mgRi^ zesW-5r9LgdG5`Eb=V67|#R+q8AqV-+0tjC@*y))!d|p3Qj-iEa-&3@~S6x8<o4KP^ zp-(JGI=Lu@0-Q1xlGE0Qs=*&1%K_lM@#5p{ueq=amQWvr%rVhPgyw&u1H15l_@;AF z-#8{(C8E=rwX2_?0D))J9s&%+Ne0>y0F8aspV1=LyAZL9;#W+JX2Ffofr-(PD<;M< z5V$Fw?^2Ma{5uxgTZlmyAuRLTV<<!$y+9cPt_9UUKv!9SO`!f5b4-j4U@3|;bwzk- zg9F*UUd4#<4nQ}`z|tF8ugyQ+4rj59pBD``kD1*C<0wX}6&D?AFQT~CVt*w|<_W@Z z<W>6~hd!OU=u-d-``-O(+d+Uw-bF95>NZG9k17HJ>m`pg<k9jOZAu%G`}`o#8D0HI z4xXk^7b6S&zek|oex)B30+<{2Tnml)MzOKTD8!%rPw(TZ0%QbUItDQx!;V{aaA%A; z-VP>meKBb@u93)D&>DQ;4%aAjz`*6V`YwHHD~dfcI(<#*c6<!2@tr-V8oL(2jJz6M zZ7eFpr%b%v5R-)%RPuSmUCY*?Q852OrbCBbt43=9eZ=bma1^sY1W-Ktk}?O~0OLK$ zn~eXS=8Z>R3aU4+Jg)WXQ^3S3+SD}v8gnm430xb(BqZ8nM!}FmRZL=2?1vD+RT~s6 z@{ezh@Q`L7Y}KJ^r);a|eyTldcBu=Qo{qu*IOLs+(-caP(iwHojxPYFvVvOmw_1@g z@qqgc;2K8-F2_5wAOdq~57ow~zGVgb&>T49DOks2lYQoXxe}<Z>;jfltFwR#5A5{? zCb|6au+xyAfebthqRs%CV8dOQa2;=zVQ&=3lwCZ~p*X1C^?+lw2P}s7EyMdgII*KC z)>2+a(Y?DbX-lvIuSa4e1-5jh<UtGVH3Lu)8SU$^`v~=`+fWAQ<of{}Y-q-8FXX`J zO!!!ruMU&5ZoI=$S5{E3euaLE-?H(z$`xnkw5inI6!407#@u{L#EL!><l=-vRgq#| zoLO+h-J0U<V<kr+SzHW)N#=eKJ<&?|d?Kp(HDd5+4b0kE1VA#;nHn>7&|g96VR%mm z!d&kuR=$^z?=^}jKo3QB=S{)D&Ry&aa{ciGYpfl+*kLR@v9?L)LZ>o4aVw79j4^yy zfA6&`KA(lJ<dUx_aXybuF6oPpE0ar(pztfb=Qg;ba6RkuTLgv|N|3}$vnxI?$A6Pc zo&$8l8Gtc!23Kyyl%#fInc9%d7<Ze$0{UFkq4#Skm*mp7tuZ^tP^Vr4zqDtg2>?;$ zCj_1*DkwTQ$f0&|Twr-3UNC-!70sRQUlN0RaO>?rGy<j$ROQ4(*rFx@4d_w-m1dNY zP#HovWw@@t2pcTV&q7emnSdspGF;`pFXP~J2rq$C&!AFxg*|sV(8KPZ-6_<Q-T+pa z>DQs8V8b(Q=t`kg`(d!$sg@CJSjFTo!Su3)iAQ21y?wCY$W3397i~`A6Fhj7O<$hK zO*<0nLTbdxQ~Mr?&GBANqF)?OqNCM)`$#mNa>i+HX|5}<95*0OM`r($Xv5db!Vc-W z7PM=S72SAUufdDj0Fl2!W(`~~)L~TwgZ7503<$9ns^pcU5oPh9VaN}XOU_1AV0j9< z0xuQe*wUPmqNZV<uX2AIfpX>qD(E)E@b)Qle+xglE#{0i3YY*jYVGT=|Ho?TTV#h~ zlB~h~GL;Q!QSIKvY<Trf4)AdPi;>IchrokBkK>@*rINq{h95_mJb7?0dH^HVB4W^+ z*Qz`VU@biQH!d$wDX8N$R%IF&n9YIZI6Kb@EQgEH^O$e4AR4a50TB)^5i?R^da0p^ z8P*ET;8lreqTyInTnGxe-~o9!zjl#U!1n+=NxK&C0P1?gUE`8mym)xcHM2`oiXt!+ zc)Z&MBLL^W$HF8d_jCP$spHEIc<BKPEZ400i=eZ=1Mki*oV8#!w1=2;0y}HX+Un@^ z9Av^}dfa1M^F}E=dSGH%eHECpPc^&;U*S75WWLZ-RP&%i!;bo*Uyi^fY%SYn5cGhW z0#I&5eD(Tq3pwiz?5tt7?@J5h!Ud{$A)yOeRWiXL@{&vLwJM*=l)WmF3C-2+8a?H3 z0#U~>&6O3@sF6qmU#8$hpFPz(qCjTB>rrvM1@60uuzLUtG^5@H8U$Zw5am6IF!s-< zVVL4N5E4#6C^aVHUNVInUb4cP>qC$u-odQh7Ia7=-*=-9yl044S8;xcC0T;G2kV4t zbt-a|`gS8G9t1~WN8O0GscItefmQ{JG4RprxQGjk-xpWyu4kpH-F5uYm$X>;V)R%X zC^y1VAyLiIfogXXkOK|ggoRE34)TerrI8NfQCJJRHw)uc18gs#RuBOyclXph%y6<G zz!mxnAVXIFI=U)1#-MZRYS<`{nY&edjhxBTawE>#Q`W-m50?&2nABGR41Bx^P%<^; zRJ*zU#3~>fsYOhEU%iM_G)Ri+PRFBv2h<&9vWf2nh+Lh2kd@!Jox6t&+3SI?(ko;+ z^^PpGmZBDDo?l^^l<;DNM9sk2Fm{&_Xd+tOEJAy6L2GWO-*B`GHg8rBJd`J-?t8}~ z74jKtpP<5xA$fU{Gw`c`v8TQ(00?*Dz%eOb9$drB8()A7f6y7)RH?>TML^8*T>o*f zaQPQh^Bq+CRm&di^`p~AlQCY}HLD5Cx=%fftl&&{Y_cF#V+>ycwp1=|_qR7jZi)aa zq%P9Gn!yb*mRUXixX{B1tzxJ>p`ojxlS}|@_=PR+{oJK;DG^kc{TK6KbHm+;5c`m1 zUL^zYcmQLfy3IV%7>_3JeIJ%zt!w&8*A1#G)`*SGf6R9V?4iuvuO5LM@h>}$xmM7? zZvyV93#NPylWw8#UbG78g_p>h&7+MGxocuob1BjJTKtz|YW1OH!I5AgcnAm_>Ge7) zMd>y6drGfozYCLIXxBH@7Xa34DtT6i>k<1RBzdxLn9UQ^{nK15f|~w`HW&5BU%><O z9a+8yAh1O+@J-5+?a3wUkT&Q@Zs0_OF9|9c%pmGIP|%nGT0Et`rYd(c?2($_bG->A zs3)_5bUYspBjgP5hS#>Z-hLlb0J`Zb=%Nf(9<#crmAr=qH%oVY5_|&0CLH#lA$YeE z=Icuka{<T($Dak^4qFbPRFI-gEylN!H)adyYqSKB*44$J7PepgP`|;@Z<Cj13yQW4 zx7nlm(vYY5<q=1#C@6dhC^-HL=@Uh))?Rf0rQoY_AM&V6zznQP@C=Xowo$qnHfZb_ zw)%^&s5PsECMdpYkpTf{y>>SOMFEVoTGb=KMjpwGFz7w?4>0E4FGu;0Uzfb{4)h48 zrvH%K)+=N;9%W58d>d9%z_w%kWDK2-bscnFsOO5E&!HJPMBXeddjX%NWsE2t-z>@i zbc;uD$e}ka^CHw5vEGp-+<Ye<)xQ!X23n)ws4S>X2rGQusKr%xfYS{Fz^1YXi5<yb zeU2X~N>>QYH6Ke-YKY2KZUPK+z82`xRn+-1P`MeUsU}p(l(2dnO!cTBEP5cfVTp!i z^0VxRAb5g9n8v5F8>DTffw5%|)&ZN=tu6<)vIkjPP}N<Ek^r_00V#+fO^X^zqNQYN zZ1tW1EQ0M7ZUS0lW8U<r%RmwO@Jgpm3P6pdBqJr*(ES^<M`%sDSW=;Z9taz*V8ge# zsvnm66jIApk__E>%Q2+cRf_N%Y^WkI?1e%~XSOeUBz4ZxhvkiSjPq99%G9rQUV!5& z-I|!{5(-pzjHGL@-pDH8I|^`fz;$mv_H(V6W$Kt{a)#|rx%ci!ON+4ft+3&BF)*^1 z?nO%n8wQdntx~<llI>IB-RT$x?%NpERjM9SE{x#%9ASrv#Bw;wza(O)FVPHE`hiKs zA%QcIT^Dp!U6+<HInD>?o3UD8b2mCQ5*f?En1KezgNA*$qy=P^-lB5EsW%jpoYwh9 zh;LE7g?MkXLp&$$Xufv<J`Q?w68~{l#T>;lci^y3b5V0GC``lnn5R1=Vb+IW;IRS> zTE3dw^d@depAPV|Ssg%SJ!)kd)`6|joakFs-GA6w#bXL)vT*I@lRzjvDMory^;aGG z%9}`a49af8sArp8f!|=m<AnSq)KSEjLM^Y*V{$zc{N?f#+RQZa9KU_}i?u>>ATd1x zO*RlzV&$3w&hE*P`S-$IvT{W;!KcXwVCx*Lrvf)dAD6W(oEpG+MoD=F`l5K^;9?@E z?nhqrd^Husny(?*bEx!jkv)&Iub0kfgOQ?MERm5{;MC6QvhChsmT;(6ul^Q1)I-u4 z#aG?UI3l@LT~)%>lCLY|E+*+&fJXbg1y)<~ysLw@v)G9N7EA0*1Ca88i<a2wkC6v^ z-QHnhXAc-iGMh%)WLjdU>ad8N-*gf?U5E`dq4}RfH^6ky_q(ZN5P?$jolJsmr%t!8 zAT_KL=6uxv`JroQNv5YhMZ(D>)00@dhD)X=VP1$`>B?WDah?AEEr^yrbt_VX4U50% z(5Jei_If{k3R4R@rsg6wTsnP&(L?F<mi)G<9rz74xR|NdnQA+ni-pFP3@%$Y@;;7c zb%WFPmfMC$z+=vsVB7sXrd7v)oA$@P)9h%T+Nw{i=;V@iwhESZE$SUK0~fPxrR&)t z<s%axV!Ya-W+ItODqn&XaVf3MVFWynZgymGSn#cdLA{e5TIWvP31tcuAL3|;f>RV> zu(z!sErxes0lg3)-Y>NM^)9p{+z-JKK{|va91$>WbvkK+PbzMI5fP|h{lYU#eHVo? ze}+2RnO!>bCM&bL5cFXWwpV=);+#gV13yu+JoBZ-K^O!Z)?jtf*x2cPXr4BO3Ay{+ zb~A))`T|>Y?at+^ssX9l`^#A~S<YQa;vjf>!=V;dX57gR4s6j?(mA9$Pls}(Svd~> z+sT2$5Qp~lAOg6p`R_~8zUOn&F8g3kF<O?8Zh6-cPu`Fz`_(!CmkEK`I<1m`u&W?Z zEs>CL9=-tPA%qs_a)xMoxnEP)FFes+)GHS!KAHHBita`A)r6jSSC6Mp!TdbWEN>Ca zvKHc?CbxLeR6O8|>mSDAqQd#}?L#)SqWl|^YkwIE$eQsN4GKHk3vKk|cDP6OV|T5_ z0q%cdb8Ae3y~CUlh8MrIxlNfpqJzEA`m15X0vlc!d$hLzM((RjDE1cKP+WX7c&qPN z*%9+WJxzPgFcN4kWr3v`c~`+C7Ypg#z=q24pPzs6u)Mv|JNLFi54;cjm{WnSmQw*< zRL=vF&epOCmbL7US;PK+?+oC_tYMQw*07z8Q(5a2$L!R0Zg4WQ)9$~-?6gN`v(q25 zDec+Gru1Y6qrHCKU^Mlo&5TevIsvc^Mqwp$GBYDM0kGTz{Mh||?F8Uw?)N)R0Dj6& z^VDBpr+M1X+G+N+?KFSPcrtYP|EG*6fAx!uC;R;Z<4HK;2y+pD@n`?z2n+u=7-7nh z)$raCZWos_@#J#kImCzi6xllAe<nxlyS8yR!c@JJ9I0C~!ntcZ9p$9(KA0^WIPxh+ zeh|6&N?4CwJOUQa9c9VM!~kjzS)z^Rf6U!S*Ppj{haH^d?&HTsc%mNRv}4bLC>owS z!e+XkG{hLOd4+RtD)JH_9RPLijsS4bIj(SyB<Fw=iICRTKgpkj(F%Tyg&pb=8fKqN zigf!$QY878NRgCZDn<T>zDZd74Aj1@Q|+USsL8M=N2)Cz?8;L-!gGlw9+*E9`TKTa zZ?q9Jb?$6$(T|CbUbY4IPnmhA+CV=gK6?KG@gY7<e$vc4?dQZtA4f3!l=wK+f%+-i zYw>9EGag37qlx2TBxKz&=R>S<Z0n9?aP#p}3^sO|M{qp5Arbv_PJ%Y_z=F3*jXy4r zK6bLf2tsEB6}5H#y^7O3_AXtp(i#EvjbvN`#8jqp&&UG#K(tvdka&sGyq{n9tIKc1 zW+Jc)p7iv-@GayL=L?sbVkKbaq`VZN5~pCNX@z?sTssxva7PT1rm}y1T<<5Xg{!Cs zmm~mod4^eC$@Pjlc<6gBM)jdSs$fvRpzRV&IkX<u>^(#3vRC<_A0rMP$PULII36b$ zRcaJsC68zTbS7lTFe_Lkb86hMZ<a=x-@rpI{5>4OVloz+EEu#@n|stdHyjg%24rBU zJ@(gywa2G%u&8+mbfKi@zdPo9{~g~rnBDh#9LzrR0rud+bTGJc%b@P`MySk{R;yfS zE{p>)OZ(;yqOMk=)$&=`6TDX{?J;J8?=vfUF)*X`{-O4R3~9Z8sKq4jAC|8@c{c%m z=cD1P0%tVz2!W4k^-U7EOanI60vkhYwMQVbPj^H%v+O~+@O(kn5&KgR1qDDQ1-=@G z;?Nk~{lB@Cnp1ICqI#mH?g_pc`;7$ADXami6<4vnBE=6X)JX6>!x{#b#2Gj;{B9=H zur+~Wc)tU5C+akupkE1ds`tzth)c;aA7X}KBjbEMa5m5lRK{CyIdOStA;G6^1g6H= zVKu(D<^5vpOR*t^#!Pl^(!|r^u3C9$X}?iuT~U(x8LI{e1vpr0FNn*%%6Hg$sM*x1 zNk|RqZ!;$@{BE%}m6&ur)Cf-yk<%Y>)+7|65DoJ^a147HOKTX>p;AFL1fKx6?@m`~ zt{$n?TpcFpP)8o>(Edq2re%tu4f06;MYm4WfXOT00gT3<T!InKt?2Tn(O%H{dj|xz zuwcV`rulFjsMNzz4Mn@71(VEmOhp5KS9P4~qASsT@Bf}%79a6P(Iwiwm)I!IH-AeM z!(`O@`T^qG^94-;D6Cd50R;|I_TuwdeCm=oB%$u!1}Rl4EC9kYZG?R~AWX1mi@ivj z>}X#BMU&y(tRUC86Tb)X$A1Y3*MgF@`D2ZWJ|Q0^Em0$7|FyKsNXHjjO3X-OJ^r|E z8kaaye6hVSRj->=Jg!-W`6%gy^uyD~{=gr?v}D|^#Qtmcbz_Ye(%{Pizh0C}UjaM& zjg)m$-wQ@|x|>l03S*4ZL2CuRK=sH)#kVgm95?HR!ueYf6T!=7-XdO)+>T(Rk&G3W zwoKPo@OMgV+{CMNaF+xVN6}7jzK)8-rMxBA!U*0*q%UfnW^B9;E5%Oe#A#Re$@-q3 zE(iPGTcV78e;O_BUg)x+yvq+En)2Z`W%5`!UrR#fP)?{#M7K(vL+F3(pkIp*EI8ez zQtc6NTdRWd2fYbdNObCP$OKD?SL~!iy$PlD>bu`ZO`(B^AqTPXFT*@UmsY-L9G=rL zWhA;MbQONGP2JeSnJ&5H1+Z9RcO$lvhWl#k`w)Sx{_M+k(j2b<Y9{#qc_|9Us&_7r z0I+_1m{FS|)J+nFw}|n|FruKiRg)#E2~kR-kZ}Z~p!TW0M&5O4%nCz#wuO`@L(O)E z6v@yGjZU>ngM$K$n)`b2WEvlBumTicT^IANf2?Z7B`Hv4_Evj7`o7&eP{)4E*n$?E zsIktho%lM(E$H6iaeJw*Ippi%Km}xCGpP4(HOrX~A1aZSw7mt0olv!Y3jvJy4BXex zOMbw8!oTc<;q8wHmP0Tb1?DiwQL~^%0Wl!{DCQSO#d90lkXSz7OYKfGBv~UYfh~)S zr;u2NYt}yGaCBI!5y1HeA)(ejp_PkJ*UOm)&wESW^TyGxw-}Ac?xgRWMMOjy{%!j} zx#7z;_n<rRK92fkAJu!MPq3DyFDK%^)d9+?CJc@Z&q3c)Dh4st0UE?CeJj^!9448i zo4oQr$vpXOXq2*nrRY=8@LCT3Q^`9O<|^SZ4qnDV#!Eo$`WnpIZ>4ZCVy+UNXQ9iQ zt0)!J+4!6T&6t(r>hr_~S7$F}_A1poD#|cZmu`hCg(@}n8^on9VL&4o!ia~6OX{ie z(77;EOF^b5BWkZY*2L1J;Jq18-}iq2{Yg_R=^rpX^#MUCBkEI@yNaJ0!D|4ha<_Cx z`=c9Isnc-}kJGLIZ<WO6)GGJa-JpFH^F_dXk3&j~Z!>kZ;HB(RWyA}6e{&my<`_7z znwlOpHFE&8kP|ba-o{c3?|+XoQ#VQ;ia&LYlZQd(sf;DJtJD_w_BS6AOjoB5sBw_2 z5<o#zr6RvTku_0V|Cuj}UNx1y0l_#_;s<{6sw^G1mTO^t{XTzBcf#5=?zq(fc0W$! z)E1}z0Esx;Lr=EsFtt8bj+_pmH(EzdRJ=-)<TVRZc(NSR9Var&+F(__!wg96gI|TI zfImiV9td4<ki!V~AMlI&4;UVe3Ur6`s9_~Oh<QMl=-)!AYIrZ=SxP|qs$St7f@K=e znd>NR)p#uJsG`@z9YXnyr&!>!=(G}cAi=*y55t~1-4ZvBfDTCahzPI2W1xnV&&Q|_ zHoUcuQi7Dze#9&nX|LtmX&;H7J<w}pOoz@Bf8qZ|B0L)rp69Uz&CGFpluawvdXw^~ zkT2HFkt2+0(eULJ6Y|B{3vdtM?>YSK#9tl$TJhIS3gPKG?~q}0E5Fboz?0L|xp&T5 zG@BcL+?fmyHlb2AASBX=)i8p@aLvdy>I-v?MfkmHHoTMI+r*y-8?DakmT{)0`{&jz z8yElY)-9WW|L4~&FzJ^1MuS4uKhFA1w0={pU%uVM^fc?Yul1W}{f@)$B;#S!Rj+$G ztXSCR;mlzI?xgD_40{P8=uS4Y>WMItCi-wS+txpElp}8Jf(4;CcHu}PVQS(08;frd z-84H;q!BMrY$$fmNFy<K?t;0{>Py?z>P+M2-dMO`v1F>#K=!qN=Bt;eZoES?vTzQr zXE5@xhAY4o940VINfg&aa7i(G?jpuDNn9@-2RCO6ix=R!$6_WmOHyy0<XKdF)1q0o zj9FCdTgb!~Nley>lV>fyS+cZBY&@L_+(D=|2`A}O3z#S}4pqeeLG5Ditoie;NIrEG zNrvGX&>S$5fN_Y6GP;ePyZGk(g>Wn@3(-VGMjKr~J=dWr2*nujLKVY&0VdW+oKQUW z#^MEwN73O`nqWz?`6Wnb)7+(_BM+B=b+^HYOhEa@Oq`)>L??F{2;+cZ@*N8c7mHW8 zOhn)?VPxTLh4ZuUonUm=!z#?TF+I6Q8A(>t3*Lc45SK_c*o{W)!v(NcC{otIk|764 z(BzGuHFtq$)`G(MqY>^3_rEN6V4mbdC2uO^b#lotPUB+S=)%P}E}Fa03uhUU<Uvw` z(Oc7*e+!x+jM&MNudB47Ku^=i?QSV?(-GIrh`Xk6vAE!xDZwriiX}7~p#-DH57=-~ zk;W9xhl}RxIID*X@_`Ex2frs)92w)4m{9*<+!D#z)9EuIUM)omd?<&yGkx0m1w1Vj z*|B4lNOGd^vv9W1v09=MpxW~K7E8=piAl<xJ6|sOOI$hPQVjHQ3=sHC7&FUvQ{e*w z*UcGe0=QlxPt}o~uJ#JRV*-$>0YY?2+EbF25;oo>dLyE{8NDn{Y3~7rv!xZDlcZCu zBuJ(XsV@k=?zVVvdd()p#~3N$@f-`A1>A|AxacM+zCxgrZD>Rjcq?KPj6Tk&cQ0C0 zyeO=PZ5L$SoOD68QzCoWy(|wR1hPSrc1coCyOjLGMRRA(mz3Q|i7|R~Od$z1NJuu~ zMKH1P_er?R)xHG`)gpv+2ob%-)q=cEV!Mkl36HNwe1g%-Y0R*i9F`<YMCyzo$L9)( zQQ`SQ+vz4ra-Fm*gzdVU0oKjv?l8(8ZY>g@;>26yt`*U7?1?-h2J<*b5^;o9v;}Sg zLNl0*litSG?T8IcV-lNYc;3i0x`%JsB|gPah>z#?d(`~m#f5+i0xn$63fw718{kqx z(oyg4`x)zZz@tJ~mqsH<1`*LNqaN7$oU9WI&{;++()<2MPZp3qM#|3IP)A@FuvH6v z--K$RQ&UTx(~TM=_5MM7OJao4BVr>;wO3B8dUt~w2da0eRkXDbbm>Z$iu4dg7pQaz zS`U9%baVee+h}9=v5^LS5f0xr+L+lonmPz)Jw~h>u{hM)3THhAJN_o~gO4(5lcvvs zFR<b1zdMwfu0DR_`}W$?XCmgK`X_Gd!Kh~$6*Joc%IDQy8ckL4!Ae}{PJ#XFLL{mu zd(d{Oms}n+{5SyOKmQd_7`Ic`dG-Za3m6kBS0PtzQj>+4Ma`Ddn-Sxbey)_>5&}AO zek%eWzDbHtN=)KSAf`tcG5(7U!!?3slb(O>*8h%QfpZ#%wt+$$_St%$AQl(Y)BFX< z^j^WNhWXcCv)6+jY{b;n|HPJ{+Ds~f7Nv40OZ0lNgG9`H#_VIv4T#~!qDqz1$O%^g zsw))}#ySaKISH*y$U=gnA$SEb+!*BV=EmT~U7?ME(9Ip+b@T$mgK_-h6U-965N@Wd zIP(3vn{PlURM+cn(P8VHU{B>V5De`okx>6Cx(2aH6gz6Uf<aEKE^;`5jS<X}Q_Nbb zj?aPWnD&UGJ;n|*k;)oeotTNcGtf%YQYIEE<hn51mwSN<Dk62q+pO7vYSzrTtS)U3 zwp;5x*Dja5j8ZMY3-vXubkwJ_s2UOj<S%caK8UZpd4W_zzNI16DliZl_9(RsAGj3x zs>9;bf!i^{Nf2trk{Vi2bL-fdmYPnq6tM&;^~77q)*UVpu^83wX{!7^Fy$HsPw8gV z8bd`~C+6<|qIFS}8W5tqj-P^~5;!#Fymy2;s@)(-C=cQTl$Sb`9|)&>5;EfccU2hW zxO*VBiEEG%e&>71qdESiJ=^=;9=$2zy5Pt>-`9MA%7*KY{@i$~e~8PMvc?nPKQ`SP zUGkn!Kvg$T=pSPE{w*(7X}m|k%0_o%L=Liek3szy^%B1?@V44<P*wF>6X*Y)nBMfo zvrx5jW?TE36r{wU1Yfg%$aEib8NSyvEz<Www!OC9-03&lT>$Mn`c3czyxD|GQ=7j$ zdmDL<DF4!|b{E`ufakQj9gJM+e)1G5mx8u6lP_vlr!W&*AgJ!ZSMEgLE{CJ(0H-G5 zFa}z%VdOthKiP+)8_4)#AublQL%l!t1pU*)Xf_uP)N`{2yy1zOkYVEOzAD<wj>9k# zJx5@tjHCBx)hoJ=i|5-F@n>H_{cCc`{XiMWF42LN2(SkPxI$7RKa$>6Q4xf|c^qU( z5|=~j94l!nlkT>YxKdGxR?>DR-Gn4)p>fY&@(MuXhtj!VUS8#HO~BBt^nk1lBtaee z7+Sa5#>kg(JJM2A4o4!z&~6NjV8eMk$rop^f?mp=1pLY@tCvk-cFm|e-o9z00Quc5 zcIC~O)*aA3#=JnSQ%swDZ^AbemwC_R80x-lyxG)BLq#?g3a`EZs=TGBk*UwCZWzV$ zKZ#LyxltdvR_7ZNSl-w0jlk_6-n2qv9)g8Fj&v@>b-Q+NUtG1^;3r$gAxoL3R|N@B zufyYQV^Z0a(K@&Z!7*3)Hf&fJDlSVG#~76&#fi39;g*t|7?n-2a4puEaXGA2efxK` z7`V$qHl3xOf<Zl%#1Ni-ZWGkHe}(C>eh=nQB+kJg4mRxEVf8-x2he)Az)rsJ#rr<0 zbjD%6=VO^{|8s%ER-CPISEAm4l^-u=i{}aWtrcxt@BE?{SP0(Zvf*CAg<NyYCA?WY zW+)hr%PgefFT7oE!<+$J;2?}hdHq=3k2JAQ#nYp$hIfX4OAa&}hVMM+#+mmIc*4lU z=Xka04E6Ohz>nL^Hm>n^o@j5p%z|tQL7u6qJ3*dB$YeCXowWxdoG!T!Rfg_d+fGi# zNDVgJk7a^=@kQIW<CVN4F==SA94}r;kc*1%;h@)}xiBt0F7Q^n=@)+edESZkYp#`Z zOh?0>gg&S*xLddO+RD+*sw%mXQcJd?gN~Wm>BPDkvxb~s@-kfROq}xd4pg+EK{yBa z`2m}Ph|xT(#+slR_~cZ&O8pBxMQjS@1eRQaM@sM>SdBSiNc*J0LK9nhPT)6}Gi9$i zDyKbv`07}ZG5N@l3+$83w;=6n%u#vm`J<gPROFdp<?%o&*?GhdG}5M6Y17*CCtGP| z-b}MpRF0nXVQ=}O&76#&xx=<+_z)xA%yF4HS)qC3Ejun#;siHbC!wNEK~yTJ&Or4w ztyUVIT~;+ZjaQR&8mJ#N(<~p2zBDY~g=18I9@&+jsc!iIY)6`ZoJ3@)>4<RTYg0ai zi>Qa4TQc5To$>JKW)vWfptapYX4rQIXnXT|9Q)+-s!YbZP_2g}i+L^{biL+6HhFBq zb(uJ`^#Jy9z+S7)fl0@_C^^@2&2wQa!<t&$xhzMr%D#f`5{@>7odNv@)DTQPkJw;C zBYIWiS8{<KbKQ!a>#_dhu-;y}lAo5OTm+S-wdm9a^nPv+wMXk&`zXD|tUfIE=CD}q z7d7m~Cyl)Vv6RPSoKlKXa9Gp9&qhj-AE|2owPMFV$p3em>GQ(!O1gXUXzO^-hF+V- z8Xk2ypzxZRc{PmKNvPuO{z30;!X3Z9B7P^%I|r_b5xL=kHy}ZmPr|xb>RY*<rF;o# zXG&N-iRr~g``I-iw5*fr3Jh{-5z~=<l2|n>0(ThO3}3Pxi6hDvtw`@Q_+;%=Gq#2r z!eZ1tC;)@>XKFXIGZ_I~9<oJIW7mfCE#J4RVQ5!7uILU_O4m<4yq(LBHgzw4gAHFm zY&3ofDM7K`*|(HEkA~Y?%X$d6NJZ|~l+M@=57+h);QZGhgT}Y4E;x=}Q#M1U*n?}F zjx)XmQYK3M2b{A_ZHB%IKKCrWo07<$YWrJpLoo8}xE@wqdRW|vzv;XgVR4^ZahYLp z`>nVv#BJEf8I<qum_5z=Jt);&lr;c8O_mQcqfEa<c(MlUw*%^#chR?<l#F*zz%|o; zBPs+i8UPMfR|sonXRMiFSTF2=HT{QJ_h1?atAhWDG>*jd2F)&ScN`+8HgkCrrM?9V zaWWmHx&Z*gJ&`01W^Hmtn@N*d$J9*xSAF;q7EhtHHK}cA4mJA%2pPnRK+73z#ZEx1 zU0AZ2x^tTp<$oVXOQ)8NuQ5}(vE1}~^_M3wg%;GH^w~(Wa`<u)ZUxo!9TKH3LIvri zAZkr{3RbCIQ{lmYgujHRZeSD;rQXMfSwPU@2l)k1bsxT}+`AI1+;8GS<6Fs9?zdB_ z+`D_gk$}AQ3y>>6L4BGlxv@lOCTh>?yQs=`lmaQf{~g_2Jib7%+6wZ31HlRjs!3#S z>wsm=15PljBpy)LA<>DG{0Gz+#tD$%KcFtL5N46rskK-ps!<PO3IZA(^%S|D7ZwF` zIyZtxVopU$G>;4|Saq8PH9Lgs=mQ#;juKpLVNt;KJ%Sx^5mudN;gSxV%1*9=KY(PS zG5}c=jn=Rv<vxW`gvK=eTS<q!wx!PEEM!GhZr{G$P>*ObJb8AsdJ-`O3Ok?nYh?0a zKU>Yi9@*ESbw2FHokPv0H&r_BA(pvoD$`J`TE~?IyN~X%svlfLAW$ydH%evk0+5wv z=4C|XWihb`v<<j216b3LPONXKJ+RUsR=iDasBErm-RPvds0z6-R0eaZE$``W!DA)Q zhV`#wir8SFe|vy?H5V7MZUgr7EShgo3uyzQ$(&CVOEijd1^`(44U(Hl+CoO`LDX_a zf%1)vNNxK&`-WBSa}pJY5>=KJRVSo8CZr7SKnlbZOL(#;e@uUx<jrB;7E5fnBx(qw z{;i|R1u9B?^R-2mUtnN2uwVUtw`Q=!M5%WG5=F}WeThau?$RLsdLgP@h^j#aLj0lH z21IqWh#D>w>}DOWw<wUPD7Db0pnM2n$e2P#p*$YVc{Xen>@)daL~8DH)dj#8dho~e zzaZFW14Knw*d;1T^{}z~H#x-bcw0B_W+!G-cueYi;(1L3s#z{TQMfl}Gl6?o&4fFV z%i05buO%6~>?Av&rdo(4C3PVY&$JLrRFt~aLA*OWHv_5<a^qQV3p1?kJeD+JDuN@d zAkQm38=fPF*wgP-hjHW6bk~IVMMWF<wG?(qgt$-bAcXF%53s1WfT}W4Lk;~mWF|B` z<|eL$;9DjtH#17Y1U0J%z}w7}%mFo5Lv7$Op){z18LPbchu$q9QR-2S1`sY7a<Vwh zF=g1utmQ+Tcuy8TB}YzHp5rgkj*RkP{OWYo4Y!&}`8_HwM7bj6DWqJiDWg<5ibGMA zf^up`)YPmiqjq@gdM(naF9}UkGNPtrMeVp&ErGLZl1F3%MrOzu^)n!iOai2svN!dh zkd!D@`K8?-62n0mP&a5$zXUFe!J>NYLX-hawS-N5juPh@xX-9^@9bSxfQMetG#l#3 z^r;S14p?jFfK<b<K>tEJo1V-82b>gg-JaY6oVrmFDTJ0Ygdz<CJn8nQ`VTG#laCju z?YuRwdq5ni-bH^BXmbXzWsOn?;3~kJk^wwb>Rx0c4xWO0HoRc>w6*F^VhQhQU34Gn zf&B=}DO1xz<vhl6X6kav89*twvXo}x&R_(kiycsXbgAV_nL@!Z4#32EmWm8v^%HAX z3o8QvJPm;U>@n0xd9T<oAJZGmk|TVBZPXY%(Uu64V)LY@v77<&sf&zKhuGOb8;|%s z8#dYXen{QTTkPTWrb{Cfd@4*$Na4e3CLuI`*OS5`lxO$E+J9Li%zv2l=A^UT_!%|Q z8fnb(Gb2qvqEwbeqQ)d6jVaDZlXyMSBuD3w#z<?V@l$QA(mmus^#rfu>l!pM<qr@? z_DJi`8h~g)d3A=FV3rD^NgYO<VL=HE8cJ$8Nk-lY7%1tcC;9;kr49J$^a3fiCkR3t zluJsK%7L2>JsqWlgEFA#eS^(a#}qxzzJ}lkA7_^xbjF!LS>sH;Pdd&dC48Knh8R{| z66|rt;;nHelq|O>=_Qn;apt`Vl#n=Dgm^Y=w)@h0b;)O)`ck~^OM9S_WM6tj^&*6B ziKkf4z8Y0I1L$<;b1-lWmDezWBjrp+p)f|Evp+qwt-Z3hMtk!iO+S-L@16{5^!hNu zT5B?1U40YQ?8r|;70-r^HnA&IDO@0Q==j#s`V0`u3~iF(DLcbmYFg(ERJ4M^W@Kar z1I2kZJYZ+IL7me%gEcL^Ze@s;3~QNT!>$f%4r>;8$O2pfKx|96=4iAei9|)IHuh{` zn3phQ*w=^(Elc;I7L^#vBy<eW*;}Ta1n;zE`qO*hCn{p4S(~GQxUtN}D^OG61OO{d zkE~{=shux5%UR}79*Z=|9;IfHG#i_q0GSe{NANV}hz#nEG@ZnxZU-Y&f+e44N>pEV zw^lfFu$z1dJ3YGWJ|ycV4`h2W3mM*_m4mSw26<}qi`Ige3F=p%l51tAs_r3@OGv=u zK;4*3Dj7ugT8oH4_6rcRypMqRg^0)IW5`n7ix@OhnXXnWI|0y5A<!WjG|2*G&`f2z znj)Z^L!fLdVEy<v8mqKjD$~^ffI^3bb=rS<8{CgeMP@Ubvj_+Ma0Pt@Oe#0Xp=ZR) zP@5DbpTjntqRv4)a!tdC^JgalQ=~UdfAIcGRG@-3Z?I3-uB*(RtM49+2!D2x4ayG- zl;(6DKrco_wHxi(4hi%bMp+*K;|<@ZrC$XqXm4luu0b!^kj{<amzUE7U8e0#sHwU{ zOX3X~Onf(#Si!_TR$?X-H-{2;GqDZQ2k)vuAg~NJh#>q_3#D=z_%Tut)mV|V_G6?V z*n&vCQIAY6DFc}#GLA)!wTp_0Mh5lPUvNN}odT7Z;Z26_eFHyL>lG13V}Ix&+3Cna z^&i45YchN(R;=W%L2OyUb~s*97mvhb;NFgM)PLOgET{pX`YQlPR3d6c=L~1DVm+Oh z)N+>A4UzU7ZzSJCho*$!#I9cI)27pK$tQ2+_NBfYylBRILXtss$)wt$9;KS@dNU_l z&4UHF)dsRK@XIxt@%1!d&I&A3?Y{E^*_l$^bY?+cWk_9em}iu}lu{o&N7Nt5NssVF zqtPRB+sE(o-6t6*us_k(5)W)k=@v<sbR@|;KuAIj$_Xrmr~{t}`WT?cNi=cR5GOn& zTNTCC1$8Crs)r>>$FRH%5d>IDP7J@O4Nc0!1eYb~CHlLWC))KfkuWHE?Q<Z|p-4`P zK0XifruE2}i{rdmYsU12x)|S>Ew&Gi@JuD^;JNvt;SS%377opZkH+!G@XqjS#<)Dl zozgLP%dpP5FBk<eao12>tXgr`CA1q`6mLdV`FT(yJk_pJ{L4Nwe9QdVL!?2x_KNT3 zF!m;|{VKddTnei0s1RD+YAEkOhl%@DY#O^^y_o{#S(Mt0{SsE^sae2}pc{(VhNpl| zTHwWo2k|M*a1+?CJJjFK?ST67LGS7KClGJK%mi4j2hvaxlNiFbmP$$dmQ!H~pbxNq zZX6<DlIc8vHD(AdxnOs?jo9rJXrVU*p?ZU^XQI?4pM(~|9=o0@`V`c%MpG8;Adp@g zulq;}ZkJd+2NJh-JBFRhjzG_<W`xWD(%SE-zahd-U*oxypMLhbClGHpi>&WtRF?Ec z`OxAHM`bCt&2s8)^*#vXQ`jU@*wkHS^@|wVEUOuRq_F8FjeRP7Q&mvHQf&^o!&v1< zKWZGoaVEmp3kOz^9RRA#;XF3!h3|14(Goy{aUw7_+9HX7DjPA(l>+K1ab83Pv?Pr7 z4)$leSU9H!e}#*M!wE5fdjS}1n$%y9H!Jx2*KH;-0$jTf5srqv9*Wg6_jWbpd6{Wd zmi#uU4EzQgRy_m4>cweR_=VCaOYx49A?3JqGV&)+^o$)pVvHN#oN5@Cge42Vsf0=D z%8(8-kIVYTlxJj&E}S#VH{W|MzV+SVvQ_Me>YQmf-dL5%&%W|WUAXElpX{M3RzBHk z>iAT`wxL|rj88cjoVvuhY`k*=7|P4WWjTiSNA<^dB8?4HOsl@UJvgeb?Q;sZf_P3q zpJ+5U!0B&6QNdd0IN-M|BXoK85DpS0N{#4`&X?mF=5F(5j>6?xm_T@NL;_7OZnvN} z;gVLxLf}!`ae&2R?YL(lUEU70#dIXnZsLV!$@{Jw!TTTB2mA^=8ddC@KijpS*z1~u zrx{!eVKVHxeXh62HFmV??AgLYoO5FL98~9n{ZNwzgfCB>eXJcEpj{H3Dbb@Uovvx7 z-Hb%Jv&0JrDjT=GaN+4UE>>U^=9rYyQ5j|dj6u{57|T4Pf_)Ib_FDO$O_w{&*UZ?F zNSis}FVNn00`2Ya>rHQs^1g|3;}WOPV;03(gnfm)?EzR{8i6hRZ-lRFwFFTatc!7) zBKLwlZ=k$ZbDbz4s@04g2nrZHD4PN5LrZhhOL3`t4=xq!DyO1Waz|Otf9lw-u%l?A zJ6u>(6g1=77h3n=y>{#3Y<`2{7*_C>&C~hh5^6jxzfWdFgz-9i_7*RmK*7Q;f=6W- z$)1X4puibImAf8JWSikkw#uz=(qAW5Ocj~s;OU#6v)P+e42BlYrF%ZL^f454Xd;i! zl2_i0Vo1xM9a@gWoPud02k#%;GY(9t90DXfayvM|o<bwM1Iq3Z!Q!#f{*JWDA}g>9 z0T>)~sai!L5urtDw0CORJ)F`j{T5g$z~G~<a=jJ4LuczogOOD-%zD!EAs{L&h^gTa zGE%>WM=Xus?;TChItw&298^Yf6+j8mYC&`jhmZljQIK(&>hfMzb`KYim1+0s%GZrY z?t8d&tQ>4by(v*#I95)xqW*>`N5pLdN5MCbQet=W63j;$zX}ASCnm4FjK{0Cc}_jx z(3aW<Rvtzl<R4)jC!myNgD9hZ@%tME3+C#36CwvG>&{+0{p`ip&s{ta-?&Lq45MPN zZ{bkah=mJXyk(2%4)MGh;S!tIj`0(UU2<unGrXX4(W18_ytZ8~ob3u(^>!!+cMjy9 zNk@nu!6A0q9n-?{Td5t>Y4h!(?f+00jn_Mr9hL@@^jQmV6^eHsehkL4j6yp=$OR@- z;@|%ogx5NLLd-mK5OQIcxh`D?pFmK24r)tC%hu=W`|Tlb?&q=c?%#9%YpX0myn6O& zj8GbnO(XJ)1vx)~JdemF-dvawwJ^&JOlQI#D(u$n(=eHYfw>J+)S;K{4RBE1{#GPz zHbS)+;0{@BN0QU~u0g>h<gb{hf(=PeQ21k-wQc4AFY{?gj=_GZ9xp=3OU)2v^zTji z(Z0^98118kB)xsW@$rxi>oKbIia&X+3nB+=?8Dd{vKw*r$YiyoA6JjfkYh)3#^X(a zCMLr3Anle~)yP;{A|#jWM=T5UhZWcySdwOVQ?L?3W-}*EZOFn>s6b<i@SOvJ$OJ=` zBHntd;q!~JT;W>{O`F!J_!U^LpY4F%5CRK^z)bbAKV-wynBLI%sI-^70HiK>87dD9 z<Fp6RlHXwfD|mwCwp^+cr<eS&<HP^>3^OEy<`UL@SZEEu6e0n;<?)A;S2l)AhghI1 zbJuB0sq=sqWvEE}1{-ERhQ|6Nv?ijQpaS|jxk)iY+wj#|Yl_;^@rO&t*O!j33$@vG z>+LoZOEcSgVBbSD-h=f)LD6LbanbD3GwsAzC9&CVmp1h)>YG@Z8ur3alY?k=?UOXB zkk_+e#J0i9P9W|-lGhfX6Nn2CiB(JKw-_cwX~Wzq`Cht6EXzNqY}Dy$P>wYFN_GY? zb5sf*H|gauuS(SBflKjFEqld3nFE)*M@6e=E{MQqJsu=bkK!}%n>53BA@>pmb!t3% zx%W(}MjVpK|9Vw)$q8__j-Qu-=p&;BMtCn;Gb+u4Yxc6}jYU+X?Zw+OFCxDKg2U=6 zAZWb&r*f<r)z<?g*5<Es{$UqGturbO;{w)!O^pMoF7Td)c^ln%*r+sL3O`e@r{Vol z*u11@UM-8VxjSY;^2)!U=U4<Mue=8=afl2xOp5k_vY5<wn(cs^n1}ND6v-5c<&<gm zR4=|O=8=6tH+t|J{;$z@?WR7Ut{R6r_m>z>pnzYY;c;8vf&zCBsIveEw=U%y27{Gi zc#f6FJs<uQeaUNIM{*|`|1?I^m|XHG5-YvvoMrA>wHo6LzbJkV#21Vsq#X5KjnLl9 zq2<L$(DJGWH2>P{sbSvz0Sp{`tHoCVW@x3~!k^*bj}6EFpw8Q=u9qS&n_@Huqf_z^ zxPN`8n!O8;<-+}u&>6u9^RkoDb?8da<swA0I_0FLzXk|!dZQ!Wb5I9@XRHHffY^oK zU_<})kQ{i@-ZBurL043-K&pO6h-gAME0ECs={zu=at5Q<I0Jv!H(@fAZS9}Cw6*7W zPd8r{)lrpt9AWGMR*4P?ZUTB?4`BPSvGzKcOPcBG-I+z2AF(Bp*2*l2n}{dw)^hNV z5xteDWG42ZusAXbYM7O8B8i5q$tCo}S{e5!`$V(yq89i?pST)QQe4uvs!#SvkHD)q z=$%U;uFxa)t7j&h&_-!wY^&O)fpoVKAUsQ;X2M{+ab{&N3w^4C{#$%m=u0~1MCaeH z`ZH&LuIcf%lQiyh4W~N}OAxpd7=XE08=eC0IxTY){9tvuW2Ol<6hrpP>`d#kP&@pv zO{T(bef7BXINHpXMyK1d`*=BMZPlFBUYN$@;&r#Z5~IF{CtW|EfAhv3$+<Yfdk*{+ z!Mn#jccK~T3#nQ?{ZCopM5k-+!I|q=5RE<ORwPydd0=NErX%ikWv^$}+9j_*qP0-? z5-ilFk=i<(H$MJ|rqeel^1ctN{dWLGTdA9oJJ@jRgRDJQCK|t9SHbfVR|E5YXJdtR z-9YRPbEDN`8Jz6n{BX(SJ%^5Br}QoBb@e8f`U(S@#nB=6?cgkShCz5I$$2Eq1n^cM z<htl#41{3AcMn*cN9p>0jqKIge^-w`8tT8NKW3AGu0%-(C6?9Kejo!h@11mY$4If$ z&IIvx9`zdH%vLx+Z(dVy6ikjm=eS09H@X4iet)aeS<+EBJImpRN%BaW<ZyrCFsbHx z0Ccy~0Nr*}zR4jQ+=F>{E7>>W9I}sZ2234`>m%?~LoVVXMxy58^D?kng^L5hI*W_P zP`X3Xt3pz%nj|Fs6~f29k^x_~vZl0c;tx|4%xJ<(7*u{po5np6Vy4_z8scAuro;=1 zP09d5b5+MBM@k;1m9=l9FL4%S$JP+4-w1Lxx#SP*W_IMS5efK``@$o~A`-53Sj-e| zzQ@F=DgCjAxC?8D!CXROsTPmAde4!!E?~a^e=^PLl02>@@hPumWr9FD#BRoLHOHjM zD*%|x6WZ~NORSE7D8~N%uxHKq#5D!S(Xh}%hhrGkK3*lS92PDLlEDqSn~4Qht~0qZ zSA7r&HcY)Ae6<#W;45_?XlUCnS~K2ql&;8^9u2sS!}UMiHCIvig!ju<NZX}j#%R_t zQ4PrfLll`N!S}C_KAL0}7{tmh*w|C!O=KKVOTV1x+iH1C;~Od+=utmP&&p2isaGmv zDWi1KUiBOZ5D#D%I#DAuO^N0y4oN*UNePH@D4O7_v?%J(?|2u3w*)Nd^vv%=eGcnK zj3G2?m476bH_&0qz}!l{?EIr#0^mU1&hX|?xS8RNp>PYs4}`+443{7*nlck7N^q** z2db@2es%6HSvBYaBO1D3nsu%g9RmrK+d-ec==1TPBW30L38Upy8Pe*OWQWY{$g55d z6}y$;B!vChm%=h6!k6Z}T&lj@jsrq^kWnv`9oJv%As&eDO<#_LAEL=^5Z|Jatb594 zP?h_r=%Tomjze!giX}cCREfckDvZp}{))Y)J1#H;{$IAA={^d%yZUaj(~%LM03#>f zm1~6A>TDcj2O9$SqE9QmwaVWB`$~<Y<UUjb&ET()Ch^`(l^~SbO5F|Ng5SzIa7fKS z!#M#@cwm$cz*Ow;rfKT6Dj9auRAx9#KLqFv%W2&|J`Y`XzEjjG;YEED9{4moP^$xG z>SmrPzlBf-qy<3ABFfo;@S$eE*-mR;mMVR0=5yk)&Y{ACFjB3mCzq^3%L}w1n3fSW zEz6oaqzfK=8sKt3E<h6Z?+{7}|Myv2OMvn{kSXF-h$Tv|eMnI7KwVHs+!G-b60QUa zr!8Lq^PPJ=OYfs_sw_i8S}RH1>%l)rwRW5(8Ttl#;pAe=$%mZ=c7${eHP(Ek!UpLL zf3W+YKYKHJt>Ha)Lo@c4c#1TqVyscrf^QstGpao`6ESqxR~6HQFix-K2m2@LsZ%lf zs$z&E!b(Uk!PNtFPIPxXvPDZvem8NA@ybTKSajE6?v`b9Ws??1<!a5{-?z_ow>-wN z{Q|y`1u~vDvfwif02m*55gJn8CUh{!I$A@*&i@>R_)_fz*1)2*5vW<v(uW=5HUL(Z zyZ1bdFLOpKFYsQ+3%mttZq>7l8{bqmdPSnTn=>Szo~*BOABIY}9>)Mn!8rBr51{_% zvjQ$Xrf{{%9ap)NN&V4c2%wv))9{H)zt0ge`2oHch^M?$pnfiO*HpRpX>D_DmAejm z?Ha9Zt|5v5ushvhD>xS7(F-fsAO2{fKYVTv=Mpg6pWR=!*gcNKoQ5WHdHeaZ&ykqk zu%gG<aXPs=;|~~!z0B0v9byv@tBuRhi`Tr0UW_HgqcSS;GotcgZiP*XUR8<kef_CU zBk%Kn$ikL`kpL)9eZ(k6*rT%w5#ghA$HtDM^Cg5uLI|}|&f;er5DDK45Qol>|7OuC zC3dD$M&~J{Gj+FJSBdKv!YScl#3{B-Ao?ESq+c*+1n+y2D0;yPC=^#0qFhFBD@M7~ zWOLDo6sJ#O*ajQ^TZ+b_K2R?r_1L`}z3l2j_~lvT9Y1RUPJtG=<`nyIA~b7(Yu3Vr z^XJ|udQ_KhF}zE-;3>#eJjYe+0~8#hEFS7Qd$Go2k8{d{3xN~<B#@`j)d{z^*fs06 z;<>Y3i|F{@dj<0A*RU{;Llp~^#d!8vyi(#%XXE*Maf-n7m4a*2)|0B?NjQqUvO7D# z5Ay6)1CekY{dUP3VLfFJMt?0%Sg=08XvSI&8cGaqs%hMZDHZ<mLP#ovFrttRzvtO0 zO%CF4%mT@Gk`lQ?a4ciifCms0W~!GKOfRj)R>;>{v=jJ?YVaS?PU;diQOtY_{O!Iv z<j@=UGw#8hM@6TGsUXZ7fC((C!=oKPhDyL5?SyJS8efwY=}XfH{S||`2J&5L8OC@= zK$>A7lGH9jYRgGUrR|CuYU6Lwq~69k0qgh{H3ZVYpPffj)#Q?T6rf8}8)-q!wjIL7 zbm~GD^Aup)eNExTKw}uKHlK<YB7C)66mx!2X%_Y-^#PU?_7?O6qz|m3Fu#&NFmTwf z2Js3)mEBdQpxc|NGg;ClD9K9DE)qtL!W)jjjdE02`QvM$Fa#i-CI|)AOC}GIA@2IC zd^N14Qde_ngLjod0?akUE_Z?5PQA#W?_$Nbz%`obc#hp>x<2CvubUwXN!ss#s@>Nd zMntH|Q;2F0gobpBX3dSRpoLU4tKAsPHaD96nj0PXadT&W95z$uv(WxRzcA_t{5Tv& z$`AN)SkthIE$8s#uo?+Uz>jqx!dc$F5AIghqo3>LZPe3xdAkkK9A@U9>|r*qi`<5H z*Lo^AEK1$$tK5$zRB)V>x}U0YZ^Yb$f%;sP`vrVqyl$#;Z^jqKY(<rOE50yvx5FwH zUl_`}aAyi%hpl<7Z2bB#D$ad|Lb}#&t1$V3T~4|!G#lqN)ML&kl&4KESzW(_;rnMR z!TJe^#tNVnzRTqu9R^wy9-NXVD!DdLgF*qN`iBC|3Xj;^V24$r6>vlygiO<6SsI5& zo%?CWsEz`0Ae0(r>NK{hXSJpok`rzk`+v#_FC@WW(ecsam~Hz?hUv`EuS16K@H~;t zfudI^prDH_`YjjUb!w*k9<Jnhgj$RM{GSBCjYHOP1!X>Zt7EIdD;h5Or{@OjV~m1@ zvuAk=#lskV6p2m=VmR=5yf@}bZxTGkV#-?wTX!gB3e=V8_V&AOW^G{0Xo#z>zBuz` zZhRVN=!gX0sevtd6l8Goy+yVV1mT^w#-TQd%L4JiMWoEJpWx0F4zvNtU}JaozZdn3 z@zH$2yLs5l+-><%EjN-cYxr1Qwk$N~&ky;zZZ#h!aoF|8en=^IRp7X>Gy@A1ZO?IQ zG*B*d1x_S-dm?YO%7aux@$rCzkO}O;(4m&CTy(GN1XWON`4>>}2}*5%kO?G5a;D=o z?4zixu2~{(p9j^Q;CxOeca}$fhiO7MmMC62Wv}>eM4ADj52#3Qmw<}*p4ND|8Q2IO ztSOJ+B&*$Nwg9m4BAc&CHeYR*#v14y0wrMqrGwiM)Jq}wtpVx7n(yji^WVmR(-!R% zIl%T&laR$C($`xXZAW_J{n;5@Dt3aM#nR5fhF!bs?2RA;Qm=R`AV}LDWhLeFzqmUE zHb)OS(ipQ11sZ`p#+0I&&2sJ(R10tu&7;yc@!s(f7-l+p&M><j=Pko-FWJ%xErMS9 z?>aU#zDhSqdyUGFBb*vpl+mt49sfNb@?r6UWsEpU{hSd&_4IaL`e>E-63X{4L9uvl zfG!!Zx_u(NF#(n2v?>z>_;gke<-dy?&t|IMUP+2>;C-DIs33~2zVpn~aywo4^a|6p zqg&z=9&JEe<E^2BTNCg+VnLg~QV*q=Kx;Q5TH689{F5M>MnoBA>iQ0lBToW(0pm~w zSeNlvlN;m1!mOa^f)^b&17chyAT&#*0@EJ}t!o?4X~<p%#iXUeA;+_k4BEB4UWm)I z>Qc-{L>mZ4Yl=?;QqcDh@MFc6VN1QnQySD#$WR-}03!M3E{){h4iamM^Y(Yn9m#Rq zK5Kk)WjcC`p7rKp0~v;WO*r;{J^<_w2zKk-CKdT;xb>}UtR^joe6`l<LCRNJ@Q?C| zlT7X9Y&K-7*#xg)Sl4QuH9AsPALXcj3En)2r%I>cIGAHOZ8`4)T%XOEj$@W|L;@J^ z=;}=xmbBe<R3t>IHhxboIe`+jddWy$`89{oGQ7N+<j=lbFYtKehp1>@l4S&+Ttam% zqGE{HvJkJ(QL%WLp4tvscP6j=Jz^cBY;Akm+J(5S#pB&NR~)1;bLoZCLVLM&6UvC^ zS{6OI2E!;!>xq##7O7o*F#aS35x$`aCU^(qze&FMK(@BQKO4brzSFdIREoEUKRZVj za-iTW*{oV-@~hoP{mYJ`{x5?d%=-bA5PAUigO{BStKH)4s^#!LN~P(Lu!g_y&aiH^ z?|wA=@6daR*LOX8=oOo7Ja*?ghn;JU`zRI^Sp4XhjiHDu0-)|%J06WRKwDTLnc;;L zvye+r2yleW(d<L{MKt`&zj>~>bhY}B_(j6rNQ^&TeZ?kc&>^}hvX&8jDX%Vnh}$5V zltp9y!7zHT4t&AOt-ef~_OnQPKGLwgvOOBr0Hr289)!zFua{QENI%lD-{tM0?(7H0 zjzgrswyA6kjqsAOI{M~8NSQlyBzw5`T=nwvfNCy^yo+L8CH;xwydD27`jW&hgW>5E z^%cS(36>f!;<=6u+j)oPWg2Nqy#x^iwO%T*jwoq0N(zsnoLFM>x@a3J!^5O2F+_t6 z&w=mZ7M2{Vyu34tj%aPyvIt|W3S;o{fG;jkC7e!u)#fxOg;;a_CU)kas(pavizBrM zUy;6p$Zrv8fpMFMm={A}3mmZB4w$|uu@+%;c7ub9s$yR2I7E+9aCU?H8Z1@=-bic( zt=hfSHuN1UQTCL%R-!n#+7L>V8y4qUiQ?j_1c{C3hB3T|mwHAH1;b;7*-3VZ9l6>U zyrB4Nfs`b7oA4WKxbhBQQ=Q&m#3Sz3ULI?I?B%he7k0j1VY3rw4AP?NOf&@#i}KK| z!uqo8V;8Nn)#n)BX#}8VPoDC{BMQy1tHlChp7`VA=JvCE+E^~TrYIVq=uWZN3qtW+ zS3!q;D*G>-&_GOmSphb$Eh<wYKpLJTs27#mrVG^-({bS8R`h0(!hSdaM&W_h*yNSG zso>9!!MKW~!i*o-om0R;BTh#y<1opn>F9A@oLsf3-l<}hnK3U~D1lR_g0@WqRB{Nv zLHuuHI03(JoF220I`hF^vOn#Z`CRqhbq;Z@n8?*VR_5fFBPw=+AQYkg@SCvnz&h|7 z+XN_@NgGnQJ02{*Z7LJLc>nWuwBI4eKbb!34eS&>Fyu`=Zm?jh1}2H&OF_}0%1{$J zbI)(>w&9_i9;niQFW$!<3+GlXXs?_<SnWmsUTlC%ul_-M)uX-kX}4l!FR;B(cr7%Z z1Yar<Af*lsXt&qB*ODdmPJ8|4Qmeg=pvpEa>1Z0+P16qM5E96S^C^xkVwZBbI<{2W zWG8uT0FYuhqH82T2h@mkR>N1=A@2dT9MS0IXnLIHN5kO=zEf-%5}@||S<E3aaft&S zs6awx3wWu{U~@pN0eD;qni`K`2s1el7>5KHm-q$V=?eAG7H{&Y>T8^OXK=3=xJ37( za7T0>13j<RN$dX_<Fw3OuP%|_!|DS0#r_w+@c-{aFWBq!0>|cra#G}?4CjKPDR5dF z?r2GENd)KkF8CQ?gEs{ws#or1+qYHhLdR4oD8&)aGk}Bw<WEajbUcgJ2Jnupfh9j+ zn-4oW3|SE#<KY_DF56y-w<ac+tiygS(AqWmw|@h%?ddCD0Q&2;>c3iiH(TKd#Pz`6 zS@;`lrMvM<&Wl?Nthv#Tp%@zhjEy%JsJmOS$E9$}V#Kut>LBzg648$lV+#}>w9*mX z7%`+kz0L=CndQG|^2T!t)Ha+nOGFbRdfOr%hXAq&OfK1ncq|0vAj(<$x?pZ(ty2ce z@}}g^0JA6XEY4F@C0T6HhYs*mS6?|BOw#lCi2Joh$BT?%kT_FsMo=AtRSYz&(8&b0 z9}l#~C;zqwD!<16H8=t$9>-5aB(3yOvFIazhgV|!Ex_L+_}hs;(S3pd&WLJP85_G! zPfce*q}Zu4H~rB{mANS<ELA3_wN|Q3PM_WOeS5=dw1SO5<j7ot$hcRRbmQ57t;jp| z8lW3z*r3wwE)RhwSfJ7a?;+?#I9}lviu)R^mT=*_%FlP}BAAx^zz%&`<f|nSM#E*O zT041!YPR7Uldl@t0<n?fqT#G&<ojPzPBmlQ=}pW_F5y<T;bZ*AI>)la=D%OJJFl%0 z{MURrwxT^`lRgZ7`6C{AXpfGsOR8e3(y3?H^JZ_YhyDR+c-y9)MvQ37+G1E4^(Ty^ zu&QBc3c8u1`-gofg&v~DZKwEXOa7Z2wL3>mVP{uQ5$tS$sqKr<Bxj*U&Z*cdXdmYc zd~P%AkCM2{#nP;g$+kk6n?i)+5!SuF!x{MJ8|*Xi=N8~e6)dv1IxLb3Q()r=FTBFn z;wDO9SuKvXW4?e?@n`eD@Lj4-2Z<^T|7l$ANSPqefez(H`ve=FUPvk9Bz8ybFwHCf z&16}VT7utT!*T+FyD~uTgGyZYg+sS$o7lhUEwR;I;44J~ra_I15x??9ChMpI<aNrL zjIyY!+q#$%xK3@xZ?K_<lw~dbMcz^e*U2Ba#Gi)v&S$r-IkRxMGg}UKxSl1<ghE*L z<Mamp?s-<^nu=RPcq)tsIP@XiVr%IVy+u{g=@F)_%G&%k=-wxGB>v&)hWAQa%w$?( zCLsG~%Y(I1HZDD-G6xRDwV3&!jAF){iq-DDa1Ie@ZHLKA4MLN^cNnN$CwpVot&>-C zLmi!W9IxV8_9{wWBXX$v6{&g$>YR-Bf-FB=IgYT&8Zs{uHV`&Zad4}hXq0-jf9;sk zrRiyi=^Fzw<0|(#WZtzl(g^HKlS@LNg*?OEKc0a(&!CBiam3}D2X(to1$|XfhUKTR z*0Ho4^dU69;g*(W^O4+i+);f4PELcW=|Jcf<RnuYYZ}N>8qhZoF{an?E*n74I7ok4 zJhMvi_18G?Xb%?}>b>7$7|ADZI0pQT+s3${%I88TsCGTC{ZC_RE|?Uu{aaatE{*Hx zv~mR0Htcw<@~YI|kKzF$7!p;f-vUZnyQjI1WLb22|Ap80Cdpk*Q;b2Ejvg}zk2mVu zo4I%~Uf0!ouDM0*PJb)rru)@r$B~3*F4aZAfYlfo@yY)7_Qq)UMBnQOJn<(Xx+jRf zR$4*c{0zu(%$zUCQ2#g3R*DSoA$8{`JcxUSz=ilyoP?`qSCb`@V{j-(9XV6KO8dCX zH?NE~53cy687A#3j=P{t^d)MI(|gPKJm`w=c^MyZawG7(>v3%%My;F0q;jq5iu6%y zD#A;x0oJg1XtQ+uB8kVkNbc7`)`j$B6Di52?6ieF1yK64sCkVe64hYjwuM7uzlPL# zSQ>@t$x@N5c0v5BQ*Qa5?}gF^Qfq;7pe?>yZxm=AuJtGQ+M(~Ps|D!2*1bQoc189$ zZYGV0m_=6yvMa=HV=R{82hT-U)GMmkf7o<lK%rkjfa1ROJXmoM+@`T831F;9KAsf| zHe3Ty+0iak!~|6eQ>LySe?lJZBNx_I+t{nz|HXVxC(=)?#1<KQ$h@b)6N%Y|7#`P9 z9%iGxjOBf}wy|^p(cB|F3!lUdUtu;O+~>tO#A=OP%J=B#4m+N|OCsPj+u1btqw%CK z9L-klmSz&ob3g-K$Sl53=j*Z!iyQQSZ5RN8ybQ>p8b1#>;eq`1S>Lx;K80GS$J1pq z2hAPJ8fq09Io<0HqqT{&9zPF-jMB80EsT6=I>uUZOdGH+3MWWl-y!TNR=t*kBiL3z zW!9=5)!$gBz&={Oz2TYbSkV2<`~m2u#mj3DXLnWFwRjt>#6(oFi==-XDLy*~YC>^k zM@I*x0h(axx~Yr0b39iA&D6fAp~QPP@p6&Ts@{vhdduAe>r8dDjVE2re86v0G-F#- zIThXb&Cmy`y~Eg1Pb!<v#R$6;48M>@p1yMl+XN<i)T1zX2|zU&o~44#^cu6koxy)Y z9<|q@BF=I1gBTjYhP{wqjg4#E|J5_7wsZp3_=g2IkHLQMk1{_Fu@??K?}{^rU%r$8 zmd;1pHj5SPcf0If3l+sG5jNF|?~^94+=~p{<*X7R_5R)L%55rs1G};v`xRn2Rz_j$ z23nVN=*(Nmkq=-c-CzO}p-Pb#jm`zBdPcsz;ruwv49_D2&eQ0!H9ReayS_4}jo>aT z<xRBp5kuPg0=unSbo2qCum#4%o8r_xxG;fsmA0P1?BP4cHdG#4ZRtrWQ`SWDZX%;Y zJ3~Epo`jEs-kgMgkOA6r`wkGKcWX544Md}JsyopatqydkoqeeV>{OF+Cr_%EgwTdw ztk(!cQD6jQ^?&mU;i*R}A}Q}s6-csbQ#RCcgH=P`3P?w6y$K31IP{VD^^mf`hR5fy zGS;H2L)+I<V%_{!h~^eE5J#FX3K9AzELl4dx*kzNsC0=P{%}HZ^N57Pz3#8V2^Gj) zfOH65gkl}8|7|V_Z7B>RRO@8WsFbjH``8ypVzb^35zA*Dl0XXkVNg8{6!hs2#{ufD zCxu6Ss$yl!Xo*#kARbs+!*5H^iacOal_&6YFC4!+fT)&ESq~JD)v)M?sF;ZB73i(f zeUgE|sl=r~LfaV3#)kSDqchlWp<M}_6JvmK{KX@6de{K8+914Mal1R#>*A;Edc6&- zcD<f`;$-!b0kh<6t6nZ(QXl{KB=wS%?LcAGD^A_c`&d@JE(HRoUdce>)T@uwYwB#P zaelmBI4f?3%L;ifbIz9U+STjVqZSWwA&m*)KRElxn%PQM-)`nfsPA1Iae^QE&VW`W z=_N^mZzf2ycdV1~ZJXobI93iryjNI)H_BQ`$bPUGr$}MIiPbSnu_EBmZS1PQ#atlz zb&$pln=JFS*>U<m?M9FkIo}&6WWo!Ky}6T${pZ&q%}!%x!x+q&vbgeB(9>$f?Ojyc zjbIl{*sY^K-yJyl7!DQ+Y20}mzMGu#hq+smS4N_zbU@OpVjl=nYyOJuXu&pYN9!Tv zD^m6#?l#2zAM)NkFskb6|DHgA0Kr5Jii$dF5Ku&JDhg;I3<M=G5`v)68b~nEKroq6 zC}4vjN;0OU3e~o@g=$-R(bB5z5O2}Yh>A*;DizdJsqPr6Q7J}=<oEgRbI!~Jp-+F$ z`@Vm@v}Vq}-_~Ax?X}m1E!O*tB%ed*4G$qwJ?KwxL$mxrQ;8U`bAKLx<6%opK~6b1 zY#1$1vezixnwFK7E^seUOK~gcztwtbv{o0!_zUKjmW7b68%hxi$Cv*1Wy_08Z<S!4 zQz11J7t`-LUxm*XU8fO@hEp6gUn2AKfXJ?fyc}tWyEi_35nWfdC{#4wX;*^h<;6uM zB_l@+Ei5S^<nv8@1>e@YCi!OZyO00$uQ%a6%>U6oBL7?8)`frl-}#9Azw>P^!)HBw z{pf3yFYEiO{96f*yaaYhKG&V09K%`nV&XF-`Fd)SY*^3tUE*G_cM$CAOHK3@CcD2~ zeK8l<G9f{Z#JitdV4GL*-5GPHb#1t)Y(+m`^ff$cCDvtciK#R3imeVQd$M&Z<vE^` zGb((0cFM7XWp<oN^>E992I}oz*W0l4gASsM18T=mhj9B0rr%|C_7Nz<6;d7MEhY)3 zow8gM&w`I@%_N$Xzh<j(lE6ei0GfH^er+=3uprs6O0xBCQ-Gl(N59*>$z*+-6AQ@( zTtaIa%`n2e)75@YCELuLd5$}0M;)oJb!pLNZct-ri8q+bX)lH;N6{k{8gjjm{|FFX z0>fnviI8yS&+}~$&F}d||6Q334!hkW85tWiqO8N_r*5DN_=NzWHJWSh<V~^>xjruO z<D@u&JQ4R>&kOJE>#V_XbRetA*SB6m4vnU81!L<w5qctWhhWC!*@(4Dy+cr9CfEqa zPq1Lb47U;MYz{$*@e@%z7r=1sQBOqZQ&)e%t80yVWAfpSI(Db$O1aM!94oVOoIK`K zg{(7SbN}zT*nNCDH;KKWL^C@wS2J-+-Zh?GolbO#YscUXy5Lb$P$qV*W-b@C0SVP+ zPW+)=FHuvcd?CWB9dXOxzr|N`Wf$J20zIN!27ZnmXIB$wXkIsuMey|69a<x<FWOc; zuN_qYOCJ52z2HJ+C6uEtC)6z`w5%m8nz+FPK-!{?Lg@92WomY`N<$w*E&@(-1q&|d zc$5Bd*kw6%21E&2f)VQsSv*zyC=Iwe?>jTi@3Z3M>d(&PVDDkluTJu<>mD1~R(cg1 z(efKLqCd@LL>`$Z{XvIvvV%B%w>Jo<+u!9RvA5r^9%4Fohy-0P67)wCJmL}q5q7>a zZcU)s&Y>Dn{~rLs4b1^H=-P2uFHAO<<fH#BB`%Ap*pAoRM1RBE|K|A&CeixD9nHrH zGv&`Rusl>&upm@g#=2CFdqR*OK6_;Srk=2jBB@ntVT*tp)S7vc!Vf6NX8nP$7S*qL z0VcTR33&9QorMv!=`3Yk4xbvy9~g;NuE9KgqFC&xQnZ`3%%|2eeGALb=O7b9bH2hX zpZW4na45Pl?$|<HZYy#rz>gsd8k#R+6WfK5q@d`(Q|V+Lvgr$otaQ46L1|f8cv(oC zOcA%<=6~ionng<tt4y!LQ~G267ah+{PFDrbP0rBIb;VoWo}|8P=o5f;#lTDT<YX^0 z(%6w+Jvrs5ZDyU#ICiHZlTytc)ESwSVs5j)$>tV*Ev_lxgQ7jaAh)O++MbRM>Z2~M zMt2f)E%ix!3q}5p0;Ldg<{ocK(RJF~rnx`#srI6M{(RLu_K~wO`}kP9AAbHtq*ZT( zd>|S$B|KQycy=?-t&M>_y{p5rF~n_ix7`TQu~cqKxfQjHie-GFF;Gv&?KmY6-mR=J zSQpsY7}(XNHvfrjBEzFWmAaf#=m-U?!;dxwqEz`Pnkj`!Ihz!{&LZ)h+iKoo#VW_u z({JQ9Gz5K`u41(Ds@tF}b!6dAaq1!GK75cilyM#MIOfd*2^qidWc&yWq>Hl^I&!NX z9;<o_CFq!RJkL~qK3_9G25Hd5qi#uQi^iI`HD2HVILj%p*eOtH3xo@KI7Ns~9r_2b z$z`)Tpked&p<yrAu!G1A;BHB*`bKjrPkfN#1EU(P6mb?(j287c&?9k3PYFwQGjBYS z0Pz=69V4id+LHMSSZ`<^GuwsuxX!rlJOj!v8c;ZN{vvVc1izx=Y}|ly8>_fp#0?!f zS4Y8s!nsbq!NiR(|CZ=SR5hgdQRZJ-bgRD*+JnurG*p0FY7);KP=2n6Q%h4A!6|R2 z?ViW0NB{1D=9qF!g8r3^&t==~RGXb@w)ARe;eA%9>ICU+%N}=c7&|Q|fC3_YEhyi^ z=)`yD)iJl7eYY!_eRs-G_FZ<WS9k^V!8TnlBH5{u(NC#tO9}Og?xc0Il7~{=ar^&p ziqGaTH%~`YqF1z4sgM~=daL6{BUTszrf9~SBwuNhjjBa(E19(!6KExIv=T9W+fiMf z9z#QqQ=w2-t|dc$JB#)3r1YFQ?MDx%EWM?m1Ra-hv}cO^#kjR)at969bldegex4Ek zMV^uWMV?VM59?)FCVzK1vbBuJJ!17bmo;2YFek1_j=U(F_lUeX$9c;s&2Q%kyxSYI zh9#LFF-X(QA0jI25p6c<!`offv86NDZ0CC0k!KHPE6k9U>MRt__uN%lwU@d48}Hk- zRfwo`m|L*mNq#5ftk^w7c@hmeqRcm#VoWeOLKN#2<rZF~!W-458*wle;pDEYAGr-@ z7C!UFA)W8)6H#?W92Y~Bb@=11#mW4}?`dVMmA|~8BqUf5M$<`LvptzN$Y4(RkjB5g z9q^B|)~;^*#V=~ZZIRU}mCtdE<QJc`Pjf5dI*;oDQF&XkFWi01S+{hFoQ2}c;M$FC z9bR7|FPiyu9#xaq%pWdhdtBuUy%0HdWPQi0Ezial;jHE}Sp*&0_ooJY=TW^RIKB@? zF>^UYJet<-N$7kG4O+ctbuv0u#Q@=CjxqE8EH#YMzhZTkeDszF28Xh9vO=fWBAQ=c zxL0(Piag>J!5P<>u807$PqX@u$xgu$7`}~ygS4;r3>7zUl_O~|46z0T0mTn^F3TRF z)Lem%urv*!-zMH}mDJII6i8uPh7a>FTPu>6(zUOU0}+v|RP+8|u&3jd4<Hi%T#yM6 zX}2y{*VfBVUEtuDZvEKnMBb;!l|<UH^vE~g0=LY;l4X8-^@I#GitI-}3<%ke{%R<% ze|69w$@5p^O@OzGSF3|V+}}ZNzsb99!f;i|AZ%a+IozSYb&-aCTP7GonxWb04r!@W z?jRqKny-&Kb;MiF;(s&gRMD|ctAPEB8DNf&9oJJ9C!Eh%xiiWj;{u$sI|K}@0*653 z*>yp<tb7rU-&Z&|<nnla3$&=)6)jy*wnF5NQ+R$6_`Jv;DlYPWt7wJ4xS-rWzo=-b zzq}|!S)B=e`8^8uW!Y`YL^u5eemz{~B>?{LkTB~gD<WT1uFUj>Q^u_H-_kX*(qBC` zv#KLB*BTgkMfg-}$7ad)b76RH2q3s}1b3@hk*S#}WJ;;c9%-^ZJJK=c^U%Nxk0gbt zF*_amNUK1;@35>7{#y`|J^`w64Y;GKBm5v%0p?r}>|1(I{U2YV;jch5(O*(f9&&Il z@yFi3Yqmr2%f(yd6Gvv6C5dmBwk8_=b6(<hVQ0TXth2MBgCfBUS$quk!}OzA&y6}W zQaS32fm}=Boi`8=uEH=;hglCO2seacHCV9?2SH#%hMAk!%FNAc1w|CsZVVow=@;pe znee5cyzNj{PP+Cda*5PP1J8pp$~YI3=HVK$mB7sx3KuHPX%pOXHLb?#vg&N<m8(;I zp>>glj{MY?H6BQ|oYnmJv^a*TqLacf7ayeOUj`+hjNy!7wHwFADmM{TU8M*p_{wK9 z&5wpzQNmu)LH}Ut4&tB4tG)Pr)fWf&3J&C!j~%RqS&RP_%nMiN<&3{*xPZCXzhqJQ zl7i5JV&AnD<F<>k439T+kovl#Y2mn}?qwIvEZ!muo9Oox-=`Pew>}iJ7LoGg%wWXV z5lkhJLg0ZN6mIOMDv~P4DS!+}{q@$*qS?egfrRsqtgmT6k|jz-!59N@vohPd208Ee zTx~@bnZ-`2%c}dMS5}SL3PcFttMirG5$gQkF)GWf+@7v`0mD7!znSmC@gXJk$AM0F zy^75NUomN^&jftw{CCn!YsoQYKyqs7P3y6hES`^<TF7&&$NSfY5I2Ow;a$qRya3Ey zI<hiR#2b8(=|dvdO$5>#Q+0vEd$zf;*!s*&cXCzOT#~Da!9X*WiCQ}QT2Zg7b6skQ z>)Lvky>d6q72n<F6l!v7QG}Jw`6EwsW*!rXZ(pu%dV%e=B|Rh$)?FUy;^f}CUb$bR zS9ALTlve$7qL!+rVyBk;3br9L$v7Eee#B`1LFZHlT=%t(;iOrT!*t!(*1rtZv4=bR zi;=$jxJzx`%^!0vLP<cu;L4Rau01W1=Q^&vhs?FXjL2V1&p{Y0?^T;Ok?*et;<9#H z_#rEZfNV@#WFKctUUH=GTIyOfBSnNr^~u~M2v&ZZUDka~SH+=gb99VkT^^#ok@XMk z2G&rMYp_1X%t0bMx+$)5C8UN~GiDzbh4LnM7VW&8Y@R*kNJq5)dy^z8^(^Z)=lYnh zPSNp^Zab+!f_mL{*^hRyRQjq`a}Nz9R<<sggNtoH=7msSa~t(0CTi6a!|Ne|*!^v$ znO?f0HEC-rf!VrM|MY}={#9&+dzK08t|8U|JMC9WBH7j$IN(dHv_h3~)>=!*xhA2e z4r=m%uEpQ%pYlaVbQ3k2Kiw;=>_GhW2x6FXrp8Do2M3)-pU|sutyTofN^e5KsXV4) zWAT*kKF7`DFDqD7&Y7zNc=>{&WwJU-0hHOT&(f*AElcjCgn_UYGYZA+G3b>_HYAc> z-B$|{2_{$f)j}BLj^V4+De`W!c|d!I5xFZkj_ism*4(Gak&2AeSB%>a-1tJ>%nwj` za7H`(8;22$^WtwKzG1yVN~Xggn(6Uu1OhHoxcz-^0Y>iSDwedkt7Fr&jZMoIuFLp< z>3ogzLbtXz%=3JK-R(<VQ7`CS(>0Wm6FNI5)U&0xNu#-zli8?g(M*-Q_y;_#e2Fz& zZ;^_-5-rTojp`ek7qDP)DP23~qWu!>eP2Ns{B=`NVQ%?N6H1pu5rx8KOPz@i^Qf|{ zXn{x{ZeHP{q5kpZ<>4i|yN=i6iq@lY`_{;tGlS+G<QHluW@6+9v>Y^h2=X$yJTL9f zAZHMCe+0bzK7~#olu2li4V^@22q9=)(lQ8*B7`LzLZ=WKODM~R`VpE)D946QCp48% z&{sP%v;Vg4j3b(1n3N;y8MHj3XDPHEz^vRJyrF?~7O3M~eg_O46~1V|&=JlbzrL=B z{TVu7=*X~>w<mcAEpjfMgZcLE1lKuIZ`xnqqYW3WTaVKXro8Y-$E@pW!w0sB!SLBH zzWI%~m+_X==6wNHYp?kvhjngnFB`(4!KhXy;Zn3V)0c(t@b&|dPin_z{^A#$e{B|U zBiqeq=Rz;cgxGt|UajqCjAFXf?@~;koOz_<aa+kMgzdt;#>~x3xg|NmU&x{`h5CVv zpEExvn;U49++Mm?5fW%Ajkt&mDMA;Mu|g!Lle|F5yA?2*d_uUVMUpdFlysSs;@4(0 z%RyA;5&ksa%<R+moA_R{y&q$9@VID3Hp`x>L!oo5CGra}FD8M+lOsFU{Np<m>ix2f zubX&8w=?!7>)`Q4-P3i}hu$*SL#sD}d+Y*v&+P^}*pBfS%jCXDcj>O?E|Nua!g&AZ zUQ4@VI0=W9V7aMtu1?rg^Qb+>tbUO_h5Y*@fK1G4@kmeTJ99?SO^eDyMP*|DmQUq# zM$rN>Rluy4In0mGvxyf$k)<_g?pVr(fz)l-rt7d7NsIOZ?Y=QJ0Tnt?WkSPhbXb1n zf);O}o{5QcA&$OMBry+ayJN+m-E`+m4xC}End=ve@TM9_+x=#p4N;@VwMV<4P%9&) z5yS-$AJV;kVO=`*yZ!_ud2bPmX&F@nN6MrT@KrlM<+q`^eIo51>n#HQ2wbPoud?Xd zRT7-GSNi)8Xbig2YkZLV2b~)!$6EJyz_W#n#j}7ba~}>Bp;+^6{Km@yE;rYXP|BEY z%kQ7!3m34Y)eM+1#n@5QRrj{Gn7Qg2es;+eFLA$A9M&+d|9bWaNwp-UCFZ|{NG#IH zR_O{RY2@=<MF1QzU=q7MUDZ<k-naPOQT6;YUx-8(B+Z~L<|sCc4={G+eDX?7TthY! z=kd8DQ!66Z@-O~A*(y)Fu&~pG1=MJEGN;TV^Tu#3*Wq6tMAXg2AqJ~r9ebPisKJ8~ z++VaslRp9-KJ+?r1b_&3K7nABpBO98h@u(Fw2n-L-xK-*|D?2>)I4y!miwUjJ!Q<L ztajzN*|cTN47Qp+oR*8b7yFXCb(32TrI_Isr0DN%CPH3&)#ZJbRo=8&qWxBZYiBf5 z?e(L*h(=~C>lgVpN;y#IhmZJZ0u=t6-qr?oIsz+Mbcd}}C(LO^65#$nff;?<#jEt8 zL!(%U!JXCoDlFlNl{b}@hKW&F{M(f!1xs%VW21*mij)2f8yX^imQKCEa<{DR?Zjtu zGY%D9Q?x<}%8xdU;-@bwTI$BSXT@%<oAXYL3B5hl^LD#_EB3hJKsSHvEuQlL%mlQX zFJ$M|Zdf~O0QG^$;mQxbQ*-AoXm9(pU~&h5wBgL&MFnPqod+39#AJ5zle@{~=vzU* z7v3h&+ye&TS%UDR_N5U8E%fL1*$0QMV@wBXP_WTwo2#iQl6%m5E_(5P*86o9KL)?c zX|Fc0+nN7*AVC=BKKqMYA-@gHA7!xwt_h2{Ewe<r1N_azI1lIS(3dz8vx0oA17xup zz1Vl%EaNY>^aEC`frK2MCS^7RT>c=y#`1dhO=I<Nq@|N7$dUF2!~7x3GAAM5wJ_Ef zC&MSd7S%rAjG(DULJs=mYxQ%;$W(@dtM@={T3r1my@8U^!-O^G#pkE4{tlmqT%uYU zZrq!E(Ysn%m0Q-i2t5WPqB}%q=s&VK^n}$B7L16fU~>xsN?8W&&B!MncyLxlA0%Yw z$lCl_DTs-@IK^IDRH#O4=e#VxGa78z-KwV+>3De2x!Y_}4zHrCm~30oc}G_?K3>re zR8fx>zm7+mxYG%q=mwYDW<cUS)KuCAEEl^E*LTxZsx`N<9d%CJ!f!+KZjhd<b!s14 zw0Cqs>K<TeE33cA8^}Iw6EHS3^y5u%F*O(WwRv+<F>b76q(f&^JdP}zuWJ~As>>A< z?)h9m8b1{+J@_E0qIfH%W)-*cR|hzELHyPMr9#1{19p)enwbj6+sF5LIr8epBvzYg zQ_dZNbvH*TIYfEzKVDTdZ}v`QUa=XOTBo9t7Aw7W0$M*JG7xm)711u}q}U+x>)QC< z*8dBg2M6taZq6a;1EQ(Qk&Y!Jd!+xB&F2^<8p&6F-5}-HS$5D!v1LxaRinc8@n4}_ za`)9`x%K_SCe{TN>?3@u5^EJ%F>WV8UnnELu9#GdPL%kDQyr=<MR3toSA|<wu2L$; z?XtyY=5N+VB&BYHn+(I+>4$Tr|DGSZkkY?%lhb0!dnjj?xyd`-WF7+5rzv(tuheih zi#=d++<dKWz8%VElbe)0*iBCT(wV<sEBR36<;-7t=&Jm>A&T!4RZkgP#1^j0v60ee zQ{*j9WQmQG8k-`y%hF7wuLz6HH>#x`PXPoeb$7W9S(`+aD@RKi6yhy=w7LEjj#M7q zSh5mEVa@{ojeK=$H}m%&S>{HMr@GQB<khbdn4?P+jJ)h_+E(*7Hil;FLAUyUz@T&% zHG8b_QL_@ax{0YykGB()O44JHRQv)ddO7_b%@V3ps=1wjO73t=*4S!ono6$hR5IT! z*`$&=Zpi~~$zZ%gnWpq*r$fnyompQQPfRy6+{6qw@f-2P40DN_=ywyx#}oURes1D0 zH!(Aw*xwv}$!RmoP3#d*^qaTc#HnuLhmdRT^aaf`ZsJ@w@uhg;O!J_dSm-8hjVI1F zce;rsZX)7{9Vqp)+;h#hNRz!sZJ^~!cXs0-WoaR9Epf3;b-S&#Zhc}LWWV~zGTg_P zR_T7Xnf=mS)rQW_G|B1$%9FW<<KMhWPWWV*`E^@tlThgg%>bwJsEvVgIA~5*%w}nj zJY&+~)xvPS>v^EA^6?RXpfCKb%Exi`z{mVZ4~{Rq@`(<(ryp_BGQJ-L_5_pitEMHG zllMIiM2UZwohqc)8}5(g;Q2RMAn#q9m!T@=P{pL_;pbtfRjMhqQmMviXyN7{JzMyU zNm*D`e{0`P{rnE6)qbR8bi?pLE10QNlwY^Qj;%>!yG)bgX_L*?iI5gUrozbNal|mt zsNG%HL_tT@ZOp7rJgm8w!o%{l1L>cxjq|X6Fby8oyvq{^om?uX%AlG4O&wjQan!YZ z%ozwh0wuc(4Q-42MWxpCk+Z0Ub$1|}_S*zn^=DL}WnM8xJG0f?Y=7I#B7Pg1pSz42 zn_NoOp(97JH2(|#MMxbu<waw;?u$D4=W+ZF%_`!d3(q}H-k$tkGW3$6qx^#k2J?M< ze@EygmXu5_b?jAk%J+Zk|46=sXsS~kPT&6j;S(uwj;Fd;4$TKLsmn?VR#@Ll?zg7a z(v8}#=kj0du^}&12LH{bX${ZyUz|5(YGB$-zOM~0DheH)k$AVx7ytyr^Gg<$7u&_i zpD|UQpJ3;O^?d2eDJoeu6K_+?im^%RhNmuC`YolA*D*Jz5`<^)LWsL4U$#VA7KHd+ zvZQEfs9bq-OA8k*T;X`lnpWzB6hEzWM$xi@MJ^mz*qX>~%9mTPxU?+RL&`5&+9@0; z4=v(Vs;Dq;(YMtv(T*AXdW;t&uWwmY8ZM`@0=1)b!S%7ykHcC{ph2BG8^U6`v$^K> zxx==bzg^)_=7W!T)M#ViON5=E$lA?@7sXfNzIM<AUJ)nhplII{KpjLW!;g0!M%q%2 z>%PIdLK<@E**nA<*ho7RIE*9RNyImQO22iNaZ9~rt34R3=`)sAKmY5wxrZYS*PCgK za1OOPmk(s6&^wRjki%r&uIrpCUwVP;_lFD2iIS_50TnE<pab8&^-^=isk&xzqmg9} z@?HVQHhxoVFf~xI)|5y5rdVwL#sfvd1@SlE<%0Ow$S?3-{ACg&NC{moOx$js1efY6 zmtwABCZLs_2{_3aiutLMi<4k{72~+oXHF**#gjuPk9@x7Mf$h7kfTC;mSHWIl8_W0 z_LOc`i1>A_eA#bX;v*dg&2|QM)#mQf6;X_<HTb&bmKeK>3}Z@SSJpnDe{ivLfA!fw zyV-Mz5b~uXK*+Dx1ip;nWVI+bI)z_*=@;X>a1k;C$ab!9Z1mcD3wJnfv!AXDbYOij zR8SpuEHvdGWJUICMeeR(+FsjSEQ0b+k7z02S^bUXtvn6lgmS#PBSPyP=G|S^RLL1; z9)ddXc`){*>7%NQ4yu|=RSEJ9ne+`DDm@4PvZ6BHZiVE_^=^MuPo1$0A%9#pp}Z(` z+)~zl@KCbH?y2q=S%iL_hFGtD{r)?+a5<$@{6WRvOFWlyJGAnP-J#t+=cu6#@=f-c z60*8Oi|t=;Y|~~=%0qT;$ud17F~VaFP-}Ie`n!~I*%|qtOR3BSUz?M!l><?Qio6+N z&0~6VB1Ha>G}(Ow(5|iNQ%~5rzikTWM)08M_RY(6#c+M~w9}$PTq)K(@COSL*(vz# zO69+Fe0TAz8Gk3O`+=yew6#xAF7o=;?q>MAd}Q}Ceed!4HmN;e?@;!oNulJ5+>Ru^ zaKpt{GGEE|3;EJkVD6!3g<33%dcRTo+e)I}`+`2{I_^&L+ni2+EIK=KP5)TL4BV8b zJ$=onSVR(nIMk17Up=zn`2M;Sp$aGBS%BHA=qa+{j?DbvZXgfeJw2H5*yfDVb?rxc zGhfCIY-oOXDErWp182N0{J|SQ<R!3c<nwhG5ofL&$eeXcM_LJTEYdB*e(c6%!#3=l zG5wjE*q3jHpFEW>Sf&-@=JJ6N%!=H03`NCncmtsQ#Z>NRvcY7*T0VM#5nviO&JhYq zm+^MB31?P82Sj-@1P-pvlP8uvb;Fe0U~Wr>EtlW!@Ut6i?zk_W%I)|#rJ)A%&F;$P zSY1L70Od|X78M|}i*Qf+bAh%gyvOM-(7+Q9YSa6~8fq|~z@CEp;>ZCy4LIHT@9D-# zoYvTuIIf>e|FoHNd6g~WBzMo_xlR#{*WrG|xNd^}Daju6i!H*5hn&JD@naBmZ-NzR z`6qDhzWb(qYPkyT+}`1q<JV|@pb57x)6bb2eS^)hA3D?W=6XeMq-t~Z3Y}9#|0NH= z=oQ_d$V-R>4^5}C87gNgkotz7carVknZ+HL5-_7A{W}CZR(181*?NVUoUW=Y$gh7_ zAkU+GKdI|Zde`2s{t$!9AO$!ropWN(#e&OIh9tt}vGIm|CG{^_>bEn-TdH1#%2r5F z3{0vr=K?5k{96jk`1pC#$UDBUP<3JM-3s74xY&~wK2V)&Vy?l&vC<i)HEHYSt%<7; z{>8HlH=h@vHgg-JvBz<nd1t#t0p^-vf_pAmCsF=-6YMFgSdcUvsHxTjm*ZrnKu%_y z$k+7nn1MiVI7d?1UZiY%!@Aa$wbIs&kDr64o$9S41*(&%l|USULDg=9Y$|_CGH#lF z?p9>kX4*Y&F5R)&X37^^p$>)!^VwOUOTihj<r++&q4}l@ST64+z<o#Qd`^d)L#Zy) zd2cM*k{<4SbZ_boq`k2`esmxHt;G~w&FReHF^=wm&%5W_&u1KUzU@#|cTrX1`6fi= zoo`2--SPquvlD~yiv*ZC#+j|$?%{M4J@U1)x}*mk=}JeAI;-zje9Nuzv-&yY?Lg~i znAZ_9>O_X@RMvX3CXOYM4*A;Y$#ESU5M$9kkX+_}KBwa)l>dKmMz7i4pMuU4%ujCQ zv-&5a^miVrAh>3=&oT3MRnObb7Fw5o*z(>Fn$Lh9Txy#Zezlcmo$hU==rTUd<Dnx^ zyDwq=>t#{8k=bKK^PLEFSD_PU&#yIGO)b1T^TTmuzI~x!bGIqu7c=S<{LJSG2pLa6 z$iB@6ZO-i`hhNDzo_U&@whyI*UhU_F8UruD632SGb^hLCP3{)y2h*8DS<?{Ys?6Pz z?gacckYxkYD?-Xy!MxjWFx`e7fg(y?>!gbu=ae<u**+TnZ+m*fr&LYWj3Yb3u&4L9 zOve%QwB?-2)#*NBWdh!s!^=UluBEqf<)@o84QivNpUZ{0`6)1t4QXmVvyHgY@uxP| zXKJSQm>i<bO3rul0)OOBWRLmX9$P_m)of~NteVT;-nAPQfH1yG3o|r)1iP$<ujnS4 zE7af4O=@(Dl6sT_@8~q>`*4}o?_umv**AmGFwf+QuUlCrhPkN1{1}Z(*lm5Itt#<6 zB^X)7@)^8w1Ri$tWS@7WV_o2tiq$V6T2T{tWnJK9z#^$)^~;bLECH6untY+5ysIN^ znhb!z2@8&{&fgRXj;+pru!ULN#BtYDSwA{xzKs+oVm;}#xtl<k>cUt#S(AyrOPt9g zw^_fBIjFLbe9UPWat6H}2z)ZupuW@SdBy5ixNi>Y#<SE~#T~xcj^<ESFe#K4-J~c( zRC6-gEmG|1J5>kboWU$b?tSi9rO&r6@cW9@zxT!abD#135B=G#%I|gNzFptniM5T* z^=G+WH3lAnnaVt!<IEH0nCjOB8Z=i~S-2vw9}}wsPqdut!O%f-(GxKk%8hEScAu^8 zHB_u_@P%&RJ+7|0YP5xtvHV3?C=ji#%CZr1II4)Js;hEr#8fxpiR!ALjhLy3+Kno| zO+;yQRDU}DDig`1-l*@oWsqwzfZp_Yyfa(XnaOlUr20$T<Z0=TNB3px(S7;T(S3RJ zxP4ix_9xjzWvKlkfvsZ#(OcQ<`VEI8fk(##p15U+v%iy>%TY<a0uP6C9do8EX03%D zySJRrx<^%I9^7juj4Y*=e*zH>q*+O{z3;(8ZtIb@R@Mfi+g0SzQebA6MLTNTF`@5t zAg!v!Lo(A-(yC<7+UZf2<A1ca)(V_BTW!mmmhxI|p#ZDYO|{E1YoA=M=?7$ypK7_t zLS<0hYB-;M)+*86CEc%LEn-0XpprK#xwcA8n7ppm0#I7CO<hh>m(Qfj(a~oT{B$X6 zIx)Id-|y>twC&}zif~$VyCVNeWb?le7ywF>T27DdSL72!3edv6Y%C^k9%9cw#1^af z#yPDbZS5lj*u34fWvDOxEQ+pCeLtZ-?flxneL-^#Vkod@(xPLPUZC{ViRl;G^xGC4 zy`WQ$UeMq07Ld50w`(TsTDuE+GZ6_3+Us4rpdf%7)$#{RXt}FxdB1r9EL^erVIPV2 zDe(m*zRz2NGd)S6*|zl_ac~-PRO`tJt>3S8`-}{3>v)7Pcl|@Hcc+2<YG9EXs8RzC zNDMwhsE<=MZLR!w9coBQTl-yaa;GPU&q2bMT6HRX7h`20>a^&fv#H3hipElr1&RJ@ z`TGne@?zybj<|J)&k{o{lp0;70w0&yZT+CW-{aekkQUB!gw=GQPWOlU3a7J3yOr$; zvNi7!Hcj;te25@Ceo?vS(-a86Ie)^1@+cIZSzGIzeC=TUNFY@tY-;6`it~jotF0A1 zLZb<Zk&TKIB6+vJJ%moI&E3~Ii)!W|dQtY4UUbGfL}UHMc`SNhcQB5e@}eGc+BSsV zs@D6@=af8i6d`9hyM(${yeOlj&<-j3Mo}*#R>f{}<Db1MA}^}^o)0b8aW}6YdIPV? zJ&dr(u=CL?Jb|gL4r~z7aMsBl(E!1NxOskY`APAZ&ywOh`jc}JCelnzG_O9(o-agP zR{q6TzrZHe#?I8pUL;qsO;SID6&AAv%_d67w@~f|Q-s&umQ`GngO0vqLceZ7zOg#6 zUcHzf>qWfoQriQLAe5(?YI8Co`5PjE^`=;6@J@*2qTXb~vkAxU9*d|)nLh8Qo5ojX zLIfd;<<c={G`F20O7An4#+c==froy77PQO}{%Ggxh8hWMKqn+<PRap1EoqSyo~PBU zo3b<?uSXlqCi!*>WS~v>xo7C}m}h>Lpl~Em=op*p62@3<z-on}LMG{!4Q35h#TBLo zur`VvWBWed_MI+NIu3x55PZQ;Kl68Kd)>pJEkSca1d^~B_zId^!ATBH;gXKfMQqT| z*r0Y&mubOHKj({%$Mqc5yn{dHo&c-d278-FO?G~_P|wOXe_GZ3gpk`oe8ce)a6Om2 zLldSYhfq9mL_Bg5={=6++3XGIy=5BomEUr4|8ljsg<dyyQ$6UqLU`^LuwIPv5X5p) z%j~MXw+%mbUG=K#Q=}rVDYlA?Kbyo_b$ON5Plqle5cQoyjv!LCE)MxahHyyQ+5vQ? zV)YB426qW@0eEiU<&c>2nv^iJmQh*H)pfV&sqR7iGeu_6*;JaLN=u7%n7rr<rRS50 zVv($|=5*8|RYfEx%N@p^-H6Xh64Fj^iH5t4I^yHJ7gj#!NUvy)YW)Qih||_?^OXg< z{pR2NM&~N^@J$JA?s41vr9gyliv&)B2hS4&F5+(#7YCFz%<GP&j;GKaA}quNG@$#a z+*Xv5IK^@De4X0;-XaiB?h6&4SPRH_%?6@=i(ev0<z!Wo=TxGJ3(a@B(j{Exd}M_e zEe0=b0i5?#SNSc{++AIjX+M}W+8t!ScU4yn@gh^JtA_DiTkGV{u#W?`;~ORd(mzd0 zvmF19SR%}5%=$Q~rHAv;#c45J37QUn=r(uRXE4c}HKpq8FWEL;dTR7hjqibl_AEJ| z?|b>KD@1BI3bo-gZ90VD`%#g3f|7vdIut0K`bF_(ce8=%SvJs}o<y<?GS(me$ZH1D zNqQn``vPjPmz&d~{&Q*U0vfByeVNL)b}^R>r5C40XDZ>uctVotPlD58m+;NZc}o25 z$Ue0x*CshPLg@1U_h!4Ih7L`&jb(!QbeF5H>TlOYf9+6tw83!WEag1c!H&nvGlD#t zgY*0A*w~E_20c%EI%lf8Q%=Ert#x_j#946dLYy-`f7-?dtQtBidu>+eN>#NNWNoVg zBv|lk$yCpKg@ZsIR(+>-POz13j8$3@DvYkvbpO1NN2ljG4TJY^8m4?lr_NnEb)K;o z_hE(Ae%lU4wb<%+nG4o1-rg*m0%sENPLSdq6j0=SC+T?k>8YKLmkXMI*cS{n1kQF{ zurQ1J2)TgEZe|J?y*9AjeDV^)4C@KRWq6A-VI@?o-YN5P&d3g=9ii?Cs{4b=)!U(8 zw*ab))MBplSr=`O5Z+~g#a7d8mLO5s%>3qb`^l!^>bBn+#ou4|pk^SIRbf01;b~4` zViRf7k78j=Q<$cN(021GA%{SW^xYu*_SjAlcHvViR)0p<9%Ht3m|jS1^A-Y%4xeG~ z3><UZp)<@F(&P&^#SG`mWbwx;3YG6jIJoC=pRcVFg=OA5&Fh}oqfaJom;K%4$P?Ri z;Nx){dC)v!f78ux`9=Q!6ejMmZ(0u6vy%U%O6#xpqKo{K#EpY{4&V18Jsa3G*)5)k zjc3aUTUxNh;qEzU)(&*((u)d<78Zm{LjL)SLQ8q&y25|ysEhcv<&T?Z<cL_F5s7X1 z7nRFATF6n~nZLrbEbVj;g)F5wI#ufX>6D$hXi1Tum#!tt5}lF8eUT3O4|xVHj2UH< z;;^3Hzdmj>x!{MF>rqi{Dw90sEVJ*bVRWiX{pXf0Em^T>VPR=e`O=Whey)FENr5%u zrZVE0cJ8Omq#9xjL*>)N|HpjC=&;K9Dd#?W95o5yp#$9ilO?t$$ILruDZ&$jZJq(0 z>pQx$ohnuPBAOEQv-F-B(5!hQ)VdbPoCvlrZgE6<hWfo(9BSLV^yo4J%l(P^y;ANi z;)&SxHk(-7mY?vS%hLg5I~Eq{g~-3KtaM32O~925^3hrMy+eJ8zjp{U93b$9)2VAi z{a-6@Z4a?sjyG06^(U;sQS<9A1bH;K=kc2@H%&_ihIpHyE69|%5T7^+%B%g5r*@B> z#nyK*c{;C+i~$s&FpnnCaSE#Ltgn^(Z})1#LQ{w88qKfds{EzaLV@fYu!~B8j9X=a z(3&aeG%1M#b?dnLn04@QwP@Mb%d=pbx{I_={RJU1%@2pr42*-I?bn&qDN&_m%TOLX zRspwdy&J^g!)fz4*=@a&U+|jp7k0)OpjY7lJKXX(+OXv^DCa7p3iM>XL3xFWY`XT{ z(9n`)3hSTd_I!S0;#5p=S<%g5q(4~VLUbVYvR8m0NE|-~$Ul>cJI%MeJr@;}m1|k% z7wK&fn?TNE4Ja9l6lFySe=WfO^HM&+zE-W$wy(YOe^uX%A`YGS-s?sAiO6z=igYA7 zV-gOZT2ye0orIz#%Sy`%IHxof>YCFNYp<yE*4W&Lh|LA0oLZcE{KVyj7cAhMS{N<? z6c#PD!d$HO*XH&d@_KSu-oE$SowAUpP5&U-LDE^EIaj0Zv^W}dvFZ?1^oLd~EAp2t zny*d|cJ`TzXH@?9<t9#@dhzt^+3_N_EzQLgjC&MGYE2z0FD@u!0CqMO;H{g!IY;o| z*j)TKWt<~9Ugl)mj-4L0vS=xwFnN5o?E}QN_3z5N-J0!p@w)H6SFPu>`X`ETESA|< zt0w2M7g-O{m5a{zcq;g<?g$_32=~K2iX%#K`N=K|qILsS@bW9kqF@ivr2F8vz*<|t zbwZC!D>7A!9+@Il%DW}q@mg51Is@`=3ygY+uS0#+ZmcJHo30_I3pA%*cuXX}pSkEn z+g6g-3j<m0^x_e+SuaWHvVbvslL*Xocxvh4ejVW^+hsDlI)!(r&MPGzhd=9$8b6es zS^o=!XC70C?6n&;A&S1%Mk^F6KZ){@s;xvx->m9U`>`8GUwV97^MQm9ZsSItf>t;L zI4a?yy!&%`<W||lf2r_fccZegzb2n1(oNla+=-<$1xdM>;<a{q$hZ%_%_uQ$)2evy zjg##a%%n}-k3>R4^ZUIS4<f@1IOtDX+n0GmCZ@JZV=-T(iTbpIgmw5@x)-Wj%c7bF z!Vx<KwRZiqc=vQmSiBuTjX>bX13VCLdS`0?XvML43g}Ny`vq$(4+wc8hQ~mHFe=?1 z+-iGZXE0%52iulytkcoa@vf~`*9Iv=t<&)~^($NEczOjsTNn5&afVt)I5Q+ZeC%TL zbGmD1=vh)5nz#4T3^@XkwT#Hl)wQsRDhOB-|J!ls`Rpfg=)n(HlUS}lW(+N7$AM+R z17cRHbIOo=&^$$knlm@haa;E^kK4(b#JHUf2yo+T(s0`T#&BTXC7B~nC-i(7Rn%5# zUL1jgzx2_Sp~<-_L<uxBAL>bG_SOVGb8iJ1c7L<#KD}Kt4OZ953TqR#@ANyg*<S@5 ztMhkN=kKh}Kj3cd?t{H`<vyA73vPLZ$$D3|`m_56c{|oVIXkMdt4^5Y=%yl<F=Sf! zv(2k`jrO!?pQINFwm3#bSi?OPE8*L1tnU>78EhZ}T**$hIqtaGkvUr~z<mQN;!k2= z2N9&-lpu1ZH`aB5y@#@|MZByru-C^|O6b&zaaWMQ<4CkWBQOoU#fjRRWX*eAV6}bq zr&W+BCTJU5t`#lqntXiOnJG<7eRCI@Q`hvMd;qbbJAa2i7aG6{2zroRP0NqzMK{O3 z#(wYlTqwu%c?#T+JyCk5**QGEqb<bdJzxfG1}e0*`F`x_!yUmqr{#S?%jP^_hA2Zm zl4Ui4y{24pZ|eeYR;+&07cM%KJ-ti#n~}bHei9xTpQ?4=U01B(^|wF(!#%K5mE$J8 zHh%{ud$*W}TfU;noz!mz>cu;M*KG3<Md^ln!QK6&F1TrHvw;iDo2dV1zGqD<ngB^m zhh(m$csvQ9i|wHISbGWjtnMO^tLy>D#W>H!edv^wW4i)h<~-1k%w-*Bli~kEIXx9^ z!D2RfT)SBA$!(84OQtwyp1;JE`M1KPp<-xM_r9Tvk?W`E=rhdP#cOK}U|9DJ1g<{X z#Nc_#>2lkpbvx)?O%K!K8JU+1oqtVbOP5vsv#nTfol)Av%dm%6Z&OnyT@(J0T9Vk3 zY$p^l>8}09WN?ag@K$w<f5jbLkC%RI*|m2s@b+18JD=AT`!CcKwmVaJkST;eJ+dR* zUOa?^Jeypcr96^nPBGn4;O1P46;rp&lN1xH3kZLi?OV|ecF^X1U)k*o&VDl1revB} z%bx%ED!#zmNmb<iJ}ukNyLDRNW)dZ)H4s!I(ektT#r}^n85iq_j@A11<M)OsT%ob$ z5yClbS!h8xG_OxDWcbHv=9I^yJ@nm^I4K>7##08xiGEbvl%<75%ZcnXhk#vvai1aH z{2_?<JmU_U?_DJ1BAJ+54mG5QZbs*}E|Y9zIPgPl#CG;e8=JmvG_lbf{+JdvVBL+% z#K=!TISpp^XmXnGGQX1FTkllxTU)_Fb1Tu6?;Xjb&Y3hCX}iuu5!boS+--$+TqV>D z3P~u;ZikE%P1OvrXk4~bW9-cs3yaFX6)Ige6q??Sn-@f1_SC#76Je+*Pa5H&c{1Rh zT~bh9ZnYm2ulvEuVdE!_&kjr+eo<ibh|w1fAI{h1!$)6s(S%Dzj+it&aQP*dT{3ZX zd_JM?Zz>86Ez$0dp8@C_?2Z|ybxFN>`(nn_R?Ci_nZr)jr0*H#O}YpcD+(G@0<Izt zNT#lpJZ3H6!9(Ha77t=87$IV~e*&CugARZ`VYE^{h0&6SQ{rl7iQ>o#o9BKcyk)aY zb+cqB%Rn#70rOxy%V0N4rm`e^S&Ugj7AxtB4ltiJXAU7l#cDrBb$E7c=_xmfdUfn# z$;}i0n1pQe<^oH@aI9nqYJLd;$Wc?Vdava*a_}2d*PV5Q{v^<99wGn<hiwGx=%NR) zlNX}V>PP=;k90_SsL3pSRAl355qowrn#?-e_uY{fIbxDu2IV6aZO%r=R;R?N_ScyA zermB%1|p57g+bZ3J1ng~jwq<&KF-qbe)C?tSdx2vX;lva5|O|tj)P&r>mq?cd}Ia} zCQ@QGP+~Qlf4mx_2nt20hQE869%Uf7k)GUV*4t)rC|uvtWowc>i~9RQA$uY%wf)~` z{OUi;X4hoz7`tU=2s$z@_MoF;b^jz>BdW%qVlKctLs~9uzOJLK!z|?pX*t{WQ6AeE z&K{0F`<QLa9B@iw;7!c8Rp?1gP0PuR>Ux)@c2qkGe}dn!3@3J{8{5T9BUTC@oW1+Z zId;eHHV-K|LE&RCnFI!DRn{Fk)u*lf9&-oY#8m~t&O2&zcQ`BNDRo?m+>2fZ+?vnE z)4Sj{sFl8(?lK!+E5>tA2Qo(q#mqfUu|gHQ;rPXNP^_iM0^K<j_aCcM)V^8Su5>b> zN^?}N$xz`mPkBopbQ%=N1tdr9yW>rdB^>kbuzj^Tuk5PLxvx$b$y{p#?Pf5)4b6A5 zhAn$ttUt`+Dc#du+ZLA06ppfd4U26Y9Av}G7A+*JEn~ysGH5!Vbuywd;%Dm|NMKXj zygCmO@t5)nf5O*};ZKXx+C<l)$KNKSMFPs6BRrsFs(Aiy57zmKk~s3mfFZxwzIusq z=>S-xRY_F4p9u-biEtKr)3YfhTzK<uMOf%CF%J)r>2F?j8mVJ5wRwPEobEQ!mZS-r zb%Y7C=H5k4sPCib`|;)Aj~0R-zigRb`fTMM2`~KZ=z+LClr+-Oqr8!BUMmVbD<y}E z;$1aRwFtBw#4Z7i+Pm9}BfXrUS)1AX_&bceHS+eXnm$s}Pt*YU9V;e!@n4iC|JI&n z=vKb6hnSN<m(d{28voV2j)73HV)K{v2+m~ZC5KM2x@m2O$0^Wxt7d#P(?MDn+&`kD zA%fl9^5s{S8oiU+A)8TjPBFJr1-J=>i7nPtQ*MJ;%*@B6bGj+CL4&eN4*yLJQlV}W z!J6zK_%8ceMMyJ*{QD!>!^|j~f4`z}u~e^Ly|j_s6v@soeU&Ux4%uh2deD*VL1w{? znkrYWVp#L0FF{))d5Ll!zMlEKO>aaec!ucydJ^cUo0;$xxxTMIWB<sOdKCm;`Y@}F z&CJ|`X;nP5#UbP>rcKv4<azLa#E#PZJkM`K^T2k%#iN*=y^>BY-giV2b$Z{4pW|F^ zz+J9&9xN`Qn<t?7>{4&3H?K<oit{1B0E+!CPzVf^Y&NX6GQ=EQSPJF@;isSTqf32L zBqu!)GJZPWfeiV=5M=Z+84qjaD3xjc{SA0GI%5bWo8Ny|At+ZuDQ2?`wc1dsxyOc3 zEN_bV%pC-rd$}XMhYagj*9JKm2qa-X6<blNtIdQsi-654cn`jjdj%kzp#wp*)(Li@ zW*~ZrHv_u+)$~cejD3v8BKNyS4&T@!U*>%^Khmbv*k{iBgAO{Z99Tt-pKP@PUp*g5 z!p<=Z)WiHrKlg(GE`t+*s8s%etz*qM-q!ugD^zR?g{{F?t4d&d{cYRp5O!fTpybfG zmSWeMadNSQdlJkLRbjstaT6zNip>gLalEW|#j<t@4YdrdL6S;xjsRQtPOGhs)*@$| zqqVr!XY!q5ctA3X=K*m7*!^i$|AfKf91#<Lp8&dF0#llwGk|m$aSjL%CD71Z@<k`m zWmUj)XiuTN(P+-&V$ss8;!AulB5~X!t0sNzt6{8=VOh<>v9&t}J!)OM!j6c{!@z2O zv2V1ufL1V1XSEi((Oh#xQ!Vpije*wQ)vI0A#{<>|LbM;n%!bKKovZyA{Wd5L?MD<I z&2D-d*P?(35d-Gl`y^%&9&WyIjujdTr$(o$lI#E{?HMMASnl?Xf&H}K1f{n{i6dyi zgPh_X#OSp+i5=X~{7vA<v$5s+GZR1NIC>X}8ara_&mB<i?EM*(v2RCyJ+T}^2SZ%% z#L_VP7ZixqzX;3Ijye@wa=mNX8tfavP^WIaBPG0nd|fBAQ@w)*6vA4zYxSVcS#Zu4 z2i1T|09&org<0NeZN4i3;rtUi0)(^Uxxg-(WCQN9$>zKjn$+zP{+}gYAwR-9{0Q%C zkL08#BAkoBDLRTG)J7Fsdz%M-ErdgMzgc^|0E3fxJ80yp8U?^9B*FhBWDVr33%o(p zp{y*+J9>kiq(CS3(L@Gd)_(C7MCcn`8UwFbR`p-6)Tk`0S|zT^3S~-4?Ho1;9EE=R z4ggZ<9@1cNbWPw5^CY^Lwt6xnDX_g_`IS(b4@31hu@#|f-PmvrqzUS42O04m^A)g@ zSkGVKEQ;Y9vLz3gw@4==_8}%)Q6N6f=c9S1Q*+wWSz}=(+i7q*vWY8#Z88h_8(Px; ztbsl>vaJ)5J*N7oHV4qAEHs4&U~eQTt?Di<Sz!Cu>z+v6EjK&0CxwgiVhv+?DD((v z`R*7)lhvv>#?y{!?_WQ6+6$cz!$uPMS{2-XC)C%)WU9VykBfCswKuJ*kju4R5$cax znhJTGJ7E3<a(1T4FWC@p{?jRCtG_BKbh`3=mwf13!rIshD?n$-zi5FhHCb2UO?X%3 zm)+Cue3Ph-%#E*)ne6*D&3($R{@XBavhM~re2DMIIR`Q4TJd3*P>+fayJ9#s)pnO& zi#;>8n<G|C<&j`Y^ezF~NM-`5U?hMJn69=fwYmG%n_jjzVV)57n?FKsIGy%~F4p=% zI9M*`0rLuki8IUs1X(1}jc7_z2%9ENUBcKQZvq_!qnl_7RR%7M)q#4sd$AqW-bgW* zLwPj|sU~*oe!AjytAr*Z92mA+-+`?Lj<nr6gKi~M|2td#*63E-*rU;U`x~vz|D9E5 zQ1vwT!W}x_jW2Yz?tN21ksQVqtGXbS3~$}ksgxO~Xp%4DH;dsJ^8p7-FwdT3X0N{O z4hTyi2slk!D`y9Gin0J#9QR_a*V_Y}^vxW@&3Xo@&EMko<1G3S32ZSRT`UB&4-0LQ z;Kf3lR$@i0g_C0~yzWeq0F&1j0-aj8Q!PmJKHkC;Rkj6aAT#A<J8S3xX><es{Z+?e zX0R=|xVO_@&scj8Amd|gqb+tv6E5h~&e^onGR+;s2`m5;Vdu4xsS0XetN+^+urrkB z)d#RUo9e_)^}UjKus;VZ+fskC61qS8g!AiT?{I4w)cm85wcuM!uPs7tTU^3uE&i$j z3796YB$<0YZR2*0-cQvtT<L9_SEYo83$Y!<r31)vfbH;Tx`%1N2WtZlT1XZtQj`0J zHDz-vHwLF<x>K_5zbd&7xQUhQ61p(49Y7zFslGPw1pEVs@Ug8``%KSRndJYj%$@i> zSzvpJ4-Iq0OwmibI&ycURh<t@)}fa&ewjcojbPC=Z7rW^`u3Rj?63P!d5Azm^Qcy) z+PzXY07beZiWlng$qVdjw=0y@>8$^c9CD`~@mE)tmJ}9Zp9FTGty}2Gjk00gLgpj< z0Bg{Og&*`!{Wz1~IE}Cjfr29cxi{ZhT2^?jW1E?DXo9bq5k^jTyQ?l-d*Er_MzO3X zjdf886%#xvLEB*4eFP(~u~C;F5<{AI8b_ACcB2Xs-+ng`XKR72ZG8#7@E5VQ59$QS zwUy~`1~-cLo!jQ+deG*=DPVqadMsD%#{JX^pgSgv-B7DSsbYzhK1V08w%Te2Q@nO# zE4jD%vb38IN+vl4%y^O$t%JH%ap^5@cw+E<kffi%Lr<%jRUd}}Jh$I)K<nRXZUVLI z@^T^kYI6d6%FN@Bx6g`aYBI={(JUl*(4_L)(0tNIK!}0uz|GlQ!Y+&Dzmxp6RhlSM z&5qSQat*%?&F}n+BL8&wGyqix|18g?XgLxYcFnGJCv1l|U!m=qRcr6}13O=m9TnH( zv!~)iDgMazu-%jyHM3mJw8Gh_&2nf%Yz<i2ki(`ueiL0c$y;(y#2&N$`Nfm7y=d!7 zPxj<~4^`!ju4P1XW{U>3-)#SZrVW!Y?WUF-W{_s&WTpHjo>EQ<{RN{p2Abf=?t@O> zM9ZdT40JkRaF*?cfQ1vSZYLoPFK3Od+Ze9s&YUQ9pPPDtQgiovFDla;VlOJ6P4s$S zcfe-GzAn&HmpNHme!sbkea)|HpKl?{BIjtV(7nnv%FVUV%Vk|>WyN#d>_TFjxk>q_ zl3#_dk3|Rhvgi!_Y24@7LcO=@ZfE1(F!f7xq;R%Ide_}Y4dy%xCC2<rQ1og|UN@c} zuSu>=%{ACesL42ST`;L)Wp_Bjlri5XQ)5<_n>nS`^gE4T$rHlQy!9#mk{M9K!uJIW zC9G9TtGB>C^u$(y{Xx)4h3FRkmq2-L+obWl&h~!nKGC?LwBWXVHVW$T(q97vtXH4d zdX3zh&8uP%4QiH_b5={+FNg8miO_>iy#`Gj>^yCn_wKbP?n}j^$)Q)YiTsMbfd2ED zjZC=P$*`q5W~!d&?D1ymZd9O-fC!J@@avEug;Z}XM!;Q%=>7uPlf*tVjN7-w0k=5A z!UGxCk&*YG51E<xVLG`vm(7z1WPiEM0l~h5_3#u2&4=9huLfz9?dIS7q6-Dq7|3MD z*5P|J2c$XU+su~KW6KJD8=Bt$fgHt8I*(bH;h2ahkSH#KW4I#<70gE%3#lYoyNcNW zusCB$`AxzZF&t7-9`eGHcOB!OsaIMnzH}?{Rc;-AgnxBA^(3^cL%J&x>KWtr`@MQj zu=V);p24>(NKt#^ZM-a->-ASncoJ>S<rHbqLW!`cA?u2{tZ05|X=tc_;&lJC=`;O- ziBo2tLmgh<Zx}ih9tZT>aqW;C&3~N{UOIj00wGP+G5r5Q*;6PhTWs(E!pm3y@wzel zKYUoBQ#TvM+FVmR+;L@NZAM^nJT0F%rHM~&lk#TG$elhhK+wUxF&>KZl(#PTbG#zC zq8(36@sL%;YRK&~*tRb3MDh;LM|YEM=3ff4gX>7=q;@4uCaE!S$g+^rVs+I7KIgvK zhUgMIU=Z$EqM28d`Giq%zDV;ry4O7SpKTp=Iiv}#l)Fg%X<lPMiHgeMc+`&DjSmbx z&V>;fYE!~wo7dD8tKM_%A!@j~HksRP;U;#=)(PgHFMta3_s=#yr=CdP`y|f){{0?x zdML^K`vXy@hoDZsOytEjFc|S-Ep8}cYc(`K06L35*V;Khi$OShrbu@1JZj7p@Qcf0 z9-YsT$@70LpWewk?ZNVxP$S$KXPpHvo$@TSvhG*(;Xy=jpuOqIY<K3N9b^6fa?O8U z|9zyJ`K;U5*FR;d)}JJA{rh#UE0v{U`G10ARcS)BnZqcpMMtSrw-HAJLf(4-!fevC zxQjtfIw}8z=M)zZu3`lQ2rmvl3J|Wec}?AN)q5JbsK5fk3R~C$Lblnr!v%!T$xb~k zAiVXX1VA_dEINSjNg^QZWK=Ogm}{w<AMqp*2L#P|9CvntgG2$*816heuL}#u%=`ZV zJV1!K8jfL{$69(|cFHwXdsp3>J@Swn@w)k05o%q_yP-{3lhZwtUIW8yD=*(IePY4Q zP*upqywq}4G&7gEA3jWLnqPc`g(&P0jhJte4kdEaPibEA4^bD6>zY4&fh+6f%p}C< zyapGx#n(hexIkjV-krudj6n0A!@P1ovapLv;>f+E^d@k9`6BSKzrYh)mS)0Ig#U{Q z**WY3>%UnYylI-(!OiQ%jdYEm>AAo$f~HvW(?U^5ygc!qbW9^?k4>?10k>cPE!7O$ z$W0)-pUIfy^VMVz8`7mLIdpN$jKvU5!+7<scc1F@T-*+;`7sQx^Efi{dB?cf`=5T* z(K5g#hAc_sWc#j@?GH&#wx`La*Qvdrc9|}_7Ql<0^-CF*j`tq{#SP7EOtka5IM3mu z+c!`yQTF|F%JkR_Y|sqgAFJ{R#(BTb6hvO%tT^-21^?6dbL{wMG5$Vg*amm}bPdN` z*~21Zs}4XpqWvogJj^7%;>VD_-hR58KSL(i!=zoFV%--9>?FQ7gBvvCJ3JA?oRvp9 z(yB@mM;N5ny2wO<8SG!hMwnn9-??MJ{pXs|WFNom&2ncjHs1Ra$9pzME8|t1d3e4v zUO(%N<G5^OC9pP^VD#=U9J%5%H`z(rnr6n{qcIONe!4rdqb7UmksYD#{MVx;rSg@e z7KYsAP<C!oC}qtnYbn!mB2si?_t;76zUCFFE0c@}C{x3;Wu-|f%cwM6LcJ<Ya=1_B zD=DfbUDaeQPG;r|Gq)P{KiG>C+P-5Zn-UwrXj|>eWs14MMlg2FiXnKIYOb~sdIl69 zoY}qHM!;ub_Thzt08n_W@R_1(HTy%%>TGZJ|B;9WUt<noR5%Yi`C#jY=6l{rK!et% z)tc>5$~afODt)^5#z`~01*olhf@n1QmFl!^-YY{0!e+0VOGcB&0!M7vBy;2j%>{^S zxF#4h`+#}vM%~IB>F;D^2l6xct!(R=cGqU*vE_r-YDY{Q=@5Ivskm;L8X5s34EAWK zZaE>UsLASP4sq>(BXwguuDf~HiJKaa>tSAY;zm=fVtLBY@Woz>U1{A)NT^S1V=bB= zN~thErEzT+Y)N+{xf79R@{t!3FaLaCJ<nW5D7L3_>6TNiX#m`{y&vZn`_FGP^WH6< za#l7jj2GwftFF3gC=W`C>qbXx9KX)L4)yJr|G<x~>;Q}Buw$m>#nudV4B}wcAzOYc zL}4LGW&oTmb}>)pE)<zFZq{*)?Wp!S=Cya*I-;@!zim00!FA>tV(fyaRMzj`w$6?H zZ9;6*w)@=Jjl{-gA)iQzj@CD63S8gtuMucyKJhK)!Fv_gn8nw!W5#V(A>WEi=69&e z--v}_d}$(LVfQY>Jit&ct{_QVBR=`6ce)+P+HXPte$ZTv+@6I;B#YbVoq49|E7q>7 zqU|NSG3%Wqd#I^?$TG)XtE;g>8*8@vfB|=(;IOZwx++C~9WKl8S+SYlsOZfZ&w`-V zl(P42w%Uy<VjeALx~udl_Q&h*>(<|1U8R~EtCIQKyLO`jELaXTn)@#hgHq4kB?NW+ z)SLU@)6S`_5=0^bX(fMZcei!q8yptP5kfMk5pxQA83Iq~k11b;o~)iAA|HGPYe=$c zAd&rM;&Sbrw6&W^tF1kmtV#&N+7OO0<3oB$O<TK$WT#?Z7^by~9=p@a)#(qgnLwt- zthbX6RjJOTa3AL*D{bvIs<MfnCp9~wZpW|fcdG4&)Ye={sq9H>4r{b&RTr^B49!kK z#b{snG7alr8vTFjTa#+LhT8JY^O}N|;n`VEjp4f5TCIs>AEuf@%#B8D7)Ft=Fw1AU zV`kT!xHkd5M^jg=U06q$zYU<)R^P>ML-Wu#0r8k&cEQs*^napf_SbrIw-7J8=*~^p zxpt7tf$zcmT3sZmel0~Isx+<=7B2}6<(5+$u`+Shy_g!=@yh6q6SGS!2lL0s2<%sG z-{Sy&00}i1@SJ9Qo))GMZ5E#Gfj+Y@mG88*XC(Q2PiYTZ@RYpq2bQ(RQnyA<H6u1! zsH<uwhuMZKkv3+xP`Ap%{%}Usq1)1@smT2lF^_*20(RTtZtUzXkyFKWO|nznT6Y)C znte_n(%0Gyc{wrZ87IKKf`_yF$qa2Fyw_mvLHpglBQ!Z?tKVDCrqnA&+)VWtGxQ1V zO>2kpSKqZba<*AYm2h;eL91Rr<o(Mz`n!bFnoni{%pYN3HTUEzx>cQfEfe30KULhn zor6=l?++(}(JHd(CE<re(og5&`a1#*%^$vzfF@%&&$}aPy@jJZojT8t)EMIaH@+Bo zpIA^-Vr2q&%}%LU{;@B#%wvROUB%ji34H_XD!x1jAg9S=HTQft#%i8FCjk<uBPonY z4Di5PJk_+D<%wLiMPyav=YQ2;zj~d)iuG(^O>}R}GwF{6MMJKi?D}HJJD6lCIw1t_ zO0-N+*cxlwp~?07fEGb}@7mn9g!1S8TjfJ1Hado0qFK~zF2E3<cXYK3X<i97jV@Qh ziAr$qK93#X?z2j((kuF)5)Ynhy$Q;FpIslxF;3(1f}vHZVA?pzWw<(pHZmsCk&uzg zkLxdUW*H7LZ8?AEx{haV-sYXEysmR{UBMEo_9RH+H!Q1P?0V+5PR9$2P+lzL+9gFy zlp-z9f)#MwcsOo&uXI#@mWk-T95cDca^o>)tR<7v4rO1`CDhZM-<D*U%zxpwh|fjU z8FESasza-?oH`X_{wdoKR-^~R)r);2pLd9O4!f?gT8AfhuC+n6dhqg8@QEqD=-jz1 z%e-^oZgl%dhoB%~b1PrLj=rO#T$=W*Is8pfQ#d=iURg(wHS&WU%wOaViL;nBHI}!K z8QrerlSw{a6`?0l>lp4-7aHs}l0_rc^8|KW8rwL;ee<a24FJXIk<an==-~JZX)&)j z?3fuZEWLH9^n6PeEwFcI?#tYbZ;I)~WAQ+HUN}Cl6rJ);Sy41CVFiH!)Pu{Z5+R{m z<?7a!8Og7w)~kagmZ5Vc$8689vP;xU+rb#5%B5~unblkt$)>ydn(dE*<#bG-j#gj2 zQ6U_%SLg4q&To=ScNEkDd!F)~am`;4#}#`Tkw0BdgxQ4Qq0Jlgcr+9wT^rb8-ma2F z`3^Jf4oIZH$5_&PhyUK<zqfsx#&J<y7x)|rA5J2UC2&#>j;+o2v!&^1pTD}r+7XsG zc%#><uC<d=%sWLAV`!7U*@Nmp-rsoB*URI`SEF*`ZBANnq+?tKL%gk5bf0nzCx_Mg z;{65|a%57W`RFo!k<@9g={rU}3a0a2S>G?xx0s;m4R*5;SO#k|U;RyQ7FNkE1bS?* z$T`#RJ+#QK3}MW8R*ciwd|r+$Cn5RJ9r90=<wd6)y5ow(aC*M!au=jczUjfaIfv=k z{d4G-#XH-W4r9)T#xaZT<j*pFeUq<>aR=BRzR-w@asRR(gDb|pWIs;X-1Zcm|EQ9j z8<l++*};A3g-k*l7SYTN9}#;xv6bUOwzFs0-J)+q!D@52FRZ)EBKfB#U|j5u%jl^; z)K7V|SWbqB&F~X4&}W&DGS9Qno7>fNIZfxAziv|OBgA42@x;yjpC)CFO}XhHDVtLj zk)sHXcGIZLcaXVa+-TdUQ#SjQVW2Hhi&3sQ<|efuF<EPW>XgmN%Fx|r2w|9Nj+vwk zl6rG9q$tBbZ&z=g+oKEv$N+MBl_)a>VF8mt1k{3?KVA7Bv-z(&p#1*^h}R<BQUx42 zBe>V5ZWgaC-`vs0Ph`@K<`<V(9NGr~Y96F_nZe(;>8~=;b2M+YfqL^rwVH}e;E8qu z=Z@D5OL(S>M51eQ-?s0Q?dE|3c(3D9@k{Ls_1bLRd`->JX=nP<12&F5ny0W|yaTYg zo?4o3eM!`AesS%5Z^M{&9;_U(>6#ZLHjN-O!=Xz-^AEjg`5Xp;DR~}Z#^oeL8v{=y z*XBn-g);>=4`MAyC2Fm5wW+Rxva*<BwmFegmvNb&V7u|TZmU>45s=>Ld)Ys~bRKk* z{?L`UsNmyHq@7waqU%-hO|eqCLRYMQgKGj<#TTtt>J(BnnzLe~+1yWSbmAHodJB^i zsgPTC3`^#jFFJU&+ygYY2~nnlgj+~(V&qZXo2-^z&ADtYQ}_ye47v1zY2Ip1N2{}9 zHRO*w<GpP79h<t}w4=pYvHC3=YO*?=j#F5C?oM}ow^uB`jO8kp-*|H^GC;BBPHBGo zMS?C#a_)XelIE9bf4}~u(TSENW)I(9f#Ot9mKD<)3V23f8do0ntvVe8>Y#(t=`5&h zjG2e_v~`fu5q@9s3wBt1Wp3aXK-mePG&EliK(ss-ZPIjpd73VGU~LRDx|(u}XvbaD zox4QL;xpO)?lMo<-zMjx^ok9%nqS%9HuE!nq5qh}mU<3!Id#-IcP>kpCn`#3V8Y9z z!&k;Ak%$!zIOWwj7nf^6HO`N58$E?CSr&>Jm2e84iw4G&LMm4|ouzJse?b9{c_Hpt zGCkuTK4LU4o*~{R2Nf+{PzpO*c~xdKzt&dDg5pxdXH>>LQU8kr+^s|B@g!t;N^Eo1 zD?MgN>{FEczS?P&82Tt5tcN1CKQPw5CD`ff@h3<5`;vb~X-SEuael#qZ}}G#<29-% zW<N=`kfu0hH##?J->@7;yrr@B>tIKw8^h-ZBY&6tkJa9+UFe|)n46pL(!u@wH*{O# zCGcS6WmCcO)@>n^o`xm^pZrSgK9hK4K+IMw;<=jOhbva6pdn^e{SKPF3v4Yi!MLhj zH!(TN)a4_=Eay91<Kd!eV^56rL!pteka>D3*z&cJ&zq&UNFsz|G{O4k&ut>|{HAz? z9FbsT`-DjLXpYKA_E;{uEs`m~n+N8#&p2prX!cEjEsij9(A-O0Yy(_Do7(&5|3v^j z1PmEht8O{Hd7$=`W0(8UXTRz&?~uU^WiQhsYo^hf>>du<iPgBlowil%Jl%&w{5CYd z3U=+Js%zom4AwEQ9BVQd<kF7mWR`^ocx3lIztGQ6jTLZhxj53jW@5jNu`9zTqP_QG z)PECu`vfjz*)1nWPQmQ&y;FPx@Pgq>d!S2sQg(KvyD0>>jM;NrBc!)&7u@Ju$$u6` z<dRp!-$7A(4)xVamCnPG=q>Jh<p5=ZVS!aM5{wGGbG2>(R@477>6oB|^t%GU07!yv zx*Xju7{6z-h<RfjOZgA0zz!j^b~6i>PRn3!8-HM~5K5H9lGF*DC-IbGhBgoZ4#||1 zzL=mb{W(3PgoB-igNGWLOIfS<Q=uKFWCh&$o$1Z3-u$od&qP|mic81@jbAboLJA8p z{UXBH&WnA^XI_k*8aODHFs)zYO^v$Wn^hSn!zimDGf6Qo@C<GhZQ9LBCc$236DBV0 zt~aPYVe)<s9pX%0+S*4+60v|`1n30b9bgn|Hm|sW^IGyht!AK|SYxhZL7A<CW*Q%n zU9-)@-?6;(khES~&8m6K{|;)h{CM+gWy)`jrY@$3S#0N=@JS?Y>rR7Cjyv5P{gvY^ zav)mMD>_J_HnuB5o8IDmlH)C2t3kyR?W#7}Dj33-CCCS8@7Z;fss`&QRgGn;=$n}2 z&^h%hDva%x=a@7~m}zV*^_Sxu-ADor%|B~oJ>P@x?H(|s(1^vQ$68aY=Aon~wRdoP zDK-q2I==EW$d%Z4T0Pe(FWC2FU?k&toVung#ih%lLSbHQPmDleB?&)t3yQ(s7ILH{ z>Gnxy!*S}FR_e;k*s|K?7UCR8W9P~Fvz0g=0SD~_OohH&w<;atKdeRQxUDZSuRrr{ zm!w^hSDb{oBtSB+e%wCiy8f!|9tO|jxDMAaR?yQvKfd#=7_^4lBlA+RhC2oDblem@ zXG(qrj?O<=_3AUYvIA~P0B5VVl%dcO;kjK{Q;9rhCMahkKx7WG%_<v{uL=Jd1tIF2 zm{4DTa`AqkqvD)|st%Y(5~}+Amrhj&%&)zwkPlAn8c2DjsS8)Q3vq`=i@V4c1C#d| z2NgTuF@a(Y%@y0@+x^)TA8Lfozd=hT`!<#Eg6RDtEDgE4@?bTbHo@0)L6$G&!Ytpx zt`mIqf6DT$>M_B$@3Ac3)a3EL^llS;_wirGl<~f)sS|uR5*J-I*>`ZwcqEl4@LDn6 zw<UYLZ|=nLz6{d$&z<6Xg1BVTcda51-?P&u_$DqK?<>4vitl&*CivFz8=~C}MdN+j z&z|7(e`ma}|Ii7(ZoUk9CNkCM>z#+Ot_7i~1@ntao**X4*HdmHajQ7LRCIk8U&{1r zCctwjUAo-{QytEq6Sae=uD&#BCr(%tT2ioV%94VcicX&CRqD97pHy15B-yw7w-bH7 z6DRrhoixdJV|Pq$*Y`M9#!MzKbLJG^XxlaQMa4lwS;CDROW}-2ZaS;RGaKxgmTbBZ zN~vr(jBStd6K7o;oUwTi^m)*9X=RntY{Whr@yW++9Y`TOo9@<Cxm_G4Aw2$n(4`9& zGUv|u6X`SPPg8u{h}9$01bWcJI)aH~Z59cVR*u`Zeu}S4cr2DYgT>2<M^XP(+69LV ziUf8%pq>=ZX0jLa1l|^@&<vX=PyUkUrE<i-A5h1v%V%UZt<LVBSduI-FluwJIliC| zXM?+1$DAqOVWHD1ZySQuaC7B{oT`(CgnAz8b~?AtiqNf`NZU5hfyk_6Gxj<5iQBbv z973pA(-iN*6}Ah@knqIGMSi`|c?&05M4xUqBNgrRMWWF|s_Ivr%7GfWTiuV`ZR20O zTOO7C*&VqD(ySW`hxePDw${oQ990W9p!A&EzRlL=C9!_95!v^Hnd(tJFH)Q6w|T@b zz6uwjnF$lJYI5hv_-F!?!Q!`?xra5&*yX3Ct+rox*nYic?%<LF?r1cB9fodhcl9v* zbZl7WXT)ZO&r`&Gwp^txXMMAotDUk9W+S;`W!$N71~HLnv-qhmJ902{!L<x|x=Ug? z&3KhVFJ+bOm|btTwBx<XY(d&XM)W)4H=%4T8<n03UTtVTubxGLM0Kx8OGwn+XiG!F zDfKvkhUPDxCg*#OwHoW&KHE3lm+PCrU;Q_m<#Wy*ooxE2Gc1GO<N1VTe_=~!?W=63 z?X70v6Kx&qFiW-viTDQ7_Cb;iF@5o&{rQG|`flP*P27Mtnee{%D^Mw<Vlr&RgHI?z zIK*_d5$kM(u!#Be?-Z#N_J~x7_Ao#E=9e8P07mk1%;HPF?6AT^k*wu%1m<Tk6S7)} zOib_p_4GkrdN8r18AT(yIh%Vfr?p3H^LMCuubD<OZ#Nw~Dn$)6ngyiT)$UdJJ#h?t zmD^LL!764x|1!%G@V+AWcO`Md_}$K_I%G&z4F6B%3^>8&(8}n{72`s`L-;*$X5OMD z%Sws@%RRr79!Z^ccYT9Hmp5i7_tx=j{_%`(8oY8#H{xr|($npZ1%%H+9xiL?+A%q^ zE;$UKP0qyb^>2U#G<QB!s2`HxuT_3I<U41CR#kqORCYz>hv%oQUB=p69lGl3(2QnQ z-dFkTuF4O4rQM!szrU#b@bt2x$`6x6H&#A-M1k4O&yZ3(d5Gx%ej6tb@-@HaL|{_9 zolX*!L?4=E7L07fzVF0#QS7f`vAdjD^|$%^#70{Aa=M=x>wXKIV%z=cnHRpS+Fm!s zl&hO+a||(8p&kWt=t-l=&DT&%-E22yKs=>e^KhjUx+%TmDcze-Rmw6q<P+IlsA z#R}C`xG8TWro2ZA4fbe$laGXMud|so>!ZHj?LRoP)wB5*6w>t7v#A-eT_!0MCY7aD zeAqK|wzLXQZyC02E46VZ*;nRG@W#w<*`_ToZ9A9{zfSS@DE_gr1H-+Y>MBML44=-6 zbL6_rnv={T+U4<DExsUxa~C~NX*qA*JgHJ!jnu`yZRxkf+bUL_S5apSGkpnk=>_`) zdW`%($jeiC)`noH*7h8q|KXptopmpHdmNofxT-6W+>I>W(suzjB*kmjl$JU8OgksU zD;PgEO<QweK}ordP^9np@-V7P^msnP<I5bI)p|Nd2$3*$QLWF{TZ_51@#0n>1H)LV zwrm&Z9bV^_hMYD}wsk<LW1&?7^lmQOpVLV52>S9B5LG4qfdk41cE0a<G_*%RTY0wR z<=*Zcd8m0U068YymiE1C`54<Ht?Cf<*7YZgq`9WUSAgU=W!oqsJm|PxCfjT4EXn>h z*QJV;gOWn$lO0M2DIY8uwZfd(wkn}WrHWkd6v5builqDxMS?0akRl5!SDu1yrxZ0J z*Ra14l<dgk{Q|k6_S)oDlP$qgY+))8$s1xu66Wxj=rq$MwEREztT}^b>bC)7!Lcb} zC;+b--dH<Y#*Xb7?nhkX#MWdxAt$jh0q^SMPh0$Md{W&ecec)f@<JACLp?dxC4V}p z<&<q(6DHwmHI+|O^zN6`&LniD_6GAq0yWu#*p<(IQSo7N+U?j*=!m=>+Yr5}L?TRI z*>n7cs5V4IkB%OXQaB&14j5;5f}bmihpI-E0d4&SR>C8^)EY|npW8V<{DMVT#lvVW zSHmS3*)78|E!NE)IFuZ*2Wz3yZ{g;%6R25uJbJ$jpiFMT@<mI+OZ-d2OXgD}@E@zb z+~sf<6_U@MF`IP8SUWp!Ivl-@6&{=-w-uQ+#C)Ieb6_s!nL|eTP=JKS3sT;kx>fii zzxdr)k&4@}GL=_x+n}UyE@cp#frqhWTTgNmd`BWSZKQSq3MT=$n;HWT0=RN$v#sB^ z<FNh$c392kKihU8YX1*yZvr1>b^VP`!URGHBw&K5paTX(LAIbG5DjDjk!2tR1VN1? zAz&bBG9xHkFhmItv1p~$7AkRRX={H)i#o(DGHK#MEfs#63bm-T-f^Oh8X-bt-tYI^ z=XquV*ya8IUq6z0?mg#j=bpQrd+s@*V03DzVm+jTP8jL9ys&b8FA56b%wyJk9P@C< z%T5f<i^uDTAY5vNqR!fo1yH?LanTa0S=?4Jp@%oFCZhwphK<O$G8mif4Z{B23+UY= zcGq`BUC??Jje+0~+(BS#cw@$S=HK;A&b-Qob^|2cl06jarE$Z%c+&81R&XKca2ZO* zh-y?E^{}Ezg7n>YG=c!zA*oWkP%e<Z#G~2Z6nrRrNV3OKfw56Wb8xf-xeg(aLXtXD z8Z%RzJ?4U-Z4vq1!~ERL&%a=yCA;g1(mU}N!v9&@W^YbPLDTT3QT0I*ls*WbQ~131 zh_?qsM~#XPGlKCN=L@MJ+8N`44--}(XI^9;+`k}?p}^=0m61mE9l8s*eL5#xXxced z2qy77?^dk8)Zyuh?{1z(ohx(<NOq{qI@NlxZFNQp2KpXkR<UM)!`nl)zPR!U1yeB% zbc5{&OrH@XOJ5u2!E9KmRRf*}hjYJt5Uh(Nj(?ft0w(!vZ+mFLLWoEIBU;X`1`!X7 z6h%#+3D3D&Pr^6_8%|B?1STEoEWp(lub*E=_0)4OK<Gi{d7Y$aQa|SWeh_w78&wZv zfcc5*HDKcJbUrP((}?=YrE^R0TadS6ylZ;F%B7wnOf@TDSVUiWa6*_pxAwT4tUrY& zC)S_Kiu$jc;wT!2KWgGp>QK(aUjVuqNhxze2N$BCNyWt_tMCX4hx&r0WfXd9tDdNW z1C~q5Qpb$QFD}Mi4*DhG#d`OgA~%*$vz#U<W}>tFn6%`TbY-!pZ*_m+V25!S(!NJn z^Z+&(Y}=__v%Ljn_vDo3ty-B=PzIZ#<6RM}KGynD%*YVVrVL(f&U3iGsD|SDS2&DA zjP0FHV*#y3SIF@pEKpG(7neF*F-$Wnca^SOquN+-I<)aLw1$ekF{%|ed1qC4@$tqi z1+nUJRQULMRJi#0??Q#ui%+GVP`O9g!VpwFZ|2v*Vc40+m5qnDZ>;+c81*})KIYhH zH5v=4Oy-)(pR%hHUTlOmS~%Z+8<1}j@-3n`et8`4f+3su;v>vVwIa)sync+l5?*W; zH8P2)l8E}(k0thidO~b<zrxBhU9ePYrz2QA$S1tp%D^)9ACgnj4EZ-{u$}UFAxIqz zz6zgZAXjWNzQnY+u0JI&b1S&iQ1SweEGU^B1NS++S45gRgkT6VV7%vmX&(&3jR(Jj zA;(bQmna?^BhN3>9jfLxRBjL<<#m!FpRw=|#6$QFE;+DF*sgxTFFYwV<8raVXjcy* z5~#UJ3{WQm?q>N}fKOhzY{cpV86=|$38m3RNKR(N`|1Pb)6^5VbC5TA=IQ<hluz72 zsFFW06w718(f?KendfhRPhbxL+KbBmevWP5OQ(A`{<n1c%bzu!o{peX!LMyPEtU-B zNw`pH3pZ~<r3!utmG0)3rqW&bw5c>r;)O~#;*%}9mG5;mmC^|fQ|Wb5X)P!hNu_+0 zPAYZ$iiC*%T_-AS1dw??@En1E|DR4vFQ^2$;gg)D8e_;UQGBcZeg7RsR$QmgKCkbn zp5lm~8^P_!LqBhNb^oc5e_PH3xASgT&cr#qU-d;-x}8ypd!lYd{A_UU0d23l8RG^_ z+YK|J(Wm+XOirTT#?^;Y_hHP&a3_edPxrf(6H^>(yKkHbXJeShovBA4rJJ7OWZFjc zpoP}UXfoncjJYXJwH%G-l*h^3sGnEeID1a$ZfEG)P_ja!tGiaubKd6P7W#oRG<ptH z+gcC_yp0V<G2Bz@E7OPtE!>CE_{uaw5vW1{!ck`m{$Pt>G>9=5EeFSox{wvYiAh1l z#Ex(=Vs%7BA|sX}q9!vX7JI?|NTPcDqCM1vFa!9F=Vgg;fEabW(@?X3f3o?K`jgEY z8z^-ky($~pQjg4C9;<GHN|ammJ1ncqNL@iDg&i0C#Jge8GczU8tv);?7*1mm8sJQE zt1Kij{1Dv;{bz5Un-aAdEj*%HK?(HFFm)2Q(U2_+sz4uzxw3v0Yf-+Zw_1l9Rkp)n z8QcnbqJJNSErjS3%9}G@rEqKe*d}W?j5~`%YQVF+&PJTR_wcJkkq&!ruk<@HJ@uM` zM=?236ZU%tRIG^_@4awKMzk7@F@dV|kPMD;*pIH;6OqL?kYhu-(H~jxJby^}fMZ~- zYOJdVno2{N_Re${Vt7g~!l>~F8ZpmUFUA~>MT>4+1X4S4XJ*JR+9zl0MF?S+pS!Wa z*@|a8WYD70Dy-~V@kiYW61tU#goL2eQw)~O0Q<RBcSKdThdc{+!_D_A$Tu3>@Xwb! za{2Usc{g0cHmZvR^Ple`v8wzo<Qc)o7vK-+yxh<sqd8aA0*c$63pSo^O>j8Y^}zJf zpdLa01iORd-&3Q}6uhlKs>OQqG6mZSoV<%^DRU-{MU(HDiZfO*Zao~1yJ(EM*xFUd z+On~s9hqrS*>-;FbIgeQt)8o?>Oic!$Vom8qBhlj)aUArrx~$sa7`5x)odq{ew?%v zH8La?)!UEgU~gY0vQycxXn|G-e;d&w*8rfiP=^rj4~)h<8~i-toJe^B+LWO!xY@4& z^t$L{#j!57V`-EPisrjtJYd%z>kZzZv5J@$<I$%zSx~2{n}}T1_9rmvvV8n*%6d6H zro!Rdi<DxBtzE4FBf(S~YWxHFI>3v8Lis${lyw-b2QT^D>a{E}j(Uk20pg@JVOxNm z&Oh)l#@B$%)T6)sPIQ}~B6*bIQP0q<N^a36sUw$f^$O0?dTRn53z0-bso8%a|3rB{ zPDjGn%}6*48L5YXiZeV`^;Wmq31tKDew=SO;UfXJIo&|+f|GZUR6VjARJF}66#W)Z z&_hpOYn~y-K4Jt-x|exZ=HVDEdljD3#q@TT*hYXPR>u!ICqAr+T_j$l%FEM6X<W*E zW|S|TpSO%#-5GGPwhS`eS$8gnoXIMu4{*@WS*w?MGN3bL=3wrBTG`L_=02qdRv>*V zg-r~XDb;|qre45tkit}%z)LNVO7^G`FS$~XTHV?T9?fmn>(-@p&;z@kdWiY&Av&2i zT@xm|yz$HLRb_}N#FbAsbq6{mh*{0ttOQXGa#vpPkUy~ImjJfPC8Ama6&4$<4@%=% z_ypM6ADAm>CXrER&M_4B&0m?H#?3ZbX<ayc^CYVB0YumD;*_Fl!KhP`h(5n4X)78q z<Sq#9TdP+&t4^T*x3W#2{stywk9Z;_@=bb5kaFTt4$m7<kS>^t0ue-cJY*Z$P8>^O z)ZNGv#Wkw!C=NOCDEVtvgZe6Ze|5kdZ^|~2UcLBW_2L7@2PXMLhDCl5r?7H$T(md7 zDXYB;_Wyx5F=X)V#CP?KR&J=X+E7d~bSikweOk<0C2V>EXfSBQS9Ptb(TuD?Bn}CT zI%G!OD^bT7Rc}Tum8heP`mGr?SE69|rB&T)Mop3^m|=$vA~R})L>*+5$Bg159I?P! z)f-=IO$erBvO1d5Ig4-*7B;2FMMJqUx9Fg>TCC}09Z*|fUV*W@?N}<K?m#ROCA^p( z3(-MkF_;<KIJauX>J2L3hV&@Rk~f2854($w%O(#>(AdAvI3~)dN==59o8VR7hgZ3- z#R272jjn!-XKJ!+>S}gzV7btrPV8e$9{wFFXrRJTsG2|U;#1^d8~DBe%|5geM>+g~ z9}@5HHeOe-BYj>_4y{IF7NNOpOoFgcfdJ$`ME?*?)oc$7pmIM$KNVsJ3)M346lj{~ zlB=g9nKrO|bsete^cE}-1M+h-@lzCJUPeQQ;_g`E2BRq^z3<lNapo%@!fdjg9Pk@M z+&7Ee^$ufZET;cSIA~A+Iyv5|b>I*x82B^zT;+d<P07~$blk)JoO-#m0MAb5ku?~n zzoYT3UPD6yKSMfS41&ndm=l}u;?1!W{_MTR*VT%0PV>Z0^CV95^b1~=@M1=s^mQ-^ zpYi&$J3f2Kr>;`)W>!7jnU;73R*tTX8HrKBaR8<DW*B;>0LE5lBn5Fx%TIGolOG3O zZ9|i8C+2va8EA|vxNSK_Pt{;X_ye^)nv3@0J4YQv;7M+6i{6lMJ;U7HLNajnzF=NK z8Ke@B%jPemS)3Vp<#*A?-?GAc@Rt_>^uRD5q%i;McyNk*ZN=|<_}7YmyiPt_*JJ2q zQ~x7fkAnlI{y)+6a5{QB+6PT_#8Ha^4~>@HTafG+d;L^LFGge(Ln&26BZ-dHsA+db zy7S;ItdHZ4@lzc=7{0mSo=m(BaXR`$B{?3z3F#JKmg3)VU=&S2s<|_egs9Nz2nP~D z60OPMB;2ChxxdqYI7Mzi&pvnYp0vl@Oz(;n_lOe=xd(mySig-QQ>gL!$B8}mPl%Zg zz3+q{*YjLQ8EUIc@4Om~dm60JMSX&w%J%EmPk<&_7an9F?~LsMz*_*gF;pJL3bjxj zTo2Vy9323Keh3d+{<>qRm%0wNL@FB+DJA11$TxI@M~od;zJBnCah9y;n7Kwk2MXc} zJ;v9G3FFVV*&~=+*Sj&GXteSf<U(CNznY3X#UIT}o1ox<eKIW7YZpbn*oU|=6J0j! z!=Pi@nAJk9Hf`lN6Hs-(;tboW_Tw-Gy~Yc~)UA4ShHTH$Ifc9)t^k(qpArxHT$r2G z6Vs_AXwHl80!`-T!%%&L|KG<kgZ&c+4CvPtp@ueI8}P7X=&5fkR!V=MjJW1D3R4~a zBb`$5`=8rc%H^wezHODX-H}$zAm6^MoO+Zw8yno%&O-9npkmj;ZOhAOJC2{d0aI5n zq7`qa5fRIXzK8%}gIva`>e-;2h^cubWd|3v2K6u#97TefO%kPQp}@GYVGp3_V>g_w z(86IxQNfbCrskFNX*lF8ImTb8Z{%0UP$B3LIZYiRoc$=hplQi??#3}i_S^)Hd`Mk~ z*#J_21&g5}2Hq4|jokA=uM=8wEqdF2`Hw9AU}wGauoc2Kj~WH)qer<T7xm9qY#?UE z%6cabexG1A_i^;dRG8Q_IbMM>;h26+lamgTR=65V?~gj-X8?axOdz6D8;~<2cc3u% z|JjNDv=_zTb%C8f;|fQnY*F3kQZEJ%di52e7z&t(HmHujlM~xj<}Pg6AHcF=v&>Zh zGwDBeNjB<3{Q3hES&HdE$dW%(_Z;_K*3GND7n3V2vkz#r04L6=B-O(<;mn7h*c19# z5&z?q{wlgnv#Jp68~Dplxk1sJ-vPhJ=Jz<t$I`LbDw}t3gC-XgLM&~nw-0ial(_~? zD#Rt59b?~%$vqqtcU|1L!%Eo70^CQd`Cxp?DU4>Hf?Af5<5cNrEo_abi2zBY`Viyg zR=*l{E^d<Gx>TZ#`<&o{cZ|s{<In1)LuW!^ej-nb+LBfjdzVI`VN6p^!UkUMH^HYC z@7a8cQ~24OItjAn&U`AyJGEZ6(tLVsyTzF#{sVT%;?wJYY|9Gowt?V>#`IY5Tf1i0 zv1pCSobA<<$*$WTvDp<dVRl72vMYWr<+KE@<&T>6kIsU@btsDQpKK>f1<=P4j5{H4 z9Q=$kA0Kop_iQpQjjDuoygQIwWqd-$ZBxch8vYJJj~eW5aZb^vKw<JL!O=WU55%uO zuz@8hTNZ2a(7)ne$O4-o<@3XPrO21!@JXkEkUnj3ra+Kn%@L;I)EPM3D@&*}>nD-a zKk;KLWKsX6M{Mf<-3AKXBB=iYI397B#;V;=o{X>NqeBu}Q}|L%Zy|Jbsf%PicDysW zTaY*7Jt)o}xc9NM$nE_}nA{)DI+xtVXoWibktTQl9VWSN<;b*_p?N?dx$AalazBS( ze;|=1g~<)3)@#haqPHy@=i3uLE-==`8{R}%Ht&P;W3Q@^H?DGBEH>QS7GqMmta4ok z^ecru-9>KjCFgR#Dw2gK2ytK436G0<=AMf?A+_Vkh{tdcSfAuI^2w;Gkf*PSk&kTT zG&=|g^sBUK@kv}s!(_5{vn0~q`K*U$HpkWSN3EU>Pii|5r@r_pCN=neyN!1W_K7^$ zKM;j+XU%I_|AWKq5fw*jiFndHe()G9>uL&q2g$-VD15_z-kD6Vd6;kiLgC+u40o)D zQs~+Cw6+X`M4sPV3~NK!lJ~<+m~nF=M0L3T(j>DXMh0Ann6LtY>51@v(et7o!Q~XL zA}Z3ZlLwe_Cnn8EM0xeM`OPRVqg;#%_BAHC+{PprZ<;jJ4GHN@{Z((|d7C|c#0D1S zWBSoiyWy3MSkzA~(&FSfq7rHc-l1I7B3zkuRWIowQr92I!h`6jBf(3IY&0Mn#b%?} znf=HZP3mVnVcA_#6pJLtPdU&if8aKBOHeC+;I%(@MVQh<<l9JJNn4U>H|s<?{8>h) zzKh>jPjc9s<sw$%n@7K+JF)%p#w`Qsp(n!UBIb6<RPe`(vj4_^B6h3j)@BG(52@qe z76X1Z*%z&N2XLvp^f9_stnC*X>5WH2%P<BTGy8=WWz6(`3YHSN2yYXajVbkhey2s< z91_*&84nHLx&w&y9mOBDehj9A+;$(M)zv6c&;(}mOeAg#(dL_Ij8R?BLQ5iAJJCj& zXpB*R!z7<0Ic@3bB1-Jff$}uei=JRGvY_Dv_apd=(Yij2Q9GFfWaMtiW#4ch)Quz7 z8^nTRM#iY$fI^<j8e_&GNtF3E>G$Mj$kawLn=`PCb9Oe<nQ~)fHu+{Y*GFViY-Tf- z*}TYX%=QdKMBO6h@xN&D6AW6QK?D^OR7Vhl7U*(<DhPU<AO<Z^3PFz$w22@FEzn?s z_7Jp;AO<ba5P}X6G?O3(EzlJNDS}c7V$cE&B`EfBfcg={U}R@ZB)C7pdDNK(b1+6F zVi6JMGMOWtXrqXB1IYL!gE?Dz39xP|qhCVw=B|-B_h*uP!n&C`Ge*6@snS|#UIrh5 zQ}sEf7!ZHp*AHXN@*HE^=ip(64-oJp<2MGsV!zc4cfl{D^EPY>^chM`SU3F6EaAh5 za)I+qBWdTtow$jE6NiIyGUo=dA5{Y1=quqD90Fp-vAnquL?9?(UXkTM8`07`WEw~( z?um?JIWtRe&=-p$IvvkRa?;0RR@+<z;#kH7f`2a5f|)sWN=X>kUb~!5P@OO5x|t;z z^5_(wQWoQ^^OY5c8y?u2klI>uaKXjx4t%|r%3%O<^vNZw3rGfmk+wN`cVnYo$a9sR ziRAX}zFqb_6uC8ik#4$U>mCKvw;O-dS73}B`80YqV5eT^W9-q0*f$v4z}QARR(nXR zJIvS$uw7-^L0~yN*XPvo!-$m}>y8t?jj3R=tM)J;>I+)&n$e-*?Sz*C9vq~r@U~8p zg)FTI!5NDP$>S*V_;q9+@wLcfIP$PLx*ECiqHn{G$jpEJAr~MrGfp_{um9J){O|Y| zi$yN3Z>w=ztre(Z9kux+nzk2{sUIdXMs??_%Vu77cTrwEUd4USK;y1hUKhqrxSH=^ zyuB&JiNYPPlV_}>7`b@I`Pvpl;%ZlJ1?~MG-<O)c2R;DNtc#Kk7`rpwMzui?r<L>^ z_dfTg9jfA?h-;;f03ltkKq3A>)q^HoEuGF0;6-pb*W>~`+w<b8K|iyzRD`XU+F=m~ zc~;xulNFSEQ{?|oY^u2j?DJ$qB}LRDsz2&>oN=)8*t1rxy9UgJgRr*;({(|A8_h6~ zj%D}ln*^89t;kN!J~>hQ(ES@2cNB5hpDlifpmsHStlTqC<+*0C{>DS5R)|?)tqGEP zn04c;CDnT%F9TX3z8W?XOn-yJn>?>GPMiANMTxa3Ou7h7ppb|>rxH+_KQN=loLnus z5jOSaj5+wR`4i#X&f)1ZtT5-=sW<0F;&MBr<tk!p3_7XJ)jT$}R?mPUHQvt3wjb?& z1SBG9yZ<7Rw5)+9t&?;CX&0$MAOp8S37g^}+$a5vcfvH?fqb-wx-T$wn{K5(<>7HX z8cCC6(Q9u<5PPRHsonwlD>TM?L1WgZQO2Rl&!||h?n7x1cWbn3Deh*1&{%Iuc<<*z zP1Uy#@`&_lw4HJ)Qu0dh*lS!FUfPP0KrNasY8Hfc7$va~jRP9&TIr9S<vk8hKsev< z;g>MNyf7mi0xu&acxg2DNo+8AsZG7O4e_nnIDxrqZ1gtu6w%+C#>)SJ+=i6H)k!Ss znp7X5GQu}DsoK;Jkc9eik=ZPkxK_0f(;96A{z}r}Ev6ZMOu|Y%W`?T~2LGMKkMQpc z8+2Mw3UBIieH6*Bttt<27@JVPWv9FW506{2K2@8>iA;3zxd~d-C^NxYCcvvx@cvO% zc^%q^3o5n$S@c(&&%-V$g#QVf%@YwrTWmcsCxB#{-CYvsQ0-uN`2XC3w6=E_&cj$Q ztog$9?UHBh-R~-(@d;O+YY<c;2f6GCL@eB&-xInXJE(qyJqyUF=%=Mq9x_gBzoC)S z&T4cy$Hvax=N}u2EP=5xTy;gaaN0@O^oX!j=lP}rcsv~^Y`R-B9Cmc-0T6)`6I5L6 zNoc-g*bd%%9?O?CkF~1_Ae_u&;5{3?T@5ArA@Cl2DY1KU+fkJ@X3B(3-K8+hS@zV| zuD-$AC%hMt%|{Z~rqVEjk@x;Ayw<9&Hp8z=xJ3;x!_P`ssh(!IR>H^6;>9-g%_ZP9 zv0b5lx|PMAjnb;#wNP5ss`H|>sNY#AEo$z0QIy(hp(r&PC>X8oc?Kjzd|%P3E**^B zM4WFgI#KQ462YTSAqJJI<CaNnGRTwrABdQWWj;MG|G+VMm<P>yR&)~dTW`#>^443n zU3-6JF^_7!%A6J++=L=uL-)u<N0Uk&27q7MS6LtJt~-D<m^IWAR0_Y8TT0Vg>zV;k zW2KR;N`Zwy^)~f4d@Nj`+TW6?ZV0mKPLww)U+1i<CvxE-inyTnf^35c*cEKV6aofT zr!f@mq5G09TyOtZ0OAk)=Ke^s2whnDk@&}P%WuBfx7Tjo=2AOY7Vj~r97j?6uPs7g z%MfAY;0ZktSdVg)MlJ^bU)_oSQDNbKJdurH+@VNm@xM$hV%lN^GU0T*a=0wvc_ieW z`a74bfA;b`6Y3~pw6{%tU9Cq)XOvbo%tC2Z2Z2I2;jN^57aUG$#OpWcl%<;^SSy6K zqAYDI`bs462bNZyLqiv67Phrx&P^glkK`_szvTU*t@GP%3c=v|6xU)<#}+$zG|vc+ zpXlRSUbLvoo{oamZQmoTU(*AkZnbu^$oAz;Ec=dnJA-JICtT!trC#Un+j;01_U*xE ztiG*GTP=dBzWWs7AcU3IczurHYJC7Gz^>;4t$Fg7!r#Jzt5GlA^>rK!<`%A9rIX&= z!gcQYtH}|1>YFJ;L%Kc{nXv22G0<>ze*?RIss0{wZr8V}oD0paZ&mFW`F6h=x?jis z7IgdJ{Sp28KH6mW>ue-}{zK(C{hE#jp0n>gi^i5M$r3y$D#2?y`j{zSmS5m1C@eJ9 zpk!=ahP=+<k<NMPeV)kn^xGqI;OztH*g41140~%IG4QUGfzqL}t`use$Tqpt{<cGn zhOZ4y5{Fd6B{Ge6kS1%YB4`ps43g^kA`LSI^q=lCX(HkRX@~24?Z_`%c6S8h0Y$gv z4a^^WM|F@c%TJlj`3#*akDuU(UEACkWpdxX-$gc%yJ5{<Q^`BBJ{O{ivXz4kB4M}g zoY7!T0}HjiGwV?AqX-B!H-JlF@PpHua@u(evhwIvlezOSr>h1I>12jF<?;}@5Rt0o z3KABVZwFC9mA#2pI1YB6e~9)+D7V0Gt0egWvdn;}v3up|*n|f?7@%5#{4ZZp1=kBR zF3bR%_ct1|4&cK34V=%~nfs$}qOH&?I)<a5Aazr3lBM5<VUfe?{v{avxd$P!Ohf_p zR9}yjKvqjPaoijh>T1%~2yd93S_H5^@QVtx_Rm^wuFuT_K%jGZb47S20i1ITu7&ZA z^sbe(%DKc_?kQQ}T0!%uOJVa1DyjNRh~3?wCFiE49az47$=5#ZB|oUkNSsJURuruC zn&nWKPh40uTZ$)uwoJszL+~MmVx1^2D#wdfPl>K0C#Av?5ibecN|RSwN*93=M;VRO zrDTbnw^bJ!i7LhcmjLE(#TVw?UBYKWRy^xSt-E3?;|TmEB`a1y$;ND{&WAD}9UpEj z^QRuBjt{riDmMb(mbtM$IzC)5@hO|o@%hp!#)Zoax2kh|xK)hjh$}B!5~gd}60tT< znAIoCpdw_N=IKOV#+Q_7n?P(6>B~6&<P~cg@HASqO6w>xPu6+WvU~H&@^!4pGc22G zEu#AywzZS{vNbtWq)nEkY0#_O@x2tk6Gy}@#{24X%;0z^2S4|)3`xBXuQHnIN|8>z zOAtKg#_HgqjnMh}L3a$-rn<F+KSy}3mGO|uv;&Z)(){UWLg!Y<&6JVMSoLEj9*e}4 zX%wpwOA%{?g~eD^N~~VGh>5QNJc~tKz#U2QHfA%62%m!$QHQBS7!gL$wqA*FKqJg0 zLQf)0u1tHBb@S+~_^q78d;*x31=ToT5fkj#VAfmm`w-(kuvX{yGQqE4b~kIZnc2KT zgj+Sj8<IYZAin!{5MjJVXeI*J2Q!DQ%wY`?F473ciLfw?u!9H-iO`O2L!(=Xa6J)5 zRHp3#)M^vI)hJ@VL(JS*pW{`aP6Im!Ue;+{jQ9@C_KvJbqjgy;?QW)R+kmtW6O+{5 z#i)-MwLvEy&cyXhjDq(@6wGh+A~AE#f+rI7&*0}khEAK$h)w4y_!*{M!?YJ!1wX~8 zB1U!9iA$My3KQ$jlbTH-0v(8hBo#y$5=M|5h7h4aBWxo=3=xJ|eXX;Sc6Y1?=1+m? z+eN&c>%I#G#F=<g-El@708P(MDE0O;VIC8<5ig$!=jam0y@rS%F<~F}L?(mvn1ljj zG`xrr<%H{s_}J)j=GR*zc!)5E2=Eggt5Tr45;%cb8qM8G&~-K_i=ZPKw2Pqr1VxU@ z!^oWDZ7-p(t~I%vvC6?Be~!eJX%uS{E506Bk6KuaRUfPa)@ofu5yAUFT(jmcGn;)x zn6D8kBz+j6o(PW;;aZLGC=phL5qvCS6%mp(!X6^b3nRQtgn2}0!(0doG!WsMFhV^M zt|7u9jc}9*NnwNr)**=q&uN4<B7BX;Yd_`@Q`kYEk_^t*f$`89lUR&Zht?v4A0UG; zv2G#OUBJS=+kGOYFDjA<z2mV_sc$|Ptv=`v+;wftZVwSB6OqUAHucXQ*pl%x*61lT zeuA}2GOJJIT-44x!K#^NlV(<9I;-&+R-MRujDLQM-A*D|<!XZ8CK!_iGm2+MV=B{H z`FP87VJ&}E&YO^==f<i-dx5=^*qG%V`+@%X8pIeneLN!$pk_?J+f2`2b%B}wM@+vs zGW~Cv{$`!t#q?X5Uby%(KUj5?1`Q|Z2L$ytX2hnx3q!fr9Rawv2B#A|hhW(BihV9h zt1l)K<DZbfqHS}DG0Mu|xhQ0C;sbyWYH$(3y$OaDYHcB#1pzNwy+gd+!1Jvo)^F}X z@G+gNfe{~ogu2{lUG7dMSfw$ViQyxL<OkIawVvQxG`NM}#|Z9RZZyiBN4!xi*Wm|N zD$5;+AoM~8R@^w)+aI=?Td+$#@hNRM3wNm7?gcqJuo-7Ovc>g>zb+lg^+WF?`$Xtr zrHqC0o|Q6%Dfcs_ziz6X;MbiKgo5D&U*CfSVp+#u=Vk&-MGkdO=LCIeSlg`IekQm> zmv9RcVEn><cIO1I<Dr<9;2|a$sT15`mvCX{1jD}yC%A(N&LCH`p@<2<9q`}i>(uC` zhy){<;EzCR%=+5#(q72H8?(N07+*u9p|6StYkDEWZga!CZSGfFvc6W=LAD`7bP!L- z)$5Mqp)?K_e1PpidFsYjc(7<u53JHN0pv#qR^ueF;!M_8FgRGT?yDZ&C(mSkUFjcQ zvF__=??dRzk*OzOkY(Lal!^PLr03KY^aQvCV;$kS&pA~!v$(3VF&cPl@f_o<l6SM@ zKfJ6<?unA^Bg-OenSieLuF^;SXYlI}#CedNsWBPWvjv$Qc&;b=O_B{eU-_Pg?@16Q z!z?AN8oOv_bVVMH-cS{RaT`33bI}g)AfShjGOjz}2tY2WUHQxMS6<;Uy}3r9=Ht3s z@}Ks9mA~j$x?n_r^?`)ZgZ(cw((}XhUj;>R?tj^q@_Y2%IW|rFURAQ{+OhZ)_*DE_ z@(10XK^976g9?`9VYkf&l))J-O|80e?kS%?YyP!k(Z(`JAxg^bvGSBMzh{q67)*Ie z*%-`@a<k4HJ#ro^)b)b2#jz&x@Uw0a-gW7t8r#LRr6#VGc8M9L9QJ$CF3ON|lP-gK zSZT19AivZx_>sCXyyUEKX<?Xd;{ZR4ZUjfr>|b6tM3nI_^IY=Z=1KbI=aoqQ7_E*q zOA6O5nz3w2SxGs(^}2Fk3$-90#xG|9X7R_871|yY&tEv-m3pD78+raB->`2Y<GLe` zb|*^BNan>n&!UNq5<wVCoMo~vuYB|FhF4bcotzie$?`0Nbynu<M!x^S7(9Pj)I>h- zNYU-*`4tRr9VMkTER*NUh<F}5r7r(}oKYnYOH)6>*BTcDX#{>*hnw+xK6?Itq2+Ys z`Jd9VQ#t>JjsuZzSiWOUjf12$;cU!yk)Mj859EbZ2cObbj<?8jJLh9O0TtNUXL!<v zd=4*M0%v~tC7zW9p3xK^ofS8R+1UALyfLFV(wPtQw&FMv8FvHX&Z2u5CEObAGW&Zj z6q!%BUSrQwhq33W!`M;(whl!359@%dOPXbKV1bZdxh}vLMZ$~_kt)M0#!I`0A?}<$ zEH5gctF)5he3-Pd?^0<2S<+B{$(GkaNsHFpL`a8t*czf@<MOC^Vp$-zW-iSZ;Kqps z(HK!pI%T-L01^|*eEoq(YVYA)jbGt7>wo}}N}nRLvF^;;Xd>CXGc$Eki{Nck3$5j; z|AJD}&U)Zm<Y9EBR=}Ess>2e1-$fcyU)LY;6Z@_4CS@3nq8$RUb!IuXLw_LJX&9(E zq>lAAZx`Zx6(~aOS@~V)=8ARkxSZVtEN+czrbHQU4|}6#eiV$`G?a0lflE|uTzL82 zrXKtpuf}hV8ulkt?0t0{aA_T`8eAxgH;!9TS);kj-^66=bjIB0JRPbSx5#@Va$E`M zgys!nbt4vehlMNq6J!>=BqP{Q+mb)8(fE;)JmEpUv$uCeC1?t2sb%o{R&q;payjy{ zo*u<YzxGB0b5}0myEa(RHanJamY$fYv3gabP5VQ>bOh8BsMu8R%uoz3cX+4Zv{4`{ zcgqEK9ft-w`C)VhG-{v{1N$=JDkdRCs3+6=1GlnnUrEPSpt5!|Mgs@=srOf~1=kQO zQcsKQqi3P<th3xQeo1Xzt?__*JcSHMgbLK-e=ZcQhC#U1fen@p^-f=r#`78TD&&tS z*g?j%d5|#$h%q(7z~fj|S7A*Jud$1?A*S+0rriPa-6QJrU*XQmo;!cioUC*6b<Lc6 zZq~Yu*4fSZdzy?mVl_3je%JM&r4e5>6mm?f&2?xalwGdgN1;UBqfPql(&6OOp?#D> z)a^E7_9I3J5VZ{tZm0)0r(h|J<zXk7KWh~q>_mjimgcR5w3Sakg;!vgh4(Yo`}-fi zWpN9xQ`Fu>9_!nE+jvmFy_kciUA=8aKElXpX5`0aq=+J~L8N7txj!_Bea|3Q^?rAq znaBY900oz=^8LbHMCYf&I|k^rQe3ek0{xQ+lmtmtSI<1(Mm)XPH6VbK>t1;b-0l;Z z+V3O{KcUAZQTvVp4F-H!@hI>JQ?}@o_nIk1*yfd#{B(FPV}&HY9;fjvAB|!BKIhvg z{S`FA>e1WmYDBB6&CEm|H&im?Cj}?{nXdbC2u`fBqtzL{bs&{kuWvC<D%1E$^hHGf zU>U4Tq&fb8sDw=~flX`q6!dkKnC8I7I$`T>L~-EK!bk-c=~3VzsI3AY+%tg#y!lP5 zSL^m5XAYphV_@6%ePfIM1`Oe$b<w9WS|2Dx_xv+5)AYzpuV<#iKsi0B*X=bk-G)r< z@jr&d=D55{vK%W}R-}>99iD+Ct8mcXZ#7vdGu-zm+gk{V1%>Xy2tSHM*iD2iAgE_R zHM^{xD2u##*D}sEZx$c}nQJf@xX$zb2d5#N5Hop6Df1`K78zJu%|i=aR+MMr&_{gk zEv?gxOCZ3NbBT>6c-$xIcneGKPk49>uhUE6cc(NDX60}_Y`$JF3)QL4J)foiyY!KT zMkHt5Ij`cpATEL#X4^An&6qK1X66X|>b2T>d)1*e2vgt8ExPXjyK{7Y^+1Nc2Ay?C zy$CO)7NLX1fr(4nMMuQ<IIKA%jk=(Q3nY1^w(S-AH-qzT`VyT|%Xt|uDB-(XA^em6 zoTl(F4X(Re_mTX2iqywbAc&aJVW}3p_!@e4e?I<PjXtzWEviO2R6JuM^~<H4hoJw9 zU+Dj$I=0VbSx1Zy+{@#Po=JPeru`egOn0bV(KKo&k4yh5&9n@Bb*RrHSKi|Qa&WA@ zjalEvtXnyuB3}^(VZL_U<o#AA%-o_I-mwM%RTGj{pe1ksvK4%+Qc<_MxquV0Tq@jZ zBnv3Bh-8882`uJ>-H!?AdAfGUZPm_#cAVh2Xhlo+twl!4jdXm|*r8qple^WXEh06_ zQ$I2^{h?Dqa}phUu2nB*Q@nFbyKM#OUw)ir!fQI5wnE^h;&J^C#X-Cgglx#_iup`5 zqt)t);jf|>t^)};t}chAL3t8(IrdchwxT{LNWFrFK|KXm*y=uzk^8CfK(xCpO9-Hi z?x|LED0ekHN2pH_@COFo2?Bp;UP6;sc?T^%cj>*!awZez@9{3ci6>jnW#w=Vs^t{C z4_$P-gs&Ytg3=4_ZRgMCt`+YNjrZ{KP|aV6_BEe8a><dCM_`L{m|6%5(!$k1<(985 zo(t8h_!`!fb`T|$cV9k6eF5SIUxNWG)Y5zpWcL2nKUuvGM_}_|fDk_u@l%<`zI1rt zZaQ8>%-sMu@-!X1&`A>}=^gCOTomMfHcB%EFrNJZje2-5uX_sllD)?Yy*f;;>4n*o zegD%)LqI<=QN0*2{=lI-$gcLjhjbbOI)vw;vVs-xfBb!f1&>!Y$oqcm1u#lwv~>Hk z)kutC&6mzL@+GXgbnJ5hs(h#?n8BCMz#2@-awX8Ae7Vw~INw|X`a)*`b^v@^8Q3Wx zPd_lsgshfTF8vFw-mLZsS*@!e_h-B}S%<w)^XRCPgf29+j%%FnDdyAr0z7bMkd$#E z@MJp{m&!E$bx^%RLA?Urj>NKn_LAdcy6bn7n9#4i6J{e1BBqup+^QP79!7KZfDVM9 zbspzyA@;4nvRS$pVvw(jmVwcsPJxB}fm?0|>CbxOodnwBSwDFctXahKS(&!@sd-q| zq^a4nre|i&$(%l2`1<Nj{l#_TZf%ppv{+ouCFHEk*w0*tbP)yTlp)7M(<~TqDYpyr zL~%)8z6-_c6JgF&SZT_ZlO#=yO#-Uai--1b8rCZ>KcBDHS)a2Kxe85_&PbD5|0HQ? z_K2sCN$1(n*8zw`moc@m;W(xbj;kZpJ9!kU-r2_a<Xdg8Z1EwB31L8~>&AE3<DIrZ zYp*!j$VeFF)&|Wu%#6mtp$!mCEyrGnm4Fr9n3rPG9Tj*3+cyGlUKjy=er-(^i>`^V zc~*`tHq2O7PQ`tL5ulBry|4DQp9%%9#cf6_hF|qgHl(pi;jg3m`4$P#;GUyqJ0aSj zg$M0Xe}zRSo2&8>qYKtcTm$lg{l~?TT*ba)hs@6_gJcTc&Cj7bBy^ZJX*V0^K}f(y zt)}G;3PDWa03*i2lt=iCC`zpx4_oxb=|16w)u`7N|6TA8cK<QZtzshF$lnG?jq`ao zHi3rIhnu!7bIw$J6;(5%L+r0fy7W*@(({{<qQ-e2SBH^k1OOGQ&%hS3JUYgJNB-$} z$GhdwUGMhTxS#nqI-@C7fb|<>oAAOMIIh_8_FZrGsEMy(W=7IO>PqBf(`qwn%lWYa zW6mG=@Ye98XWAaxJmZXb^FXHRRv^*&X%7%@0U|2LIbh>;Q?sXgF6LbN9$!F%0JhyC zD=nVR4zWDX_Nhqgii^-Lw8JW!S8oqIh<BbE9$khb95RJZ(KB1%Kg6%rqL_&M@C+!& z=*i7GEM{0c-(JR4CpF=w;cr_oPArV`4<6@mh4prOHY%_gePk@|n6S9L-1%&DaIKa0 zl0swgnZgN+PkDP6f?$OcV%*65Zs)UIg17M6$1?}>U7=h6#SG@qwQAgbLRMSZHP1SO zqw%roD*W+wE3CX1&#^CsHC$wwb;8?MM<f&)ldYUrML+8_UKg|OVH>Qp{?UwbjJWDp zwqmLiTZXAmW1BS~*M6N}|DMfLhcJz6UnXloMq_pCtg6u3k||ADZD=L-5pCkTO?4ar zyR;e~R<22Oc&1gZNpg5IE7#!l@(qwWy@SW)*k!o)i|xwcM)}0bGa=7K#(Ub^T|Ls) zxM8ZcLtTS6L%|+3Iq+W7p@t$5%4(bCeavQ`CRB`BJvNu@^Y{XjeW*e!c1q>#*7THE z7|i7RExf$KZEm&OX?`SHZ5@sDMyvJ&uA6k{l+@3S|CJaul8tFLa$+Hk_){9hMQc-> z4$mMs0FUxqtF4<h!zcpOT8Gx;T+6)GTD-^!UaVm+YgoJmy92PSS>9UY_E8QtE#}j& zZLsmyY^0uSOavi4SDkF+{@6RHuHk(Qk&NML*$!?IJ-zGRFe7e}2yYBtoZsr-6NNtx z#|Weufj@hq%(-|6Muj;S@4{#GPDaq@*<!_4N4f1{u@(kEKd`zu<i&+xTgaP;yF9V5 ztS-a`8dsK4H8oEmG459}V$_H^bV`ZWI>$qJb_Dq`4XI`Rg}KnYno&jE-H8cRb*K`h zc%InZ(Fs-0AjA^{=Ln~|2{*j>Jdr*t(K|ZiRVcWoiuJ77eh`1PnacV_up|Gx#NyOI zNwlisWO{=Pl5sWL3E~dmhpn)=D2U8wJ6p<Vw?s3<Q-`F_LV6=B$+!h-@JYs0Ojfkh z5ITfCTQ6SDs%LJ2Y;plwRU_@d&f~aSQLm?}KB3BmiNR*Uo6%%}UIeH=aLIhs?4Qym zw<}>&Ut|GkfNqo;f%#2;QrABg?b4yTy`a8o2h@<pXhM_9Z@43<{3e>tv-(oIuXODc z9Bq>O?nYx!(?nROGp$MIn&eb_7qTp&K?G$Br9_Dpsw=Nu!Mb`@selMILf_nW)@L_L zS^z5b5Gviz#$u6WS8EcbK%avoS`ta3mB>m+bYdMz)Q*WI!o=k+Ky}sha=9I&*ghU^ zMgaC-nc@hp#P#W7f4uBtKw8ID_=lq849oju+4mmR48QnT_2Q#6e<*xz?tz~=YVkQa zx|5^HmytfZDXRrP=(83*k)^)Rv0t%fjw7M!Apo!ydD}cCZF@ziz8*_O;8j}E2#QP3 z6zolDn16-hSUCp0jxAY1m_`THa!9qn0J2r?acDJ80}9kCj)6Gp*Pmk_l68z^RO91M zhunBVdz68F1mqsYLYfs+L$M_%{kuy}hftwVRtv0MO$QBXw{b?6hp7o$eE>x^hA>t5 z9vfq1K<b|X4#`M_feWW~=6gw6bI+EHQCJI|o{7Pg%cCmRjEce%3qw&w2Qcek7RC;Y z74D)QgdPZ*m-?o-wN<a>%K>3L>lM6#TekD0S*X)I8>Q12I!#we6Q>*Ej%1wQptESC zP{!;!Fq=Q{5@yU`Fw6>0u_xZiszZm}#dye!&Pfph!p^X)TlT>1@>jj}h>?7kFkkb$ zrSC~#l+ENL*sO&`eQi;w9jR=MeF)NTMQUq7?~jA%2#CVCSbegX0)%$%ZN>p52!Fp4 zf8-Q<Q{r8SH)A)#AB-6rhuGS9i2LZ>E754ax$4N;^o-OK5HVtb6u`L9{CF<I*p?l@ zJjExQI2T2jwo3dEWA~<7>`9LVyJp|)_5VKXwk;&hHr2<koJX22okN;-^7)cZ_Mw{t zS1B~Hu|tK)SYFoBxKw^YF<iJnIRTf)+P^1G4l4mFbd`9^v~3Sq#HU)dmXnK5UOFt1 zAtk=!@3vOn7pKFxAzQ_X?I`N4iR<&B6OCj7R4HuSg((6lXgAf9y)|aJ!xxX%;1=PK z>Vkn0X?*<?WF?8zI+WlKRL(|<FEE8^yNj47gh$DzViDvokS%0kR?jVZ|Cm(?$V$+| z_h9l7X^GeHW0EZ)x5}v)wqgSuvk<$qsn<S(`?uX3fZ=YtPP(lH-6jCtZ7u2mdKkmJ zP5JS$Pz{D89r<z;z@rO#>j0E>uyg!<RNzv~6jF50+J2zKgqS4!^(4s7vZykRagO!3 zTMemAMA$8u?%GyV1t!x+`9y9!)EGcy@=_8iC76bDk6M=99zuz*H~b{w!3(T(=}6ZY z(}GN(fh<1>o3@}oS#-jt3Vc=2g<$`h87*6qslmowSktZKd02ymJvDBq@Y^56gE%oG zs!P2(o`vsZR?_In(yE<Xa&%3S88pUjo0r2h&wwd0&A{)&t5BGVOi|e6%*KotL-Z{J zSS@=re~4bA^3iqR3`n)~QZfwze_-=0bp0nbdvB{q>yPx<kHA}Y8`d+wFYzOcmr2;r zq}F2(#r0$wT4>%$<3T{NYmjy6B2H`1u{!}%5Mcc!cras~m!ZOh5rW%lQLE7F67Oa> zk2Fa?D$HuN>`*vyRc~Zs7?3pNz{-y;4qP7PYXKt*hYy6^WAkZQ!X}<68e`ZFjO^T^ z(RK=kI?x<Fj7UYf4QkBl;0v_69YE9%&}J4#+0+ZV0wowFz5{@&n4f_Trp>uu<-_J& zDd=a@c^pu5!MH3OF%y*i(qs@%4>~EtL2MU>qK&@=_}{~PEg72mga_1z2>Am?XCTKv zQS8N=FWnbc;P*cxzt+2&_@Cpu%JLx8$#><g6#p>dqn=x6>n`1t`Xy}o5#o4|uB<;* z+1@?jfl7o!DOJ~fGR1K_{uSWg@A2<0{QCj^t-`-`_*aR4)%f>A{A+ZkID#YaH!3(3 zf1`tg@V85_KmIy{eepLYn25h!;oHfX(hWwroH(qYNW)n*l{Yf)sb9W>;cyUEKBFiB zeP!EsA>QiqEEl%RKtt4EfrWp!Sirc@SBikT7b9{iRmJs7iv$QcdbqK#?-CW5%uQ-j z#PhRXb9!w=$_l1T@08NZlz#?GFlDSxNv#h3CaaVww<6^uOxcww6RO?;II`RynW^7G zJQhf|(M{h{Lre>sBUp^!q(I(=P5T=2E1&sWZ^J(4P=?gH^V_hOkOcWy@4{Lb%x&dV z68Mmt6o}p1)pJN{i{pF#jq5Gq+n_n1{GbEp<IB`3N^L2*R2STb?a&dJ7>1r?n;MP8 zsYhU7K{mE{ordhYDMRNDdh{mTvLlg)rrWadCJYgOAm(P&+p^it`2|;fc;f_VBJQjh zCI!8gj*=Ni9Qw^JN7#7lx$Y0Ew_sYqzfFI?Bj1)-x;rCHIA)n#L%rG`)1$UKlCWtk z&XPFI-hn8UcL1%$Ca|B{fLgn2@R5zhaiQuMfwP7fDuGLej@}ut-Gcs`XPhy<-p4cP z*H6P%@oTqf(9ZzcxPEAFC+;k(?gLcimBFa~Q<&7ecW+Fim;_##W6GENTne1<atBH4 zSyYpqSSJyG!$5D!9!FWHh3$wbpIDO}tKqK+d{lS9YqH~Y+;1dqEbkR+vXgY&Pb6+4 z@hD&LB>0{|BaNK?Y8@cKL>)|?4#TPHF2q!>aS>^cAi2~n8cBl5ZX#t1QVNmw3Q~$n z)kqRdo=c>Gh}n{zt^!!QYY*d|Oq~QRjf0r|e$FWMGNO)46fUw2My(|l$Bl6i+SaS> zs8@AV7gc~LBe?<oXtll1(YInpQOqi6TQhUDtr^Csoo}%Zw`2^a&o%t(i+_WHBWg07 zMzW6uRbV;~UMk^(tV=1wy(HYq@Er)_mHF=~(wuU?(KolKH|E)*AEQ5OV-e+61F`su zO&ani_4e*7zOT%6UrA+7<-E!}D`(2K2^t=$^~N=1tO>WpuInityFz&ISlw+;6sB?N z9L=8V8wDQF*44Ho$Fc#NR(}^79))8@pP;KEtsA1E61K-&3$6)XsKXHL>2SA3`Gu%5 zMGeGqy^wjrR_XE<p_7sBa;tCdZV&CQz)59%vuAzLPf%HFQ?y)DQ?UL7&F08duOSu2 zc(=hD(86F$&kCe-M<P6k1VHGsJSJRJ9pZu)FQ0$D0#*VhzEvt4<ee<;UTDmP6Y`%v zvnJ%i$~4OPaHoXLe_<`Z3tv|-P+qS-u0*%a;NhT70bgB(UMe&O2+GD!LXJX6yDtxU zJBr!>Me2kXp-Y1_5ZN#d#-2khM;cR}-mg0AU}M%{Tf8oYsH?M@8?%n;xWRPPqi<Ar zwli%tTly=`s>Gkk4Y0V~%snVd{XRz!75n@V?v-}Q#?L~Fc=kGuIB#m43aGhb2}^m5 zSw-N?CC<~pu})88EfH<JZ#7}-9)=P9%PP{+gjn&uU5qSZWSp;o-;3~VPrC1sBGyyq zIX7|A-G=?9J?Vlp<YSV^mE*Q$23+hJ&tFrK$hxJ$5ym@0{vTZKat)n1*Tq+)(948p zxxwXE>U4dO&eQ@hlk1ZY^Sl@^s0J*-%?eIUd1XtA@Yr;T$6E%6Z9E+jhi}Mpq3i1^ zg(?H)`lXodU6b<RkrgUGWl-!f^&4PD<6Jy<$tt8|a>+|{1JBNDCQfEZtNky-g;0Bs zga=+l1U4^iAmVRYVC)?KQt@vx{>{d}JMgar|JLIl;rv&Fe>?Dx&U)~p@~3JC&W&{k z7|gYUM;XkvgDnhRX9qhN9BK#SKS%H)JJ^rGI6Iia;OQw=LE{)~F@toHwzon+(ss&9 zXWgu6%5@Wa_az0zIvj)Wq&rK>JZv`pV|Y%1M-=E8CjL!JS3+@F!^tBH3iMu*`OYlS z@myo(mfho;v{ajgXId)OW#Db{vX$DGuerlFPFH@4eNtt6*MtYEfC6gYiR!P%zpeQ9 zQ~cYFe=p!)1OB~>f1qqTepDP<7+j2y^9zJJa6k*rLZ}}@UobQYp|K1dV<;7&=?uNg z&|riXG1S1&g$Q{VdV!(t(1mPL8z80Ryv$1Bzeu{VeY0*JX^~Fg<Zq$fNTJxsNILPJ z9&{Qxv!rtx(o@IlGPuU;)OOaAH}&Op%t)K8BO{0@vOMeUa0dm}i;ru~RZghm{%K99 z+(J^M+@$(qd4R;%ww8PxBKGBwO+t(Y#TB@S#_O3DeQoDPa&@L!HjZwH8zDj%3MxSm ze2XgK2Lv~#Bh4n=hy*lALyD;{aa=>O>P`Im16ND}c|QSF#dL?XEfrXq1%-KZpabCv zp08jM!QA00H;n`0&|y8azq4euYba)v@jc`8IZ@<JxI}_JPpc(&>e1S{x$vZ@ekjdt zwVOtZa4Eo3L+p0ZK#iN{?%dW})KB<<T3;U7u0BXWy_PdLf3Zm?<Qz6P9Zfpx4*UYN zX@+SW;QV!_jh)Vp1m3r+y(<&Dia}ZNo&?j!;Q)5b--6S?mVV^~FXEId@;WCp%xGoA zGnm_KztX<;IybY8&0LBtFcyROFY!HVYs6ykq1mRZq%E6oL|bf^#$tw9`luJ$BXjSP zBB<S>gRls2OmH5ZR9b2_6($^Ag>o6oH9~mO_Itf~#%arI0*o}1D-WSA`si)9HwjJn z3n>rRj%p~o>~F!@i2DQM;O_xsn73udY2EgzUBYdr+Eu1_k?L%?zLo903w?;T$9{$H z93!Ib9{@^0$cV{g&8;_dYCDJGzic~cqU~0O8{HVQ5le8Cs)yDGjz?o6cSFyVV7Eax zOtQi1ixBojP>p#OmVs+M+=;%0_Q@HwvO(<K!LFgwngCa}S+x4z9oqn8NbBZur2X1L zhwM<CNv--ZuCla8%$sbWwWEzS25=u6?26NzaSL3|QGKKxmrmvesCqFKNwAA*))PWH zYNI}{;vi7ymb*YcD#pxcsg;NF*ZqjoNc)!b#Lck!#Eg<K?(FS{8|5QbC5|K2`=*iV z7BDz2(0c;Zub%ob^j+Nf=?*mpSX$%<C(g-{^jrj;YxNr>SEuktWNdLhnQ~sh4UXA1 z?;X5r`@1w*?%J~2;P@)hNS1B*<k)pFsvSm2D%Q0+;4CT)9bi{wNZ|hQ=%a}J>}M-* zbT!32b#ox@*@%MqsxS)$TIq^LfjS_JYQ|Xd2d<sS_E{4i#|+P8BXiu7=FglzGm{>& zTq9@BntN0B0xJl(%K73{=!uEoC3C0e?Wv|C3Or>R7Jq_!J=HP>WpIyAFOxW4hzLZs zqNWRD@tNDg{wjdcu+0N#EnxEi8l~PmARB+NW$)e?vlbiA=parH{D_M1t4p03bI)ek zqh7%$8r+nLT$qbEdJkHZ-&ibX^o9MloBtP51DZeTyKe^|U_-H>bP)Zjj-ZFR5W%X8 z(N)VrQpiG>Q77V5V8GtG@wSeij(D4})yRm`?gk80=s%)!FjdhTSXlnW_jMw6T;iEt zvU2HsxcM0Gnz0O)iLkQZ0ojT?YkyZc0dJ^7sYPwbbRJ%%%7I`3rgAL!2A#_+Ln*TO zv(Ly@SaR5A(bqo(0XP=XZ_xj#M_%QI-SAKBwyIm@u?-1NW`)Y>#;~t?7%4OOy7aWu z`!`)r^pzg<a=^f5-;E>Yvt8hO{EwKv)TZsaKV|N;Y$4efD)lEU8tXhr#A=*pa@*zY z$`1!XrkvFwxou!>*CIEYdQC`7>P<qOasPk4$(9rzivEasheKPc)mTeJLFSf|=N9NI zMI^?vEI8I_Y%Y$6Mi$l`RHjWPi9K(tQ2%g!{t1b!`o$v=^|>9{a4~%r1BCVZ6@LAJ zZmd^$F(vIO>M{=udQG7XF|nuQbGR^6d?Re-3un7kUseO>bH27delb-z+Z^jtjm2#n zPczN>n3wotc<CtqZQ#@cM?O)J=6BmeS1xX2k_~^f$=3r}*GVEwU5im9-hW_fvJXv` z|1WMr!0qCOxN9nFCTH3WcFj->3Q0x7C<Df~F)B0<@7aCvk4=Jov%^r>?E-@?Sl(kp zvnSf+-;WHK@B@zcz_IJtefIr~*>@3V=yl(QDbcR=7c<|cAdjcteUAXD+Cgy9Euc>u z_2Ijmv|}slJJgf7pRu(Ie}TZ0P6*E{)A(1k3n5ZG>lSS<GdzO*GAH)S$A1^v)g5vQ zNLsq$U;p5kTBcR^{zX>B6yIT@cU+HUxu1rN{i~@n={N<*$AH)k-vnIywE7eVy+82r zwGo7uHM*0|;j;4lf+Z_TBXth{mF^#TY!FywVezs%Z^DD+%mPdlVwF1EROrKYRCYCb zKLEyYOkVi!FwOms>`x>5r3LLX??mwqK$M@KdDHF}=V`S54or{IFLG;{{b#dZ+Eou+ zq1pY?3xOwNrC<2>d-^4X8D>Dyfc;{O!{s26)gRt7$(>1fIpS?{e~k*-<h}-@(H|(k zCX(FeqxX`sdrCe34ZV3rzbPk!$w<g^2yM@Q)VY%DWLep`Xk%*5_O*v*R-IUzosHR# zgW@J^1)xHOljH`&`AR!PF>d^h!(zrad(@wS@VY~dC;=^<ub8>0=OGQ6(e8bfGqcup z*KdN%GA()W5bmL#z*gkCkthXM23!2q6Xl*k)>}ILdj3UDY>`!b5;4XZD10Ss{RP?z zrLT7U$OztnT?E%mpeI$au5+*q*mX@b>w4cxTw$$?4|y&`{cD_EVYN0Z9=~d5GnEg# zqdJ#&2^wQnc!UX(s}R^|4edq$T_ln5Qjl3Ljz!HY!2DV5vl6QA#D^vXcKurCO?VgU zf$S{cs_;9DbvG}jsBc4M+C&kE-ko{`9AhLir0&MdbRy<Lbd=KrM}zHZ;3FV9d|rEp zTgDzQr#z6?m)1r6jMlon$Xs8xZJ!+ll~v?_8F#ZMVlGBjE>9oT{rxkcm~l~{A)0gm zGl0#qwMdH!sHKSX2mXKwGT4gSYqZ9;56Sa)2K{|S7^l}fHgA4K8eJ<mxDTRtlIUP! zMH>AuI6T-8F(%4#TQWs|M0*ouAK#ch9=mO|<1_eoqs5q-b?r|VKFz_Cd1i{^*{*8d zaP%~qDfVQbZrD*+EzP<8Hu9T`41xbpkBtpf3&OHSJ>cE=tlr58x&Q|MLvU<9C(Uw9 zHD{0c5N*P?2@8{*%i|zBZZEU3JFM<nQ}YZ`gHAXVJvWS6QC!VJo*70J0lO2uLn_um z+0eN=+S}i#dV@t_r(ShHK5$3h0@nCD6l-b(AG3X%TX`4Avx}D{a0>$ZxvBUOeZQuP zwO03FrqG{UQgYBAI#hQDDy}jRHntPdte{^dg=?3vsS(8BR<fVnN?pF{B`ohLH?sPn zE=kbY(t2AsyYWS<S$M}-7Du|(Y;VS2tr7P>sFJZ=Vs#x~vFlh@%v$}H2sNw~9$5O- zN_;@tObUDg+dh#LD8EH3Y!zat*vxks@(_|_0qPG-83pbO`y`$YsIHS1h8)L^fUNp5 ze*J-qiF{1+>3&`t$=nJSKcBAF#)e{)OCG7Ou3C-H>M9ymM8`pfQ_VLn&5&Wk%`-{Z zKgnVg_3YOm$P9F<>B;x8+rJCdjRhS0HPyaMI`t;;PuLjKhIbqAPS~PcZ6T~K7zB+m zy!4Q`c*b=Ag9sty`lJIOACG*{WKh?mNx?y{vi3FGSw9SofrqfPNkGt4GMg`9eNtS| zWWzTjFZB(^F6^N@Qjaud{R6xJdAr*9?y1nQ#)Pfiv7Jk=&Z@8W@}$Y#C(c+0ZbM@- z&BhGVjY;@Ds(Vx|Kwg12FgWVwn(!VP-bdi9@>@iCnke}uiYgL%#5cxp27o>?fgTh1 zwhiQj5f!+Lz|AJ`e{3MVu|x%C61c+zK4b$^1UQ;Np9%EXKzd|}3M3KOYy#)oK>B2f z3Y^4Aq^{irj<<pI$`Td$fWUsqx@!m6K$ietA#k_}blAY50^CJlx(WOQubZGc)JJ^z zkWROa2A$Rs#ciV0TPVYkoG25BvXCfum?%3n%2k#>9qD!+mhbophMH!AQAn+J<1KsO zGA3PZCcV>6s(t9#Ne73Mj%CsnOnMwFSGU<rdPS$CCMUAg&maIXOO>Q!nDkdny30)3 zQYg*7Tr()sT-;!@XFnD<592l9WtzQa8s9l-{^7UN^k<quOhf0)b#ItyHt95de2IXQ zb|LI5M1QHS*+j{+P?AiPqeMB4p;f0$lp8D*uDZ-+A5of#(qW=pqEV7~%7EQ-aKAX$ z3H+W&{rYM)IZ+_3hLYqzq5_W*GS-9~wIDHBC?YDjp>Dbf*{>nm=>f97AKaww!5e_! zt#x;pI6v1oeOYuN;E}UQaBQ8&L|diNx~b2gL=fy>x6O>dUB|;`L5sQq$uSdzvQ%hB zeL~e4sJ26)3w3gMde-FrqgMK6+IC8D{^9T>?c&gli{TjM3Qk#Sl<y$!itC<2=ISAw z-F$B_m~tV4_c3^YK@WrF2v($V9&~tT*3`&6_O70+9IshD3zq=<;`;&ndC;7G2zp~4 z!=7xI#X8NZo6QD$cBv6CorN3atY#xw1Y~ni$nt2O;f)zQEFN@b!T*zk3-w{n-kCkD z+1p6wgll9SR`&v2vmG=J?Mp{5A<BS~Tx?}~x~JQo$JH-k&a0-1;JU;|@t&AC>f%9g zXhmo>pv<_popDjokt~NX<1k8BJyH6|?y^lF(y!yJ(wASd+*x-F^xHQP3{16;7APy{ z?wiC4B(KHoKIZt@SQZxK?xVQWNUlH}Zt>G}oE*TDH!&_+T`6&?^_BIBZvMU4y^m62 zBY897T@*Gbp#|#nF?Qpp4zGI`-=0A77dyO*xP^m(wz1fW$%~YP?fcb0G!|gEcxzK% z9yx_&^{@)?SI-vM+w#0CE2a7swrG~<)kuEiHH^!TKR$*1^)ZJhj>F@aT93Ep*rawp z5pxO3jq==1QY6P(q^MkX)ZvZy^=Gf2F2lhUnlDGyuRP(CQ}F7*#aHMT!W4B4LDFhJ zbcUfwP&b^(HeZcVa(XEKOuG_1H<xh@$e?aBzG`$u$6?2)KTTFiKq9jdj}mux7&l&U zJ?L`v*jr>xewz6-bLXkE%tJEu2*_&g%3;><i5sx1ZH&1Qf3d;l)-{%~=?Ld84=oSv zqnR1JzhuWa)p43-)A6)H1p}^(k5LCCo?YpZ4!z2~?>d1$LU>p8j13<u@G<UvIRbx_ z@NR0W4IeA;8{GTm3Vavg-Bqy-x6`Ky{3*iY)N~u3BI!rCO~%|!cn>w)hW8iv5cfVl z=QEO@Av|8ie;<4g;XPFg<iZQ^TB@?%uHP(4znAb{>cIEGeS{~dX9)N00(Get^ z_?|KYe@1}2n+_3^OdTFwelZ53$c)}~iOfhe%{x@QiP&zPgKWHC3m!xS@(THQOT?D+ zSqxwf*53ieA9#K+&qHUA_ZwsE@$RrEh1`A9q=7rwfLOJP7XR#xZa1JY*9DU6?UJhn z3=Rlfnxc7sM|_rJ5K#C0TwQ<{E9$l(5ht~qC6B`@S@O6<@~B9oDvQH2OjNF*@f@`t zYA$jB^FqHx&Su_TY6K3bm||m8UPXIoS3QQo_?S45(=%ol)g~Z(jT7OkM3xQEv%oH5 zs3{ozdg<S@T0Mb4T_YOkdl`S!tT#hcuDN)4v?n^)v#_>-kzW8O*lo`NH5(siW#0oi zmS1WbzwpM_9Y9U?l&G75iHXmHR|-MCd%g=FGJ}~iu%zH1Q$53b(Vq3H9rhi0&ZLAN z`pXz)|3Hi?z{3KyxgLL(!hD0x9Nlu&h3Mb~784-+I2Z#Dt+}0ac>Cx{E76l#k;Xlw z!#hD;e4-<yvQBnzj=Z|44YkGtY-&1(l80+W=L@ycGG1a&MWaRUTJ?`T9a5j5-z(E@ zK_v8->0AiB89xPd`Sp!ajwk7ofpg<8dRlX%oZFky<9*QFG`|yfK(WvKPTC#*?zb1; zFj2roEtw_gGk^E=C|q=KR&scg>Y71P9e)qvWwP2um@33FCc%m{nY)17YU9ozE~9Ox zyeRMo@R?71Nc;)+5o-PAn0)_;KfDv_(u?)yoe;$l%b^=wUBwetV^t~s_Nb|0pw4-b zRhRFOf7otF@S;EwGw%<$I<pc}>_BE-ia+2|mv1iP|H1fY*J1o6=mtCu)7;Vk&7QSf zTUF`v7JK@N*veK6i^{a)>_^Wa6Okb`C5%{1#3qiPyK8a}`Zlw)wGYb(f&S;gx?PM2 z0<PBscP(?)?W>V>qSi@9|7I_W*2hR`b&XH}XY7M&4i+jA<S$eSP6)?kRrN`^vzV{m zz_+kozhf>MUdnon48vV4<%eOohwuc#Wou<5vtE0Cp`4hG%-y+pL#ifWEf0<r+X2y? zuy?5USRq;6o{iROfa-@Ig+fztgO{-um#k7s?@W<#zN+;C(_^RN-mjbo$fhiXSq^=U zJ4*qod!N8+nU0q}R>U%ih=+Mm(b9hS0io>GHvA^SduC$ZF_NA5tF|q~{QIU2zvjty zh}F1V^**YLSc;g`5S|m1VhExv)FxqTEvgYwBPJ(UeO8O?n<uR4zjjnj&aj${fogYy z)L<YgZN5e_t9J5!0z9$Cn*LLauY=ieVVn$Swi7b?!&GlyygllRt4TbC>|tc|pU}QO z8uH5%x}s9jR%ysoX-F*p;;wxG_}<)VFUO~@(l3G77&8UE<%lHc$g`?18kfUR{S)aa zQIx1LMN}}>B*sz6jIUat!8jG5+D&M$86L;5Cmg;BVI!s;98?{1i+p#;_afrSi&~S6 zcVUV;s~!ZaCwFlvg~00N%GDD?o}1(&(UDL!0tqCLgup;6&>w*$9WdMz_50d8kOkh? z`dGd?1baMzued^Hy$n~r=6g-fg)jB7=0bofR?l&G;%jmth*7TnU}79n8W3;bE#|X) z#HKf>Sq<vr7pxsBhFpUx!5oDT<c;T$+w0xtXw(Ci2p<SOw|T;<(#TgI$F#E@44V4p zLiMaz0Y*{VIeAsPGmY(>%&Of}?MX2%u;&t_Xu1?EM#3cG-K>1z+3`j4ftSaL_^5Gb z>SiCsLw}1Q_`ETKh1X`DMR#GUVW<)wvd9EllamA{+_#_ejMORPT0^Fq>WuLwQ#4r& zRaL)!4M*v+voaN?dhh4V^h8DqlwbGjypeGxmPsq)Ay&p$RjyOeNrqdInv5apuP0Ao z0KheP#t<k~8W~qrXB{w0egY`EjqO0PNK|w=#49y2D{7(LNKEuKAb&UcJ*YyLG2E<y zeI&9)2VxNL2QvC&UgoVrSjUNabR%=7U&9S7Iz)VRj+|by6hR3K9AOL2JI|4((^ult zX2!?}N3e{e9y}DvOxLP9AL^iuJm<-chVhOJ_~(H}z|GvC(-Y}NR_X{JIuYe{#$bJ@ z--rCQLtK0_uDe;L<s_DIT^UEGyJ)N(rq5h6%#$Q^+bl=9B#Gb&O~hGlnuG;!MnT!q z0yEOYlQO5nya$}eTJ)4S)1j;tCp6EzX^s_^{HM&BmFw2|3w^Eo0wA%jy;(PtMwT;M zE4{$Z<ItArq^_A+b0=j?&B~mSGsS9?lws?F=rW|Q!x|ysax)9=^e)XQ&0DoHr=Se> zQOx#A9+_E_bEi;&MCY*zu(`1Q%r_CP!J}yxd4;J3QCJ4YHM9(EDs+fNys)XE5iWOe zK^}CxmXwsyc(S0DmX+LDT(E*K8cXi<K&8`_=UQ2?3OJ?r@GT>=0}gE<kC6JZfh=F% zZI~|1^I+|knR-h-1^IR{|5<(y{=58!vu-S5*-GBtqEV=@HVGn6%Pey;sB8}3lGx?{ zUpG_QNnXBs)QCG_(ptjgDajwd?Dzio%_=KH-IkOUpi<C6foWJF2viuUQKIpN;aAdy zHL7n~NlVtOs}<+EX2dlk#=3^)T`75UJkKgywshIbykZkE>z1tXE=1dKon91Q@IJM8 z*-EJH5YGQtKP-0+9*X&WzB@9;lOHp9cLuJbGaJSwAdVNe+PJrFG2@4y8-KocW3Hiv z@J3X8B?Ul|-<9V}hqjlkgz{&0UU7NB1XmvQl0iWxVp+ZLI}`70C#}rK%vdgV9U0F) z0Lu@iutM(m#OECDG266KOV9q+V(m-8r%H#ep8Z&`35js`cqdo&%P+PNc|xdNi#-4Y z3D9w|UI=C)xjv}uxdtaAB3O$Eo(WD(!ucSdC45LjN~Ye}eZz4Ox#>b4igSzZ?Nmai zydSmmKA76+_2HKnAltpn_JN3OhcVl)`dY`GV{hO=%pItYeq!6o+w#%bxTl@bW*pK0 z{lpgTZ_O~YO_H!F-Cn;?4e9k=C}XDgT|0+ywfS~l%{Nz`c3@*FIY~71SMbJKa*}XF zPRIMeE^X!MkoTaS!#Gv4?+j$DE!d)ApA`9uwlYmr89Y5iOTn!MK~>3AJ3$;(NZhIy z;?&L;a6~TpJ<YsKLd6`Oi><rw-oE1`O>rI^>&6I79iIoa2kTVvlRurZ6OHzb9l-tv zuB8ci5e~_TS9E^dlbMC(JVp(CFG9qUghD8IY(q!-19Q;Ropt=E7n@nI%o-sa_cBN< z-sM^fi&GimMob{qYNC0Y^TGMy=NnFX&gJ?OQD%W2l{&v6=YyR;D;Zmvz@G{0=VjV& zJL_*f`LJxHOZHq??nFEB=G_ZxOV-ko&y{K^OmZO`$&dQb=CT=)*9bj6sb@f+&be)( zp$f5>xQD1&++G9QB<r9*wWTX8CtWaX|H&1tv-ja0j^nYD-!5QOm;IZ&P07x<$qREt z9p;X!$cb5vBbG+ywn4A9b}N-@R~&*=1CI<IsfWIs9Qpg;+4QHA(SfG^o7jegUbcd@ zEqEDkRoMycA+e~$u^M}sH5))+>{oA%hnj+4y`2_iicnpi#afn{?(HEMJHGrj6ohDo z^3@7&_vfO3z8P^9FY(Si8Wq7cvpR*DgV)Wly)YE6T>NVBl5b5>ZImbJxoE_EasnB3 zw^a^m;1gD#o1ahzzUc_z*a)QihJQ;diGDQ+>D}sNI=0KLY-W)I8?$-p1*kLDQrS?g z?uVz0MG4^Y<%s_|;&Y0IPryvZF``Zk#>~O5iq+$x6Ct&JrzLC%vnT;{pnB`KV0wRG zes8kAR=%~RBk}eFa=fMaz-XNpk^dLSALMCNzdin~yePxx#l2A3Mkrfu+jy^&74vpg zKgBI5bltn268%<8jg#ZiPv8{TDQbX<Xp_nWEsf^dgE$mUh&hbE-oa3k$w*Q?9{4r{ zgWkiTgNdnVxP1E6ueN?03Va0KQ9r3bLRHHo%D^|Q9YvtSCehexx}DEV8HeB4)Duv) zho|~Ks997<mlA$;ztu+--i#tLWKDLI8z~aq>T0N{xoa|0M!5wr53&8+>O#aK?evs* zoC>?b1fp513s5UOQ$aZqY0S)$-0Bz<usY@QCq$&ayFmG??JN!&--fa`o^gPw5~|!- z0CBD4S6}>)Y;X&7{9aAO?ziH#y@10W*~WLG9np@W<AbI;mJcv`y1|@A@=*TGh*t~7 zMma=Oq=K)@Bh<t#$t}Pn>@WABroFZ#x0>NM5k@2U>X%er-oCsYtwx<2z)|z&*LYHr zYSyNth!*D8Pv3r<RfELk&gC7zOmVA)H-dS3A?(!QX$XTiP*^FtWga43?&Tp}q5a9A z1lrYC+NIF0Iy6;kmSG|%+Q{2Y<iLX@!b?D|JQ1zi3_ne`NSjBQZ7#s_x+S^IY}MBr zJGbi8@>9B1UtrxiPpgc^o(^1dvGb&^A^_`a7QbAIpNQho!9#}u#h9DYZ`i@=xhaX~ z$tz5usO50INeYbvEkPl?642qH2x|(>+z>$_DRmbHBq`KZ!$vnki_oUfKoeOgB*^6^ za+4rG2IR_yiHk9VYM+?gLrv1I3&~dw3`Y5n+li@qz7$&^oEYD@+?p7nT3UAuA@u{y z3Jk=iATYfTgkgAyxd(xwdj4tQpLYBq4vSL9fCG^;rYDEz5(_zW4I_xd;?>K7GZdG1 zop2ao<2(u+ncE!@awRW9a;gWG{V`(c{u3$)e06;y=dYi{n@e|R9rAy*`R1;j`^?8t zsSF%|umvyjxQ1q2=^B0g_19fJX4L3Z*EA@e!%)H;Z+SU<6!eU9bL$FI^{&nd#*7*@ zN++0+2ZZG-UDNaOR`!gW1Tz|vZ8=w99`^D_@VF3Bt)dcGm??#u3Y;T~Jf70=BS)@U zwQ9sNoEpmIfP+o{NU0}pVI$8Pmm@r<V8yIEm(xS93nyHd?QrERDO(0FLg8#BEwnO3 z@15=CStg<+8dcR<j9^iv<p6U%*EV84AZM%{Y;lI~5qzrm=4)fHur;I?o6!Rx07GB= z9sEMp{VRUu{rp1p?pqOkR*BT?vnnhU{=g@3=kyun9$BlG6o^#{>$Mnc0oe8VQt$mg zw`)XuN7+vGw|dk-o>EOh6Rq8QQJYy{k`!1LQJ_(;tNx2iu`-4AB>B7vs@(gL*XH~9 zcEM71EahFpk|897b=QD<Dy{kGsDb9=Gl1zs#HUw8Z1l$kVq>XeciQ2($kzZI^(gkS z$X*ve!3Du$g0Gc;4FISoP)GG8{&bQ%@r(px|2dw5(u^XATr59K<blrd=idyn-?<n4 z_qgFBot(MEeoIg8BXD{2)S_(czowrFJxQN)7G-dj0*hQ>u?UB4rxQ>cK$<Y`42dAj zMS*{I#W5#wC|X_xd%9|OceMN@{?v*`yWUvC*a5iFLSgE?2YA?^8mGgXqNDDDHlR>Z z9%8M)imKy>VY3m8)889_14>d)lQf`mUiiE_U%a*=O2!Cn*PabKA2q`ia$v#X6Py$2 zGb%iI{dFRJW|Sw{x>JnvdDynU#(fvU?rXo4e<RAk`%gL~l8rV^T|m@fSyiVuDm}ma z3)fE4F9)bVh_i4Do|aYTHdp5!miHd*`VmjZFsnD%H_zH3U(#^Y=)$?*g-&G8j853@ z#}PT+H=L2th{WT%>HI#CLxdSoP?RWU`2P_1E$~$p*ZL<A9x4!&hoGntK~bY3BBFrJ z>x4w|A}8S`SON(o5R#ajgHS=EAxb!4sbY)x!bf{iX^RzWh}fdRfJ$3hQBkp`6?J03 zMnwsblK=P3W1rb40lC-S|J5Hkd#{;UuUWHZX3gxG&+v}43O;{;XSTVnqGBD^)z$*W zeT3uBU{7%Xb}fd$6?41KCYiH^tuqH%d5n@jx^|;3(BBkj5#QjE1@1(Fdhg+g6-lXj zwY57AhVdTu;9wZ<;ZEczs;Uo60z*xlo{6)sz5}ci?vTxCUE%#s{G~HjilUbN14_nr zU3?&WAehu$?0pEsJ?t=D;XRxgOiIoyXq8T(ITKsSSLA#LcQq<UuF5RJeng<!G+K=N zqLtFrZl}cAic@|un_0655Ny)qDdgC8IW&QsW4~qtuC*q>{|7q4J?h+YbuRfB@yA9v zxSt|Ur=V#E(30dwRKZ*r{Lj${DwZCGWM@M%5XH&?c7pDz_wL4gVi!JdJwPVLrz;)Z zoP|3I4?@729#;UI%GbZ+RVo7Ee)!fWIpT|2#xLG2E&Ofm3ADh^h?Dw?-!UDJ*r!}4 z(xgJ7s+IwVqm*F~!%@nQ;GxK@RLV%O5>iTUOvPME`SB|qDCJq9mGUiGyrq<dGoh5b zx}ax(F;c|BiPqkn{*ASrIC4_X^Y}Rkmb{L<j=%3Lt!s~p;{OPa7yPN05%NW!0XGyc zb&azlLB+X3T>1dU!>+gj{XGsxD#qvX(N|m{;fw<in2VzdoLC)i^a7lIg)uynt}kVY z*2yxR0YZkxZ;19T%Ac*ukd}h^cma}3ATH+REe$+-j!{0s7<bOhMOYT6(3OD)yh?cZ zm_Ww<7@^G9r!eSz<X=N@>JzR-lNU7Mv<IDj9)3wPI<F+ZoYx5=Q@Q`jXy5$8(o)Ry zO}vBski#u5ar5FZX7Y!*o-BWrb5q}mF-iYr&I;K{2X*`^<F1}qi_yGXM_iVIG0S&d z2I9Sf2N!cw6Lz{^v#kjm$ne#koT_%`2I1b9(m-U$0VmnHQJEFm6=++r*k5g(*-J_y zc^Q`$o6+Rp!y}`rCegd#3-o^bkov?PX6ZSf&LL{q7$nh$1)|V?H+>oJ5f@;$AjqOH zm*4#JDat)p8d0z&g_K}yZ!!5nHm#kqLkd<bhg{;3L7|y=Q*z^{ZHLihx(74$s9@*- zo~*~s6*7CUUo^M6%|#*cF6_UlfBVFnkZ40Oz^5mHSh4<*GNEG8bsj%p_=={rqDJls z2*jz^`U<|PQ><IXZHN>%UE<2fqwZNwWrSbhi%3UCY+S+~s%?njNoj|RC-UT@$ibI_ z5)>n90m3Q9ZD|Lhs_ug0cAD$oQCp`#=QA`3xH9ppV~16}pTEkxOANS#J<%?jz>%-H zKPG@(qBN5ToPXzmmVT+c#FVqFHNh^!*<bAxozeE|8grS=eAFxLvRPYNRMl>nw5`y7 zeOU*eoYP*-HQld<pL#Ww{k*b_F0V_=pg}wcf}w-yOq6siw(iI;3a3q-npfSs;1T4a zgxilE23v2!9GaRH_v_9)+IH8{)?CyNy5o_gG#Qk55^$@>KiVL)4lhI}V1}hR&FDW$ zS>~#A*@ds=^Vuk`mNaGC<rp$fT|UZ~9?osh(ZXn4IqIw)s@UXk<jvr@mu1llc<Z5^ z13o2Cl!tpe{Rkx*9GLK+h@^7?ezO+n=poYessPWS<H`!YMOJr2a*ULokM#nJ6CJdS zk=XT3sV8Ap#Utf88W<z($9J$YDB1cl+Z1c%(rZnv)O(Lf$VVd$1k2I6_w#6LY*O1g z6<r8EQRp13=)rcoc>u3zZm!u*&k%*Ch|DV=)R})8%G{fo@70-iGV?zpm^oO{mnkWC z;H&Um0HgT7^D&;@&F7wb`L`dv4&aODAIIL51_`1!0_Zz}fTI~WR#Zg5B%b^eQYy!B zhdOq^J|TCiufh7fvYn&7<g|>F{Y*7>jtKOVNpi$I=1R$b>ru$mS!Tj5*>D25QwCcq zS9y<$h|9Q(_b7IziTklJ&a~Ucoghs{YVeCso=2U1q%B7bIV!iZeF=^*(5o274;`F6 zZPET-7327Ig9lo@zqPIH`3S^BLF#UhQaf6s{k_$czW@f%T?~EbC=&S9SS<Df-5JB+ zz8wDhyFnE{0@FB+iOn5f-Kj&HM7{R_PCF5>`9##O7&C!oRL2opF^=DJcmmhq7~)M+ zMCXxEr96=M(HTmq)1lPgMTjf=OKnulRIeA{wQ&U)su))xdmwBGIkah#sJrGkMksuq zEMCGh+#pU$5wUP6JTaw!^v^|=;{`jL7_RL}1CSIi2Sv?SU_`K|tXxy;?<sCJ?E(4V zJ*^-tSAMXd^Z08R_O9-SxU-%Gouw+dU(Zk_!<d~@Z<{Vg)C}E<nQ8tNj$}s{u5EP& zR`D7(Hj3)j!%n3Z3<uAYK^#8}wwpzR{5>T0;uq&1!1p#atneOl%}dV(suQ%;AMtDf zjt%TF3VbZSyBAMf3SBhwbV2_>!~-%XiHytC_9ih3JMYGLTcg(C>wWcIv`>5i7;e89 zEdGIq%j?GR7}4_c#2D;vtl?-$JcA82A_lMGVGu;ieMg-U8M+%ze!RVVlxgE^_1d{h zO;<RY4z|dTJ?{tF@z;E4=XqP4vq5gdyp^suGz=Jk?+M_`-B}ZmHMm<2XT&GBQ(AZW zMKT>d=RF(IO(qQ&^Jd_;UR;3Y5KM{@_u{qUj?{<%ras3a67XT?t&mKH5xR&k>^}58 z2*rj}eTdccQ&hP+(-|{fxgMh06sC*84`h#%Q}EnqqXxRddCr^UP`q&y8UW75!5;WA z&4FGachLh?q_Vt*g$(Sm?_-Skbb;gk+ZsE=8*oCYtc=@8n)+0Zi`Bk~zjA3+w?sca z&XNmzjXbw|J)1T*@J9I)kME3H_835o>+uKp&efW;ydKLn-i2hH#I~y)B9od5QEZe< zYul6zV=34UAwz%IY^Ms(a4?O9DSUb<W0yl<=WNm~NZWta@ixS>Bj$B|J_2!C^vvJY z=w&C#G|$)|C49&rWx!QCyFo&1#b!l#w$7}O4RX)7>foC$Y>fEMYK)2S%vNKJK&^@4 zpN2ea!S8?#3zKT@vJh>ru5t5W@MjLxgzRivklTstaST4W5D`ZiT~G^t&T3z7z+Zxc zs|$Iu?_#-LH<71PFZUi_m3Dkpj;>hma(E^lavW8$6qla#5{vfB=7jqeU{0GNq)p)* z!ukkwI_yiavG|{+8pI{A9FCNok&{@O%n<fl*g6gewv6>GD@Ei>_;VV*-oRCdB3>G= z@GJ*>MI~cEFpNn5l%}7^(v>xdsM0e6XX!Uquro6dgQWxTXSlLzlkA3!O{XipQ*+{# zPq2M^i0WlJ`OmEw$FJznXJH5U2QUt7$V5HwM;8<Ue^Pl<k4|-~VmY?Ja@dUS^ICkO z6kA}&;DD!Y@_Wf9EHe4T5PB=Dg3WlXyUdH-Zr<*l0_V-y0ZA~qE`WHM1tV{OxlBDD z@lw$lTkhp8v{)Al?sXJ<FE~`{`ZLr8UKY!@ikclrK<K>UWi^IZ{ebMz<G>C!iRxJr z&WluDM|_*adZ+`PXHc{^HV5F)$ji`3`r=p|8D4u^=J+dWqzTKZ3id|{dj&9grX_@i z%MNy`6ypPzhTOuRfc5a+bGIGdd&4~(5BPg7m%ngkSE4TH#p_n<v-o)I)umq?X{)>= z(u1#<>%?@B2<{cv)9LRGjM1|DM<@o~m4@Kg;lAOLojX7dBKB4}21!^M#0C}Ajc*c; zT&nNFLmE8=8^%J#x17hmqo4-QK2eAl6wb$bS7cV(?t)zs>SGohx$B>tEq*%)HPZGj zGTl@;7AK-6if<7Mg7U`{?30-<Rw!Z$TJT!XeH=&}V;Rv?CG=6$Bj8D}_?Riq2Y3#a zjUwk%iioma_}j&QCjNHz_iZ}2z6-y3h-ez99y;SRWC@XH_%O*+xqTSda^~Y|^!y@y z2^OjldkWIgniuA)OChmCuEdj4KDp$!Q6rs+Kk}$l3C7KkSSBbbTO3F0!P(M@@<{s$ z`HQ`a;yk%|3v){gL-^HP2wew0!No<k%ONIRQ3Vz~KV8p#m;qe0(88V_?h`>ET-}F_ zBUq%~jGS<OnPTBNRCS;~K3I<o^v1+FGH^ORoo}A=R3<7%X6b`0dLE(}HJ8rvK)kY& zBJ50<t{=^fx8yy+m+0&hl6=bZbxZ(Y(T%2a3vmyS;r<fEeIXA9uK}EnI^l7-Mw(i? zO9EQNv-s)?ykpyQ7JYovh}wNRWwk4%Q`3OjW}UK7rNCdX3_E~KF=C(<nz|Di`N??o zw{+&8e`WR4h^ffCJx?M(YBet~+n*s9M#>q>;VZ*OvL9dvhB;C?KfGeUz|I$2GZ*A4 zkONa24rMmaUE6uz%#O$*YmhlxJSr<JYS}OFhMgL)*jF0{U~dL))PD7!z0Y_p>Ln}^ zpYhsLJm%P(Us_DVu59VDWYUgh63rthyh=T0iU|^<KLyy94H*X4@M;6DB3iL#$Ypq* zbH;1R6p+S!+)q+%bAro;#4z!xY`ir^Rnlri3D)byS>W}q?Zc6%+W8B;|G@J<Fyr3y zWUNQbZaUmn-4$mv9e*p(WPAbl7#zZx;>~}21X*7mi3YU;4Exn@_hoSQ!K<nc`f<f< zbvGQ%kY0J*v*Z$-H1fK*stmT-r|NJ1o>=RT44x(yVk(5)LzjPcxDDCb0`DVJe-MQR zx{K?d!bgZjL%K)ePh@0eQ)K18B9BK72|QsgI+CA{iL;PRemf?*^NBYkh~o&?)^NL( zIK-!!eEI@UVjQZmhSNXsArm-D5P#(pXNh75pJaUM6+X#Np<m#W{1p2cJn_y?E)rmf z_eq>-6EzziMd1-#Y58^?=AgU|OdyQaCccD{cXV0yixkgv?5BWQ<%L*1zBt_W6j2($ zu|@z$%>ce2fQ%Tx`vj0j1K3Fb**Acf2#}Ipi%K=nCkUnZ2C$j{YQ_NWB!EgQXof)Y z1f81R@o>OzK7kGQVkP!)J;h6d%`~;(3uLQnT=FHFS_`HvGwM9@%DD-}CASqPIhO>& zWM%t6Fbj7OA`%;NgG}-~4HEW$EAj3J;K0pEo|u?ePs3%gp6-{&dNz+w_H6rotY>xS zIM2QpV?C*nah}bc;yhFEJG@JrrvSe*@vi{+)|4c9HsIfO{M(0rE%?_jJEgcZ;GY=C zFI%iurZTZC9NgBe<AhAGk%<MlPM*`$nr~v!Tr|E|ht=r`ZoU)oUfKcQQ$YJv`0k5* z9r4{?@vU4_i1F3kPLR+Ye6(jgxQ&drB5g>bo9|wDuRvP3zBi<vn!Zz!&*pn(TC&tP zW7!CL;@^_qu~IXAlqBdXLt;Sx9f7xXD8y=s5`XrF$*}DNGPF)SH5n?9&z8a1Okc$@ zL-!$;VFTSdOjrgk+H2nMywdB|yC3fbNDSBe54D%R*%<*p3>{}~hV$G(!f0@DVxAL| z+&mA%d(r;_&jUg{r(wT@o9`1Q9ylrQ9{2(Kzy097BfoO0`u0ri*hU6w-Z5sFi^y(y zh<Vudi4!+~o%V`{ZSh*-qrv7CN!Q_KVz~wIC~l|5p*!{5KsFZR{yVxHX<LD<cJ-nG zDY$vK&Ns>I#jO1leJ1u2%7Q<;<T(Am?7^S-1U-0Co_W1rz7}APa=Nu2k(&$EUc_Kh zf%rM{1e5Z_efX95s(=qAx`Fb2q$Bqta<5_V3mhx<XX1V?5$D$xA~>_R`j(>LF%;V& zW-Y*by|`)^;&{99-sw2@T+uzKNyhE?noPn^2OI&?9paZP@D3jKQ1W{52Iw+}Qoy7l zRqnmPfbOjw;2;_SM4dsmRBq6ce7z4<3Y;#s>}SXo{FC8uZvhA>9lc(J$DC47necCn zNnRJr6|s78Gu|yW_h4xpOw^0nfP>9?ahyd_FX9Ta`MMZvN?wnCmsd1l1~0BAmo2ru z9WGY_Pv@41rKL@suxFAiwVZ=}A7}2xszD1bJJ=!S@DVKS5H+omrEf3Rn%k+~x0v_c z7**5`aZq0k)DhlNOtnsvd_|B!9PCygE-C<`_k!L$F%VB$KRhuG$q9L4J%FhC&^$7s zK&*6NlhqN~$XX}rIp=&&oPj&v(dDbLqMiOLm40q0-I+t^qm3;?nK&2xS%z}`e7x6- zu137~kGX0f>nv?3{{UPX$`Tg9ZiyY@S&y`o$A@-gDZh?p9Y_Nm`v(~4!KI3Bo@G4W zVz+T{cW0h$6%X`a<4%REPGpgdPaQ44C39Zx8-}ctkyNo1*QDY=i~$%rMdRGrzcqCN zb9G|Oqf(k43Ju!PV8rDS;a#3oz#@TBXdHlUD8+GwQJDPk<uJsk<*s*SJTpn^mb~i9 zZ1kh`mAGHY!z(bb-3C|E!dI+FE|`cbr`XAIJSsWqGm$eh>~W6GL(-&**0!d83MB6r zSKyL6TiY}ahAx{yI~W$EU2+Kmw6I5T^$J!L5cNGvy_L&1e`K((sarxuU|;1<X$n9r zrXWe%1bsqFaJ&nx{JvrczOMkH@p)p7LK`)vDQeBD3iR;LTlq=F$I?QB+lX^HKnkbv zaql)*KJM3OU&g7u@^|{U0`vMC`C4RNAD6HG4qP7X9zHXe<QGpOQ!uGWtdqY5;(q)} z-&YMf+V|a0`qKA7=V~9HJO(xkBOkRE8ASV8lMgFu<~6j}vXK>uF%rPdJ@w)(`kI8& zOk9w>!k33>|CQaj%7vo<W%52GJHza$K+9cyzs20BuCXVav5G*?V0)dMGqD<7fe3nw zf>XNlHntlRuED}^5gO^6dE@{mXGchPRe76SNIOTGmRzldBj@tRBHV*gkI-GO@e=~C zt3BKoK-y`t64c&3#sJ#4-=ED^?P!s9^o!Y^>qQb>9v%I_7FYYdzn5;m7XmKZ?^YI& z?e`0MwtDgLg|7CyNHv3lg8;QXeKIi7(=U<DDQ{I$Dei_Ae@CC>w2si8LtdWj9D4tB zrl})bL4q3;alpNz@#^UjTr$RmOscPVi)O>#Y~w8O*djZ!hvwkXw*-=1a2V_&zNXm~ zSK;02D>n4hl3oY6l=N>b%G(kmC}^GdjxLEh>WN*y!S@soT_|U>)mO{}p3cn?<x9|4 zv<1nMe-d^^9K2EOi~uW$cs%eOXmg!LAsK`++$6e9Qn);)b;{+tnQbMq0lZWZX1T+l zjNj`<VBf=vM-g^vqy6!lft~r_mgM%Gg|6vWGq42KjIs+1O4QW9zXdw%&d3~g6W*eT zT$=7sJV{1^6<gt#f|<jSJe<i1McjFU%f9+;*ow$Nz4-1Z!l7ql{r3q1!~+k43>Jgy z#Yae}evHA69rvuo-v&%EK>oE0q|WNa``@{`y&G^>a74lqwz2|oJ$8Mer%UjQtM~+Q z(Da7z5p7g&2Y3!fz$LgDXiK>N^JBIs`&$g%FBXX9DCh1Mi-f-&%r9m-FuO0*edWhT z)cqLn*V11ok8#9Y!*DC+9?ns>(EYB3TyVqz(XC?XPvqJo4`;0ti_o)96R!c8BgY~X z<@$;Ywr~0;h4~WxO0HsXOD6n-@tIG4X!*>==Y@P`_4}@I;ZNi%U8oFD%$Kipq4IUQ zd@aSR98;#r*N!|YWDWV$bYu%Am5L<!TO@9jzXf8H{LK?r;#d0Eq2NpV*el7e@v-VI zx{2~gap`F*eMV;-y<CPpZPL?5E&B%6qU_*LKb8jsVZDhl$eZDDq!#BOsEV%aW`36k zdnx7VVDhUx>@g;wNCU8au}(|`KVraD2<~&QBbrKutQ&00!x0qHW<S24H6%b~DsBtm z{>VUqq;njrCh+HTPE1FA4k+m~qTP#4SBB^e2&Z$KMQ6OEgQF^xXq(_-9E(^1#c)ra zTyc90{S@v$+@~#qv0zy*;p6o;XP~vin;JL%yIj0u{6lX<7nSw3%elRUEBYjS8sO5o zeaiwIuMeSHtQP}yNj+ZIUi^}?fzS5hcLS01;<BTW<3#5k4Cg@OoPq_DOl8-5o8hvt z=|*|FUR~(2TiUzqBh$f;a@n8F#3TIV4pH<Kc*FNi=W3~z;N5cB-*(edEdyLibpfTK z%T8CGGr^Rc#zkc9va|XFo$a!J4LlvV>>IA9%RWR_@I7Qhv&&@{q73b=r=)OsPK$Ke zhs68H2JoBbNS0X+XJxVcGJM4*-us1d*@wVnKMLx&>~AK+F6pvsWm%v^wcJE>;6b_U z>3oy$GCZ|&*-M$6kQe5%6X5mfvJWWpZ}=(5$U|T+LxSzH6SJhtj#8}Gi;KazHB-5_ zt8&@sGSCM3VH7%Wwm$iYc9<thZw3R>k;^;9@mVsw`^^M~9JwE+fo-y4%}2EKui-~R zjvOOoYd(`FwxX!pmluc)?O=Yf#({O<%ljO1d^yL>(uvFVuID`$+39+IRVM;)-Ia@a z@ZM`PXJXp2H?X&wt{vNf+i)-xhw(_4pm>0=0X?$^0rGo3_Z++bG*ma*Y@Qx^9cLTH zxN?BD?#I4#S@+p!DzeS~3UF!NakroV+idAKP-(r$*ClnE%~MURyw7npTU0zutnM*H zMi&lNeW-5l4bA$OO$EZ1>N^VLP^nn)Gsf`K%gxWd`1n-v)8Fv(JPUC4+W@Zue%_(C zfcKI7So5?rmfRbhRG=9A8x}4)@9o^wgf(;w{UtkVS}|;U{+GZf74!}?Tyjt%-Kdb( zi97LbP3c;&w<5Uva^|c;3KUc)_FQ+gO@3FJkZ`oEzVckw4)_|UP+(T%!zopmoXO1p z`W2{Q9FFfwvGYWYoTaZd{qNvCR{wjX-|@EfV-Zg}J!$&#r0E^ZNI;9r?i}9-n_pod zA*ASYrx?jpc%?JEoz(eFbbIw;2VD~V_PPTQ8pl_vO|BS-?GXQEgI27D-{I8{*Q$cE zbU|eTPB`be$%-B;woW{FbF0!%4IU)qZ9K>^D`<(|bdnWYC;r_eHGYG_3EyTYuf%AD zqry6I4ng&z3EBX^2slMxONW$mW(#WYsmB%FqT0)-dLW-@kgr$BKT;*@#3sDgauYUl zU2byK0xCJ&@-Io~ZcV62tUb`C%$jwCk7K2RE4c4rOhR;ESmo`dI8#iXX*KKT+}$d6 z+yfqcrOM`>%{~rTbwa6(e_%Mv>bYN*&WsM6uJ(=ny75RGVri3uU-4k_s_*U?j&_Zq zXcydNOt)4fqVNRc!P7wShoe7dkqA4SYCJTZ3D%MJZ!{1vki@h)@l&`3OmWzc%l=ZX z&Ei{Zc>uZ`8ohe6=`HC*9{^@9AqUF~g6T2ANr@Z`eeeLiHhTm=6;mg!r?WAG<DEdj zh1A%+^r?@*Zk-KJYCIW<E8tJx(AyvRLPS%i7di!REke7k7n@jJaz2^JGxS$fZ01_n zeO1Tlbvx3t|01X`=!;fL&G8*?tJw|OxL)kw8ZcNVo<tZ;UMq)+#s2bJl0Ao}hhn;2 z@!kykUFpLig#+WAb)v+XD(1hWTfDPQ)VoW(XD$BqO^NfQ_K273M4O54F5D$@TD+&A zBF?iRA<i>BG0xK$>HDXrc(wu-iS*q|kO$9GqT)S?bK*P)fPdqFc+c{iQ}E4Myk|{* zoM-z5@t){A<2-||jQ8~NoCnO@s)4;jh`8sM;e>$vStTX&IUkDfoQAIx^UJvQv`yua z?<UW7nWtAuaXAkDz(FK)nQ<q8Scgi(i87hF*r>1z@0~q8nZ%PlQgdhJ7wwj?zJw*_ zm&>md@g=29+JmG>Pk$Ad_ALP3_(K1J+|rZ<$h;ScT|8am^B3k9UA<2tIm74A^#{sj z*#<zmdd@Jx?fBfX{W4DvSs*`8W?}%Ui>HeO9l&!pPY-;Bh1(M21Ac!=asTWba}Tk> zlY~1jyL*a~l02JlO7iSF8t>s;duG=pPs3qU51Kz`o?PSVu;?P#!I10}&uGtCD&5BG zVZRT*8*Zo1Qx<8eT^<cH)f$@WCwEIzH8CCIxeNZRJvUZ*`=jpFTn&x0UK~7v4}}(? zwsE(`^&Fwsi+^ILBYwv7=N{HmFg9^TzmX^>{+NgmWxpD1b5|+iJ9@EuSUbUr&9D~n z=&i^R+n1yF3Q>gJIeHt=B1UPV;Ulfga-?LZ4{D!2%%o@9CB-O^;kkI?!3o$aG|rF7 zx5uAQ8w(~GXZjFL9>2kUOb{==Bj04I*nk&K^Y5V%h*97l4otn|d;wwlEk}{yJ+uKa zfZo?QmGd<2rnl)-Qg+j+gm-)JYnZd5g{bvn{zl`Unny}!{LX6WjBmh44pRR=dx{$+ z<$A>NUDkY2&9L>itRFjd2A5I^E)jDJzPssF@zM*h0ti#drXvcSlo!RLCWY-mWFW;6 z<TEYEU@1t&UyOI0QRl<J=xtGa6t_=L7=q^NQStP>6N8n~@G2--W|kOv1e`W2;FwL3 z0Q%2?{Y0z-H!A09=7bU5U15A@eJ4+y_W5^hZ-HAx$HLDOaRrsWb>yR5W0{aLa3ek? zdyx5RdS4Ci)$a||p?s%fzZb0Q07EiA9fJyRUO>0jwt_=IvLzLNYLoFttZO|M5_~@( zPOKsEZ>+|<(K13iCeeq;??3S!6~66?&z(JgZdpm7I1g3msg;qm`*9?BZQmCYJzHXC z0sRZdj<waPy5{#+ae4D_%u8~9AwCmlnb7!}G5O=Sx3(?s%C7I;H$|WVAz^p=iX|r9 zwBOLZo?AgpM_5qx#I^?5RJiKdzgk<g>yVKxzzbkq<5PbMRWAB3(ET-{=3#X2u=$!% z)h_*RC*932;nhZ-9F}X(w|{mx-&-BNzeW>sjPiD5B;Tt5tZQsSQ!o)?#rO4+uUfhG z(evND4zjk#Td0O5d2*6=*-_L>4FRhaU?2he2zXinx)ad+IRIM~;P8=SZ3VmWyd@ht zs~w9!P-`Kw6*K@^I~@Rd+1ez6nwfDIGx}A=SVAN70X;zI9t9;I1p@%BJp_O(el|fd z%s2!x*7m?3(1{>4me6H{#wchLc+%%GaIZ;RUY<OT3%6}L`?CNW52NHZ4GH5SBw$&& zd4(mauTt>S0GEYR{P_!XUhZy{Fnk<NTW5%c9c8{wCrxHg$d#MOoINjud5d##&YCJm z+=QjF$JJ#Sy(LT?HlTPg_<Vs`Ou~&392BRs(X199J`9TqZmX43of`lvSVnbB!5{eb zf3zSIc_hzS*-6>?i~P6_gUgJ)RQb!_`8UhMw=&jQAAEo=M?8uKt>&AxV+SMiKcHvW z%GT?XJX^ZYk*Ys_7?!a61^}WJ;2;16WAVIYEr{2y#~;+tkHLYiizx7*KB{;2NJ`!C zEP@32EoFNCZJ{KYMjcroPi^W@u#*LLYM=Ikb`j`_a!}U(qdW3rJ7Z?9zd)X^Q2WS5 z$UhkQ>sHrtR3ZAyXN>i0lcSQzVHYAB(px?sf#uYC&Xmsw`Fuz{|AWsQh#>zveBRba zKEJ`|4SnVFD|ilD2c?G@)r5n?W&74Tt`k>Dkk&7UKH@Hv1xL##LZpJZQgM%c2X$89 zxi%7iWE<#14X+{S0K}Fc4?r9lvySOIlM0LT(oxAA{o&QoA>R|=gy~S3mo`fnl_ahc z(guREW2%;WuWLCP6JMb63ig8FmPbhSY5WoQfiHFD33Y8ot9bO(jy^pB_d(O-R<Ee| zJ?v<?#I=0&i+CoCzY2y)f%ELE<;YzuMM3Bw5u@oXYYL<e)_n{0Mo$CaX$7bTpkN!G zYn#D~)WC6q_5!q}l{`kOjDpZZ%-9=$WX5*@l9LF^&vOV9&^z(NV!ror-Z9`V%!97v z&RCfy?N+^)Cl%p4UEO|Zw|v)m%QK371tmC0lK9wWv)F-Um!#&;L7VG+A1;nthuW(3 zTm)W+6hf6RA9C!Lb;r`U4?Ezeqr!h`m%geGwT5Dzw?TL2neznm%;|x7j>N#jJaZ6Y zo?ERvE!OiP>zT7Dlb=I4^UUGBdFH^+JU3X+94Q$%rxfOyqg(ULah7@J(AYe8xA^2| zfCkR5{LC}I>od;-tmi@2bF}q5#CjfPJ;zwj!>#9$*7IoVd93vuYdt4g&&k$vs`Z>{ zJ!f0bQ><rxT4UszX+7sz&jr?Vk@Z|^J^QWaMb`5Y>$$>uUS>Tnx1Lv8&#SHHHP-W5 z>-iDudA;@gwDr8fdfsR~Z?c{@ThBGt^H%G5oAtcidfsV0@3NkEThDu}XGUs_&i7jI zeb#e>^}OGD7S{6t>$%x_K4d+&IM1QJHWl>6)jOQNR-XG3_=bM4V0k&5*GRYt>AVJf z1%I}lpjZRyLeOS{QVr<qW`K4QG{t~ECa8g+JOkQAPzyl==4td>2<qVnsD}alilAtM zJO=atL8A#eWN=jwluD2=palfw5wy>MrV+G+pxp*Eo}e`ZZ8xBi1Z^a!#(*v)Xcs{n z4X77E2MAhkK*#<CP-Fn0H3lRI8bHu;1A2#`;RG!)pw|dWCaBbaeoN3yf`%BeA0cQF zLBkEGnxN$bjWwW!1U*7fvH{H|Xfr|C29!zAE`nwn&^Utj6I5hCml5Py2+$$}I-8)r z1T8b5NP>nDwAz5a`Vyeg1U+Ive<vuLpbZA}7C}V>Z8o49f|e1q&47MM(9;C%GNAhj zsv&5v0o_T^PJ;FuP!T~51T`DbRDwLW0n}<hNd!d`)P26T!fOZ`Nl;${iY6$PplAc? zNzhD!Vhrf$L4ZmL8f`$I6SR_`L<8DG(9;BE8qli*Z6#>B0sV%c-2@dF(8B}?g8T-w zoS?`>096=JfS^GHtu&xn1jQ1x)_^hynnKXi1~itSB7!y<(4_<|BWSAu^(W{Nf_55E zXM#2pw8wy&4*;~6paui_h@cjN4j9mz1od4EP>TV*M9@frB8zl&JWWtGLA?#=X9SfJ zG{}JNAZR5)!whIXK^q7fX+Tp5+D1^U0eK19Pf)4>jUcF%peY7)0YQU)0#Kd-^&n_8 zL8S(CqzRyGf|eN2X9N`xwA_H+CTI~s>kVidL8}ScXh6RvXd^*22DFZ#T?B16pnC~A zK+tXj@)OkKc7XO7P%c5E2@(dBPEa;MhYV;8L8SzF7HHiMBWO86YfP?w0KvX7LwE#m z%q*6C0YEGPH3~2vfP&pD)WhIu0LY#n*wI*yF*#P{oRf0~d)`YJBR4jTXWqEN*t$I7 zuF$oHa|}E=zX*rj<;&>^X~{XS347~&dfrlqZ$k3yc?-*@7S7HuE)SJwUUS5}otN`> zew-JdKL^KUs1(v;{u~@1#56lUdG_JMyxD%tE_DL)_jTY2&Vl-NIqt|*<z%2acY%x| zgy?aupwi_T`!a!eDR)+WZr);x7J0}l%P-9>)6sprGp~}x4*M&((({~>xH*`%Sa_H} zv9NqTPP(71mH<?K&iNsoH?Pny@sbD0u7s#O)Q`S`K!!B%D)UO-a?8ta!?}zyvajK` z{xuqz|4gKtdLi5{<H*h({TdJLiyzgML(Q`Qq}-g7%9R71hd9+zg|$kd)5xE;ElKKX z4R_mtB1qh<*N}ZA;Ix(bhDAp=&Z>&W#W|u{4Y74%t+eQT#LemmUu^+c;-<}XyyT+N zsS9Zvnj`W{`7oE4ZNe~0IOp6`^UGzN3Xc*$>lxQtFmxr~IWKLew-F&3Y`p<2%aERK zYc73SZBQ!H@J3xqJGAPQb7%){shDM0FQFEdiZibiUGCWr!NaXs<)O{li%fWxJd-zT zfy$A?oatrjP1>{mE@OOdKn6z)UydKJ^nVU<OaA~0W&X7M;(+>)&C0`NW|b!-flZS; z{ViW$k|dwB8LjWQ**u0bU&S5)mg#4Q(h*{DXCdEg8^*6WD}TBy>Dp;_JGIj?%I3Ow zqVF>0kS2?f)<D1=KP4|`Xx|=LzfK-YN0igpaWecLJe`XsZN|{VH?z1NK_!ze?bw~B zBw-qTiuAC`l%&pNj5AOyA<RR0;Q!*wN^UF9*Bu$*)SdK$t`wzr^6S`xTTDqK<o^|h z(DG?V<t1g8ywMK+FuPK`xbl)uN2gY!rwpt|C(Sf|z?i0NUH2<i`=rirW*%KtN}|q7 z8fv{ol6Dqdh==-1DW08OQks}QTc;3Ce+AkLaia~?`$OYYcKpYV3)%4^JC0<>m+ZKc z9gni(RH68lua>LDqThZwzuvGE<D`8UEXnzG%|9@7+D4EtpkETShoD0SbU#4{2=Xk^ z1@9y%@(zG{7*G*G0|**mKvM}CPS6koN+Kwepy38|4MC*@jWwWXf+`3~HlUsatsyAe zfQ~i*w1J?R2J|^W+XyN$pgjcbCTNiXy$X;M6Q$jBG`^$VI9nC)OdDX{j>ded|7|~Z zA&&6=RoW?xG2DN#4gQe+G`!#LsGlIrY!$#(1}W2t`kC-?3G;=Iqj4$-0!h|7iZ4b? zc~J&-`27JlEMt)tD=b)?8&Ja)yPSd>?=-7=YUMTNtIz?Q1zsd_C9iHXSMn}=KD3f& z_A=H7eZ$2eBx50=9gWQ|DH>0P(b(T?(RfDF__3t%%BJ=-@LdxMRCiTt6>5#BPTYKQ zSTK2H_36Rn(bYFaaxD}4Ijb{A26K8;XO8AkEvtjcW0@Xnr;nBCu{u4G>B)9_qD)WL z>8VW5w9`{%dZtd#X8II6JzJ(vk?Fo#erYRu!uAnoTX`26L<3rd^aGndLK|5N(3Vy< z6oEgOX{{r41EDjavf5Pq0dyImTUmS)0J8Y41nnYdy8+!o(0+pU8qfrST8XX&pxOiY z19aCC+WT%m2UGys1AhR$fY2C1M-v*Opr;X<Oz0FsQx)`^eSqc>x`@ys1^oz6r;Q^B z>7nyy8)ko*5Vl5XjbWWUzChU=%q*OCuissL1>1y%PcF>!7vNRqXJ3&~95)+BsK^CU z(q*5MQ5>3G%Aump&+$M;vE8~<YN%XjrfQdCe<;^qa55s#Qq|L=u)PCk?ZDlBdM(cE z+2tBtF9+U!?Y$ZLbnh8BgwHwDo`HpEmd@JyVPs^BJrlsX#*$x$TGOgnZ2l>d{sDUj z-a+v?UoDRn5Y?zhta&X-Mx8CMlokG~4^W9~@LanH2&Gk>`yoJ26SUfZx)ZdOAP@e? zT;H<b9=vVoPWT37g=ilGirT0C5Nzfew|u5g<7lcJzf5EO!5=OtRWmn&C7fdbtUGHn z360I@V<+Vn1-O8SZ}V*5S0`SO>Xbf19K$pGq9y;;J1M`jXPWwd6PeVW4qq)#EfBZD zW}%mv6ClmzWm1s)-bb{fh=6ShuoQrT-FU9uXH@VtK?0yHEmXmN`~miTghp0TS4fh& zdV`=r0Bz|`1ikSG8D9YO1iFIWcm%JbD>+%_NK>!XQHLC_s<C5!p43fBab7+OG3`|J z=+?;{Z*^>|KRE$>p#u-bE;6?EAb=h0C)p0k-8P+yjLN2;{EcPPZy_UXdK`dtjSoNT zvT0u}4`&ds!@_98>CooPd!!=&`5x3;gy-5JKp-_fc`raq2pVfZi3F`ADBFOpCg^E` ziVWy{g0=#*#Sc*J68u3`bqADAjk>k%nm$bp_0^e(|4BP{*Uz(m>9~GsPXNEqfm`+S zDu5l-Pu{)Z^|J^WRsD2=V{v@Wd}L((Ji3wfb8LgFe&A~!C4M*G#Q>SM#&aq}7g#;& zFD4r*9=Tj<cksK=c`Tl5w?px={(eDFCP9Y`Xc<8>3EF2sw-U67pdR2%7QBU^)c|ej z3sCJK{6YOC6S|&IKcPz$bOfL`%l#_<zv`6sL*JKD&dV-Mv@_(>YI!V%koLTfVr{}7 zd`w;a4p#12mhl*zui?zwj4uqv7AT)s%d;uO6KD_^YmBZ23L#NI2Z=yZkV#Op0bLD{ z(^qpWomDuyfPQ*XVg7AquR=$@B%H4Cx4zm9NuYnBq+k2=G$_2s3Rwd;?g8~dc&?oZ z7GzbuK+tf43JhpHL5T#F8qg|$YCSgt(-ej2(Axk^C!k0HJ|UpTbO4qpz~2B+^@@+~ zJjvK!fgjm+<-DML?$t(t)TxGzuwfmI*X6h#dwq0RN8)4q$NnF=&xyE5PwmR^cnYfT z<P~0GJNK^cR99Za@CvUxpTQ1&d4{L@u#g`)4#ifMI+&wA%Jaxd(;_*7zc>QB2Ju^_ ze~;?luBXY3{79MJMdjFq-IUBZ@^tlEp?`~dsdu5@8_rPg%QbwX{v8`-Fiz{Oa;!U3 z{T_V>9s!vD)=#~^tA9Vxzn|&f^ZTpx{%5P-!TR^L0qVWeIqLTu{Tr`;*XiH$&(-Dh z@5TD}GW~m{{vDxz*XiH*L8@Gm{=G^6rt`N>bUt4tH)%2EzNf^w;C=Obx&F=2zvTx0 zflB{Izh9!?FW0}%>EAIQs(f?x?=SRk`91~zX@mOx{9pR_8}&OIUldcV<?@^8R)G_j z<vXrHl)qSnk-rz=2nXhSSpPnb131()Zq=^PX4$5*8_S;HCfin#^%#yGz2a&7S%N=+ z{8;XC#@LW{Iudp|Cs2%WGA<<H;57+@v6RGNvvCKKKRPAxhUgS*R>BQ|m);Pat%AGE zH3r3G`D??=%dy8vkZ5#7K>BQu4t=#5Pu;ahDw+!!@3mMNgM-M)U7Q{r#ze<i(}x?P zeSR)%v}c&~D%#Tv9m@4TrU?#0gH@Y>5bh3i_xK5TQ3q}PXPFs;dnslY1<G-vWK6Uk zKi&`>Us8fQgo~*v$!YizUt?q)J#zv+^$OPisFpg^*qG=z#P;%w^MKi54nS<rR6%e? zY}%<8ncd1|J>PKxo*AS6&uZ3Dp8Je07&!UBw!CorMyN|2j`c(MK;LgG!og{4g7kUL za#;Iv@-jsGLwIO!@=nW??8RY6W2h~<$l7d5J<UE5pQe|!8U5aNuV|T~HZkgCs7=c^ zJGUr*%CIT6qYLv<?ek9^HuWU=FSha9K8@cTp{Ze<5GdudwviG$zlz5rRav}lTxyDJ zYJ5!e!rZcG*u6UNH3U|E(P=JfSn0GRSgLODs$DO)>EbZi3^Y9&F<aS5=$b6yWcAfr z4qGwN$cYu>nCQg(Ik|x%zju)zYwGA|Oi7y|@WQ$Y=ZT|ZL-7BKrx~`MVA+^@YgRbi zGr}0#$LccbSY_i%vw`c`;YsY~78e~X!Y(NM37nO`z^V}HqS*3+2740r34<(u#zd#( zE=tXZmP1{)YKGe0uD0nAA+9to_m^v#!hEb_F{*xs+htMJr&v_h?I^n}>1LFjG6vd4 znq40D3WHN}Y0iCU4zRA6Xq<WM7@f32m&#yujyfb?SV{`{NQD=g>j0@!P!B+~UB^VH z6@n_XenWI>NiptuM;)l97+zhVZE`4m7PhBNjh{O4P@6t6$*?-~+BBg=c|^2j0d75Z zAi_!Um9tt@O?VO3TO2OR_v1^o`Gd1Oc|FUBSBJH1u_^0$PJ6tkR?m_|sOC;Z(X`jO z?dhFj-D-kHfKwnydc0Ssw5()yeqI1K_o(B)p*t_{ISa1^*+kk^h3Xf^c8o_?YB;72 zkf1#Ixzd&&?aEucP#4D2q+AT~oY8^PAX#ouSh<7+dD*#zMJ7AEn8MFH&784~ygW^Q zY2x@jW+cAL+T{beVREA4<VC|Qm(vFABd@Z{APCD<gYu%>@&Y5i;l}bNq&31Whs#?_ z5ZpP1qLNSQ-H|7(Y)&yQk}S_EDRKN#2MnM*d5E#`fcJ?3eEx0RyYIy1Trw;A-&>UQ zTz(z(jJQV`POo<c5%hRry^5>8&$anQd7N{Oe!=jmZ1ViDJnB4kS2ihobo+efbo>xP z<RRY|w$H21+;^judBbfoJAVN;A+*Ek_FdAV)Td{|IAn8_@AMCtZ9^9^(b*;VG1y>J zy6bjqeV)y$(w@TWUG(3<Z0Py|rKPB(#P|fTq}_~*D)r-PUpeKNQ_B<RodTwPxyDCy z2fRDkv~&(FP?F%7XpT(rVB|F1B%yVu%uz!L2Rqm?{!iD}HMR~CN{Scem-#dE%dk<? z4~@9hV3(#WuCWy^N01)YHF#m$f>#WwUVB~4asa0N#zf0fVWu2nl5~Dz^9VZfuy0jg zvanXm|A?3x_TzpvjHTVy;^qO-M%#}l9@0=q510ObFhX7AhVkKCNP*2gMFDQff^O&M zFE*~}BuYW96RKUd&nYLQHOC%>{7*?p8WY24z%2fo7Gw<Hwoc`X!tGP(>Ic`9ixBJN z)-W09u4N@qy{AwSx+xezlu636n0>^RmE|tZn4`?yMOx~wv^{O7LH#e1mb90K(U$Ep zaWZxp|6m>4%~E2#Avz(q4Cb9%)LsX7bi_wI@|G?Bk1`_tgDU{z_7Sdm2mI9JvO<6U z5A;)*bLIMTjcK%(-4*9BG`)*TbBpu-*C^BGi^Fs-W&Kb1!;=V1x?H!n#&b%?|0$bO z^Gl`hj?GQl{p}s`@E@}`n~9E%jd~bt^N>;=m$#s>IJIOh?zqoDkiu=3uGm>hd1eV# zAGsIzMEPCo4~%}eJaQ7Y51qW<h_-oyGt5cBtvYi9SbPW#1dv7QGJIT(u}5J^-bp3| zx*YesI(C3jTN#2gbN%gR5@s~iZekKX7IgJPm>;KSC;7M&oM-<d{-GJ-KuZQ#OoJQ~ zZ8AAZZ{J3*1FxYuBqDZYxwwT0gWZxcxG3VZ(7RNt#_61cI<j_D+&Fr~wGbP$LxGN% zv>EqUuONT+e1t^PaF*2~^iulQ2xd#cvXgBdu!XoRe*uSxP<(!#oFQrvQp!h-#8zuZ z8>Rv%Ww8}w3&)@A(h+*<+{LQ94pWbf!{E*?E6m6B-dfg6o$-C1o9CkJvV5ayMgWbd z22DyiCLfG(72&>ck}Wqc=*{yA%gW=5%1a!<Yym)rI+|e98=sH!z_3jYCt2MZP~qQ> zh;|geRgPQL{UvUkewv#+eGIx(`5ZAM58?C1w8U#O=A1-_5W|p@<y~zbZC938IYN!n z<(8b{vi#^Uer0*+fLEu7qfzfR2TG4@FOI!)FqIs4^{EQMdI;BnDj!b0V<A}n`VQ%z zx)8+S8WU0me$SPGIe7Vet;fVNtQ&Id?9_ms9HkVe<<HHXwHWaQ$J*3*C<zA4X)O+s zJK1>XqA>pH>*-dM1{`v-zSxh4d=n-SKeS<+))ZHSQ(*GcU_L+35rnOi`U%=RdKcx- zwp<|FcnlWK%W@Z>31U1sAJZB;FkohpIAa5GET`og(vx%PfU=2|kM>wH0cPmrx0^6| zdMKQyxblp$LWG`ki>Si?V-A(x9<+J%@!~B@dAQ+kRw!!wA6KFLT<C-vRQx^FA%7hz z^8b`u)_1JUE5=1-2<gqn$6G26c5<f~8eu89T|Of%cYb~*mfUrWCQJ5wSP4XbfU!im z+;3VQz_O)kktXJoZS#{>l2<rqac1GkoVPLfgrbsiI2R1lLLIMd+`vnDi|`w2>zFJc zjFex7FSQW#(Z+qM-M694C{qHaIlLlQnn%cGv85}z3-Rmt^PJ+c|82sKv(diB9m5YX zz@e>a)Oe(eMC-v5tKJ@HKosha0@?b*moa7jto+g<xOR<)qdJ!6$e~=~F_o-wxYqhG z{F<E)$0nDYF@_l?om{!uY7=f_58HZFYv9rYq!t#NPQ`F8>6_z1W1?mBcy<5>7-^?~ z5l)%Qx5h-LVB%ql8>US)GffVmB`TNGg`F8IrjF9Xbfj#IYqqI{vpC%SZyFk{h<IJG zs8ALD0K~SHC>pNVwc6mo9R=u0LNBxd^5cr*@?$8S(>$7d(RQ85PbctIx0wtX#c7<e zcHR_zO<h`2%u%-db~WG3iX1rFn!<oO2)7m27$~KjpI3&VkzZVPh=KB5ZS$hy2?^XF zmg_VbpH(&_2+Q7l;<AXWtNE={+L)Nyp(bg>M5`AWyy<`nX}IRUbbN9Hh}t1wYlC^i z#^so`pxe}2L7>b9+&p3QXU1UIq?c{wOGyl~^Bh}7j_*P^;}<9RQW8@g&r+0^k5vdW z6Vn7#^L6N2*p+?xZ2bD%;Edwzg2Hlio7RjJtK=FG6P;09v^YM$sN^;cu~cWoleX*H zdjsCF0+EN$YMoLh^kHn+y>{8IfL<+eilepI_}GG#Oqbd+wL_z9$nb1vyY>-qg+)%t zaqQv`-7`WDDR<B~Rf9S(m8AIPcjHdKg^QvKi${%gY77k0wp_Z@y{E1&^xzn4I+|Dc zUF(q;am+@1p`<LXY<2-+g|q!wWTxS9GgF6&jxJs8TQ!$7pbBm9gnrne8GYIYM!sEh zgscTV73PrNF<YZ`)$h6HGG^Ey;}CM-f$fDjf<X;!u#i#`K&PgSAJZKkk(pGUm5&K@ zNEx~j#D(`a;4(~Ku5p!W<1R6|g;nWGi|=ZwO6Tr1SVTrk7HIym;EG-I0mlHSqj<ai z$*K=~hjd9>w`zjHM8|?$f)G~}aD~PW@%j0s9n9|$$S|D2KbD(ufO=5*FSmJOex69E zc{))USB#Bi<Y9&<DFhni`2w33+AF>{=OMt>AVu-yiYuXxLiscetAwo>(s0EKR6j#a zQ@y&ddF?<Unol+gr=2PsIq3<e-1nm)ALHFPWQZ;cQ7B#)&$x}o5}#Wxc~j#%Wdt48 zQ<z*5A31_5zMmm2*9{%;Byliua0*yD(67S>n(rxKP<G&IgF60r>e@Xy4okNNWrr0_ zSzPT=t<<wjdr@MrG27V|*{*t|ZM$S57GHiYoUqmjD;8B;SjJu5C*)_GT|a7)M@$+= zMp2$Zg9Z99LkaV7u9#aW{CMK}2`lgNZ)#u>GP9GkJy$ukH|3Pdx!OBNqX+`~uvtKl z?5@TnVT7eLmrr$l8==c`$LIGJ)@@?Gt#kM!EY{>_7n<0X#$tdRljoxTz#OLHW~9kf zA5YZC^_Os$2uqt+gw+tzwmM7NovVHj9FP-T)7y3!6ww4V&oje#)+43#z=ByA%URW2 zY<1YGQ_)$|eAp+U#(k;q@@9Z$J5x=|6{m-O+_V&5r$W&v%_c!zTmd?ve#}>dj!dIV zE5ywf<@qpzymGa#4;6o@8OPmd>wpIvt3e{h%Gdx_&i0|vIPVq*$&=F)^>{1xM0gZF z3sDHr9+UD(t}(U`@fuU7%8(})BeW<<>){H9R0v1PxFo*!kiX6bM(D}egi1ZRaA%g3 z<J2L0boSrH?X-B}o@(oWeB)Fh#ESky6qIgU<5V-|Qz~`SQLarHmaPQvNM2oYFY=1L z__=wrbHf$#-_flLCw2Qj!|Bp#*!rKvXGhBY9&R1XN(U)+eWgPD#8fjo#FMQ+)#y8P zDUNk1oXc#S3Ap?Pm^fq5tq5<)80d0am?@}@n3>!pm9<NAhU=EUaNkZb?y*z*qa2{^ z6m&hi{5sbuTr!67(m{FdCk^=()rrX^NiC4g@}=4ra4Z}ulaaq5yM*35J}_sF*|=sc z@`T3Ep)$;#U4oJ)EfejclTbqOa*6}xxF<)(v=F(Yn{&p@A^ccj*Zjk4>o%hJV5}*W zFP{BVHV`BD7+0JJb)##_H@-6(d7bgC3Pquxc11@V`mVT$$}11I3eU~9*#TaCe4uL@ zCgpOCbrfDX8)E>@*j(s>BBwlR+T9nr#@PlBk8b2LvW|C|F46h`5j~1-R2D|c;2IOU z@yP&Jd)_)k<<wo6o_!e4@goqYMYq#iO1ZkL2u+Y-9w#H}jCo!4;pA+GR_1lZAN3?E zG$?lK(KRMXfIC&m*(G|kWg37sI;ZIxn{utOvb-)Q_sqf=wcb*lf?;~+87(3Ejhlsy zuZ|76Vj>uW;44WSiiedC-E)N71m~wATv@poML0z?A8@#)6kC5sZH-@sJH<35)z)0G z+U)!?Y?Z+f5S_bKS*)v6;C1RBeDhqi!jeEaHw0-uWHX{Ka>7Rv!W<5N=E31J{2Pf5 z@Y*132Xx{HX3T2Q?TBDV5XzBh%fbFe838{aw&o}8EK7a>2R~)`OqYtJjk@BVA>8Gs ziv0WbGrGU;z=vwau20Ijo_W~38_lVYUmZbU#*VV6E3Sz-b<Pjt6uojd<Iq&Dy{a67 zZh20DsJ30#zD*b1ob060|GTtZzT7J>vC$Da_~FoICzayp%hsG~e=Z;5__j=ago9oX z=@33f-E(*dr<uqLuXy=uPQkie=3E9GgOXW2<50b~<qUb5d(9>!iA6XVg<s!q!>#Mi zsVPq&g{P*>oy${GUZ1T`P2si3tY7YZ!wFQyCH`nEQ5HoH9$G#)+Np4S)B|4^EqgMY zPZ>N=xjl@hEB|yto)VEH_CKe1im`dR7AfTE?K$M>>TsSo*7;tZ9KChSSN)0k+DE=p zHD7D;EnWRd^EF2D_0X&^U2&cCd-*EHnFipE`+1b!qD#sM;M!18k#$DbU*wIqJD)fv zueKC@eu-07aHd}Hyk=aiS@mJy^qQG}2BY8P@dyd$oRm255LX<{jcoYPE&8_H^5_M* zAmuNK&c)fP<>mM!P%XAa&yvSOM;H2|3y^D8etvQEY<cq#_kDrR2192j=>*+$626y? z8cfiNPeuuJqF>kY4F3!0T;!(1_0W^c<LJ(AI42`XJDpfDZV1SF0`qxm`vbTQZo*&X z&FE}LUw{vFBGf$3yzarCsdc!%uip^<g;ADOc|2QUP`Gv&{t&YK9*@UqPhX)hfh9N7 zb^|kMBlTTKEP{8>%Qmu`?H2cw?x~)!8~32j=uWDi?KM<`<vr5ty=@V}@x5y!--k{z zU~hrzD#pcc2h0BMfQ!{UYUACTaCpc~j~{Ex6sfq@Zkiae_1`$nMH<d?Fr3C2IFg50 z1`x|>?XleCV2PAix=Jj=UUsm&K`du$EW?SVF8^>_RMlowi;Eu*FbQ124)V~bJX7$} z$8cJrw}rC#{%T}fm9{7NZsix9!1%$(a1Kz;9^N2-BTfv_DV>q>b|@tlDN4>+0A`9j zd9(=bm46FN8l~f8kpVO4M_NS7R2(Yu_K)#rFjOB*Ymv%$Y(2!t?532FN-<jVD8`?| z#kd|Pnh1{(Lmo@_d)!lvJIX1>$iH<U#>Ix&L*h0_Y>Ck$l(HBpN{ojer5Lzs6S5zg zDk33<E)ogJ-$$y{$sth-x|V>~O{ai|#Mu<^>s#<A4pIiw4oLxDLG?A3bX5WtQNVMh zfKA~7PQlSF;sR1<J<0Rs?s|mv)Jy?KyxoC-Uc*zf`1zv_x2&hjLn&*Kq6DmcgaU5m z(J(p9Q^iHKOsM>#EAso8WJ%kE_n>!ACeynh{TjaS40@ZViG2%Q(qE6(1h^PD1%e+! zU5f;$Aeh!HrT-%o-FRykCH+cDe;)dbsH(5RrJsfaY{Z3Rjnc~#+g@J8>ODZ|NA2lA z`tjt6R(e3Jg`%wLy&{yd4k=3dtq)WBKk$H@oC8zE&@E08D&QzmDe$Va-ISR%{<#G0 zc64wR-=Tv8)5O}vE*)GujXF3W`b~!T%`gY?BN~0$0jYzRQ5TI1B9#s{PzM9iKXqW@ zlUksI^T;4|AWuDOT0$KN>fr2mI?zD^d7=)4So5$W5G~-+P|DAdqI6KRjykC2VL>@! zs<^PmDMEq2L#jr0?;S1yvtin#F>(@Qi=u$H(CE{I6z~J6yK!Y_CE#`nI6AjO0RuR# zNQ@<Q3MkJkd+Z^a_<jo5(vg6(3{U&T3+o(iDPVFa<wc|@0pELw0=^GL26OgL6|pZl zMJQmuP?2eOxdbeS^#;BBg)axPT?vyGOKI0>`=x+Kpv%VRIw=7gDBxtcu&AnkhFkF( z9LpqbCUpuZ&s2M5Ed^|#fCu00pa$;($5QDH;&0G}WyNztDSMEj1pIC-1#IE5PdN=! z#gBjQ6k#)k6ya8Up~SK~=tb_v3YXA#z+3?rw`4=!>tVxUISo0jK?)s7p?N(XyD85H z5PBBeT2$5Z;X*(DErdo7ri7LUxow7atG)Xu^z-kzgl4~ZA7qds?-L(GJ6dFRJpNG1 zKae7N18e0Q$h=PkUW5v~`@}=;imQc161>g__5<|5+i9z5`=ku9sPM+G!7ybQLKz-| za|&D`9suHbU7z4M0qvViJ^BkOcKqEath(s}mi@ghJ5tKevX=>Ht!-Y<Cpgg1WpicO zGeTu!P_}6)i6*k(r7Sq_nm1q*@(#gQDsZ8fSI!KcbjB9AA=tZD3?6!<?RTB|H1axJ zu8iN<%Fq}F-RT>!P=cSyf~?Evbl;}!rtOsiXP~y5A~8e>4SNoP!Yc3XT9~g#jFDrX z#So#XX@!^LS4<~fgKtvvp40K088_aWl$DWY&fn$wK4B^8iQXwXf%6Z>NfNTWaoOI4 z9A9=u8uI`o=hA(hw3PJBoa~7?-mIy1dOvr1MrL+OM!L>G+-JGd6H~HOBGdY~(~?qB zy)x0AmXVVU!fC$oPTJW{IVUa6o0j3E4+u-o%*q&_<@Na#WhEE7agQ${F4c=od!*;Q zW8s4D;W|mm$l@_19M@vN>io~6F3sR_(LU2Y?7`(4K*iUntUz()I1cwc{$A?d`Ro4+ z_g1$wb-D)a216({U>o}&S`?n?7niSrA+O@-gJwOLDc(b?aPRV8#4}^ihLm;xQ<vz( zfmof$K*MXiSvU5LBpv|qsH$~fK8%5yUv<F1%OEOgs;+Y*UO^RXG@B8`LlV@SIe8Vk zMa62BgdIRObR^`~F98DFP8A1kbeO%?&FqtCZjHYIXKY~G$?Q(}t*EMBv}g8=j+pHQ zDi*VC542<UfCRaj-78@hvpXa}F*`fNEcLJIMQZljpSNp~cY@_rUcqbAJ>nU(#k$7N z;l9FJB<+c9FFq?{vd;@kO3Fx0^kzvrBYeC!J0sJZPWw-fOY_=rU)&_G19xoCwz`i$ z>d5L^0ToN&KLfMO6ryXr_jnCG%JD}{t(D&o1EVoZ17x+m0tklqa->8zK9TP`ui3W3 zdpy{;Die3CPZ6*8VFw|dR4-I#(-c--kH3T986@b%UELw8Es_WiNrbd%4@oMeVh-{% zVBbA;ig@iz+y<`a5%&?N+wpw{X;yg;DaRL&exk0i0!}kb%}zUpuZYjk?V9a4EhRlA zEoB;<OLnqUFkn>S5qSl1-K*k)<Up@r-B5t<d<J#Z>OZ|^4dpqO-P(4z4&VrXm-?;| zO_#`*PW}NE<8I(I5%Gb|%=b3()pzaG)NTEeM^Ze?yWaH)uvAoE0H@5-tbh8+l;VZC zMTL3M`eSs&GI5@@PG`JJ$2D{eVbsVgW+85%cA}Rpj>f0(<<SUi__4n-dZAiqk1m-L ztrk4XQC`k__vv|WbM=e^)wp#0DDD6V^kDz}V1u!gdhaplvw4dLJqa#t-h_^59=e$o z-tNK3s)qIG4WaE!&ae-1V6ju)TwZ_tNL$smsH#EmE!X@lr=Ucl8<AH%IM@}ZxlW1{ zdBLM?*L=t+#Mi)x!EVLU?jHYz##^GH0B^JSC2(f?=v2h%i%^RfglAY5%J9`~hubPe zL|MuejS$e^tx^p1FKHS{8ux()v=-r6a=LhP;^DSN^sa~sG>ZWH)t#N+04)gjHikrv z1*ie>OJr)wT{R&h*p=M=e#Ox?veTa;?q20RfI+bMC33IAkfT2Mws<ic&c(YAa}4pp z;-hT|je~*3%oYn4LVPL1#bB|nu{i_C{{_WHI5{3c4xm+5yAp1puJKLgLU(;kch}uj zoo&>0wzYajP4$e;)iX9#&)8T!qosO=sGhOEdPYO_jD1cwGxV^jM!TDd1ylqfdEl~D zX<L;KZoUuAD`)HaB-pA5rXq%=TJ5Hv!t3saMY7>$vtX9H;7fMF5y?)$+gR`yx?lkd z4s;j1!!B4DDtIFc-l7XuuwVle9mrpmRzqLF5q$!SdTU@ITj4!68y6KL!J7fvWW2^e z3EBkEMkQx=3D`Jos#w>Akru@V!X!AC#xF2_p_FS$vxqbo8iET~X-~xAb|GJ+;?ykq zMZ5<kCz3(B!Y3sN43ate%AZNVX2-P+<@?Sl)5L%S;6kbTAO+9YOl%|*>>mQtH7N>y zQ+ra^g_F8Cj8ySTO)4%#>I39yJc=<D<=sY7OGqkBlcMwen8n;u?UEo%s+T2TGnDyY z2=^Vt{g}qRm$;*e`+AL=>Z!DGQ$1x0^EB~L2+t_unWXU?BA&hQ<AIr$I>y*|)Zk*6 z!lX2>hDrS-NSg(zMM}UX+CYfh4gecJ#}HKZP%R)=NOHFJcLm$2WQzn@D%l_bp^6^M zcUJV{AyU&xYKbNlO;X3<Zd{~t+mlKUCp9jNRMiSiYE6jLSIE<NrY1F#q#hutA6b?0 z9gCTYrg}b=04)>V-;wXEWgieX)}5(zluB$~V!K>oW6@`ATzFrnP)!s0ELp8f7O><Q zEP1JH)GS%5a<0nRDgtC*H_Ttt2qx-si&*aMOq3glmM?BS7|K`0e3$BcE1B;(=IbYV zf9bTZRaAQyoo7As+{-){sTTS`H9R<|k6{5#{VHO88^Z$H#AcSrVTlmewI~Ef#Bwiu z6e@R^lpfaQcCp-f?s9jB%6+~+RPK)~H(Qt6&vKul6R_yr6e`#4(@?p4S?+ROuKN*` z`?b5=S)p==Ev;p++&36jQocbf7jT#RV7VjT*_K|;X1SMjxsfb4j^(a&YV%2!%c+4~ zs1D`p1oR79sUOfJ@6d%)S=htEvPw_?DkRkJm~WEKH<S7Hrki}dtb8k&?@FC-5%X<w z@||Vno5g%xb-vZix19OTN9C>O2u&1PnXhH$_j@VLY+&Y_9i*RH`Fb+n^E%&F=DUXZ zrZ{t(wfAz?fnG+rr)s=9jZL|yg#<xYUWDdu_y+Q;-r!?a8Tt-PlIp~-&^j7#(q#6K z%&s($L7ym;^<GURx_4Z9PpE&QC-2vuW+#hgudf}N^KF_VNb_CXgGJ*wK$=rXv!8f1 zRN#K#Y5bke<2i~vBbmqV%n=>}FTs8-n96c7;Ng877W%zL8*f(~YpZOy({!fn8VXnd z`pRihmeX(}M-+$OKlhEp@5`?G0+Rd@NManxt~-kFS7{ddl7;6}!NLefHT{7R$`!w1 zf3I}=A&D5>vQ0I9*+a=WoCr#Zpjat(30TD3bydz`@hwhamsnN3{Q)T$jYeQxh~cjg zU!oN7=Nwq!JuF^FMOJMK417L9GC7X~kxvX=fDz_hAf~yWh=j&lHSuH;|7HRwwLj(f zRE`{uEpr&~yBQc4#=rubfkef?4XYT;RJPX>`5Eo>G9N;N&0=n-CU?q2a9CLc4nID_ z;qbReX#5M_X$CXN;Y4s4NLAd;2yyrB*Dm!ujufipJ>+)Ok|nu{TJx&ZN;XmZHR|O= z{oPF=)SW`8Z+D|k)To!(s3#nfQx1*#2(mN|)To~(>W6_ks_K46uTNDvdL86O|0z;X zv7JoC_Or<xK;uWnj<fXoBJxwO2SEXr03A-Af0)xB&C3GGF2KV8Zd`_Fo38w9GU>-V zRl8Nnp91-BQL60}V(|8_FpJi;c!mUT`(1=MEt!VBEfXfF91PpfFfzmTBh9csB-1wk zIT9MXX<~axtlA>>;N6ZkdRfFClVB2iWV|MZ`M>mLB=$0rL&Tn8LDj&1LSpMqQ<5Db zu|XgfRrOm({X;?oA8mFS&K#uJ?ds<!=@`(0W~u&Zmik9YOd@!^@?Vj1@;Q`Tp+07? z;BK~9n0ns7oYwyl)8A8$HO-j)%0kqQz{0Aon;K+l+^ZK_dmn=Y(~{j1%(}}_*@w8N z!SW1GBgK|r4@x=`JO@T#K(+*aiOG^+HUO01VHPwJ{3bM#IoFaPXsqka0!VOiNP_Qx zq_Mx2U?e42JDw7}>D0mc3P*y0ZVCR06kCF`YzZ2{2qXwtb?`gn-{IZGi1I4$F3ihz z<KJF{izvlAAgkKNT(F3egDaQrjSLJ@{S{W;>crO&NW01(f$gR<bS;dKia^sjh}|%a zDOfPp2?HtI^?Ct0lfu26MB#ccm?`~c-JOnbW50A&PnR&^t_6Qi_4JU!MOD2(Q9{1+ zufzt)5dL!H`Zp*lxqb@nAXg#e>KvFY;{dzFP0*QA#y;_PW(}3Bb4uo@lGI3NM<e^7 zkw-piGa9)9{5B2Hf=BbksHYEJq{I319H{3q#HDqvqhPo39JBmP^*rLGdLkY5Jbj0w zp7Rd6)bklqQ1|@5GsSI|)hI+SFzu-6*BGNS!1I(_P0vcKSV>az^oKR7RajzGw(thn z2)0a?Oiu;V&{|aG(mkC5r|t0W<yu8kH#~q#SWbg@FX3=oEL7Yeeui>*ph>C1Lsa3O z+G<XNz>Zp4K~_?D340?N`yk+|)$$1v8av~i4tF`#Qk6)x{F(Hm)vQ|TsHN)xms<XU z6s?v{wptDYgQJ$8V~hcjZnZ4u7ZRhRlI3`%K&|mcwBG|k<~-nJTX}{rlJ^Ag4pc_K zVPM@6@LVI{yLk|B1e%=|uoDFwtQVa(QoyI7!l<glj({7NI06oBatZh)QaTc_zb)X4 zU#NQjIS^Vx{!U_bgnSCGl}j5u{tGDTnGhArmK94nwR!wKS9u$1cayVD1S9$DIHQS; z;5BnzH>HWk`64xOJ%qG0aXvKYXyQz%PB@5Nv!RJ$ogGcIfQ7~ZcxP4bBfWK?7ghDD zqlqVPcQkSC7cNcgM@mPU=mD0Ts(!9fR&}1Gg^eg@Og|CN)!yCnBIyg~MJk!z0t-r} ze6VZDbQ8FBWEzJTDR|2)$dt{vs~YMKp-hQ*r%WxBsUEtEs``^7)1QCh$TYsuB~$Mc z$TXU@U`DO)2`N*lCDUGsai0<E;9m6cSa=;53rXPUL?lI`qoDORfgL4Z6<D|An+NKS zd^4yf4wD8@K0g|}mXA7X%%h8fe0^IX-)A6$8Al(^S=GoQnt5V%o*3qNP31YpsDaAU z3Z5GodM2J^=6Q^HhRTr(gAJXL0kbf1K?v_omJw7W%1mdOc`VakaK0S%l0rOz6;P)$ z`I*VfOrdzdvx|vX#shp9shBD6=PVc0<(9KtPnN?R1w$z^R3^)9brw6i@_qLd@vA>M zLj8p*youaBLIk^h1O(SP2(Au8uy_#=?37ceX(D>G6P5i3@`Wv!#2~b`%DYjmOPx86 zoz}iu_T(Z`zO;yaV;PUW;d;cQ-?f*IxmJMzrH6}7-YF@*Y@b@cz_`zY#ajb%)~J{- zBP*1`@|gN?O$)0ozU-`&^znF=`H4fpQ_{0FjI<OiJ|iPl<zsmip5UG8kdx&R=JBNX zh}N6HWoB<$W;VYwGc<iCpsC<)nhF-8iFvpu(VObc#_D*AH$6McS_gLEnl7?Rnp`sm z@80xD>Rro{kd~Mom!f4MEHf@EE-fJ=heDHAjNcRt>cOMKe_Uc>d|bi=Uuv8$*}xIo z@MK|edy+SlL>vR#!*kM8vB;g3kzsU8eFNvjoQ!NQs?njN@Ht=y4q1H38Clt8jf`}3 zolVA`ffO=Jn66*nRA06?O@SqxIwX#%zR4MrM~##z%ug8<JUuQuWs;W(gll~PNv4yR zxRuo;B*&$P_8}0r4L9rd#E}D=7!M9@{n9QIGBRl%k``?zAtQZ~H!C~So0WhXR>~(I zq?zR%-_G7h6YxoKsX4B;z%$_iS7w1yDd`ERIf>xGmlKays#?<Q6P_<gSuAO4+zN-J z5aJWKsV<3(bz$lb!9dbQnk-<FY+7=EhSHNlN?P0xfpRh}EhjZwH%m=b(M34f$&)x4 zE!yHq%OT6hr=-VaO%37JX_K>3U}Lhihtiadj+bfPDVcHUiFOV}SMw(GoQOAgefb|{ z(R|AMC*V`2h4V=pO!37fVl6l|11e0+NO$y>;>*mK?9IyYd9z$;w5_C!^lamWNFPBd z+A@xdg>~krjWUGmwg%fu$w)*V!dM<woP}lm@wn_%!pJ{-k36~+J8ifv1)fZ=-L~j; zz!qn*Z`!}jVxL*YmphZc!=0-3>fa({6RY6N1N~)~4&Bc;W$d<E#M$$Xw>4eMK4vX5 z6)@9aCzkgoo$Ivu$4yUrL!e!El8cg9)ffLYik(K6YtU<4?F;RBO)>mbpCMDcM<Z z3E6DZ8CkFtwnKoW>|6uyD4q8G#4uir`E?R5##H;aH)vgO|916^UHH->_%&Ctk9JGZ z8^?oKu8!@IjP1{IBX<(EV0Q<OdqzV-bl-arZ@dY4MB}a0#2)cPj_fkAe+Iyf5WMj> zsI?%<4QIJ@mRo8H^+2Iz+x)SimHtd-Y8=^$r~pwjU<f=bi9Bb|rcUB`iiJLn=re%c zmHEdybA<S-ojIDB2Wwu|lFVz@ftMQ!jzTf=kHSKFgOo6thR;o<)}Y|_$*qWRqkExH zn}}#J5zUe8Vk=sAaV@g5Ea!4~y_m0hSgcu<D*HXLa?`LQXKRT?=kYj8)LG!DF;5fS zMxv1<n!*Vp_ux7xawSqk5z=-6DCwjVl(S2YX{L&n>ws1&m%QCm4!k`y-hITo5#|>- z7kI@TtV$>6bmsgg0|yYhl{xQbPQ>#Z8~Bv$=j_4QN`;`$!)iFzn^xuQ5w(MDT)m0w z=Nebv(|~IfagDZcz49lHm-ldiXhfQWrrd?*4O#yhO$^ce>sp}c2@b_yceS-OUZc}e znf5l*Y<5Q(b~h+?`%88=kllxSbE^ymqmpt-=W_-HAbK8g-Ai0HyS)s%8^q%wG}$gR z=Mc?$jb;ha#5(K_CcDdY+9OOGg0!eAj+q($urzaLvDR{fV!LvBD;iPMvU`v<WCzbL zkWK3x&Kf<Q-dKY;ojWo1s+S3Psa(3>6X^P#_mc`gLI(|SrFT{?-6ugGN)To&ZFfqH zow>;sir6Zfmb7bZpakGK01!w}YWf2hYuu)S2D<$d@*9Q?pt#MHDt#mrC#`F`&$fu; zu+he4I_GXFKXOJ@-K~Tot&fYOL<wQeV(W0@ETpmLLT-1X`Y)6V?%dRAnh3<B<z4_H zmNu_$m;W}EKVq8jGXK9A6af3pWa_8z%Kkol^_-5^3cN;D4daB#fEEz6rf%7J{KN%c zxWE*D^9CoBhoB|N;U9@#uk0KWuf8VZ0?YmYL9yR;)0gqMyBn(u`a6c^&c+cdp0z`~ zoj9zfFWt@@3B(3`I)g4$S<8HvBWmPp!6w<y9LU5M7c2U4*9!Wv^4n$4q-yOu;BofX z90miJbBe-C*ejL9uvd}<x^llhXq2*!-&FAfRsQ$ngFJNI0$rnYcQJvPe#xK$^fZX7 z^Nui@9M0EKc#WzWr8Ox*7ZK#vWZq7rNv(%+NEFg#;8mr|H!WRm!E93NGPz5*E~VP8 zA`VNJ(r2F|fm)YcDZ<8iMwe2xkMdRP5<9L!-nIb=@V5M(1^aDmy*>t<j$Sjs4E1{E z#nkKBmpgjx#`rqu4S-=bmZ=zq((5hciF)nk==B?@x-pG`4d^wKiaa<R4Ginaj#JK* z{OnP_;sUi>Na5=Re2u+z;Zhdf#KISIi@?!L$LF^3YG=n6=8&xqbv><Tq1#z#j79P9 zg-W54SJ{6LAq2B>e>zYhW+J`nPr+E@&orhQV!E1`#)gU=EP#$J#8n~0)X<-i9Nc}) zwy9#x5;W8#jcPYheRdU4-NB(ur_fM_x|3DDCWKfU(q$pkvXPca+?yh%iqXLBxVR6I z%~WCIJ210GwhKgIlt^2VEXprKaApe)A9Zqo%uFRSF_s`(iQO?d%JQs)?1s;o)Y{f` z2a86YfuiTL=+#!yyV?~kAtYzFtl+8Qp=(k8M%m0*{_j_!JhquQ<`5@yYjYSo&8m+! zq=ZE{BGAnv5?_mk>k(I>?PJHH=!W0A#{6Nh*iY=B2J&z`&N)CrvNvG@H*@D;SdW<% z;T*Rnda(mOjnhI5*u9B*wyw(kC-!C<`k3&=O;xi#IW#65LjlGfva`Hu?=R;F<GtzL zEbPe7Nl(GNOU=lcmt$zmKN2u^fCO1`4rqcbOxJUB9%-LskG(nHL^%mpv#`*Z+`vIA zAtO;w<B*^D^n6DiPj3(sZsznn_C84?B)q?(qw<F#WV+@9d+`&z8Hg$PCMY_bpL1S? zIaoWHSU;F!pRj%y*g|C{;79UI{qa4{mywk+9uwA7qE%^}r}>h-so3~03y>#%PvF49 z3Nf8J#~d*WVU&byZ=#BOXyr2f5~QcaP4Hq5H=_Vd$&yuuUEQcd%<p{C?0h+Cj!x4u z5>t|<W~SIW)iD7~&%Ie-7_kb)Gw1y|>6pR0QdAntgwi-$4Z$(F%#O=~S!Jd|+aX*q z{{#kMAPp2G!wd3z-7QokX9FpLBlo7YVgeTYfPN~er|F&G59}#d0>+$36MfJ}s4zS~ z6QD1XJymHQeMvL?<N*nkz0=JSs5alro|rx+Ndko$A9N#R?`+ejb?56Fd^HmlF4gdh zg#8k$bemlyg8cwCNTBrX%_xM`2mrB(SB-E!lAwLq_tu9FMh<<5f8bnr{BIzB5Hc;H zOh1CJ45XkOlaJ4m1HALCvC;#?l!H%J#n44?@h_pQl^T$A4vAZTjI@U}-nGR0`K8p= zGJvSsULn<L4j)jY&Qr*AA8@fEwkbl?+y*B)(3N<argiB|t2@{Qpy>{p&TE`;q16{` zLYkO61YXj;%{~pxFi=c?BtDeA|G<lotE2CWq%W1<49S+0nvy<2+P01dNlVS1n(0kV ziDwu<rm-D`Y}HQH@eg^f!5iGQ{<S)7p<ge@^0+T(%mc?UpFsE`{OE-k<P-m%$Hk{s z;T>unCol*pJm%oQP<9PB4d!4*ZN9FPJVleI;`zlTx8ckD0FE?T5WPU1f)-tjBUI#B z49KGPX}e<*+pA}6tDdpfiPg;L>o9A5T)qfU@in?)ta+TV&Dl*+iaKaq$yo&=Gb@?r z&nnNIe{}MsGEafdvz~dLWghHq+f!4+*Y`GKY>W<+x|xg?&^ShC-o@0V$Q)Jm5SVwx zj%r_NYr}9p`IoUC(RC2_>C106ACEHJ&%^hDV1h%3{UT;1KkLIMX<X8Hd?uEnynD9@ zpszhd8Z&ks(aUQ1ZjIl)?H65_JE5fUxgjGgxEA@DUVAQUVp}w8g2H?H0ncAyZBbQ^ zg!9_V;&mFz>CZ3Idxv-hx10Z<xNQ*iHn(5>IGo$xzJ;Y1x!{b?9UvaQ<rI_eb=X}C z@l2c1>^6uqB)exi><;*U?7e$@Rn@iky+Xp(AW=clqDBlB6%hdyFK9xtL!w-^BmqTK zA_*iINKE!dP|(moOW2@zx7I4C=Nzn5siF-LEt&{esiLByQl(1U8ACN%geZ|b-``wo z?Y$HAobx{KU+?GhZWx(sjycAdW8Uv`O5K5|t2w3}ZoK>opCW-B8lGo88%vT#igMFh z4J`=fF!6m(E(~Am&y295t{peIE_ZEU+sg5cT9nfUzmXQ%SR2^BGO&#rY_sdri59(i zBOOX-syXyb%(E%->>|&zaq?`DJnLs}PmX4&Kf>K~oJUh6nyW-JQVPjqX>;ARs(5X3 z_uzBHYg5g_hL|@kBx%!5^~?#=LWww5BF^#IcU}`^?*}{GyQyZw<{1Ba@!#X|KP3M5 zsEESz)DN_tUIZ5%P_9%l4|MxZ#l276Ceh73g{pKaoR-v8_DG-Dm>YcJ{UXi~@mV4+ zFzOlhBnZqzc)PcrhOMcOr^Lu(p}#^(^yL}~4LVhv%B1H$_1g(&P$WY|a<!srji_EW z{c8hjw*=NXo;77qJBd;oSidE(!Nm<~2U8oU+Y;D>9&0z^p;K2OS(9c`Re1&XVRBv5 zFFc=?$hDD5H(cQtTFz~KV$W@T5<R!|!ZfvpY(sRnWUP}l8iC(oQxD!xk=tdrN4P$T z9^vZpF)8A$e=1KTdfu;=_W^m|cX@AZptW&PO`10CL3zc+dXWtDNG|e8t`W(L9?5o* zv{TiFj~(&a^4`^)iL!F`DB2(Ji1vx-LlK=8Ek~DH)onRq<u@8b3sJFohCEL?4yOMQ z(^1QN@6%-=N~=AvHD}5_RqjjWJ}fSmn5+F5Q6)AU+f>uIJsJaR#NM$bETXPr8=iY~ z=dF`9y4c|kH5#!rG<BigZ2mZYh@pO<=KH7QPR*E<<(?K5j`>UahPe}5OssFl962jt zu|))*|CTcE<%LBqt=iMvJazY3?__ks5~cc}w(U|SFbxo|zR&i))hDC@&d9qwN^WU{ zch_N93B%p*E2@9l5wF!XSFYN5)<5t#zaZ!xtdoC|MStBk{@!s$>xVZ!iNlY%%04yV z$#eVics_0%ebt=YJbJnA3W)2U!ti5H3Fx*l_w-!sH39GTaqI87|07@Lmj`@q*I#e^ zp><9UX~vXNST#N%tR3Cr#ym>*LE)i;h7RXX*p;U-NM1qEUEmorE)ahvQT?mjJj9(h z(&{eS+&tc-%Vo{nMh&9_ufMMNWaN>_I+4~>GILmG%gisBgtO(<_{=@E%{pOTY(2`Z z6^_qymzR(^NtwpuIStbvO}OhZ<0j?>GJ?TzxtZ>8g^|O=0tN{b`F^&t`@DZ`ivO9i z_)}Zc1(RG1R@HOC9y25Tf>a1IU;eyDpFh4`8%*{QVz8K$<^3*zVp*{7@_v)-M?Yxt z#Z((Swqa$u9fvURs4ZxVEb0-tDS5)P3H0eA>1-b9PuYIrB+B+FYALpw=cXKLw{>nL z*`7?LF4$^<lx~hxe-vq;m**``DGlwqvdzQMXp&zV<G9B_13iLN4&NgmId7Ux-`P8% zw7TW4N40qCQ7!J6=$FU)T@c0xoyJ6u<7V1VMAK9KaYs*dHJei0eK~eW@y=CLhFeGp zjW{-l<1cWy+i5j2$cuX5j;ZY2&q;{Uh)P?_W+yK1tvOQqa>Gswu<mti8~r1Dht8NN zFDDeu2m90j#D+yz;d6A_=y4=Q`#ibuiQ~AVRmq)roVsYfBZG+k{o)1@Hz-5{`$N*P z>RgEo9jm<M1j+c|SjmX5D7`$$dV({F72%2F-F&QiQUm8a>^0w3%%W>3So9<4=gj zx2pUbpZ=DUJ#Bn_@|5~?ZRR%mX@qi1y=p@99C7JuUXlv0#sKDcsg!M1vbjTdeNE<k z?1-fYLdQiCpP6Qk`U7*ai8U8-)HISv>a-_Dws43yve}-k-Q(o}_ekdc+G|=OU)2`0 z){;RH{|6cct++mcsT4eAfUok(g1sW>yB<{w_DYqnP{m?f&0&IKv90E#7`BHE76aOX zJ!1X#_X_2nsb<KNb|QJ{5d@PylHA_nLMioe#^dkGf)=Upl0~(c3$04~xqF9$s3wJS z5Fzuma5Pt^Csct%b~X2v+kQAAt-^k;uU$*qL#HqOC^TqgU@u2uKSVM5?(7cR6M5fk zw>Fe{<abgg^ry%cvx1yZvuK|aI)Nk@Maazo1qR6vB2O;ie@I?6QJdO+o-4KnlJ@Z4 zk}T+9qhsoro5(jci;NTMCz=9du9a^@;1=_^Bq}OfO|Ig@BJTj%+=~Od1)N1eiD;@1 zMyQsU)ax?6aUoZ_d!QUF4NaHyh4JI~v7r1PI&_+?SN*otrn{;M-6f_o)i%YK1#Ajm ze4?Mi&rnOXnnX7~21W{)v}iR8Nh^IGP5w7W9A($S?8v|Q<`*QNAiahv+yRl0dC{ST z-K!U#)P7NDKc7=s?ruIJ@(vU?{nxkciMyiC;m?WFVC3~PHFdEc_XzRDjYV!HVHU4d zK4A`qISZ7D`o1znzK44?->>P6PbdP>c*-OY$aLfB@3=HHoq7yW)9gkK6`(DPvB?+J znf{#@|2)-?f%xqRNol12VS*O!Wsay~&UrY+UH!AZa`?L(7(8)#g!*HbO;Vl4X`B{w zkb_44eN(?Gpnm+WtIL-rzTbD`J37YKhx1uJ-$e1f;_;0VU$`URhgU@XJ0gznIPop_ z_{NEEwD>r})?&`);IJ?MOHPG1UGLEqiLRgM*ofHThUaE0zr_p`liSC>6jhssdOQoo z^Ec|&xH!m;=`{8Ul1;LRni~0afLS@k-96%aq9fmtF}}pSn2wi=?<J3Kz4&evA1loE z!VV4db_Q)MFl;cc+6@+A2*y;?N4Ix*I<)5@tJ0ITU9tvs)M2?RN$GcHobFr2ccI6( zSA72>Z^eaqQjG6saeQ}(uZzd$41({uj(jJ?_>PI=n<73f_9?FVi*Hd!zE3B{(mjsv zWbxhQ@eLDSpd;V!Vtj{Gy1aP#r_yw)$Co3%-r|do;|iBE7RT3Fgd4|skH=*FMzW6d zWKEZ>muYIlncAoymu9J*<@FJwz<BE`<b|kqxstfa8{vi|v0M__+00EdDs?+2z#2Wo z_a4enk)LZbu{*SWRs@9AKeTt|5n7OmJG3_&&zr8o3uaQ3S*OaL>v_3MUba!gY9Qtn zj6z8)XmOYOin@0a_cO8g^4K2|`->gf2gb9n?AnQaH?B>uQ>!ZZ*Ngquj_jX}kMsSD z&Vl)@*jIS$jbgu4>>O}Mc{f5Hl>k3M6oq$M1b4`#xhH893EwLeS)QC-l5>!{w1b?f zo#o{Ea*|_mo|Bw5wGjkopX5A^oIXo+i`D8i8|Xp@4y;~h&2MxW$8uW_>oSfwja$Z9 zjh91w&_io#=>s2Kz38A5>bbn&;Ie)a$#$o%k4mQb4VUoLG`9YAK-zDj)%0VQ%U08C z3u9Hy9u$o>C5>pYJn)SbvOI9$QAurRdN-NY#3&#=PDA)V=v;<V-CX$f<xCM#aUA<< ztT5b;#7=$6FOW;u#O)xAp%<;qXeVGcG|iXrPK$l&?^A&|V*-I7hHcMfXPu1RW~{#{ z`?x?hD<&>ZYeT}ZXp|$Q<ap~}nFW(r(#f~mRHJyt#6Q5t#@Oo3#@6jLzI4afdiE*m zWMyfL@9m45#FT(026R=8b#vv}J$2%W?vr)L>@oZ#m=N=0JcxGj?pQv`W0g}FJK>{# z+p(qHg)6VE7%N}nU11nAG9Yzj3+FC+$t8x1Tk5pDievY#u~=LR=k7_4;UrJ99xTQ( z(st!>^wY<&c$;tKdE@phmP+$;83M<zg(_Su)&(X_V!hWJ_R-&GL=oAtGH=L6ot!df z_aQSU)@CO~G6&RV_lRVs)@CP1GLvevQzDr?YP0)BGLvhw`!h<b%^ncR>|2|i8p-Tm zo1L~Yd+^G;haqC4(#ZVt$b;>S6!I1~GTYf6`7p9Q;x2rfw-VdhYg*ewDYcnH=+ZTs z`NaA9gy!xeHiH?ld2yr8K3v_fDsQsK+!DEV2%Y64^7G8<bL^puq!F8&yR1)$>{{|s zs3+BJqZxsaNQ28Oe+g9P5bE$Ff@T^#RyH!}yDe@^;xuNE0-ZOxc6_Ub)-5lv?~0*b zo5?}#(GH{IMW@Mn0ai|XZ~>IY!{gglE^Xx$VZE}5DWtd5oGhwipu)d~$UB!^^vc4_ z=3$8+(G#tuDB6p2(vIQ-vVFZf3WGe-&76Q3%eaVk<1TZMV%&V>%6sKc<c&McsWAC> z*{yWv10v&l-1)1w%sGTOHXiry_ic&xMMs_fV|~$lu%;4)!`DSyqW3xYN=w8ln%fvf zNFi#!p>9=gx5tdU3=%sRZ}0vZgw;EiR+&T9{3nv!Yxk~~{b}r~;VR@?62A3Ws)^31 zkHwvQJl^$jwp#eeqWzJrFPjvO7HtXabQb^9PNyu|wI#5dBx<!Td$t7j%HmBan=OHT z4F7g)q|e~gt&*qh6N%PXYn2mI_+|WVKFZT}gDf3K?3co>UhZqXRH6R7JL%DJ#7?}o zd*#fV7@JTqehl+=crG_@eypQg-29lzt>(wP|FQ8z{7B-?p+A;->%f`~WGp7<)xN$Q zV5-~vdl+MiRbC%)lSu9q$yqE6lX$j&vmZiDWeiasG>?uXa@@Z7)k>~>k9W6t3oLJx zv)<$U8Z=AJW@e1{WbyX*c-zE#ym-edqv$H1Q>C4oYZ}b4zD3>bo~}jRhQnD3LiKr3 zjb0;3nqKjGe<^1pwc!Y)j`yYhMGU^w&AvrapLH#gy4FgqXJ=-IPTH&Z+ceXYohI3{ zI>^4!7pIOvk#CXgDKXjOtn80F%Py7dUY_i9$v#4|+0x^sK?QtDgSDW8<`T<qQ}O+5 zICpq`z3Jk7i@X=U)DPrGnO=yc$Q!Ojfo#wxcX?46X@9DhqP3Ft3r||Lq}51T^hS!6 z@zSbe(!w!mzp!Z>*STGZ>P<sEnX4u9><%(7h?hAeCi9e-%%?ibyg)KP^!kR4lKD|j z^vsLKS31nZSG`kB0N;F`E>SDfFe!?aE)-wZUy1SNW6Z@v+_1a-Qf?D#kGL1v-=-9q z@A<G(J}i(A^Q{jq_3klln)D?&WGcn#98f{?bA;Az#lH*vd{-d6pCmc5w7;(?*AC7G za}0iYHR5#iZc4yguZ{`I{uPB@HKLIkU-v+b(_HTkXUIEqMyH(mGcj%Qm|Dg3qL@y# zy5rxep5j*%BD)jBoQsI2<sL`!FgPOO80nvY=(m~{g^pq|HJaKqlL{*bm8Y0n*uUvt zH`pDj=CRT=O(JqSh<N)ESHwVH#9wi?B7*FG^F=g5)u~Q>fXab6Id@WJRaaH4ZzNE$ zcGyaxx|2x(Cy&mRI;yg3zCW8q2zRl8wG$45<+<HR>#qG(@$N2Nte>g6HjjNset$<Y zg$qv1%a6yYJ{R4DiTUh9@?By&`0E3%{EqHg!x1m{S!QIh%PJ}uy!?~9{QD{Q6FT#E zQbIDcMlufZJke!k+P)u)MtVYw<q(S#O*Wh6I?&iXDRy_CrBNStVqkp!L><H#Q;?mF zUGlxY?WFvPxO#Z{O6nf6;=mrq66J;qyOE)~o95qq>n$o=dv)A-7o}C^L}^ekfgNU9 z?p_ynLzSI3jGpIFpDS!%ATWq^-#v)jnmjSOxRG=YzHKL;xCeONr#m(LQkB$JGlot3 zTG5D(vc5!w20+IrDqG#uet`DcUG9im?@-5p!%VSxbo)lYgLvclu2qY+<yS6T@)37m zZmnN01+GS7bFN*`Xp2--Fe^TQX<4Tzowqu^JD@I7a%8LSP8=@6)Rk=1v0@^ts_~9O zIx~U8350d4Nr57&@fw6{)_YbLY5eM8Y0T^*Z#CGoI2q=_`6b1b#i?9vIk%jRIQ9|W z)MEcprqg5Lu&XtiUO#<!Tv&qj=~(5*{rG_ydC!DVLCU;|Vjo;{IHt}pk8~F$vZ3j` zm^#dLDsL!Vb9s&>)xNosn#nUFdhF)HRPc5#RQ;9@=y%%t{C7t6pv#_xU*DhsHykvW z^+~F#5@tK~`#c}N!$&FizS#wl`p7FpGufQZCJNmyvzht$F3-m9ko?GFJj<#Y`97A` zUflf;x?Ukwzt#-FJtGudnjvskj}khr9_6&@Y<rs`cCn=#R#clR1%LB4*^mJfs{rH3 zpJdFxD_(a*UYF}N@5BxNm%%9Hu7d}N*N@wzY%DCz$xZK*iAH>6_7MzkeXhZl6Fa}o zzOPo+)=>4{k-n<3RYh%`6<?-huj^upPq&m-@kE-Uyd?AXdE7{Ppm~@sO-8XlzRPsO zgoH?<+@8lxvl|U$l|MV$Dx_VC=F36fwP%a?W{Ao0jnP~@3-NOJ_JD%de&`3mYyH*+ zuQ$PqGCc&73Tqj~l>0v|lMTBb|MA8*N+TQa>~sBqFL^C=l8)e$c{--kYStx5r{)1_ z1ApN93)fYtIKs;EQ}OSl6Jt-bZ+<H-#V&+M$kS|)hWs!{gWMopNLu<S=B<VKYa*?& zl2Cr0Un1?ruf6J4fH0rl&+aVJalCa^24oC-(&SEo+o!agb;t|c<W7OJuDPzOWL+4Q z6`7J0=^o)ujFHqlyDne)(ZbU+M;uVPZY5p6KCF{POj@;?_ES|g*=+CtDVu$Hn7yr2 zuez$JHl-v3af*hMzfmF$BA0f`xF@yRlpR3?MVaQoq?Emj<mUcYBFd|VJKV#r@~KOl z-Qf_otJ|lu>=cRWlA1<;9LpWAyWH1mxa?IciyvxP(QP!EF7YE)jfO6n)uM6IrNr(7 z<g4)U?&-;#Bff2Szdr26)r?QmK8h|)bQPlGG^78#O=gPu!@XRJJD=2vR43EZUCGt_ zPaVUJ;DOyNI+|PV(Ucs^eU$h^7tuGH?uolt;!gRYxa%eEbSq9LHze-5n7AQv;?_yr zQJ%OfCGKtN;P5#ev^z%PKD<xb^+lZdaz6U#CgLroWfc5xX-SFDRfzvC@lWr-|IR(| zKM21GPv`paT~y9zN8Y~-_H)j+1^cMT<+@vHi#bv1{6gZ6u=d`vS7N6Qk^A=-V!z(= zZkfD0Ro*S?;9U{k`MWCDe|^ATiT_}fpK{!$VSRu0JavB)6fnI_v;BJZS89!y_1lkP zF<y(G(VX@?$uELx<Tf<@lG>G=M$p$um;1?n;oCasvg_`cE@?4cW?c}|#n)z#)uxKL zw%Yu1MpT<WeHhc`&;>uD&DUQ^n^tNLSDS6prl+(yy@NKFp-uJZ^BZ#=r_a4F+Za8Y z6lhA(dKjVDBfht&V6^8<+0&9Fi{xJ#YD3a0lBYy6$P*oAqAtZ;eOG(?^4_~&_IP#? zm?mvv7f(t$JU5GHbO&`_fTw1(X+WJ28~*fRJv@#uHZ6p?Zm>9=Z?W2^UXZm@n4#8x zZ7{d#c=x&Lp6xNOgZA>JqkMUR=YNZMzN5kj4{{m0iD3sT(q;t}j9;`?i>Ir{lbiw1 z7V-2lKjSXdrhOV+qrd<;{9X<}E0BcKc%9@bU&J*MVdoE^93{#c>#bFl{M$4VkH_yJ zciNuZ7eQW{_?DWk>2^<gP&^aG^K+!{GTXk9^uR7v1Jmsq_MW<w+s8WQPfds0o38Y@ zD#UfXxQ?}z&hngvHX<hx&ZZF_(Gn5uC%hdu_p-93ZTY(*?`u@L#birG?<}c}-E)N~ z*turg%el@~rX7X+(3UG>Xai~|5s95ed_6)kIfGoVV~s(Kc|tpV13TFJ|8$(ZlO=Bn z@)XYxN!<YIhR532(_Y*yX04UfLE(EXYFE%r+B2~sc8|omRn&O2apw<^x<OLEq=5)$ zYeLWq^SnECV$jP?0oMzyg=CYqo|NtilO>03i<t&T(+3*fBXoy^J}9A=_!1k3Ys2kc zZuWcSp!znR>?Y9URCZ37+heky#7B3<3t{^tY`lc!df`^8>|BK=enP3{e8fspsNIP9 z=Q&8$MaWEM`8wxG?nqC`9%GRE4UK2m@<`~(Q6*1ANzK@KYL0Q$j0#_Fg`@SACK40B zA1ZsiO>vMW@%Ksmcs~v{!{x@oO9v3oHHx12&m@k(_`07N6VJ?tul>D<Z(bnTS(1IB zWCz?HSoK#4Hh))2Pn${2Fx!yy+|pJ1u$<<M*!kb-;@-6XP`m4v&^$;o9~br?)ZgKw z%`8Q(n^}s8GR+?xiaqtxLX{uga~h<u>RzV7*4$%Kt=VGwV>UF+qaJR4Cw8a2JBHCb z!5Ce>lg|K^otA91(n`uiZ5-4XM{5@DURBmy;_mv;x{`|@J85D;&~u56nO(OD6FDh1 z!Jq$SalqrTyF_)c!}_7SJzRQ!A8KqLD^8Y1YhN8{?7mg&ragO}8yzO?R*mVAo5$fY zceA99Nm+X75yj@YEDEde-a?%gr=sg#kAnY+cMt75oS_oVe{_1|IPPK2nY>k-S{@En zmGbsuA(SP>Gj13-Bz52z`{<*$i*=yho*bAlGgMp|#T3uu!RFWtpVt?cmCv1}M?Up} zWa_}HHQKDYW?(8*l?!6=q^TCSADKUq+l&HZ3Aw_jIFy@*%V+AvUb`eW%`at);Zh$= zpO(F>fh#iu_Ng9!W=C$y6O%HyT`B77@@PJXi-D#@(LR$WQ)_h`S>tLIR^hT@X@NiN zf1R8=u^^B2xr}HUkxPDn*B)5S_qeL-aiZ8dqQVz*%ZoZnXXV#e|C-G1cCD>nc8)8) z@9jB?@4xGp%UynwQ`otioyU1ldst2vwa9H0Zr)oRMWt1R*OwKiX6NxxM^R~|`#9}? z|4fIKA^)R!)qkMK+aw;HWBAaWVR$Cf@3`5)>T?u$CJ};>#EsfD>27#jvY$Rhpsjuz zw5EZRKit%IOr#->;!!A?&-WO$<mxhB?lJBb<8qhrC>UcDrJ^{du0;e1R5?ga#@;6T zSGalh9$DD`Cfav45=pn+WrktVCe1{1(qMNgroptf#0{Y~A_9fXM34<lzu%{>WZb-v zLgzn&%cqSusTF;P+r!b=ID_N9FO2)v1J`z(6`PA2-!|eko-aY&qV{u&YEOxLz4XAs z!P${r+Tx~}f<$w(mT>LSKPJgo1~s(~w^B4DO$f)P;pQR0j{m-t@-5B2^2};^<9Y^g z1smIVtF&&@Z#gif>Wpz1eXD|vSAGb#MOb<s+(YYPckTw;Cai*FvRv$1-Vv!wdKm2a z!VYz@>$x$mZm+PGw!e$r#0?5{`-IgbtLfrmhjHGz?#f5NTHp2&I&=sg3ARXB6>#&O zi>>1bMO__O-cI4rj0nfE^SW-62(4GY_pm2|Z4_4Pf98G{yZh&0(^mVmi(TwPEHTy% z5mt4v;j$sg9mzyyT^U%sy3$2e3svEw0xs%t#@Tft@!BArEi6-N^Vv(Xu_#+3qc-zt znr?Tj-yqz45BG+PYY}dRhpTsSX#{BFY7h6HE^Zr&Z`|PF?s9QC#Kp!&4|gj#%~;0r zVRq@<qU_Sjs*s0Meid#)@qD48`Bk{gvhu2852yMvdrruE|J|iyc<JaJ-$FP^G+Y1h zyu0_f&t&(xpTK;me*Bj_HrE+|Q)5cHGh|4*v*(O-r^lJ;&dBk(PVfA@8I`3Kp-JJn zbBinO{Ef1@JMF|&Q7ydgtZ@BmK2;*G_!mWYd@CpV*yq&DNU(st!EI*X7aF;=`9q1v zvKUG{)f88vS6Tj6H=jK~fo^De&rmY7nUuSt-1%O$Gp<Id#g&!im6}+kj4p26M%tp4 zp4--@YE5Iko#X2!TWeHPQazHMWS%=JHZpB$L~c{nKMu5;Zeyr#*r4FfU9bAg&RvhC zw6YGw%yv>FJH#GnEuu%V=W_?gmcV{WzOl#Z>I`1m`zBNa9Ewa#S~)h!lo28369r{j zoQQ2(0^3~?cIkfQy$XTqyHAO}rLyoiAnW)^=AI0DdXZ)Pt~$^+J8@%5uHCzD$7Hu> z5|PD7H#_(f9r%BMCaPl2rgCX$TKP|}it*nKKauc~rlC^KsRk60se=ncse_6x98`4r zg}r<ARz6c+y5N7J3;6Tw?$hH4DJ&|g)I-*TD&URQpWa^gZ)-TtvEl_>Sf5xqtu<+R z;*f;OGedzPNug_obPM0)CeAax%!hY;*KYo*2M}6Tvco2?&20FbK$Lj|-ONT2Y_bHA z%r<u6G}{zPPht@BTe+>aZp$;<mf^;`PfB&%7Rzmk&&LioT#wy2^0HWzb|(v%qlq$B zoZ0fc;_YwSC)PCgsG&Q!bR3c5W=LlI-8ecMvqLc%%H)4AFEGD&MzFAwlfd-fs$z$b zLJKO26)&1!UpBs-wE$k(>ao0_J(8JZ_TG+i|I|%6-6F?oEd;-9vxaXrE~95jc;m^= z^C@rNd%2&}Z3au;5;*A8+?wq4Sz>pR1X?3`{mn)S8`-jMJ;WwNp3Dh#AMsJsQnV+d z*aQ4-CB1>NC&JAlyc|MW>7)@KHD5~u=QYoFLc$ve@U>4)E|J9cFr}OgDS7=}zGL8v z?6BnQc`~Umw1-<(X7+b?;%z4_mybW_&MUt#nqd(SVR}=l4<SyQN<!pkW#KYR=D+un z`aFI?Y$y|Zaj!HeDl1d7ZS$*I8U5V&C1x{;jCQB`g|#3P!+mS!r#PWrD~aru$jj}M zQ=Um^?mOb`n)!X5P;wO8H?m{N+o5Bt7jZ#xPinC<nI&oN&c_LS*rP!`9Jige8>8(0 z{#G45w=?l~k5gjU$IU8|Yi{lDgid7_Qlua`lAUCxF<xW#qE(Aa-1GVmvUi|$YWw8= za(sdLglH^0h!}-_F8Q#bX*>0h+reR>F4>+dBLARekDA67bMu}9?aK($E^62H^Rpat zFOniHwN**A*Cx+)Ha<Y+t{+Bq&LFxQ*`J)YwYrWNX(Xz*ruQ9;Uo@n*Tml!F@R89} zKAB9DC7BAww>BPn72TonfK$_$9BGKHza@eq{%H`{w$`FR9Q!c|pWVY8iOFnzcf33f z^}Mq%<oN<lO^Nm$s3SevuSjO4WYE&~KKC|6<|Zxst=94FPPO+VubRT4XoS!;OwTo+ zh$yZeYv0&NNc?u>>PslAGl`vR$QZFT!H(r|TzO%U*J{ixWPns8eYKbGJ%w>6Z_lyG zuFt)jkwCgi$17@+(;}ZozM*?}MmDc(UYS&VQP*()$h&90A4y6x_rCdUd-eRJ1g*N| zwJqy1wx*%Sgz)aERtZ~9bss_WgwLX6wFhpqGZWt;yJ`-#hbjm|-SL^MopP<Ocl>JG zgj}yZW!9D*6s$nfc0RA?pkLRa4Ohk&zeL6sT|x1_nLvdU%`|VquIb*MyeiPpbpPL! zX(T{zAvdSEODoSDCCmsgZc%!rhvTiwsBVdTs|Dv>yyv$pa7ek72zr+1?jkKUhuhuj z*nG7g=K#N__9GKJsLg8%DP-?<4&tg((1|hK8`WLA%-_&ALeEebw%ThnQcSJdKF-&o z6#Jyzm<=3?2J1P*D_Fz1ji2-XWT)nq>P5+vP6E?lW|2u_lNia-vKbd1>Txc6^uqI5 zZ8SVf$ZdXjcD^1B&z#_oh39NPJl)*zoUdf@!!vbhTzEEqZ^LuFW`{UZlb(d<(a_W& zT%jrYmqPRPC!Ip`YfZETTD`<^%X&?t@{@PFg-$nar9LtLB-^`L_^4Qjw5!DrQ5PE` zyL=zGA{HXLG9>KyzC_(LVq7<({Gpd}DEqhwqJq?_B>L47f<%r}b=BAWU9ZyfZnM<G z`~8tgNv0SLqT#w4FSP4m1qZMjnojV-MSbh0(#uS7dVxx@9Z2`^Bunh9wvFT|AQfO+ zb_`+FnW_EWmQ%Hlkwx|)%CqzQU@Q-`(R1h%3LoCqXUXRTy6GA!e{|1Gid5f&JyMWj zz9$0Mm(;iYypkL^r}!tu#?zR9%LfOU!g~4Xn*1}=f-irng+ESOsC4D46BOpKl-q3e zgRkiu35R9V;6v>f1zN+iWcdt>B96TL6MlX`Ty^wQJg%SP<Ne%2VTki{4SY?D<>wYt zs1iM2{$1*MUL?!SQO}cq!t-fA@LW8u=R5uu7vLEkJx_y=rf-Y+CxtGW(&rIxIyU$= z$cCn2e^m~S=GSODJQST3eQG08N2l`F{iWsS`kzh@zK;d!NV`$JGM&2P$3({;`xD1F zo1ag27Iq)w?0zoY8JCpdq;wtQJOK2~&2Yvgk8!4h+i_*Cvwv|0D@bFUlIjd+ZDxiu zEi1$6i~HVbxy~kVNx1J=2o2v?_8H@3&CGC$uFiGV^&jIb!wli?J;fPL<H=*3)Y~$g z0Yk^|!s$`$jopES4M4AayQM<|E!v3gaaO(Ny#w7xIX$B!q}FD)jiD_|neAv*dYHML z9i?=pel|P7T%?VSV9jtoxMSgM?h|>vz}*K<`%}}X%VA7O3vpwfW}`=BS4kV+d8S^L zmXhQGS$=O_*lc4DT+Z%N(EeVeWouHJrZn;=x4*-t?mkmihSK`m?%lut<GSXak@vX@ zsE}l-X&mgfnc=G9$`Qkdsu_32m(MK?l~-mnKRJmBDTi^ShsvEhvpmC@ofGLd<atWX zq_jx~cLmJ=?N4+2LW>)95Y#QYztv~7y0RrVcXF=RvT3$@>482=)bk`~J+bmzZI-xT z<<eG|BJXWvkEUa8Bjc^S*J2vXQ{%O^+-7b?ZMKgzm}@|2ExV~2S_=4Ry2^#FoZ+6F z_gy*X$IF>%<@7M;`EvS!XufpiQmJc-?xZ(%uRdK7u7Cp?kNJuW@&tS%O{K`rajmgp z5hRG7tUAg>L({PzQZoJ(Ynr?_TQ}KuRvi%1e>vL%y#cF<MiG*)y}VUh58Hy~N_LW| zj-EZTq!kK_+ob(8f&Cjbukq`H-=@FSx*)M;hf~{4Z=hO=M=iysT8;{M{pv40W<33# z?TqaI`atTr1(yzW#+b~kK=#<2+{-Q>H-5sz;1!ed@(U(Ux$>&1h1bt0DxNv3q;&QT zWpn11SKP?NMR?v#^B3HV_pvdadmMhs<Va>(&~#y|kG3J`FhC$V7|9$QG+(fDiI(s{ z=D7*sKB5~EG#`SCv@|D1s)m5?67Cn{7#1{}<l2hsEyL)Wc>U%`|Mt9bsI42Mdw6H; zO<wKz{jmepOM11o=ddek#X1yBXTZKS&>~&gy046MF3y~6=Im&F$~n{uPrPG?`O_mD z(rqw5>!Cy~D9NW{@wdDY0(-1M7oI}0OgTuwiXl0#{59Dk8r?U-jR)r4?ybc25xZ1L z{*dKQu(StS+Q*wdORwWogBt>+GZ_u_s##2LS2s3^bC~?<)TJMV|2|@~&Xt?@p{Im* zUtaw@)n~(q%?+zeLln2c$Jw!vKUA2w(;F(Rp4Pxouo_V<t9g#UcEV=e+Sc~!7mmZ) zCEU|u&UgWgMnWA%0NQ}pLGD4cv_p^|m%HkTpOWJBJ>CAY9nscbu7o0$y3=xyUC6J+ zWM*|W*}v0gsuINxuhbdNGUw*lg2I!~XOrdVu%DaFd(?^Eg*Eg&X{a(*P_$d^WTgZ@ z#aw1$Yh){}_pOQekU1f|J(_OE;sHF`zyBU3uc0aUo{9-Q8?U6~O=irc(!1of@QL}< zU{C%W4NNUMk{Tl-JINoz2txB<KDTIyGlbXUveJ?e3H2gNeFUN{rDpGH8dG!*$JYCM z?7$>*SkQ7rCMPp0I`iE#^M<|k9Yy?YC-GfISCLE3+<Io_5U<oHZjD?%#5}<%j+Oao zDID;rS1&Frt$!pxt;a>LEb24cIrA0C>k%{!sur@+2H=z|Cmfi$woYqZr<6$Fw2NN3 zHJ<5q*QGB^Npgx~s*;mJJf>L(|59y}LffY(+7;PJTl0-N^`aO+)+D6f7|R=fHJDTC zmF1KVxjA9+gdPs_M#Kg(R0hn)<iDEH!(OG&5IP$BC8yCA^po9`-~Meo=aj1JlzpAh z&$d+CkL9aW9IC%gSY|&=5~l+Fah+9*wzvoPHIe@#{nGR|Gs|40zI|jpj4SV6$6w(l zs()W2TTN@XaL<|-<lH+{8o65^lV<ncsKm4Fz<dpD2&9|Z-CV9<q%19^z_hZlCDJmx zcceyaL1Mpe(0nE&z3d@pzM9xVO*rh#thAIwp2E6(a3n7cL8{}3EiXQ2cZ*a@k>Dir z1e^^>tG3c6nP1E9#?{cLiOO5fcfy*i_&YU=jqB>si?zngeb{4?5#cB<Vlmq5qTY(k za1Y<rEJ2EBwsu|pe6F*WYHVxQ$NAdCSILlTi1?={Xpf1j;fio^<pLJ8W)zoYghS=Q zvO*Rez2D|*bDb8*{og~_ccXx6wf~!bp1JP-uAjGV`hVZg>*+j$X6k`DPR}vrMGM9i zvaGtv+Iwp~Rk!(B+-7hIPO^^+6qSY=U9xfIGYUhc<#R3BHkZuDiEKNlE>6#@imS$i zL!t7yJFNXk?D^#xWo0gMr$zRdQ0`jw?pYV7_k{8|l79IGb4%w|h4M-YSu~U)>X0Tn zJD<#QLX+tyAD!)V|8b%aNujRyD5vj_$?)27JHN<&+7>$vpjPl*qTOu;N4&<sQew=@ zM3o)V7L?o(b!G<&+3xdFs#>+Ot&wWQmwA<n!F3uN=cG6?zrzVa^Wht6j=6uv>#5v_ zOyU3hx_VJNcBtvBS+u`fs26{Gg)|w-PG|cqOiwWG8OH+VVxm%ZBSrIwLum3EnwDEB z(fLES&l)#}cHUpS2JEHaCe4Nslm^vY4W?0LyTLF(Y>(V$N0tqy<#RN@ZxzuHsZq`` zpIF2S8kR_nvW|JfrLYKP67!-Elcz;$lo!m?);2v-qnu#YSlhTrjk18b+uDMW8sz}9 z6x$CQU^@k;I`TtyS3gBXwfOQha*NJ_Dj)youQ1mcf<y9e0v*<Qs@DXZb+|PG_sqz3 zQt|`yLv9u+EGrvVKFf_OyXvD1u^2ixLzoX(oUIQQrL+I`&+0*OM>oyuV@tnnuX_M0 z^YYKy*hs^5b724a?t%7=Dfl1hx9~;W{&IWVzWQZQi?#Y~rPar8D8<#oyM}%#&4zuu zCAQSyU9-uoubF`(ZG~vq73ydk1m#Kd3pI^~Hl}s;<<wKXx{l*-D2b!9Q>$+q?1Zma zIb|?yaZk<D>{@o+>9r%%w$MT!LC>KflC(7CH@QwNjUu>Y;l>UI*}_61$P|!$kBIDa z@8rw5o}m1L%fy$DJ-w!}KRT-i)_xkgOe&sJKCd{n$`;ksnUvMkK~<Ng7BJjOol(M? z9@arsas6jozUEKksg<+Z4!1v+ipp#D;b|nNf23cQY(kkG-yfz$Tw?3=pb}&+I=Bg< zwK<OO>RFSvBba8cA3}Pr5viHU^L~EOXg<E_R}`(fd|b_mC$zPjbYk4x!Jq2UiYX`D z*Y#`vpIh7QS0tr<Qqb*llO#4xboL^b;bLiFS?SHi(F_x;ET5$XAXQA3?&ANMF150- zw5qr$wQz3i;701;nT4UkvePw<VCRdz(o%`}nr#G;9cSjH)qHnSRga4fhLV;Z2p?0M znHG8fOr}d+wJ#uw-0jRC?P;|WOL2MF9i}MaE-LaPZn@W&*SQoO77eavI*0r?m~L&5 z!DT8Y4gL6(D^0%@>;;UiR*XT0a_*Klm2=a!+it#hgIKaVHnQ_sEKIi57VN7nFz(Kb zy-~l-e`)8#E`$VYSt2RW5M+-Iiv{*kDYCYReb^GM6c|#Ls?_GZ^(E$(r%^Jtq#9%g zhPfIA{A4a^wz?U2Ni~3iQuIWt=q;pw^JiX<*6V}YJ8I+a(7nIdkDrqDeCCyG;_qaH zxR)Vye@hbUM!Z&^MG~3Th6B9%TBq-ofwf%tR7ck`_D|9I0UYXBzslBPCPI3xX;n?| zzDCo5bwM)|bmW?~QT-prJE=UIjM>n%jVgvARCEPM<%|l_83^c`+Rqu7s=QLuxHqz& zM&j6-Ta%6sCq0|cd=lqm*lj!6<gqPJhadEBvU!pHn&?44v!-zXMOSCu^BAOY3EYmF z&yNa?T>SaPEPI5yG^e2TBT$dn{FtFgHlM(h=p?55CfOn2n(43RIzcm;{dwxNa?&fs zU!$2)w{R9={3BPaDa-w8rXQsv-d>Xqmszy>P`mr}^rNx$pXOdod$&?14-x1(OV_lJ zE&8Lx@g$jJ&Bgj!!&lAdEBSOn3u;E^+m9ZR6ZO&DEpnn<R3Ee{bLE-C1fC&EUy_1U zD6uc7RQ_8!>y((Hq+~q7T_ZN$r&i>A6gqNtd!E?`Ri4?xW}E8K$(vO{^eWk}*6A@E zyf~RX+&(z8QRm|#{YF}^&8c4=@>y7J+-&~TyUi<^?|x`YW^7-?N$_PAmlcP!oh@3O zq!v*N*xIv-nt=3?nwn)IGOsR;M&?K6+%k>vSV+2k28z9;oIwq!O+;JF;?_g$^&zO0 z3HLCkK%yVJrR!zrm{1qwujx*?X&MMq{SuFCqf2&tJQ;(3bCxJukzRj~M|nq-GDiZ{ za|tpmdQ7R%^oA(cd6dOb%3SNUB1tkopfol;F3Lua@*<b=XbDS{Fr|r|2Cm=jk@R;- z*h8u&E}?l={XWm-Fh{-!Aug)S6Pm}@JG0%e?~S^Qw=N^<`+6>ac3o^?sUPMcpL3DD zrNtuV8XubmSN6m{OCP1kGPBt?zIE-srEAv9co!|c*P{+gm~Qp6g^b+LltiA6?dWjJ zZ4%)=n{Eb%Eyv_QYuDQeD%Z+SXY;foJO3tTPMMI^0nfXNyaf=<$;b=%_&%b~&Smz> zqAiEysDHrvf!z)&yUvB4&CLT>#o@H?;p_?JlZvZCg_YiZ8tnx<J1<;Op;m2t)vPh) z^NVS=t!|b+D=?;Dtg9IL(_O1!F2rx6OEhg!ON_eH7RtXhdv2p@-x6rmtpoMjaB~~! zmp_YZq=z+qN{wo}en-_AXiVkNG}Sk<jL_VtF7*Zwg+eUZLOt;gf4tgUVbi`Uwx32z zQC_IHBC~}1VOjf>yZV7Y;r?T7v2BCJH}d}(Uxzl_#*N)er%gJFlvcvvMvC_Bv<dZO z6g9gGbyTGHC~_RbjvYxH^1A&u-bq7uoX~uJ(-LAxC4G0-fU^l!uG0*fgI~}tF<016 zyz4icnzd@oTTMCrdGoth;~L0zShUFAbDJ{ftVY|w1lqiQj@xITF|pMRdwsn7&TpFI zS37oZ!Dy9wr_a(8QG^<<AJOEEjczIP30+;J#HVMswR5Rbw2=G)8sR^FNh<6mJk2c! z0tXYqz4)7MH(uyer^X{k9A|H$Ub2Azm)y@EWhM8Y?d(L-Q-kJfIuoiJPmL<6C0O6x z+qy)jV#I58s~|C5xQ0R$T$yNw&eYhAUGrh$gF)OzHFaxLNtsKJkM-7@hd1TCOrHCQ zD<a+Ae<{k-`%jtO)%Pf9evKl=5FT?r@v3+BqG7%jkLBN8WLk~TmSZ+FnO6wAiC*|= z`_Z=S#h3lGLGx1yxy?(vW9hQnn?etl`!O!Lm#Ikz(4}fKpZ!@I?!!YBH3@TlB93X1 z?KYbW-t5rw&fbjHi&32nNP}_eYxG*&Xy~s`^B!AiZ1-iqx-b1HkR{b9CEA0;T+m#z zPrPgTuBRRKlgKqomY`wDGXBt^xRw2%WR;S(VysM+w+79rw5N}$Hz7rHqM`Z8<W7X% zCSSpB!m+Yg0VXnZ>B|uajHdS<cZ1pkNHl$V`ANRpT*QiRq+s`z<`<-aH#`0%E45Tl z=2-$poE=x96`9#OaG`0@1T*U^Z64aANmBDHn{%S+IuYqM6o01#^8OQ<r1{IJ>q1<0 z7U3bXgHq=nYjTbmv!Us8;=Fl}SB2pp{kVMYv&wYq*+JOPj<4$n4yqcM+NqZJ@<!cG z1@h(wX8mkkr@d~O9p7iLeTo_7m6hR&5H+IBPu>=mK#z;AY@65BJWnxZD4;{?t&!Kw z$$unz0zFQ@QY#t>SGIDR-&^;(LUV5{14O&U>*2hrW>K57u;=1MESmRmZtZGjNn8WH zb?vhuz;X}u5ueuL6U{AR(s(y+FNQ`8fmY5{?RWdzQ$)kc`<fyqEzOB+{EJ+(U*}fC znRUqo!kol09Pe4M?<)K}UO)-3>)2Q6t7dbO8EfSPTDGS5;47MZ%_lY8_#&zKnr*Pf zb>Fw&x0^vK3?crIJ6xY5yjFdAc!if%>NDH3;`Y=jMPRS3VGBwsZ}e3l;1t186sTxs zSb(Ft_IFU|8=C$_{oxPz-8+*Ty|TT7XAFphjcUBPK)-$=n^et*^deL~@^AKi@P@6n zi)rQ^R&^7-Tz|B~G;N>XcFk<myiP&M9~Ov9D+o2C)t_PO*E0!g^koX#)mv4!&<PdE zhf6DcA8JOcpXh{>>&o!eywiiL6?(0)eaG8+#a<0*KC7u^liMa~du9;++6In`uFOoT zuNLFAsuABJye9QebnVv)_aFl5ck{)$9di^hg6a04O*6I#*qcP++~SgaLBX;lYT(Q^ zk0f6t{XLS`Ey;Fs^>meQUV_+RR(o_qpflGINmLjmG>MOCctI1pe>%d(4sC0H%uYJk zmN(K*j%$Q4L-O?|;SOtw1pBZ5qd8*@4Qs)UI?YX(e)wqJ4y2!$8XE2&XgXc<KWi+- zM+BW05dH-54n8*yBTc88R~H^`Hzizz>N6*VhMQsKS`-e)F+XgXhr9&y-7)56Vm=dQ zcZ~EZY`mv>7yE8(sPyE*>~0&Kq^@0O)~9;m$QtfmXj^wNab+g`=@30NHy@<X7l`yr zVSHmEs*aA(mVVw0Jwek%oNk;<5NldfLmW>R>v6Ew7ZG;cHm0foe)|kV;I2#VC)4=R zR;?X}1N_+NRkuN$e|_l?*SML1)jY7PQPJ^ym@+o9*DPvf*XH|@b#5NGi?2T1Ue`#k z+RF~>m1lIaG1AW_(xkrTx1i#>;g9M}Yu$E{aE!WI^gFC&kExPnr?u=gGiBLjEyi4h zMQfE|74seXx{29N@`Uz=n>$!&d`y!_wv)OwJ-P0)vHo|;Lw}Ec_gx$N?!STWNbkPH zB?BC{ciWB}6~GyHuS`LW{YPHN2(`o*x1whbqphuT2nmcTZqwHoW4g?^7Y^Mm&G z=+?v@Ol&<>N4N&yZnC&1)XaK;lJ-1*$W49ft`vTV@CW-bt2$Z(Cr78p-AS*(C292G z$gth~Odjd2oV)(#=1>1(@v603sH=GqPP<(rWj`J9Q)iz8eV0!3FPb}`&w=_5sI8;v z$&;Qa@n-W;vwNAcy%ZMvZt;c8eOHgpB6hjvdW)^37!<@x*?*bF-`Y~<_pD4(=-YO) zRnvKIlZTf7n@;UtKeZLVt3^ReZ7^+P4igPjYqsP*e4*FpTpl>+&u)5=S<tACprYjz zYBWn;J%4}`?qfeG%01|U+R1gU4fRGeeU{XcLF?B>6XB`%)KLh{t6p@#3C~o$8M(=? zH{EVeht!KPE+t36c;uGAfrPqk(&7$oXZ0J2=0Qz+o+mYv7vV4u2NP~0ux2AgvsYcZ zu+uF$7l!^=uvUxWGE&=5-?Q8(-@3h(alqdWw4WJh8Eq0Br>d{p#p&fLYko<mrum(^ zRFd9Q-ta92flB3+ueBAH0AA$hn_GOjl_lw{3)za!mdap%=8OXemsht^Z@O8?+)9Eq z=T?u_xZ4R2^I1<V$#PjcXSo;5I5@QM$nnnh1Puejz3Lhjq#Kgjq*9`}{j0dvyKmF8 z&ym+B8KUTTZhSSHDG7d5mfS*_Q^FjwrA>ExxWT)7_P0@@<~~go646H@egU^Xg0-{E zm)TM)PQ_A(1l^BTZV`9hjnnA(rc)4C*Y{R*{v)>*n&-Kn(43CoXkOlXqxK4ZK`J+0 z8`l*nsl&56J8%6pi$<oFs?p>ZFsW<v^D}=ytQsb>6W4~Or{HhiVMoe^{`}O0x*Yj? zDgJKhss+#l(|xxc16<<!9yD{<Ty2xhu1H)&?<cq>^dfA-`1IPRL9~=)w<1aVs!J?) zmRxNc?CtLK#y`oFv^KV%;&xL0MV+d#<?nG}|A$n3E84wPzpE#OC^|srTR5G=anEDS zs4Qkhk(scv@>zEJ%RiQ3>CS}Cy<%vdd%j2K3!>K!dAQVbhn_ohBquvgw><sfnOIrM zY0<*6xcN0+Gt?;>*MH5OM0HB#=p|0lOT01sjPf~i3g;H3mX*$RuQswY0cgCljWap6 zlo}3Ymd~kR*`r9;AaTf%4tG)NOwO8wO1P}aSF(I2_TtpAUDss6skqY9MRCzl#?|Ls zqidc@-RE3zw*HR6^v=ho-c(qXT2wxl+o0yAo;UKW>q|qabL9E;;Sje&g;Fay$D~O0 z+`KbVINjvR(%H=)S<|rosJrqbZa+3((qZ01@pslw@fL@|m2+A7$Sy3aD!wSS@cQyf zrMf0u#HaLd*O6EpDJ#2_B_oUP3qG126N-zAqBB-5-zeOtl$Mnd>vkq9_4?u&g>3YT zrF$F`M4lG;mEq#(T+iu0;m3~!*w?oJo(aUW4ncRA#*O#R*QGG3T?xrnSVoR7T7ag- zb5o0oi{}t4bBkx_MZL-ezWkp_KEc&GpC2?Y5u<VQb3g1h!M*VNDP71e1y0J9N<pM5 zj&+_ktGM)sD_P*>e#TF^|3pNHNBPK05=DdOyX#*LZi*vM|2X#_rjoMz_2@QBIXBfF z8&_c|D!x8EYgTckO)EPWV%M1HBH4Sz`YrZb-})hZx~*Ol%h~bsGvCr@P)F-;)qY3I zTpvD6mDOTiy2{R*m<KhvP=H7?vOvR#mO48Zbfy}KN*W2Sq^M7q2Nu04;L_MZNq1=E z9E>{u)^omC^|skS#jBTS5+c3D?9cG6`&INVvDVxCKxhe!y<TjjO5)1;n$LM5qs?SP z$tx!Il(OtcVqd&ye=ZZWp_D%`Vdk!od~z=*NBZalLaVFg8z7>sVmp3_x$sHV(X-Z5 zN4L~zOHloGMk#KeK9`WJ*@yKp?HD@HwS~_F4vRdh4Rq$q3RY!ys>%4C8eR`Ko5zJR zn?QYTQFPMo6w0<S@4Kij=GG{x(M2Vi8$hwO3Hfe{o&O4puQoPUj<ds|lV+!=wTko> zjW@mdl1XFI*!-Mr#MPs<s^ElEOn|Nfea&REb058quI7oBxMsOe)AHYwfT!<)?ID6} z9{GwDC{6X5tJnk)jhq1_opQrI1~t5Y`LrU(Z@`qtf2{q|T>emIS1@eZvGzGtc5a`1 z%Anp;GIT}VHsqT}4k<YbO76zuZ7O&uNMk>1eB69vpQc^w(DSBG(D-xoF#l@tG!B}h z-`9j&+6Q*}`x<|3`fU8q;^5s3rg!{;HZ;}Nq$*6I;yD%NmDDS#?!o(V)iCI{xN!pu z8=87}yY^mvGEwb5Cwg9uuiwh0bvOhg@2p%Z3R6h*xS#doATk#)Z5DBzJ|~w4P0D-f zoVPLK!vPx2-736CM&;E{<8$TGy~wgJpqrgcuQ9tg<$(1lB|O2EzVcp6lEetbJcpl= zmGWLA)^|)#`T3mmI=DsC;i02z{&9G+rj=(|75+jb$#x_2lD_`hTD<68dDUm>e3CPo z?)}h*LJ>3*acyY2g3J;(i#OV8YeW7HnMXaG*D)KKP8Z$Zy$quKp(&}-s!4fgU3%%I zLql^au)20kTW8sMb=I5rY3r_b9Qh}Ar!Mg$TS}M78_t_hPM@O=8Noe(ddQ~sn!Q^B zhO@VO8NpP*Vb1@CP>$!lBA%YuZ@!_Es7b71;wEU$BrNs}Q)uA9E!u?=zN}+ZwU~=7 z;iIIMHmtC3NOt*ps&zOW2NqAY7Di2IW}{W}F=K1mdxd&uE<U7TM4zQa@$p!QPI?^& z7sqTR+cq?HB^&#%<JkFat!>#j8Z>l7*o!3M#vO;)DX@Z)zDxbsU?Q9PW$nao>6!0d zmCGL8bT48a%2JKJ-;83W!cJPWnO~C|G@TGSQnTC~0y24Z)P*PbbKU{jl6~9x*rGY$ zXZWaDN2_^ntNG>BkWtO;9Hq^yQj{m3(ewq4W|gxyEsLqU$L^{#2PR0nJ@q?rGKGJ) z*_*d1+Y_2k<Dw{+=53E=uV_YFnm$X9MgvXd)$a$(Ea{*Z)rN5iqgFab?WQJpdhX%& zk~UnWiMi%&JE6|By-U&$5*r66!Mx+8*7mrm>{d->Kg16GoY1FHnR`ESXBHnsqFWuI zpxQrIJGE#7YEf{<C3-|mE+_ad`|5|t<#}8*f%0Lts_Z^XnkkQJj+CP&-EpWr)_|C2 z8GA+gH8Q1zc9(5(H=Ums_1RpVeb{d#$M2(sOk<JDEU#7zY2Rua5G8H81Yc}3x!?5W zY$01k%o9&(vMQ<1?ON3aQ9bJFK1+}FzUL=i(`RW<G4V9lMsn?K^;&inUzm(7^7&nE z3>{;~R6VOlU(5iC{Zsx-z+olyieLG01o`sxgdusM)Wh3CqlTOu>V|n*^Qh&4!@LBr z*Upw~p`vd-&BHvybdK2|40{pwnqThaixX&j!5;m6EF(70Zu;auwFG+D2~WjY_m_Q5 z5yGs$Sdsk~>KuES7n5^mT}Nyd?Bd1l^<&Jc6`C_)S>s74$a>~Fa&d5t;@af%$<btW z=dU!6kOt<yCq%U0ys}sW#6C-S8#h)MP9>J*IQlV_;LNp@1A0W>PQ}qUniohX>OZ;s zTS<Qeqe>-rBBmm0b~K$#D(eA0Gg~|o2%YJV?>??%4YW4LYUMv@_Pr%hd|dvfe1G-7 z@Pl0E`Q89Ax30ObZWr4=%wwYP-rs77wZUg|DKp`<ZL(co$F9D*>S@{SSQ1l%$g`~F ztVzYQ^5#{ZH9j0Fp8tckTzs}|FSA!zMBTls1KfQYUj6kVDdjcoPdNUH;rWl+6Bo&K zJC%;V{x=!G?j4+U4SNUo3%3-U?d?zluOSuV_YU4UGuAsOX@pu!30c2W6g^6m`b!CJ z_|(52OMg3%p}|#bgPA|3(EUL_wzm-UkNz%Rp6e*=o$t#ScV@bCM1EFy&YT6AWrbB$ zBQ{5R)ifOy>R!{-HFR$C_1-@0@X`LIg2z{n)|!M9N@3>&9|_(T?B=e_u8c`upU@B) zlXP&`&o&?2b#X!%YP*j+e4NjJq#@@pf$VZS(61`lg>ogW{4opIG!--v{?cl7Y2VS1 z<z6_%{yYt;ydlY0HX>@kNqFMVf!X%iA5*aHObb!U${SYrY3c5*aqI4Z?=lg-9VfMx zi$Ae_iY3|9F1m=oJd{JhY*~8X*30eFb?%0?&xGV%p51Vn36>>HlW>sh&Rl|5Jc1Sx zoE0PJ(wxL`je0#m)Mx2Z)OLpvFj0A|6w`R)k0!3YMRg^mwV>qasN(f1_$r=BxU$>M z9*vWI`^~YMr{s7Wniezm5oN0Jk1JDAw$I9)J1H;Jo8f%o&%(W|zD&;@?80mxRi3K7 zQ<{TYy6P^<1aC6eOk?8Eji>KeKWIKj>MV+?WB$Mrj9;Ref%{?&Rl<u@6UO-uz8YZh zT}xhoi=(M#DutYmmpk(`2TMcKlhjVp{d}=<eRkfsbNziWcE5{zag==|R%O`Ys0;EY zPqH|h?mCNOE>zWY=WG1wLC42DsXs&6D_}Bi=Fj5``E%$u{5dj_$<&^VRLpkG)IG~C zHFLO>2R>h&%b&)1{CR9Sf9`vnKLwxhC;w~y%+hr3FYEa8ZaRyMZSDNIjt9`qFW*#j z6qIaU>E|?>>8^jl_f+~ebt-(pk{tfJW2966h|d#n@gs>PfG1Z&O=5bnzJx^$^DOaG zKk5#jZTE(bgW-Mec$1R#x~;Ny)hhDH*6J1fT{|epc59~G?(5@ve5*Xps65=hv4u4b z%jP<SaabdqdGmo-E!8}&sjt-fjIG)VUUgI)*>-p&j<8QtGkMO`LukIImaG}Q&{h)3 zYh;?||3pIfa`V&g_%<IvBZ==uCAxYnLXT*q^l7?JLW?DIt;cW#vEkOso)_F^VE$`) z2UVtv>uhmV!sTi(5?|@&o57g=eKPTF2$A;x>0cMl?&=PKWvS^-%D{AI$)I#+_{ovY z!;b-<(4|XaVp4a)%c3&BF5vuMg8PFeF)6W2cP9bL#6-*_{akz3ZkV`tliA(=ob&<N z{#`uwQlnJ;xJhT2_j6~29gF^d@uzpMI9)j)h1%)BX2AZauXTdJQLn%H^~c9K(@yJp zGB-n=?40C5{MU&;ich|iLngqWp=T6HRxMjcByTyU+RO;1^2!R#BFvST#hABa&c?h0 zGk;dPb3bOVINe!=xeD`6%pI6_$$e(Jb2sKanD=1r#Jm@?FMRi5K7jcEW-6;Pzs4-V zd<b(N=5H|9Vm^pDq%_@m)H5IR%*Q?R3D5kUXFiEp0sT5mrB{A1Tg}K%{)TkVh`Md= znc@7ZWm!vY%kq{;%ZiqjEw{Ja(Xy)L&X&7c?ryoK<=&S2TJCRophXNl0L7R8OXnli zx5$xSI*<zJ=b^Ndw*#L|$S6S%;y#x4`R8XihY3ds=J%NMG21YgVSb1C0Oq%t>o8j} zH)9^e+=+Pr(_nss*@n3vGi6kU^KZ;l%&##=Vt$30gV};P4f9LP3d}Dsmtg)2^B&B7 zm}@Z)Vb)>lcfT{mNw8l!ZRP%Y{5Hd>=CePhK8DDSd9myu###4jXPR}db}FoUwNs6` zdGlsx6((LdkIS8p4YFf4$_`?eb#Hf!b#Hgttb4nY{IJ}e>H(Mun8Ps1*VQ?gq*L{D z%p}Z(m|ZbfU{Wzuug2_-S%*m)Rd2^+zN~sLW-rV(OxoV+zK>++1-0s7n7uJ`FptEX zhRNK2bqJHBtzL%7UbyOqFzK&Wug7GLxw;XPwSelqnDle2+c3GmwYu->42M0S)q^ov zyQ#hylji>9AZF~>dwgDMUg6v-UaP1qof*Ub@Qbi}zXZac=p+%^ZeE^3uJ33~(I%kv z5m5Ao@<?ct;pqcsPhz9HVxZG+;km>wb?#67u4;1gZ_>3tO(Wil{WhJH2DUtqHcAKk zExr8j$Zga~z%t-F;1JLTd=In(hk-6Y60ijL1+WyT0URI!Nc6tJIRBGg3(p%PGJe%S z7ve|ZA!RK%PAXsa=M`ufa#f~_{s_#@2V6Pi!8j*TrUJtN-v`%Sb&1v@PL+dxo;(?; zvhz!|f89U6B-!MLe$hHcA0EGT@Cd4{rQ@F?Ji5&;I@?KdiG6#5F6QUw+rQ{!w~qSL zRq>SIr1O~yD1_4S=9XJp7VwWxC-s{#GJfz=9?&l*-u<9YTaAmK4sPBO?e3nL&aiWa zj~IFGdFPM1z`ge%Zei73a?R3-guz-|9d^2y{)b;2e{{(%mHqCigRlSJu-h@Y_nyoT z_`QY9|5k%I|Gj%7t6c3z{I9%sPMK3ye#)?6=iFR&{RyQ-RW}rl7=FU`qcWY{fC2Uc zmq`OEvIHOzQ2&WedAqOJX7}R<`C!j^zbYJk@ta32PIi9hjQY)uKE2AVe#*bfDauYV zWtSUutu5m!&&rn6t+rOtct+m)zmW&Ey&}fz<7Kub24qwN>A+^71Fi3Gyr1!XsFvdb zKgcVwyz}F?X^gri;FJK(x6fJj^@{AQm0kW)f8vX8{`##qzUwvEymi!_zj|)?S4~r{ zDHuHNkp+)jaQWIDf7^N1-`@SV!rK|AaCgQj9y;R`AJ^nR@#rh7H;lQz$LeS5|9aE5 z4<CGM+<y!je%Z5s9C^zZSATZHNppUY+5ewkjM-GM=F`H4TMolwf9om&PThil(+K## zCAS5laqJay>(qExz`6LIfRh8{1Nsd+C$c#eGaXQ#cxX5K^a1@8zxsLcT#Z?+Hjl7Y z-_twbJn(kFDSMCj`Y7OR1G4`8{p2~{?>Oq-<<9i`Ut7KE&O;}BKKS8ZUcRd7;YXHV z`{mP;<)^jsh~kHy_NwfRtW~4F$aaE231GU6b^0fcbvQ+xk6&tcZN5@{;p@~nkNGW@ zX!WglR^Af`ClHT*@p0l}{&#;VF71jV0WxfS41R2^n5#!&3YUYac)Ajkd|6$DsrVYX zeyo!NOb6xzD}aZ9b--p|C$JAl`omaf05B352NVH5?Lxlq0oDSW0nzRP_5%BX<Y&e@ zslX^82iUP?tkVX3`qcZ=jvqMdvbt-^9{Stl>90>2_Tr{#e;$~<;jB%QKkD`OV^v?P zTq<rAUy3{JUpN6!{A+$raj*Rz#{;^5p1zCvEm7K2`PO{hS-{DFX#HPFdX7zJrFGiM z9H$6)9O!#{j<Xubxg*DE1D34Hagy%Lan=F-?*b3Z2i5|qcjq`8fSh}Bob^Eedvlz8 zU=^?f7<?Zxf&TaBaP)$Ul7W;5a-3?Q1sL^fzJWSm576Vm9Oq&n1gr;IfnmRa7g!5y z2lfN059K)HfDo`9NdGM~zz!h!VemjJQ2j`bvkwTaMt`918gv7aAI)*@0R}vV9q92m zv_R5-<T%TK4ZvO??LXlKmI1qfk^hBkU=z>^T)7sxz<?)moC;tyum?!}9q|b~4(tU6 zKgl<+1ISsI<Lm~ie-GVL=nwRNI>(s?Yyw8E$A6#=NdH5Qvk*vqhByay13jK4PJn5^ zTEGBl8_*Hh0Q7i{xBwb~{lLY~qZ_afNckf&fn~rpU_Ve%2OqEx7`2h`0@c6<U?0%8 z9vpBFunQRcLXJ}gtOxc3qc))<unkClk@N@d0k#84FX10h4eSR-{)spOoXzk7)xdUO z@XO>gzyQNu;TzZmjBG$xpnoHA4Xgk*1N(v0SBXm?1gr+O1Fb;%7Sa^h4J2(v9xx49 z25bX*Y$Lvad|(Bz0oV<Ue2p{$oImF{(}5j8&g;Y@ki0#|)=#P%<LjwSh1~B^AKC1e zssG<}V_^EOp3cIzRAa?{*&p_FS~}sTgKO=C`x;#Tw>$EV+1=AA>V(_;Sx+Z<XGgj- z_V#qrI^pJn8`%jr$@FxFz1xvD>+7D*+V?x+O2Dn}g!|8b_vGw#N4lZ=8KDv8_}{JI z26V!`0d80)T-rB1ovco{so;X0a5sayvJ=ktZ!Y*>0uKYv18)O+fEJ()==DKQClwe9 zTntPCW&-noWxzeae*(_~uK;fVdw>?;FmNPkG5|OO7zOAz$us9-E&=WX)&Va8ZvY<y z_V-aw=V;(G;6mUsU@9;hSO}~D9tPF{F9B}@p99|kDWv-ez-fSfLCk4DC9n#32zUnA z4D0~*0tbLzf5lHA4Y&lD089hs0!x5<fX9JNzz$#!un*|=aZjf&Fc268i~)kcG@uNa z58MSj3Tyxxf%kxa00)3>pY(K&1=4`wKsJyM%mi))ZU-I$HUN#l$G{gr(jMX$7zShk zlYvTL8SoJB46p^*1sI?eNd6mf0}KPQf$2a6umpGzcnW9)b^$Fw(x>PKqyoc$Y#<+) z3ET`U2Ob300d>F*;B%l2=tWsO0T=?L13}<gU@q_r;C5g&@C=~eHq2c>3($@7cLJc_ zd6+rC^`89~nD+pyf%U*kzz$$9upj90chV6!2{;271>^u%0@nj`ft!I<z(c_AfK9+Q z;0<6Guow6OXa$o0fh=GckPTc5%m<bO_W{2H>VR#)PGBGK9nkBagaH@=TnJ<V`M`7_ z1S|m_0M-I80Xu+y09>x=91ENV3<X93mjL=*i&+6I1eOC215W|30K0&FKvEO@z);{~ zU;;1=C<Cg2yMRZ5I^fU1ZomMoK#$L<M}dLBP+$}=0hkKR1VX?sfro%+fLDOGfxW<f zpj$J318Kl;;1VDR%mx+$%YX-g-vRZ&HsC|R07?5uHy{-l4rBq7fNOy=;AY^Lz+J%O z!1KT>zz$$H&;oS%7czh}U^tKtOatZuw*t2Vj|0yGe+E7T3~&JG_65AaNx&Jvg+LB4 z6_^d&3M>O22G#*D0o#F3fiHkAUy@gVzCao<3`hrpz;s|PPz|gA9t8dqcpi8K*a7SX zS^%d7J%E#dGk{S*HZTd83CshQ0}ldgf#-oOz)s*Fz;{5euc#Y<p}@t!WxzC`47e3o z1w0Bo4>SUA10MsQ18qPr+OPq@P(Z&)o;eS56|fH24txr<0!Pxm4FpC3L7)U!2&@A1 zTaURJcpLZ!a2QCTT}uV@yBKo<Fddld;g(}Q1gryI@^Bww?$bBz+OdFs!!fhH?;_7! z=9xDXv*WwWzj4*O^P)JjlACncm7M3k1B8rm#f9^J1nmUo@}R&E$>a8>|Il%AX=Nx} zSe9K`T#RJTmQhw#K115-rZV5nen(xV@IV#!22|#kj}MoHO2;e+i9f%rikYy<g=JyS z#x=3NElQVP?lZ$-?~yGEmlfx5ZlH{dc3s@K!m5xx?%>%uFrb44<2Y9!k}1TAeLtCR zJk)h(!SYfCU-V!CbBiX<6k7I4p|XOxH*xYn-)tq1;&r!Bbc2T|(Izic<f`J?MV!Yq zMxN_}Dz=E`^E!rWmutS>ZO~4U(vY`>0$V0~)?F2)uYIY-6C1yqf_rtfjeS-zS4U(x z<z>a}LXV|?Ug6B*jLOQw1;KDAP{zLZx!OJ(#kyXAnOs;|S~xf4UgIEb?3*q=w!C6N zt_^yW4sYCeT2Pf2s$`GHxZ=5paq<>a+4PMe3ybCzR+Ppx($*g@MFS|z4~)I)&!%!G zoNflbym*06H?g94E>@QazQEk@9LpvG&mQk?uY4(vr*JWzNI2XWi082p4FZYsF296i zD9SIt!3IzmFNJ&*IlTOaa7D1PbRH==E9M(HLHBV@;D$e|KX%KbFzH1duJpqX6`Q<L z<*UGrlp^=jv5`pXXUr{%9SgB;ol7{Iq$+33sjxoSJdJuYmEml%2<>4@=OOP0jvdOu zl)}<bc6ntU=~-4h@%q`ir8!!nf1-TnSF*@cI3uKB76nUfKF%+$oWn_=P_Y|%$cSQM z+1tr0D=x0UO+}-8CMO!o!<92^X(NL~#kpBNFN8GF7Kb{NYwWiCxTVRnbu7nn&j=A4 zoYN_;vhf6+tr^C1d<UUFDDAj=@9SmRx6|0dZTZ~OGM#ahg{oqAD;u)nYX_UHgT<9L zy}8FSvz%vfYy}gSkKmEb3b4NXcr6Dut8|{U9nZ~g3Y1$4e4ALQUvG$y#~;+aeq803 z`(Ku;P)B^Cv9A{`#+6>LE$m)tjKf$BbE~q(WaiO^6nT}llUp^Wu*l75Ayo`x%gV1W zq{=KqBdnf%Qn6q8yY6wdq@|bsF={WvdAx4H&ESMhjH08ojG`hrTMa2|-X^q;sRcgz zXq5<Kb}Q8_v02443u%$YaivXemWR(TopFOrKF>}?=hfmFRdI2NJl92q+?DUzJE#$* z@_ovT`jc0}KEhyOsKl=}p#4Fib#XHYFz0-#JdIQV{b&h?dLjqn$_gtg>{%{?=4wXv z|3Rzi;uIoZ0mTt3O6osk;f1}P$i;yvcCT)C<=O1!HEfomQwy9OE-Q-<nrP%xtZkI7 zQ(1*Z&7zL^#nm0c&Yf3USw2@ynr)|e@6bz8tEL(;-(FgEgRN#O3TOB@uY9`|RIaLD zY10AQ5$AbsNn?~Tm14LKNo}QaRFS%;Lrc)9Hv)G?W>7v#(fHDss~SVasJMuJMv1Oj z@~FHrDw}OjyncYq|Jh~XsuIQKnDES*oZ_^S>Av`qMdZH;XCvLS+jrx9gr)Fbh!aw2 zn_nKw`mR(TZ<F6A!zrtHUg?bD-15wF-U}@+vlwn*vvrsJcbnd56XDst7`35rDWXk5 z94=N{x-`DZt}UR4Oyj6Krbs5;nJ7I;Q&<_-SUNga3MMWb@jb6O6_xH|2F{cT6f5d& zbwT8n?4%;As5*RFSmqZW4^Jd;;81P8)k|1$#;1pH)-O3Y-Vs*MH!7`IAIVC<FX@Ow z6+%@ERgC2HLzfI^R#B`ARxp<yjjq*<w($A93^+0D#u)vE;?RtetlTlBA!QrSKE_rW zYAM}%bz<c#_t`%%lS_+l;>c4d9w(8R<z?l5Z#pK%Yjok8G%+|_K2XDz&M#I5(f61e zViaSjbE7iKh`%6JPRQ#C$Q}&>ecE}&S(%bCiB^`3Zu>68FHcUm4sPq6O>T^jbrDji zY&T!ulS`{gsY)crjis2EPO!XefzBn%mtd(3sxvQU)DGvDyK$m1M!u?lM_*aI7oy$o zl;bKq$Sf<Z@U$bPI>ja!#oYK}`YSVRXT`&CZ7zA*_H4W~7F`^6#BdMq7Ee#>07b9V zR@unO3sH^4Vhl_)-u3N9Z3hmQSb~+S+yb3hSfP9&yPrq+_G->xc@;y=^0{t22v2Ak znRpV&Q*#O{yqtyd*=6PB8cW%<r+O<3GbD_~j|zg)%k8xVIQCm%U#oQc0<n;|b~p9i z8X&K{th8uMC6%Cjc5#aINwd`FcJ0ApicOL2;Kgv!{N>Wfcb`bn;9_mS2?z)eV{46& zGETe}F{~T#7`;`^7aWxmM@2V4jS?6ye`Qo^I8Bq^DFb&L3%c1!PpsIi0tc9!;xcc1 zK>yxrCFJ7v_H*abIOQ^M2IUk~aKN(Im16DG6|+j|>Qvfe2R0`Z%q?NW<I+^+@M#m< zjswbIj(On3a9O!z%ZwRZ<u0k<XWS4huLxI+FP<9~#?Q3=lZJk`g6_~wF>Pd<coRq3 zEw8Pez>xK-qV<eR>?U)pw(``J`qVHkjmnP=PZUGuwYvBe+&DkOA2P@I#_=fjln!*l z_>$B_M(ey8G<#(+sXP;h-Rl|Rt1@I@PDRLGYwy`z4QT}36a(u;5nnX(#j`3^yG5hK zVrPVXy`xb9o^r~`dz-4*GH83|#S%8JnD=1IL!~np#P=G6_3R1<kBGZ57R7quj@sQ& z+hDmWd2K=*#>UkDY42U&<0`KE@zHzrvgC)10TVC6B<3Mo^2)Yk%SN&!BLx{NmXMsr zJXX@KSN2M~?8A})V^QHCccX;1Ns3$YgS`HA_>-0<<R2$?8u18r5~bzSrr<nCAWf46 zyWkLtMevXPf4?(#_TGK@5kk_mTzfQkUT4mnIp@roxwA9<FlvUoeGqLZF~)3m`MtVo z6&`~A)Xi3!TJy$coZIRQY8@`$Ep5XbUh=1^-`X0TVsdULWZ6)?(B;9<2f|i)V2rhV zr^~g&8s6k~2UVvL<4st@@p1Wz7M7$#JVu7_TX93c<b2MrC)DgJ1FBrHF+*xLywT}b zO_2gDb36UUqMEU6fq5S89E{KJ8EWrWh6Udh6A%f8lulvjI_O!=p6$Uu@%b=eM>OVc zszP(*(=n~XyhWUubd1VxW!&~4>mHPAeV7;Gz;53*E7jW7ff`T@n)30H(1^hK8m@q3 z^L9+Bh^ZN)LT>66BR9qrg|0Fj4RbMW!5e8>w&S@CjbMf$d#EWMPLTC@Y+SMtqg0eJ zGLsILIH|-`SQ{)1h5IxQGi22U2y1319Nguq1OxA?1q!}FNTouMW+AK$4TnuOARJbw zmr8V)M77Rb4U~|ZD=A7ZNPTLw2~4IzAP+*cWVNzH47=OVVF;zsNix>ZNqBE@1$Tse z22&e#v@}aa!Bm=T@D<Y<x-uR%(xloj`(Fw)QJ^|vUj8CZj~EP_nh&8Q&9{L=i~)-? zAVqHS8SM}wL9WEAl%T{^uFV;Vv`UOLlwwG+qBU-y(}}fYBqN<Nq|(eVJAoa;n3jNZ zg!E-=^gHq4JM*oVORWr%^h(3(kS;G<)f}H_$+8=K=mZ02{65d`gjsK4Ak5E#n3wH} zqh^E+{xCwUlDMe6@$p4jTt-%;x)l^kBT;9}#+LSG&!Bg}8Yj`z5z3ZQ1=T{6im@67 zDn{3%LIz4$5$9-v`Di~!7uMSBarHxG$4T4l^m<LiNZ-U5qRJTFj2<^+#Coo0t76@_ zA4OVu>oLj<$NRJiD=8cUhr<#A27%6iYo~rEH2vP;8*!N<1cwV5!(?FV4BP-niRs-w zj3e<erD<S0P8U_kuq)a7{l208kmVZ>7l>hL4*7-+2Ed?^l4r=d&DDW{@@7Z`m}gr% zBZ!53ktvL(g>^lqTxuQ8OoIi%WYzx}%5nyj3K6S>GTMYiK$vAnGs%p_=N2X;U?i!Y z5(```^Fk8>Z3-A{278$C2Ja?7R-7cUO+!6=MTvi~X!dnGgJ7y5V>z<9qpQ6|8rZmt zLN41i`wYIs-8sCih)|n-%znc#taD>6Rn5YhecWcP@3l}l%>{mmPf+TbYi|JT<gYn# zZ5E&UXd8#CU04qS0FL=)2!obf`I5$h2zp#zlX1Ej;!WaMn^N*;jUkJ6wV_6?GHB%r zy%>V+F2?|5NP^b}j>htovMbq^uD107-$;=62yO6r2V{>+m|O)U4clADdAg>J5Jh}6 z1n&-bx5Ybv8lIDT;-ME+7{|pIOI%`~LEk}fam7WGD)~E<k}UZ_CjRM0n$bl39emy| zY}nEM{V(G#oN~Fd{T;09UC{p>De&Q)7t3`j?m*50f?Kf1n){dUgP#NcAbjpwj>6}D z@cXjFSPA@-@MpoV&K6_k@Y~=ofPV{oc*2C6FX4_No^bDlPq+u*=fa<Yp9lXKeAaUk zKD>B&mT4;zW40XpRt&x!zBQe@(TR5*;+eM-KH+=d6FvfC@Z#{eBRi`M?O=ZRk1#*{ zqs$NgdH8woXW-|<FV7WY1@M=^x500OUkHB-{37^%_{H!i;FrLE5Pm8AgYYkf|1|tJ z;78&A2END>V{gJ=0RR8OuZI5?{5JSJ1n(C3R(!e3!jE>3BK|Mn-wXdC_y^$sBm61& z$KW4>e;WQt_=}5yYrYuU4Brm_PWW~3t#G*$oxca`L_B{J=7G=Og`pG1_}j4i;Pba( zkHF{e#E!zZmM6_W3AoQE#dEhU(`GWnmlq_$(Yte(aKk(vlWzzG{hA@ZEkpd44Dp@} z@uL~yCo;s}mnOb27yO(d{$PgqqZ#6lrHLmUq8Z|6GQ``s@flAtJr`t%Uy>odE<=1< zhWITR;yoGSM>E7vWQe~nL;QgZ@dq=+AI%VdEJJ)WL;OsJc$?ZDl}i6K@#LQ+8RF~G z#Is-9GQ@Am5bwzlKbj$aB18Or8R8FQh(DMi{%D5yV;SP38RBO$#M_J?GFkbbbY74l zeo2P-I>aA1R3vJZIwI-Cj}Iq?%b|#^=`G((43ADFh97<`G5q}FMI0aE&(R|Y$3xJ; zM~lP~OZ~^bT_ijlG>xb6pOK$~pYbgDmm;C%fl*KY5Md6A#xwepBGG0EPrXni9=3$N z|4}4<W(jw`2z)K@?>=56erO5b@^X>*jU~MGS4AS*629fvMdGNg9R8Bmio^*^d*;1f zByO|hzjvlcJY=cA0R!8emhy)Y_FB@H;8$0#TFNiXDHbKx^!#G+PnPr<Te0w1;N4PK zEFQIl=M@!;zq5p&L|Fbv%ZPijvRIUV$jtEl-NoW^OM6aZ!2OJ+{s;fGSlBJ$sl9+_ z4Nnw{A6WYH{*M+5r-dKHUlxmAyIJ3sFBij#F&}SIcq}RW@ucv9r10US@Y4vdGr^1U zM~lT4OZz-uDHc%+zSu1+aA}^n4u3a_CULE3g*DkFy2U2ZX^ATrZAj@rT&vhDZpPm& za5tmGMnG68YSE8f$g=_EIuOHLEqLnyv~CHxU0g3yHzQPnxa*OpH(oo-F=aMVx{%TV z*Nk^7Je_B5Ql1WAaXm1<!N6bVn~!`qAcZxvMNJZ)PSmprxi_PRF8tHEE0S`vHBB;C z3-Yu}jC9^&<n2Y=pU50cSJ>O)Eo}$(n@}&GC2)4QMmS|*!B)e&ek|<G^AB{i@)w<i zUyUF9KZ3%Kh=Tu{#;tus<UdC@Ci1=kcNi>s2i6Wy(hbMWUX;N-Q*dMQXaE^T7BLFv zhr0!?5snXk<0+r1f>;dhEuq{=_-A+5#Qfr#Sant`Rt_f{1Yn{JZV}uyaC_hohvZle z9BPRnIkpJy8n{{DkGDlL)r|CiNo?}JZ448HMs$o_h_%nlxE!=J8~?1n%*%A<V}6!n zd26R32(-`b;SbJnm{#oMo>=VpYe3&c$|3Hw$VzcCug=5#EXVSMV|mJPg2mZr1~lUj zipJm1_>%KH+WMgBE_zsqD<2Z#{a?U=I0whFvL9@uFT;#yx-~z`XLu~=XMR1s2!ye? zpU;iOo}7)7gUi{1J@^s$HS}ee@l3bo=X-{SX#Fl}R&W}>9Zq%)n63R-xxB+*9k`r3 zeh0Fd)TWaVrgL$A<g11&hx=`0lk)Mqq*(^mh)0usO6o9#mta1LMTV;(cN;MNHe*a{ zx=V=0$KagMUo{X>{8+mh3meQk3kw>W^^!<+&Ox%yNhqi1p`@O83<uTXfa<#-d*w5G zVhirr6I<A@C-$C&dt!@9_TbRuJ+Y5X#bWn7AB#Qqf-1wZgu%v~jb>JL0tDmjKc|<X z11ekT7Bu`Im=GF0=N60?Q$jssh7XUjnb(PPfKjGwM#by$W-hV@o>yYAUoMEne)u=B z*y}%v#a@Q{A>1$5sAT?~0wd9pNZPUCGtlU#7sX<4U1K_i8Lx?|^J^FYrytU*+HhGS zS7J7%JPVfkbxaMYV`BnuaQMe4{NcGu(9ZHd8pSs_vOawLnf?PlK*fAaJdTW5pOSdO zk(mi3OsMA`zZriDPzpvQ<!0^~i5Hj}8I2rzP>$}xX2u^Oh(izE!%;Y9$$tdVkwXuC z^yLE7GHT}E!wSEC;N_Rc_!5slGBbnxh>uR#CMuVh@q0eT{2zUJA~AmC9u$at{iD%| zi7`}s%E0r;=qL*uMD__;fsViD9uycEL3RQ{#j0J%Kf320*e#4FrXz|DN09#>KWquc z$4M|f&HST&m@Srv$!zU}KSluYha_eENBuF`XlCI<lo%fc&ES2Ebd&KYfcTG2JT$Tg zk*ovEjb0+4(T_&|?C%ckxo2d=FS}=CRK?%<^29?gA0iwiArg<we<b>6Mm(b?CidND z#7{i*cPf8k{Pb<s_%YQyAUb{Ip_h*z+5;T<$l42J1=AyU9zS%C0y43OwcBPC6OG({ zXhI?~!FXFde)>q9G>P%3#dy#T<e5-#bR>L(ere)~Rhs-HYRtgL3g`C{e=-%%4D}im zxx<3u+k2&+D>qzR&#BH#^LLEOjfzcq_>0$b(sSr{gWGPMJ)3NI*M<A{&xR_1w}1Zy zqj%BU|L5=@z`s8qxp05%jo2IeFSv031F;w~T(}<*($`^`zQD*oVU#!EEimAd+wPh@ z8-H~>?Lc3*a|-WipE0xv32d8u!;Aa}U+QyHog-Z;azm$6yUWo}6pV@3<h=-tjeKn1 z1pU#8!b8%J2!>DI9{H*C?>Y3-nTfH2lM}m-6^x7(_{q>CV|z|Xk?<Fcj0P$zm-#XE zQN9>4d=dBz<An%3^w8ha-vbWze`FCb#<zg60*iyKGKLJ=;Z?pr5C0_GX^TswlMN}b zZ%{tnGsZ~#88cqSi~wmg_2Vh=|9t19z?q)HX0wTsk`gg{_G~eK{(P};;X+YaSt+i# z;tFxY4L6958#jve>(`6=`g#$&1BC1B6wipi6w^5P@Rett62JWAGvbS1xK}t(9p{t# z;ilmj;ed0)?T4F&i@`CI1I`V%A8r~h2FHR9I5*sWxM{c;9DzCD+;IEhrr}}?qdR#v z=Ctfq2dZ-bv;$xqDB?h$qcR}ifOEs`hnt3r!4WA3oEvUG+%#Maj)*$o+;IEhrr~06 zMBV}ChT9J}4HtvMMGn9Nad6XcI2czp5V7*#e*B$=i@~wc4mda5ez<A47#s=VfOEs` zhnt2YVH|L7xczX`a4|R%%K^6^ZW=BIN8&l)_QOrX!D_)j5@$c^fy2LP5|@-g7&%e* ze&j$Li0y!LGavkExES6YDC=f<xM?`ZIO;|`oLkn9c)Z7qPI925+<4y)e;N)-L3SJ{ zBPoDb`Hvm!Kxew)_QOrX#o*Yv4mdaJ-w%HpE{1n@xC71&w;ygAE(S*?aKO3Y_QOHT z0vE*?4lsus_3wv24Htt$@5o*NW|Em44)h4zez<8k+{ghOz%g)c)V&}6G+Yet00bNm z4+k{|91sr&;J^X#aQoq=;bL$O*o|(~xu5nUT#S9oet~mKm`sm}&x=dN%{SjHpijhy zKm1|w$xnV#eD}NG6<_+&m&CKrJ}aJk?m6-A|NigdrI%h3zxvg$#LUc$h`o7IJow<} zAk$-P3Hl!YjTh7;1JE-}NqkN~;hcc|^VV-vJi;dm3StGnDL?`q6)q6JdGk$681Fhg zCQiIr@a9`FGhA@uO@w2}Az{aJo{)8&K=_35psrX9)#1N<PM|(K1t)yBZLZna5kpvF zcf$7{j8I`_@%;xQj4-nJZexTc+`-2TpH$BY@w?Eob|BRVr^ll)>m&^E@n=lwYprL| zIncED2mc(#BZ4Uyi35|t(aGm9IPn>s!4Low___TmV$a9M`~~;S{NEq!$LOTe?<pAF zGx3A_R2b=_Be0EsFcEn~r_;nOj2x0-BVC9?2gl;+6BzlBhhe6V9@_Uv!9DlL^gXeY z_uPK)Z@v-J>9LceBl`}0W9HO7%#Km*<URNN&7tQ$_OVgh1W-VDV&e91JU2nSC;Td0 zu=_a-p)>?lxa`!(2!}%~1;PR~40VVBP>^8>nSaJGQ#@sxD4?N$=N`%m3LsWKL;+xJ z1+QYf!Z0jRLWY7@4~{!lKcvFQT=43f6Ap(FW)-h~lNnSxVZ8b#Gg!jkWClw(!VH%1 z1T$E}%wP#y@F9E)z6c803^ql?-YSSq&1A)<{314GS4*%{ShG^@7Wi~JEOPLk1t*f- z7}*pKGxjXl3t3qA%7PZiip`wCofbJuP{<C~2$zK&Lwv?^rI+$&j4}8Fww5nrM&Mn0 z;$3^<U3&s!`u`q#0wzgwb2HUIy62^r4jp>o@hvq8IZhmo9aeV9O9cfgz4`$Qh!aRY zEMN(|^a^Z*LoaNpsea%AO9oZ`)CqC?6=XQ{0+U~T)dXOaKlRcpcu+w#Qt`wy=<+We zmKlUVBHqk&RsX4%4j)DiHVgKLHC^I=>cmTb!H4N5Pa;QZ`Bz_k;DIe$gm~pt?4-3k z#{hxyuOfAGF!=RXPT_OeNlSUApFjpCkG}BrSC}E5ObbeuKlRd<&6|TSyzq4ZI91Rr z?J0?^N<Ve#)Jw8B(qB0xix<2?`^qSfbaDJRz$3l684Z9LR*;k)i~T2_<G6p(cw{=W z3KTyjZ8wJWBjJN3V5iD-qLc8vQmm?v$qY0+6CQv!KuHKjUR`-iqDOcqR24`!ZmE!- znQmlY`kS}iR)Ysq*DOoAg3R<MZqgYN(iI*emUUA+Lt?sYmMpI`q)$hABSZT1+u|8A zq{lO4N|zbX%=GCN0$JOydPTBAoV=;&V35QI(~3W^opKSrRy)No{`o`*7K>8^@o!LU zLkvT9aXG?vr1>o2ilkEgB7mDZoXF)uE;q`1<r~Y+P0H)T%D78HPs}$PdjdiRoFPC_ z5C`z)!g~Pq2XMPVVxAGi4H~tYxvs(vfG}e1DC5T8AwU?C<#!=8f_*F+KNr5k`(^tF z5I2lgC+7}YaJtfH$@?U1YuzSwG}cw9Zx~cyjf@K-9L8He-t7pPEnSKo4Z0PZL?3QC zaUmD6?+0dHNl8*61k4AG@^0B0#(4~QPT5MkYz3jSPg&O-;Os?+y{h|C_cft}k#7K} zEVskoDeD_VI1xkkD5*b$^bqoH2HeE<C>}|LduhhJgAyOrKcsxWtbvr$ZP!>Yzzz`R zCPkQY0C`67PTb8t?u)l2DA@nxv4F&P5Gmwkjh&*Y57czYma0^?CjfXVPW6xG2(MB9 z<p%d9$J+tNhmxdlYAs9+10O<RkFt&+&am#rd*3;?=`!qiAxHSo3x3%m$`IQ>3^?R) z_L}MkwovmS`H%Ec6by>R;(hqXeDq1tM6B%zTyUoP78w}nemY-FE;}zwNOMwd8(aW* zD_#vFR4Vyn7;j2TQBQd#g|^|e@OG55^0gnOl?GyOlR74(R4GW!O>IG`y8t_~k|CvX zfl2v_H2D?nbx)ZZ;{xoE(i+dygPQBucS~gtt_JoDU5uVk(oVi5A8U!V$NSpkOjGJF z6zkFdAt~2>lo^z7q;N7{m=wGK6eU+sqRu6M1$Jh+P>0hpDkSop3A-!>AMz%3w;vF8 zVO1}2tm;QUP|qohO<g!BZj)_L+J!lYtHOFQcBT!B9dOhDO!3RKkkrnJqZfORJU0v) zYb~<Gp#2qMp@bBavQ3FJwMV~{bw8xr2mAt3GOZf)f~4^&h_<ok*wWO|A}B5~+D%H4 zBB^|4>NKWO?{TakW#*(vfVJ1yF4C$D+Q^509Q{Zy%7vLPh*jQp3vY0&q{cDnqOmf$ zOpO)nAuA+GrqV>jGZo706l~3U^(b(Gq&sz|vN6=y%Q1;M)`@;*FPi1Zv57jsOw%x# zUym${6Qs|yY_$9-%CZkeP!C6=ooI=wRq+^mlAN<hj=h5jDNU{Tu^W3Y*+aB7^k_lY zl*B>AlS1s10m!vg51b7Xa-ACIE6$_bRY@{MKJ5ojvqx$Dv6q5)Q`F`dqx1_gX1mEj zx+koZp{!C%(9ZDzGpi<|)Dk{hPx+&aXc}2zXuj7}qTNP%6EjLKcfhv8Zw8mqq9b-2 zBz{BUillZW>WZEu%-I?{q;eP|yay22v#OnpYcuMtOoB-s-(ldxaU?S}C|5q<$KG9p zI@p(_iWjtF>q&*=(InBnA;&09x4;<X&%MM2QU?#CS1F5{&yy`Evxd1z`GaVqsohLF z^a8Xbj22WG+CahAJ*(|CWl^*Ci?J_P%`({AY~MDiAISIACjo=&sOQ+9n(Ho=V<$1E zWRY5=v?)F0SB{s8hm_4t>ZlU@yA6B4IbK_16fHF6x5@Ifk}tC4)U}<RW|yRtBGss& zXwNF^ED>vS+_M=yszz0g=#AJXO@5%=*ly`D+K=X3tq*XiQC%oOdT<0(l0nHO1(a?g z9HuLst$Im~Ht&=1>FQdZ#Os8-Q`V<uQmommkC-z?OQas{h=rn|6K_@<SdFJbtVpWI z)N+KU;Vi{Fc_+07woB;`TF0q;!0~|mMcm($G7?Z<C)?Ac+BV5y)Lpdp6t2|<rj#2! zvr|$%2s}ArD%z8msojY`Q}~y%pvMOCHb+jSU;AV#OZdf=aU0*NHxv8Z><2<sJjObd zMpbd7x~WsMq1Ubx`3CkJr@SIpyjOe>Z$XiRH&Qkaew$45Bky~Wn>IAz7a-J*_E2I; z8>ViCPwMPKxh7};W&IFp6UuqztkcS=$|m86N6yr}dNE{%bGXD=uNu$Qywrufq?VQ+ z#kC879eG-5eBwp=5?`kr1Db&ae+AJ6TTT5IVm|!jIT*(cQfUCK<H$j*RIQaL&+&kq zODUwrVat_`sIhU&G+Jye_}2>Gj@_n<v3v4zjQ&@MW%2k{<kWDgkV|m_Ig%RB<S<jC zv1e#Ab7ZB~;4GgwTH#kGjPe|{P5x(Iu5(Z$n)oRVpRD((6_iYqhpjbKrnR&b_N0QE zsq5BfYE?GI<n@Aoc{|m5{JqTJ#nhhTn8*>H6xa08mbbQ^I6_leT=<2{M*OwTErQ^@ zR<v2^LGn5&k(w(HeXj5gg1@b^pdjpe>O-{(LS9t!NpgykX~n&yV(J=0suj(CA3+Z? zKU>9Gz2LJUV98jvmKt1*5xm>Vteu?C^wiZ3bF8ibT?dgvwbTk-)kTh`bPS<R@{}Ds zMa`6M)W}r&s)RaJi_RZ<YPr&cagUs?Mv=?W>bX)X)rd|lN-LW5BQ;2OJ*t*L%BhK1 zmii?%{d!4lwmN<J#PyKm^7xgS?5E`T)U^UyIFu#g(hp43_|6rI)ENkS!o*o~A~~78 zb$+WB^FXP@`3=Vut_o2<C*rXQIEK*on$q+&hiPdv^&r<c%yA@@hZIeSGhqy*8DC8r zXsu7av5wMebfgC2U8Kn^A%1>|v$Y+o&M_aY20L^ZM=^3n5OpifVV8D0siQ_4YFgC} zWrJB~3&Aw2qZ}#H)A1sS8+%k)q)JCp+NjSs4^ne9wZcw*VUMTId#%=^(tu@B3JJ+N z){)=T*m9<Iu=hX*Iw3i<O~|Es3@|x?J;+rS&ez$m)Sc{8x&o|FlMgsYrIh7aMxJ8X zUOl3lV_AV5qlcyBa^*PH;z(zg@F!lT9WvXn`8bYwfgNd=JU7Tquv$!8B+*JqwqZ<5 zB^TO%2Xu%ZmQXj~_rY(KoWfSJZ%E-hnM18D<U%U8fvfyz6W>~pi)APU#D*573vV6x z>qhx(nKus>3H#iGm|T=mt4}$SdbGk?WE=BQ59hKhcNJ=Fh95xNuR<AGR*Wsg7@fF= zbp>p)C6ZRupI2ap*@KpFlp(JqYkq1%&f(a<v<|3kNm=5rLJdjdbD~YIRt4BLCu$&0 zYGy&+;T)G%jQ$#-$4WxCBRA(R=4v&iB+>d_lp@(`+*O)Yjbut<IhSVNkXzN)1M=#* zm)CR7#PS!N*P67(;rvSJn$K_jTi0dwl!lW!TA1I}G_~!RqpP*zxrT*KeXPEM(F$3D zxyMqtE5sefTaJ<MLcvw$55W-v#|Ua-ZNn&CM5$4_jd^awct`$ZtkPDh$EZ7~)wq(t zR#1yE&Lx&Z@+jl{>ZHbYJ>rv_xB^A%o0^nbm0CM>1(Z6AmU0N~pk>bznnO4%x(2)b zyAVf=lum9*fm;qKOs$LaBgM0;v5%_-`iUbqwRsS<DMdKB6m1oqM(d1qGHj)DF`&9o zmXgR;?Ev2VN0}#e8CQ-zSdTDg7qp(+ARX_=T&@G!{CdoqIx%K0NRgPctv-`Fq<rG~ zbSgy?SGKuAs_m2lU}Tm5i_m|hKl{}>c965E3pu;sxX-bdI+Xpf3zTbyMqrOo3lJ;a z?z4TtOT>&L6vs1a80)C1;>~p+a^6yd)5smPJcyy<X=)FvMoTQ0Y_+I0rsUcx((--k zcjC)Y?*+!JgBVZ>SpS*qe4J(>p;PK<d9Za?V6CbhWtEksW-LliP`XHCN|R}M>F<6Q zfSc3`o1&4D&qOWHbxledalJTgezu-HZq}%^y{;#HInJWaT&^CHx(n^16-L{Jc8B_+ zLmo1}h?_H9uAh*Kc8q+@kPo#srE~zfL#2@_v}8!Z4S=iWV+vw*(wJ(O<25m8MGIL% z&3H&{a+3K)Nb6C>`y7+Z?;@0V^{ws-$m%jV6IJW5nns!niG{|Obf-oo)|}H&N>oqv z$v)v|$~6z_OtwK=UuqLd=D!OJ3rDwvwgqL5+L)^c)KcU}LRB{9B`N$xN~rHt<iRu9 zw54gvYCd0(R#Mnrwp5Q0>`z@^Dl}z5G55u3p(XM&#~H5bQ-|sK_l4(CPUCS&8otou znBp_t0=;fwQnMnh9CZLAwQi+mvK+UDFy}}oqg_ZN&Fzp7_MXang$!}DBd4rK9?jY2 zTCurqm~Q=+=ZL6PL(<6$D3^loH5ZUS$Qf$RqPdcmZU|PvbtqxZq^K`A0@I%(tzl~( zrEv+t)LEB7CK;o@sHMxJS5GLxlu7-y$NIJC@(i_EakuKbWGS-3Qut?*O$CuFZv0+H zd7zGAc{P7x+b^|zc{j%yY7w@<Y`x+c!k}Jczo|6Z?n}-Yh8ulGF5>8*bOygj^PM%C z5Eq;?L~U=LdkJlio_ou69i)kxeP|eO*N#8;@+J<}c|<9!E9>qeZN<>~EP-BIhIFf* zB)<&cBoJ-wnJc-}&7AiPz?y4^Z|!+Ka%d}^=j$YYg-_irN4YZVNz~l5A~;%-BQJoa zqJAK6ax~cm*ow-`qiiOAInY?}L?UwP4jIRpoj1+ONAfBcc}%U)@b|QYpudAEi%gAJ z9KAWB%mz;EYqgR}Nv1W<8ci*!=wy`$A7C<FaXGbkDkaav|EVjri$K9MmEeefrgqSR zI#c;%j2E0Gzv2*U8!t?0qbbqMM~#@g{+v1!H1`CU_8@I2THV!{U06qbwwGh0(juz& z_)h5@z(0;Q%09RpHESJDJk<B6)I76{aY^-XGEHdzvleZIR3U7ax}7Va>T4}=qMbp0 z(RLhh4?w0ki&JClY)E4=Er_-LF2%B!V?0x<T3qGQV>30i(!iXlaP@+G&+%2IsP?P& z7Rflq&j#hvea*C6#!Rlu)54@>N*Y@2y+kdb>`=-PZ4<7Cs2<R>XLDRhUJFs*)7esf zo3O5tD2vdv3=?rk)sECkoYhh`iLE(zAWq3PZz^vlmrv!*O1UOwt%Ew%Tr<*^y`GT~ zi`02uZd|A3S$54{kwk07sd{aSa;h{ArG_=Km3CM>)uJ9Js40tr?WZoK-l26rKMAJd zI`$GRa?Y64cOeCPp{3^uPg!Q<GnGG?KCF%P?Shu>fp4Wtvb8{5&HR_9<Tuk4C#RoD zTKC6te~{YQ#x-5eJk;EUGk`?t7>!RRa<KA1y5)c_E=X36Tu~0dr!3It3iB@b@0a79 z^1U*h`#f@>3kW?2vPvrF$o0yd@LLeyAFrpts3$DjybCKXsy<3QTgoratcg3RJ$P5O zQ%h(Jat#c)21{HxSI<X2VxiU>c+Q?`DQ7Yq8v|J5R(Sc0u+6~F%)zxEVrs@{q}euV zaAH7y;7T&>w;b>&bq~WH#E^FEY38Rya<x}!eo`*qC{2rG7w}Oqf+){$p#h8bxsJ0L zaLKPKSH4k$3fYW$_`OBND2zA$$-TgVr$DRUI3F|`(rEZ+@{S>K)}pV^5|0*s@6v-= z9pAgO+cOxn`*D^&?&YxeJBNpTA$y<89taQH2Z!w~o4V{nxcYHvX=%}71Mp36KJ>+l z{`$$cwDT5x^Q{YH_*-vf!(Y4g3vXR4{ey;oSo)g>`#mg^3BS%(AqGC2C;sihg`0Jr zlla<PoQ>aK<|Af~`l0djJP5K}=4i~K$9E)=9(?i`;B$)^33`p`LPl9+P(ZZDB1Q~f zMZ={+e1tEZ+2SaHH)hMTl^FH59=kffA`^_IAzWaA#8+7-5n|hQ<M7JIj@B&=;I1&I z5O**Q5i*}~rYl17X$00wRW_Uf26|K*2}vIEO)cf!V}K{Kpsj*rv=RhC<ZE0S2+F(A zBuzjY)i+4AJdHA|CF0%J-x&qkB2TvM+hS|m=P7U7=U>p<)ZKJLQ%_TG+g&Hdz$$H% z2amlGi?u|4<(O(3f5ZMY_D@sf2knuQ9g&xQ{m{;$gS?65#SdoTavVpjZL(#tzt!>W zwtX#&>lpBK?7L%eHG@l9C$G(IiagUE`5xo!v5I{-qNQogk+QuDQMhT%Pn#mIlzn&~ zptVFkxA<vU`QgQPBiuIrl&vLleQrx6|Id2fBG}Qk$?InbwX+4V+W4oDf9m+Bntzt? z4=TCZsN`-ctH=i1__wl-6ret_@7mLC5kP9$w=K72-<}0<3)}WxySQ!qNHr>)x8`^t z(t!+~j>(S2x3o=ueDN3|d^c9{B96BM-jSJbEg{^3_F7xnl-SBIBX?T_AR;rdiun?o zpYF7`O+LE#0N}MnX0@;R=TLsEBFKE>PoeJPS>Y&4_+u5nKxE`d$K?Hs*%|GT4^_8E zcGR^;f{pEwe{Z_E>87R|o3`HkM6BXlahx9fCOhOf&g+<N+qZQwde*zRya)Z-Hh!YI zE%H+2S8bEsXi(&P8zawulaz>6Jb==Bry|F~fxWLwT*Gr)9aC+Qf14c5Mn4gWW5=&+ zi)68==bIcaVx4ue#0uv3OpfM8n&!1c+RIzYzS?wA*;hZX0G$K!-+;0bVp{|yJ0e+; zV@<J6)J~d4X2&*{w?({*w>0frxVSB{b#Z6pNZa_6)o9aAPfSlABzEu{yKd;|1^RW4 zAH^zeFBM{PM^@x}v5JFuZJR8uzeI?y=OJ&b;{T|a_aO#&BjEU#uL+qFQYl}+FY+S) z7OS`s!C1v#$w(m97C9QL_!>iNo@hhI&Ov`5RQA=Wvad(WU;GF_jNh@?lM^b!_?RtT zyd4p3kv3bb;^W9RJ~Jp2a>R>$GGSAB2bq)=-GTHqPlQ=6SG?FPlkZqO`XYbrN#+@! zDJlEYjfjqv?tf2~7@vA=&C#;G4UEVeL&UyIhTj8by~NAEc{ky2B+o13`F_>6LVmcV z<1^Xep}XG5wF?n;MM}Gnp<^<y4msK;E7}o?p2S(D`|>IgbG+rQH$GB{j14W3(ki4; zu1A(d@-D}Fr1Sz+cHz1#maRaDJsJJ}n=Jne5O!bHkMTFM;wSh^+3+LVQ+OYL3Vr#{ z<T-mw<f&N2OE{!?%@d*i`p{y3xW|y9iia;jg$GN}DLOOyQRXb$djbcY#43J+(D=+y zs4P~2pR}S6j@|WLj>E_wtN0XRB2R!v>TbU2#t%J#BQ<Q|_<w-^&71||`1cW?FOGkY zGBAE(N%RmJ&mR65a!rHq?>=z~eE%}_`rgIL*M`|ojQH0LUl*9IUdD8Ifswx0@QVz8 zz2X0f;ooNXe_{9s4F90vzXguu^RnSr8}TYuh)=7RvCkU**9~8%cNqBV@G}OSrwm`m zXDuofiw2H~McvPeMYYd}MOjaa1t;e}Kkw-|Q{{e~&oRd)=5!Z}IkiP%&gNNDCH~@D zvI_G=VPBp<_m-T_Y#20Ixj3z6J?`kZR71smC8(#`F2sYD`hJG@V~Dd^;+{gg8WDHY zQg$72N8G)Ze0_*Jia5U|ZWwU~5SQ-x-`0=Kn>IFgcj$Yi=4avR#BLuhqg+|rI@&8P ziidk~Z&gQcQ)j!pdpnqgyQX+kVrwA4TV}Upt9#CIy%%Qx*1N&~AsaVF^EP9bz*+je zfkAcExtK=?yr9iFjJv>wUA^MJvT=tQE^7<o(yHcAz}totFK)+Lor8E@kLL;oyFB60 zfNuns&gnaGF#%yZ?qK6(k?}jtF?K)68r1!imgt4dEwNS?Y9E%j8XDlmb*-DPZ;eyq zXY$_puE7DZlDNq$*Sl~t7#gul-L!ZW<8f^puaj;cZtC}<-b+LiZ|uV5oK3?6<~3#n zBXWpS8aPcYJs_>_1?=-O3DfOs3T)d6xLs|n9U8Sw9j#3_bnE=-`1swp-!la;C;I`E z`bj(P<$(X!b1+SVZu%Vj=P);3jCanFUxll+=&au}mhV>gd!ay<yryG;T;H%(sBTQa z&^Km{<!M&D6Q&K3w_xtxkN4!K;hNDQuYIR05X43DYb$G(R#)0x!~MPiT+6w(@`mmW zRdtniUbQ%YyM~8dYb$rTf|b{-D=likHL$LsKJP9&01OA$R)zz^tAqU>*N`(<H8hC( zcY{86s0#NBu6728mhP;nv_mHkx^cH@kF_>}8gTK7PgJ`LAv>OUOsL7I#Ym8ey5@Ei z2|;J7GECwV!tIP}D@O*09m^{dQ-*OF?b^zX8n>nDrqAF~YDM30mA=q3sZ^XcE0<RD zUs5tw(>Q|o0=P5YgHfoT_kgdhyfQgkxX(M-j|+a~C5US)SFWgE(YLa;rna`f-(54{ zPRj1Z-Hu^g8kz`bnI_LNO))Ed8sf2%jt!vzZZqY0a*jRZsMO$t#$aS6dcbvS7=4H9 z-~)p@G3;)01ue-Wd_z2oy5|xM)#2Ld^4h)pySCDap=_sbhbvHN4-fKs`XIQ*?eqp+ zmAYXP%(6I~l&Tt*Sx{?O7H=UiX#l7BouR?LK`&V1>`hL{PWIG|cl!P4DM0cKTN>C9 z4Ez1Q0NRg5()NM1mAAW=SJ%|ku2@x7v!ZroRjs3cMU``f+f`LvT{qxzxf}xyclGYX zmZiXOtf+C+_0>D8Rt(ewhP!W|s?N21pvt+twzhit@)hoShx2SOYMsm7%j;Z@suhmD z`l{O6+M239XMKOwz{>i8T4$|urOQ!wHW)STm8(|vuUc7ESM92)s$K4=uL67aRn<8L zs@*FGst25_EHE0DCDN#2SpqTH8OyYcB9N?d-VL7z1>Vm3|I?`F?XLf~-}e5SN-thq zYP!oyD-rIlTUA;N|3h;tOG}J&`ds&C-b_v8x_?JjuGss7t!s3i=SBWy#aVeJoMYir zpL||_A3WGTYJvI_x61cyt}`eXAIioMfwi}jlWGZDE}pX-3rJsi<x2(jE(qbp=Dr3d zHzIx+Uy>fb5Zzh0Qw(JnCMBIQi2P5UA%kA$za1+)5-&S^;B9^ET<15|@3%6c8V+s7 z*5ibyQDFVvSeKV=K!nV@Bq1A{i1m9HulW@}Mw{?SPr=)gl5c%t%)6m?Dex`@{yR|M zCsjf`4)=fHJ`VSHaNFUwz>UGx!o3%61Ke9zLl45u!8@PftAzLr+(Eb};hu*38Qkk| zMaZ`m{si25yl;UUhPxZ?ui+kodkXIRaEp<r1Fiw?=U3vcA^0cZe+ljw+~aV63ilbf zkHcMrGG6#A;irARq;x-ZcscbFpFdHaNRzhZ?!>el1aXhDd^~#-)2u3W%S2)ti(nyK zKKH(LuRMs8aj~pLGR^>5UW^dYie=4}@%o+dner1S4TtY|Bpmgs-U(+Pb_DV<nmwlL znxB;r-&lk^q>s+ecRVsb-*tW?Ugl?pcLG1wp=qJti8r4vO!7vY0oT^}v}&s{t=ej= zof)&et*xVeuP@*VY`r1q3fQ|mF0a?FE~*dyc5sqGNPL>GhlG1%ZoobZwL3^gOS=Iy zA0yqzDn4;*(IVIs#zRwsX{22UX)jpPN{ux3hX-lDvZP&Pq_MwmNrFk+fiOw0PNdy! zDQ7p*Xv?%ErCn;Ik&hdbU{)Gw1@P;V(r7BMzC!qRq-EL7_FaZJv~7%dmLtuFwCXvZ zxRrTf7RfXl{L}MP+P$+saVy(>fsqDJoIu)NpxiA;W1DC?5hh_gjkMX8G@hzST#%IV zsJXViX<%q@crX|WV4k(pW$*U+yg|7-=^M6V(UkjB;^7uwe|QKpeX@zp)8zNJ$o&gx z0U=)-fcpZwkl(ihi>RX6iKPj|%k^Y?ytvSB8+X|^hJ%CstOM_zgK{1p6rEVB@C`e? zjBoLJvCL}lGr~cScf{!*lq=U=ZAen=-02K?u&&B<@VK#<+O=szcW=|?*0ah9%7FlG z%&_CD%Y=3Aa%Pm??CSRo_hT|FXR_E2c>{JB@y1bgx2L|X^K!u6?Aq4j^oB_uzGIOB zZFRYwVQ)x)D53SP%`UI(sCYbZ6M_rQEOX`3D-~VUa=d6pX9b*I8M+b+F$2iV^B6w} z*9{yt0*g)f*Ns>{+*>+?f839ycS{H5{$x~whx<!?*b&BEctdG&;A6GTG1b`_3oV{E zk@bP?F}y55u;O6(CvJVbgx_&<_fCZtGT+{BhvvB>v)%j3@wc(DsmZ<fU&1dR&vr~b zZWA{|PK=+J=lKX^Bo@ZU;{zy<f=eeio;cEa0xPWI1F@&~PK7TS-+eM~WKOuEzV)?{ z;_$4ycF+76Lb)?<d)5|$`u5|wqQ`ST!Bjj97?G2EUk_c@6TKgT0eEvfpM`kz#NlVh zo<`siWW4DKpwQFnIgFy;%xc8d^k(@hJqHkLmYN$2FNlTb#lq#Wa0$_UIx=H`i5$V# z*T?6vJ$Ie>IMDudXZ0s;9iO=}ykv5(7f2kDf0+U*-H(bLQ{&&b0}0t>AD{XxGk=?y z+;sw9(nOcS2RC{sWRC6qQOMup`FoV^Qf-j!yCFJhG%o?GXCgDlS0iTZ^QU=F#^hdl zK)RDCBXMsmbg_rk=#-M}vCi$b?fCrvIUt4_Bw^5`4}JUba@C|ZVl~-X(i_=b(&_k- z=O_r{p*A|wdYYiz`xeD27Na!!Dja<s6@u!QL|RYhOzmquJ=uD?v$v~@^@DH~wa9mT z!({8>?TwuipE@Y9vqcZ!lQc6<?qy6TYCGHol#%~x<d+Edsx*l%&?L4pLp5H?zFI(h zB}?6P!bW_1h^^yCYu*fH?^_gUEyuU_?0pNOTNHNhjf8CyYLBOFKKbT8Kyi<+yS!}g zUxLu?eeZcO0w0a;>g@6?g6{3=>hjo-)dS#T6Q7zP;uUt3!ghv!p#G1f1n_4<C-S~V zb_|#73!heP03rpE){=b%#|z_VM|PJZy38mPtGE~7_7(J~FbI~|R!GQ$$Z+#bXlaS+ z8P*xy3)+F;<+42_bH&}rcDzRQuqTIjVP^*7kSnqCRSmlHr5r^<i*4X**0h#I@5psb z9lsc)5tF$aLUY{Xqi<~u6}yj!t)j8fJ#H5_LHe+pB{%Z8J5uC^z}NM-$KTi*D#72? zp?v&Z7QV<G31m;cKidt#oaG(|1RMS?3uQ+hTfbfv3x7uga!mC`eq+E|oeFEA1y;F) zRU~2MMvg?@h(kMi)6KvOLe<rSu7*IAef6owqPdPAHFj>#kFD5J%}(E{X!5~M9Wj9j z(CQ;9zNvTo7iDE%UC<c$r^f5iu)N9KEyrJpZ7g4NWBHvqksHgwVUzPNj(jI_GV<7C zFJ}Mx^O2+I;_(-9e*HQ3_~LSLbL5GeK6E3*2r3b3uw!w#dmmIMR0ULKxu<s_kbn}6 zyNU)>jP!Eh{&aUWw2yl&WVc!BCyQ#j$iqaB2gSFSqpuoK%1}kBoGb>}xdjRC&oZ;r zbdU^4t$Y0QGvF9XNc0n6;!erA;5kJ0Q0AgfNf`-Oc=$ELn(##=xW~UCi-&5!YLT_% zli0J7V=7x`?Ae@SYkso3LI=aP=tF?p8T}=;%}LI+iJr&`mg+^bOQ@1ai`X+cGk3+v z&b#NzFyf+qS@MgrBxGCWmy9{tBC<LBlyA=h?_%_ku3`zGLNZi7%2H#RObb*dscuP* zE`_QT9<;tZdI{=t{AjYZoRXifB%cyX!Lp<9nkUNk{t&vM7mPK}kg+K!hR!3cR6Jtx z@QOEp_{68A=B;Q$k;%JPkY>;hj01zUAhOr<C^Zjiybit4>p5VA)*|Hj95v1TM$A=+ zF^YQbHR3Kn-1gkbR@=>y6>L&3bgXAgCB~jXyo?yt5uOKOfO`B!;U5AEG|4kyguf%h z<*^Ft(wpL%{{v`Y2~=BeC-h)vPxOJ`NJVpXWVbCgV(W>10c{%JT_Qp)vGD1h*a&D; z68)@#tzaF$vM1Vwtx}Oz+jw1Gc&>Z=&g|7;Xofp;w}$iF<L-PB^8?b&fK>L?{F`s0 z4)1{qD%p<1zI&oovc_<JPqdU!S{B=6_G*>=CS-<C<+4DzW2&cf?0aLKALw-N%a7K> zKEP;HL|*8L3Y}jvhi!ZI_Ppp5Ac0~k+x8-azibH?ZqJT>HX(dL^e<JIbz!t5a`%E! z_D=PLE>YTYe5z<I88~>Er+O{~GWts(f4n@}1<!~f0Xw5VeqA<}>P|MbC;GR54c%NC zZ{ViWMixDyfl;*}()8M%-5Kq{oCW<u`=}@CQV`}Eau<D+HT6XQ+<;>ajpTT(0eUc` zk}oyyLt}6lRN`qsqJXN`UPwT1=k_cQuk49cbRZ}9+0|1po<Yw?j$QRri1D#CH_qF= znBg1CyP_xmOLqQb?r3Kh*fO`dGx{8&48u(-1Zc<7HW2I}|BSy83(Z=CJ`EK`+7^ya zEj<38(1%iyE9)rwSD+qg1;M98b_0#$ml<LxhhRiUKZrV1+;)zAoyf$&O$vPpNzlVw zBzpwrRoULVAh!}66_f16-54IWu!+&m(C~Ql&d?yzC-=Sva&<;8lHk?*cW0mz>p%4y zBusvVe?zO>k$g8$EOM{iDnhv%HXMJM!zahi_o5e7G0Jr0nEOcnR<U6Nlf&QUU_mS~ z-o8#7+8wcRI9=q9G-BYK3e9(~T`e&5VsH%?xz{`v*7mP%nH@7uNLp8q<3|zEJGpVD z>jS3kLIp7Kspr8EF@Ns9))S^O`&TgSk=EC!45RhzueG$T<fyQBYO?jUPH;H&z{yUE z@l-AiGi=_aAqVsBc=hC7LWPcCh7(;eKlA|7X}I+u1Ix-BhBfnS{f(!~_Ktz#^*6p2 zx*fKCcG=$fz#)40HQBW*C-?pwbnJm3e~K>vpcr%SRN3ACNeyeH%Y?(I=EY}aY!s@e z2TE3=Gw~?~V-=4Qjmf<-5LU)+SM1prKaUcTjVB^aFbvD?z84`tlhci|yZ;oSeK($t zUaj!it?N^!BGi|{EBX+c4e^7KukiI8mHM<qiX9TlWYd|3@$Xe~q<mNELXKfZ4CuN& z+oUYVvEv0WuDOB$YK38~LT9eKJY0y#?;`T}?4IZk0GBGx$On^ElAS6%(t3K$6L%I} zj!_<GiHL$RW8{s`F);LR`n4o>36yzntir=8--~yvB=tsT18Z<zP{l%$29R%jCKmpX z)cYO1(Jx3Egx=$Ly*^wX+7O*lCDy7*NpJLFwBh)&$O_6*?3uk&d-9=CP9Cq|-@AT6 z1n>GMVt71fd)7_v@%IT#=w6RJb-a-82S1og+~X6GF>py&<i?U7>LT~}W#S)uQ8ap( zV*_S3Wq1F7pv`3K#P)_x%t}W}_U*pgoZ3vb-rdz1{a4`2`BT|PN&zf3vLH6XIbB!u zd2mbQq+@E$$+Eq#63j*$#u91zcXoDqq7a|hNUo9^ki9iJOSQBN^-&^h(XFST?-x(* z9Rnn#QoEv0<9>D((<#SCTl6O6lB$Ls6>a@hEcW6!s-tMlEDqbcqL+c|j$b!Eb9wmv z(T9)>`p=T!FzNBLo0g4zo>d6LZsR-bwhAxOdSJ~koG_<zyncM~_{@6&+mm|%$`_B% zTos<v<@q_dHF_~x5jlD4Cl|lIA@Y<twUE=N1s>`Ia7PHBfkpv-+<>0yLl2+>=COxJ zI=1~$v~z71X3$?_mQXIV)0)Vy$9^g9`UMxJ#&?&C@RIS}^F+9E{LO{C=k|253!??9 zeVk&TQ@f(`f%|bx3V=v_LM@Fn&gK@#20MP#(+dIQxRs0;W;~3ZScLf(bptA>L9WO# z&Zv;k+Zk<qg#?W}5zaGs3mSJG&2w8@c&;4VVMvdnx%=c4;U)}Jdakt)#_&OoF#B3( z<h1rRs65VCPXIJtXYl%Sa3XkN9%obw716+5mPLb#d5BeO7IJdk)9Z-U?=IhY9p(*_ zep_V2%wx~z=80-fLw26tp3OGgi8g@xH5@}Oq9sPs#VSe^{EJZX&t}=$vaTI}s$|XX z^1vbB%=L(p_&|bjKDTkQ_FG(Z?AhLkUHB*}mja5mXG4}MYz$)&Lk%QYlc9i>J7Up) zB>7IRITd<8!XRl+v`r!7m~1_<JquhX6c(5D_UM>g6*C**&h5Dp)pA)MC_83U#0l*5 z&+%<oKR?5_i-vOS=e5MWRfSZ<rF;G-e5c9E=^Y$!HG7=cs=E=3e}n6Hg<PVGdrPsX z*xxiT5Wt=t{NzLKU+oy|3plaD`qQiqpA&m+WvEGrk1@ZoNZLBuB(k&Pu)2M^0<kj3 zi`8GRYZxn~EA%@`--~^-e(W}D9o{(@@C|d_7h8w187<f={)&)|uM6?TQIxqaT|D5v z3e5U<Y<2~G;XprDDt|69HN%gJ4OpDiVeU)5U9=8|hjdJbu?Y)Ri(%Gb?D|zpqfBjY z!Td0x4A(@N|GlzJ*hU2WmZ^9DF1%mP6>L8~n5b4EC(f!4xUj3&+9F4C9P(8W1Iym% zk7cA(lW^!7L0&t{aV@qf1VZ+OL#`n3xGXgmb@(l<91LJD8<x<U#I0#!d&R$IwFlQb z2jtf4&JcgK+A<h)_IX|19<)a@M6=V2mHqp(uJ!u*oL;$uS$x(AZQ!=<q`lF1XJG|e zZuI6d^xrb{fv_vEOD<58oy39UIN*Ih<2GRvAqq8#2?;|I6=4?oGGnl%+JJ%*UrLMt z+)@DsSKHEv=7<XcmzWEl@$Crvk>Cr17Y7G=#iIfgWukaXm>aRNOIu85p%T(sZ|6o$ z|He2SZgB<s1A~6hwZ)12F-!T>Ech8)!v1Zocgi19-%mU6@g@tA7!#$dL%0#H4eq1( zsFerzLA-B=W6rL&4VyYzS~sWrV9|tB@`=wo;0naQV6fb~&mWQkS?pkJ@YgsP;XM8Q zRfpBrWArka0bOs$A3NTy;mZ)lXL;kUY`nbt{E<;0TW%S%W5J(hNFDsd2B>}Dof+aA zvy$^K6gj!r`vD%yh0iYudGJT!=fj_XUjY9;_%`?l;By6*zxynLe-wT({A2J-;78%l zf<FVl3_cCza`+42&xXGQ{v7yq@aMvBgFg@c7WftLJ@DtlABBG*{0aCM!@m#yCGZcx zUj+Xk{KfE(!momV41O+b$te8!@Mqu`m7xB()MzRJF+2+p@86F7Dk>=Bj&8%ZO-tB* z9rn~%!k&)A@FN=)-DF|>v27CK!<PI<HwbZyC44VB<&&21R2RNvSi+4rB!;JY@GaJo ze%}XiUV<gO0DJiEw1jc&t5|Odw_yXJHGJ=l*pp*P7dO+U(b$6?w<N+_(k8^Cmh_2! z#TUB70(=qQZb`>xiv;+7cOw21L)cqn$zMK*{YRGY^X(YBEa8(*#do^CC7ToJSKW-g zMk)QvIBp>A!I$Qn@t5DbyKp+wCY%s*GyLoE^%xz6=Nq}Nyu~qbId+DewjG(H{cB_@ z_uk~nG1Ul4?=|ohMp2vw!jnOGT8#c$-Hs5?@xfjQnWx$~v4;M7xizx`r_^K_U%Gi} z5by2MXVnt;MnL3QG`z=yr!?_Q9ex)NVACf5s&j_;g&cInSzlT4x_QzGPfI6G=7}(b z$@8gsLLm3U@Ps4tz6PGD5|F26@r)Ec>u|4_3A0D0>vJ=iz5+W%R-h$I(V{x|tMIlQ zca2rc)(N~9qCDxKPUTT&)tD{hy%?mB#(^+HI5iJHghpN4&_1thuOD<_OVsJxYHvVd z9M9=&#(Ao|D<U(^c;;0N&J3!<-zs27JZn(rdf0hc-~m+!dyzHkeq@Me9bwTt3E!o# zZ%Ii$cVhQTma!{=r%?5yC1y+0_2m-u88Pk!#yrnW-!q}(6@Jyok$5_mI+2Jctny4F zo@T>mz3eNsD?-<w++%0!uO)y(I`9N7a)TGW!!zjgZ93!+J}okzI`>FZ$>etEVaN$~ zOd~gWItVycPUU#<2s7X*L4Wb=$riM}A5<fq$t^)qY@~F`{^ZG+>QpG6shs}ot`=E~ z6K9BbNNDO@B(@`jf28p?z}<S*^6xuK`EEc|r=GKY>O5<<Uh}v*9aqzZ_mfa&eb{NP z&Xq0@ypN21M;YeHK&h>t2P_9r3$a#twY00#L)AHhJm=G9&}kzmMA?K&wmfA>b;%T- z^P5OxYL!_?XB|9KOP!>~^Uio$8~be@Fyq;A%*paD{B?r*JTH~!eUYj>OFRfZW*gOQ z0X(IN*#1)d7fP@sPw--Xwq)x$!{m8#=L+-f_DNy9Pks&D**c#nO6eE2lxHGS4%kA? zt%`P}RQeucdNQSl#BUI*=!oT$q~~3^NG}(;;?uY1hyLTnkq?}i@0CpL04M4`;)z_m zrz#*`z**EgAa|vb6M1Kg$<;d$>KFfsn@~35FJ*KXz8!znnTzW5UdAatPG9<pb140G zIX1l(No?_4j6g5QR?vpvz0`I{FW>Em<=YF8-!QD5HvAm`b(~3jsARwjmAr4mXu}iR zI8IP21fZ=G_v7)jGScRvv*^<FrQT@`Yy&5#6G<t7+kk2Mc3zNC3sW!A=GY*9VbFm( zkSE(IExaR%j<aBOvL@<P_JSI#ctSX1N|RC*brogHfWxr7?SnP~Pn+W?rs&JE?>P&F z&s_SQrgQ=9ZSn^#fH16yRJnA4_A1W^^6)ki)y9$}nxv=fEb+OVf5@?mFXnt1{~p8p zQ#lVKd^qQuIp4~eB_7E68bV*e->>IP=X@jQD>;wHQ~&2#5@)8y0-PCH4ePufHv40s z)<5JN0zLj-((h4F=pS;9$nax$e<J6rpj4^&D^TlxNy{fB4gW4qy+j6Aqnol4QmqV* zX6jT--e2@WTn=~=tC9q(g`qT*-r4Kq>UfGBz>~Xw4emE>3vXN_p9$90=M3xZ>SxoU zpp~cY1x{~KEQIzoEefR(s5?o`GusrrKW`AZthU6v{lZytX6yUEOTTPFuW^jzS+wfB zZ}KhY1R?wy$V}zf%hP95bN%t_uM*5MIfDpe{$b9DC@Y1SJtkA79ODE>2+lY-+agVN ziPvGvF_x#jml$-TM5u9i5UHGZB|oK*95pvdo)rZ#9_cjmCfFc8@t$qoSqU46^FhuF zqQFMYS4|BShW<VK?DNWVg7S8?Q&D`rqqNhlpcn7sOr449yY6Z4DgFLFv@rclhy6n8 z(W2HppdcsHzeLt#wJT|<bB>&c`zT(7ZR*1N*=hdAHrLPG?s;-v=@q9jI_^U2X<Jj~ zd9rg*&RAZ@Uvhgceio_h$YiQwWhJEt2Vt$ZgSKj3uhtXvs7vUa&zm#)+fXBWaS)>} zOL3i%TFHsJb&AQ+TnEtepfka``kZ0CeZFpn+_42*Rpjr3lr~A`>p}dEze~!fIYVR% zcy9n{LV6{xz3BGy{$y>7a!n)gDHcDG{l$3&=U6*1>v|oSa2<v>A`!kivzup`4`Ck3 znWefZ%-Rp^dA35&6#loZY88lomDHnVe;vJ;{Jgt9l74+8Pp*$VS$(?tc=efANEAii zrDG;KiZ4F=HM@B7%ib@Z3mqxngOGJfY_df`T|L{9?!-KpXVz24Qy*|f&piM0M!VGc z4%=A@&8xp%=(G6wO-ijJnRKKDL9I(mAo)@BR%<Dwx7Cs`;i&XJz|dcqGObhD<tmD@ zB)LArUf~Kj^)T1DbT0)k-lbo&syYt{Z+DdA-LxFrwq;ninxApqN_{<0YhOFix*7BY zEjG5#wApAgCqA6t>lMUgdhe3oYIG{^U!V<q8z9e;vwPJG`n!QzVcm`zFO|Q?r)|L- zQpgz`tCe-3dV(dDeUS;qRp$uf?NZ#9WG{1uLYu<Mce})e@{3;pZND&UK=Q6yTTZo> z`#~LQ3s;<W+GZx**!skWGeTP5T+QapCRNMOPUF2cDi`}R{WqOIel26p;NQ7#HBFM% znu?^m`L)K{Go@l-?z-H%T--(je|2tiZbR;h+_kyubFa%Sj;A#uM-$T4B1c{BAAb*| zetVdg()!uh<x>l4)S=aE{rX%|p%M9(=T^(O6}j`{6lwr<R)J=#k+vqc1L@a+j&`vM z;cI01I^&D6qCV&E>>Wx?vOeOMW1V)sx}We^mYV<PQu9+QafGIoelEKIY!KeQCgREn z?FNOD3-h~VO_W*xb50R7zI{;t?*bIHikPVXtvt^6B7E_oy+TWcGgGc;4k4Di131?i zvc&$+<8OZNN^JccoLliaXsPDtL!bfE?a;sK%QwGw@J^zQn9tLOS(HT@r9SW4-|6k| zeDUTTx9&c-Z@r{yaf%G^wy7QHfp+u*ziraC&?`!`=QzfyIeisUxt6F(@D8}!5au2$ z+9Xzcgb>sU-kBgQIV*&>s{@ktZ))p#m*@`c2x~&yhR|B;E)v~py+TPXy2G-nk!pQl zhbG#j*8ehFAhbU^Kr?Np(8}aHIiK{U?lAY1s5G^w#EaYYw0+1m74>!Jy~axD^C(X_ zOI}YUK6*FF*`eum)iXo;UH44tdR!2_!f(OU9i&dCwNypDS)eFK6jFd+0Ww=6O1GTZ zPEXzeQ6_#Ud0*`e&^@pNU+CBaE>S5*QsT*d5S$k!?}MOJZ9NN=tIiS1J45?K3w=Ra zi3njGZfCrOi904T?~NeEHNDl^Vd8vXP|mFMyokHtsC8V}Rn>`^gVH(tHo+S>)jF)! zDx^MVNK1^IT+!^0<Hs+9oHg-o&5#_+X_uTE#H-I4;yd3PgIMwC0!0FtG0M4L7B!E$ zDVnX>ju34*Qjqc6KtZ-Wb(f0b{r^ROvC;qMXl}P-i^J~-IX>dJ*Kxq{u;WR`QOEO+ zpF2)FMD2pwg*f)PuC}wbyLL;hx7J@9s-39)NbS9~pQ}Ak`*7{rRiRb8R~=gQ*sAAN zy|n7}Ratc<b#v=#>aMNpuM5?ExbCBMpRPMyms5Xv{p$L@`oE}usQ%0Kzpj6y{ynRg zt$zRNp4Hn|-?{pes~=eX)aoCueq(jvn&_IB*SxVNwkE$}s9{gTpEZ24;r@odZFsoh zD-DMm9&h-khVM7jtlhTuGi$%G_B(5Twsz6FRqHmd+qQ0K-R<ip)=jSa^t!LC`^R<v zyzU3<ezNZ6b+L8VU4stC2rR^^>J8OfuuV6==E|CpnmcO#q2`$yvAlHo50{@<p6|HI zah+qo<4cZzalEH?U9G!zZ|&o?Gqv^=A6)V5iVIg(uH3Qmft80=KE3j%D^IMPzv}N- z<<%9}U03Hs`~Kg$U(~%`S5x0y-&22c{T~<aWC2}yMrL7A@qpL6HRy56pJ*)|=-Vdb z54rxh+Vgg??e5%AUD&<RIXJw*7Z|eXm)s7QJCvQ3)9v$T-(1ub4*9xp1A*6TD{1x) z;y0viuEA}dP|jVVScUOB)Q|_kyk;K`r7Xzr_g?SZxvOY{Z#abO02oz*OIPsgP~S*5 zE@&*42?|K|e-+9Qf9aWDy0OdN<s1&$yIg@mw<_Ni+U0c>i;_*l@^_5#=Zgiih^`qf z+{B+Mw&2Q{0>BOo>A)sjK{GfUDnJ#1A^B?CG>qS)4&LS}0Q3NVn~L|+&cRWaH;BUt z+lTu-*|!uCNdvu7Nn+Ber2Bf;2!52gg9VE%?~+<MKNBQZ&SymNdS3v)`fJC5fx+UE zzCraf*Nv{>uuhUqDzNnhTLy6r#I}NFr=REJ=Vx7+NZ&6c(sx(Z@06nXUHwk4Yru9! z%AT1tCEe=>Lqkq~`w%WyC?jnwVZ}r?$wan1$s*a+`3705F*7DT*M~zP-*8E@bGYB- zRRKlLC6fDc_6eh8yDoV_zRFx^AzLwS337VTnfRG?cDAkC*|&*Zke!!Mi*3_&)*6nf z4og#m1#*FLa${ja6<KB#SX{9-WPQLl5_DOsQ4PtyIi($zT1;>`1?2O={v8Fgt)OHS zeoofiIxrZr@du@Ru~PUJ1wZG)EKR5i6KXc>EmFHHgmWkR$=!v7(c$cKd96S?4J7k4 zj9C^WOE%!-(4cXxM?oA3vlb}Vq*}_lTweU_nT%nntIf(1IakCHZnH^E1A(+zsx9sE z_(u3cVlRJ6Z!@bCwq6KYZ@}p<jLYckZdIfD;VlKVJUK$K*HPK|+1}q?SW^He%I*iU z5_IE@?~Lr8Sv;+bnJQt8O2TTgj831eJN<klERp?_B&<5AhVpm~mi~=PSV8MBfA2nE z%Oq;}eVV03W#DJk%@%3PE|E(3+}aec(B!G?xcJRW0)Hk6ESC(u*pR@rafY@?U={`* z@bB<8SHUbTzABs|G{s8rEdnDOm0e=MZ;ivBl~!QP)+9;@$FRAEeCV?nC?Ru{gjl0~ zS2B_Ybb^#*?@kbsEB+8dk~oHO)IQ4?X4hP7PvFNiW7soF$=qlN*mb(#`3P7d(<ceo z-b@vwldnu-g~36ZHaJP6&$r$;T1ZZi0W~z#N$##QxbH=wTTzjx?3h{o!Ipr}PwT4# z$3&OvKr>Hx$SyBx54nc4F_qsXFa0Src{Fv<DAxQKADk2hh7FNpV(`B6=KuNKHw+IB z;{q<PSDuTF16U{m6=`FY6ns;e2@!3){T6mzdhiL7kmE@lFMjoh5QY5i^}JguPySV% zuNq%(j1f7%itC>2ye^N^?<y$l3&QN>-H>OKhQC&$!L@q4IionF)6E8-UhfOJ`f!R! z=_VY$63`(Fy4i-!XkwdFpH<Y<&$H1xVW<`qwhs^USdMKjW5QC{?_D1n-r($a730oI zOmO6+#cFGaa@tS2G8Q#~2!n3<l5RCtOja9G^XoX>a?;REil2sEDv{G61uR#JV51g6 z4J_xsgtb|-+7)NxcpoBYm9Z4;lk$o(HcyMhdS{^6@~&`LoS+6it#Qb%$k{kJoGo%T zI!ANvO()H;Im1EAXr=(^(aZ!?o>rPOn}0O=^1C~o!!B<jC$93%O8gWy$X;C}yGSxl zL4M!P>v0F4!2&itK{d%nezS}P^Lqzxa|Q;whM+tw(Xz&zgOa(kHE*xdN^(`<dT0L* zH3yDYk<TODT>+S_N%rzQ_M1M`1~Wnn)s{%|Uu3Yr-Z=R$IX|jpS&inT+DlnG=i!!W z7szUhjA}m-ulB5_hcwBPDkzcEcMVwJEB&%u(=F}9BaJS|D(D#u4#HZ*`4oI;+f*33 z9eOF?l6Toswa-(kJuy=C+1sB3qy?U+*I!7S!%zMp^t#1rF1_A|t7^f(a^9`zaIsR% z-!SAQ+f>XJGa|uyu#DeH_Q~}=E9CE}?mZ941*Z7HF0mj!>w_)~G>MpJ?;>~RoCo+K z6FgLv1$-gETQJX-;&v9u@tI2kZSu`3z?f>rUc!4axWr@5+P6s5KdyC@ISa0^4nc)B z-pjmc*t^R@a`1eTV3lh47RgdGp}*3dnpUz*R14y$^1Q8KD1jtYvqOdsI3G-LgmE&a z8hkRQ*&_;m_E`|cl1>uH!u7s^T`A!7_!5q*Ea&-Y%3Q0a)H<fPTMYu#EJfz4lB3^& zrD%bfs78K2=AoSZ`hu{K*g(0ydgc{|ch+KjI>}-@;|hhz%enDM{A}y0hcSb<2z}A@ zSP8R8y)laC#7$JQLW?Ghi@jN+xoU@12@Nt$eY6Fv^&LoRVA=%|vl?@CqRfP3RFh~! z{$Wky;$D}x-!~+U?PT-Hs@-gf2G(pPP|3CxY)gKJ(3<jddIFlWI@Q`NHENdXV7U^@ zM^yO^Lw{9ig^=@-I6sYWM%&3+v6=$p7!{W%SDd}_{OV0y#z`^df1eW(WremGEsERj zIsch35h?B%>~{?ZW&fMpo0U3;vSw6Mkj>74LBoW&z<`3O5SM@bxGY$v%3f7Wk#kIQ zMI4pv*;Y|)_PF|YxCShPXHEgW4s?Zl{=&GHSeT(AL$c)5$b#2ABYQ@qo;)*BCPhqn zzAzokc>TNumcwz+pliex&_vtl8uD3ak-Z?LS3WIF^Pxz6!Nb%pSWpxU;zU_|32=H% zWU`8Tox`EcE?l@h9JCeVS~*>9I(tKPuoSa|32$oC)6Wz#PwNtf-4tdo>BLpYBUtz6 zTt$>(`lo^<Pdv>uU6klAF(^~0ML*lJGMoBsWVRKk#jsGoQplX0zJ-aOOA>Ii5Z&6^ zB)bOFG1ayd6y9kfV{yRkTkmq?enCm*vTn@^iUTd_XJ^9iy;Dp$&%{zn%I}>_C6Ez( zF?RbTk!)N+A?MA}(fo+*^d>XoXtJ1QS77;Kw8J&L4d2jX!eov-^P52&CZT2cZZJ2o z-V}0pQYt<d#*No(w#LLT!A6b~piCpODX=ZM^(`q#WNLlR`L({>QfW%lYg1}Hm!>DT z!)$l9Rczz!j-$Xel;nnME5ID6GBw=tsVGkTGj#iG-SDK9n?$S0toB@5p3)Mt>1Q!U zO4Z^$PT!V7k+6U^FP?U06EEBPg(XQT&f>S^E<aXklRG(`Es(yg8ONRkcDBqDu(Kgx z{Ti?A%6rw4U$f$^?6h+QlWyh|VO|n6W0+Sf1qDb<W*sdvlWB*qTz<~a*X2@X#}=Z? ztqI9w%f9*?Wg{ci&SVzPig&rC-m4Srd2@n(p1pMzPBa?M^Wm||i~CL`Lng7)0yFuY zWGpO_NlQkWqx?vQ&up{Isu^Ro<f@aqB<E8if0NrCbYXXk+^&NSA`(`Cr2&K@c}b>J zY<Arm#-a1la8<p4^(TuVoc!6ZsC$>+h3y^q2x!G6)!fPO-Ou`+&oYQvv{|`XLxv%& zLLq9QjJZSQ{PbByZaoXv%vTu5uOH5#YXiQpKUI+#nPlpDs514Hl`|4_f64Ve`6W?y zmWALs&!$>;)+vptQ7p?GR#=8Qv8b=v3el9ENx!WEo1X&Ds53qi7RnsIjUF>grf4#3 z3gl)Y>|qLoxSP({{P73SY8R!&<oB-OjNMh;&fpHE+){K*p-f9wFDW9O^F6(D)BF&c zL4Oo-Hx|G41}$GlF#=%fh<SA|^^=ydO-dp1`<CWHuAc8Q&2!FHRNT4DTT(s_r=Lyd z2ZQT<A&)7Ti8JZAshB#AE|Tb3_~!Sc<4QXNF5H=7d?rp@gS#-E)*1--0%y@~@%74b z%lEjXA$C?AqNSngv!d2?`{IVp`I-RnYU5M}2PQAr%#LG#k35zoB!$F6W3V-mu&Ubv zsh<;8kh0AcB=aL=a-HSzI<NPoR9Sb%DosYpi8l`?;&XaQt~Gnl<YCp4Ey-YW{ybH# zOQrBGHEsdQ%1;EBVXl52ES|c^m%P;=i9bryd=XM|kUC|uY!N8K7Ya-Qx;ImXz{-Ug zNBq=P;$rTDP1uu=N$@NcW`vJ#L&>`*Kvdth05%t0>kMymSw{ElE0aw->;8%C0l-RG z^1_A?x39^K4Fgh<B`?O9$tFLj=A_f}=~dX<UJ#rc$5EOB7D>-U+4GfjtAPLa+xKB; zvh4W2kJah+eWaK)f9(4`&Lk6QIJpEDgbfBgF1dJn9v_D0q<k1spLWjpWhliMD%c#B z8x*BD8XsqJ?$=|G`B~@_dZ(Y--k9GP<TfGecPr~GDz2ifHc;|tP+%Pdbkzq_s!sTJ zVGaYi@j6n+He14wra`B+DgktwLCx}6#2nO8HMQzKQ@r&zu9S~!*(=WP8`qf@5$0*O zX;Z2`wR$~L#5?irePT=AVeoeMEoBrF3{8Bpad(7WG~#cTs6`yMO{ByzYjQqJ;Zx$U z)Q}Q~P5LQu*hhidaz%N0x%8Ky0(_yv?<2EtE`|rm*}`sDX}k$22O*Vq0ER3fZpk{o zyJ2c^g0l57?}j1V#OEM_XS*Bb<1!C#B2oWp@%vW%tO(}~5o>*pZ3})koasIn{x&|0 z-%2jSSxD-%67~CFbu&pVeuZqp=>ePoAgR*@iR}v9fWli`mg6sPa$(&qa9Q%S)j%AB zcEDD**_{1;4<R1OZMbH1$ZOx}3IwrWv$nEkX?3ODHQeu`m9w_;hVBhjb(MB(VIIa$ zo}if4R_<~IE3a8sTGW8=MXsSf?=Cw43<uX%;!ED@V86#T<P25~4dNGkL7zKR)$bcx z?F<er-C0v<A94;4x?Mqi!KA9q3aWhoOJ{?jU8O~KJlq$ww(|X(mtv2qZz(R~3;Qco ziXS&x!rt)(ngacv!4T%@;Q+FZ)~z%$SlhF-8f{YLLRfTKTRAc~>{wp8j1><USNfst z>sSkB{ivm3nKfQ!!}Wx~t$!B^5j7N4F`*`d3PyrV)RakV4wLv;kx<Z7yl(JDO}nMW zb(#24<Is?AxXSo3RM2RQE){R<O13oKR-JrSTE#Pl`@Dnw_%UO*Z-)!4uyRHHioTV# zHMO<<{qC9pcT%-p<ATk#l~-C)NL2zP2~#O##!5;ygaYAUh{oJG@{pragAcm;!vS!L zmFxkmL4vz5;0FeGVqe)dSJ09yv5IGD9R&dHk?Y_dbi0>-*H$`%?ZZ3K`aq>73jOdP zKfVXS;%=um=#reH(;Jq>L8jE&u*`yG!?Ji|fmDOj?+3BvF1_<^JNOqrZ4H7|Ll9DH z8yg1vgH0pYkg8#NLLvX^Wy=h)TpAb4r4Y+yT^rk%Ew8R#vCQBz4X|<@P<5fN3}Bk( z%Tg<DSY~Mm+Xc9Ow5o5=i_XzlWY!D`*{LIRU5Q}h)DDLIe)*e@O<nf(fwh&lyOvki z)YPt6RaLX1c4bwqqklz}bA{VgRb5>-;BvVf0}glf?!+ETf#FzD<EZPacUG+!s0R#p z-#}HJYxzKxb9rrT_44H_-1QFU*<jQ<m%EqOxg1q19DVgw_(gwBRiCrIziMD*{Xng= z*16K<s5={s8u!XoEBjZitg5Sa)l}6kchpxw0{g1!90S$vl>^lS&Q%r|DWqSPKumVV OGOdUZ;2849^!)#;3xs+A diff --git a/distribution/windows/setup/inno/SetupLdr.e32 b/distribution/windows/setup/inno/SetupLdr.e32 deleted file mode 100644 index 95675506597d96d0df4fad437d26751403b2ece4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56832 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¥GB7b#|;;h_0uX*M5nuXGIBL70bZ(rvUL) zsHH237I`aV#nvV(E9U8M4ceW~{BUcz5oWz25l_e2U$sKbe0ff|RJB6O31wH{VwI&- z2+5-$7<Fy2y0|QRS9?RYUzJ-r(Cu06js()2YP~DJo!}vdDyu3);Ua8V#2dQE+ol8X zt85TJtVG$ltq-r#e5%9YRf$MyFNq>ne$<IBnPq3&o8m1zZ9jzLSbIjuG3>K0==DZG zlL89+YVA{ABpo&|$cBcu5*eu3A99owgRO?o9j^9PI$wdbb&|Fo>H{y|>vLs<V>K(u zL;cl(hNxTb12z`ND(6?!QFlFdWf5!B!|B*yE`+b(!5NiZYaajd^m#e*K!0(ia1?7* z_PChmXqkTdWS#1Y6rL1SxyQqLdCX2ZT&>e#Vzf(H?^HR4hpPBq;gJd%QacwUf<gHv zW@f6v^+r{MI7Zo!h<jrW9jP)EJXT3p8_82uXmubO4mGpxs%)KIfs%ljibOO@Xc}F@ z2Dc1^lvmV99@TjcK?=$1p^mFML?}y!JaDvYoswe#4TDo|5};e%RLxcO*ygD4htzBp zKe+skUEAxU?oceq8nZ2c$cf!)E2s{KRw@oPUhk?*375oHUhEFU5nZ*RENkjxfTSoh z+YfDnx|RzeQLk-as^#F(Dv$db{h72mA&D>VwP`fc=-g?qw!R9M=CxlLk>Jqo%hQ;0 zgN5(LxU<EQ80l%GK*AyW9415@+SZhNns{!e8jVy_p^TFBe?`~cGGjEbdq<g(*I)Km zB=}dNepwpWlsK(I(;B7bq-D%qWzQ8oQu`R(O}HoGzJQyDyBBv7?f@>1kxoBC&1>_r zjCPshPQ{fuZW*r3b1%Wg$-p0F{AnC~2>&x~2ks%<2XOxbm-n99kKpdcP2yU(gVSdj zvJZs`^`P)9g37XyaY(q#x+Sjo7~zYC2|pRZuaL}erSq9(NO<HJ;qAu=zkQf+q5Hrw z!Z#fweETuNcON5s?=iyrj}fknU`T$CC%<`8n8Spd#|SSby#C}Yv4hlg^@J?LKQiSt zJ~)+6rQ32yX!qnS<B`$n`1qMw#(|7@Kg7n``~)lhtt{i^jQGkz=%<q#kK_MYhX0D9 zEaRsc{=DKWLoM>zVe{~xpAmmG{y&m;=Zefk-VFIi8%vCGW3jOms4$k{V)ua56BFQ_ zV1DgIAayt7r(IW~c3gGGjrzmgzI{83kLsVb7Ks;6l3)IGKn``($Z0o{>uwjf<+htT z#BJ?3eyegj4e|G1)%mV+*KU1xprbvfzvG%cIW6rukq#aswzOY+u%or3qa%{j(i+Xr zFNzpBN$nafwrfNmlyD9lf9$b;7WZ2CM{YSCiK&<EIT=7%w}apSx9WZ`Za;810|x79 zG%<#>6~kWb63S1zeba7xL`U1-+HO4jV!ttB#0X>b=+Va5v15(#<HsAPoN|gWdGcf< zKR@3%`|Pug<;#~FOO`A#=FgvR%$YOCNM4QNYHFBn-(ht3C5`>B?=pV(yVs4MJbJs~ zf}IcO0=fYSZ~;D`3+M)tfFQX5AJ7GK14%#<x&R;01#|;RK!~{jAJ7GK14;2yw6YG_ z4S=EkeEfC+-2kUn5llGX1G<22API<2F2DzL0o_0n5J6pl59k8Afg~Wpy8s{11#|;R zfI}USgD{{QV96a>L<*n!>*BW?NCJ{+7vKZBfNmfOh$38o59k8A0a1(#@Bv*wH;@EG zSuUUp=mwI2D39Il$Uqp7gkv|qqQou~Du3OgT+s}EFyY+=24N`M1^5IHw;M=u?;@>F z(gWQ<5|9FM0Y1f_aPE_KA-O0hANO6j-9XYVI5eX)K&bkY0(McDKA;Qe29kgjt_$$N zzYDh;NOCU)?gD&37tjqP0Wks>-~+mVZXgNpgDwb%e-~~ykd!dEi)N5a8I#LJi2z+d zH;@Fxpj?0t-d(ueK$3e1Ap_w+7tjqP0f-|5;XoJA4I}{<?TineJP-m!Xi$z)E`U$b zl=!6akH#6s<(FS>(4H7K-gu*N_uY3JFTM1V@x&8P7;n7shVk~>ZyWEw|Gu$r-#+8x zk3TjB1_q4ep?>3m2Yy7IZkL>pU;gbII4O_a&Pi<g>Z8HwOD1!U$YU-p{Czn&$(%pu z5Rvld7=J!=D8tXa6Q4Bt4&@v=l1%$^`VQewf}v=qF#8m*KKy<51+QchcKoZW5B^*^ zec>x>r!T2a;#bo3g+G)4?H82rhZ11>K?z?e0U7>kxzhfAef1e%MmuXFR2ks(N9`GX zCc){eUANaxJ4@lv((;G<Ir<}^lhcx>Cf?R{Z__!+)jB{IaP4g!Z+Gc{Yj10h<g6X| zk2kyMopk)#oYreQ-n>WqiEnLLyLRBsj?PU^d~0iK<oM35%5TRT#@5a4srU|hK5)b@ z@vU2L+LW_)t%|=k*}wLx&G$W(bmEi!tt~fgeQMy~T0y5*>tDO}zO8THc3bP{4n)A; z(Q(yNZ+D2?9TDx%x#n%U(3Td*Kki^li*$#{2*w}j=pag6h@kw6vi!8?@Y>SojvTsL zxz<WuApxQ45)nu{I_CiW72U8B351*jo7cF`drbR5&N*<X!{xI5!s5Wwf}rDt#(_hE zkl}w?5HkFof{@|w5QI#>AY}M6<PrKA^5QjAHY6)X@<>i{`#@H5d&Ed?H;rqzqe0*T z4Oid_IDR9W`z*j13hiR10P~A1#tT_T09u2r<iMxEVIzAgiA<mj$dbdAxY|c3=cu1{ z3E>B`RyXao=d1C=SL2DV#uN1E|No397?M;}R7f*0+_i7t)~)Y7d&%@c7=7E4+tfhC z*q4)|<BK<Bkmw_No54t6-+smjTi?56dhv!083;Q4!9JsRKL}gjljs8n(gf`E2lwsg zf<ZB{Tqy)6{l0Aqfyb5y4se%_*ZdFe+qMl1$rj^}%y=dL!M=U#<&yaRelU(sf8fA| z4VPSE82b+<`!mx^A7GIF0I{{P*p~eVbCUi28R;dy4+M#BeQ(QtK}bc*2uh_txbKqM z+Sq&VZGphSoC-CbQqt=9g9i`pQ^|?ne^4dQ*)QWOJ3aA6Z!hGDuc#mc48wAU#3z%# z=jvs5n0={uK{ZHzP>tQh=Uj?DCc!vW#fvzDuKg!y_DO{x1J6Mh<ZV)lf{p7iPb%?* zUY}+`d{)Mlj<*pc{?L_IPUm9knw1f+DNFp0|L!0Riq~=&9HN>+7#y#%rP4bH!^e}} zMi@T+$`rye;!_C6idP6^bNKk-^<x)`GKG|SGxcL5^bWb0R{Vv>DQ6hpG|n_){F+7p z*EB*#*ofo0fz|v53HPYj5aC{9B@j);CGbuC+%$Yp3qvyw%@CAK)^)?`UN~xQLUGdP zrsz@BzDNq;-3*V<pL2(Y=p>|c;m|mpmA23zExFOnN+Y2-h`vl9tbR3D6V4%{kuVQ; zpFe$ChRpQ2tnwukmoT$%Q*mvEcGPGy#v)r0@xn36pM;u}wZ}NoSbz?Kgr`f}M|?u% zF7K#3`E2YE`4`QdY}A7-xoTD#Y2z+TNs449a%kEy<D?8eZt~m+Moih5<UItQ7iqp` z)Z)68UK_Y;gO=8^;E3hvyg77_H!4XPGgc{H3Gxv%CLSeo$S#8@xQ$?ny+xF+WIa?U ztX5P4ikoRPz}GacguiHNJTggHi>;fa_v1Dyj%i(LJ!RI2Ff=7zTX_p9hg!#{+rQRf z6wYE_qJ`7Z;HT9X&u8T0YoC#RsKk>#17BN6W*$#HDv#+JEqIP)WajFWqtY~zOSf$s zaY{mLsZoW*jbhfcGi^u8Ev)bzElIu9EtUs+iIP@Z*_qHOL;`8w94it#8;WzHQAc{Q zP_e0@I>}`%UCJV^EF)+X;5V^|03oLsHH2zglKLd};<S}9l_CLEN6zuoM#)*GE=2YQ z=tselv}YPsMk{H&U^?lX9Ec4|os+gh>|ShB=S}Bd=XZ<>lko9qF2bL*;G)emy(;+W z7GXLiF5IOiiw-k;gTXDEZa+i@X}y}Et0^|vlC&s|_@Obh4Lpq}5z<-=4VSh;Q`PQJ z8IEoprH2rGOWo9MtF{%Xqf$n?{>8u$-_f=?H2u*vF5g%&gom_vamrh?E_|d%3@VFq zdde83A$m@i;)qn6Hqy9QNi3y%_7GibOO=w8yhuIQEsoS0;V8K@jS_0W9AlQ^En#9k zVpC#AF)VO!`Dv?@Qj*?P`X14|LwhpT<&?bSMI_LrsPTvDN4N>UHd^VSdKo%e5Lwgs zXB>r}j?=BN^Z~7;k$y+=uUmPk3%Zqw(W*;b&^eX9CkU3LIl6YV+T$zP$9y4}A>0Mv zHsCH%Qe~^U5Vien3Qzb5zLbE(C(v0oZGqH1K5VSCoULqkHU3J%8&iC8Y(5D^y^R$f z%`XZS$!VK0(&j9^$4HyI^o&}fHe-b19D=I83zBA(Ek%NojT^_?vWNzn$%~XYpB`3n zg>C<6TfQ{LXj{^Bh$FP*P3L(DT9&-m<M-lT%&$lJ{e+0_q?QT3SjQ+kos2<5Mx9#w za%>tg(o5{|HZ94Q6E+$gp)2<4(9j&TZ?w%vFm#9`@fUGrH90RYPpvA;Q{F6mdhJb~ z@g8TGrjC;*yxI74oIKx^Ww}3&DB*Vnl3dPj74^4{UP_*!UXHsIjVx2bJT+p!ECH(f z%%2NvkI)(#TT5UT^rQ#THPab?Ev6Kt?c===g;Pvj*MB9HZ!zIf`kO4(12tm<G9rqj zMV@7&QC$OtqF9S=mvn8G(lw11!ldVGK=)#KQp?h<wD6V|%tSJ2;iL^Kgfe@HjnWiP zY2`zd>r!0dFPHfj`V-y{D%l+UNu7*QA4IR|{_-y^<At<bSy+r72d_Xzv3%VpeG%CN z_ajng8P)u*R3$89kqG4>IbMkk$cE0pRC#>ad?mly_GDD0M>*2d{a3NQn|a!qrAB;d z*@l+xm#vfG=!u>xfh@a^bu2C2ni$3u)vDE_N2$LtYJa+Ako4>z8ZqyJ*5;rb#3I{b zOY^4}7U!GZ5NC3*&ABvxdHsTd+4&|1c!WIeAg}C~=C|>_{srgfj+w{%<lg26P8Wbc zC{~)!fgI<>I6k1+9V=)KG)BYnGI#+y8P9XanhRG?&o?>6Cg5XVq`e7ObIT;P*uyT= zK)fw?jL9Wu1C-`pSX(IX5*4zYGZEpW0Evm{^G?Fi@@S)<9qWyp1_Em9>{&KKW_}8b z$&*eeXB3p?w**428Tm!Rn4=jQqXBi$&iUy#mgW^@hAT97Wg}Z-8;L{!66%n6xvd2| zLPa{78Jr!7k}FdPO-+Y88D8S(u2Am|jTP#hp9Rj=PdhVCs#IQQNlsIFb)r90S1H6q z1LvNw3tep?EzO@bbI#0$StZj;N*Wt|(>=Z+Y@GuzO7qXjh!L#{K~dq+8cK&MP0r(R zpjccsKz~jfa^*YZW8Oy2!ihWOp;+2y&UiiP?XMZ7G8m<*6$0|wM>S{e1kIrQmgc)- zi$kl~bsx<aZ0AY@%GHrL9MIto#=OdMoVa;K$L2b(C_~D5MXAgp)Vz#SRlacEv0q*l zl@~(P!73Sfoac!I%H{k8ho*fvgIz5PQ`NGNYFSjbWO31q;^LV_ww*Zy^Up_AFJ)yD zb97#GG~;<i85xm$L6@!2frdbk!f~WHcFQmbUD^nT*I=?KZOh?L;V6f5EUPmYdrI@K z^3EupKD}h-xdqc_mdq+BaW&2?aL@F43yO<pd%Rw+%j5DDUo*JGj-uh3Io&n8VUD|C zre_W`d<~w0+1?qR0{4uPlHwUNX8Pv1+@D3G#680|W46~-Fw@mAr=X;yWO_k^dro74 zXVx4~iMzx-%j=r`Sv02mW}Q2$@!VMjvx~jc3rc3V<`hr^8wzH-JjK3Qo??&t+zc8= WslI5CGNmwzoQ4RGZtwr=|NbZIQR2%0 diff --git a/distribution/windows/setup/inno/WizModernImage.bmp b/distribution/windows/setup/inno/WizModernImage.bmp deleted file mode 100644 index cf844e093a4cc7aceee0be44353817397825e35b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52574 zcmdtL37Aynwe^3zh#&|ugOEgxnkbT(M5BquIK`NcK?M^v62U3RU>uMcgviuQGfE2$ z-AF?NBA_79$P6;ig9ym1(v2tzn&IYp75jd_wfB3fst3TB{Ga=L|9z@YRS#6HT5GTU z?)N?C6t^~OwI#B+_UtISoJW)Sy8f&vIxDJZKfioK6xFEgU-pBr`=9^$pD6puC!=58 zdTaEbfB$<lCMzp?sn2s!yN4f&hNlgTW>1+E&71y8^jz02(K~N#k2bAY9ZelGDw>!% zB3eFgZZv*aMs#nB=F#dUi=r75UWyjI{#x|mk-}*ErVUZSp##yz6-%Qp{_*$dz@FXF zh9|FyUcCS6sA%BNqEAQM92JfIb+ob1t<g)5-xz(l;Lp)lGaiXn%^Vkvyt7i&|JRkG zqRDqfH(q;HbnP`iiHg4XNA&6OkE85+D@CJQREkFOHH^Q@Xj&;6*tk+O{(-7d(W}3U zmcQ^2k1Iu!T2+ol^S8tJyBUA18om5T)oA3sRilFOjicj}?~aNVcZjAw!oO=(Daz*W zH+0qSD@D8he14SwMAaydzaQU<pFL1L%I{b|n*K!nXi@j?MQ=XeC|Wz<s;Fo|tLW`H z1Ecpgz8byUrV@Y8^YC0tyHt&4^6y`6!*lR8p6A&(@O#mQp;t$rzW)2DXw#pg-`@VC z=&Kzgqb&ofMeBLJ!WU~qb32{SYw+*dSB(~SufxB&AX+`}l4#S=M$zWXpGI3pT_1J6 z@B7i}(RW5gYuZNd&-_EQ?Ug@8|L2!Kh(6u7Alf~&M)c;Nt4EuLd@EWtph2|s`TEh@ zqb}p$Um7hPaA~w-)DNOnLw*nqdF<lot#QAIcD!_J^x5KvqN2@D^KWWKtJ7;mtNFL9 zhg=%%8{a6}IgZyI#e2=<@k>{8e@(RS<=diNlYbQ*e62~eYf6*o(H1|B-d*}!^wE~l z(I;<Dif+2$YF@Kuv}4S-qAf3eE83BLNwj<Xr9982{QFCy{gWF-FZcRxv~SAQ(auTN zL|ew`Id6z|PX0x7@YP>M@6Ed>+B^HcsAy-m=;PJTMn!wmqk>hvqQbTPqYpL=i9VQC zC)%G|J6e}nhv)k?|Mt>o*Cd`l=Q8ep5N!tY!B?+|)@J`GI`HZ*qQmok6>Xh#Q?zTw zZ9Hxo9m;PS?S8FUw0BPP=-`4sMEl-&I6AbbO>}I{6Vdz2pNI}EeI`1*vU7A|%X86x zAIyrre1A&x<<U2yFOP4EHjn>KbYR90qBS{JM2GXQ=Xrn1^Zp_#Saf@IXzuM%;o_!I z!Q$UWM_1ez6)yWjbZqq_(UBF8MaMV&Df(b_`{?-QPSIc9?i2lGS4Q;Z-ws4yeSR$3 zGp%m4HJ7i+S4O+QePHe{qCInOjr#rRis;aiyP{7v{xN!gUj1n2%uAxe<rhW!7dC|N z8=`|tZ;uvE_<mHl;nwKY>|aDfpZ|IE!PXx}%U`=G`gqS>(fWmrqm^@h7#-VvQ?zl} z&!VED|Kh7C`r?Z(qM!ZjXVFi7@)L9aRcDM}{o?<G_{A^I_{aZyfAA}d|Fzfu{{I8< zzedjg&tCZd0ja<L4JrTORkr;w5%&Eze6oMbKT9C_Cm;M<Ui_-7&ZzZI>@O&%WyFum z_*uyxo$&?E{0C=xt4LZR7y(WfCH|Tm`2R8zuT}!m4^9&)fBHinC!XS8LV60OODgu` zpZvIZ{HRnE|2^N8e2(w`gzcL|nL_;VXKacTT9V}5dYVZ5Rm#8AQ}KjX{jAK_`Winp zC}r=$%lzO6KTEta=&rr>+S7&b$AA7a{$Y5MvR~nA{<NeZ$?uceC1w3y9PzvNI_clV zzx!VD?~~7weBOWl(N(`n*{(_zR}2^<CT+~!EsE<-5%$aQmk=IP`m>l#Cl#xwzUUbr z7iXL2Q092J#Co9=eAnH=7UG_JZn)tdHug8iKhtl8)c=Y8v6N3}9-h7UtDf<@lFTR7 z`EigeNEjE&IN45hAHU*N{_nz*q&#iOS3L9gfwW(R`#>RYUKBVR;>CEn=boD(?dF?r zZgF#q>#uKNaea&MphXLQLGTCn+~c$s<J0IY_A39vH}aw(G>ne#p6i6qFo5a$n?ZQJ z#l6?x>ks0+BTe9Rn5nt>4Uol5r-+dvGKMwng0OL7UUw~9so;kp!k^ne<te`Ry`Q_} zsV`Eh#K%ZV-<Nz_dU~lWosC0LX!<6ZyO;QN>Clgj)|-+4dQ_L_$R11X{weP9k}rSy z@BO_i3q21VAQDSsmsZfq0#^dAK~=(D--3U7kFqmJ?$7Q8<Me2X{k9nWLFJ!+PeoZu z8E_NOl~qQ<kP@<V_-`y}_1CVuo<Yx~XS}Mk$&0`IDZUGUd2bXkf1k0+*NH>SdwmP3 zXaqhg${zjQsp8ka<G0SL{)L#lzJ)Xga!}k};s>|t_5Rr~jP~zigr>4y<oX!kuLU6q z@3!CF#y9#(-tkC(6kz@u&+`l@Zq+D7aL7&6^)o|_=?yYmC7F@NMnS11)l5FqHh%eV zFF?K(|AprP|4jc{&mzTXf2`sCUKr2gS3dJS@8Z^k%9xoqdy7>=uh2o`U;i#CaHror ze5&YlTc=J&tN288ZW2K*Z(%0avr{sHcW$K+pP5Ddg=7wic&kIiiZ}DTrm_fnRAiZ~ zx7~Kz!?&d(eCT0q$>0xedpIOOP#ut#mU8$#1~Oo@9`5U46w^WH@BIj&<v}UqGD~H! z#!4DTf^o_aynu~=#6Q(DBn8*AtER{8+nIINUj#2h<SmeR-7Ur;EZ!?KL*b)A<W8N8 ztcT)wwsge5a#my2&FG?1Aua=z2{OM1lP<Fc7X4#`sB(jwU1f21TPG7ZfOz(y()i+^ zJoM1B`YT|P6s~yyDUS=}bq+F4N?u;Foi>8bKl-_9Y|_uysW>9DsqES4`rdw~h|@st z&2xl`Z-S@zTlKuGF}!T;V;arTW@!4ZSZBS??=b7b4;zIsS&y`N>A5FHjA+H0Ylvq? zw0h#XCT;pY68^;g95RF8kGjE~NS7PH;iYlx8RQOsm{eM=p{1giYqN0@Vc#~-jd&(T zR@6|BzWRzgdsI~PVyowxJnlI4ZzQ=19;y&>YXJ97J*aJ^@3d0?z_tFKm+nxxt!&43 zCL0yEKYaV`O`d2K-~p*djT)6JXj9ZESL3UO4I375D=K>Ci6*z*&ZdY3m%-iMz)>~7 z>Z+fAZF7r9cz3&4S$xb5Z88Uy#Y~eYu5f_mDpamsz8X=xcBM+^o?EL{)v8s`uTE61 z3|2!~R5YSVU;d4A+39yG?5?-j8?|Megxa^>3Yn+b1o2k>0d?n&J8rlk7TPLK(3uzO z^u&t>utw$bH7~f}f|^7Eq@gsB0$Q<hg>okRi%)cQlnAc(`zU&=oL_%miyQ8^!{uho zQG_AH9+$O~)+tI~eeKnZ&**H9cAe4K09L48t!@>I;wWp0$^=NmSwjihuvHTi9Dp*o z3i@@|@d638W3hkqqaUAk12;<l#wz0tE$+J>rFlN5QEq<r*?z5LiE<UI)eRw-hEh~k zGQGi=3KE<ZYDo1~jit8?o>2QS5h>sBnkj0R#b5lhP`ht2p&eovT6kt4_IpCFRpZ?A zJRD|>()IS7ED5rDWkWfl@3VakWdfwBjoivF&BJ3Pr@sHu_kM)O7)Ir332jP4CC`a3 zo2by#s1y(;aRw@jfrP!{QLzSZ?~30i-0f;3x2tU<cc|p?P*Uc-M(N+&!n~?QF~4+r zxYI)q^?mj^5S9xZHaM?Ag9b@DU2m7$m@GvkfZ?*J=n3@pYVN*y40D^>;_=k%rToT* z>0(MN8NKMpE0wF9CvYhtoM<j8-QJ{RN!ug{t?(6D$@_J8Q-I`cGBSvb)@O!^&`7P- zr(31;4R~6nF`<F@Rjn9dJ)%K9gKA_NN&`uq3@MpFmhzzDiw%ofS<7bLzWD}u8?{+l z(o6q59=FR>*?$P%x7@)DnqEi6+j=qjuzuL(iK2$(syRdfOoVV6l`)eJvTCvVlSEmO zdf5shHFop#5Gk?m<3(ldTW(3w^b`;IBNcBT-ly@!JZ(agiw(<FF_~j@b>asx$hua8 ze84%S+SMzTD{A;e0IA`|LB`I$<=Wq#N$t2HyH>NSxEqtwjjt&Bs+u4gusVsbZ)1=l zB~MRe_3Gt{itZ=LU2F<DNth_)iDCQHVymmYqs4uuG`5TV(if$RYQ+!}0PTTLmIUdx zDa+aty>i2%XK+nW8@(Rm6%qUQ(weySx2N4G-cq`SC!-uKrTaeHsi>$zfanMt)zRh= zgOqO=ajd;KwY33Rp<&T;iHro}A9+Q@_B#IC-<~25;~xi0rzma3`(bFT=|T$@@Dic# zjml7h<n1$wUGb};5hgZ0MQGAYY&o02+o#*G^nLDWpI-$UpM9pN1~h_2kWvsfGA`@Y zEnl%l1vZb$m8+kx`crDuPPn^9Q4#utQ5&rvvq9Ut-7{JH+B@!$(5YqT;l2-z8r8R` zsG?y^B0Rg%*@4SCwJK2DlfhU*)TmIg>M6<(8Cle@$wQq|6S74Mw7$b8V4jqx-fPKL zo|dJ(c>j(W-R(_^iYmo43K;-Bcw85R>NBhZw=O(}TdqQaxDpR4G9;#mZG)iJC`{^~ zpCRbS%rL>ys@{E{9W|;=!00+B5Q4MOxk6N-maJ`=pm$KGO0CMs$+%RZVhMEN+oGc9 z`eE!&D&uBscXr_Mx3`>b3rh1ZDLYEWzJ{@@FnTr`jUusr{rc>y31O8+^}lRT7t^G0 zeRkc7g85bDvOvNk#tsPy$j2UYXMZiNHJOppHz$<7joH<+x08<vnoQ^VCr_Rf%JTfC z(U-(|7gVW2@hJxM+;X%KWeHA&3|0JIjEz@lC2Y+8m8*T#&rh?p_@fMCEJ7nfOX=4h zdF`2^3JHwHArKYy!C1*K)~!}kbDID(u2T?JRHH;s4zZ+gzlZt-tpkr%#!u~(<ZnuP zx^Lf6qeeaQ>T7h4RaAFe>H1>v%NS#=I^ywy+O_E(0a_EBFlvN0s8^HGxfGMs$5ws& zrd09A9;1xkkFURu*w=D+$Qm+C?bTaKKl=#dOyyt+<)Yw$%XzF?uRh;YJGWBpO0{F4 zV$_wd_Ek~Ck~s;D&#@e!AzM|P{wx;zSJt7K;HTV$%J?Wk$DT&%S08zGL{U-gB##bJ zAkq5#24v{TYPD*et6<h;Kt-r2e{NC38pVABjn9lq;Zd#6WB1*6-wp714~uobIsN9z zXb}57Y(l?Ay!z^^qZ&3WSJ$*wIvR^cBp9pP&ns1}%B+=epw6f%U!$m8F^n{4MK6J| zZ?S{~<9#aQcia-U7Rd}O{^+_p?!nTD>W!xn+JcO%(Lf*_BkC$6<(cXi$WG^0XMw^Z z0F4QyIu%byO41Xz-yUm?*f-omH$m5^wWwdYvrj2Bzc5dGY3%1TK4LV&ByB~Fx}iFH zKC)NsIj0&1X;7<r^{VGHLK8xo0<<_rRn1ly5v|2z8?WM+#(1PNgvZm1t+Er65ixiw zR~m?~zS@dOVHFJ{CbnQYkLOgXc|qN}RnMtjJv5AlQ%D_XF^m$r)u`7DqzyF1F-q$* z1v6HgBgoSat9l2eCAa!q3bu`eDn5cJ9{-~%Rj20p=KzxMz3>J?D>f`j`ns~_g)IEs z&L|U%&AKyFSIz%f!}X;{^gfN`Mx&~CDHg@#2dc<5ol4kL2xIlC)SYww;~Y@(rAT-L zob)&`MjIVRy!PsA&ZCXkkERewiPR$6J-0yS?@zg<D2*H_Eoc@!`m+gSQRVXGsnUvo z5p-2+{RaU$eOV+3O<=637Ve6dcs3G937Kl_do3aFqmC25Kds=tX6s5ngwoGG_gt&g zRb*i-88o&PDhMJV{VoX<LP4hHr(z9?dBYJ8S=ONSL-Cpl2bFHVS*v@R55@<PPIu-9 z%wsl<)5hZalx~6~3ZeehdRQ&eh6mwS<;ulKivtCtR#Eg<&xl0hQ6j;k=3PoJ>(5li zDUqi3=?2Awrww9PErp7v%9Sg_MaAkBE1u6}suuT^EAq3jtn8>+2`@*qsu4JKr01Md zfpNy(WQ;Hd2}Y~po{$VRDnE1<LGIuG9?i?zRKA1K4?RTLW|7PmaWvP{;v&-&fvl<( zWfeo2<NWi1%py1#!{Tze8Z`o!+)->4PqeY2z;-2!O@DTS<}&W=SZ*EiEOXO1-OsD{ zDCt~Tjg0ykVe}PH0~uo!$hgSVI`@1ug)+;57h^tK@ieVoN}4YrcFbc^Y$NjiAU1NB zx!qwHt?o$YugZh)^dOzcP_Qd$A-8J93YL68gU<@AhqroPxKhK6t)V8RjEBa88RGq# zYo9t2N}J9i(W08K$(O}s5@gj{m8w<pzNhy2GKujC)aQ~ahes;nVSP`>i&>SrSq%?r zTOp6-_KIF|uZ|2)&orG4UTqyVs92$5c}Pm6q;fKrI{~s57;9U1#vhU$RbxI!1UsiN znW&I*O~TuBXp+0d{VncEDxQ!&Jh&r_Ff1uc=PGQ5v2s!QFVAkkQc1O>ZwzD7HyWN} zjG@=9S+kOjEFAFqU{(r19>!vO8MpeQ>7jd@`PUuyoLXyI9v#=m&$SsxfLOD(mT)Q; zU8eZ}ak9~Qb!)o0OM{fwMq~nH%?qm8@PcicqzwH!kf<S>SNokEs8KhrW3axCdj_rD z)LK&x5ir(uh+*HT&UrN}x!md<T<)q>&&4yPKweO#Hf&PxulOLvJH?3XWY)I1mla77 z8Q1cXQr~lrnhDBx3dU;ictPc&;usC;$vSl}p!*JTs{);?j8!L|=x@no%^0fG)<QUI zqx}<-#~`hadq%q2LJ7$G@At90wB{!DLk~49s#ql)#Hywv21%`p(W!4>l)6X&vKAUw zN=_DJoET)?3(8wX8WBo4V(a*V$?b=V<0I}tZcVq#4)4icgGXj{h7ycb!1%52eCIot zUedbb#!?{p!O41ct5pRg7^^7-EGOOEstsY*UH4oyK1Czo@}t-`YJOzxAoioUhBXU_ z#N4>M%y6k=jKV35RU9KQzjM(=mtJy7X2(Otp{n0KyIvKlQ;ZS09b}S8=G>SspiEjj zh@I-~KT7OVs_jQ&o~4}<K1EHjnZ)>=i!QzVBE_YbWNwI&3gXH7bmeC^s#irs#wi)p z_MGI&&NGx>ef30Vig{35-nQd39H`+qjZX8r`f6LVJ%!x;`p#5mi`M7W)m94QMHgLu z`K6Zw^K!*CH?>~BvA*Wn0(rI;sm{jpRjQS&KtXPv^1KTw>-hTz?|F@!8N_bW>Crao z(H?!ws-ze5`{~v0FSUif5gs{sC5Z3{k(C=NA0@TKzVy;-9N{&JyY9N_!Sx&8WrYfW z>@;<(Q>OtqW4RN)2`elY(5^Ln@g<uw1c*!!<NA{*<@eopf9T7Ldz%8T1Hj@j1Q_eq zO<)A#MVA8-DlZQR?@~N@*OM^n>wONARdV=@*H%*0)(T*4P7r7~qSLb&+ZUYG<lak@ zYuyABLswhpY?ThAexFH<c;uj^U^+(gwP<vZm)vxzAry;-@TMmf53bvI=#U`#5eFS_ zsH@`)DZY`~ii$5@am6#w(Tuxg9t~qQYP;Bf{G�h%6mGMR?D&_9v?;#S=W5T_Ez3 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 ZAv0SJCQyo6!nL-C18G<#HQU&+{}&UhRh<9; diff --git a/distribution/windows/setup/inno/WizModernSmallImage.bmp b/distribution/windows/setup/inno/WizModernSmallImage.bmp deleted file mode 100644 index 1e8e49792789cc6c89ff18194cf31e4c6765b9a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4158 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 VrFl`p+`PP~yzE?|P<oye{2RBq|HuFU diff --git a/distribution/windows/setup/inno/islzma.dll b/distribution/windows/setup/inno/islzma.dll deleted file mode 100644 index 49395ada5e019330bb84ed5d5b2504d6fc4c437b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74240 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 U0?=&!HK8hrv+Z5v4; zeKbuPRufQsJs|~1R*z=Jj*eujDK|4p+MD3gZZjp*ej{qLG$93!z}aX}<OOhUCctEV z#emnho>sA}D%Sm^=$^0(UR07Naph^$Ety1Sb+<{~B{WCm;~JJ#4fll|DB!=L4)SeI z`hMJwZx7ZE_-e}O6LWGnn=GLWveICdw*wfsXX(*K*<4hh({R}OAl<C$6KJt-nBiX| z|4TO(A)<%jHL_WooAHjoH&DcXLzvKVpN4qg9iGCL^Gu+Qi{7AE8DH;4{aQdN=f9zr zNZ2}XPg)HxiSorHzpMhQDF^#t40px`(zMcqtheHwWGZx9*eKI#$|xTZ@U8qG#2u@t zqrAs+$ON={I!vOwfXw0(Jz@e85i>@cbPFv!SwP`Vww}=B>$9#LP4tGTXbrn5g~^LJ zHK+;xpdde^?#d=ecz<M^wt5b3p@)Tqv3fQh=#~1>k76I$<fTeLe*nG;1Gd`}yTF!{ z`FiTM(P2*veqSwjn71u@s{R@pUv60m2eRVbL!M)1SxIBl3IDZ#er~d5w7Z_#O<F^7 z(JpnWHn|Fuf)@6<VUHvYmcRyHQUGD-Jq2rIR^d0vzXx-r$erqgScG%&;B;Zf@J{}^ zE)$MR{KTMsxb9$6bg`x3Br9yCIn}Jvi}gKhaAw~I()|~qfxjC{&94XGq=C}Ms$kRc zW_0AYbFRGJ<b91byI0^T$alEc;_7YV3G`nbuq_+Vz103%H|4JN?)SFo!)st6zedkP zxn78WOMt&kPR?ip-f9-Hg3@$GDgfF)C!%K&SI7c^(V7mN&4o%=cM{o3kt{xLp(GVb z#=1(B5+fobi95=O0`RO9k)zVFaP;-4ko?Jxil%l+8ZGG;jwKQ>Uk+4iFOi5?Xv=n) zw$p06ZYTG_Kr|7yVMSpaq04ZKo25!ElD*JH84D<5pO~IT6Op%sf*W)+B#~&W&jk6a z)HUzBK~`g-MUuye?AT)@cl7*^P<tkfO;%%P8KkFY+IY~#0uEj>AIo3btR-xwn+M(O zA!0gS;$*9Yz?fCa){)TRL4`dexG9sZa!|r7J6k8DNzlO_669NwUCUMxCl6hm0gQZ> z%`?kY!E2phc98YE0lw5xk7b!vzV76*OgFQyBC_rX_3{#U{!BHj#FnBGGMvo3#Oy1v zL`nkM(ro?TFt_0)VR(myfc;VI=qOfVW+fJ$60LX&TDTCZO%K|L%NPJIG1r7F`eH%0 z_F58)G5Q`#j07*OPuqB@t%A>S2drEFF31}k)~$D#yvhs4OgeY9FAS2gtPW-IPEV{w zu}z}2L`URW&%w9|H>f4Ae=oX0?*F;%7NKik*WqqR{no8l!_Zpd;05lWb?ZNxyptdH zwzd2;jh}4#D^1zGaX$Gu_@yC?U<2|ktHf-5t#PqD7y1#8dtzF)t))nsloq)aWaor# zj{_-Ke`_g9n{-E7#D>)o^1NxqW?FNxNO96-lG<s;@(c?2pyEQ~A()MBM6NWld-jnP z*K5MMZl_YqJB_jeQ)GI=|80hwf^;|erxR*SiMDC8(@ZR2uD=PaV5tad4T<iPur2si z>}p<x^&wb=3cDI#bbHbi`KWfTT5Kb~`6V9g3b6)c!-$jn-`S+)HUWm{yV`7ri3QDA zb}zBRp#b@hF%A8U2W<ez?g_ehNmhWCG1U^Ai68O27dw}xW}0eicn9$*$WSe@C&>5; zW{E|$$}%uDPw-I;-BGB&ZHic@q1(Q+$VZ;t&@=o<HB~sIrpxFB{s1CT`%aL)SbsA} zwVo(d`Yc7Mp55xv?<Q1`Coi!Hl|UW)p{K+Jo&m3Tc6;|k->ttkWq;V$4PDP%Cm-<b z3w;81mfv8&MTwcZX}aHL`oTo<_X3CZCan-dQ)0G8YeD>%Ns;e@zo7sBKKvM5QtpI< zYdM_Z@Te4+_$;?q`8A*Az;FvDq!rN;^S5;~Z%8*&{oDQx<1_!{VE;P)PsZndF+P|u zMo)bE`0T^Vq8OhZF+S*@ob2D<b1bq5pB-O{{yoI+cfeox%QW8K^pOw%hd>dAD~Ru9 zg)d30SrZN+^t{$)x^5!b<ChNb_#r(v2sJMGZzi8i%HNZ73q1*c5BxQ*9QYLYA4zvm zP{b!`;Ue`DQ}{-;agOwgbR#@6>91_K0ltA>hmj>dHB0&d6}K<>JC~`ZBi=-*Ie3pZ zPl$@`8*aV$=BQh|0b?MT#eN8Fp~*JXFvKc>J)TnbWNu=~TWD+-ua*KqvcyRx>u*{~ zx%oOGxA2IhAytD&)NLh@jUADzTOfVc6xmv7h*^=H6**Y7nN=fd0Y;sR2;RG2@2iB| zgE@Se0#%P&$l&BA(JTfaztRz~Zf+04E^wfImn6BQIMpnv?dkk;UuT`Ql@<x9T1?T} z5z0{w^O(#Ceb#W`aUN{n8Hi(XyRgbI9`Kd{Sf~E8Lc9Yw(LL7Yt*8$kh?_`sX@N9f zcU@M~1+o;Ex_G4-Yw05@E!OBL<kIetd&lCc4rE%R58}pqD!OOscr>Y(!)*1oT?9k> zX9AL%fN6ue_}iiM?cxSK@pNi;$-bC%CHXYb1{x6P3a5+397r(t8f6OXIBi-20WP?2 zfetXO=rygeOyNZm_dBSEyueaU#@-<`WA`-WT_sBu9vJ(YeG05||NoLC5M?$-F%KDX zfgbq_Q?*&Gw2%{LwCUDB(9fmBAzx?Y2Jfl9G<GZ80WQh9x|pCspBhJ8+NaiGmtY!U zC`I=0u>2wiqIqB_@NUcb*eABOqv<O?yl(g*9$RxI0YA;O=B_lYI6*-&<~4W8-aTuk zDfu%TyNH&;BU&nLYbw%rQP=<=b;%b@MdVw_W-}b4XIOkOHp3paa&xc(lTlyX8eK}j zVUeCq8j9|u9>6rrdpJ&ZAR@Kgn60tWY*y-GrA}6g*`uA6+E}TDm71A9i<RcF(p-dl z4Y7bhe-)L8ZMeSxkteiThmRemc1htv8wSxp*KSr)5V2@QX-S&1NZKr=ETHegBC&6` zHL6orW|i__AyysW`6(-h)#{Si!-qgI@fEh6GO7X_JzfBYLH<_Ck9AN!tDqc&>h_lf zK<YWvpx%c%`4QirBMXfA-C{5?z(RJoF3l<yaHZ&BxH7_H&=SH_=&Q_M&aa@*qsUF( zcj5e+2y{Amu)wb&=Ao?oV&&^Z<<WP;Pxqy72eU~0hiao!3Y*o=>3Y*AFqYqqI2V}& zOsK=n&HgnYs6@9q0LmPOz^INv6c__g$&ahY28fF>h%+p(+7u|{<#s+U_CdP3+$m|{ ztH{?Q=6JOHY^?BGn@^*4ZJOc_=)b}$B0|HWR^W)=Rmv-XMdY;cN~{}EB*cdO^rq5T zCa@Y`q2rP8$u=CvWe9$M^dsVHYjijDEMS46ULJy_WcC#~>*{!>Tx1h`V_hU^fTY|X zz?9jQY#;1pK?Dxw&?aki56=weh&V^{BG5pQrL0`z8x#!T{%JyVT#J{!uFx|}ov_7x zmCn#_`>vo~f`6nwF{iy8yAyg5P_PVmh}@_ycS&Iv&%{ETJu)gO&F1pIlHZZfuyrb! z0A-qhe@u0f$%9r;Ah@sq!gyhq^LkTa41Mzf?<wDfNO~=nGCL3gRiV`?aak}#otxDu zY+5#(=3>*FY?^~jv$JV7HqFAOnOR*Ho0i9><+8dQeGCxEmKMZI3aQF?NogA{T8aN< z7vVWaZF9jKjhxaR_X7#6&Y`IrV8~+qi<N%K<{V{9j<F@j*%BvP;$lk%*pl-ogOHrI zLiLO*^sY9|<=20DC&XySoC>`PH*;yaMQm6`#-Jq-)QbEh;0TA*WCaGo!EcS83Ojjq zAzxmqPs_oWRw#iASdF9_kV%qWb>Yi|2_O8OHdAD;wzCalWv>3w9cU|FsD5gSe8F!c z@4BWf0pw-y;cb2zH|2>p`HTWyRLK2GnIBaa6;}Frfs!}`fj-o2m7?#wK=5UvVg3cQ zi46>5`{H-{<G=yGD;Is_4`lPYyvB5aujr`<r$_fZm@d3<{4?tx!ia(DU=L)oyMXLG zeIbge59COZrQmA2_Y{^V4_cp!rIC*p+NC6vc{{~J*Lfi)Y*OE3)Me+L|8yGhGQ2Cg zC-Q>UVB!b+o{c6R{4J%Qp^0qdQKa@gjPg`kvejpjl(BjD_zo_$gcM(UT?TI_KNFjl z1FQV6)rJsMkLL=_TbSzK--h&$mbZi`!C=TSnEj1bF-13&UM|`7^W3Fshw?H=QsRH( z=YW*GhVu`hjOuHYWsr2mje0x>@}VC_zCb4$GXt4slq;vkFn58~(1i>inYw$`*a-Dt zTF*zmH|sH#GpPevp}*83USo&=PmPa-CN2ZyCjkjztxl2}^R-&P>XRblIfS`uwqgi# z-VdTm*Oi;W$ETP#oQDn~Jj|qaxO^pfph4TRy*!wwo;86LAI##FB-zT!{a^<Db$A$) zENPL1;vRg0j9}{*fU@`uGh026Zb}N-`uVtFs~3vLTu5UZl+60Yc+}PtC&fM;&LC|w zY-NDj?$3jz2g8c32Cx$Q%^ZB|zCyBfgc!i|b^m`y-_ZyMcuw@x^7L0p9;glQmE=Tj zQZJ-GI8vMb!%?pQ<x<awePj5W>L(ee-?`>+(}ze&Bkzfn24$)?n5E^JSf->&tlD4^ z4?>iy4L0#$11;l?U0OcEy9X6pAB{olstpclx!rqMy^v{rv>hg``r%Qvy@2^0YJ*d% zp}hH}cI#&3b*c?6QIiY3MNMugG6vQTWpG+I#k$X`?Y5q?(CunNwzT{zDjyy}4T{jF zh{0q~`bnLh^fzrMu!5aMlGIsbGVyc#_3kr}U?RA(=OZ}xYynO21pWGsrDzm((tDUI ztBJA8-Xz){;+DYla$#vH#!Izl%aUK?%Q|GKO#kb{kijB-<Gipem22v2BS2vK0i<(2 z9d?=enuBpC22$HN@T!dR8@?|~I|+B%^DeN6_6mK!Y(~NtzvKP<thgmX+wQ_b)EB>t zyrsQhn~0Lz8`@;)WtYgPy|6(f4Gc}P-6V3whUOAU0~eF{#vHWIHa-kkxSC7%>K3}^ zd34X8p!<!JMV_Zbo&u5QX_2Q;<at))DHVC17kQ?OJTHnoevzkD<e4q<>=1e8h&*i~ z&peUmHIZk&$kQeAED(A2i#!WOo<kzfVv*-RM4lxg&k>O)Eb{zG<Y^Fjj*2|XM4n?J z&kB)87kQdRp5r3V8j+`8<XJ27e2IJD+9R;o4lL#;as8!8nuifjjnl@-7+SW`f^p?) z0o|)My61&-&+T--u~g)7;J#G?<8c1e4nnRSW?;`z&Y!(OmgF`Hb9($CL3|*&B=zp! zf05pZ&_HiQc4c}5Ig|88ga&#evh(ZJNaupg1icaAX&Z^sG?l3Cze{gKY1($8x<Ps) zO4GIz)eR;!fUJ-UBsQ2tl!javlenNXCa8`JN@IfRxS%v9sE%(WN@IfRxJs19RH8bd zi0(O29p6Zl#x@ewag`{IsYG?06QwauRL3_GrLm1fbzCJ%V=7S{=R|3Y6V>sJL}_dz zQ5{!_(wItA$2n0N<3x3QBT*XLNL0sFqBN!w)p1Ug#yC+O-$<0kHWJlwl_-s=M0K1K zr7=!a$2StCv5iD^TqR0lDp4KhL}`o@)oCv@fYN|Pkk}x-5v6I{iRuRFjVKKm!nkrl zX}}QO3rYiq=zb$n8Zd<WOX!X0jOdN%&Y-s+Z2B6#LI0CJzFZmarnNMLv8or$*7fg$ z9mrC_{t4^)!}I`qKs|$p-ShyHjVuncb@f(U=(fPR`Wbq&43j$5jOLNYr4FRC?G`-L zWeOvr&vN@{=%4!ZR=R*X06!*}n7Ke20d(u8Hul29xM3T&;QM7#4@`ZUSgFwMj<zwi zALYUntegd>)$&ZC5c)D<rYy(S1}GoIznd68hFkzR$NG3X+ulV@aUGR-+t@}4(2zZm z+fge(61SJyD~LrgH^B!iB|<h#DR}&kE?xgungfJG6)iPNrFsB6E8xPk@J0vT?Z>;c zjy0K3C%#4}Yji|zRvTgJeV^hxXSzKDn1R#QC*MFAn-_9uer>|KFct@9I@Cb6v|?Yv zbRSx>jlR!5B4Cd^iS~IsraP+F6f44G+lnF*c6p30wj(Nwwk`|`57PIv&hlCJEj$BG zUf#oB@A*Xi&~*Bp35QGpvl_67@iEm6j~z9$44wQ{Fdbp^rs}Y6vtlC5$MW`=KEnEk z7?5a|A~u%Mid{cgw~XoOa#!CKCQL<986t|u^6uCt>7Kp!Fe}fX!5^$V2K`nuM3oA} zQvBADApfjsA5G!l|D_=DDYOO2tYuHNZkr)dZ>i<xcN=W4h(@UamLc!G*z5r93`%EH zJYDxNl(@9rAERCQUE1Mfl0uJPrq4zDJE?5|G2+h~Ks^q`1GMo26S`ph8NvQNu}{qM z0lC|{&EnS(o;(DiZ$rdTh=yMVP%D-k<#+i$FWBaE_k`XgXw3q&%M9d-SI8m=c=zyj z?UxGhbHw_G4tWm{i_VPViEbV9D)ChJB~5SMZ~ZOuV?B9qtQRhR8@7O<0;a4F?WmzO zoC<GS(;m^?q<`w|SYIYT6FX_PZkybw{>60q-Pk!Lc2ZIQ@}T#eth^%cG2B<7H^kN) z!dL$*RDri`#9p3|Pw{sqyeGfIdt)ceav$t}n{}J>=k%DV{?&B)&#^uw_LZXk^+E5S zW#w^s4}aVH-szqRJ;_>kU20w><2R!x(28&ohkq_YbucV;J{EQmKhSd$!!SqCqx!K4 zgaLy6R>FV}iU?z@hhm59_b|&pTs9Wj@PNqgj(9(MBJvx7e=@3v{6*W679{^nz|$C_ zDM7F=Gv)suYuz@znnau9GLXKFGKR7UmAsT#x4`+)y%^Igz=TPx-4uEB60$I$QNJ>S zvCo1Swq^3q>WcWNSTA^_%ixbg;1Br_8+8vGcUkRIP<v(UFUlfWEA%OTEOo90bBG3D zsEj3|p=wMs%{xIw(&+mvo^JBmrF&v*>^&^=vg%G^nHU1Wjv+5e<74Y)#y&yuLoW+1 zrDAdy6`PfIS-EW}ClpBgK)C@;vrhp@5kTj_94UY<f^#_}Xzo(HEf}n_zkHFoDXzfa z52CtfFIFc;6`m>UHU#m5JGgzFb=zHO%<kshxAnt^-1HfJ$3DTEhhn<Il~t6>vQ9oE zcU8gzWrlmmf-M<7xazFxL;#F!pj~Ef0^YE2PLiK6cDxHy)uSdYyVtsH@z0ghM`8nt zdi25A3B{|+lb^$u&;e8AO^`J0EOW^NZ1S%uMC+_M^gH#et?n1v9RnaTv+(yBZP929 zwsbQ*B$u@D?9T~#-`q?Onjw!mnxO`hO<{U_)<$iF9;XKC=4*HK3u%`aDOg+d=q3^G z(1o6Kqa)AWMJWB|M&3cy<VrIdaSS#>byKyWf32;?q>9#C%P=oT#3YCYTIKEfshX-l zkymQZm`fq1jB0Frqk^Zh@}NEg<jGZfYQnn$WMxJ0<e1dm3a!G1x~nl49_pV#bR?f? zt_=DSkI;>fOYNa2Y%m#CZGj&M?<k;&>sTME;ya#u7;k*9lARH`6G7<+)hdT4eeH8w zkj@{X611WnGc}zx43k&rf`Aau+rG1P<1|a2=g5W@(<EgCw&4LJ?3OtjIyo13u&ArZ z6>ox5i%qP)MCC!QMNeVXwB5RGQyCetv7?HNfdJK6w>3{CQ(e#^(O+}Z6Qf|NHUF9} zq&bm8lu6}KFPM^<A`nBH%E*{SMMFwd1g+b4l#y|odM{?ev>ZDq<oSy)Qv*$(C#he4 zQ8ZXPSML0px)$-|{hCq_u=yr)D`E9n^A23(Sdjg3EpCjL>JIbMc#yQo<}lV>%Bh<% z?H>~H6_gof2JS=#<Y5m}J?gG!sX+L9@f8hpgFpWG^SEOVufaFp^&;K38ck4r{A@Il zg5l3eDA<bvCbmVu#7|qJzo69u(jLF2hHGoEkFANCt7c6ba2YzcCjp@zUqBwn#ayGe z`5HAB2>(D+eoQUCm_<dkO<7OiLeU2NPA3Fe1AB>b*RbIr^93MtBJrI>0&FK$z;@E> z$Q9%!^z*;zK?o(#y0g#DwM|sh=7%X4Hu(rYcT|wx0PVqc)sY3VthOdDa3<D>l5H5) zGWnKWM3;Pq1HP#;xGwu!iW4veG>v8nYYN?A_>gk&al^!g35;eO6&LjvEjwJ@f<Ewr z2s7w4O&ZPSDYGLbEdkS{GE?M7f?lu*(OvJ*8q+)nTgFYY=VO0RhuC0=^w0@Vd>#rd z@XfO<s2>Y_WT6|mfIg30-^v0SN`xq8negRQC>UeF7FvZ;xqRN*1w2X|=sSYVjRm1> z-t1n1?97aXFWA&J(Ji|vO33t6?>go}I~Z7o(sd!aagrF`wNb&gn?!NMG-xF#&xVI> zMp-NY!f)>Y`wLfds)jc`v)!}RL|RLEV$E##m380G117@PtLM_{oJmm7-q(@OAEl`^ zkJ5YuU@V)k^J$uyJo*&I(Ym$X@Z;Rn)$=LWp27<R$u0x#vw-_Tcry##g*`{DTc^7l z<o<h4Nhl+~M6)yXTxMvDb!)q}lNd6fucufe6zdzIZKf1`3MK4|eW1v%gP&(Sk22a? zaUrd>No0cN-+TyF(wN4h$8ks8<~_w;Izqs0Gg-H-t<Hf&Fw~tPOQ7f0YSe^~J5jom zyMT);F^aVPv@lWvn;bkGN4rHNr65<Th5SOp&7xr#jdHVqT#oso1VY^vOkCMZ1cm_s zsR<yU0IMa~dP&6CC${Bb%2qd?3wRMmMl=A#Gt*Ft2W8Dh@j2`zovPbRzI~+4W1G9^ zS$mD1r@QBC_JY`l3e)!ESzCJ(@#-MGi>2cNlIy)W)Z|Go=CwN(s29>gb6~t?A<Pv6 zTY)Xb2XsGdihJLsh$~3wLis(-QV-N?TOOU$KzN@>0)<~GAM%wQs~gG6j(HEWvhysT zl^qBBseKAHaUrelPr{X`gnnbx4Iy4h=tpY{hF}|b2Gs%Gh!h5MVLgsqmIw%PSw*Cz zH{p9!sIq15hWe`p`=iFwd|P(Xi=|(J!Wz*3tb6wenD=RGHCqlKwa+DV;02H&V5TkH zSMV2iK80e4em$3tmwDQ>3n61eUeg6af8D6q(M-8h-W2s;D@%QaFJn8D<T)7Yz3%ke z>IcKsSO&k)a}u%VatzBATX+2634}Ij%_XxtftA82u|<RWfmLqS{2)`nm1khe=52$w zALwFJ&$C<E)Z<C`BO|FVFbt?0VLJ&7g*b&IO)RIk1Vk)|0UiOd_HAu`3*J-s(DTY5 zQWfmh@(D=-6i&CQ&)^*`=cAfsCe2<C4DcN{J&h5A(rCU(h;ipl;TocZ?av}v3S-04 z^SIG0KgKAl+ezJkD<%?4*V(v5dpHe?Yj!OUmp(6^7Y=!zV9*?2dlO|(<r=A33Q!l{ zBq~um6If`UsBWh*z#N*}H+P{5$VzALL8NeHGt~|FoxQK(8NrC(OTl&(=L8Q|2|^Sk zSTJY}eICxKI(T2`v2HZCq~1A!@`gSuG7CWQKrLxX0oWMXlS-`4#|v9rXmhqeF1T_G zklr9xR}?Me!h+14FMd~dt2TS3OSoLLWzDlOoBI5V-}O299d0#t9u3dtce-$y!|%*O zRr7E=UodMSlBT=oVIZ7rW0GCxGgUCEN_@#)Abc?{7<eNwY*LS*nk=ZcY~VqH)E{Um zNx*>tZPvhF_n^U+vV=C3l;~uV+h}YVZ=Vn)A<PdVHHTzm3^xT}w<400m#~@}H0H8y zeUK{1Hl(=lut8#<OiJv%=)|C`mIv-lNB~aWDa7=J%n)J_3*A==86Gsmwf+IZv-<9& z^aenlOOOj|T7*4Vx7laWO(u?rIsJC*jG}(<AY`_;8~DkU*BX+$O-$s`aBgTXkD*i9 zV4001NilTUb=geZBi+t6>PU^NBv(ni$5j&U^oOP?w3Qf+`Yx0MWOjr^PRefN&4z?8 zbh`(wKE6Z1K$T-gQt0+0il-qDeFUmXBR|O(4b}})w^Nf+*pIp+B>$mJW{^I(h+j;a z!1O|e#C<A3zw~=dT*=2qa5Din6EF|Lt8KxX)&y1#J?#kk01~i5Nj?~?r>0p~cEF9n zUlOLmLA-R=D_FdAWA>Sa%^+3iG3h(fSk~sd@Pw!s-)A_@<1?}7irew%nF}&$vUZ2b zbGF4c$({+boz|prEJx@hhzaTdtu<IzjzD=Zfs-pyVn|?enRVNXMM7vpKB3SAO;Fk) zNEOXF9O$hk61#{?LlZZh5*GERioEG1LI>EO0ecFvweS=ZAaVFEkj(?$az2Pzu(rh` zIAR{i?mf@@@;M;hfoz3pJV)&_i8zUZ$mdWS7}p)ugmXjCTeoc~qLGln;!USTlP95* zg(imgMQ(mnj7761)Rxd;a=Wj2BDDrBMi-phfN{qplp!XVl{wf{XM8FJA4_bi1tT<> zbP=u%xDaKzki7xXt%aLrw+w>_on!{)aN<P*`3TP~cM#UHCQU``L?5MLsCEf`cDjD7 zc1N0LFAadnm^WbnE`&}3;dH);Lvv>0Sdbev3-*G6iE${%p(K#t0mlZY0<>pnaUf&1 zJBP#-?MQI(1N^kU<#Sj_@a{rmmm26HK9*nCHYK}17nK6o0^+EY4u2=5#m7M{p(;D{ zI4%urbbRV@>M}%6QlBT%>d2AYfYXVzVv^O9xkf~Z?72vgyKqbbjx4CpK!_k(@WlvQ zuqB~#F%`m&{p%(<#~It};Sq-P37t^)COmKA*dalF+18b`3TxfEY*fO!)j0}N1CnXL zt|6fI^37yWLQD}=ZdEemgA=;BMwxm(<oo2aLj_ezGL;+$QZ@^cMJaw3WzL|yGo{qt z2KmY7Kvm0yq#U&4i2CFUFzSeM_++8_M7!IzEGKRNk_)uyqf8U_^0&YWayPo11#YPP zMsD~*kR}LnlORYCvRyueo@L9O+B^rvw>W$qf+HpyT1smc^DH2_kY0L@$Q`(+2~pui z`=?DX2Mtn^Iq*7Z0g>n@HldCs86^8M5jezVP4Nd2$k+H|A|v?h+UyJy*h8$7v#Asw z*$|)Vq{dm9nUz`CR6C^^+7qxsm>i@KtFU`I(%ruP`iTg@h?2R+`|GWUmr-MBJ_t)B zz<x7skOUIS1IbMGeQsU3mzE4MSR~Aa2!e<FqOipfP@oK^*rSlifzysWTJDcyAJKtl zUD}Jc2$4cYc81}fQac6zfaeKc-ZtN6VN?RtdOP`h)V4I=CIKMeK`M0z>Vhmq!vKU1 zyJ!IR_k61TBXL2Nbt|<61JE)Pz!w0PoTM4LH))0<IS0vhd9P;wF$vBshA~RXqahak z+N^|nCLIJo+PP4h^;IbSWr{PneFeT?jed|RcgdSHVU0RtA7nt@6~KwKR`Y}Z)Q_z4 z+L!!b1G(E*aSVhwxo#}05ZsI-by&rDHX=SvFf(yB+VVl^qE}EJB%lnLmJ7>97?E-u zQ(<2_KTYS^`3CB;K&>v%+nPNe@J&asKE7L=S5LayIDrW#W%P&0`RxWXW9I2OB!3Rm z9~uh${6|BbEaNW;4ipTn73PucF?~Wm?1g-iSTINCS;6wl@-JM%=@VwVr;}0g-5h>5 zZ7no7T3CBdgIBwWE8k3Uq;L%xTAmmivP+wpRAta_Vou0=QhYo)RqDT>)slQnozlWN z1}Ar-^QCp(%Q>0&z~SkaDL|JvdAbS){?sJGw}^pJ2&t1(nk~h^Tf|%wBmOl89#n9I zeb^n}q2xRmc{}236o`2Wpv+=Zjl)#13nInFQ_awLtSrgKX^_wq1Jn>MNiu;TMk4so z4d1{Ihk8D-Zry|#Co#gE#0V;EQAO>@!5px6G~7PuoSjS#^d7a?tx+Gg&-9V=G>>V* z3ltR|A;XVBxyvyVT?GMt(eE*2c>?|_2eusb;{dtG$VC#NP&B(={~KaAQNI};rgfse zheX}e;Q<B?xNwI;;h<SJve~fv9e;HrYs4e~fm#lD8!tMTY{J2m@{nrl$gxxjH4I*G z;p0R{ZNa4fo2u{f3~#XsUs9yB#V`Cw1w#G9@9U_)4u?(o(>%KHZ_{}rH$fl5e+nid zm+lF}C0kd6Cs(~WDGyvgq#cMfsppi?Bk<7Ke9w{I4bemcu9}C0_XqSr+eS=Uk>NZF zI84G5i@mKlx!@3;J5-bG9g1ZeKBBAPBNDlcqld^x1jp@QM(?}oS80I49{LG!7>rTA zWgWFfY4y2U^SVuV;QsT}flngWfrUQF^x5DD^PlGqRX3}>X($A|+xRC--=b2eFk){y zM{+Gh<`qrXCF&Ctt_$9%P`OrO^6jo0ugyxsb_FvQ2qB~DtXfd^y%D+%k0=_t8Pq|C zv1Fsa<m`g8?6Uq2?FQPkuH1!oV7)lftgBwct@bKWMNp4JdXV|Ciby3i#kZSV`6kiF zklEK`UAczx&cG(r$OwKmb~4j<uD-z+TN)-p-W?i62cC#iBQt&NOKWi~6js0Csx#<> ztTn)i8py#(hNEjJecY9#k7?@egkd3`talQ5bQ$#2a`hzV=*U$``uHkz5(6`oNPS<` z(E(L-uoy9s8)V|bmL`)iA$Et>14-G4NMsJJ=z_ozfoD&W1)v;C6JRW3eT_$jdvEje z2n-;v7ltUHy(s39)@>OutLVkxYS}Ea8pPW7;7ZxJd$4O<L|vNdELd3Qr&*@n@jlsL zR4o*_Z~$p*4L{I0W7Uj}8@hUT56(`zyowc6g#no*D#Sdb2zE$prXUEWiMltnYmZWh z&?1Sy&Ohfp`o6zlN&i&%4&cF|HmkJEl8EH;u6y^;YKpe$Dq4TxoR(P1%QP`h@#}A5 zpQNz}L&ex8QEbtV7G-D}1p}4wxL$!XQChFYsBVYkkg);ve*(Hi)~4MQu2R{GN&$hs z6S*!~zvN8{f-Df3o}b@z6kvyk$3+SSKBzC7X^xOe!h}ysWv8_B$WDxs3QZ7VP~A?! z8<+{F-iAjbbO>g^1lq`2p=V<O3DLwa(13~k2KuD;K<wD?b}GLSv5ypn(TF7@5s6X8 zhhdAsrI8o`+L%d^7+8i9kk{4#b~OpRNE5JcPr)vd1nkKIfPE0UOV)y@17g2Hz<Wwt zO|}bkCN0a^`^?GZ<qh7$+MUEe7D6cOMNIZ)5r%mu*5$a4_4Th5O!AEN^-Yh9nckl6 zPe*iN@z`RDkbNx<E5v-**iCoAmTDyQB#zZvy#dYAA8noiW}A*v1SeMc#R!UBH`cAs zrjbU&{OWH;7;djggyHf5Y>sdOI1yj#xe(nWmdL^8_VABW`_Yku@ADksalk7dgty?% zQ3QSxa>OVgGT;DT+d`0=phx6)yHAcdVk~{P6ZL_sal~Y^3&JL)d>vM?rCeJ{#7O!J zO3&qK*Zyq|Je4<-fvCMgMj^lxS{5KWllX(8d}I^4TwjsYR|t_W@SdU-Trb(bLXM=? zJQvTnY{B!ze<LuB1>84~)xmNfhfeZ|Dnl={(&5$lD@Fa|ll9YDaBn*16ei1Rl9%Fb zNavZXXaKv#*o^boIfq3}KFh*pC<5!+4D;ap26nZ9{M>CM=H%QFs090TVv0aU=zUrj zU4dqs5G+7iqG`AIjuWc@i%t_E!5US-rC`MP$^l{*{LO88jYj$sW&%B?;-_=5&WV-U zQ`+_|WWL7P3;%(F?1e-4*5CRUSQjrisD&=vl;VcHuta>*4m9?{9PvF*e9sr(3&i(A z@x7S7VdUYHgHJX-<TfNrgglXA$(YqmXLVs#*TCxLvAX%JZUL)X$m$lex+NHF8{7Uc zDk0KKM_)kEx%k-e$<rsjjbK_h7bzU_LJ#h@)0pWm{0RtPFOdI^y+9#wB8Ix7Qd>pf z>+V+MES|1AaplQP)#ChO?+NxC^^`xfgT9TkdGnvs@xY#=q{x+go!F2PRA>t;drmy8 zqK0tXr@sQ$#6#2`pQe;o;8@@11PITGq;-T&>|!XxE(Z1-JzR|Z6ylA}$Ds8{r@E7N z4N2iEv53WI;6#J&cvPgI`|3^-eprnn0cDMzKoCO|yI%f^Yko8-sKh%VsCK3Vl}HkT zO58y?j*drDViXHxcI>62DEgiK1ms&IHh)Ri_c1xM!-#QOqyL7s1vqAagBF_?qDAba z$ts6KzV7ItvP!DabZu=GIR>x<rM>h#>PqUpv6t(;OCvj4j$EvWOk8e>3a?y|<Mcb_ zhSuXV6f)X26K1Vj+sgSt{V7m^Dpm~>upJ2IOCbF{3>{&Asyj(}O5ss}+g8qZ>(AgE zwLS~cm_JylpTHT8{86D#-iM3;bvn>@c)I>dc*o9<gf;pOp+RV0ZuAuXgMBnxr_LHZ z9bBZN@EG==boig%LYp+o7IexZ`oJHh=^qZR+bLEP(VI2oY1!&eE;R1z`GoK5`IsM+ z-@5m(guclF7wS&32{P+Ol2baXTwf1V_Ko#K$$rN^-h`jhv&;3<gkqxy#`*>mhDz^# zG7T;>g*pu5=b|<A-!p@DyoshnAgN+iABO-kY$7eWCN_>_fOXq9*;WW<g6$|`k?vt> zDdWhNvaf!YtT=kgfH-n5AE&Jqj!_WYf7QggmTD20z$z6CWfL|wl0RslwnKQi{aTbL zSN|*J10nS0lTg_75@8f5F&yHwTg`<tZd2h)|0VnI$u~qS6?QF6zi1{>KnKi3x?lsH z2(J1zGtsI(3_46<qY}0Ct|r1XhHo5zqgr6S{`bJLprT|QU=X$ag0`cG!b!@Li1<?y zY&l}VSwO%7(<tzmZx&(6z!2Lkf|3QzL6y5$RD{Wk-~?flA{NSF^cV|ZVnIxR+&c@z zfn6UO@u#+v!rQU^Lv6c&Bf<Dv{4-4x192Rr3-h)>ZGPM^ZGVX4d0@-(o_h}q1Gjk+ z8Mywk3d6SL@9SqE8u)KSCQ>|`R#U-2@)s*>2KgVLu}$G`t?>W<=cF`9kcXjrh|-fa ze22xJ?9}TZ8@INZtap73x&``kN#TIn{HPP1PiRqk6Dj8VlBT<O);5`h0l&sD;8VRk zqF+h9-0VO}U_FZfF)Co2)=+=dPZeXC7dq2cH{7~)i*VodUH|gemwDeLuST=s)o_w~ z#(~)Fx^#fuXDk?3V5Jzsovg7%I65k>{}Aj!6ZLA|(XI0yL>yxpsP07=Hk{P2dp=js zjjFrC(-Y7(RgyJWu5U&GtYyBZww;GHs}}=z@aP4!DA~IH)NJB@sy0d%t4Uy15L}Yf z1c9khGH*-<4H}e}q&LB#zyz(R*e7a2kqFT$pNUdf3_LNPoxuTqQ6jg<_nUT7MJvES zp-ldU{t=Xdx|15Vg+}nN^kO_yMPjkij9Fx~4bs3FuEH509T>N4Dg4Xy?9o`i$MRL( zG#>3jZJy{MeE*XiJ%Y=XoBxDwIoc-fU&D90<ifBV2F>Fn7MpeDPXP{!=U7+H!5vj> ziuNO)D)cad8~>~)u-Jk4x1_GVo#3^uya~BI=S+syK9J0<H(!#~ur27jOoZcYC&+j| z>?t#yXaFZh#zKlP4j?c+&Qy9Ez6q9=2}^hT@sPirLgmBX%ik{0b#?yse(*~8idK9} zeIskdUbq_ijRP-!XW|)(*O#9m6^3o6TqQN_!x@D6+sOzDoAaNc4Kd-L;A}L10D4^P zjKP5><!GL57v_@4$q($J{WH*WqvS*oIfG2p#m5G)L@f5vAWGtOrc$-m=6?Y!*e~Av z7_Lk-!Jnbc2NW<5zXi>VuGw??ZEZ7k8Ru^CF9CgBhG#c)kVSm}dv7^;n8M^|vH0=j z)aqOTP($7}+Mpb{4}$0*_P**_uO<@JwB1(xr~|YH6qRKm`OLHz$a*e=S<$?O%7kxA zl~JA@S_VhpQWpf^Nh}QQxIiZ&9jX3{LnrPkyzjC{NXxTFNC&Y;gmisGNa9C?Bwk6Q zR~cX{i3Wr0kyc#TBRlXNU->+~F)>KQR}vl4;IT)D7S}xTBEH!pM5*i%qEz+>8IoEH zX*g{qt*U50x4bGrw8B_=%8inSJ++JGf_=kM(b0)}nAqKR5A7LFqiOf2_po2;_pn=W zao~e(!D$HVj>LHj(TChZw2~ZVtWKP(AI)2c0`6hCQ)&7X51nj9tBUptNt>5fptUca z!2`sEv2Es=d)U8^g`mWR<fZnC1K%$fB=b3L9{O<0U=7G!15t?!DH`pS`S>0zG(R%* zp?<IsTS?N1tsD^F=f$^#*4Ro#e4E9$MSR=v&0A<6i{KIL!x25jZWFjsSCWC5Os{5- ztc3x`9@&6zdie;+Dz=ggKLqg8ehzgPaUD*+;&18G5p<w$qk~gci)G05)C5jzXRGJa zsI4XikgQqTMiU`zJ)wmnt$+C+C?)bI_kC*Xsq?(ETo2%tu?K{X(;2{FXy6;~32$44 z*f9w)PJ3{3v?XcU%!HWq_x#1zQ$J4J@`K{Rs<z4Mz%`)*eY97%PsaE|{?baQU2ZF5 zt7(=@OjV94#UE(e!Tvz=7kv?8)P1|>MjFt&@$i`E|3S!@;rdU|OMU;R|0i8tMY{N# zyZUpyVt?ot?b8HDoGC$(%Eq5@zEZJS94h3C*A3$XapUM&z-|Mt2K{CF$2jV2Vxt-7 zB*KY8JJ~OmSC2cn6--JIl$A7Jb^QvPdLeq?C84Q=lRc(W+m8thJVqD@XYx07H!T}> z>LV%s`5`g!dX8Y^tB9LnC|H2UY_^Jcny2}Nu*NwJz%P4DF!*DF!B-73_^Lq$e@rm= zV}ijS6Ab>CVDQI?!2@jFf8e4=>8PZ2qD8dhIe?$80K5~e=!O$#lwh7G(QzxzuL&f> zf6#QCb_k~ql4*7;cmg4P2BW&oB+iR7PKFKWPHKp@t1nPrB@{@Jxj2qu3Ku=|h~64- z{FA(jfW7h|0#+8?x$+_EN;$vM&sPzOVC0EIFYKwxchP}Kbg0{ted)XC0EUZ)TRipu z;MH2U1ufEm;Xs;yK;+5bHuym)yO0h(5T`4!RfixT;aBa9ucDc^kd_9v-oju(A!PD{ zz2`AtLwzc0UOIn>xTh{dY$@w7&L(MDMSS|l^i#cQt4QMgaTwi^1bmr}j98PITCWwN zzvrm$Q2iKjSiZO&EganA8$awD^$M(HsW1H%^n(Hb+F{-6wlzT$PFjh5;#gB6ubGv$ zCWzl7N&>|*qR`0V@M4_ZOGg>gF~oGfGaW;mVf=UtbT4$(kaTQKgQN$3ip_X|c_|f0 zPrOlE-BF7JkLgv?abcW)hYC=;anQ1n`3L-3I?8o}+K3Y`ricTxaRzZWPRl4~#SS_L zIXn)f=v-*j9X?W9BMu3s@NDC#!XXJ5uC`R%c0ju$=T#Tl$BB&e`!Z||4GddDJ0h4F z$AzkGW~?tpJ_fs**`4@rVZ+&-3cJI`?zDeBz8&Y&2KZ+|?LJ2(A25!ML`iZ&I{Bdq z-Rjvy_$r*qIr~BmfBTww7jjKwN7pE<@Inroejyh*UC8N9<-8F&H(kg9D9F48nPGSY z%%gE6V6#YNYekycXqWKgImNbU8}=^H*1;(_F+OZBFRL)l=K(@8TZw-A(h#15!^Z3F zmByLZ#$j+(@YEzJwv3ld#u|ngU^<~Gz;8<p@|(#)mRap&95d<bpb;LDSdd@q(3U!I zS`2>jBq`)l$GHmX7{Nyko?xxNK#Q4~`EwlMkvNZ#7hr3JI4=W^&057so@GID@<0vz zXiTkTE`F~K2c_V+)L}RnCt&m0!Z+cj0Oz`t3J*>OeuM>wA)=IxPT`26v-lA?!2|dS zxtR(|Vly2bvEo;7boZr2vC0qZ4K1sLU;Ekt)gmr0Zu}0GaV+)Z%g?DUh>S95&N!#K zsslP9^$T&S-C%zYKf@8@?3(b6aL5UVQAH(YQ%+DdT-GM5{I=&apnN!hR<P&e9T<q0 z93>z|3?!rAH)4dl7VI^d7(g5!j4>Y}+E?*&FxZ@x!Tn||P*&pb1pErf-UuB*Dnkxn zyCp^5<lmQDp>5f)1mYlE$fr&A$EOjw4W7pv9_?*AedHP(!g17s`2tmG^wGCFk}eE{ z%ieMjqB$ruO#!UmVhbWcNom>jGZ1lfYSEjho{z#bh}O~_FxK+nEMaLlL5A8Nq#S#a zf9HzcB-=*0sbmT`_;6Y*4AQSaKzk*B7(xs_09%S)<7d3u3fSVV9DH)wvt7hZxKQVC zdh-x;MIOz+FE2c*c5W+4&{R9vj6(zi0=41L4sqBOta*`*yrIc#+Oz__93qr(00h<2 zl!{P9`|mN+v;+Zf8BPwe1N**q;J%IQ855@fK*Xn!vryadYeK&6A&re4MiC1Fm2F`< z1{)Ps@bPr$4fziZp`t#36I^BX^E}XsJ$X(n4qxgl&}tkN$t)xmWOkn&&*BK`;ADOq z2~jaz<*X!^mE;iv4>_#Aq`+Wl9Ndq10W5cmP7G=@W4%eNmrjFU`RCY0=uP;wiUQ%( zeIQT&Jwo1nC+l6>3)C6NQ~fTX+pN()1L3p^+ga%QD%2Z20b9ln1WMLb<Oaq>2l@H6 zbQrwacwEvNk4GLf)UY=5KNjJ*{`0OT7(S!o#RF7|1U@V7kBl*hBMNu50}Y6t^-VDf zE=uP5GW-slvySpbQgESvnQ_>>J^}IF>T3?vk{KC0SV?ma>ZZ!};R@EGPz!>XrgZqh zi=SeuW9T7o0(-!&$I!Z(I@c298R9^EYx5Qqyx2|3z}G#G3}xb|{?yM1JVd{Gh+hx@ zdnc2kiTVj5xA=L1rp^t>Al8#Ih(vn;1WkTEi=MEqY9`pIV)07?O`TLd|0*?ODn1X+ zpJW`*?=?Es_jhDCqQg?(E+d7Cr_$o9o<apcp43}LQ@LU~WELGlHCCgV<l*Tl?Vf~X zGw=hA1FMCW<)`M+GA+#4%Lt}SQ`|UIxD41|B<a705~Az|=1t)YZyRmCOW{8$NiNxs z2k%Jo5cjYQE9A1Q9fLzXhDZmrj6?64N&Mu%*XkwEaQs#o2xE-f$UPgm)4n~oSkGE? zVWBw#M%;$~<uWb!Eg{DbiHnsDVV~YwG~nIs*NXZVJV~$E-Fm#pz+e%UHO4s64idoB zI1ri7=wHA_Qnsq(5j;53gD~I0MKQ`Hp1&!h!Gu6MOsI$q!+DXikUS5-ZeomtW`r$m zybq6BD6Jr46A&n=S1EmwD(}~iL1d|~DMO8LD(}}n1w|Ong1{o%B9k7YaqEXngRAsL zqltLNbq`-X1xM3{$Lrf(Ap4bcZD~ONca%k?h6@K(2gO-QmmDw#i#lCDjKBh%HV{qJ zMy?3x%PuR0Ml1}!^m)l)vgko-eQ`0ZEG<WAYx6$?flWUmXsproxL23ku(%Y(9bXE? ziQmM)TA@DSdGKx*c0!?IJpQ{Pr!3(&d=RbWN6ePO{RrHJ!GTCjCmoPjmW>~$ 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 diff --git a/distribution/windows/setup/prowlarr.iss b/distribution/windows/setup/prowlarr.iss index 1a1504ca2..a84dbab8b 100644 --- a/distribution/windows/setup/prowlarr.iss +++ b/distribution/windows/setup/prowlarr.iss @@ -3,13 +3,12 @@ #define AppName "Prowlarr" #define AppPublisher "Team Prowlarr" -#define AppURL "https://prowlarr.video/" -#define ForumsURL "https://forums.prowlarr.video/" +#define AppURL "https://prowlarr.com/" +#define ForumsURL "https://prowlarr.com/discord/" #define AppExeName "Prowlarr.exe" #define BaseVersion GetEnv('MAJORVERSION') #define BuildNumber GetEnv('MINORVERSION') #define BuildVersion GetEnv('PROWLARRVERSION') -#define BranchName GetEnv('BUILD_SOURCEBRANCHNAME') [Setup] ; NOTE: The value of AppId uniquely identifies this application. @@ -22,15 +21,15 @@ AppPublisher={#AppPublisher} AppPublisherURL={#AppURL} AppSupportURL={#ForumsURL} AppUpdatesURL={#AppURL} -DefaultDirName={commonappdata}\Prowlarr\bin +DefaultDirName={commonappdata}\Prowlarr DisableDirPage=yes DefaultGroupName={#AppName} DisableProgramGroupPage=yes -OutputBaseFilename=Prowlarr.{#BranchName}.{#BuildVersion}.windows.{#Framework} +OutputBaseFilename=Prowlarr.{#BuildVersion}.{#Runtime} SolidCompression=yes AppCopyright=Creative Commons 3.0 License AllowUNCPath=False -UninstallDisplayIcon={app}\Prowlarr.exe +UninstallDisplayIcon={app}\bin\Prowlarr.exe DisableReadyPage=True CompressionThreads=2 Compression=lzma2/normal @@ -38,6 +37,7 @@ AppContact={#ForumsURL} VersionInfoVersion={#BaseVersion}.{#BuildNumber} SetupLogging=yes OutputDir=output +WizardStyle=modern [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" @@ -48,28 +48,31 @@ Name: "windowsService"; Description: "Install Windows Service (Starts when the c Name: "startupShortcut"; Description: "Create shortcut in Startup folder (Starts when you log into Windows)"; GroupDescription: "Start automatically"; Flags: exclusive unchecked Name: "none"; Description: "Do not start automatically"; GroupDescription: "Start automatically"; Flags: exclusive unchecked +[Dirs] +Name: "{app}"; Permissions: users-modify + [Files] -Source: "..\..\..\_artifacts\{#Runtime}\{#Framework}\Prowlarr\Prowlarr.exe"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\..\..\_artifacts\{#Runtime}\{#Framework}\Prowlarr\*"; Excludes: "Prowlarr.Update"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +Source: "..\..\..\_artifacts\{#Runtime}\{#Framework}\Prowlarr\Prowlarr.exe"; DestDir: "{app}\bin"; Flags: ignoreversion +Source: "..\..\..\_artifacts\{#Runtime}\{#Framework}\Prowlarr\*"; Excludes: "Prowlarr.Update"; DestDir: "{app}\bin"; Flags: ignoreversion recursesubdirs createallsubdirs ; NOTE: Don't use "Flags: ignoreversion" on any shared system files [Icons] -Name: "{group}\{#AppName}"; Filename: "{app}\{#AppExeName}"; Parameters: "/icon" -Name: "{commondesktop}\{#AppName}"; Filename: "{app}\{#AppExeName}"; Parameters: "/icon"; Tasks: desktopIcon -Name: "{userstartup}\{#AppName}"; Filename: "{app}\Prowlarr.exe"; WorkingDir: "{app}"; Tasks: startupShortcut +Name: "{group}\{#AppName}"; Filename: "{app}\bin\{#AppExeName}"; Parameters: "/icon" +Name: "{commondesktop}\{#AppName}"; Filename: "{app}\bin\{#AppExeName}"; Parameters: "/icon"; Tasks: desktopIcon +Name: "{userstartup}\{#AppName}"; Filename: "{app}\bin\Prowlarr.exe"; WorkingDir: "{app}\bin"; Tasks: startupShortcut [InstallDelete] -Name: "{app}"; Type: filesandordirs +Name: "{app}\bin"; Type: filesandordirs [Run] -Filename: "{app}\Prowlarr.Console.exe"; StatusMsg: "Removing previous Windows Service"; Parameters: "/u /exitimmediately"; Flags: runhidden waituntilterminated; -Filename: "{app}\Prowlarr.Console.exe"; Description: "Enable Access from Other Devices"; StatusMsg: "Enabling Remote access"; Parameters: "/registerurl /exitimmediately"; Flags: postinstall runascurrentuser runhidden waituntilterminated; Tasks: startupShortcut none; -Filename: "{app}\Prowlarr.Console.exe"; StatusMsg: "Installing Windows Service"; Parameters: "/i /exitimmediately"; Flags: runhidden waituntilterminated; Tasks: windowsService -Filename: "{app}\Prowlarr.exe"; Description: "Open Prowlarr Web UI"; Flags: postinstall skipifsilent nowait; Tasks: windowsService; -Filename: "{app}\Prowlarr.exe"; Description: "Start Prowlarr"; Flags: postinstall skipifsilent nowait; Tasks: startupShortcut none; +Filename: "{app}\bin\Prowlarr.Console.exe"; StatusMsg: "Removing previous Windows Service"; Parameters: "/u /exitimmediately"; Flags: runhidden waituntilterminated; +Filename: "{app}\bin\Prowlarr.Console.exe"; Description: "Enable Access from Other Devices"; StatusMsg: "Enabling Remote access"; Parameters: "/registerurl /exitimmediately"; Flags: postinstall runascurrentuser runhidden waituntilterminated; Tasks: startupShortcut none; +Filename: "{app}\bin\Prowlarr.Console.exe"; StatusMsg: "Installing Windows Service"; Parameters: "/i /exitimmediately"; Flags: runhidden waituntilterminated; Tasks: windowsService +Filename: "{app}\bin\Prowlarr.exe"; Description: "Open Prowlarr Web UI"; Flags: postinstall skipifsilent nowait; Tasks: windowsService; +Filename: "{app}\bin\Prowlarr.exe"; Description: "Start Prowlarr"; Flags: postinstall skipifsilent nowait; Tasks: startupShortcut none; [UninstallRun] -Filename: "{app}\prowlarr.console.exe"; Parameters: "/u"; Flags: waituntilterminated skipifdoesntexist +Filename: "{app}\bin\prowlarr.console.exe"; Parameters: "/u"; Flags: waituntilterminated skipifdoesntexist [Code] function PrepareToInstall(var NeedsRestart: Boolean): String; From 83ca724120bd8203637a53b4e6382af13f2f3cab Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 8 Mar 2022 20:39:20 -0600 Subject: [PATCH 0382/2320] Fixed: (Redacted) Map Categories Comedy & E-Learning Videos to 'Other' indexer does not actually have movies and tv --- src/NzbDrone.Core/Indexers/Definitions/Redacted.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs b/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs index 4aef85308..bc6e8a7fd 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs @@ -73,8 +73,8 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.PC, "Applications"); caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.BooksEBook, "E-Books"); caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.AudioAudiobook, "Audiobooks"); - caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.MoviesOther, "E-Learning Videos"); - caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.TVOther, "Comedy"); + caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Other, "E-Learning Videos"); + caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.Other, "Comedy"); caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.BooksComics, "Comics"); return caps; From 75792c0760fa817ceccfd9dd32c2e54473e7f024 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 22 Feb 2022 10:39:03 -0600 Subject: [PATCH 0383/2320] Fixed: (Anthelion) Replace Periods for Space in Search Term based on jackett 22efff93e7f1df858b341b3c2756d8204cae6f4a --- src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs b/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs index e4d2597fe..28e195e8c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs @@ -148,7 +148,7 @@ namespace NzbDrone.Core.Indexers.Definitions { "order_way", "desc" }, { "action", "basic" }, { "searchsubmit", "1" }, - { "searchstr", imdbId.IsNotNullOrWhiteSpace() ? imdbId : term } + { "searchstr", imdbId.IsNotNullOrWhiteSpace() ? imdbId : term.Replace(".", " ") } }; var catList = Capabilities.Categories.MapTorznabCapsToTrackers(categories); From a0cbe1de5d309bf8ff746d607b73d308f6f74fba Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 22 Feb 2022 10:41:37 -0600 Subject: [PATCH 0384/2320] Fixed: (HDSpace) Replace Periods for Space in Search Term based on jackett 22efff93e7f1df858b341b3c2756d8204cae6f4a --- src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs b/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs index 9bae17112..8dead0def 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs @@ -171,7 +171,7 @@ namespace NzbDrone.Core.Indexers.Definitions else { queryCollection.Add("options", "0"); - queryCollection.Add("search", term); + queryCollection.Add("search", term.Replace(".", " ")); } searchUrl += queryCollection.GetQueryString(); From 01cc9b3d073b0e4f5c332799ae7730ffdd13a4ca Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 22 Feb 2022 10:44:56 -0600 Subject: [PATCH 0385/2320] Fixed: (Gazelle) Replace Periods for Space in Search Term based on Jackett b8b816f953ad9d0508f95a9c31f9ff4385ebdd73 --- .../Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs index 3a1e5361d..67ad1987d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs @@ -53,7 +53,7 @@ namespace NzbDrone.Core.Indexers.Gazelle if (!string.IsNullOrWhiteSpace(searchString)) { - parameters += string.Format("&searchstr={0}", searchString); + parameters += string.Format("&searchstr={0}", searchString.Replace(".", " ")); } if (categories != null) From 8834431ba63f64520b3e9bd72205ae841b81e4c7 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Thu, 24 Mar 2022 06:11:30 +0000 Subject: [PATCH 0386/2320] Translated using Weblate (Spanish) Currently translated at 77.5% (332 of 428 strings) Co-authored-by: RicardoVelaC <ricardovelac@gmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/es.json | 23 ++++++++++++--------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/es.json b/src/NzbDrone.Core/Localization/Core/es.json index 05f4eaded..8abe1ca42 100644 --- a/src/NzbDrone.Core/Localization/Core/es.json +++ b/src/NzbDrone.Core/Localization/Core/es.json @@ -1,5 +1,5 @@ { - "Indexers": "Indexers", + "Indexers": "Indexadores", "Host": "Host", "History": "Historia", "HideAdvanced": "Ocultar Avanzado", @@ -22,7 +22,7 @@ "Clear": "Borrar", "BackupNow": "Hacer copia de seguridad", "Backup": "Backup", - "AppDataLocationHealthCheckMessage": "No será posible actualizar para prevenir que AppData se borre durante la actualización", + "AppDataLocationHealthCheckMessage": "La actualización no será posible para evitar que se elimine AppData durante la actualización", "Analytics": "Analíticas", "All": "Todas", "About": "Acerca", @@ -73,7 +73,7 @@ "Protocol": "Protocolo", "LastWriteTime": "Última Fecha de Escritura", "IndexerStatusCheckSingleClientMessage": "Indexers no disponibles debido a errores: {0}", - "Indexer": "Indexer", + "Indexer": "Indexador", "Grabbed": "Capturado", "GeneralSettingsSummary": "Puerto, SSL, nombre de usuario/contraseña , proxy, analíticas y actualizaciones", "Filename": "Nombre del archivo", @@ -93,11 +93,11 @@ "TableOptions": "Opciones de Tabla", "Source": "Origen", "Shutdown": "Apagar", - "Seeders": "Seeders", + "Seeders": "Semillas", "Save": "Guardar", "Restart": "Reiniciar", "Reload": "Recargar", - "Peers": "Peers", + "Peers": "Pares", "PageSize": "Tamaño de Página", "Ok": "Ok", "OAuthPopupMessage": "Pop-ups bloqueados por su navegador", @@ -150,7 +150,7 @@ "BypassProxyForLocalAddresses": "Omitir Proxy para Direcciones Locales", "Branch": "Rama", "BindAddressHelpText": "Dirección IP4 válida o '*' para todas las interfaces", - "Backups": "Backups", + "Backups": "Copias de seguridad", "BackupRetentionHelpText": "Backups automáticos anteriores al período de retención serán borrados automáticamente", "BackupIntervalHelpText": "Intervalo entre backups automáticos", "BackupFolderHelpText": "Las rutas relativas estarán en el directorio AppData de Prowlarr", @@ -162,7 +162,7 @@ "ApplyTags": "Aplicar Etiquetas", "AppDataDirectory": "Directorio de AppData", "AnalyticsEnabledHelpText": "Envíe información anónima de uso y error a los servidores de Prowlarr. Esto incluye información sobre su navegador, qué páginas de Prowlarr WebUI utiliza, informes de errores, así como el sistema operativo y la versión en tiempo de ejecución. Usaremos esta información para priorizar funciones y correcciones de errores.", - "YesCancel": "Si, Cancela", + "YesCancel": "Si, cancelar", "Version": "Versión", "Username": "Nombre de usuario", "UseProxy": "Usar el Proxy", @@ -294,7 +294,7 @@ "MovieIndexScrollTop": "Indice de Películas: Desplazar hacia arriba", "MovieIndexScrollBottom": "Indice de Películas: Desplazar hacia abajo", "CloseCurrentModal": "Cerrar Modal Actual", - "AcceptConfirmationModal": "Aceptar el Modal de Confirmación", + "AcceptConfirmationModal": "Aceptar la confirmación modal", "IndexerLongTermStatusCheckSingleClientMessage": "Indexers no disponible por errores durando más de 6 horas: {0}", "IndexerLongTermStatusCheckAllClientMessage": "Ningún indexer está disponible por errores durando más de 6 horas", "PrioritySettings": "Prioridad", @@ -329,10 +329,13 @@ "FeatureRequests": "Peticiones de características", "HomePage": "Página de inicio", "UnableToAddANewApplicationPleaseTryAgain": "No se ha podido añadir una nueva notificación, prueba otra vez.", - "Filters": "Filtro", + "Filters": "Filtros", "HistoryCleanupDaysHelpText": "Ajustar a 0 para desactivar la limpieza automática", "HistoryCleanupDaysHelpTextWarning": "Los archivos en la papelera de reciclaje más antiguos que el número de días seleccionado serán limpiados automáticamente", "OnGrab": "Al Capturar", "OnHealthIssue": "En Problema de Salud", - "TestAllIndexers": "Comprobar Todos los Indexers" + "TestAllIndexers": "Comprobar Todos los Indexers", + "NotificationTriggersHelpText": "Seleccione qué eventos deben activar esta notificación", + "OnApplicationUpdate": "Al actualizar la aplicación", + "OnApplicationUpdateHelpText": "Al actualizar la aplicación" } From 22f9e9e6b7c82729b0fdc445441db862cbdc1d47 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 24 Mar 2022 19:09:42 -0500 Subject: [PATCH 0387/2320] Bump dotnet to 6.0.3 --- azure-pipelines.yml | 2 +- package.json | 2 +- src/Directory.Build.props | 2 +- src/NzbDrone.Core/Prowlarr.Core.csproj | 2 +- .../Prowlarr.Integration.Test.csproj | 2 +- yarn.lock | 8 ++++---- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0f73dec09..17a3c273d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -13,7 +13,7 @@ variables: buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' sentryOrg: 'servarr' sentryUrl: 'https://sentry.servarr.com' - dotnetVersion: '6.0.100' + dotnetVersion: '6.0.201' innoVersion: '6.2.0' yarnCacheFolder: $(Pipeline.Workspace)/.yarn diff --git a/package.json b/package.json index 23ff8ebf4..c2caa2dc8 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "@fortawesome/free-regular-svg-icons": "5.15.3", "@fortawesome/free-solid-svg-icons": "5.15.3", "@fortawesome/react-fontawesome": "0.1.14", - "@microsoft/signalr": "6.0.0", + "@microsoft/signalr": "6.0.3", "@sentry/browser": "6.15.0", "@sentry/integrations": "6.15.0", "chart.js": "3.2.0", diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 88e435bda..6c75715d4 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -94,7 +94,7 @@ <!-- Standard testing packages --> <ItemGroup Condition="'$(TestProject)'=='true'"> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> <PackageReference Include="NUnit" Version="3.13.1" /> <PackageReference Include="NUnit3TestAdapter" Version="3.17.0" /> <PackageReference Include="NunitXml.TestLogger" Version="3.0.97" /> diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index 99a4adc4d..455437041 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -20,7 +20,7 @@ <PackageReference Include="TinyTwitter" Version="1.1.2" /> <PackageReference Include="Kveer.XmlRPC" Version="1.1.1" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> - <PackageReference Include="System.Text.Json" Version="6.0.0" /> + <PackageReference Include="System.Text.Json" Version="6.0.2" /> <PackageReference Include="MonoTorrent" Version="1.0.29" /> <PackageReference Include="YamlDotNet" Version="11.2.1" /> <PackageReference Include="AngleSharp" Version="0.16.0" /> diff --git a/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj b/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj index ea2df08de..06267ddc9 100644 --- a/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj +++ b/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj @@ -4,7 +4,7 @@ <OutputType>Library</OutputType> </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.0" /> + <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.3" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" /> diff --git a/yarn.lock b/yarn.lock index c14096c64..8bc38fa15 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1079,10 +1079,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== -"@microsoft/signalr@6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-6.0.0.tgz#cb9cb166d8ee0522547e13c100a0992a1f027ce1" - integrity sha512-Y38bG/i9V1fOfOLcfTl2+OqPH7+0A7DgojJ7YILgfQ0vGGmnZwdCtrzCvSsRIzKTIrB/ZSQ3n4BA5VOO+MFkrA== +"@microsoft/signalr@6.0.3": + version "6.0.3" + resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-6.0.3.tgz#9904efd48cd488e3c1c80930ff9fbb3c9f55895d" + integrity sha512-wWGVC2xi8OxNjyir8iQWuyxWHy3Dkakk2Q3VreCE7pDzFAgZ4pId6abJlRPMVIQxkUvUGc8knMW5l3sv2bJ/yw== dependencies: abort-controller "^3.0.0" eventsource "^1.0.7" From 31e7a101ef1b7296acaa1f15eb7e635957a8802f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 24 Mar 2022 19:35:31 -0500 Subject: [PATCH 0388/2320] Backend Package Updates --- src/Directory.Build.props | 6 +++--- src/NzbDrone.Automation.Test/AutomationTest.cs | 2 +- .../PageModel/PageBase.cs | 5 ++--- .../Prowlarr.Automation.Test.csproj | 4 ++-- src/NzbDrone.Common/Prowlarr.Common.csproj | 10 +++++----- .../Prowlarr.Core.Test.csproj | 2 +- src/NzbDrone.Core/Prowlarr.Core.csproj | 18 +++++++++--------- src/NzbDrone.Host/Prowlarr.Host.csproj | 4 ++-- .../Prowlarr.Test.Common.csproj | 10 +++++----- src/NzbDrone.Update/Prowlarr.Update.csproj | 4 ++-- src/NzbDrone.Windows/Prowlarr.Windows.csproj | 2 +- src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj | 2 +- src/Prowlarr.Http/Prowlarr.Http.csproj | 2 +- 13 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 6c75715d4..c675f8dc2 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -95,9 +95,9 @@ <!-- Standard testing packages --> <ItemGroup Condition="'$(TestProject)'=='true'"> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> - <PackageReference Include="NUnit" Version="3.13.1" /> - <PackageReference Include="NUnit3TestAdapter" Version="3.17.0" /> - <PackageReference Include="NunitXml.TestLogger" Version="3.0.97" /> + <PackageReference Include="NUnit" Version="3.13.3" /> + <PackageReference Include="NUnit3TestAdapter" Version="4.2.1" /> + <PackageReference Include="NunitXml.TestLogger" Version="3.0.117" /> <PackageReference Include="coverlet.collector" Version="3.0.4-preview.27.ge7cb7c3b40" /> </ItemGroup> diff --git a/src/NzbDrone.Automation.Test/AutomationTest.cs b/src/NzbDrone.Automation.Test/AutomationTest.cs index 6e8d717a1..638b1aaf5 100644 --- a/src/NzbDrone.Automation.Test/AutomationTest.cs +++ b/src/NzbDrone.Automation.Test/AutomationTest.cs @@ -20,7 +20,7 @@ namespace NzbDrone.Automation.Test public abstract class AutomationTest { private NzbDroneRunner _runner; - protected RemoteWebDriver driver; + protected WebDriver driver; public AutomationTest() { diff --git a/src/NzbDrone.Automation.Test/PageModel/PageBase.cs b/src/NzbDrone.Automation.Test/PageModel/PageBase.cs index f4eb98180..4c9a17581 100644 --- a/src/NzbDrone.Automation.Test/PageModel/PageBase.cs +++ b/src/NzbDrone.Automation.Test/PageModel/PageBase.cs @@ -1,16 +1,15 @@ using System; using System.Threading; using OpenQA.Selenium; -using OpenQA.Selenium.Remote; using OpenQA.Selenium.Support.UI; namespace NzbDrone.Automation.Test.PageModel { public class PageBase { - private readonly RemoteWebDriver _driver; + private readonly WebDriver _driver; - public PageBase(RemoteWebDriver driver) + public PageBase(WebDriver driver) { _driver = driver; driver.Manage().Window.Maximize(); diff --git a/src/NzbDrone.Automation.Test/Prowlarr.Automation.Test.csproj b/src/NzbDrone.Automation.Test/Prowlarr.Automation.Test.csproj index fcaa91554..bb0b5fcc4 100644 --- a/src/NzbDrone.Automation.Test/Prowlarr.Automation.Test.csproj +++ b/src/NzbDrone.Automation.Test/Prowlarr.Automation.Test.csproj @@ -3,8 +3,8 @@ <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> - <PackageReference Include="Selenium.Support" Version="3.141.0" /> - <PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="90.0.4430.2400" /> + <PackageReference Include="Selenium.Support" Version="4.1.0" /> + <PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="99.0.4844.5100" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" /> diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index 9870908de..e54678861 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -4,13 +4,13 @@ <DefineConstants Condition="'$(RuntimeIdentifier)' == 'linux-musl-x64' or '$(RuntimeIdentifier)' == 'linux-musl-arm64'">ISMUSL</DefineConstants> </PropertyGroup> <ItemGroup> - <PackageReference Include="DryIoc.dll" Version="4.8.1" /> + <PackageReference Include="DryIoc.dll" Version="4.8.8" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" /> - <PackageReference Include="NLog.Extensions.Logging" Version="1.7.2" /> + <PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> - <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> - <PackageReference Include="NLog" Version="4.7.9" /> - <PackageReference Include="Sentry" Version="3.8.3" /> + <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> + <PackageReference Include="NLog" Version="4.7.14" /> + <PackageReference Include="Sentry" Version="3.15.0" /> <PackageReference Include="SharpZipLib" Version="1.3.3" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> diff --git a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj index f00d67248..50edb2d4c 100644 --- a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj @@ -3,7 +3,7 @@ <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> - <PackageReference Include="Dapper" Version="2.0.90" /> + <PackageReference Include="Dapper" Version="2.0.123" /> <PackageReference Include="NBuilder" Version="6.1.0" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> <PackageReference Include="YamlDotNet" Version="11.2.1" /> diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index 455437041..ad20d2f50 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -4,26 +4,26 @@ </PropertyGroup> <ItemGroup> <PackageReference Include="AngleSharp.Xml" Version="0.16.0" /> - <PackageReference Include="Dapper" Version="2.0.90" /> - <PackageReference Include="FluentMigrator.Runner" Version="3.3.1" /> - <PackageReference Include="MailKit" Version="2.14.0" /> + <PackageReference Include="Dapper" Version="2.0.123" /> + <PackageReference Include="FluentMigrator.Runner" Version="3.3.2" /> + <PackageReference Include="MailKit" Version="3.1.1" /> <PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" /> - <PackageReference Include="NLog.Targets.Syslog" Version="6.0.2" /> + <PackageReference Include="NLog.Targets.Syslog" Version="6.0.3" /> <PackageReference Include="Npgsql" Version="5.0.11" /> <PackageReference Include="System.Memory" Version="4.5.4" /> <PackageReference Include="System.ServiceModel.Syndication" Version="6.0.0" /> - <PackageReference Include="FluentMigrator.Runner.SQLite" Version="3.3.1" /> - <PackageReference Include="FluentMigrator.Runner.Postgres" Version="3.3.1" /> + <PackageReference Include="FluentMigrator.Runner.SQLite" Version="3.3.2" /> + <PackageReference Include="FluentMigrator.Runner.Postgres" Version="3.3.2" /> <PackageReference Include="FluentValidation" Version="8.6.2" /> - <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> - <PackageReference Include="NLog" Version="4.7.9" /> + <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> + <PackageReference Include="NLog" Version="4.7.14" /> <PackageReference Include="TinyTwitter" Version="1.1.2" /> <PackageReference Include="Kveer.XmlRPC" Version="1.1.1" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> <PackageReference Include="System.Text.Json" Version="6.0.2" /> <PackageReference Include="MonoTorrent" Version="1.0.29" /> <PackageReference Include="YamlDotNet" Version="11.2.1" /> - <PackageReference Include="AngleSharp" Version="0.16.0" /> + <PackageReference Include="AngleSharp" Version="0.16.1" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Common\Prowlarr.Common.csproj" /> diff --git a/src/NzbDrone.Host/Prowlarr.Host.csproj b/src/NzbDrone.Host/Prowlarr.Host.csproj index 1e8956696..331a241d0 100644 --- a/src/NzbDrone.Host/Prowlarr.Host.csproj +++ b/src/NzbDrone.Host/Prowlarr.Host.csproj @@ -4,11 +4,11 @@ <OutputType>Library</OutputType> </PropertyGroup> <ItemGroup> - <PackageReference Include="NLog.Extensions.Logging" Version="1.7.2" /> + <PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.3.0" /> - <PackageReference Include="DryIoc.dll" Version="4.8.1" /> + <PackageReference Include="DryIoc.dll" Version="4.8.8" /> <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="5.1.0" /> </ItemGroup> <ItemGroup> diff --git a/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj b/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj index bff730d28..753dc63cb 100644 --- a/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj +++ b/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj @@ -5,11 +5,11 @@ <ItemGroup> <PackageReference Include="FluentAssertions" Version="5.10.3" /> <PackageReference Include="FluentValidation" Version="8.6.2" /> - <PackageReference Include="Moq" Version="4.16.1" /> - <PackageReference Include="NLog" Version="4.7.9" /> - <PackageReference Include="NUnit" Version="3.13.1" /> - <PackageReference Include="RestSharp" Version="106.12.0" /> - <PackageReference Include="RestSharp.Serializers.SystemTextJson" Version="106.12.0" /> + <PackageReference Include="Moq" Version="4.17.2" /> + <PackageReference Include="NLog" Version="4.7.14" /> + <PackageReference Include="NUnit" Version="3.13.3" /> + <PackageReference Include="RestSharp" Version="106.15.0" /> + <PackageReference Include="RestSharp.Serializers.SystemTextJson" Version="106.15.0" /> <PackageReference Include="Unity" Version="5.11.10" /> </ItemGroup> <ItemGroup> diff --git a/src/NzbDrone.Update/Prowlarr.Update.csproj b/src/NzbDrone.Update/Prowlarr.Update.csproj index aebe9ea33..a75badc8e 100644 --- a/src/NzbDrone.Update/Prowlarr.Update.csproj +++ b/src/NzbDrone.Update/Prowlarr.Update.csproj @@ -4,9 +4,9 @@ <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> - <PackageReference Include="DryIoc.dll" Version="4.8.1" /> + <PackageReference Include="DryIoc.dll" Version="4.8.8" /> <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="5.1.0" /> - <PackageReference Include="NLog" Version="4.7.9" /> + <PackageReference Include="NLog" Version="4.7.14" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Common\Prowlarr.Common.csproj" /> diff --git a/src/NzbDrone.Windows/Prowlarr.Windows.csproj b/src/NzbDrone.Windows/Prowlarr.Windows.csproj index 449211184..794c0fc9c 100644 --- a/src/NzbDrone.Windows/Prowlarr.Windows.csproj +++ b/src/NzbDrone.Windows/Prowlarr.Windows.csproj @@ -3,7 +3,7 @@ <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> - <PackageReference Include="NLog" Version="4.7.9" /> + <PackageReference Include="NLog" Version="4.7.14" /> <PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" /> </ItemGroup> <ItemGroup> diff --git a/src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj b/src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj index df70ed8b9..c1c33aa86 100644 --- a/src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj +++ b/src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj @@ -4,7 +4,7 @@ </PropertyGroup> <ItemGroup> <PackageReference Include="FluentValidation" Version="8.6.2" /> - <PackageReference Include="NLog" Version="4.7.9" /> + <PackageReference Include="NLog" Version="4.7.14" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Core\Prowlarr.Core.csproj" /> diff --git a/src/Prowlarr.Http/Prowlarr.Http.csproj b/src/Prowlarr.Http/Prowlarr.Http.csproj index a7d87cb78..d5d25faea 100644 --- a/src/Prowlarr.Http/Prowlarr.Http.csproj +++ b/src/Prowlarr.Http/Prowlarr.Http.csproj @@ -5,7 +5,7 @@ <ItemGroup> <PackageReference Include="FluentValidation" Version="8.6.2" /> <PackageReference Include="ImpromptuInterface" Version="7.0.1" /> - <PackageReference Include="NLog" Version="4.7.9" /> + <PackageReference Include="NLog" Version="4.7.14" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Core\Prowlarr.Core.csproj" /> From fa41bf3c5870fb592190bc31abfce8ae5de6a522 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 24 Mar 2022 19:53:49 -0500 Subject: [PATCH 0389/2320] Frontend Package Updates --- azure-pipelines.yml | 5 +- frontend/src/Components/Modal/ModalError.js | 3 +- .../Components/Scroller/OverlayScroller.js | 2 +- package.json | 64 +- yarn.lock | 2595 ++++++++--------- 5 files changed, 1329 insertions(+), 1340 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 17a3c273d..dc11bc975 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,6 +15,7 @@ variables: sentryUrl: 'https://sentry.servarr.com' dotnetVersion: '6.0.201' innoVersion: '6.2.0' + nodeVersion: '16.x' yarnCacheFolder: $(Pipeline.Workspace)/.yarn trigger: @@ -156,7 +157,7 @@ stages: - task: NodeTool@0 displayName: Set Node.js version inputs: - versionSpec: '12.x' + versionSpec: $(nodeVersion) - checkout: self submodules: true fetchDepth: 1 @@ -803,7 +804,7 @@ stages: - task: NodeTool@0 displayName: Set Node.js version inputs: - versionSpec: '12.x' + versionSpec: $(nodeVersion) - checkout: self submodules: true fetchDepth: 1 diff --git a/frontend/src/Components/Modal/ModalError.js b/frontend/src/Components/Modal/ModalError.js index daf39bac4..2c982519c 100644 --- a/frontend/src/Components/Modal/ModalError.js +++ b/frontend/src/Components/Modal/ModalError.js @@ -37,7 +37,8 @@ function ModalError(props) { {translate('Close')} </Button> </ModalFooter> - </ModalContent>); + </ModalContent> + ); } ModalError.propTypes = { diff --git a/frontend/src/Components/Scroller/OverlayScroller.js b/frontend/src/Components/Scroller/OverlayScroller.js index 6a7fa1701..50150bce0 100644 --- a/frontend/src/Components/Scroller/OverlayScroller.js +++ b/frontend/src/Components/Scroller/OverlayScroller.js @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; -import { Scrollbars } from 'react-custom-scrollbars'; +import { Scrollbars } from 'react-custom-scrollbars-2'; import { scrollDirections } from 'Helpers/Props'; import styles from './OverlayScroller.css'; diff --git a/package.json b/package.json index c2caa2dc8..a4de67eab 100644 --- a/package.json +++ b/package.json @@ -25,17 +25,17 @@ "not chrome < 60" ], "dependencies": { - "@fortawesome/fontawesome-free": "5.15.3", - "@fortawesome/fontawesome-svg-core": "1.2.35", - "@fortawesome/free-regular-svg-icons": "5.15.3", - "@fortawesome/free-solid-svg-icons": "5.15.3", - "@fortawesome/react-fontawesome": "0.1.14", + "@fortawesome/fontawesome-free": "6.1.1", + "@fortawesome/fontawesome-svg-core": "6.1.1", + "@fortawesome/free-regular-svg-icons": "6.1.1", + "@fortawesome/free-solid-svg-icons": "6.1.1", + "@fortawesome/react-fontawesome": "0.1.18", "@microsoft/signalr": "6.0.3", - "@sentry/browser": "6.15.0", - "@sentry/integrations": "6.15.0", - "chart.js": "3.2.0", + "@sentry/browser": "6.19.2", + "@sentry/integrations": "6.19.2", + "chart.js": "3.7.1", "classnames": "2.3.1", - "clipboard": "2.0.8", + "clipboard": "2.0.10", "connected-react-router": "6.9.1", "element-class": "0.2.2", "filesize": "6.3.0", @@ -48,13 +48,13 @@ "moment": "2.29.1", "mousetrap": "1.6.5", "normalize.css": "8.0.1", - "prop-types": "15.7.2", - "qs": "6.10.1", + "prop-types": "15.8.1", + "qs": "6.10.3", "react": "17.0.2", "react-addons-shallow-compare": "15.6.3", "react-async-script": "1.2.0", "react-autosuggest": "10.1.0", - "react-custom-scrollbars": "4.2.1", + "react-custom-scrollbars-2": "4.4.0", "react-dnd": "14.0.4", "react-dnd-html5-backend": "14.0.2", "react-dnd-multi-backend": "6.0.2", @@ -78,32 +78,32 @@ "reselect": "4.0.0" }, "devDependencies": { - "@babel/core": "7.16.0", - "@babel/eslint-parser": "7.16.3", - "@babel/plugin-proposal-class-properties": "7.16.0", - "@babel/plugin-proposal-decorators": "7.16.4", - "@babel/plugin-proposal-export-default-from": "7.16.0", - "@babel/plugin-proposal-export-namespace-from": "7.16.0", - "@babel/plugin-proposal-function-sent": "7.16.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "7.16.0", - "@babel/plugin-proposal-numeric-separator": "7.16.0", - "@babel/plugin-proposal-optional-chaining": "7.16.0", - "@babel/plugin-proposal-throw-expressions": "7.16.0", + "@babel/core": "7.17.8", + "@babel/eslint-parser": "7.17.0", + "@babel/plugin-proposal-class-properties": "7.16.7", + "@babel/plugin-proposal-decorators": "7.17.8", + "@babel/plugin-proposal-export-default-from": "7.16.7", + "@babel/plugin-proposal-export-namespace-from": "7.16.7", + "@babel/plugin-proposal-function-sent": "7.16.7", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.16.7", + "@babel/plugin-proposal-numeric-separator": "7.16.7", + "@babel/plugin-proposal-optional-chaining": "7.16.7", + "@babel/plugin-proposal-throw-expressions": "7.16.7", "@babel/plugin-syntax-dynamic-import": "7.8.3", - "@babel/preset-env": "7.16.4", - "@babel/preset-react": "7.16.0", + "@babel/preset-env": "7.16.11", + "@babel/preset-react": "7.16.7", "autoprefixer": "10.2.5", - "babel-loader": "8.2.3", + "babel-loader": "8.2.4", "babel-plugin-inline-classnames": "2.0.1", "babel-plugin-transform-react-remove-prop-types": "0.4.24", - "core-js": "3.11.0", + "core-js": "3.21.1", "css-loader": "6.5.1", - "eslint": "8.3.0", + "eslint": "8.11.0", "eslint-plugin-filenames": "1.3.2", - "eslint-plugin-import": "2.25.3", - "eslint-plugin-react": "7.27.1", + "eslint-plugin-import": "2.25.4", + "eslint-plugin-react": "7.29.4", "eslint-plugin-simple-import-sort": "7.0.0", - "esprint": "3.1.0", + "esprint": "3.3.0", "file-loader": "6.2.0", "filemanager-webpack-plugin": "6.1.7", "html-webpack-plugin": "5.5.0", @@ -121,7 +121,7 @@ "run-sequence": "2.2.1", "streamqueue": "1.1.2", "style-loader": "3.3.1", - "stylelint": "14.1.0", + "stylelint": "14.6.0", "stylelint-order": "5.0.0", "url-loader": "4.1.1", "webpack": "5.64.2", diff --git a/yarn.lock b/yarn.lock index 8bc38fa15..027a4fb09 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,106 +2,114 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" - integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA== +"@ampproject/remapping@^2.1.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34" + integrity sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg== dependencies: - "@babel/highlight" "^7.16.0" + "@jridgewell/trace-mapping" "^0.3.0" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.0", "@babel/compat-data@^7.16.4": - version "7.16.4" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e" - integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q== - -"@babel/core@7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.0.tgz#c4ff44046f5fe310525cc9eb4ef5147f0c5374d4" - integrity sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== dependencies: - "@babel/code-frame" "^7.16.0" - "@babel/generator" "^7.16.0" - "@babel/helper-compilation-targets" "^7.16.0" - "@babel/helper-module-transforms" "^7.16.0" - "@babel/helpers" "^7.16.0" - "@babel/parser" "^7.16.0" - "@babel/template" "^7.16.0" - "@babel/traverse" "^7.16.0" - "@babel/types" "^7.16.0" + "@babel/highlight" "^7.16.7" + +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.8", "@babel/compat-data@^7.17.0", "@babel/compat-data@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" + integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ== + +"@babel/core@7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a" + integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.7" + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helpers" "^7.17.8" + "@babel/parser" "^7.17.8" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.1.2" semver "^6.3.0" - source-map "^0.5.0" -"@babel/eslint-parser@7.16.3": - version "7.16.3" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.16.3.tgz#2a6b1702f3f5aea48e00cea5a5bcc241c437e459" - integrity sha512-iB4ElZT0jAt7PKVaeVulOECdGe6UnmA/O0P9jlF5g5GBOwDVbna8AXhHRu4s27xQf6OkveyA8iTDv1jHdDejgQ== +"@babel/eslint-parser@7.17.0": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz#eabb24ad9f0afa80e5849f8240d0e5facc2d90d6" + integrity sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA== dependencies: eslint-scope "^5.1.1" eslint-visitor-keys "^2.1.0" semver "^6.3.0" -"@babel/generator@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2" - integrity sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew== +"@babel/generator@^7.17.3", "@babel/generator@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" + integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== dependencies: - "@babel/types" "^7.16.0" + "@babel/types" "^7.17.0" jsesc "^2.5.1" source-map "^0.5.0" -"@babel/helper-annotate-as-pure@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz#9a1f0ebcda53d9a2d00108c4ceace6a5d5f1f08d" - integrity sha512-ItmYF9vR4zA8cByDocY05o0LGUkp1zhbTQOH1NFyl5xXEqlTJQCEJjieriw+aFpxo16swMxUnUiKS7a/r4vtHg== +"@babel/helper-annotate-as-pure@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" + integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== dependencies: - "@babel/types" "^7.16.0" + "@babel/types" "^7.16.7" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.0.tgz#f1a686b92da794020c26582eb852e9accd0d7882" - integrity sha512-9KuleLT0e77wFUku6TUkqZzCEymBdtuQQ27MhEKzf9UOOJu3cYj98kyaDAzxpC7lV6DGiZFuC8XqDsq8/Kl6aQ== +"@babel/helper-builder-binary-assignment-operator-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz#38d138561ea207f0f69eb1626a418e4f7e6a580b" + integrity sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA== dependencies: - "@babel/helper-explode-assignable-expression" "^7.16.0" - "@babel/types" "^7.16.0" + "@babel/helper-explode-assignable-expression" "^7.16.7" + "@babel/types" "^7.16.7" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.0", "@babel/helper-compilation-targets@^7.16.3": - version "7.16.3" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz#5b480cd13f68363df6ec4dc8ac8e2da11363cbf0" - integrity sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA== +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz#a3c2924f5e5f0379b356d4cfb313d1414dc30e46" + integrity sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w== dependencies: - "@babel/compat-data" "^7.16.0" - "@babel/helper-validator-option" "^7.14.5" + "@babel/compat-data" "^7.17.7" + "@babel/helper-validator-option" "^7.16.7" browserslist "^4.17.5" semver "^6.3.0" -"@babel/helper-create-class-features-plugin@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.0.tgz#090d4d166b342a03a9fec37ef4fd5aeb9c7c6a4b" - integrity sha512-XLwWvqEaq19zFlF5PTgOod4bUA+XbkR4WLQBct1bkzmxJGB0ZEJaoKF4c8cgH9oBtCDuYJ8BP5NB9uFiEgO5QA== +"@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7", "@babel/helper-create-class-features-plugin@^7.17.6": + version "7.17.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz#3778c1ed09a7f3e65e6d6e0f6fbfcc53809d92c9" + integrity sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.0" - "@babel/helper-function-name" "^7.16.0" - "@babel/helper-member-expression-to-functions" "^7.16.0" - "@babel/helper-optimise-call-expression" "^7.16.0" - "@babel/helper-replace-supers" "^7.16.0" - "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" -"@babel/helper-create-regexp-features-plugin@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.0.tgz#06b2348ce37fccc4f5e18dcd8d75053f2a7c44ff" - integrity sha512-3DyG0zAFAZKcOp7aVr33ddwkxJ0Z0Jr5V99y3I690eYLpukJsJvAbzTy1ewoCqsML8SbIrjH14Jc/nSQ4TvNPA== +"@babel/helper-create-regexp-features-plugin@^7.16.7": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz#1dcc7d40ba0c6b6b25618997c5dbfd310f186fe1" + integrity sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.0" - regexpu-core "^4.7.1" + "@babel/helper-annotate-as-pure" "^7.16.7" + regexpu-core "^5.0.1" -"@babel/helper-define-polyfill-provider@^0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.0.tgz#c5b10cf4b324ff840140bb07e05b8564af2ae971" - integrity sha512-7hfT8lUljl/tM3h+izTX/pO3W3frz2ok6Pk+gzys8iJqDfZrZy2pXjRTZAvG2YmfHun1X4q8/UZRLatMfqc5Tg== +"@babel/helper-define-polyfill-provider@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz#52411b445bdb2e676869e5a74960d2d3826d2665" + integrity sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA== dependencies: "@babel/helper-compilation-targets" "^7.13.0" "@babel/helper-module-imports" "^7.12.13" @@ -112,101 +120,109 @@ resolve "^1.14.2" semver "^6.1.2" -"@babel/helper-explode-assignable-expression@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz#753017337a15f46f9c09f674cff10cee9b9d7778" - integrity sha512-Hk2SLxC9ZbcOhLpg/yMznzJ11W++lg5GMbxt1ev6TXUiJB0N42KPC+7w8a+eWGuqDnUYuwStJoZHM7RgmIOaGQ== +"@babel/helper-environment-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== dependencies: - "@babel/types" "^7.16.0" + "@babel/types" "^7.16.7" -"@babel/helper-function-name@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481" - integrity sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog== +"@babel/helper-explode-assignable-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz#12a6d8522fdd834f194e868af6354e8650242b7a" + integrity sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ== dependencies: - "@babel/helper-get-function-arity" "^7.16.0" - "@babel/template" "^7.16.0" - "@babel/types" "^7.16.0" + "@babel/types" "^7.16.7" -"@babel/helper-get-function-arity@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa" - integrity sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ== +"@babel/helper-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" + integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== dependencies: - "@babel/types" "^7.16.0" + "@babel/helper-get-function-arity" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/types" "^7.16.7" -"@babel/helper-hoist-variables@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a" - integrity sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg== +"@babel/helper-get-function-arity@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" + integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== dependencies: - "@babel/types" "^7.16.0" + "@babel/types" "^7.16.7" -"@babel/helper-member-expression-to-functions@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz#29287040efd197c77636ef75188e81da8bccd5a4" - integrity sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ== +"@babel/helper-hoist-variables@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== dependencies: - "@babel/types" "^7.16.0" + "@babel/types" "^7.16.7" -"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3" - integrity sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg== +"@babel/helper-member-expression-to-functions@^7.16.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz#a34013b57d8542a8c4ff8ba3f747c02452a4d8c4" + integrity sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw== dependencies: - "@babel/types" "^7.16.0" + "@babel/types" "^7.17.0" -"@babel/helper-module-transforms@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5" - integrity sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA== +"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== dependencies: - "@babel/helper-module-imports" "^7.16.0" - "@babel/helper-replace-supers" "^7.16.0" - "@babel/helper-simple-access" "^7.16.0" - "@babel/helper-split-export-declaration" "^7.16.0" - "@babel/helper-validator-identifier" "^7.15.7" - "@babel/template" "^7.16.0" - "@babel/traverse" "^7.16.0" - "@babel/types" "^7.16.0" + "@babel/types" "^7.16.7" -"@babel/helper-optimise-call-expression@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338" - integrity sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw== +"@babel/helper-module-transforms@^7.16.7", "@babel/helper-module-transforms@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz#3943c7f777139e7954a5355c815263741a9c1cbd" + integrity sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw== dependencies: - "@babel/types" "^7.16.0" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" - integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== - -"@babel/helper-remap-async-to-generator@^7.16.0", "@babel/helper-remap-async-to-generator@^7.16.4": - version "7.16.4" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.4.tgz#5d7902f61349ff6b963e07f06a389ce139fbfe6e" - integrity sha512-vGERmmhR+s7eH5Y/cp8PCVzj4XEjerq8jooMfxFdA5xVtAk9Sh4AQsrWgiErUEBjtGrBtOFKDUcWQFW4/dFwMA== +"@babel/helper-optimise-call-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" + integrity sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.0" - "@babel/helper-wrap-function" "^7.16.0" - "@babel/types" "^7.16.0" + "@babel/types" "^7.16.7" -"@babel/helper-replace-supers@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz#73055e8d3cf9bcba8ddb55cad93fedc860f68f17" - integrity sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.16.0" - "@babel/helper-optimise-call-expression" "^7.16.0" - "@babel/traverse" "^7.16.0" - "@babel/types" "^7.16.0" +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" + integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== -"@babel/helper-simple-access@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz#21d6a27620e383e37534cf6c10bba019a6f90517" - integrity sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw== +"@babel/helper-remap-async-to-generator@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz#29ffaade68a367e2ed09c90901986918d25e57e3" + integrity sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw== dependencies: - "@babel/types" "^7.16.0" + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-wrap-function" "^7.16.8" + "@babel/types" "^7.16.8" + +"@babel/helper-replace-supers@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz#e9f5f5f32ac90429c1a4bdec0f231ef0c2838ab1" + integrity sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helper-simple-access@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" + integrity sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA== + dependencies: + "@babel/types" "^7.17.0" "@babel/helper-skip-transparent-expression-wrappers@^7.16.0": version "7.16.0" @@ -215,233 +231,235 @@ dependencies: "@babel/types" "^7.16.0" -"@babel/helper-split-export-declaration@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438" - integrity sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw== +"@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== dependencies: - "@babel/types" "^7.16.0" + "@babel/types" "^7.16.7" -"@babel/helper-validator-identifier@^7.15.7": - version "7.15.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" - integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== -"@babel/helper-validator-option@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" - integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== +"@babel/helper-validator-option@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" + integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== -"@babel/helper-wrap-function@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.0.tgz#b3cf318afce774dfe75b86767cd6d68f3482e57c" - integrity sha512-VVMGzYY3vkWgCJML+qVLvGIam902mJW0FvT7Avj1zEe0Gn7D93aWdLblYARTxEw+6DhZmtzhBM2zv0ekE5zg1g== +"@babel/helper-wrap-function@^7.16.7", "@babel/helper-wrap-function@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz#58afda087c4cd235de92f7ceedebca2c41274200" + integrity sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw== dependencies: - "@babel/helper-function-name" "^7.16.0" - "@babel/template" "^7.16.0" - "@babel/traverse" "^7.16.0" - "@babel/types" "^7.16.0" + "@babel/helper-function-name" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.8" + "@babel/types" "^7.16.8" -"@babel/helpers@^7.16.0": - version "7.16.3" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.3.tgz#27fc64f40b996e7074dc73128c3e5c3e7f55c43c" - integrity sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w== +"@babel/helpers@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.8.tgz#288450be8c6ac7e4e44df37bcc53d345e07bc106" + integrity sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw== dependencies: - "@babel/template" "^7.16.0" - "@babel/traverse" "^7.16.3" - "@babel/types" "^7.16.0" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" -"@babel/highlight@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a" - integrity sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g== +"@babel/highlight@^7.16.7": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" + integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== dependencies: - "@babel/helper-validator-identifier" "^7.15.7" + "@babel/helper-validator-identifier" "^7.16.7" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.16.0", "@babel/parser@^7.16.3": - version "7.16.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e" - integrity sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng== +"@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" + integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.2": - version "7.16.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.2.tgz#2977fca9b212db153c195674e57cfab807733183" - integrity sha512-h37CvpLSf8gb2lIJ2CgC3t+EjFbi0t8qS7LCS1xcJIlEXE4czlofwaW7W1HA8zpgOCzI9C1nmoqNR1zWkk0pQg== +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz#4eda6d6c2a0aa79c70fa7b6da67763dfe2141050" + integrity sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.0.tgz#358972eaab006f5eb0826183b0c93cbcaf13e1e2" - integrity sha512-4tcFwwicpWTrpl9qjf7UsoosaArgImF85AxqCRZlgc3IQDvkUHjJpruXAL58Wmj+T6fypWTC/BakfEkwIL/pwA== +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz#cc001234dfc139ac45f6bcf801866198c8c72ff9" + integrity sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" - "@babel/plugin-proposal-optional-chaining" "^7.16.0" + "@babel/plugin-proposal-optional-chaining" "^7.16.7" -"@babel/plugin-proposal-async-generator-functions@^7.16.4": - version "7.16.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.4.tgz#e606eb6015fec6fa5978c940f315eae4e300b081" - integrity sha512-/CUekqaAaZCQHleSK/9HajvcD/zdnJiKRiuUFq8ITE+0HsPzquf53cpFiqAwl/UfmJbR6n5uGPQSPdrmKOvHHg== +"@babel/plugin-proposal-async-generator-functions@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz#3bdd1ebbe620804ea9416706cd67d60787504bc8" + integrity sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-remap-async-to-generator" "^7.16.4" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-remap-async-to-generator" "^7.16.8" "@babel/plugin-syntax-async-generators" "^7.8.4" -"@babel/plugin-proposal-class-properties@7.16.0", "@babel/plugin-proposal-class-properties@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.0.tgz#c029618267ddebc7280fa286e0f8ca2a278a2d1a" - integrity sha512-mCF3HcuZSY9Fcx56Lbn+CGdT44ioBMMvjNVldpKtj8tpniETdLjnxdHI1+sDWXIM1nNt+EanJOZ3IG9lzVjs7A== +"@babel/plugin-proposal-class-properties@7.16.7", "@babel/plugin-proposal-class-properties@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz#925cad7b3b1a2fcea7e59ecc8eb5954f961f91b0" + integrity sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww== dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-proposal-class-static-block@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.0.tgz#5296942c564d8144c83eea347d0aa8a0b89170e7" - integrity sha512-mAy3sdcY9sKAkf3lQbDiv3olOfiLqI51c9DR9b19uMoR2Z6r5pmGl7dfNFqEvqOyqbf1ta4lknK4gc5PJn3mfA== +"@babel/plugin-proposal-class-static-block@^7.16.7": + version "7.17.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz#164e8fd25f0d80fa48c5a4d1438a6629325ad83c" + integrity sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-create-class-features-plugin" "^7.17.6" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-class-static-block" "^7.14.5" -"@babel/plugin-proposal-decorators@7.16.4": - version "7.16.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.16.4.tgz#9b35ce0716425a93b978e79099e5f7ba217c1364" - integrity sha512-RESBNX16eNqnBeEVR5sCJpnW0mHiNLNNvGA8PrRuK/4ZJ4TO+6bHleRUuGQYDERVySOKtOhSya/C4MIhwAMAgg== +"@babel/plugin-proposal-decorators@7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.8.tgz#4f0444e896bee85d35cf714a006fc5418f87ff00" + integrity sha512-U69odN4Umyyx1xO1rTII0IDkAEC+RNlcKXtqOblfpzqy1C+aOplb76BQNq0+XdpVkOaPlpEDwd++joY8FNFJKA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-decorators" "^7.16.0" + "@babel/helper-create-class-features-plugin" "^7.17.6" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/plugin-syntax-decorators" "^7.17.0" + charcodes "^0.2.0" -"@babel/plugin-proposal-dynamic-import@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.0.tgz#783eca61d50526202f9b296095453977e88659f1" - integrity sha512-QGSA6ExWk95jFQgwz5GQ2Dr95cf7eI7TKutIXXTb7B1gCLTCz5hTjFTQGfLFBBiC5WSNi7udNwWsqbbMh1c4yQ== +"@babel/plugin-proposal-dynamic-import@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz#c19c897eaa46b27634a00fee9fb7d829158704b2" + integrity sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-dynamic-import" "^7.8.3" -"@babel/plugin-proposal-export-default-from@7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.16.0.tgz#f8a07008ffcb0d3de4945f3eb52022ecc28b56ad" - integrity sha512-kFAhaIbh5qbBwETRNa/cgGmPJ/BicXhIyrZhAkyYhf/Z9LXCTRGO1mvUwczto0Hl1q4YtzP9cRtTKT4wujm38Q== +"@babel/plugin-proposal-export-default-from@7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.16.7.tgz#a40ab158ca55627b71c5513f03d3469026a9e929" + integrity sha512-+cENpW1rgIjExn+o5c8Jw/4BuH4eGKKYvkMB8/0ZxFQ9mC0t4z09VsPIwNg6waF69QYC81zxGeAsREGuqQoKeg== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-export-default-from" "^7.16.0" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-export-default-from" "^7.16.7" -"@babel/plugin-proposal-export-namespace-from@7.16.0", "@babel/plugin-proposal-export-namespace-from@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.0.tgz#9c01dee40b9d6b847b656aaf4a3976a71740f222" - integrity sha512-CjI4nxM/D+5wCnhD11MHB1AwRSAYeDT+h8gCdcVJZ/OK7+wRzFsf7PFPWVpVpNRkHMmMkQWAHpTq+15IXQ1diA== +"@babel/plugin-proposal-export-namespace-from@7.16.7", "@babel/plugin-proposal-export-namespace-from@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz#09de09df18445a5786a305681423ae63507a6163" + integrity sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" -"@babel/plugin-proposal-function-sent@7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-function-sent/-/plugin-proposal-function-sent-7.16.0.tgz#6a873e125e4081e48d9b37518e8e2c63c9a8cddb" - integrity sha512-CkUaPsTiRB72BlsB1Istdb6LSJDi4SU4gH+hW9EKo2/o6naq0HEkuY2OV5anl5Tsnwtdn3FmpteguRc9kXd3Ig== +"@babel/plugin-proposal-function-sent@7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-function-sent/-/plugin-proposal-function-sent-7.16.7.tgz#a258face9ce63ee0c14e396c9b96f171a340de89" + integrity sha512-iJ4DQ1TblymT9ylXSxRG9JH+kYWEHcKdKz47kQqZ9Qij6HOOjTbP9ksG1RFtM+CMnmLJaaG/P+YCvgqUt+5hTw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-wrap-function" "^7.16.0" - "@babel/plugin-syntax-function-sent" "^7.16.0" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-wrap-function" "^7.16.7" + "@babel/plugin-syntax-function-sent" "^7.16.7" -"@babel/plugin-proposal-json-strings@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.0.tgz#cae35a95ed1d2a7fa29c4dc41540b84a72e9ab25" - integrity sha512-kouIPuiv8mSi5JkEhzApg5Gn6hFyKPnlkO0a9YSzqRurH8wYzSlf6RJdzluAsbqecdW5pBvDJDfyDIUR/vLxvg== +"@babel/plugin-proposal-json-strings@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz#9732cb1d17d9a2626a08c5be25186c195b6fa6e8" + integrity sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-json-strings" "^7.8.3" -"@babel/plugin-proposal-logical-assignment-operators@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.0.tgz#a711b8ceb3ffddd3ef88d3a49e86dbd3cc7db3fd" - integrity sha512-pbW0fE30sVTYXXm9lpVQQ/Vc+iTeQKiXlaNRZPPN2A2VdlWyAtsUrsQ3xydSlDW00TFMK7a8m3cDTkBF5WnV3Q== +"@babel/plugin-proposal-logical-assignment-operators@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz#be23c0ba74deec1922e639832904be0bea73cdea" + integrity sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-proposal-nullish-coalescing-operator@7.16.0", "@babel/plugin-proposal-nullish-coalescing-operator@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.0.tgz#44e1cce08fe2427482cf446a91bb451528ed0596" - integrity sha512-3bnHA8CAFm7cG93v8loghDYyQ8r97Qydf63BeYiGgYbjKKB/XP53W15wfRC7dvKfoiJ34f6Rbyyx2btExc8XsQ== +"@babel/plugin-proposal-nullish-coalescing-operator@7.16.7", "@babel/plugin-proposal-nullish-coalescing-operator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz#141fc20b6857e59459d430c850a0011e36561d99" + integrity sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" -"@babel/plugin-proposal-numeric-separator@7.16.0", "@babel/plugin-proposal-numeric-separator@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.0.tgz#5d418e4fbbf8b9b7d03125d3a52730433a373734" - integrity sha512-FAhE2I6mjispy+vwwd6xWPyEx3NYFS13pikDBWUAFGZvq6POGs5eNchw8+1CYoEgBl9n11I3NkzD7ghn25PQ9Q== +"@babel/plugin-proposal-numeric-separator@7.16.7", "@babel/plugin-proposal-numeric-separator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz#d6b69f4af63fb38b6ca2558442a7fb191236eba9" + integrity sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.0.tgz#5fb32f6d924d6e6712810362a60e12a2609872e6" - integrity sha512-LU/+jp89efe5HuWJLmMmFG0+xbz+I2rSI7iLc1AlaeSMDMOGzWlc5yJrMN1d04osXN4sSfpo4O+azkBNBes0jg== +"@babel/plugin-proposal-object-rest-spread@^7.16.7": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz#d9eb649a54628a51701aef7e0ea3d17e2b9dd390" + integrity sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw== dependencies: - "@babel/compat-data" "^7.16.0" - "@babel/helper-compilation-targets" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/compat-data" "^7.17.0" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.16.0" + "@babel/plugin-transform-parameters" "^7.16.7" -"@babel/plugin-proposal-optional-catch-binding@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.0.tgz#5910085811ab4c28b00d6ebffa4ab0274d1e5f16" - integrity sha512-kicDo0A/5J0nrsCPbn89mTG3Bm4XgYi0CZtvex9Oyw7gGZE3HXGD0zpQNH+mo+tEfbo8wbmMvJftOwpmPy7aVw== +"@babel/plugin-proposal-optional-catch-binding@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz#c623a430674ffc4ab732fd0a0ae7722b67cb74cf" + integrity sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-proposal-optional-chaining@7.16.0", "@babel/plugin-proposal-optional-chaining@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.0.tgz#56dbc3970825683608e9efb55ea82c2a2d6c8dc0" - integrity sha512-Y4rFpkZODfHrVo70Uaj6cC1JJOt3Pp0MdWSwIKtb8z1/lsjl9AmnB7ErRFV+QNGIfcY1Eruc2UMx5KaRnXjMyg== +"@babel/plugin-proposal-optional-chaining@7.16.7", "@babel/plugin-proposal-optional-chaining@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz#7cd629564724816c0e8a969535551f943c64c39a" + integrity sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -"@babel/plugin-proposal-private-methods@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.0.tgz#b4dafb9c717e4301c5776b30d080d6383c89aff6" - integrity sha512-IvHmcTHDFztQGnn6aWq4t12QaBXTKr1whF/dgp9kz84X6GUcwq9utj7z2wFCUfeOup/QKnOlt2k0zxkGFx9ubg== +"@babel/plugin-proposal-private-methods@^7.16.11": + version "7.16.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz#e8df108288555ff259f4527dbe84813aac3a1c50" + integrity sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw== dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-create-class-features-plugin" "^7.16.10" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-proposal-private-property-in-object@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.0.tgz#69e935b2c5c79d2488112d886f0c4e2790fee76f" - integrity sha512-3jQUr/HBbMVZmi72LpjQwlZ55i1queL8KcDTQEkAHihttJnAPrcvG9ZNXIfsd2ugpizZo595egYV6xy+pv4Ofw== +"@babel/plugin-proposal-private-property-in-object@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz#b0b8cef543c2c3d57e59e2c611994861d46a3fce" + integrity sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.0" - "@babel/helper-create-class-features-plugin" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" -"@babel/plugin-proposal-throw-expressions@7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-throw-expressions/-/plugin-proposal-throw-expressions-7.16.0.tgz#f9450e11d90159eff29a36e5bcacc9b49eefc4d7" - integrity sha512-8u4KrMqdzRLkfHMN6WOK4taEwV6Dv69O/TuJ2TCGapRXtbjRKDW2UyTxEzlZpA1Eu+MxquSW9+y8qy89TIJfOA== +"@babel/plugin-proposal-throw-expressions@7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-throw-expressions/-/plugin-proposal-throw-expressions-7.16.7.tgz#d3512286f634a06f7271abecce752e1655b9ab03" + integrity sha512-BbjL/uDt7c+OKA7k2YbZIPtOb6qmrzXPybjqrGreP8wMMzTPKjjiK+moqgpElsIXv1XHmlk9PQWdOHD5sL93KA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-throw-expressions" "^7.16.0" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-throw-expressions" "^7.16.7" -"@babel/plugin-proposal-unicode-property-regex@^7.16.0", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.0.tgz#890482dfc5ea378e42e19a71e709728cabf18612" - integrity sha512-ti7IdM54NXv29cA4+bNNKEMS4jLMCbJgl+Drv+FgYy0erJLAxNAIXcNjNjrRZEcWq0xJHsNVwQezskMFpF8N9g== +"@babel/plugin-proposal-unicode-property-regex@^7.16.7", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz#635d18eb10c6214210ffc5ff4932552de08188a2" + integrity sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -464,12 +482,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-decorators@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.16.0.tgz#eb8d811cdd1060f6ac3c00956bf3f6335505a32f" - integrity sha512-nxnnngZClvlY13nHJAIDow0S7Qzhq64fQ/NlqS+VER3kjW/4F0jLhXjeL8jcwSwz6Ca3rotT5NJD2T9I7lcv7g== +"@babel/plugin-syntax-decorators@^7.17.0": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.0.tgz#a2be3b2c9fe7d78bd4994e790896bc411e2f166d" + integrity sha512-qWe85yCXsvDEluNP0OyeQjH63DlhAR3W7K9BxxU1MvbDb48tgBG+Ao6IJJ6smPDrrVzSQZrbF6donpkFBMcs3A== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-dynamic-import@7.8.3", "@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" @@ -478,12 +496,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-export-default-from@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.16.0.tgz#648520667776781f9a0da178f245fff85bc9e36f" - integrity sha512-xllLOdBj77mFSw8s02I+2SSQGHOftbWTlGmagheuNk/gjQsk7IrYsR/EosXVAVpgIUFffLckB/iPRioQYLHSrQ== +"@babel/plugin-syntax-export-default-from@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.16.7.tgz#fa89cf13b60de2c3f79acdc2b52a21174c6de060" + integrity sha512-4C3E4NsrLOgftKaTYTULhHsuQrGv3FHrBzOMDiS7UYKIpgGBkAdawg4h+EI8zPeK9M0fiIIh72hIwsI24K7MbA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-export-namespace-from@^7.8.3": version "7.8.3" @@ -492,12 +510,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-function-sent@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-function-sent/-/plugin-syntax-function-sent-7.16.0.tgz#c6e0eb280a101cd7bdaf6d3f750eb27b59978c48" - integrity sha512-CrwPwHy+ks1xokbZ5x2ZbRwZ5qptN0PE/N5M+o8eQ2LHXGFxlSuDVx515crT7DxUnT+uKctKDuk0NAwG7c1Ebw== +"@babel/plugin-syntax-function-sent@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-function-sent/-/plugin-syntax-function-sent-7.16.7.tgz#46ff4ac849881dbeaa5c5ab60cd1041ffc606095" + integrity sha512-W2fOJmlqHJ0kalyP8kAA0Jx5Hn87OX5qZwjtII3uqi+VpIdLTJLAHH8d4qIt5eqflLALFf6ehVT6+mnFJ2d7AA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" @@ -506,12 +524,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.0.tgz#f9624394317365a9a88c82358d3f8471154698f1" - integrity sha512-8zv2+xiPHwly31RK4RmnEYY5zziuF3O7W2kIDW+07ewWDh6Oi0dRq8kwvulRkFgt6DB97RlKs5c1y068iPlCUg== +"@babel/plugin-syntax-jsx@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665" + integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" @@ -562,12 +580,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-throw-expressions@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-throw-expressions/-/plugin-syntax-throw-expressions-7.16.0.tgz#9d5fc5c185617bc5f727fbecc360601a52cf6879" - integrity sha512-tr5wm8EYRpFW47uVJ2B660pJQXgmeCShz82tE6LkIVkcLzXMz5xhj0drYyehuAl1utNGFqPnMmjpzs5zavAbNQ== +"@babel/plugin-syntax-throw-expressions@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-throw-expressions/-/plugin-syntax-throw-expressions-7.16.7.tgz#5fd64f4d58d653499cc1077bb58594e18da5a514" + integrity sha512-6Kw78ssLHIADvVsqLOLLxuxH4SG55A2tqn0Og2tQQq6X/06HBWLClg6quL+oTfyeVEsPnFYTSECkajseotTnbA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-top-level-await@^7.14.5": version "7.14.5" @@ -576,313 +594,315 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-arrow-functions@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.0.tgz#951706f8b449c834ed07bd474c0924c944b95a8e" - integrity sha512-vIFb5250Rbh7roWARvCLvIJ/PtAU5Lhv7BtZ1u24COwpI9Ypjsh+bZcKk6rlIyalK+r0jOc1XQ8I4ovNxNrWrA== +"@babel/plugin-transform-arrow-functions@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz#44125e653d94b98db76369de9c396dc14bef4154" + integrity sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-async-to-generator@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.0.tgz#df12637f9630ddfa0ef9d7a11bc414d629d38604" - integrity sha512-PbIr7G9kR8tdH6g8Wouir5uVjklETk91GMVSUq+VaOgiinbCkBP6Q7NN/suM/QutZkMJMvcyAriogcYAdhg8Gw== +"@babel/plugin-transform-async-to-generator@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz#b83dff4b970cf41f1b819f8b49cc0cfbaa53a808" + integrity sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg== dependencies: - "@babel/helper-module-imports" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-remap-async-to-generator" "^7.16.0" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-remap-async-to-generator" "^7.16.8" -"@babel/plugin-transform-block-scoped-functions@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.0.tgz#c618763233ad02847805abcac4c345ce9de7145d" - integrity sha512-V14As3haUOP4ZWrLJ3VVx5rCnrYhMSHN/jX7z6FAt5hjRkLsb0snPCmJwSOML5oxkKO4FNoNv7V5hw/y2bjuvg== +"@babel/plugin-transform-block-scoped-functions@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz#4d0d57d9632ef6062cdf354bb717102ee042a620" + integrity sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-block-scoping@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.0.tgz#bcf433fb482fe8c3d3b4e8a66b1c4a8e77d37c16" - integrity sha512-27n3l67/R3UrXfizlvHGuTwsRIFyce3D/6a37GRxn28iyTPvNXaW4XvznexRh1zUNLPjbLL22Id0XQElV94ruw== +"@babel/plugin-transform-block-scoping@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz#f50664ab99ddeaee5bc681b8f3a6ea9d72ab4f87" + integrity sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-classes@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.0.tgz#54cf5ff0b2242c6573d753cd4bfc7077a8b282f5" - integrity sha512-HUxMvy6GtAdd+GKBNYDWCIA776byUQH8zjnfjxwT1P1ARv/wFu8eBDpmXQcLS/IwRtrxIReGiplOwMeyO7nsDQ== +"@babel/plugin-transform-classes@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz#8f4b9562850cd973de3b498f1218796eb181ce00" + integrity sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.0" - "@babel/helper-function-name" "^7.16.0" - "@babel/helper-optimise-call-expression" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-replace-supers" "^7.16.0" - "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.0.tgz#e0c385507d21e1b0b076d66bed6d5231b85110b7" - integrity sha512-63l1dRXday6S8V3WFY5mXJwcRAnPYxvFfTlt67bwV1rTyVTM5zrp0DBBb13Kl7+ehkCVwIZPumPpFP/4u70+Tw== +"@babel/plugin-transform-computed-properties@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz#66dee12e46f61d2aae7a73710f591eb3df616470" + integrity sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-destructuring@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.0.tgz#ad3d7e74584ad5ea4eadb1e6642146c590dee33c" - integrity sha512-Q7tBUwjxLTsHEoqktemHBMtb3NYwyJPTJdM+wDwb0g8PZ3kQUIzNvwD5lPaqW/p54TXBc/MXZu9Jr7tbUEUM8Q== +"@babel/plugin-transform-destructuring@^7.16.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz#49dc2675a7afa9a5e4c6bdee636061136c3408d1" + integrity sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-dotall-regex@^7.16.0", "@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.0.tgz#50bab00c1084b6162d0a58a818031cf57798e06f" - integrity sha512-FXlDZfQeLILfJlC6I1qyEwcHK5UpRCFkaoVyA1nk9A1L1Yu583YO4un2KsLBsu3IJb4CUbctZks8tD9xPQubLw== +"@babel/plugin-transform-dotall-regex@^7.16.7", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz#6b2d67686fab15fb6a7fd4bd895d5982cfc81241" + integrity sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-duplicate-keys@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.0.tgz#8bc2e21813e3e89e5e5bf3b60aa5fc458575a176" - integrity sha512-LIe2kcHKAZOJDNxujvmp6z3mfN6V9lJxubU4fJIGoQCkKe3Ec2OcbdlYP+vW++4MpxwG0d1wSDOJtQW5kLnkZQ== +"@babel/plugin-transform-duplicate-keys@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz#2207e9ca8f82a0d36a5a67b6536e7ef8b08823c9" + integrity sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-exponentiation-operator@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.0.tgz#a180cd2881e3533cef9d3901e48dad0fbeff4be4" - integrity sha512-OwYEvzFI38hXklsrbNivzpO3fh87skzx8Pnqi4LoSYeav0xHlueSoCJrSgTPfnbyzopo5b3YVAJkFIcUpK2wsw== +"@babel/plugin-transform-exponentiation-operator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz#efa9862ef97e9e9e5f653f6ddc7b665e8536fe9b" + integrity sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-for-of@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.0.tgz#f7abaced155260e2461359bbc7c7248aca5e6bd2" - integrity sha512-5QKUw2kO+GVmKr2wMYSATCTTnHyscl6sxFRAY+rvN7h7WB0lcG0o4NoV6ZQU32OZGVsYUsfLGgPQpDFdkfjlJQ== +"@babel/plugin-transform-for-of@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz#649d639d4617dff502a9a158c479b3b556728d8c" + integrity sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-function-name@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.0.tgz#02e3699c284c6262236599f751065c5d5f1f400e" - integrity sha512-lBzMle9jcOXtSOXUpc7tvvTpENu/NuekNJVova5lCCWCV9/U1ho2HH2y0p6mBg8fPm/syEAbfaaemYGOHCY3mg== +"@babel/plugin-transform-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz#5ab34375c64d61d083d7d2f05c38d90b97ec65cf" + integrity sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA== dependencies: - "@babel/helper-function-name" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-literals@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.0.tgz#79711e670ffceb31bd298229d50f3621f7980cac" - integrity sha512-gQDlsSF1iv9RU04clgXqRjrPyyoJMTclFt3K1cjLmTKikc0s/6vE3hlDeEVC71wLTRu72Fq7650kABrdTc2wMQ== +"@babel/plugin-transform-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz#254c9618c5ff749e87cb0c0cef1a0a050c0bdab1" + integrity sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-member-expression-literals@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.0.tgz#5251b4cce01eaf8314403d21aedb269d79f5e64b" - integrity sha512-WRpw5HL4Jhnxw8QARzRvwojp9MIE7Tdk3ez6vRyUk1MwgjJN0aNpRoXainLR5SgxmoXx/vsXGZ6OthP6t/RbUg== +"@babel/plugin-transform-member-expression-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz#6e5dcf906ef8a098e630149d14c867dd28f92384" + integrity sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-modules-amd@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.0.tgz#09abd41e18dcf4fd479c598c1cef7bd39eb1337e" - integrity sha512-rWFhWbCJ9Wdmzln1NmSCqn7P0RAD+ogXG/bd9Kg5c7PKWkJtkiXmYsMBeXjDlzHpVTJ4I/hnjs45zX4dEv81xw== +"@babel/plugin-transform-modules-amd@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz#b28d323016a7daaae8609781d1f8c9da42b13186" + integrity sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g== dependencies: - "@babel/helper-module-transforms" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-commonjs@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.0.tgz#add58e638c8ddc4875bd9a9ecb5c594613f6c922" - integrity sha512-Dzi+NWqyEotgzk/sb7kgQPJQf7AJkQBWsVp1N6JWc1lBVo0vkElUnGdr1PzUBmfsCCN5OOFya3RtpeHk15oLKQ== +"@babel/plugin-transform-modules-commonjs@^7.16.8": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.7.tgz#d86b217c8e45bb5f2dbc11eefc8eab62cf980d19" + integrity sha512-ITPmR2V7MqioMJyrxUo2onHNC3e+MvfFiFIR0RP21d3PtlVb6sfzoxNKiphSZUOM9hEIdzCcZe83ieX3yoqjUA== dependencies: - "@babel/helper-module-transforms" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-simple-access" "^7.16.0" + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-systemjs@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.0.tgz#a92cf240afeb605f4ca16670453024425e421ea4" - integrity sha512-yuGBaHS3lF1m/5R+6fjIke64ii5luRUg97N2wr+z1sF0V+sNSXPxXDdEEL/iYLszsN5VKxVB1IPfEqhzVpiqvg== +"@babel/plugin-transform-modules-systemjs@^7.16.7": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz#81fd834024fae14ea78fbe34168b042f38703859" + integrity sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw== dependencies: - "@babel/helper-hoist-variables" "^7.16.0" - "@babel/helper-module-transforms" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-validator-identifier" "^7.15.7" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-umd@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.0.tgz#195f26c2ad6d6a391b70880effce18ce625e06a7" - integrity sha512-nx4f6no57himWiHhxDM5pjwhae5vLpTK2zCnDH8+wNLJy0TVER/LJRHl2bkt6w9Aad2sPD5iNNoUpY3X9sTGDg== +"@babel/plugin-transform-modules-umd@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz#23dad479fa585283dbd22215bff12719171e7618" + integrity sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ== dependencies: - "@babel/helper-module-transforms" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-named-capturing-groups-regex@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.0.tgz#d3db61cc5d5b97986559967cd5ea83e5c32096ca" - integrity sha512-LogN88uO+7EhxWc8WZuQ8vxdSyVGxhkh8WTC3tzlT8LccMuQdA81e9SGV6zY7kY2LjDhhDOFdQVxdGwPyBCnvg== +"@babel/plugin-transform-named-capturing-groups-regex@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz#7f860e0e40d844a02c9dcf9d84965e7dfd666252" + integrity sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.0" + "@babel/helper-create-regexp-features-plugin" "^7.16.7" -"@babel/plugin-transform-new-target@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.0.tgz#af823ab576f752215a49937779a41ca65825ab35" - integrity sha512-fhjrDEYv2DBsGN/P6rlqakwRwIp7rBGLPbrKxwh7oVt5NNkIhZVOY2GRV+ULLsQri1bDqwDWnU3vhlmx5B2aCw== +"@babel/plugin-transform-new-target@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz#9967d89a5c243818e0800fdad89db22c5f514244" + integrity sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-object-super@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.0.tgz#fb20d5806dc6491a06296ac14ea8e8d6fedda72b" - integrity sha512-fds+puedQHn4cPLshoHcR1DTMN0q1V9ou0mUjm8whx9pGcNvDrVVrgw+KJzzCaiTdaYhldtrUps8DWVMgrSEyg== +"@babel/plugin-transform-object-super@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz#ac359cf8d32cf4354d27a46867999490b6c32a94" + integrity sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" -"@babel/plugin-transform-parameters@^7.16.0", "@babel/plugin-transform-parameters@^7.16.3": - version "7.16.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.3.tgz#fa9e4c874ee5223f891ee6fa8d737f4766d31d15" - integrity sha512-3MaDpJrOXT1MZ/WCmkOFo7EtmVVC8H4EUZVrHvFOsmwkk4lOjQj8rzv8JKUZV4YoQKeoIgk07GO+acPU9IMu/w== +"@babel/plugin-transform-parameters@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz#a1721f55b99b736511cb7e0152f61f17688f331f" + integrity sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-property-literals@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.0.tgz#a95c552189a96a00059f6776dc4e00e3690c78d1" - integrity sha512-XLldD4V8+pOqX2hwfWhgwXzGdnDOThxaNTgqagOcpBgIxbUvpgU2FMvo5E1RyHbk756WYgdbS0T8y0Cj9FKkWQ== +"@babel/plugin-transform-property-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz#2dadac85155436f22c696c4827730e0fe1057a55" + integrity sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-react-display-name@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.0.tgz#9a0ad8aa8e8790883a7bd2736f66229a58125676" - integrity sha512-FJFdJAqaCpndL+pIf0aeD/qlQwT7QXOvR6Cc8JPvNhKJBi2zc/DPc4g05Y3fbD/0iWAMQFGij4+Xw+4L/BMpTg== +"@babel/plugin-transform-react-display-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz#7b6d40d232f4c0f550ea348593db3b21e2404340" + integrity sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-react-jsx-development@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.0.tgz#1cb52874678d23ab11d0d16488d54730807303ef" - integrity sha512-qq65iSqBRq0Hr3wq57YG2AmW0H6wgTnIzpffTphrUWUgLCOK+zf1f7G0vuOiXrp7dU1qq+fQBoqZ3wCDAkhFzw== +"@babel/plugin-transform-react-jsx-development@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz#43a00724a3ed2557ed3f276a01a929e6686ac7b8" + integrity sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A== dependencies: - "@babel/plugin-transform-react-jsx" "^7.16.0" + "@babel/plugin-transform-react-jsx" "^7.16.7" -"@babel/plugin-transform-react-jsx@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.0.tgz#55b797d4960c3de04e07ad1c0476e2bc6a4889f1" - integrity sha512-rqDgIbukZ44pqq7NIRPGPGNklshPkvlmvqjdx3OZcGPk4zGIenYkxDTvl3LsSL8gqcc3ZzGmXPE6hR/u/voNOw== +"@babel/plugin-transform-react-jsx@^7.16.7": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.3.tgz#eac1565da176ccb1a715dae0b4609858808008c1" + integrity sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.0" - "@babel/helper-module-imports" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-jsx" "^7.16.0" - "@babel/types" "^7.16.0" + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-jsx" "^7.16.7" + "@babel/types" "^7.17.0" -"@babel/plugin-transform-react-pure-annotations@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.0.tgz#23db6ddf558d8abde41b8ad9d59f48ad5532ccab" - integrity sha512-NC/Bj2MG+t8Ef5Pdpo34Ay74X4Rt804h5y81PwOpfPtmAK3i6CizmQqwyBQzIepz1Yt8wNr2Z2L7Lu3qBMfZMA== +"@babel/plugin-transform-react-pure-annotations@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz#232bfd2f12eb551d6d7d01d13fe3f86b45eb9c67" + integrity sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-regenerator@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.0.tgz#eaee422c84b0232d03aea7db99c97deeaf6125a4" - integrity sha512-JAvGxgKuwS2PihiSFaDrp94XOzzTUeDeOQlcKzVAyaPap7BnZXK/lvMDiubkPTdotPKOIZq9xWXWnggUMYiExg== +"@babel/plugin-transform-regenerator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz#9e7576dc476cb89ccc5096fff7af659243b4adeb" + integrity sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q== dependencies: regenerator-transform "^0.14.2" -"@babel/plugin-transform-reserved-words@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.0.tgz#fff4b9dcb19e12619394bda172d14f2d04c0379c" - integrity sha512-Dgs8NNCehHSvXdhEhln8u/TtJxfVwGYCgP2OOr5Z3Ar+B+zXicEOKNTyc+eca2cuEOMtjW6m9P9ijOt8QdqWkg== +"@babel/plugin-transform-reserved-words@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz#1d798e078f7c5958eec952059c460b220a63f586" + integrity sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-shorthand-properties@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.0.tgz#090372e3141f7cc324ed70b3daf5379df2fa384d" - integrity sha512-iVb1mTcD8fuhSv3k99+5tlXu5N0v8/DPm2mO3WACLG6al1CGZH7v09HJyUb1TtYl/Z+KrM6pHSIJdZxP5A+xow== +"@babel/plugin-transform-shorthand-properties@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz#e8549ae4afcf8382f711794c0c7b6b934c5fbd2a" + integrity sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-spread@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.0.tgz#d21ca099bbd53ab307a8621e019a7bd0f40cdcfb" - integrity sha512-Ao4MSYRaLAQczZVp9/7E7QHsCuK92yHRrmVNRe/SlEJjhzivq0BSn8mEraimL8wizHZ3fuaHxKH0iwzI13GyGg== +"@babel/plugin-transform-spread@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz#a303e2122f9f12e0105daeedd0f30fb197d8ff44" + integrity sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" -"@babel/plugin-transform-sticky-regex@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.0.tgz#c35ea31a02d86be485f6aa510184b677a91738fd" - integrity sha512-/ntT2NljR9foobKk4E/YyOSwcGUXtYWv5tinMK/3RkypyNBNdhHUaq6Orw5DWq9ZcNlS03BIlEALFeQgeVAo4Q== +"@babel/plugin-transform-sticky-regex@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz#c84741d4f4a38072b9a1e2e3fd56d359552e8660" + integrity sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-template-literals@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.0.tgz#a8eced3a8e7b8e2d40ec4ec4548a45912630d302" - integrity sha512-Rd4Ic89hA/f7xUSJQk5PnC+4so50vBoBfxjdQAdvngwidM8jYIBVxBZ/sARxD4e0yMXRbJVDrYf7dyRtIIKT6Q== +"@babel/plugin-transform-template-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz#f3d1c45d28967c8e80f53666fc9c3e50618217ab" + integrity sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-typeof-symbol@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.0.tgz#8b19a244c6f8c9d668dca6a6f754ad6ead1128f2" - integrity sha512-++V2L8Bdf4vcaHi2raILnptTBjGEFxn5315YU+e8+EqXIucA+q349qWngCLpUYqqv233suJ6NOienIVUpS9cqg== +"@babel/plugin-transform-typeof-symbol@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz#9cdbe622582c21368bd482b660ba87d5545d4f7e" + integrity sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-unicode-escapes@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.0.tgz#1a354064b4c45663a32334f46fa0cf6100b5b1f3" - integrity sha512-VFi4dhgJM7Bpk8lRc5CMaRGlKZ29W9C3geZjt9beuzSUrlJxsNwX7ReLwaL6WEvsOf2EQkyIJEPtF8EXjB/g2A== +"@babel/plugin-transform-unicode-escapes@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz#da8717de7b3287a2c6d659750c964f302b31ece3" + integrity sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-unicode-regex@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.0.tgz#293b80950177c8c85aede87cef280259fb995402" - integrity sha512-jHLK4LxhHjvCeZDWyA9c+P9XH1sOxRd1RO9xMtDVRAOND/PczPqizEtVdx4TQF/wyPaewqpT+tgQFYMnN/P94A== +"@babel/plugin-transform-unicode-regex@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz#0f7aa4a501198976e25e82702574c34cfebe9ef2" + integrity sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.0" - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" -"@babel/preset-env@7.16.4": - version "7.16.4" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.16.4.tgz#4f6ec33b2a3fe72d6bfdcdf3859500232563a2e3" - integrity sha512-v0QtNd81v/xKj4gNKeuAerQ/azeNn/G1B1qMLeXOcV8+4TWlD2j3NV1u8q29SDFBXx/NBq5kyEAO+0mpRgacjA== +"@babel/preset-env@7.16.11": + version "7.16.11" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.16.11.tgz#5dd88fd885fae36f88fd7c8342475c9f0abe2982" + integrity sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g== dependencies: - "@babel/compat-data" "^7.16.4" - "@babel/helper-compilation-targets" "^7.16.3" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-validator-option" "^7.14.5" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.2" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.0" - "@babel/plugin-proposal-async-generator-functions" "^7.16.4" - "@babel/plugin-proposal-class-properties" "^7.16.0" - "@babel/plugin-proposal-class-static-block" "^7.16.0" - "@babel/plugin-proposal-dynamic-import" "^7.16.0" - "@babel/plugin-proposal-export-namespace-from" "^7.16.0" - "@babel/plugin-proposal-json-strings" "^7.16.0" - "@babel/plugin-proposal-logical-assignment-operators" "^7.16.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.0" - "@babel/plugin-proposal-numeric-separator" "^7.16.0" - "@babel/plugin-proposal-object-rest-spread" "^7.16.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.16.0" - "@babel/plugin-proposal-optional-chaining" "^7.16.0" - "@babel/plugin-proposal-private-methods" "^7.16.0" - "@babel/plugin-proposal-private-property-in-object" "^7.16.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.16.0" + "@babel/compat-data" "^7.16.8" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-option" "^7.16.7" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.7" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.7" + "@babel/plugin-proposal-async-generator-functions" "^7.16.8" + "@babel/plugin-proposal-class-properties" "^7.16.7" + "@babel/plugin-proposal-class-static-block" "^7.16.7" + "@babel/plugin-proposal-dynamic-import" "^7.16.7" + "@babel/plugin-proposal-export-namespace-from" "^7.16.7" + "@babel/plugin-proposal-json-strings" "^7.16.7" + "@babel/plugin-proposal-logical-assignment-operators" "^7.16.7" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.7" + "@babel/plugin-proposal-numeric-separator" "^7.16.7" + "@babel/plugin-proposal-object-rest-spread" "^7.16.7" + "@babel/plugin-proposal-optional-catch-binding" "^7.16.7" + "@babel/plugin-proposal-optional-chaining" "^7.16.7" + "@babel/plugin-proposal-private-methods" "^7.16.11" + "@babel/plugin-proposal-private-property-in-object" "^7.16.7" + "@babel/plugin-proposal-unicode-property-regex" "^7.16.7" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-class-properties" "^7.12.13" "@babel/plugin-syntax-class-static-block" "^7.14.5" @@ -897,44 +917,44 @@ "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-transform-arrow-functions" "^7.16.0" - "@babel/plugin-transform-async-to-generator" "^7.16.0" - "@babel/plugin-transform-block-scoped-functions" "^7.16.0" - "@babel/plugin-transform-block-scoping" "^7.16.0" - "@babel/plugin-transform-classes" "^7.16.0" - "@babel/plugin-transform-computed-properties" "^7.16.0" - "@babel/plugin-transform-destructuring" "^7.16.0" - "@babel/plugin-transform-dotall-regex" "^7.16.0" - "@babel/plugin-transform-duplicate-keys" "^7.16.0" - "@babel/plugin-transform-exponentiation-operator" "^7.16.0" - "@babel/plugin-transform-for-of" "^7.16.0" - "@babel/plugin-transform-function-name" "^7.16.0" - "@babel/plugin-transform-literals" "^7.16.0" - "@babel/plugin-transform-member-expression-literals" "^7.16.0" - "@babel/plugin-transform-modules-amd" "^7.16.0" - "@babel/plugin-transform-modules-commonjs" "^7.16.0" - "@babel/plugin-transform-modules-systemjs" "^7.16.0" - "@babel/plugin-transform-modules-umd" "^7.16.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.16.0" - "@babel/plugin-transform-new-target" "^7.16.0" - "@babel/plugin-transform-object-super" "^7.16.0" - "@babel/plugin-transform-parameters" "^7.16.3" - "@babel/plugin-transform-property-literals" "^7.16.0" - "@babel/plugin-transform-regenerator" "^7.16.0" - "@babel/plugin-transform-reserved-words" "^7.16.0" - "@babel/plugin-transform-shorthand-properties" "^7.16.0" - "@babel/plugin-transform-spread" "^7.16.0" - "@babel/plugin-transform-sticky-regex" "^7.16.0" - "@babel/plugin-transform-template-literals" "^7.16.0" - "@babel/plugin-transform-typeof-symbol" "^7.16.0" - "@babel/plugin-transform-unicode-escapes" "^7.16.0" - "@babel/plugin-transform-unicode-regex" "^7.16.0" + "@babel/plugin-transform-arrow-functions" "^7.16.7" + "@babel/plugin-transform-async-to-generator" "^7.16.8" + "@babel/plugin-transform-block-scoped-functions" "^7.16.7" + "@babel/plugin-transform-block-scoping" "^7.16.7" + "@babel/plugin-transform-classes" "^7.16.7" + "@babel/plugin-transform-computed-properties" "^7.16.7" + "@babel/plugin-transform-destructuring" "^7.16.7" + "@babel/plugin-transform-dotall-regex" "^7.16.7" + "@babel/plugin-transform-duplicate-keys" "^7.16.7" + "@babel/plugin-transform-exponentiation-operator" "^7.16.7" + "@babel/plugin-transform-for-of" "^7.16.7" + "@babel/plugin-transform-function-name" "^7.16.7" + "@babel/plugin-transform-literals" "^7.16.7" + "@babel/plugin-transform-member-expression-literals" "^7.16.7" + "@babel/plugin-transform-modules-amd" "^7.16.7" + "@babel/plugin-transform-modules-commonjs" "^7.16.8" + "@babel/plugin-transform-modules-systemjs" "^7.16.7" + "@babel/plugin-transform-modules-umd" "^7.16.7" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.16.8" + "@babel/plugin-transform-new-target" "^7.16.7" + "@babel/plugin-transform-object-super" "^7.16.7" + "@babel/plugin-transform-parameters" "^7.16.7" + "@babel/plugin-transform-property-literals" "^7.16.7" + "@babel/plugin-transform-regenerator" "^7.16.7" + "@babel/plugin-transform-reserved-words" "^7.16.7" + "@babel/plugin-transform-shorthand-properties" "^7.16.7" + "@babel/plugin-transform-spread" "^7.16.7" + "@babel/plugin-transform-sticky-regex" "^7.16.7" + "@babel/plugin-transform-template-literals" "^7.16.7" + "@babel/plugin-transform-typeof-symbol" "^7.16.7" + "@babel/plugin-transform-unicode-escapes" "^7.16.7" + "@babel/plugin-transform-unicode-regex" "^7.16.7" "@babel/preset-modules" "^0.1.5" - "@babel/types" "^7.16.0" + "@babel/types" "^7.16.8" babel-plugin-polyfill-corejs2 "^0.3.0" - babel-plugin-polyfill-corejs3 "^0.4.0" + babel-plugin-polyfill-corejs3 "^0.5.0" babel-plugin-polyfill-regenerator "^0.3.0" - core-js-compat "^3.19.1" + core-js-compat "^3.20.2" semver "^6.3.0" "@babel/preset-modules@^0.1.5": @@ -948,55 +968,56 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-react@7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.16.0.tgz#f71d3e8dff5218478011df037fad52660ee6d82a" - integrity sha512-d31IFW2bLRB28uL1WoElyro8RH5l6531XfxMtCeCmp6RVAF1uTfxxUA0LH1tXl+psZdwfmIbwoG4U5VwgbhtLw== +"@babel/preset-react@7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.16.7.tgz#4c18150491edc69c183ff818f9f2aecbe5d93852" + integrity sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-validator-option" "^7.14.5" - "@babel/plugin-transform-react-display-name" "^7.16.0" - "@babel/plugin-transform-react-jsx" "^7.16.0" - "@babel/plugin-transform-react-jsx-development" "^7.16.0" - "@babel/plugin-transform-react-pure-annotations" "^7.16.0" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-option" "^7.16.7" + "@babel/plugin-transform-react-display-name" "^7.16.7" + "@babel/plugin-transform-react-jsx" "^7.16.7" + "@babel/plugin-transform-react-jsx-development" "^7.16.7" + "@babel/plugin-transform-react-pure-annotations" "^7.16.7" "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": - version "7.16.3" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.3.tgz#b86f0db02a04187a3c17caa77de69840165d42d5" - integrity sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ== + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2" + integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA== dependencies: regenerator-runtime "^0.13.4" -"@babel/template@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" - integrity sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A== +"@babel/template@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== dependencies: - "@babel/code-frame" "^7.16.0" - "@babel/parser" "^7.16.0" - "@babel/types" "^7.16.0" + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" -"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.3": - version "7.16.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.3.tgz#f63e8a938cc1b780f66d9ed3c54f532ca2d14787" - integrity sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag== +"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.3": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" + integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== dependencies: - "@babel/code-frame" "^7.16.0" - "@babel/generator" "^7.16.0" - "@babel/helper-function-name" "^7.16.0" - "@babel/helper-hoist-variables" "^7.16.0" - "@babel/helper-split-export-declaration" "^7.16.0" - "@babel/parser" "^7.16.3" - "@babel/types" "^7.16.0" + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.3" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.17.3" + "@babel/types" "^7.17.0" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.16.0", "@babel/types@^7.4.4": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" - integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== +"@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.4.4": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" + integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== dependencies: - "@babel/helper-validator-identifier" "^7.15.7" + "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" "@cnakazawa/watch@^1.0.3": @@ -1008,77 +1029,95 @@ minimist "^1.2.0" "@discoveryjs/json-ext@^0.5.0": - version "0.5.5" - resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz#9283c9ce5b289a3c4f61c12757469e59377f81f3" - integrity sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA== + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@eslint/eslintrc@^1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.4.tgz#dfe0ff7ba270848d10c5add0715e04964c034b31" - integrity sha512-h8Vx6MdxwWI2WM8/zREHMoqdgLNXEL4QX3MWSVMdyNJGvXVOs+6lp+m2hc3FnuMHDc4poxFNI20vCk0OmI4G0Q== +"@eslint/eslintrc@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.1.tgz#8b5e1c49f4077235516bc9ec7d41378c0f69b8c6" + integrity sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.0.0" + espree "^9.3.1" globals "^13.9.0" - ignore "^4.0.6" + ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" minimatch "^3.0.4" strip-json-comments "^3.1.1" -"@fortawesome/fontawesome-common-types@^0.2.35": - version "0.2.36" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz#b44e52db3b6b20523e0c57ef8c42d315532cb903" - integrity sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg== +"@fortawesome/fontawesome-common-types@6.1.1": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.1.tgz#7dc996042d21fc1ae850e3173b5c67b0549f9105" + integrity sha512-wVn5WJPirFTnzN6tR95abCx+ocH+3IFLXAgyavnf9hUmN0CfWoDjPT/BAWsUVwSlYYVBeCLJxaqi7ZGe4uSjBA== -"@fortawesome/fontawesome-free@5.15.3": - version "5.15.3" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.3.tgz#c36ffa64a2a239bf948541a97b6ae8d729e09a9a" - integrity sha512-rFnSUN/QOtnOAgqFRooTA3H57JLDm0QEG/jPdk+tLQNL/eWd+Aok8g3qCI+Q1xuDPWpGW/i9JySpJVsq8Q0s9w== +"@fortawesome/fontawesome-free@6.1.1": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.1.1.tgz#bf5d45611ab74890be386712a0e5d998c65ee2a1" + integrity sha512-J/3yg2AIXc9wznaVqpHVX3Wa5jwKovVF0AMYSnbmcXTiL3PpRPfF58pzWucCwEiCJBp+hCNRLWClTomD8SseKg== -"@fortawesome/fontawesome-svg-core@1.2.35": - version "1.2.35" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.35.tgz#85aea8c25645fcec88d35f2eb1045c38d3e65cff" - integrity sha512-uLEXifXIL7hnh2sNZQrIJWNol7cTVIzwI+4qcBIq9QWaZqUblm0IDrtSqbNg+3SQf8SMGHkiSigD++rHmCHjBg== +"@fortawesome/fontawesome-svg-core@6.1.1": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.1.1.tgz#3424ec6182515951816be9b11665d67efdce5b5f" + integrity sha512-NCg0w2YIp81f4V6cMGD9iomfsIj7GWrqmsa0ZsPh59G7PKiGN1KymZNxmF00ssuAlo/VZmpK6xazsGOwzKYUMg== dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.35" + "@fortawesome/fontawesome-common-types" "6.1.1" -"@fortawesome/free-regular-svg-icons@5.15.3": - version "5.15.3" - resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.3.tgz#1ec4f2410ff638db549c5c5484fc60b66407dbe6" - integrity sha512-q4/p8Xehy9qiVTdDWHL4Z+o5PCLRChePGZRTXkl+/Z7erDVL8VcZUuqzJjs6gUz6czss4VIPBRdCz6wP37/zMQ== +"@fortawesome/free-regular-svg-icons@6.1.1": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.1.1.tgz#3f2f58262a839edf0643cbacee7a8a8230061c98" + integrity sha512-xXiW7hcpgwmWtndKPOzG+43fPH7ZjxOaoeyooptSztGmJxCAflHZxXNK0GcT0uEsR4jTGQAfGklDZE5NHoBhKg== dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.35" + "@fortawesome/fontawesome-common-types" "6.1.1" -"@fortawesome/free-solid-svg-icons@5.15.3": - version "5.15.3" - resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.3.tgz#52eebe354f60dc77e0bde934ffc5c75ffd04f9d8" - integrity sha512-XPeeu1IlGYqz4VWGRAT5ukNMd4VHUEEJ7ysZ7pSSgaEtNvSo+FLurybGJVmiqkQdK50OkSja2bfZXOeyMGRD8Q== +"@fortawesome/free-solid-svg-icons@6.1.1": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.1.1.tgz#3369e673f8fe8be2fba30b1ec274d47490a830a6" + integrity sha512-0/5exxavOhI/D4Ovm2r3vxNojGZioPwmFrKg0ZUH69Q68uFhFPs6+dhAToh6VEQBntxPRYPuT5Cg1tpNa9JUPg== dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.35" + "@fortawesome/fontawesome-common-types" "6.1.1" -"@fortawesome/react-fontawesome@0.1.14": - version "0.1.14" - resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.14.tgz#bf28875c3935b69ce2dc620e1060b217a47f64ca" - integrity sha512-4wqNb0gRLVaBm/h+lGe8UfPPivcbuJ6ecI4hIgW0LjI7kzpYB9FkN0L9apbVzg+lsBdcTf0AlBtODjcSX5mmKA== +"@fortawesome/react-fontawesome@0.1.18": + version "0.1.18" + resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.18.tgz#dae37f718a24e14d7a99a5496c873d69af3fbd73" + integrity sha512-RwLIB4TZw0M9gvy5u+TusAA0afbwM4JQIimNH/j3ygd6aIvYPQLqXMhC9ErY26J23rDPyDZldIfPq/HpTTJ/tQ== dependencies: - prop-types "^15.7.2" + prop-types "^15.8.1" -"@humanwhocodes/config-array@^0.6.0": - version "0.6.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.6.0.tgz#b5621fdb3b32309d2d16575456cbc277fa8f021a" - integrity sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A== +"@humanwhocodes/config-array@^0.9.2": + version "0.9.5" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" + integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== dependencies: - "@humanwhocodes/object-schema" "^1.2.0" + "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" minimatch "^3.0.4" -"@humanwhocodes/object-schema@^1.2.0": +"@humanwhocodes/object-schema@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@jridgewell/resolve-uri@^3.0.3": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" + integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.11" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" + integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== + +"@jridgewell/trace-mapping@^0.3.0": + version "0.3.4" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz#f6a0832dffd5b8a6aaa633b7d9f8e8e94c83a0c3" + integrity sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@microsoft/signalr@6.0.3": version "6.0.3" resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-6.0.3.tgz#9904efd48cd488e3c1c80930ff9fbb3c9f55895d" @@ -1139,72 +1178,72 @@ resolved "https://registry.yarnpkg.com/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz#a3031eb54129f2c66b2753f8404266ec7bf67f0a" integrity sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg== -"@sentry/browser@6.15.0": - version "6.15.0" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.15.0.tgz#7a1d316dd31cedee446e359a21774bf93d1e553d" - integrity sha512-ZiqfHK5DMVgDsgMTuSwxilWIqEnZzy4yuJ9Sr6Iap1yZddPSiKHYjbBieSHn57UsWHViRB3ojbwu44LfvXKJdQ== +"@sentry/browser@6.19.2": + version "6.19.2" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.19.2.tgz#c0f6df07584f3b36fa037067aea20b2c8c2095a3" + integrity sha512-5VC44p5Vu2eJhVT39nLAJFgha5MjHDYCyZRR1ieeZt3a++otojPGBBAKNAtrEMGV+A2Z9AoneD6ZnDVlyb3GKg== dependencies: - "@sentry/core" "6.15.0" - "@sentry/types" "6.15.0" - "@sentry/utils" "6.15.0" + "@sentry/core" "6.19.2" + "@sentry/types" "6.19.2" + "@sentry/utils" "6.19.2" tslib "^1.9.3" -"@sentry/core@6.15.0": - version "6.15.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.15.0.tgz#5e877042fe18452f2273247126b32e139d5f907c" - integrity sha512-mCbKyqvD1G3Re6gv6N8tRkBz84gvVWDfLtC6d1WBArIopzter6ktEbvq0cMT6EOvGI2OLXuJ6mtHA93/Q0gGpw== +"@sentry/core@6.19.2": + version "6.19.2" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.19.2.tgz#dd35ba6ca41a2dd011c43f732bcdadbb52c06376" + integrity sha512-yu1R3ewBT4udmB4v7sc4biQZ0Z0rfB9+TzB5ZKoCftbe6kqXjFMMaFRYNUF9HicVldKAsBktgkWw3+yfqGkw/A== dependencies: - "@sentry/hub" "6.15.0" - "@sentry/minimal" "6.15.0" - "@sentry/types" "6.15.0" - "@sentry/utils" "6.15.0" + "@sentry/hub" "6.19.2" + "@sentry/minimal" "6.19.2" + "@sentry/types" "6.19.2" + "@sentry/utils" "6.19.2" tslib "^1.9.3" -"@sentry/hub@6.15.0": - version "6.15.0" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.15.0.tgz#fb8a91d12fdd2726a884374ea7242f6bbd081d69" - integrity sha512-cUbHPeG6kKpGBaEMgbTWeU03Y1Up5T3urGF+cgtrn80PmPYYSUPvVvWlZQWPb8CJZ1yQ0gySWo5RUTatBFrEHA== +"@sentry/hub@6.19.2": + version "6.19.2" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.19.2.tgz#0e9f9c507e55d8396002f644b43ef27cc9ff1289" + integrity sha512-W7KCgNBgdBIMagOxy5J5KQPe+maYxSqfE8a5ncQ3R8BcZDQEKnkW/1FplNbfRLZqA/tL/ndKb7pTPqVtzsbARw== dependencies: - "@sentry/types" "6.15.0" - "@sentry/utils" "6.15.0" + "@sentry/types" "6.19.2" + "@sentry/utils" "6.19.2" tslib "^1.9.3" -"@sentry/integrations@6.15.0": - version "6.15.0" - resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-6.15.0.tgz#3c83617c301b5f77a57514ad7812aedc03613a31" - integrity sha512-fSBAipas6zwyYo4U91pyQOnaTcRCfwvH6ZFwu0Fqmkm64nU9rYpbTNiKkwOWbbiXXT6+LEF6RzBpsyhm4QvgmQ== +"@sentry/integrations@6.19.2": + version "6.19.2" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-6.19.2.tgz#d5abcab94ae23ada097eb454c269e9ab573e14bb" + integrity sha512-RjkZXPrtrM+lJVEa4OpZ9CYjJdkpPoWslEQzLMvbaRpURpHFqmABGtXRAnJRYKmy6h7/9q9sABcDgCD4OZw11g== dependencies: - "@sentry/types" "6.15.0" - "@sentry/utils" "6.15.0" + "@sentry/types" "6.19.2" + "@sentry/utils" "6.19.2" localforage "^1.8.1" tslib "^1.9.3" -"@sentry/minimal@6.15.0": - version "6.15.0" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.15.0.tgz#fcc083ba901cfe57d25303d0b5fa8cd13e164466" - integrity sha512-7RJIvZsjBa1qFUfMrAzQsWdfZT6Gm4t6ZTYfkpsXPBA35hkzglKbBrhhsUvkxGIhUGw/PiCUqxBUjcmzQP0vfg== +"@sentry/minimal@6.19.2": + version "6.19.2" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.19.2.tgz#e748541e4adbc7e80a3b6ccaf01b631c17fc44b4" + integrity sha512-ClwxKm77iDHET7kpzv1JvzDx1er5DoNu+EUjst0kQzARIrXvu9xuZuE2/CnBWycQWqw8o3HoGoKz65uIhsUCzQ== dependencies: - "@sentry/hub" "6.15.0" - "@sentry/types" "6.15.0" + "@sentry/hub" "6.19.2" + "@sentry/types" "6.19.2" tslib "^1.9.3" -"@sentry/types@6.15.0": - version "6.15.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.15.0.tgz#a2917f8aed91471bdfd6651384ffcd47b95c43ad" - integrity sha512-zBw5gPUsofXUSpS3ZAXqRNedLRBvirl3sqkj2Lez7X2EkKRgn5D8m9fQIrig/X3TsKcXUpijDW5Buk5zeCVzJA== +"@sentry/types@6.19.2": + version "6.19.2" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.19.2.tgz#0219c9da21ed975951108b8541913b1966464435" + integrity sha512-XO5qmVBdTs+7PdCz7fAwn1afWxSnRE2KLBFg5/vOdKosPSSHsSHUURSkxiEZc2QsR+JpRB4AeQ26AkIRX38qTg== -"@sentry/utils@6.15.0": - version "6.15.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.15.0.tgz#0c247cb092b1796d39c3d16d8e6977b9cdab9ca2" - integrity sha512-gnhKKyFtnNmKWjDizo7VKD0/Vx8cgW1lCusM6WI7jy2jlO3bQA0+Dzgmr4mIReZ74mq4VpOd2Vfrx7ZldW1DMw== +"@sentry/utils@6.19.2": + version "6.19.2" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.19.2.tgz#995efb896c5159369509f4896c27a2d2ea9191f2" + integrity sha512-2DQQ2OJaxjtyxGq5FmMlqb6hptsqMs2xoBiVRMkTS/rvyTrk1oQdKZ8ePwjtgX3nJ728ni3IXIyXV+vfGp4EBw== dependencies: - "@sentry/types" "6.15.0" + "@sentry/types" "6.19.2" tslib "^1.9.3" "@types/archiver@^5.1.1": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-5.1.1.tgz#d6d7610de4386b293abd5c1cb1875e0a4f4e1c30" - integrity sha512-heuaCk0YH5m274NOLSi66H1zX6GtZoMsdE6TYFcpFFjBjg0FoU4i4/M/a/kNlgNg26Xk3g364mNOYe1JaiEPOQ== + version "5.3.1" + resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-5.3.1.tgz#02991e940a03dd1a32678fead4b4ca03d0e387ca" + integrity sha512-wKYZaSXaDvTZuInAWjCeGG7BEAgTWG2zZW0/f7IYFcoHB2X2d9lkVFnrOlXl3W6NrvO6Ml3FLLu8Uksyymcpnw== dependencies: "@types/glob" "*" @@ -1216,30 +1255,35 @@ "@types/node" "*" "@types/eslint-scope@^3.7.0": - version "3.7.1" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.1.tgz#8dc390a7b4f9dd9f1284629efce982e41612116e" - integrity sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g== + version "3.7.3" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224" + integrity sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g== dependencies: "@types/eslint" "*" "@types/estree" "*" "@types/eslint@*": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.2.0.tgz#afd0519223c29c347087542cbaee2fedc0873b16" - integrity sha512-74hbvsnc+7TEDa1z5YLSe4/q8hGYB3USNvCuzHUJrjPV6hXaq8IXcngCrHkuvFt0+8rFz7xYXrHgNayIX0UZvQ== + version "8.4.1" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.1.tgz#c48251553e8759db9e656de3efc846954ac32304" + integrity sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA== dependencies: "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*", "@types/estree@^0.0.50": +"@types/estree@*": + version "0.0.51" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" + integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== + +"@types/estree@^0.0.50": version "0.0.50" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== "@types/express-serve-static-core@^4.17.9": - version "4.17.25" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.25.tgz#e42f7046adc65ece2eb6059b77aecfbe9e9f82e0" - integrity sha512-OUJIVfRMFijZukGGwTpKNFprqCCXk5WjNGvUgB/CxxBR40QWSjsNK86+yvGKlCOGc7sbwfHLaXhkG+NsytwBaQ== + version "4.17.28" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz#c47def9f34ec81dc6328d0b1b5303d1ec98d86b8" + integrity sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig== dependencies: "@types/node" "*" "@types/qs" "*" @@ -1262,14 +1306,14 @@ hoist-non-react-statics "^3.3.0" "@types/html-minifier-terser@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.0.0.tgz#563c1c6c132cd204e71512f9c0b394ff90d3fae7" - integrity sha512-NZwaaynfs1oIoLAV1vg18e7QMVDvw+6SQrdJc8w3BwUaoroVSf6EBj/Sk4PBWGxsq0dzhA2drbsuMC1/6C6KgQ== + version "6.1.0" + resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" + integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== "@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + version "7.0.10" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.10.tgz#9b05b7896166cd00e9cbd59864853abf65d9ac23" + integrity sha512-BLO9bBq59vW3fxCpD4o0N4U+DXsvwvIcl+jofw0frQo/GrBFC+/jRZj1E7kgp6dvTyNmA4y6JCV5Id/r3mNP5A== "@types/json5@^0.0.29": version "0.0.29" @@ -1277,9 +1321,9 @@ integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= "@types/lodash@^4.14.159": - version "4.14.177" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.177.tgz#f70c0d19c30fab101cad46b52be60363c43c4578" - integrity sha512-0fDwydE2clKe9MNfvXHBHF9WEahRuj+msTuQqOmAApNORFvhMYZKNGGJdCzuhheVjMps/ti0Ak/iJPACMaevvw== + version "4.14.180" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.180.tgz#4ab7c9ddfc92ec4a887886483bc14c79fb380670" + integrity sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g== "@types/minimatch@*": version "3.0.5" @@ -1292,14 +1336,14 @@ integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== "@types/node@*": - version "16.11.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.9.tgz#879be3ad7af29f4c1a5c433421bf99fab7047185" - integrity sha512-MKmdASMf3LtPzwLyRrFjtFFZ48cMf8jmX5VRYrDQiJa8Ybu5VAmkqBWqKU8fdCwD8ysw4mQ9nrEHvzg6gunR7A== + version "17.0.23" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.23.tgz#3b41a6e643589ac6442bdbd7a4a3ded62f33f7da" + integrity sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw== "@types/node@^12.12.54": - version "12.20.37" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.37.tgz#abb38afa9d6e8a2f627a8cb52290b3c80fbe61ed" - integrity sha512-i1KGxqcvJaLQali+WuypQnXwcplhtNtjs66eNsZpp2P2FL/trJJxx/VWsM0YCL2iMoIJrbXje48lvIQAQ4p2ZA== + version "12.20.47" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.47.tgz#ca9237d51f2a2557419688511dab1c8daf475188" + integrity sha512-BzcaRsnFuznzOItW1WpQrDHM7plAa7GIDMZ6b5pnMbkqEtM/6WCOhvZar39oeMQP79gwvFUWjjptE7/KGcNqFg== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -1327,9 +1371,9 @@ integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== "@types/react-redux@^7.1.16": - version "7.1.20" - resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.20.tgz#42f0e61ababb621e12c66c96dda94c58423bd7df" - integrity sha512-q42es4c8iIeTgcnB+yJgRTTzftv3eYYvCZOh1Ckn2eX/3o5TdsQYKUWpLoLuGlcY/p+VAhV9IOEZJcWk/vfkXw== + version "7.1.23" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.23.tgz#3c2bb1bcc698ae69d70735f33c5a8e95f41ac528" + integrity sha512-D02o3FPfqQlfu2WeEYwh3x2otYd2Dk1o8wAfsA0B1C2AJEFxE663Ozu7JzuWbznGgW248NaOF6wsqCGNq9d3qw== dependencies: "@types/hoist-non-react-statics" "^3.3.0" "@types/react" "*" @@ -1337,9 +1381,9 @@ redux "^4.0.0" "@types/react@*": - version "17.0.36" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.36.tgz#0d81e0e2419e6a8e9ba6af5e3a0608e70835d7d1" - integrity sha512-CUFUp01OdfbpN/76v4koqgcpcRGT3sYOq3U3N6q0ZVGcyeP40NUdVU+EWe3hs34RNaTefiYyBzOpxBBidCc5zw== + version "17.0.43" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.43.tgz#4adc142887dd4a2601ce730bc56c3436fdb07a55" + integrity sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -1479,21 +1523,21 @@ "@xtuc/long" "4.2.2" "@webpack-cli/configtest@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.1.0.tgz#8342bef0badfb7dfd3b576f2574ab80c725be043" - integrity sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg== + version "1.1.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.1.1.tgz#9f53b1b7946a6efc2a749095a4f450e2932e8356" + integrity sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg== "@webpack-cli/info@^1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.4.0.tgz#b9179c3227ab09cbbb149aa733475fcf99430223" - integrity sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw== + version "1.4.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.4.1.tgz#2360ea1710cbbb97ff156a3f0f24556e0fc1ebea" + integrity sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA== dependencies: envinfo "^7.7.3" "@webpack-cli/serve@^1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.0.tgz#2c275aa05c895eccebbfc34cfb223c6e8bd591a2" - integrity sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA== + version "1.6.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.1.tgz#0de2875ac31b46b6c5bb1ae0a7d7f0ba5678dffe" + integrity sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw== "@xtuc/ieee754@^1.2.0": version "1.2.0" @@ -1530,10 +1574,10 @@ acorn-jsx@^5.3.1: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.4.1, acorn@^8.6.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895" - integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw== +acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" + integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== add-px-to-style@1.0.0: version "1.0.0" @@ -1578,20 +1622,15 @@ ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5: uri-js "^4.2.2" ajv@^8.0.0, ajv@^8.0.1, ajv@^8.8.0: - version "8.8.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb" - integrity sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw== + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" require-from-string "^2.0.2" uri-js "^4.2.2" -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - ansi-cyan@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873" @@ -1647,14 +1686,6 @@ ansi-wrap@0.1.0: resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768= -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - anymatch@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" @@ -1809,9 +1840,9 @@ async@^2.6.2: lodash "^4.17.14" async@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.2.tgz#2eb7671034bb2194d45d30e31e24ec7e7f9670cd" - integrity sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g== + version "3.2.3" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9" + integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g== atob@^2.1.2: version "2.1.2" @@ -1830,13 +1861,13 @@ autoprefixer@10.2.5: normalize-range "^0.1.2" postcss-value-parser "^4.1.0" -babel-loader@8.2.3: - version "8.2.3" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.3.tgz#8986b40f1a64cacfcb4b8429320085ef68b1342d" - integrity sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw== +babel-loader@8.2.4: + version "8.2.4" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.4.tgz#95f5023c791b2e9e2ca6f67b0984f39c82ff384b" + integrity sha512-8dytA3gcvPPPv4Grjhnt8b5IIiTcq/zeXOPk4iTYI0SVXcsmuGg7JtBRDp8S9X+gJfhQ8ektjXZlDu1Bb33U8A== dependencies: find-cache-dir "^3.3.1" - loader-utils "^1.4.0" + loader-utils "^2.0.0" make-dir "^3.1.0" schema-utils "^2.6.5" @@ -1853,28 +1884,28 @@ babel-plugin-inline-classnames@2.0.1: integrity sha512-Pq/jJ6hTiGiqcMmy2d4CyJcfBDeUHOdQl1t1MDWNaSKR2RxDmShSAx4Zqz6NDmFaiinaRqF8eQoTVgSRGU+McQ== babel-plugin-polyfill-corejs2@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.0.tgz#407082d0d355ba565af24126fb6cb8e9115251fd" - integrity sha512-wMDoBJ6uG4u4PNFh72Ty6t3EgfA91puCuAwKIazbQlci+ENb/UU9A3xG5lutjUIiXCIn1CY5L15r9LimiJyrSA== + version "0.3.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz#440f1b70ccfaabc6b676d196239b138f8a2cfba5" + integrity sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w== dependencies: "@babel/compat-data" "^7.13.11" - "@babel/helper-define-polyfill-provider" "^0.3.0" + "@babel/helper-define-polyfill-provider" "^0.3.1" semver "^6.1.1" -babel-plugin-polyfill-corejs3@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.4.0.tgz#0b571f4cf3d67f911512f5c04842a7b8e8263087" - integrity sha512-YxFreYwUfglYKdLUGvIF2nJEsGwj+RhWSX/ije3D2vQPOXuyMLMtg/cCGMDpOA7Nd+MwlNdnGODbd2EwUZPlsw== +babel-plugin-polyfill-corejs3@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz#aabe4b2fa04a6e038b688c5e55d44e78cd3a5f72" + integrity sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ== dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.0" - core-js-compat "^3.18.0" + "@babel/helper-define-polyfill-provider" "^0.3.1" + core-js-compat "^3.21.0" babel-plugin-polyfill-regenerator@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.0.tgz#9ebbcd7186e1a33e21c5e20cae4e7983949533be" - integrity sha512-dhAPTDLGoMW5/84wkgwiLRwMnio2i1fUe53EuvtKMv0pn2p3S8OCoV1xAzfJPl0KOX7IB89s2ib85vbYiea3jg== + version "0.3.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz#2c0678ea47c75c8cc2fbb1852278d8fb68233990" + integrity sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A== dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.0" + "@babel/helper-define-polyfill-provider" "^0.3.1" babel-plugin-transform-react-remove-prop-types@0.4.24: version "0.4.24" @@ -1975,22 +2006,22 @@ braces@^2.3.1: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.1: +braces@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== dependencies: fill-range "^7.0.1" -browserslist@^4.14.5, browserslist@^4.16.3, browserslist@^4.17.5, browserslist@^4.17.6: - version "4.18.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.18.1.tgz#60d3920f25b6860eb917c6c7b185576f4d8b017f" - integrity sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ== +browserslist@^4.14.5, browserslist@^4.16.3, browserslist@^4.17.5, browserslist@^4.19.1: + version "4.20.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" + integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== dependencies: - caniuse-lite "^1.0.30001280" - electron-to-chromium "^1.3.896" + caniuse-lite "^1.0.30001317" + electron-to-chromium "^1.4.84" escalade "^3.1.1" - node-releases "^2.0.1" + node-releases "^2.0.2" picocolors "^1.0.0" bser@2.1.1: @@ -2083,10 +2114,10 @@ camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -caniuse-lite@^1.0.30001196, caniuse-lite@^1.0.30001280: - version "1.0.30001282" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001282.tgz#38c781ee0a90ccfe1fe7fefd00e43f5ffdcb96fd" - integrity sha512-YhF/hG6nqBEllymSIjLtR2iWDDnChvhnVJqp+vloyt2tEHFG1yBR+ac2B/rOw0qOK0m0lEXU2dv4E/sMk5P9Kg== +caniuse-lite@^1.0.30001196, caniuse-lite@^1.0.30001317: + version "1.0.30001320" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001320.tgz#8397391bec389b8ccce328636499b7284ee13285" + integrity sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA== capture-exit@^2.0.0: version "2.0.0" @@ -2123,10 +2154,15 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chart.js@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.2.0.tgz#3d0a4b62b6bee428f8547db6aa68c792b130c260" - integrity sha512-Ml3R47TvOPW6gQ6T8mg/uPvyOASPpPVVF6xb7ZyHkek1c6kJIT5ScT559afXoDf6uwtpDR2BpCommkA5KT8ODg== +charcodes@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/charcodes/-/charcodes-0.2.0.tgz#5208d327e6cc05f99eb80ffc814707572d1f14e4" + integrity sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ== + +chart.js@3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.7.1.tgz#0516f690c6a8680c6c707e31a4c1807a6f400ada" + integrity sha512-8knRegQLFnPQAheZV8MjxIXc5gQEfDFD897BJgv/klO/vtIyFFmgMXrNfgrXpbTr/XbTturxRgxIXx/Y+ASJBA== chrome-trace-event@^1.0.2: version "1.0.3" @@ -2148,10 +2184,10 @@ classnames@2.3.1: resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== -clean-css@^5.1.5: - version "5.2.2" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.2.2.tgz#d3a7c6ee2511011e051719838bdcf8314dc4548d" - integrity sha512-/eR8ru5zyxKzpBLv9YZvMXgTSSQn7AdkMItMYynsFgGwTveCRVam9IUPFloE85B4vAIj05IuKmmEoV7/AQjT0w== +clean-css@^5.2.2: + version "5.2.4" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.2.4.tgz#982b058f8581adb2ae062520808fb2429bd487a4" + integrity sha512-nKseG8wCzEuji/4yrgM/5cthL9oTDc5UOQyFMvW/Q53oP6gLH690o1NbuTh6Y18nujr7BxlsFuS7gXLnLzKJGg== dependencies: source-map "~0.6.0" @@ -2160,10 +2196,10 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -clipboard@2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.8.tgz#ffc6c103dd2967a83005f3f61976aa4655a4cdba" - integrity sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ== +clipboard@2.0.10: + version "2.0.10" + resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.10.tgz#e61f6f7139ac5044c58c0484dcac9fb2a918bfd6" + integrity sha512-cz3m2YVwFz95qSEbCDi2fzLN/epEN9zXBvfgAoGkvGOJZATMl9gtTDVOtBYkx2ODUJl2kvmud7n32sV2BpYR4g== dependencies: good-listener "^1.2.2" select "^1.1.2" @@ -2257,6 +2293,11 @@ color@^0.11.0: color-convert "^1.3.0" color-string "^0.3.0" +colord@^2.9.2: + version "2.9.2" + resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1" + integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ== + colorette@^1.2.2: version "1.4.0" resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" @@ -2277,7 +2318,7 @@ commander@^7.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== -commander@^8.1.0: +commander@^8.3.0: version "8.3.0" resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== @@ -2335,18 +2376,18 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -core-js-compat@^3.18.0, core-js-compat@^3.19.1: - version "3.19.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.19.1.tgz#fe598f1a9bf37310d77c3813968e9f7c7bb99476" - integrity sha512-Q/VJ7jAF/y68+aUsQJ/afPOewdsGkDtcMb40J8MbuWKlK3Y+wtHq8bTHKPj2WKWLIqmS5JhHs4CzHtz6pT2W6g== +core-js-compat@^3.20.2, core-js-compat@^3.21.0: + version "3.21.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.21.1.tgz#cac369f67c8d134ff8f9bd1623e3bc2c42068c82" + integrity sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g== dependencies: - browserslist "^4.17.6" + browserslist "^4.19.1" semver "7.0.0" -core-js@3.11.0: - version "3.11.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.11.0.tgz#05dac6aa70c0a4ad842261f8957b961d36eb8926" - integrity sha512-bd79DPpx+1Ilh9+30aT5O1sgpQd4Ttg8oqkqi51ZzhedMM1omD2e6IOF48Z/DzDCZ2svp49tN/3vneTK6ZBkXw== +core-js@3.21.1: + version "3.21.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.21.1.tgz#f2e0ddc1fc43da6f904706e8e955bc19d06a0d94" + integrity sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig== core-js@^2.4.0: version "2.6.12" @@ -2395,12 +2436,12 @@ cpy@^8.1.2: p-map "^3.0.0" crc-32@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208" - integrity sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA== + version "1.2.1" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.1.tgz#436d2bcaad27bcb6bd073a2587139d3024a16460" + integrity sha512-Dn/xm/1vFFgs3nfrpEVScHoIslO9NZRITWGz/1E/St6u4xw99vfZzVkW0OSnzx2h9egej9xwMCEut6sqwokM/w== dependencies: exit-on-epipe "~1.0.1" - printj "~1.1.0" + printj "~1.3.1" crc32-stream@^4.0.2: version "4.0.2" @@ -2418,18 +2459,7 @@ create-react-context@^0.3.0: gud "^1.0.0" warning "^4.0.3" -cross-spawn@^6.0.0: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -2448,6 +2478,11 @@ css-color-function@~1.3.3: debug "^3.1.0" rgb "~0.1.0" +css-functions-list@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.0.1.tgz#1460df7fb584d1692c30b105151dbb988c8094f9" + integrity sha512-PriDuifDt4u4rkDgnqRCLnjfMatufLmWNfQnGCq34xZwpY3oabwhB9SqRBmuvWUgndbemCFlKqg+nO7C2q0SBw== + css-loader@6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.5.1.tgz#0c43d4fbe0d97f699c91e9818cb585759091d1b1" @@ -2463,17 +2498,17 @@ css-loader@6.5.1: semver "^7.3.5" css-select@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" - integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA== + version "4.2.1" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.2.1.tgz#9e665d6ae4c7f9d65dbe69d0316e3221fb274cdd" + integrity sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ== dependencies: boolbase "^1.0.0" - css-what "^5.0.0" - domhandler "^4.2.0" - domutils "^2.6.0" - nth-check "^2.0.0" + css-what "^5.1.0" + domhandler "^4.3.0" + domutils "^2.8.0" + nth-check "^2.0.1" -css-what@^5.0.0: +css-what@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw== @@ -2484,9 +2519,9 @@ cssesc@^3.0.0: integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== csstype@^3.0.2: - version "3.0.10" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" - integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== + version "3.0.11" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33" + integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw== cuint@^0.2.2: version "0.2.2" @@ -2507,10 +2542,10 @@ debug@^3.1.0, debug@^3.1.1, debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.1.0, debug@^4.1.1, debug@^4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== +debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" @@ -2686,14 +2721,14 @@ domelementtype@^2.0.1, domelementtype@^2.2.0: resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== -domhandler@^4.0.0, domhandler@^4.2.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.2.tgz#e825d721d19a86b8c201a35264e226c678ee755f" - integrity sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w== +domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" + integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== dependencies: domelementtype "^2.2.0" -domutils@^2.5.2, domutils@^2.6.0: +domutils@^2.5.2, domutils@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== @@ -2710,10 +2745,10 @@ dot-case@^3.0.4: no-case "^3.0.4" tslib "^2.0.3" -electron-to-chromium@^1.3.896: - version "1.3.904" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.904.tgz#52a353994faeb0f2a9fab3606b4e0614d1af7b58" - integrity sha512-x5uZWXcVNYkTh4JubD7KSC1VMKz0vZwJUqVwY3ihsW0bst1BXDe494Uqbg3Y0fDGVjJqA8vEeGuvO5foyH2+qw== +electron-to-chromium@^1.4.84: + version "1.4.92" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.92.tgz#88996e9aceb3a500710fd439abfa89b6cc1ac56c" + integrity sha512-YAVbvQIcDE/IJ/vzDMjD484/hsRbFPW2qXJPaYTfOhtligmfYEYOep+5QojpaEU9kq6bMvNeC2aG7arYvTHYsA== element-class@0.2.2: version "0.2.2" @@ -2738,20 +2773,13 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: once "^1.4.0" enhanced-resolve@^5.8.3: - version "5.8.3" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0" - integrity sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA== + version "5.9.2" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz#0224dcd6a43389ebfb2d55efee517e5466772dd9" + integrity sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" -enquirer@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - entities@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" @@ -2851,14 +2879,13 @@ eslint-import-resolver-node@^0.3.6: debug "^3.2.7" resolve "^1.20.0" -eslint-module-utils@^2.7.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz#b435001c9f8dd4ab7f6d0efcae4b9696d4c24b7c" - integrity sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ== +eslint-module-utils@^2.7.2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" + integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== dependencies: debug "^3.2.7" find-up "^2.1.0" - pkg-dir "^2.0.0" eslint-plugin-filenames@1.3.2: version "1.3.2" @@ -2870,41 +2897,41 @@ eslint-plugin-filenames@1.3.2: lodash.snakecase "4.1.1" lodash.upperfirst "4.3.1" -eslint-plugin-import@2.25.3: - version "2.25.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz#a554b5f66e08fb4f6dc99221866e57cfff824766" - integrity sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg== +eslint-plugin-import@2.25.4: + version "2.25.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1" + integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA== dependencies: array-includes "^3.1.4" array.prototype.flat "^1.2.5" debug "^2.6.9" doctrine "^2.1.0" eslint-import-resolver-node "^0.3.6" - eslint-module-utils "^2.7.1" + eslint-module-utils "^2.7.2" has "^1.0.3" is-core-module "^2.8.0" is-glob "^4.0.3" minimatch "^3.0.4" object.values "^1.1.5" resolve "^1.20.0" - tsconfig-paths "^3.11.0" + tsconfig-paths "^3.12.0" -eslint-plugin-react@7.27.1: - version "7.27.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.27.1.tgz#469202442506616f77a854d91babaae1ec174b45" - integrity sha512-meyunDjMMYeWr/4EBLTV1op3iSG3mjT/pz5gti38UzfM4OPpNc2m0t2xvKCOMU5D6FSdd34BIMFOvQbW+i8GAA== +eslint-plugin-react@7.29.4: + version "7.29.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.29.4.tgz#4717de5227f55f3801a5fd51a16a4fa22b5914d2" + integrity sha512-CVCXajliVh509PcZYRFyu/BoUEz452+jtQJq2b3Bae4v3xBUWPLCmtmBM+ZinG4MzwmxJgJ2M5rMqhqLVn7MtQ== dependencies: array-includes "^3.1.4" array.prototype.flatmap "^1.2.5" doctrine "^2.1.0" estraverse "^5.3.0" jsx-ast-utils "^2.4.1 || ^3.0.0" - minimatch "^3.0.4" + minimatch "^3.1.2" object.entries "^1.1.5" object.fromentries "^2.0.5" object.hasown "^1.1.0" object.values "^1.1.5" - prop-types "^15.7.2" + prop-types "^15.8.1" resolve "^2.0.0-next.3" semver "^6.3.0" string.prototype.matchall "^4.0.6" @@ -2922,10 +2949,10 @@ eslint-scope@5.1.1, eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.0.tgz#c1f6ea30ac583031f203d65c73e723b01298f153" - integrity sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg== +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" @@ -2942,29 +2969,28 @@ eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz#eee4acea891814cda67a7d8812d9647dd0179af2" - integrity sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA== +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.3.0.tgz#a3c2409507403c1c7f6c42926111d6cbefbc3e85" - integrity sha512-aIay56Ph6RxOTC7xyr59Kt3ewX185SaGnAr8eWukoPLeriCrvGjvAubxuvaXOfsxhtwV5g0uBOsyhAom4qJdww== +eslint@8.11.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.11.0.tgz#88b91cfba1356fc10bb9eb592958457dfe09fb37" + integrity sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA== dependencies: - "@eslint/eslintrc" "^1.0.4" - "@humanwhocodes/config-array" "^0.6.0" + "@eslint/eslintrc" "^1.2.1" + "@humanwhocodes/config-array" "^0.9.2" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" doctrine "^3.0.0" - enquirer "^2.3.5" escape-string-regexp "^4.0.0" - eslint-scope "^7.1.0" + eslint-scope "^7.1.1" eslint-utils "^3.0.0" - eslint-visitor-keys "^3.1.0" - espree "^9.1.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.1" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -2972,7 +2998,7 @@ eslint@8.3.0: functional-red-black-tree "^1.0.1" glob-parent "^6.0.1" globals "^13.6.0" - ignore "^4.0.6" + ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" @@ -2983,34 +3009,32 @@ eslint@8.3.0: minimatch "^3.0.4" natural-compare "^1.4.0" optionator "^0.9.1" - progress "^2.0.0" regexpp "^3.2.0" - semver "^7.2.1" strip-ansi "^6.0.1" strip-json-comments "^3.1.0" text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^9.0.0, espree@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.1.0.tgz#ba9d3c9b34eeae205724124e31de4543d59fbf74" - integrity sha512-ZgYLvCS1wxOczBYGcQT9DDWgicXwJ4dbocr9uYN+/eresBAUuBu+O4WzB21ufQ/JqQT8gyp7hJ3z8SHii32mTQ== +espree@^9.3.1: + version "9.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd" + integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ== dependencies: - acorn "^8.6.0" + acorn "^8.7.0" acorn-jsx "^5.3.1" - eslint-visitor-keys "^3.1.0" + eslint-visitor-keys "^3.3.0" -esprint@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/esprint/-/esprint-3.1.0.tgz#ec5d59c24d66bbe06fe8c64266718c7cfd92de5d" - integrity sha512-UfD6iLycX/bZHxDJW3bfYTNj+RyD89nS6fVx57yS6tuup5ymUxGzopEwhwK2q8D0HKn0pxwaEwTjxBAfH7WggQ== +esprint@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/esprint/-/esprint-3.3.0.tgz#ed0e31f536ac647fc10171cca9575c08b922bcc2" + integrity sha512-JcfyfU5SfsofQKj6D9rET99IX3SuthuL21Ltc8yIiqHK4XNEGBM1d2XSlZqht4LGAr/ilgNjDf+yLZJ4OKFOvA== dependencies: fb-watchman "^2.0.1" - glob "^7.1.7" - jayson "^3.6.3" - jest-worker "^27.0.2" - sane "^4.1.0" - yargs "^17.0.1" + glob "^7.2.0" + jayson "^3.6.6" + jest-worker "^27.4.6" + sane "^5.0.1" + yargs "^17.3.1" esquery@^1.4.0: version "1.4.0" @@ -3058,23 +3082,25 @@ eventsource@^1.0.7: dependencies: original "^1.0.0" -exec-sh@^0.3.2: +exec-sh@^0.3.2, exec-sh@^0.3.4: version "0.3.6" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== +execa@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" execa@^5.0.0: version "5.1.1" @@ -3184,10 +3210,10 @@ fast-glob@^2.2.6: merge2 "^1.2.3" micromatch "^3.1.10" -fast-glob@^3.1.1, fast-glob@^3.2.7: - version "3.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" - integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== +fast-glob@^3.2.11, fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -3224,7 +3250,7 @@ faye-websocket@~0.10.0: dependencies: websocket-driver ">=0.5.1" -fb-watchman@^2.0.0, fb-watchman@^2.0.1: +fb-watchman@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== @@ -3321,9 +3347,9 @@ flat-cache@^3.0.4: rimraf "^3.0.2" flatted@^3.1.0: - version "3.2.4" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2" - integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw== + version "3.2.5" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" + integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== focus-lock@^0.8.1: version "0.8.1" @@ -3338,9 +3364,9 @@ for-in@^1.0.2: integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= fraction.js@^4.0.13: - version "4.1.2" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.2.tgz#13e420a92422b6cf244dff8690ed89401029fbe8" - integrity sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA== + version "4.2.0" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" + integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== fragment-cache@^0.2.1: version "0.2.1" @@ -3355,9 +3381,9 @@ fs-constants@^1.0.0: integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== fs-extra@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" - integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ== + version "10.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.1.tgz#27de43b4320e833f6867cc044bfce29fdf0ef3b8" + integrity sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag== dependencies: graceful-fs "^4.2.0" jsonfile "^6.0.1" @@ -3407,10 +3433,10 @@ get-stdin@^8.0.0: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== -get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== +get-stream@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== dependencies: pump "^3.0.0" @@ -3464,7 +3490,7 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@^7.1.3, glob@^7.1.4, glob@^7.1.7: +glob@^7.1.3, glob@^7.1.4, glob@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== @@ -3498,22 +3524,22 @@ globals@^11.1.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.6.0, globals@^13.9.0: - version "13.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" - integrity sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg== + version "13.13.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.13.0.tgz#ac32261060d8070e2719dd6998406e27d2b5727b" + integrity sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A== dependencies: type-fest "^0.20.2" -globby@^11.0.1, globby@^11.0.3, globby@^11.0.4: - version "11.0.4" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" - integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== +globby@^11.0.1, globby@^11.0.3, globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== dependencies: array-union "^2.1.0" dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" slash "^3.0.0" globby@^9.2.0: @@ -3543,9 +3569,9 @@ good-listener@^1.2.2: delegate "^3.1.2" graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: - version "4.2.8" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" - integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== + version "4.2.9" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" + integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== gud@^1.0.0: version "1.0.0" @@ -3586,10 +3612,10 @@ has-glob@^1.0.0: dependencies: is-glob "^3.0.0" -has-symbols@^1.0.1, has-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" - integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== +has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== has-tostringtag@^1.0.0: version "1.0.0" @@ -3666,24 +3692,24 @@ hosted-git-info@^2.1.4: integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== hosted-git-info@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961" - integrity sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg== + version "4.1.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" + integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== dependencies: lru-cache "^6.0.0" html-minifier-terser@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.0.2.tgz#14059ad64b69bf9f8b8a33f25b53411d8321e75d" - integrity sha512-AgYO3UGhMYQx2S/FBJT3EM0ZYcKmH6m9XL9c1v77BeK/tYJxGPxT1/AtsdUi4FcP8kZGmqqnItCcjFPcX9hk6A== + version "6.1.0" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab" + integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw== dependencies: camel-case "^4.1.2" - clean-css "^5.1.5" - commander "^8.1.0" + clean-css "^5.2.2" + commander "^8.3.0" he "^1.2.0" param-case "^3.0.4" relateurl "^0.2.7" - terser "^5.7.2" + terser "^5.10.0" html-tags@^3.1.0: version "3.1.0" @@ -3712,15 +3738,20 @@ htmlparser2@^6.1.0: entities "^2.0.0" http-parser-js@>=0.5.1: - version "0.5.3" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9" - integrity sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg== + version "0.5.6" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.6.tgz#2e02406ab2df8af8a7abfba62e0da01c62b95afd" + integrity sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA== https-browserify@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= +human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + human-signals@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" @@ -3736,15 +3767,15 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^4.0.3, ignore@^4.0.6: +ignore@^4.0.3: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.4, ignore@^5.1.9: - version "5.1.9" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.9.tgz#9ec1a5cbe8e1446ec60d4420060d43aa6e7382fb" - integrity sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ== +ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== immediate@~3.0.5: version "3.0.6" @@ -3770,9 +3801,9 @@ import-lazy@^4.0.0: integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== import-local@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.3.tgz#4d51c2c495ca9393da259ec66b62e022920211e0" - integrity sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA== + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== dependencies: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" @@ -3878,10 +3909,10 @@ is-callable@^1.1.4, is-callable@^1.2.4: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== -is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" - integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== +is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.8.0, is-core-module@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" + integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== dependencies: has "^1.0.3" @@ -3961,9 +3992,9 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: is-extglob "^2.1.1" is-negative-zero@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" - integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== is-number-object@^1.0.4: version "1.0.6" @@ -4029,11 +4060,6 @@ is-shared-array-buffer@^1.0.1: resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - is-stream@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" @@ -4053,17 +4079,12 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typedarray@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - is-weakref@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.1.tgz#842dba4ec17fa9ac9850df2d6efbc1737274f2a2" - integrity sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ== + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" is-windows@^1.0.2: version "1.0.2" @@ -4107,10 +4128,10 @@ isstream@^0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -jayson@^3.6.3: - version "3.6.5" - resolved "https://registry.yarnpkg.com/jayson/-/jayson-3.6.5.tgz#e560bcad4daf098c7391f46ba8efc9d6f34a4102" - integrity sha512-wmOjX+eQcnCDyPF4KORomaIj9wj3h0B5VEbeD0+2VHfTfErB+h1zpR7oBkgCZp36AFjp3+a4CLz6U72BYpFHAw== +jayson@^3.6.6: + version "3.6.6" + resolved "https://registry.yarnpkg.com/jayson/-/jayson-3.6.6.tgz#189984f624e398f831bd2be8e8c80eb3abf764a1" + integrity sha512-f71uvrAWTtrwoww6MKcl9phQTC+56AopLyEenWvKVAIMz+q0oVGj6tenLZ7Z6UiPBkJtKLj4kt0tACllFQruGQ== dependencies: "@types/connect" "^3.4.33" "@types/express-serve-static-core" "^4.17.9" @@ -4125,7 +4146,7 @@ jayson@^3.6.3: isomorphic-ws "^4.0.1" json-stringify-safe "^5.0.1" lodash "^4.17.20" - uuid "^3.4.0" + uuid "^8.3.2" ws "^7.4.5" jdu@1.0.0: @@ -4133,10 +4154,10 @@ jdu@1.0.0: resolved "https://registry.yarnpkg.com/jdu/-/jdu-1.0.0.tgz#28f1e388501785ae0a1d93e93ed0b14dd41e51ce" integrity sha1-KPHjiFAXha4KHZPpPtCxTdQeUc4= -jest-worker@^27.0.2, jest-worker@^27.0.6: - version "27.3.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.3.1.tgz#0def7feae5b8042be38479799aeb7b5facac24b2" - integrity sha512-ks3WCzsiZaOPJl/oMsDjaf0TRiSv7ctNgs0FqRr2nARsovz6AWWy4oLElwcquGSz692DzgZQrCLScPNs5YlC4g== +jest-worker@^27.4.5, jest-worker@^27.4.6: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== dependencies: "@types/node" "*" merge-stream "^2.0.0" @@ -4207,11 +4228,9 @@ json5@^1.0.1: minimist "^1.2.0" json5@^2.1.2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== jsonfile@^6.0.1: version "6.1.0" @@ -4279,10 +4298,10 @@ klona@^2.0.4: resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== -known-css-properties@^0.23.0: - version "0.23.0" - resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.23.0.tgz#e643e1bab2b1f8ba292eea9557121cc02e9846a0" - integrity sha512-h9ivI88e1lFNmTT4HovBN33Ysn0OIJG7IPG2mkpx2uniQXFWqo35QdiX7w0TovlUFXfW8aPFblP5/q0jlOr2sA== +known-css-properties@^0.24.0: + version "0.24.0" + resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.24.0.tgz#19aefd85003ae5698a5560d2b55135bf5432155c" + integrity sha512-RTSoaUAfLvpR357vWzAz/50Q/BmHfmE6ETSWfutT0AJiw10e6CmcdYRQJlLRd95B53D0Y2aD1jSxD3V3ySF+PA== lazystream@^1.0.0: version "1.0.1" @@ -4326,15 +4345,6 @@ loader-runner@^4.2.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== -loader-utils@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" - integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^1.0.1" - loader-utils@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" @@ -4526,12 +4536,12 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.2.3, merge2@^1.3.0: +merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromatch@^3.1.10, micromatch@^3.1.4: +micromatch@^3.1.10: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -4550,25 +4560,25 @@ micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== +micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== dependencies: - braces "^3.0.1" - picomatch "^2.2.3" + braces "^3.0.2" + picomatch "^2.3.1" -mime-db@1.51.0: - version "1.51.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" - integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== mime-types@^2.1.27: - version "2.1.34" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" - integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: - mime-db "1.51.0" + mime-db "1.52.0" mime@~2.5.2: version "2.5.2" @@ -4600,10 +4610,17 @@ mini-css-extract-plugin@2.4.5: dependencies: schema-utils "^4.0.0" -minimatch@^3.0.4, minimatch@~3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== +minimatch@^3.0.4, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@~3.0.4: + version "3.0.8" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.8.tgz#5e6a59bd11e2ab0de1cfb843eb2d82e546c321c1" + integrity sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q== dependencies: brace-expansion "^1.1.7" @@ -4616,10 +4633,10 @@ minimist-options@4.1.0: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mixin-deep@^1.2.0: version "1.3.2" @@ -4630,11 +4647,11 @@ mixin-deep@^1.2.0: is-extendable "^1.0.1" mkdirp@^0.5.5: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: - minimist "^1.2.5" + minimist "^1.2.6" mobile-detect@1.4.5: version "1.4.5" @@ -4666,10 +4683,10 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nanoid@^3.1.30: - version "3.1.30" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" - integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ== +nanoid@^3.1.30, nanoid@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" + integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== nanomatch@^1.2.9: version "1.2.13" @@ -4703,11 +4720,6 @@ nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0: resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - no-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" @@ -4717,9 +4729,9 @@ no-case@^3.0.4: tslib "^2.0.3" node-fetch@^2.6.1: - version "2.6.6" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89" - integrity sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA== + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: whatwg-url "^5.0.0" @@ -4728,10 +4740,10 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= -node-releases@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" - integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== +node-releases@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" + integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg== normalize-package-data@^2.5.0: version "2.5.0" @@ -4753,13 +4765,6 @@ normalize-package-data@^3.0.0: semver "^7.3.4" validate-npm-package-license "^3.0.1" -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - normalize-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" @@ -4780,21 +4785,14 @@ normalize.css@8.0.1: resolved "https://registry.yarnpkg.com/normalize.css/-/normalize.css-8.0.1.tgz#9b98a208738b9cc2634caacbc42d131c97487bf3" integrity sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg== -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - -npm-run-path@^4.0.1: +npm-run-path@^4.0.0, npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== dependencies: path-key "^3.0.0" -nth-check@^2.0.0: +nth-check@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== @@ -4821,9 +4819,9 @@ object-copy@^0.1.0: kind-of "^3.0.3" object-inspect@^1.11.0, object-inspect@^1.9.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" - integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== + version "1.12.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" + integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== object-is@^1.0.1: version "1.1.5" @@ -4904,7 +4902,7 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -onetime@^5.1.2: +onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== @@ -5083,17 +5081,12 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.6: +path-parse@^1.0.6, path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== @@ -5127,10 +5120,10 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" - integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== +picomatch@^2.0.4, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pify@^3.0.0: version "3.0.0" @@ -5142,13 +5135,6 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - dependencies: - find-up "^2.1.0" - pkg-dir@^4.1.0, pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" @@ -5278,10 +5264,10 @@ postcss-safe-parser@^6.0.0: resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz#bb4c29894171a94bc5c996b9a30317ef402adaa1" integrity sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ== -postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.6: - version "6.0.6" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" - integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.6, postcss-selector-parser@^6.0.9: + version "6.0.9" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz#ee71c3b9ff63d9cd130838876c13a2ec1a992b2f" + integrity sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ== dependencies: cssesc "^3.0.0" util-deprecate "^1.0.2" @@ -5311,12 +5297,12 @@ postcss-value-parser@^3.3.1: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== -postcss-value-parser@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" - integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== +postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@8.3.11, postcss@^8.1.6, postcss@^8.2.15, postcss@^8.3.11: +postcss@8.3.11: version "8.3.11" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.11.tgz#c3beca7ea811cd5e1c4a3ec6d2e7599ef1f8f858" integrity sha512-hCmlUAIlUiav8Xdqw3Io4LcpA1DOt7h3LSTAC4G6JGHFFaWzI6qvFt9oilvl8BmkbBRX1IhM90ZAmpk68zccQA== @@ -5334,6 +5320,15 @@ postcss@^6.0.23: source-map "^0.6.1" supports-color "^5.4.0" +postcss@^8.1.6, postcss@^8.2.15, postcss@^8.3.11, postcss@^8.4.12: + version "8.4.12" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905" + integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg== + dependencies: + nanoid "^3.3.1" + picocolors "^1.0.0" + source-map-js "^1.0.2" + prefix-style@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/prefix-style/-/prefix-style-2.0.1.tgz#66bba9a870cfda308a5dc20e85e9120932c95a06" @@ -5352,29 +5347,24 @@ pretty-error@^4.0.0: lodash "^4.17.20" renderkid "^3.0.0" -printj@~1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" - integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ== +printj@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/printj/-/printj-1.3.1.tgz#9af6b1d55647a1587ac44f4c1654a4b95b8e12cb" + integrity sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg== process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -prop-types@15.7.2, prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: - version "15.7.2" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== +prop-types@15.8.1, prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== dependencies: loose-envify "^1.4.0" object-assign "^4.1.1" - react-is "^16.8.1" + react-is "^16.13.1" psl@^1.1.33: version "1.8.0" @@ -5394,10 +5384,10 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@6.10.1, qs@^6.4.0: - version "6.10.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a" - integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg== +qs@6.10.3, qs@^6.4.0: + version "6.10.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" + integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== dependencies: side-channel "^1.0.4" @@ -5471,10 +5461,10 @@ react-clientside-effect@^1.2.2: dependencies: "@babel/runtime" "^7.12.13" -react-custom-scrollbars@4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/react-custom-scrollbars/-/react-custom-scrollbars-4.2.1.tgz#830fd9502927e97e8a78c2086813899b2a8b66db" - integrity sha1-gw/ZUCkn6X6KeMIIaBOJmyqLZts= +react-custom-scrollbars-2@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/react-custom-scrollbars-2/-/react-custom-scrollbars-2-4.4.0.tgz#6cc237abc18f5ab32b5392b336e6f072c2b4cfc1" + integrity sha512-I+oxZ9rfHfvYm85jdH2lQqpzwNr/ZAdYB8htm6R/hwRGoIEK31jq+YE6MmFwBzuO7C5zcAtH5HN9vwZxnW61NQ== dependencies: dom-css "^2.0.0" prop-types "^15.5.10" @@ -5559,7 +5549,7 @@ react-google-recaptcha@2.1.0: prop-types "^15.5.0" react-async-script "^1.1.1" -react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: +react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -5780,10 +5770,10 @@ redux@^4.0.0, redux@^4.1.1: dependencies: "@babel/runtime" "^7.9.2" -regenerate-unicode-properties@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326" - integrity sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA== +regenerate-unicode-properties@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz#7f442732aa7934a3740c779bb9b3340dccc1fb56" + integrity sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw== dependencies: regenerate "^1.4.2" @@ -5817,10 +5807,10 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" - integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== +regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz#b3f4c0059af9e47eca9f3f660e51d81307e72307" + integrity sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" @@ -5830,27 +5820,27 @@ regexpp@^3.2.0: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== -regexpu-core@^4.7.1: - version "4.8.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.8.0.tgz#e5605ba361b67b1718478501327502f4479a98f0" - integrity sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg== +regexpu-core@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.0.1.tgz#c531122a7840de743dcf9c83e923b5560323ced3" + integrity sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw== dependencies: regenerate "^1.4.2" - regenerate-unicode-properties "^9.0.0" - regjsgen "^0.5.2" - regjsparser "^0.7.0" + regenerate-unicode-properties "^10.0.1" + regjsgen "^0.6.0" + regjsparser "^0.8.2" unicode-match-property-ecmascript "^2.0.0" unicode-match-property-value-ecmascript "^2.0.0" -regjsgen@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" - integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== +regjsgen@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.6.0.tgz#83414c5354afd7d6627b16af5f10f41c4e71808d" + integrity sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA== -regjsparser@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.7.0.tgz#a6b667b54c885e18b52554cb4960ef71187e9968" - integrity sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ== +regjsparser@^0.8.2: + version "0.8.4" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.8.4.tgz#8a14285ffcc5de78c5b95d62bbf413b6bc132d5f" + integrity sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA== dependencies: jsesc "~0.5.0" @@ -5859,11 +5849,6 @@ relateurl@^0.2.7: resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - renderkid@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a" @@ -5943,12 +5928,13 @@ resolve-url@^0.2.1: integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.9.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" - integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== + version "1.22.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" + integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" + is-core-module "^2.8.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" resolve@^2.0.0-next.3: version "2.0.0-next.3" @@ -6023,18 +6009,18 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -sane@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" - integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== +sane@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/sane/-/sane-5.0.1.tgz#ae94cb06acf5ad158242ff23f563d8cbe0ec1e4b" + integrity sha512-9/0CYoRz0MKKf04OMCO3Qk3RQl1PAwWAhPSQSym4ULiLpTZnrY1JoZU0IEikHu8kdk2HvKT/VwQMq/xFZ8kh1Q== dependencies: "@cnakazawa/watch" "^1.0.3" - anymatch "^2.0.0" + anymatch "^3.1.1" capture-exit "^2.0.0" - exec-sh "^0.3.2" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" + exec-sh "^0.3.4" + execa "^4.0.0" + fb-watchman "^2.0.1" + micromatch "^4.0.2" minimist "^1.1.1" walker "~1.0.5" @@ -6089,7 +6075,7 @@ select@^1.1.2: resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= -"semver@2 || 3 || 4 || 5", semver@^5.5.0: +"semver@2 || 3 || 4 || 5": version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -6104,7 +6090,7 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.4, semver@^7.3.5: +semver@^7.3.4, semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== @@ -6145,13 +6131,6 @@ shallowequal@^1.0.1: resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -6159,11 +6138,6 @@ shebang-command@^2.0.0: dependencies: shebang-regex "^3.0.0" -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - shebang-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" @@ -6178,10 +6152,10 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: - version "3.0.6" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" - integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== +signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== slash@^2.0.0: version "2.0.0" @@ -6237,6 +6211,11 @@ source-map-js@^0.6.2: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug== +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" @@ -6345,17 +6324,17 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: strip-ansi "^6.0.1" string.prototype.matchall@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" - integrity sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg== + version "4.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d" + integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" es-abstract "^1.19.1" get-intrinsic "^1.1.1" - has-symbols "^1.0.2" + has-symbols "^1.0.3" internal-slot "^1.0.3" - regexp.prototype.flags "^1.3.1" + regexp.prototype.flags "^1.4.1" side-channel "^1.0.4" string.prototype.trimend@^1.0.4: @@ -6412,11 +6391,6 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - strip-final-newline@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" @@ -6452,49 +6426,52 @@ stylelint-order@5.0.0: postcss "^8.3.11" postcss-sorting "^7.0.1" -stylelint@14.1.0: - version "14.1.0" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.1.0.tgz#8cefb64df6158b30f678c2d93a7052e2c1d8235b" - integrity sha512-IedkssuNVA11+v++2PIV2OHOU5A3SfRcXVi56vZVSsMhGrgtwmmit69jeM+08/Tun5DTBe7BuH1Zp1mMLmtKLA== +stylelint@14.6.0: + version "14.6.0" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.6.0.tgz#bf577103c8a1d47cd8818469e27db77b83ab3cc1" + integrity sha512-Xk2sqXYPi9nXgq70nBiZkbQm/QOOKd83NBTaBE1fXEWAEeRlgHnKC/E7kJFlT6K0SaNDOK5yIvR7GFPGsNLuOg== dependencies: balanced-match "^2.0.0" + colord "^2.9.2" cosmiconfig "^7.0.1" - debug "^4.3.2" + css-functions-list "^3.0.1" + debug "^4.3.3" execall "^2.0.0" - fast-glob "^3.2.7" + fast-glob "^3.2.11" fastest-levenshtein "^1.0.12" file-entry-cache "^6.0.1" get-stdin "^8.0.0" global-modules "^2.0.0" - globby "^11.0.4" + globby "^11.1.0" globjoin "^0.1.4" html-tags "^3.1.0" - ignore "^5.1.9" + ignore "^5.2.0" import-lazy "^4.0.0" imurmurhash "^0.1.4" is-plain-object "^5.0.0" - known-css-properties "^0.23.0" + known-css-properties "^0.24.0" mathml-tag-names "^2.1.3" meow "^9.0.0" micromatch "^4.0.4" normalize-path "^3.0.0" normalize-selector "^0.2.0" picocolors "^1.0.0" - postcss "^8.3.11" + postcss "^8.4.12" postcss-media-query-parser "^0.2.3" postcss-resolve-nested-selector "^0.1.1" postcss-safe-parser "^6.0.0" - postcss-selector-parser "^6.0.6" - postcss-value-parser "^4.1.0" + postcss-selector-parser "^6.0.9" + postcss-value-parser "^4.2.0" resolve-from "^5.0.0" specificity "^0.4.1" string-width "^4.2.3" strip-ansi "^6.0.1" style-search "^0.1.0" + supports-hyperlinks "^2.2.0" svg-tags "^1.0.0" - table "^6.7.3" + table "^6.8.0" v8-compile-cache "^2.3.0" - write-file-atomic "^3.0.3" + write-file-atomic "^4.0.1" sugarss@^3.0.3: version "3.0.3" @@ -6515,7 +6492,7 @@ supports-color@^5.3.0, supports-color@^5.4.0: dependencies: has-flag "^3.0.0" -supports-color@^7.1.0: +supports-color@^7.0.0, supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -6529,15 +6506,28 @@ supports-color@^8.0.0: dependencies: has-flag "^4.0.0" +supports-hyperlinks@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + svg-tags@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= -table@^6.7.3: - version "6.7.3" - resolved "https://registry.yarnpkg.com/table/-/table-6.7.3.tgz#255388439715a738391bd2ee4cbca89a4d05a9b7" - integrity sha512-5DkIxeA7XERBqMwJq0aHZOdMadBx4e6eDoFRuyT5VR82J0Ycg2DwM6GfA/EQAhJ+toRTaS1lIdSQCqgrmhPnlw== +table@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca" + integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA== dependencies: ajv "^8.0.1" lodash.truncate "^4.4.2" @@ -6562,21 +6552,22 @@ tar-stream@^2.2.0: readable-stream "^3.1.1" terser-webpack-plugin@^5.1.3: - version "5.2.5" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.2.5.tgz#ce65b9880a0c36872555c4874f45bbdb02ee32c9" - integrity sha512-3luOVHku5l0QBeYS8r4CdHYWEGMmIj3H1U64jgkdZzECcSOJAyJ9TjuqcQZvw1Y+4AOBN9SeYJPJmFn2cM4/2g== + version "5.3.1" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz#0320dcc270ad5372c1e8993fabbd927929773e54" + integrity sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g== dependencies: - jest-worker "^27.0.6" + jest-worker "^27.4.5" schema-utils "^3.1.1" serialize-javascript "^6.0.0" source-map "^0.6.1" terser "^5.7.2" -terser@^5.7.2: - version "5.10.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" - integrity sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA== +terser@^5.10.0, terser@^5.7.2: + version "5.12.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.12.1.tgz#4cf2ebed1f5bceef5c83b9f60104ac4a78b49e9c" + integrity sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ== dependencies: + acorn "^8.5.0" commander "^2.20.0" source-map "~0.7.2" source-map-support "~0.5.20" @@ -6703,14 +6694,14 @@ trim-newlines@^3.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== -tsconfig-paths@^3.11.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b" - integrity sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg== +tsconfig-paths@^3.12.0: + version "3.14.1" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" + integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.1" - minimist "^1.2.0" + minimist "^1.2.6" strip-bom "^3.0.0" tslib@^1.9.3: @@ -6755,13 +6746,6 @@ typed-styles@^0.0.7: resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9" integrity sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q== -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - unbox-primitive@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" @@ -6845,9 +6829,9 @@ url-loader@4.1.1: schema-utils "^3.0.0" url-parse@^1.4.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862" - integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ== + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== dependencies: querystringify "^2.1.1" requires-port "^1.0.0" @@ -6880,10 +6864,10 @@ utila@~0.4: resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= -uuid@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== v8-compile-cache@^2.0.3, v8-compile-cache@^2.3.0: version "2.3.0" @@ -6918,9 +6902,9 @@ warning@^4.0.2, warning@^4.0.3: loose-envify "^1.0.0" watchpack@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.2.0.tgz#47d78f5415fe550ecd740f99fe2882323a58b1ce" - integrity sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA== + version "2.3.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.1.tgz#4200d9447b401156eeca7767ee610f8809bc9d25" + integrity sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA== dependencies: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" @@ -6967,9 +6951,9 @@ webpack-merge@^5.7.3: wildcard "^2.0.0" webpack-sources@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.2.tgz#d88e3741833efec57c4c789b6010db9977545260" - integrity sha512-cp5qdmHnu5T8wRg2G3vZZHoJPN14aqQ89SyQ11NpGH5zEMDCclt49rzo+MaRazk7/UeILhAI+/sEtcM+7Fr0nw== + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== webpack@5.64.2: version "5.64.2" @@ -7034,7 +7018,7 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which@^1.2.9, which@^1.3.1: +which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -7072,20 +7056,18 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -write-file-atomic@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== +write-file-atomic@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.1.tgz#9faa33a964c1c85ff6f849b80b42a88c2c537c8f" + integrity sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ== dependencies: imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" + signal-exit "^3.0.7" ws@^7.4.5: - version "7.5.5" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881" - integrity sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w== + version "7.5.7" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" + integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== xxhashjs@~0.2.2: version "0.2.2" @@ -7109,23 +7091,28 @@ yaml@^1.10.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yargs-parser@^20.2.2, yargs-parser@^20.2.3: +yargs-parser@^20.2.3: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs@^17.0.1: - version "17.2.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.2.1.tgz#e2c95b9796a0e1f7f3bf4427863b42e0418191ea" - integrity sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q== +yargs-parser@^21.0.0: + version "21.0.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35" + integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== + +yargs@^17.3.1: + version "17.4.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.4.0.tgz#9fc9efc96bd3aa2c1240446af28499f0e7593d00" + integrity sha512-WJudfrk81yWFSOkZYpAZx4Nt7V4xp7S/uJkX0CnxovMCt1wCE8LNftPpNuF9X/u9gN5nsD7ycYtRcDf2pL3UiA== dependencies: cliui "^7.0.2" escalade "^3.1.1" get-caller-file "^2.0.5" require-directory "^2.1.1" - string-width "^4.2.0" + string-width "^4.2.3" y18n "^5.0.5" - yargs-parser "^20.2.2" + yargs-parser "^21.0.0" zip-stream@^4.1.0: version "4.1.0" From 83bf3620c03d406225fc531be800dcad7a191aab Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 24 Mar 2022 21:01:36 -0500 Subject: [PATCH 0390/2320] Update webpack packages --- package.json | 16 ++--- yarn.lock | 181 ++++++++++++++++++++++----------------------------- 2 files changed, 85 insertions(+), 112 deletions(-) diff --git a/package.json b/package.json index a4de67eab..ba04e56d3 100644 --- a/package.json +++ b/package.json @@ -92,12 +92,12 @@ "@babel/plugin-syntax-dynamic-import": "7.8.3", "@babel/preset-env": "7.16.11", "@babel/preset-react": "7.16.7", - "autoprefixer": "10.2.5", + "autoprefixer": "10.4.4", "babel-loader": "8.2.4", "babel-plugin-inline-classnames": "2.0.1", "babel-plugin-transform-react-remove-prop-types": "0.4.24", "core-js": "3.21.1", - "css-loader": "6.5.1", + "css-loader": "6.7.1", "eslint": "8.11.0", "eslint-plugin-filenames": "1.3.2", "eslint-plugin-import": "2.25.4", @@ -108,11 +108,11 @@ "filemanager-webpack-plugin": "6.1.7", "html-webpack-plugin": "5.5.0", "loader-utils": "^3.0.0", - "mini-css-extract-plugin": "2.4.5", - "postcss": "8.3.11", + "mini-css-extract-plugin": "2.6.0", + "postcss": "8.4.12", "postcss-color-function": "4.1.0", - "postcss-loader": "6.2.0", - "postcss-mixins": "8.1.0", + "postcss-loader": "6.2.1", + "postcss-mixins": "9.0.2", "postcss-nested": "5.0.6", "postcss-simple-vars": "6.0.3", "postcss-url": "10.1.3", @@ -124,8 +124,8 @@ "stylelint": "14.6.0", "stylelint-order": "5.0.0", "url-loader": "4.1.1", - "webpack": "5.64.2", - "webpack-cli": "4.9.1", + "webpack": "5.70.0", + "webpack-cli": "4.9.2", "webpack-livereload-plugin": "3.0.2" } } diff --git a/yarn.lock b/yarn.lock index 027a4fb09..7f82d8e8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1254,7 +1254,7 @@ dependencies: "@types/node" "*" -"@types/eslint-scope@^3.7.0": +"@types/eslint-scope@^3.7.3": version "3.7.3" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224" integrity sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g== @@ -1270,16 +1270,11 @@ "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*": +"@types/estree@*", "@types/estree@^0.0.51": version "0.0.51" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== -"@types/estree@^0.0.50": - version "0.0.50" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" - integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== - "@types/express-serve-static-core@^4.17.9": version "4.17.28" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz#c47def9f34ec81dc6328d0b1b5303d1ec98d86b8" @@ -1522,19 +1517,19 @@ "@webassemblyjs/ast" "1.11.1" "@xtuc/long" "4.2.2" -"@webpack-cli/configtest@^1.1.0": +"@webpack-cli/configtest@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.1.1.tgz#9f53b1b7946a6efc2a749095a4f450e2932e8356" integrity sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg== -"@webpack-cli/info@^1.4.0": +"@webpack-cli/info@^1.4.1": version "1.4.1" resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.4.1.tgz#2360ea1710cbbb97ff156a3f0f24556e0fc1ebea" integrity sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA== dependencies: envinfo "^7.7.3" -"@webpack-cli/serve@^1.6.0": +"@webpack-cli/serve@^1.6.1": version "1.6.1" resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.1.tgz#0de2875ac31b46b6c5bb1ae0a7d7f0ba5678dffe" integrity sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw== @@ -1849,17 +1844,17 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -autoprefixer@10.2.5: - version "10.2.5" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.2.5.tgz#096a0337dbc96c0873526d7fef5de4428d05382d" - integrity sha512-7H4AJZXvSsn62SqZyJCP+1AWwOuoYpUfK6ot9vm0e87XD6mT8lDywc9D9OTJPMULyGcvmIxzTAMeG2Cc+YX+fA== +autoprefixer@10.4.4: + version "10.4.4" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.4.tgz#3e85a245b32da876a893d3ac2ea19f01e7ea5a1e" + integrity sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA== dependencies: - browserslist "^4.16.3" - caniuse-lite "^1.0.30001196" - colorette "^1.2.2" - fraction.js "^4.0.13" + browserslist "^4.20.2" + caniuse-lite "^1.0.30001317" + fraction.js "^4.2.0" normalize-range "^0.1.2" - postcss-value-parser "^4.1.0" + picocolors "^1.0.0" + postcss-value-parser "^4.2.0" babel-loader@8.2.4: version "8.2.4" @@ -2013,7 +2008,7 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.14.5, browserslist@^4.16.3, browserslist@^4.17.5, browserslist@^4.19.1: +browserslist@^4.14.5, browserslist@^4.17.5, browserslist@^4.19.1, browserslist@^4.20.2: version "4.20.2" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== @@ -2114,7 +2109,7 @@ camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -caniuse-lite@^1.0.30001196, caniuse-lite@^1.0.30001317: +caniuse-lite@^1.0.30001317: version "1.0.30001320" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001320.tgz#8397391bec389b8ccce328636499b7284ee13285" integrity sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA== @@ -2298,11 +2293,6 @@ colord@^2.9.2: resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1" integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ== -colorette@^1.2.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" - integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== - colorette@^2.0.14: version "2.0.16" resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" @@ -2483,18 +2473,18 @@ css-functions-list@^3.0.1: resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.0.1.tgz#1460df7fb584d1692c30b105151dbb988c8094f9" integrity sha512-PriDuifDt4u4rkDgnqRCLnjfMatufLmWNfQnGCq34xZwpY3oabwhB9SqRBmuvWUgndbemCFlKqg+nO7C2q0SBw== -css-loader@6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.5.1.tgz#0c43d4fbe0d97f699c91e9818cb585759091d1b1" - integrity sha512-gEy2w9AnJNnD9Kuo4XAP9VflW/ujKoS9c/syO+uWMlm5igc7LysKzPXaDoR2vroROkSwsTS2tGr1yGGEbZOYZQ== +css-loader@6.7.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.1.tgz#e98106f154f6e1baf3fc3bc455cb9981c1d5fd2e" + integrity sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw== dependencies: icss-utils "^5.1.0" - postcss "^8.2.15" + postcss "^8.4.7" postcss-modules-extract-imports "^3.0.0" postcss-modules-local-by-default "^4.0.0" postcss-modules-scope "^3.0.0" postcss-modules-values "^4.0.0" - postcss-value-parser "^4.1.0" + postcss-value-parser "^4.2.0" semver "^7.3.5" css-select@^4.1.3: @@ -2772,7 +2762,7 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -enhanced-resolve@^5.8.3: +enhanced-resolve@^5.9.2: version "5.9.2" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz#0224dcd6a43389ebfb2d55efee517e5466772dd9" integrity sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA== @@ -3363,7 +3353,7 @@ for-in@^1.0.2: resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= -fraction.js@^4.0.13: +fraction.js@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== @@ -3530,7 +3520,7 @@ globals@^13.6.0, globals@^13.9.0: dependencies: type-fest "^0.20.2" -globby@^11.0.1, globby@^11.0.3, globby@^11.1.0: +globby@^11.0.1, globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -3568,7 +3558,7 @@ good-listener@^1.2.2: dependencies: delegate "^3.1.2" -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: version "4.2.9" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== @@ -4293,7 +4283,7 @@ kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -klona@^2.0.4: +klona@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== @@ -4603,10 +4593,10 @@ mini-create-react-context@^0.4.0: "@babel/runtime" "^7.12.1" tiny-warning "^1.0.3" -mini-css-extract-plugin@2.4.5: - version "2.4.5" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.4.5.tgz#191d6c170226037212c483af1180b4010b7b9eef" - integrity sha512-oEIhRucyn1JbT/1tU2BhnwO6ft1jjH1iCX9Gc59WFMg0n5773rQU0oyQ0zzeYFFuBfONaRbQJyGoPtuNseMxjA== +mini-css-extract-plugin@2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.0.tgz#578aebc7fc14d32c0ad304c2c34f08af44673f5e" + integrity sha512-ndG8nxCEnAemsg4FSgS+yNyHKgkTB4nPKqCOgh65j3/30qqC5RaSQQXMm++Y6sb6E1zRSxPkztj9fqxhS1Eo6w== dependencies: schema-utils "^4.0.0" @@ -4683,7 +4673,7 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nanoid@^3.1.30, nanoid@^3.3.1: +nanoid@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== @@ -5182,21 +5172,20 @@ postcss-color-function@4.1.0: postcss-message-helpers "^2.0.0" postcss-value-parser "^3.3.1" -postcss-js@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-3.0.3.tgz#2f0bd370a2e8599d45439f6970403b5873abda33" - integrity sha512-gWnoWQXKFw65Hk/mi2+WTQTHdPD5UJdDXZmX073EY/B3BWnYjO4F4t0VneTCnCGQ5E5GsCdMkzPaTXwl3r5dJw== +postcss-js@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00" + integrity sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ== dependencies: camelcase-css "^2.0.1" - postcss "^8.1.6" -postcss-loader@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-6.2.0.tgz#714370a3f567141cf4cadcdf9575f5234d186bc5" - integrity sha512-H9hv447QjQJVDbHj3OUdciyAXY3v5+UDduzEytAlZCVHCpNAAg/mCSwhYYqZr9BiGYhmYspU8QXxZwiHTLn3yA== +postcss-loader@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-6.2.1.tgz#0895f7346b1702103d30fdc66e4d494a93c008ef" + integrity sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q== dependencies: cosmiconfig "^7.0.0" - klona "^2.0.4" + klona "^2.0.5" semver "^7.3.5" postcss-media-query-parser@^0.2.3: @@ -5209,15 +5198,15 @@ postcss-message-helpers@^2.0.0: resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" integrity sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4= -postcss-mixins@8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/postcss-mixins/-/postcss-mixins-8.1.0.tgz#bbb46f017ca6b0b6ec88b5814b106cdf2fea2817" - integrity sha512-c8zHQm0QtiGUe5fpn8jAjZauQwCg2BsKyJDynamJ6cxVakBQFFh0qpo0FPnrb0/diz7tt/emUhOq+fo48rp5Cw== +postcss-mixins@9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/postcss-mixins/-/postcss-mixins-9.0.2.tgz#098969dafd1b9a98e2973fde024bef9d2563f604" + integrity sha512-LaFjXcR+7LRji+Sc6DRn1mUw43+Y9Lyh5JjFTQDedlIi4W6REAesRXRJLlms5424vb0zerBfCVZzS2ZHRxGZOA== dependencies: - globby "^11.0.3" - postcss-js "^3.0.3" + fast-glob "^3.2.11" + postcss-js "^4.0.0" postcss-simple-vars "^6.0.3" - sugarss "^3.0.3" + sugarss "^4.0.1" postcss-modules-extract-imports@^3.0.0: version "3.0.0" @@ -5302,14 +5291,14 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@8.3.11: - version "8.3.11" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.11.tgz#c3beca7ea811cd5e1c4a3ec6d2e7599ef1f8f858" - integrity sha512-hCmlUAIlUiav8Xdqw3Io4LcpA1DOt7h3LSTAC4G6JGHFFaWzI6qvFt9oilvl8BmkbBRX1IhM90ZAmpk68zccQA== +postcss@8.4.12, postcss@^8.3.11, postcss@^8.4.12, postcss@^8.4.7: + version "8.4.12" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905" + integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg== dependencies: - nanoid "^3.1.30" + nanoid "^3.3.1" picocolors "^1.0.0" - source-map-js "^0.6.2" + source-map-js "^1.0.2" postcss@^6.0.23: version "6.0.23" @@ -5320,15 +5309,6 @@ postcss@^6.0.23: source-map "^0.6.1" supports-color "^5.4.0" -postcss@^8.1.6, postcss@^8.2.15, postcss@^8.3.11, postcss@^8.4.12: - version "8.4.12" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905" - integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg== - dependencies: - nanoid "^3.3.1" - picocolors "^1.0.0" - source-map-js "^1.0.2" - prefix-style@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/prefix-style/-/prefix-style-2.0.1.tgz#66bba9a870cfda308a5dc20e85e9120932c95a06" @@ -6206,11 +6186,6 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -source-map-js@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" - integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug== - source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" @@ -6473,12 +6448,10 @@ stylelint@14.6.0: v8-compile-cache "^2.3.0" write-file-atomic "^4.0.1" -sugarss@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-3.0.3.tgz#bb2489961b98fbd15e4e35d6b9f4f2ee5547a6cb" - integrity sha512-uxa2bbuc+w7ov7DyYIhF6bM0qZF3UkFT5/nE8AJgboiVnKsBDbwxs++dehEIe1JNhpMaGJc37wGQ2QrrWey2Sg== - dependencies: - postcss "^8.1.6" +sugarss@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-4.0.1.tgz#128a783ed71ee0fc3b489ce1f7d5a89bc1e24383" + integrity sha512-WCjS5NfuVJjkQzK10s8WOBY+hhDxxNt/N6ZaGwxFZ+wN3/lKKFSaaKUNecULcTTvE4urLcKaZFQD8vO0mOZujw== supports-color@^2.0.0: version "2.0.0" @@ -6901,7 +6874,7 @@ warning@^4.0.2, warning@^4.0.3: dependencies: loose-envify "^1.0.0" -watchpack@^2.2.0: +watchpack@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.1.tgz#4200d9447b401156eeca7767ee610f8809bc9d25" integrity sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA== @@ -6914,15 +6887,15 @@ webidl-conversions@^3.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= -webpack-cli@4.9.1: - version "4.9.1" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.1.tgz#b64be825e2d1b130f285c314caa3b1ba9a4632b3" - integrity sha512-JYRFVuyFpzDxMDB+v/nanUdQYcZtqFPGzmlW4s+UkPMFhSpfRNmf1z4AwYcHJVdvEFAM7FFCQdNTpsBYhDLusQ== +webpack-cli@4.9.2: + version "4.9.2" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.2.tgz#77c1adaea020c3f9e2db8aad8ea78d235c83659d" + integrity sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ== dependencies: "@discoveryjs/json-ext" "^0.5.0" - "@webpack-cli/configtest" "^1.1.0" - "@webpack-cli/info" "^1.4.0" - "@webpack-cli/serve" "^1.6.0" + "@webpack-cli/configtest" "^1.1.1" + "@webpack-cli/info" "^1.4.1" + "@webpack-cli/serve" "^1.6.1" colorette "^2.0.14" commander "^7.0.0" execa "^5.0.0" @@ -6950,18 +6923,18 @@ webpack-merge@^5.7.3: clone-deep "^4.0.1" wildcard "^2.0.0" -webpack-sources@^3.2.2: +webpack-sources@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@5.64.2: - version "5.64.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.64.2.tgz#152e28d4712a6223b06c06cba0d3e622a61611a0" - integrity sha512-4KGc0+Ozi0aS3EaLNRvEppfZUer+CaORKqL6OBjDLZOPf9YfN8leagFzwe6/PoBdHFxc/utKArl8LMC0Ivtmdg== +webpack@5.70.0: + version "5.70.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.70.0.tgz#3461e6287a72b5e6e2f4872700bc8de0d7500e6d" + integrity sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw== dependencies: - "@types/eslint-scope" "^3.7.0" - "@types/estree" "^0.0.50" + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^0.0.51" "@webassemblyjs/ast" "1.11.1" "@webassemblyjs/wasm-edit" "1.11.1" "@webassemblyjs/wasm-parser" "1.11.1" @@ -6969,12 +6942,12 @@ webpack@5.64.2: acorn-import-assertions "^1.7.6" browserslist "^4.14.5" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.8.3" + enhanced-resolve "^5.9.2" es-module-lexer "^0.9.0" eslint-scope "5.1.1" events "^3.2.0" glob-to-regexp "^0.4.1" - graceful-fs "^4.2.4" + graceful-fs "^4.2.9" json-parse-better-errors "^1.0.2" loader-runner "^4.2.0" mime-types "^2.1.27" @@ -6982,8 +6955,8 @@ webpack@5.64.2: schema-utils "^3.1.0" tapable "^2.1.1" terser-webpack-plugin "^5.1.3" - watchpack "^2.2.0" - webpack-sources "^3.2.2" + watchpack "^2.3.1" + webpack-sources "^3.2.3" websocket-driver@>=0.5.1: version "0.7.4" From 627da14a326b875fa46474e36d660c1f352b62f1 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 24 Mar 2022 22:19:00 -0500 Subject: [PATCH 0391/2320] New: Load more (page) results on Search UI --- frontend/src/Search/SearchFooter.js | 33 ++++- frontend/src/Search/SearchIndex.js | 4 +- src/Prowlarr.Api.V1/Search/ReleaseResource.cs | 117 ++++++++++++++++++ .../Search/SearchController.cs | 41 +++--- src/Prowlarr.Api.V1/Search/SearchResource.cs | 117 ++---------------- 5 files changed, 176 insertions(+), 136 deletions(-) create mode 100644 src/Prowlarr.Api.V1/Search/ReleaseResource.cs diff --git a/frontend/src/Search/SearchFooter.js b/frontend/src/Search/SearchFooter.js index cd3897f33..36dd4acaa 100644 --- a/frontend/src/Search/SearchFooter.js +++ b/frontend/src/Search/SearchFooter.js @@ -37,7 +37,10 @@ class SearchFooter extends Component { searchingReleases: false, searchQuery: defaultSearchQuery || '', searchIndexerIds: defaultIndexerIds, - searchCategories: defaultCategories + searchCategories: defaultCategories, + searchLimit: 100, + searchOffset: 0, + newSearch: true }; } @@ -115,11 +118,28 @@ class SearchFooter extends Component { }; onSearchPress = () => { - this.props.onSearchPress(this.state.searchQuery, this.state.searchIndexerIds, this.state.searchCategories, this.state.searchType); + + const { + searchLimit, + searchOffset, + searchQuery, + searchIndexerIds, + searchCategories, + searchType + } = this.state; + + this.props.onSearchPress(searchQuery, searchIndexerIds, searchCategories, searchType, searchLimit, searchOffset); + + this.setState({ searchOffset: searchOffset + 100, newSearch: false }); }; onSearchInputChange = ({ value }) => { - this.setState({ searchQuery: value }); + this.setState({ searchQuery: value, newSearch: true, searchOffset: 0 }); + }; + + onInputChange = ({ name, value }) => { + this.props.onInputChange({ name, value }); + this.setState({ newSearch: true, searchOffset: 0 }); }; // @@ -141,6 +161,7 @@ class SearchFooter extends Component { searchQuery, searchIndexerIds, searchCategories, + newSearch, isQueryParameterModalOpen, queryModalOptions, searchType @@ -206,7 +227,7 @@ class SearchFooter extends Component { name='searchIndexerIds' value={searchIndexerIds} isDisabled={isFetching} - onChange={onInputChange} + onChange={this.onInputChange} /> </div> @@ -220,7 +241,7 @@ class SearchFooter extends Component { name='searchCategories' value={searchCategories} isDisabled={isFetching} - onChange={onInputChange} + onChange={this.onInputChange} /> </div> @@ -253,7 +274,7 @@ class SearchFooter extends Component { isDisabled={isFetching || !hasIndexers} onPress={this.onSearchPress} > - {translate('Search')} + {newSearch ? translate('Search') : translate('More')} </SpinnerButton> </div> </div> diff --git a/frontend/src/Search/SearchIndex.js b/frontend/src/Search/SearchIndex.js index 06479972b..5a7d9d484 100644 --- a/frontend/src/Search/SearchIndex.js +++ b/frontend/src/Search/SearchIndex.js @@ -196,8 +196,8 @@ class SearchIndex extends Component { this.setState({ jumpToCharacter }); }; - onSearchPress = (query, indexerIds, categories, type) => { - this.props.onSearchPress({ query, indexerIds, categories, type }); + onSearchPress = (query, indexerIds, categories, type, limit, offset) => { + this.props.onSearchPress({ query, indexerIds, categories, type, limit, offset }); }; onBulkGrabPress = () => { diff --git a/src/Prowlarr.Api.V1/Search/ReleaseResource.cs b/src/Prowlarr.Api.V1/Search/ReleaseResource.cs new file mode 100644 index 000000000..6654d82b0 --- /dev/null +++ b/src/Prowlarr.Api.V1/Search/ReleaseResource.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Parser.Model; +using Prowlarr.Http.REST; + +namespace Prowlarr.Api.V1.Search +{ + public class ReleaseResource : RestResource + { + public string Guid { get; set; } + public int Age { get; set; } + public double AgeHours { get; set; } + public double AgeMinutes { get; set; } + public long Size { get; set; } + public int? Files { get; set; } + public int? Grabs { get; set; } + public int IndexerId { get; set; } + public string Indexer { get; set; } + public string SubGroup { get; set; } + public string ReleaseHash { get; set; } + public string Title { get; set; } + public bool Approved { get; set; } + public int ImdbId { get; set; } + public DateTime PublishDate { get; set; } + public string CommentUrl { get; set; } + public string DownloadUrl { get; set; } + public string InfoUrl { get; set; } + public string PosterUrl { get; set; } + public IEnumerable<string> IndexerFlags { get; set; } + public ICollection<IndexerCategory> Categories { get; set; } + + public string MagnetUrl { get; set; } + public string InfoHash { get; set; } + public int? Seeders { get; set; } + public int? Leechers { get; set; } + public DownloadProtocol Protocol { get; set; } + } + + public static class ReleaseResourceMapper + { + public static ReleaseResource ToResource(this ReleaseInfo model) + { + var releaseInfo = model; + var torrentInfo = (model as TorrentInfo) ?? new TorrentInfo(); + var indexerFlags = torrentInfo.IndexerFlags.Select(f => f.Name); + + // TODO: Clean this mess up. don't mix data from multiple classes, use sub-resources instead? (Got a huge Deja Vu, didn't we talk about this already once?) + return new ReleaseResource + { + Guid = releaseInfo.Guid, + + //QualityWeight + Age = releaseInfo.Age, + AgeHours = releaseInfo.AgeHours, + AgeMinutes = releaseInfo.AgeMinutes, + Size = releaseInfo.Size ?? 0, + Files = releaseInfo.Files, + Grabs = releaseInfo.Grabs, + IndexerId = releaseInfo.IndexerId, + Indexer = releaseInfo.Indexer, + Title = releaseInfo.Title, + ImdbId = releaseInfo.ImdbId, + PublishDate = releaseInfo.PublishDate, + CommentUrl = releaseInfo.CommentUrl, + DownloadUrl = releaseInfo.DownloadUrl, + InfoUrl = releaseInfo.InfoUrl, + PosterUrl = releaseInfo.PosterUrl, + Categories = releaseInfo.Categories, + + //ReleaseWeight + MagnetUrl = torrentInfo.MagnetUrl, + InfoHash = torrentInfo.InfoHash, + Seeders = torrentInfo.Seeders, + Leechers = (torrentInfo.Peers.HasValue && torrentInfo.Seeders.HasValue) ? (torrentInfo.Peers.Value - torrentInfo.Seeders.Value) : (int?)null, + Protocol = releaseInfo.DownloadProtocol, + IndexerFlags = indexerFlags + }; + } + + public static ReleaseInfo ToModel(this ReleaseResource resource) + { + ReleaseInfo model; + + if (resource.Protocol == DownloadProtocol.Torrent) + { + model = new TorrentInfo + { + MagnetUrl = resource.MagnetUrl, + InfoHash = resource.InfoHash, + Seeders = resource.Seeders, + Peers = (resource.Seeders.HasValue && resource.Leechers.HasValue) ? (resource.Seeders + resource.Leechers) : null + }; + } + else + { + model = new ReleaseInfo(); + } + + model.Guid = resource.Guid; + model.Title = resource.Title; + model.Size = resource.Size; + model.DownloadUrl = resource.DownloadUrl; + model.InfoUrl = resource.InfoUrl; + model.PosterUrl = resource.PosterUrl; + model.CommentUrl = resource.CommentUrl; + model.IndexerId = resource.IndexerId; + model.Indexer = resource.Indexer; + model.DownloadProtocol = resource.Protocol; + model.ImdbId = resource.ImdbId; + model.PublishDate = resource.PublishDate.ToUniversalTime(); + + return model; + } + } +} diff --git a/src/Prowlarr.Api.V1/Search/SearchController.cs b/src/Prowlarr.Api.V1/Search/SearchController.cs index 836bfdaca..91e8c02f6 100644 --- a/src/Prowlarr.Api.V1/Search/SearchController.cs +++ b/src/Prowlarr.Api.V1/Search/SearchController.cs @@ -22,7 +22,7 @@ using Prowlarr.Http.REST; namespace Prowlarr.Api.V1.Search { [V1ApiController] - public class SearchController : RestController<SearchResource> + public class SearchController : RestController<ReleaseResource> { private readonly ISearchForNzb _nzbSearhService; private readonly IDownloadService _downloadService; @@ -46,13 +46,13 @@ namespace Prowlarr.Api.V1.Search _remoteReleaseCache = cacheManager.GetCache<ReleaseInfo>(GetType(), "remoteReleases"); } - public override SearchResource GetResourceById(int id) + public override ReleaseResource GetResourceById(int id) { throw new NotImplementedException(); } [HttpPost] - public ActionResult<SearchResource> GrabRelease(SearchResource release) + public ActionResult<ReleaseResource> GrabRelease(ReleaseResource release) { ValidateResource(release); @@ -76,7 +76,7 @@ namespace Prowlarr.Api.V1.Search } [HttpPost("bulk")] - public ActionResult<SearchResource> GrabReleases(List<SearchResource> releases) + public ActionResult<ReleaseResource> GrabReleases(List<ReleaseResource> releases) { var source = UserAgentParser.ParseSource(Request.Headers["User-Agent"]); var host = Request.GetHostName(); @@ -108,35 +108,30 @@ namespace Prowlarr.Api.V1.Search } [HttpGet] - public Task<List<SearchResource>> GetAll(string query, [FromQuery] List<int> indexerIds, [FromQuery] List<int> categories, [FromQuery] string type = "search") + public Task<List<ReleaseResource>> GetAll([FromQuery] SearchResource payload) { - if (indexerIds.Any()) - { - return GetSearchReleases(query, type, indexerIds, categories); - } - else - { - return GetSearchReleases(query, type, null, categories); - } + return GetSearchReleases(payload); } - private async Task<List<SearchResource>> GetSearchReleases(string query, string type, List<int> indexerIds, List<int> categories) + private async Task<List<ReleaseResource>> GetSearchReleases([FromQuery] SearchResource payload) { try { var request = new NewznabRequest { - q = query, - t = type, + q = payload.Query, + t = payload.Type, source = "Prowlarr", - cat = string.Join(",", categories), + cat = string.Join(",", payload.Categories), server = Request.GetServerUrl(), - host = Request.GetHostName() + host = Request.GetHostName(), + limit = payload.Limit, + offset = payload.Offset }; request.QueryToParams(); - var result = await _nzbSearhService.Search(request, indexerIds, true); + var result = await _nzbSearhService.Search(request, payload.IndexerIds, true); var decisions = result.Releases; return MapDecisions(decisions, Request.GetServerUrl()); @@ -150,12 +145,12 @@ namespace Prowlarr.Api.V1.Search _logger.Error(ex, "Search failed: " + ex.Message); } - return new List<SearchResource>(); + return new List<ReleaseResource>(); } - protected virtual List<SearchResource> MapDecisions(IEnumerable<ReleaseInfo> releases, string serverUrl) + protected virtual List<ReleaseResource> MapDecisions(IEnumerable<ReleaseInfo> releases, string serverUrl) { - var result = new List<SearchResource>(); + var result = new List<ReleaseResource>(); foreach (var downloadDecision in releases) { @@ -173,7 +168,7 @@ namespace Prowlarr.Api.V1.Search return result; } - private string GetCacheKey(SearchResource resource) + private string GetCacheKey(ReleaseResource resource) { return string.Concat(resource.IndexerId, "_", resource.Guid); } diff --git a/src/Prowlarr.Api.V1/Search/SearchResource.cs b/src/Prowlarr.Api.V1/Search/SearchResource.cs index 15ddf9f08..4bae4eabb 100644 --- a/src/Prowlarr.Api.V1/Search/SearchResource.cs +++ b/src/Prowlarr.Api.V1/Search/SearchResource.cs @@ -1,117 +1,24 @@ using System; using System.Collections.Generic; using System.Linq; -using NzbDrone.Core.Indexers; -using NzbDrone.Core.Parser.Model; -using Prowlarr.Http.REST; +using System.Text; +using System.Threading.Tasks; namespace Prowlarr.Api.V1.Search { - public class SearchResource : RestResource + public class SearchResource { - public string Guid { get; set; } - public int Age { get; set; } - public double AgeHours { get; set; } - public double AgeMinutes { get; set; } - public long Size { get; set; } - public int? Files { get; set; } - public int? Grabs { get; set; } - public int IndexerId { get; set; } - public string Indexer { get; set; } - public string SubGroup { get; set; } - public string ReleaseHash { get; set; } - public string Title { get; set; } - public bool Approved { get; set; } - public int ImdbId { get; set; } - public DateTime PublishDate { get; set; } - public string CommentUrl { get; set; } - public string DownloadUrl { get; set; } - public string InfoUrl { get; set; } - public string PosterUrl { get; set; } - public IEnumerable<string> IndexerFlags { get; set; } - public ICollection<IndexerCategory> Categories { get; set; } - - public string MagnetUrl { get; set; } - public string InfoHash { get; set; } - public int? Seeders { get; set; } - public int? Leechers { get; set; } - public DownloadProtocol Protocol { get; set; } - } - - public static class ReleaseResourceMapper - { - public static SearchResource ToResource(this ReleaseInfo model) + public SearchResource() { - var releaseInfo = model; - var torrentInfo = (model as TorrentInfo) ?? new TorrentInfo(); - var indexerFlags = torrentInfo.IndexerFlags.Select(f => f.Name); - - // TODO: Clean this mess up. don't mix data from multiple classes, use sub-resources instead? (Got a huge Deja Vu, didn't we talk about this already once?) - return new SearchResource - { - Guid = releaseInfo.Guid, - - //QualityWeight - Age = releaseInfo.Age, - AgeHours = releaseInfo.AgeHours, - AgeMinutes = releaseInfo.AgeMinutes, - Size = releaseInfo.Size ?? 0, - Files = releaseInfo.Files, - Grabs = releaseInfo.Grabs, - IndexerId = releaseInfo.IndexerId, - Indexer = releaseInfo.Indexer, - Title = releaseInfo.Title, - ImdbId = releaseInfo.ImdbId, - PublishDate = releaseInfo.PublishDate, - CommentUrl = releaseInfo.CommentUrl, - DownloadUrl = releaseInfo.DownloadUrl, - InfoUrl = releaseInfo.InfoUrl, - PosterUrl = releaseInfo.PosterUrl, - Categories = releaseInfo.Categories, - - //ReleaseWeight - MagnetUrl = torrentInfo.MagnetUrl, - InfoHash = torrentInfo.InfoHash, - Seeders = torrentInfo.Seeders, - Leechers = (torrentInfo.Peers.HasValue && torrentInfo.Seeders.HasValue) ? (torrentInfo.Peers.Value - torrentInfo.Seeders.Value) : (int?)null, - Protocol = releaseInfo.DownloadProtocol, - IndexerFlags = indexerFlags - }; + Type = "search"; + Categories = new List<int>(); } - public static ReleaseInfo ToModel(this SearchResource resource) - { - ReleaseInfo model; - - if (resource.Protocol == DownloadProtocol.Torrent) - { - model = new TorrentInfo - { - MagnetUrl = resource.MagnetUrl, - InfoHash = resource.InfoHash, - Seeders = resource.Seeders, - Peers = (resource.Seeders.HasValue && resource.Leechers.HasValue) ? (resource.Seeders + resource.Leechers) : null - }; - } - else - { - model = new ReleaseInfo(); - } - - model.Guid = resource.Guid; - model.Title = resource.Title; - model.Size = resource.Size; - model.DownloadUrl = resource.DownloadUrl; - model.InfoUrl = resource.InfoUrl; - model.PosterUrl = resource.PosterUrl; - model.CommentUrl = resource.CommentUrl; - model.IndexerId = resource.IndexerId; - model.Indexer = resource.Indexer; - model.DownloadProtocol = resource.Protocol; - model.ImdbId = resource.ImdbId; - model.PublishDate = resource.PublishDate.ToUniversalTime(); - - return model; - } + public string Query { get; set; } + public string Type { get; set; } + public List<int> IndexerIds { get; set; } + public List<int> Categories { get; set; } + public int Limit { get; set; } + public int Offset { get; set; } } } From 69de6d18eb6d7730df48f91152ae2e7bea58910b Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 25 Mar 2022 18:53:29 -0500 Subject: [PATCH 0392/2320] Fixed: Prevent delete of last profile --- frontend/src/Store/Selectors/createProfileInUseSelector.js | 5 +++-- src/NzbDrone.Core/Profiles/AppSyncProfileService.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/src/Store/Selectors/createProfileInUseSelector.js b/frontend/src/Store/Selectors/createProfileInUseSelector.js index d9445e361..807bf4673 100644 --- a/frontend/src/Store/Selectors/createProfileInUseSelector.js +++ b/frontend/src/Store/Selectors/createProfileInUseSelector.js @@ -5,13 +5,14 @@ import createAllIndexersSelector from './createAllIndexersSelector'; function createProfileInUseSelector(profileProp) { return createSelector( (state, { id }) => id, + (state) => state.settings.appProfiles.items, createAllIndexersSelector(), - (id, indexers) => { + (id, profiles, indexers) => { if (!id) { return false; } - if (_.some(indexers, { [profileProp]: id })) { + if (_.some(indexers, { [profileProp]: id }) || profiles.length <= 1) { return true; } diff --git a/src/NzbDrone.Core/Profiles/AppSyncProfileService.cs b/src/NzbDrone.Core/Profiles/AppSyncProfileService.cs index 1ece1dab4..952a06d8e 100644 --- a/src/NzbDrone.Core/Profiles/AppSyncProfileService.cs +++ b/src/NzbDrone.Core/Profiles/AppSyncProfileService.cs @@ -46,7 +46,7 @@ namespace NzbDrone.Core.Profiles public void Delete(int id) { - if (_indexerFactory.All().Any(c => c.AppProfileId == id)) + if (_indexerFactory.All().Any(c => c.AppProfileId == id) || All().Count == 1) { throw new ProfileInUseException(id); } From 135efe6d943905650d5008f90b2b7d72566c1bb0 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 28 Mar 2022 19:55:35 -0500 Subject: [PATCH 0393/2320] Fixed: Validation when testing indexers, connections and download clients Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com> --- src/NzbDrone.Common/Disk/SystemFolders.cs | 5 +++-- .../DownloadClient/DownloadClientController.cs | 10 ---------- src/Prowlarr.Api.V1/Indexers/IndexerController.cs | 10 ---------- .../Notifications/NotificationController.cs | 10 ---------- src/Prowlarr.Api.V1/ProviderControllerBase.cs | 14 +++++++------- 5 files changed, 10 insertions(+), 39 deletions(-) diff --git a/src/NzbDrone.Common/Disk/SystemFolders.cs b/src/NzbDrone.Common/Disk/SystemFolders.cs index c108e3d02..1c81ab1e0 100644 --- a/src/NzbDrone.Common/Disk/SystemFolders.cs +++ b/src/NzbDrone.Common/Disk/SystemFolders.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using NzbDrone.Common.EnvironmentInfo; @@ -24,7 +24,8 @@ namespace NzbDrone.Common.Disk "/boot", "/lib", "/sbin", - "/proc" + "/proc", + "/usr/bin" }; } } diff --git a/src/Prowlarr.Api.V1/DownloadClient/DownloadClientController.cs b/src/Prowlarr.Api.V1/DownloadClient/DownloadClientController.cs index c2e927924..994db6c69 100644 --- a/src/Prowlarr.Api.V1/DownloadClient/DownloadClientController.cs +++ b/src/Prowlarr.Api.V1/DownloadClient/DownloadClientController.cs @@ -12,15 +12,5 @@ namespace Prowlarr.Api.V1.DownloadClient : base(downloadClientFactory, "downloadclient", ResourceMapper) { } - - protected override void Validate(DownloadClientDefinition definition, bool includeWarnings) - { - if (!definition.Enable) - { - return; - } - - base.Validate(definition, includeWarnings); - } } } diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerController.cs b/src/Prowlarr.Api.V1/Indexers/IndexerController.cs index 48adfcf52..c184e2436 100644 --- a/src/Prowlarr.Api.V1/Indexers/IndexerController.cs +++ b/src/Prowlarr.Api.V1/Indexers/IndexerController.cs @@ -10,15 +10,5 @@ namespace Prowlarr.Api.V1.Indexers : base(indexerFactory, "indexer", resourceMapper) { } - - protected override void Validate(IndexerDefinition definition, bool includeWarnings) - { - if (!definition.Enable) - { - return; - } - - base.Validate(definition, includeWarnings); - } } } diff --git a/src/Prowlarr.Api.V1/Notifications/NotificationController.cs b/src/Prowlarr.Api.V1/Notifications/NotificationController.cs index f8dfbbc3c..310d2dd0b 100644 --- a/src/Prowlarr.Api.V1/Notifications/NotificationController.cs +++ b/src/Prowlarr.Api.V1/Notifications/NotificationController.cs @@ -12,15 +12,5 @@ namespace Prowlarr.Api.V1.Notifications : base(notificationFactory, "notification", ResourceMapper) { } - - protected override void Validate(NotificationDefinition definition, bool includeWarnings) - { - if (!definition.OnHealthIssue) - { - return; - } - - base.Validate(definition, includeWarnings); - } } } diff --git a/src/Prowlarr.Api.V1/ProviderControllerBase.cs b/src/Prowlarr.Api.V1/ProviderControllerBase.cs index 0be76531b..ea37ea535 100644 --- a/src/Prowlarr.Api.V1/ProviderControllerBase.cs +++ b/src/Prowlarr.Api.V1/ProviderControllerBase.cs @@ -62,7 +62,7 @@ namespace Prowlarr.Api.V1 [Produces("application/json")] public ActionResult<TProviderResource> CreateProvider(TProviderResource providerResource) { - var providerDefinition = GetDefinition(providerResource, false); + var providerDefinition = GetDefinition(providerResource, true, false, false); if (providerDefinition.Enable) { @@ -78,7 +78,7 @@ namespace Prowlarr.Api.V1 [Produces("application/json")] public ActionResult<TProviderResource> UpdateProvider(TProviderResource providerResource) { - var providerDefinition = GetDefinition(providerResource, false); + var providerDefinition = GetDefinition(providerResource, true, false, false); var forceSave = Request.GetBooleanQueryParameter("forceSave"); // Only test existing definitions if it is enabled and forceSave isn't set. @@ -92,11 +92,11 @@ namespace Prowlarr.Api.V1 return Accepted(providerResource.Id); } - private TProviderDefinition GetDefinition(TProviderResource providerResource, bool includeWarnings = false, bool validate = true) + private TProviderDefinition GetDefinition(TProviderResource providerResource, bool validate, bool includeWarnings, bool forceValidate) { var definition = _resourceMapper.ToModel(providerResource); - if (validate) + if (validate && (definition.Enable || forceValidate)) { Validate(definition, includeWarnings); } @@ -139,7 +139,7 @@ namespace Prowlarr.Api.V1 [HttpPost("test")] public object Test([FromBody] TProviderResource providerResource) { - var providerDefinition = GetDefinition(providerResource, true); + var providerDefinition = GetDefinition(providerResource, true, true, true); Test(providerDefinition, true); @@ -172,7 +172,7 @@ namespace Prowlarr.Api.V1 [HttpPost("action/{name}")] public IActionResult RequestAction(string name, [FromBody] TProviderResource resource) { - var providerDefinition = GetDefinition(resource, true, false); + var providerDefinition = GetDefinition(resource, false, false, false); var query = Request.Query.ToDictionary(x => x.Key, x => x.Value.ToString()); @@ -181,7 +181,7 @@ namespace Prowlarr.Api.V1 return Json(data); } - protected virtual void Validate(TProviderDefinition definition, bool includeWarnings) + private void Validate(TProviderDefinition definition, bool includeWarnings) { var validationResult = definition.Settings.Validate(); From b45e5a5e38a6204555b523b2483e125077cb0e6f Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sat, 26 Mar 2022 22:11:31 +0000 Subject: [PATCH 0394/2320] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (428 of 428 strings) Co-authored-by: Havok Dan <havokdan@yahoo.com.br> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/pt_BR.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index 1e8d6c1da..5612af34d 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -17,7 +17,7 @@ "ForMoreInformationOnTheIndividualDownloadClients": "Para saber mais sobre cada cliente de download, clique nos botões de informações.", "IndexerFlags": "Sinalizadores do indexador", "IndexerHealthCheckNoIndexers": "Não há indexadores habilitados, o Prowlarr não retornará resultados para a pesquisa", - "IndexerPriorityHelpText": "Prioridade do indexador de 1 (mais alta) a 50 (mais baixa). Padrão: 25.", + "IndexerPriorityHelpText": "Prioridade do Indexador de 1 (Mais Alta) a 50 (Mais Baixa). Padrão: 25.", "IndexersSelectedInterp": "{0} indexador(es) selecionado(s)", "LastWriteTime": "Hora da última gravação", "LaunchBrowserHelpText": " Abrir o navegador Web e navegar até a página inicial do Prowlarr ao iniciar o aplicativo.", From 9ddd38a3347dc46ee46a0fb53e3ff65fca97a0e4 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Tue, 29 Mar 2022 00:56:15 +0000 Subject: [PATCH 0395/2320] Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 98.5% (422 of 428 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (428 of 428 strings) Co-authored-by: Havok Dan <havokdan@yahoo.com.br> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: libsu <libsu@qq.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/zh_CN.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index 84c73a256..96db6ba5e 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -27,7 +27,7 @@ "Message": "信息", "Mechanism": "机制", "Manual": "手动", - "MaintenanceRelease": "维护版本", + "MaintenanceRelease": "维护版本:修复错误及其他改进,参见Github提交 查看更多详情", "Logs": "日志", "LogLevelTraceHelpTextWarning": "追踪日志只应该暂时启用", "LogLevel": "日志等级", @@ -185,7 +185,7 @@ "ApplyTagsHelpTexts3": "删除:移除输入的标签", "ApplyTagsHelpTexts2": "添加:将标签添加到现有标签列表", "Applications": "程序", - "AppDataLocationHealthCheckMessage": "更新时可能会删除应用数据", + "AppDataLocationHealthCheckMessage": "更新将无法阻止在更新时删除应用数据", "AddRemoveOnly": "仅添加和删除", "AddDownloadClientToProwlarr": "添加下载客户端允许 Prowlarr 在进行手动搜索时从 UI直接发送结果.", "AddDownloadClient": "添加下载客户端", @@ -272,7 +272,7 @@ "Wiki": "Wiki", "Yesterday": "昨天", "Torrent": "Torrents", - "Torrents": "种子", + "Torrents": "Torrents", "Type": "类型", "UnableToLoadNotifications": "无法加载通知连接", "RefreshMovie": "刷新影片", From 32fc2ec36594605f4a99428fc40db5e8b8c3752b Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Wed, 30 Mar 2022 04:10:44 +0000 Subject: [PATCH 0396/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 163 +++++++++++++++++++------------ 1 file changed, 99 insertions(+), 64 deletions(-) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index 019947d3c..0995a4529 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -2675,6 +2675,7 @@ "in": "path", "required": true, "schema": { + "pattern": "[-.a-zA-Z0-9]+?\\.txt", "type": "string" } } @@ -3510,17 +3511,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } } } @@ -3537,17 +3538,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } }, "application/*+json": { "schema": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } } } @@ -3558,17 +3559,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } } } @@ -3581,14 +3582,21 @@ ], "parameters": [ { - "name": "query", + "name": "Query", "in": "query", "schema": { "type": "string" } }, { - "name": "indexerIds", + "name": "Type", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "IndexerIds", "in": "query", "schema": { "type": "array", @@ -3599,7 +3607,7 @@ } }, { - "name": "categories", + "name": "Categories", "in": "query", "schema": { "type": "array", @@ -3610,11 +3618,19 @@ } }, { - "name": "type", + "name": "Limit", "in": "query", "schema": { - "type": "string", - "default": "search" + "type": "integer", + "format": "int32" + } + }, + { + "name": "Offset", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" } } ], @@ -3626,7 +3642,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } } }, @@ -3634,7 +3650,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } } }, @@ -3642,7 +3658,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } } } @@ -3662,7 +3678,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } } }, @@ -3670,7 +3686,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } } }, @@ -3678,7 +3694,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } } } @@ -3690,17 +3706,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/SearchResource" + "$ref": "#/components/schemas/ReleaseResource" } } } @@ -3719,6 +3735,7 @@ "in": "path", "required": true, "schema": { + "pattern": "^(?!api/).*", "type": "string" } } @@ -3763,6 +3780,7 @@ "in": "path", "required": true, "schema": { + "pattern": "^(?!api/).*", "type": "string" } } @@ -4383,6 +4401,7 @@ "in": "path", "required": true, "schema": { + "pattern": "[-.a-zA-Z0-9]+?\\.txt", "type": "string" } } @@ -4397,6 +4416,29 @@ }, "components": { "schemas": { + "AppProfileResource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "enableRss": { + "type": "boolean" + }, + "enableInteractiveSearch": { + "type": "boolean" + }, + "enableAutomaticSearch": { + "type": "boolean" + } + }, + "additionalProperties": false + }, "ApplicationResource": { "type": "object", "properties": { @@ -4476,29 +4518,6 @@ ], "type": "string" }, - "AppProfileResource": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string", - "nullable": true - }, - "enableRss": { - "type": "boolean" - }, - "enableInteractiveSearch": { - "type": "boolean" - }, - "enableAutomaticSearch": { - "type": "boolean" - } - }, - "additionalProperties": false - }, "AuthenticationType": { "enum": [ "none", @@ -4982,7 +5001,8 @@ "data": { "type": "object", "additionalProperties": { - "type": "string" + "type": "string", + "nullable": true }, "nullable": true } @@ -5184,28 +5204,34 @@ }, "scheme": { "type": "string", - "nullable": true + "nullable": true, + "readOnly": true }, "host": { "type": "string", - "nullable": true + "nullable": true, + "readOnly": true }, "port": { "type": "integer", "format": "int32", - "nullable": true + "nullable": true, + "readOnly": true }, "path": { "type": "string", - "nullable": true + "nullable": true, + "readOnly": true }, "query": { "type": "string", - "nullable": true + "nullable": true, + "readOnly": true }, "fragment": { "type": "string", - "nullable": true + "nullable": true, + "readOnly": true } }, "additionalProperties": false @@ -5844,7 +5870,7 @@ ], "type": "string" }, - "SearchResource": { + "ReleaseResource": { "type": "object", "properties": { "id": { @@ -6099,23 +6125,28 @@ }, "days": { "type": "integer", - "format": "int32" + "format": "int32", + "readOnly": true }, "hours": { "type": "integer", - "format": "int32" + "format": "int32", + "readOnly": true }, "milliseconds": { "type": "integer", - "format": "int32" + "format": "int32", + "readOnly": true }, "minutes": { "type": "integer", - "format": "int32" + "format": "int32", + "readOnly": true }, "seconds": { "type": "integer", - "format": "int32" + "format": "int32", + "readOnly": true }, "totalDays": { "type": "number", @@ -6292,19 +6323,23 @@ "properties": { "major": { "type": "integer", - "format": "int32" + "format": "int32", + "readOnly": true }, "minor": { "type": "integer", - "format": "int32" + "format": "int32", + "readOnly": true }, "build": { "type": "integer", - "format": "int32" + "format": "int32", + "readOnly": true }, "revision": { "type": "integer", - "format": "int32" + "format": "int32", + "readOnly": true }, "majorRevision": { "type": "integer", From 6ce9c779c12690c84fef5a00d47c23512bcdafb4 Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Fri, 4 Mar 2022 13:34:15 -0600 Subject: [PATCH 0397/2320] Fixed: Update from version in logs Closes #873 Closes #877 (cherry picked from commit bc3e3714b97dec19091e45324d9f2b550f1dbbd5) (cherry picked from commit b34f4fde1bbe611bb5c886890e3be7cec2b96e6b) --- src/NzbDrone.Update/UpdateEngine/DetectExistingVersion.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Update/UpdateEngine/DetectExistingVersion.cs b/src/NzbDrone.Update/UpdateEngine/DetectExistingVersion.cs index 1de3db7d0..3bc7687a7 100644 --- a/src/NzbDrone.Update/UpdateEngine/DetectExistingVersion.cs +++ b/src/NzbDrone.Update/UpdateEngine/DetectExistingVersion.cs @@ -22,13 +22,13 @@ namespace NzbDrone.Update.UpdateEngine { try { - var targetExecutable = Path.Combine(targetFolder, "Prowlarr.exe"); + var targetExecutable = Path.Combine(targetFolder, "Prowlarr.dll"); if (File.Exists(targetExecutable)) { var versionInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(targetExecutable); - return versionInfo.FileVersion; + return versionInfo.ProductVersion; } } catch (Exception ex) From 4f056bf2288468cd4988cd78a94d6f3c584f9ed9 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 29 Jan 2022 17:37:29 -0600 Subject: [PATCH 0398/2320] New: Add Search Capabilities to Indexer API & InfoBox --- .../Indexer/Info/IndexerInfoModalContent.js | 108 ++++++++++++------ src/NzbDrone.Core/Localization/Core/en.json | 12 +- .../Indexers/IndexerCapabilityResource.cs | 14 ++- 3 files changed, 98 insertions(+), 36 deletions(-) diff --git a/frontend/src/Indexer/Info/IndexerInfoModalContent.js b/frontend/src/Indexer/Info/IndexerInfoModalContent.js index 8a0ec5d5e..47ad33e17 100644 --- a/frontend/src/Indexer/Info/IndexerInfoModalContent.js +++ b/frontend/src/Indexer/Info/IndexerInfoModalContent.js @@ -4,6 +4,7 @@ import DescriptionList from 'Components/DescriptionList/DescriptionList'; import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem'; import DescriptionListItemDescription from 'Components/DescriptionList/DescriptionListItemDescription'; import DescriptionListItemTitle from 'Components/DescriptionList/DescriptionListItemTitle'; +import FieldSet from 'Components/FieldSet'; import Link from 'Components/Link/Link'; import ModalBody from 'Components/Modal/ModalBody'; import ModalContent from 'Components/Modal/ModalContent'; @@ -20,6 +21,7 @@ function IndexerInfoModalContent(props) { language, indexerUrls, protocol, + capabilities, onModalClose } = props; @@ -30,41 +32,78 @@ function IndexerInfoModalContent(props) { </ModalHeader> <ModalBody> - <DescriptionList> - <DescriptionListItem - descriptionClassName={styles.description} - title={translate('Id')} - data={id} - /> - <DescriptionListItem - descriptionClassName={styles.description} - title={translate('Description')} - data={description ? description : '-'} - /> - <DescriptionListItem - descriptionClassName={styles.description} - title={translate('Encoding')} - data={encoding ? encoding : '-'} - /> - <DescriptionListItem - descriptionClassName={styles.description} - title={translate('Language')} - data={language ?? '-'} - /> - - <DescriptionListItemTitle>Indexer Site</DescriptionListItemTitle> - <DescriptionListItemDescription> - <Link to={indexerUrls[0]}>{indexerUrls[0]}</Link> - </DescriptionListItemDescription> - - <DescriptionListItemTitle>{`${protocol === 'usenet' ? 'Newznab' : 'Torznab'} Url`}</DescriptionListItemTitle> - <DescriptionListItemDescription> - {`${window.location.origin}${window.Prowlarr.urlBase}/${id}/api`} - </DescriptionListItemDescription> - - </DescriptionList> + <FieldSet legend={translate('IndexerDetails')}> + <div className={styles.groups}> + <DescriptionList> + <DescriptionListItem + descriptionClassName={styles.description} + title={translate('Id')} + data={id} + /> + <DescriptionListItem + descriptionClassName={styles.description} + title={translate('Description')} + data={description ? description : '-'} + /> + <DescriptionListItem + descriptionClassName={styles.description} + title={translate('Encoding')} + data={encoding ? encoding : '-'} + /> + <DescriptionListItem + descriptionClassName={styles.description} + title={translate('Language')} + data={language ?? '-'} + /> + <DescriptionListItemTitle>{translate('IndexerSite')}</DescriptionListItemTitle> + <DescriptionListItemDescription> + <Link to={indexerUrls[0]}>{indexerUrls[0]}</Link> + </DescriptionListItemDescription> + <DescriptionListItemTitle>{`${protocol === 'usenet' ? 'Newznab' : 'Torznab'} Url`}</DescriptionListItemTitle> + <DescriptionListItemDescription> + {`${window.location.origin}${window.Prowlarr.urlBase}/${id}/api`} + </DescriptionListItemDescription> + </DescriptionList> + </div> + </FieldSet> + <FieldSet legend={translate('SearchCapabilities')}> + <div className={styles.groups}> + <DescriptionList> + <DescriptionListItem + descriptionClassName={styles.description} + title={translate('RawSearchSupported')} + data={capabilities.supportsRawSearch ? translate('Yes') : translate('No')} + /> + <DescriptionListItem + descriptionClassName={styles.description} + title={translate('SearchTypes')} + data={capabilities.search.length === 0 ? translate('NotSupported') : capabilities.search[0]} + /> + <DescriptionListItem + descriptionClassName={styles.description} + title={translate('TVSearchTypes')} + data={capabilities.tv.length === 0 ? translate('NotSupported') : capabilities.tv.join(', ')} + /> + <DescriptionListItem + descriptionClassName={styles.description} + title={translate('MovieSearchTypes')} + data={capabilities.movie.length === 0 ? translate('NotSupported') : capabilities.movie.join(', ')} + /> + <DescriptionListItem + descriptionClassName={styles.description} + title={translate('BookSearchTypes')} + data={capabilities.book.length === 0 ? translate('NotSupported') : capabilities.book.join(', ')} + /> + <DescriptionListItem + descriptionClassName={styles.description} + title={translate('MusicSearchTypes')} + data={capabilities.music.length === 0 ? translate('NotSupported') : capabilities.music.join(', ')} + /> + </DescriptionList> + </div> + </FieldSet> </ModalBody> - </ModalContent> + </ModalContent > ); } @@ -76,6 +115,7 @@ IndexerInfoModalContent.propTypes = { language: PropTypes.string.isRequired, indexerUrls: PropTypes.arrayOf(PropTypes.string).isRequired, protocol: PropTypes.string.isRequired, + capabilities: PropTypes.object.isRequired, onModalClose: PropTypes.func.isRequired }; diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 7c851310b..a0a9beeac 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -55,6 +55,7 @@ "BindAddress": "Bind Address", "BindAddressHelpText": "Valid IP4 address or '*' for all interfaces", "BookSearch": "Book Search", + "BookSearchTypes": "Book Search Types", "Branch": "Branch", "BranchUpdate": "Branch to use to update Prowlarr", "BranchUpdateMechanism": "Branch used by external update mechanism", @@ -172,13 +173,14 @@ "Indexer": "Indexer", "IndexerAlreadySetup": "At least one instace of indexer is already setup", "IndexerAuth": "Indexer Auth", + "IndexerDetails": "Indexer Details", "IndexerFlags": "Indexer Flags", "IndexerHealthCheckNoIndexers": "No indexers enabled, Prowlarr will not return search results", "IndexerInfo": "Indexer Info", "IndexerLongTermStatusCheckAllClientMessage": "All indexers are unavailable due to failures for more than 6 hours", "IndexerLongTermStatusCheckSingleClientMessage": "Indexers unavailable due to failures for more than 6 hours: {0}", - "IndexerObsoleteCheckMessage": "Indexers are obsolete or have been updated: {0}. Please remove and (or) re-add to Prowlarr", "IndexerNoDefCheckMessage": "Indexers have no definition and will not work: {0}. Please remove and (or) re-add to Prowlarr", + "IndexerObsoleteCheckMessage": "Indexers are obsolete or have been updated: {0}. Please remove and (or) re-add to Prowlarr", "IndexerPriority": "Indexer Priority", "IndexerPriorityHelpText": "Indexer Priority from 1 (Highest) to 50 (Lowest). Default: 25.", "IndexerProxies": "Indexer Proxies", @@ -189,6 +191,7 @@ "IndexerRss": "Indexer Rss", "Indexers": "Indexers", "IndexerSettingsSummary": "Configure various global Indexer settings including Proxies.", + "IndexerSite": "Indexer Site", "IndexersSelectedInterp": "{0} Indexer(s) Selected", "IndexerStatusCheckAllClientMessage": "All indexers are unavailable due to failures", "IndexerStatusCheckSingleClientMessage": "Indexers unavailable due to failures: {0}", @@ -219,6 +222,8 @@ "MovieIndexScrollBottom": "Movie Index: Scroll Bottom", "MovieIndexScrollTop": "Movie Index: Scroll Top", "MovieSearch": "Movie Search", + "MovieSearchTypes": "Movie Search Types", + "MusicSearchTypes": "Music Search Types", "Name": "Name", "NetCore": ".NET", "New": "New", @@ -234,6 +239,7 @@ "Notifications": "Notifications", "NotificationTriggers": "Notification Triggers", "NotificationTriggersHelpText": "Select which events should trigger this notification", + "NotSupported": "Not Supported", "NoUpdatesAreAvailable": "No updates are available", "OAuthPopupMessage": "Pop-ups are being blocked by your browser", "Ok": "Ok", @@ -279,6 +285,7 @@ "QueryOptions": "Query Options", "QueryResults": "Query Results", "Queue": "Queue", + "RawSearchSupported": "Raw Search Supported", "ReadTheWikiForMoreInformation": "Read the Wiki for more information", "Reddit": "Reddit", "Redirect": "Redirect", @@ -309,8 +316,10 @@ "Scheduled": "Scheduled", "ScriptPath": "Script Path", "Search": "Search", + "SearchCapabilities": "Search Capabilities", "SearchIndexers": "Search Indexers", "SearchType": "Search Type", + "SearchTypes": "Search Types", "Security": "Security", "Seeders": "Seeders", "SelectAll": "Select All", @@ -379,6 +388,7 @@ "Torrent": "Torrent", "Torrents": "Torrents", "TvSearch": "TV Search", + "TVSearchTypes": "TV Search Types", "Type": "Type", "UI": "UI", "UILanguage": "UI Language", diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerCapabilityResource.cs b/src/Prowlarr.Api.V1/Indexers/IndexerCapabilityResource.cs index ffeee495a..f97204289 100644 --- a/src/Prowlarr.Api.V1/Indexers/IndexerCapabilityResource.cs +++ b/src/Prowlarr.Api.V1/Indexers/IndexerCapabilityResource.cs @@ -10,6 +10,12 @@ namespace Prowlarr.Api.V1.Indexers public int? LimitsMax { get; set; } public int? LimitsDefault { get; set; } public List<IndexerCategory> Categories { get; set; } + public bool SupportsRawSearch { get; set; } + public List<SearchParam> SearchParams { get; set; } + public List<TvSearchParam> TvSearchParams { get; set; } + public List<MovieSearchParam> MovieSearchParams { get; set; } + public List<MusicSearchParam> MusicSearchParams { get; set; } + public List<BookSearchParam> BookSearchParams { get; set; } } public static class IndexerCapabilitiesResourceMapper @@ -25,7 +31,13 @@ namespace Prowlarr.Api.V1.Indexers { LimitsMax = model.LimitsMax, LimitsDefault = model.LimitsDefault, - Categories = model.Categories.GetTorznabCategoryTree() + Categories = model.Categories.GetTorznabCategoryTree(), + SupportsRawSearch = model.SupportsRawSearch, + SearchParams = model.SearchParams, + TvSearchParams = model.TvSearchParams, + MovieSearchParams = model.MovieSearchParams, + MusicSearchParams = model.MusicSearchParams, + BookSearchParams = model.BookSearchParams }; } From 788a5a3e241bb1fc861bf42c5b7aa030fa46c10b Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 2 Feb 2022 13:37:53 -0600 Subject: [PATCH 0399/2320] Fixed: Missing Translates --- frontend/src/Search/QueryParameterModal.js | 2 +- frontend/src/Search/SearchFooter.js | 2 +- src/NzbDrone.Core/Localization/Core/en.json | 7 +++++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/frontend/src/Search/QueryParameterModal.js b/frontend/src/Search/QueryParameterModal.js index aede4a251..d684d32d8 100644 --- a/frontend/src/Search/QueryParameterModal.js +++ b/frontend/src/Search/QueryParameterModal.js @@ -248,7 +248,7 @@ class QueryParameterModal extends Component { onSelectionChange={this.onInputSelectionChange} /> <Button onPress={onModalClose}> - Close + {translate('Close')} </Button> </ModalFooter> </ModalContent> diff --git a/frontend/src/Search/SearchFooter.js b/frontend/src/Search/SearchFooter.js index 36dd4acaa..5d8c42a42 100644 --- a/frontend/src/Search/SearchFooter.js +++ b/frontend/src/Search/SearchFooter.js @@ -264,7 +264,7 @@ class SearchFooter extends Component { isDisabled={isFetching || !hasIndexers || selectedCount === 0} onPress={onBulkGrabPress} > - {translate('Grab Releases')} + {translate('GrabReleases')} </SpinnerButton> } diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index a0a9beeac..8890e6212 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -22,6 +22,7 @@ "ApiKey": "API Key", "AppDataDirectory": "AppData directory", "AppDataLocationHealthCheckMessage": "Updating will not be possible to prevent deleting AppData on Update", + "Application": "Application", "Applications": "Applications", "ApplicationStatusCheckAllClientMessage": "All applications are unavailable due to failures", "ApplicationStatusCheckSingleClientMessage": "Applications unavailable due to failures: {0}", @@ -154,6 +155,7 @@ "GeneralSettings": "General Settings", "GeneralSettingsSummary": "Port, SSL, username/password, proxy, analytics, and updates", "Grabbed": "Grabbed", + "GrabReleases": "Grab Release(s)", "Grabs": "Grabs", "Health": "Health", "HealthNoIssues": "No issues with your configuration", @@ -179,6 +181,7 @@ "IndexerInfo": "Indexer Info", "IndexerLongTermStatusCheckAllClientMessage": "All indexers are unavailable due to failures for more than 6 hours", "IndexerLongTermStatusCheckSingleClientMessage": "Indexers unavailable due to failures for more than 6 hours: {0}", + "IndexerName": "Indexer Name", "IndexerNoDefCheckMessage": "Indexers have no definition and will not work: {0}. Please remove and (or) re-add to Prowlarr", "IndexerObsoleteCheckMessage": "Indexers are obsolete or have been updated: {0}. Please remove and (or) re-add to Prowlarr", "IndexerPriority": "Indexer Priority", @@ -206,6 +209,7 @@ "LastWriteTime": "Last Write Time", "LaunchBrowserHelpText": " Open a web browser and navigate to the Prowlarr homepage on app start.", "Level": "Level", + "Link": "Link", "LogFiles": "Log Files", "Logging": "Logging", "LogLevel": "Log Level", @@ -213,6 +217,7 @@ "Logs": "Logs", "MaintenanceRelease": "Maintenance Release: bug fixes and other improvements. See Github Commit History for more details", "Manual": "Manual", + "MappedDrivesRunningAsService": "Mapped network drives are not available when running as a Windows Service. Please see the FAQ for more information", "MassEditor": "Mass Editor", "Mechanism": "Mechanism", "Message": "Message", @@ -227,6 +232,7 @@ "Name": "Name", "NetCore": ".NET", "New": "New", + "No": "No", "NoBackupsAreAvailable": "No backups are available", "NoChange": "No Change", "NoChanges": "No Changes", @@ -435,6 +441,7 @@ "Warn": "Warn", "Website": "Website", "Wiki": "Wiki", + "Yes": "Yes", "YesCancel": "Yes, Cancel", "Yesterday": "Yesterday" } From cb8c0d4aa713cf54fe158b21daafe629bdf4c4b5 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 2 Feb 2022 13:53:44 -0600 Subject: [PATCH 0400/2320] New: Indexer Description in Add Indexer Modal --- frontend/src/Indexer/Add/AddIndexerModalContent.js | 10 ++++++++-- frontend/src/Indexer/Add/SelectIndexerRow.js | 6 ++++++ src/NzbDrone.Core/Localization/Core/en.json | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/frontend/src/Indexer/Add/AddIndexerModalContent.js b/frontend/src/Indexer/Add/AddIndexerModalContent.js index 253703d5d..236e0d747 100644 --- a/frontend/src/Indexer/Add/AddIndexerModalContent.js +++ b/frontend/src/Indexer/Add/AddIndexerModalContent.js @@ -37,6 +37,12 @@ const columns = [ isSortable: true, isVisible: true }, + { + name: 'description', + label: translate('Description'), + isSortable: false, + isVisible: true + }, { name: 'privacy', label: translate('Privacy'), @@ -136,12 +142,12 @@ class AddIndexerModalContent extends Component { return true; }); - const errorMessage = getErrorMessage(error, 'Unable to load indexers'); + const errorMessage = getErrorMessage(error, translate('UnableToLoadIndexers')); return ( <ModalContent onModalClose={onModalClose}> <ModalHeader> - Add Indexer + {translate('AddIndexer')} </ModalHeader> <ModalBody diff --git a/frontend/src/Indexer/Add/SelectIndexerRow.js b/frontend/src/Indexer/Add/SelectIndexerRow.js index 481f21016..c3f33220d 100644 --- a/frontend/src/Indexer/Add/SelectIndexerRow.js +++ b/frontend/src/Indexer/Add/SelectIndexerRow.js @@ -32,6 +32,7 @@ class SelectIndexerRow extends Component { privacy, name, language, + description, isExistingIndexer } = this.props; @@ -61,6 +62,10 @@ class SelectIndexerRow extends Component { {language} </TableRowCell> + <TableRowCell> + {description} + </TableRowCell> + <TableRowCell> {translate(firstCharToUpper(privacy))} </TableRowCell> @@ -74,6 +79,7 @@ SelectIndexerRow.propTypes = { protocol: PropTypes.string.isRequired, privacy: PropTypes.string.isRequired, language: PropTypes.string.isRequired, + description: PropTypes.string.isRequired, implementation: PropTypes.string.isRequired, onIndexerSelect: PropTypes.func.isRequired, isExistingIndexer: PropTypes.bool.isRequired diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 8890e6212..7c0408572 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -416,6 +416,7 @@ "UnableToLoadGeneralSettings": "Unable to load General settings", "UnableToLoadHistory": "Unable to load history", "UnableToLoadIndexerProxies": "Unable To Load Indexer Proxies", + "UnableToLoadIndexers": "Unable to load Indexers", "UnableToLoadNotifications": "Unable to load Notifications", "UnableToLoadTags": "Unable to load Tags", "UnableToLoadUISettings": "Unable to load UI settings", From a81d632878d0eb188e45fc2d35a4e68002d0806e Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 30 Mar 2022 09:22:17 -0500 Subject: [PATCH 0401/2320] Fixed: Indexer Infobox Error (#920) * Fixed: Indexer Infobox Error * fixup! Fixed: Indexer Infobox Error * fixup! Fixed: Indexer Infobox Error --- frontend/src/Indexer/Info/IndexerInfoModalContent.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/Indexer/Info/IndexerInfoModalContent.js b/frontend/src/Indexer/Info/IndexerInfoModalContent.js index 47ad33e17..1b162efa8 100644 --- a/frontend/src/Indexer/Info/IndexerInfoModalContent.js +++ b/frontend/src/Indexer/Info/IndexerInfoModalContent.js @@ -77,27 +77,27 @@ function IndexerInfoModalContent(props) { <DescriptionListItem descriptionClassName={styles.description} title={translate('SearchTypes')} - data={capabilities.search.length === 0 ? translate('NotSupported') : capabilities.search[0]} + data={capabilities.searchParams.length === 0 ? translate('NotSupported') : capabilities.searchParams[0]} /> <DescriptionListItem descriptionClassName={styles.description} title={translate('TVSearchTypes')} - data={capabilities.tv.length === 0 ? translate('NotSupported') : capabilities.tv.join(', ')} + data={capabilities.tvSearchParams.length === 0 ? translate('NotSupported') : capabilities.tvSearchParams.join(', ')} /> <DescriptionListItem descriptionClassName={styles.description} title={translate('MovieSearchTypes')} - data={capabilities.movie.length === 0 ? translate('NotSupported') : capabilities.movie.join(', ')} + data={capabilities.movieSearchParams.length === 0 ? translate('NotSupported') : capabilities.movieSearchParams.join(', ')} /> <DescriptionListItem descriptionClassName={styles.description} title={translate('BookSearchTypes')} - data={capabilities.book.length === 0 ? translate('NotSupported') : capabilities.book.join(', ')} + data={capabilities.bookSearchParams.length === 0 ? translate('NotSupported') : capabilities.bookSearchParams.join(', ')} /> <DescriptionListItem descriptionClassName={styles.description} title={translate('MusicSearchTypes')} - data={capabilities.music.length === 0 ? translate('NotSupported') : capabilities.music.join(', ')} + data={capabilities.musicSearchParams.length === 0 ? translate('NotSupported') : capabilities.musicSearchParams.join(', ')} /> </DescriptionList> </div> From 3a896fc43eddc142f586fe35fff7e334cba24d16 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Thu, 31 Mar 2022 01:17:10 +0000 Subject: [PATCH 0402/2320] Translated using Weblate (Finnish) Currently translated at 97.7% (436 of 446 strings) Co-authored-by: Anonymous <noreply@weblate.org> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/fi.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Localization/Core/fi.json b/src/NzbDrone.Core/Localization/Core/fi.json index 9955875fc..3ba4ee2c4 100644 --- a/src/NzbDrone.Core/Localization/Core/fi.json +++ b/src/NzbDrone.Core/Localization/Core/fi.json @@ -426,5 +426,13 @@ "Website": "Verkkosivusto", "IndexerNoDefCheckMessage": "Tietolähteillä ei ole määritystä, eivätkä ne toimi: {0}. Poista ja/tai lisää Prowlarriin uudelleen", "Private": "Yksityinen", - "QueryResults": "Kyselyn tulokset" + "QueryResults": "Kyselyn tulokset", + "Application": "Sovellukset", + "GrabReleases": "Sieppaa julkaisu", + "Link": "Linkit", + "SearchTypes": "Mitä etsitään", + "UnableToLoadIndexers": "Tietolähteiden lataus epäonnistui.", + "Yes": "Joo", + "MappedDrivesRunningAsService": "Yhdistetyt verkkoasemat eivät ole käytettävissä, kun niitä käytetään Windows-palveluna. Katso lisätietoja UKK: sta", + "No": "Ei" } From 6ab226c43aac991d517ff7fab2ffdb99d9432839 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 2 Apr 2022 13:58:15 -0500 Subject: [PATCH 0403/2320] Add Support --- .../Applications/Whisparr/Whisparr.cs | 179 ++++++++++++++++++ .../Applications/Whisparr/WhisparrField.cs | 22 +++ .../Applications/Whisparr/WhisparrIndexer.cs | 44 +++++ .../Applications/Whisparr/WhisparrSettings.cs | 46 +++++ .../Applications/Whisparr/WhisparrStatus.cs | 7 + .../Applications/Whisparr/WhisparrV3Proxy.cs | 157 +++++++++++++++ 6 files changed, 455 insertions(+) create mode 100644 src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs create mode 100644 src/NzbDrone.Core/Applications/Whisparr/WhisparrField.cs create mode 100644 src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs create mode 100644 src/NzbDrone.Core/Applications/Whisparr/WhisparrSettings.cs create mode 100644 src/NzbDrone.Core/Applications/Whisparr/WhisparrStatus.cs create mode 100644 src/NzbDrone.Core/Applications/Whisparr/WhisparrV3Proxy.cs diff --git a/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs b/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs new file mode 100644 index 000000000..fe0f294ab --- /dev/null +++ b/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using FluentValidation.Results; +using Newtonsoft.Json.Linq; +using NLog; +using NzbDrone.Common.Cache; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers; + +namespace NzbDrone.Core.Applications.Whisparr +{ + public class Radarr : ApplicationBase<WhisparrSettings> + { + public override string Name => "Whisparr"; + + private readonly IWhisparrV3Proxy _whisparrV3Proxy; + private readonly ICached<List<WhisparrIndexer>> _schemaCache; + private readonly IConfigFileProvider _configFileProvider; + + public Radarr(ICacheManager cacheManager, IWhisparrV3Proxy whisparrV3Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, Logger logger) + : base(appIndexerMapService, logger) + { + _schemaCache = cacheManager.GetCache<List<WhisparrIndexer>>(GetType()); + _whisparrV3Proxy = whisparrV3Proxy; + _configFileProvider = configFileProvider; + } + + public override ValidationResult Test() + { + var failures = new List<ValidationFailure>(); + + var testIndexer = new IndexerDefinition + { + Id = 0, + Name = "Test", + Protocol = DownloadProtocol.Usenet, + Capabilities = new IndexerCapabilities() + }; + + foreach (var cat in NewznabStandardCategory.AllCats) + { + testIndexer.Capabilities.Categories.AddCategoryMapping(1, cat); + } + + try + { + failures.AddIfNotNull(_whisparrV3Proxy.TestConnection(BuildWhisparrIndexer(testIndexer, DownloadProtocol.Usenet), Settings)); + } + catch (WebException ex) + { + _logger.Error(ex, "Unable to send test message"); + failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Unable to complete application test, cannot connect to Whisparr")); + } + + return new ValidationResult(failures); + } + + public override List<AppIndexerMap> GetIndexerMappings() + { + var indexers = _whisparrV3Proxy.GetIndexers(Settings) + .Where(i => i.Implementation == "Newznab" || i.Implementation == "Torznab"); + + var mappings = new List<AppIndexerMap>(); + + foreach (var indexer in indexers) + { + if ((string)indexer.Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value == _configFileProvider.ApiKey) + { + var match = AppIndexerRegex.Match((string)indexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value); + + if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId)) + { + //Add parsed mapping if it's mapped to a Indexer in this Prowlarr instance + mappings.Add(new AppIndexerMap { RemoteIndexerId = indexer.Id, IndexerId = indexerId }); + } + } + } + + return mappings; + } + + public override void AddIndexer(IndexerDefinition indexer) + { + if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) + { + var radarrIndexer = BuildWhisparrIndexer(indexer, indexer.Protocol); + + var remoteIndexer = _whisparrV3Proxy.AddIndexer(radarrIndexer, Settings); + _appIndexerMapService.Insert(new AppIndexerMap { AppId = Definition.Id, IndexerId = indexer.Id, RemoteIndexerId = remoteIndexer.Id }); + } + } + + public override void RemoveIndexer(int indexerId) + { + var appMappings = _appIndexerMapService.GetMappingsForApp(Definition.Id); + + var indexerMapping = appMappings.FirstOrDefault(m => m.IndexerId == indexerId); + + if (indexerMapping != null) + { + //Remove Indexer remotely and then remove the mapping + _whisparrV3Proxy.RemoveIndexer(indexerMapping.RemoteIndexerId, Settings); + _appIndexerMapService.Delete(indexerMapping.Id); + } + } + + public override void UpdateIndexer(IndexerDefinition indexer) + { + _logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id); + + var appMappings = _appIndexerMapService.GetMappingsForApp(Definition.Id); + var indexerMapping = appMappings.FirstOrDefault(m => m.IndexerId == indexer.Id); + + var radarrIndexer = BuildWhisparrIndexer(indexer, indexer.Protocol, indexerMapping?.RemoteIndexerId ?? 0); + + var remoteIndexer = _whisparrV3Proxy.GetIndexer(indexerMapping.RemoteIndexerId, Settings); + + if (remoteIndexer != null) + { + _logger.Debug("Remote indexer found, syncing with current settings"); + + if (!radarrIndexer.Equals(remoteIndexer)) + { + _whisparrV3Proxy.UpdateIndexer(radarrIndexer, Settings); + } + } + else + { + _appIndexerMapService.Delete(indexerMapping.Id); + + if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) + { + _logger.Debug("Remote indexer not found, re-adding {0} to Whisparr", indexer.Name); + radarrIndexer.Id = 0; + var newRemoteIndexer = _whisparrV3Proxy.AddIndexer(radarrIndexer, Settings); + _appIndexerMapService.Insert(new AppIndexerMap { AppId = Definition.Id, IndexerId = indexer.Id, RemoteIndexerId = newRemoteIndexer.Id }); + } + else + { + _logger.Debug("Remote indexer not found for {0}, skipping re-add to Radarr due to indexer capabilities", indexer.Name); + } + } + } + + private WhisparrIndexer BuildWhisparrIndexer(IndexerDefinition indexer, DownloadProtocol protocol, int id = 0) + { + var cacheKey = $"{Settings.BaseUrl}"; + var schemas = _schemaCache.Get(cacheKey, () => _whisparrV3Proxy.GetIndexerSchema(Settings), TimeSpan.FromDays(7)); + + var newznab = schemas.Where(i => i.Implementation == "Newznab").First(); + var torznab = schemas.Where(i => i.Implementation == "Torznab").First(); + + var schema = protocol == DownloadProtocol.Usenet ? newznab : torznab; + + var whisparrIndexer = new WhisparrIndexer + { + Id = id, + Name = $"{indexer.Name} (Prowlarr)", + EnableRss = indexer.Enable && indexer.AppProfile.Value.EnableRss, + EnableAutomaticSearch = indexer.Enable && indexer.AppProfile.Value.EnableAutomaticSearch, + EnableInteractiveSearch = indexer.Enable && indexer.AppProfile.Value.EnableInteractiveSearch, + Priority = indexer.Priority, + Implementation = indexer.Protocol == DownloadProtocol.Usenet ? "Newznab" : "Torznab", + ConfigContract = schema.ConfigContract, + Fields = schema.Fields, + }; + + whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/"; + whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/api"; + whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey; + whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray())); + + return whisparrIndexer; + } + } +} diff --git a/src/NzbDrone.Core/Applications/Whisparr/WhisparrField.cs b/src/NzbDrone.Core/Applications/Whisparr/WhisparrField.cs new file mode 100644 index 000000000..e3b1139b1 --- /dev/null +++ b/src/NzbDrone.Core/Applications/Whisparr/WhisparrField.cs @@ -0,0 +1,22 @@ +namespace NzbDrone.Core.Applications.Whisparr +{ + public class WhisparrField + { + public int Order { get; set; } + public string Name { get; set; } + public string Label { get; set; } + public string Unit { get; set; } + public string HelpText { get; set; } + public string HelpLink { get; set; } + public object Value { get; set; } + public string Type { get; set; } + public bool Advanced { get; set; } + public string Section { get; set; } + public string Hidden { get; set; } + + public WhisparrField Clone() + { + return (WhisparrField)MemberwiseClone(); + } + } +} diff --git a/src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs b/src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs new file mode 100644 index 000000000..cd8c5df01 --- /dev/null +++ b/src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json.Linq; + +namespace NzbDrone.Core.Applications.Whisparr +{ + public class WhisparrIndexer + { + public int Id { get; set; } + public bool EnableRss { get; set; } + public bool EnableAutomaticSearch { get; set; } + public bool EnableInteractiveSearch { get; set; } + public int Priority { get; set; } + public string Name { get; set; } + public string ImplementationName { get; set; } + public string Implementation { get; set; } + public string ConfigContract { get; set; } + public string InfoLink { get; set; } + public HashSet<int> Tags { get; set; } + public List<WhisparrField> Fields { get; set; } + + public bool Equals(WhisparrIndexer other) + { + if (ReferenceEquals(null, other)) + { + return false; + } + + var baseUrl = (string)Fields.FirstOrDefault(x => x.Name == "baseUrl").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value; + var apiPath = (string)Fields.FirstOrDefault(x => x.Name == "apiPath").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; + var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey").Value; + var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value); + + return other.EnableRss == EnableRss && + other.EnableAutomaticSearch == EnableAutomaticSearch && + other.EnableInteractiveSearch == EnableInteractiveSearch && + other.Name == Name && + other.Implementation == Implementation && + other.Priority == Priority && + other.Id == Id && + apiKey && apiPath && baseUrl && cats; + } + } +} diff --git a/src/NzbDrone.Core/Applications/Whisparr/WhisparrSettings.cs b/src/NzbDrone.Core/Applications/Whisparr/WhisparrSettings.cs new file mode 100644 index 000000000..a6be4ebdc --- /dev/null +++ b/src/NzbDrone.Core/Applications/Whisparr/WhisparrSettings.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Applications.Whisparr +{ + public class WhisparrSettingsValidator : AbstractValidator<WhisparrSettings> + { + public WhisparrSettingsValidator() + { + RuleFor(c => c.BaseUrl).IsValidUrl(); + RuleFor(c => c.ProwlarrUrl).IsValidUrl(); + RuleFor(c => c.ApiKey).NotEmpty(); + RuleFor(c => c.SyncCategories).NotEmpty(); + } + } + + public class WhisparrSettings : IApplicationSettings + { + private static readonly WhisparrSettingsValidator Validator = new WhisparrSettingsValidator(); + + public WhisparrSettings() + { + SyncCategories = new[] { 6000, 6010, 6020, 6030, 6040, 6045, 6050, 6070, 6080, 6090 }; + } + + [FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Whisparr sees it, including http(s)://, port, and urlbase if needed", Placeholder = "http://localhost:9696")] + public string ProwlarrUrl { get; set; } + + [FieldDefinition(1, Label = "Whisparr Server", HelpText = "URL used to connect to Whisparr server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:6969")] + public string BaseUrl { get; set; } + + [FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Whisparr in Settings/General")] + public string ApiKey { get; set; } + + [FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")] + public IEnumerable<int> SyncCategories { get; set; } + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} diff --git a/src/NzbDrone.Core/Applications/Whisparr/WhisparrStatus.cs b/src/NzbDrone.Core/Applications/Whisparr/WhisparrStatus.cs new file mode 100644 index 000000000..59b8c6e44 --- /dev/null +++ b/src/NzbDrone.Core/Applications/Whisparr/WhisparrStatus.cs @@ -0,0 +1,7 @@ +namespace NzbDrone.Core.Applications.Whisparr +{ + public class WhisparrStatus + { + public string Version { get; set; } + } +} diff --git a/src/NzbDrone.Core/Applications/Whisparr/WhisparrV3Proxy.cs b/src/NzbDrone.Core/Applications/Whisparr/WhisparrV3Proxy.cs new file mode 100644 index 000000000..cedd8fc29 --- /dev/null +++ b/src/NzbDrone.Core/Applications/Whisparr/WhisparrV3Proxy.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using FluentValidation.Results; +using Newtonsoft.Json; +using NLog; +using NzbDrone.Common.Http; +using NzbDrone.Common.Serializer; + +namespace NzbDrone.Core.Applications.Whisparr +{ + public interface IWhisparrV3Proxy + { + WhisparrIndexer AddIndexer(WhisparrIndexer indexer, WhisparrSettings settings); + List<WhisparrIndexer> GetIndexers(WhisparrSettings settings); + WhisparrIndexer GetIndexer(int indexerId, WhisparrSettings settings); + List<WhisparrIndexer> GetIndexerSchema(WhisparrSettings settings); + void RemoveIndexer(int indexerId, WhisparrSettings settings); + WhisparrIndexer UpdateIndexer(WhisparrIndexer indexer, WhisparrSettings settings); + ValidationFailure TestConnection(WhisparrIndexer indexer, WhisparrSettings settings); + } + + public class WhisparrV3Proxy : IWhisparrV3Proxy + { + private readonly IHttpClient _httpClient; + private readonly Logger _logger; + + public WhisparrV3Proxy(IHttpClient httpClient, Logger logger) + { + _httpClient = httpClient; + _logger = logger; + } + + public WhisparrStatus GetStatus(WhisparrSettings settings) + { + var request = BuildRequest(settings, "/api/v3/system/status", HttpMethod.Get); + return Execute<WhisparrStatus>(request); + } + + public List<WhisparrIndexer> GetIndexers(WhisparrSettings settings) + { + var request = BuildRequest(settings, "/api/v3/indexer", HttpMethod.Get); + return Execute<List<WhisparrIndexer>>(request); + } + + public WhisparrIndexer GetIndexer(int indexerId, WhisparrSettings settings) + { + try + { + var request = BuildRequest(settings, $"/api/v3/indexer/{indexerId}", HttpMethod.Get); + return Execute<WhisparrIndexer>(request); + } + catch (HttpException ex) + { + if (ex.Response.StatusCode != HttpStatusCode.NotFound) + { + throw; + } + } + + return null; + } + + public void RemoveIndexer(int indexerId, WhisparrSettings settings) + { + var request = BuildRequest(settings, $"/api/v3/indexer/{indexerId}", HttpMethod.Delete); + _httpClient.Execute(request); + } + + public List<WhisparrIndexer> GetIndexerSchema(WhisparrSettings settings) + { + var request = BuildRequest(settings, "/api/v3/indexer/schema", HttpMethod.Get); + return Execute<List<WhisparrIndexer>>(request); + } + + public WhisparrIndexer AddIndexer(WhisparrIndexer indexer, WhisparrSettings settings) + { + var request = BuildRequest(settings, "/api/v3/indexer", HttpMethod.Post); + + request.SetContent(indexer.ToJson()); + + return Execute<WhisparrIndexer>(request); + } + + public WhisparrIndexer UpdateIndexer(WhisparrIndexer indexer, WhisparrSettings settings) + { + var request = BuildRequest(settings, $"/api/v3/indexer/{indexer.Id}", HttpMethod.Put); + + request.SetContent(indexer.ToJson()); + + return Execute<WhisparrIndexer>(request); + } + + public ValidationFailure TestConnection(WhisparrIndexer indexer, WhisparrSettings settings) + { + var request = BuildRequest(settings, $"/api/v3/indexer/test", HttpMethod.Post); + + request.SetContent(indexer.ToJson()); + + try + { + Execute<WhisparrIndexer>(request); + } + catch (HttpException ex) + { + if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) + { + _logger.Error(ex, "API Key is invalid"); + return new ValidationFailure("ApiKey", "API Key is invalid"); + } + + if (ex.Response.StatusCode == HttpStatusCode.BadRequest) + { + _logger.Error(ex, "Prowlarr URL is invalid"); + return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Whisparr cannot connect to Prowlarr"); + } + + _logger.Error(ex, "Unable to send test message"); + return new ValidationFailure("BaseUrl", "Unable to complete application test"); + } + catch (Exception ex) + { + _logger.Error(ex, "Unable to send test message"); + return new ValidationFailure("", "Unable to send test message"); + } + + return null; + } + + private HttpRequest BuildRequest(WhisparrSettings settings, string resource, HttpMethod method) + { + var baseUrl = settings.BaseUrl.TrimEnd('/'); + + var request = new HttpRequestBuilder(baseUrl).Resource(resource) + .SetHeader("X-Api-Key", settings.ApiKey) + .Build(); + + request.Headers.ContentType = "application/json"; + + request.Method = method; + request.AllowAutoRedirect = true; + + return request; + } + + private TResource Execute<TResource>(HttpRequest request) + where TResource : new() + { + var response = _httpClient.Execute(request); + + var results = JsonConvert.DeserializeObject<TResource>(response.Content); + + return results; + } + } +} From 1dbf35deb51631fce225d6ea2eda7b95faa419ef Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 29 Mar 2022 22:26:25 -0500 Subject: [PATCH 0404/2320] Fixed: Cleanup Temp files after backup creation Fixes #925 (cherry picked from commit 7f0b708cb9f16a0116199625a2a5b4e67049be6a) --- src/NzbDrone.Core/Backup/BackupService.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/NzbDrone.Core/Backup/BackupService.cs b/src/NzbDrone.Core/Backup/BackupService.cs index a25f67e21..e1b7fe008 100644 --- a/src/NzbDrone.Core/Backup/BackupService.cs +++ b/src/NzbDrone.Core/Backup/BackupService.cs @@ -90,6 +90,8 @@ namespace NzbDrone.Core.Backup _archiveService.CreateZip(backupPath, _diskProvider.GetFiles(_backupTempFolder, SearchOption.TopDirectoryOnly)); + Cleanup(); + _logger.ProgressDebug("Backup zip created"); } From b4b779df5cf1d848219270014d1f0de00e28d832 Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Sat, 2 Apr 2022 14:18:07 -0500 Subject: [PATCH 0405/2320] Fixed: Loading old commands from database Fixes #926 (cherry picked from commit 0f87cb72e559a19bddc6c9d4387ec7d9428291f8) --- .../Datastore/Converters/TimeSpanConverter.cs | 19 +++++++++++++++++++ src/NzbDrone.Core/Datastore/TableMapping.cs | 1 + 2 files changed, 20 insertions(+) create mode 100644 src/NzbDrone.Core/Datastore/Converters/TimeSpanConverter.cs diff --git a/src/NzbDrone.Core/Datastore/Converters/TimeSpanConverter.cs b/src/NzbDrone.Core/Datastore/Converters/TimeSpanConverter.cs new file mode 100644 index 000000000..902a26009 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Converters/TimeSpanConverter.cs @@ -0,0 +1,19 @@ +using System; +using System.Data; +using Dapper; + +namespace NzbDrone.Core.Datastore.Converters +{ + public class DapperTimeSpanConverter : SqlMapper.TypeHandler<TimeSpan> + { + public override void SetValue(IDbDataParameter parameter, TimeSpan value) + { + parameter.Value = value.ToString(); + } + + public override TimeSpan Parse(object value) + { + return TimeSpan.Parse((string)value); + } + } +} diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index 685b7fb22..27c70fb9e 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -105,6 +105,7 @@ namespace NzbDrone.Core.Datastore SqlMapper.RemoveTypeMap(typeof(DateTime)); SqlMapper.AddTypeHandler(new DapperUtcConverter()); + SqlMapper.AddTypeHandler(new DapperTimeSpanConverter()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<Dictionary<string, string>>()); SqlMapper.AddTypeHandler(new CookieConverter()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<int>>()); From 37c393a65923aaa65b2e4d27d25ddcb19c619e9b Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 15 Mar 2022 14:38:27 -0500 Subject: [PATCH 0406/2320] New: (Lidarr/Radarr/Readarr/Sonarr) Improved Errors --- .../Applications/Lidarr/LidarrV1Proxy.cs | 6 ++++++ .../Applications/Radarr/RadarrV3Proxy.cs | 6 ++++++ .../Applications/Readarr/ReadarrV1Proxy.cs | 6 ++++++ .../Applications/Sonarr/SonarrV3Proxy.cs | 12 ++++++++++++ .../Applications/Whisparr/WhisparrV3Proxy.cs | 6 ++++++ 5 files changed, 36 insertions(+) diff --git a/src/NzbDrone.Core/Applications/Lidarr/LidarrV1Proxy.cs b/src/NzbDrone.Core/Applications/Lidarr/LidarrV1Proxy.cs index 449ce6236..e46c603ea 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/LidarrV1Proxy.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/LidarrV1Proxy.cs @@ -116,6 +116,12 @@ namespace NzbDrone.Core.Applications.Lidarr return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Lidarr cannot connect to Prowlarr"); } + if (ex.Response.StatusCode == HttpStatusCode.SeeOther) + { + _logger.Error(ex, "Lidarr returned redirect and is invalid"); + return new ValidationFailure("BaseUrl", "Lidarr url is invalid, Prowlarr cannot connect to Lidarr - are you missing a url base?"); + } + _logger.Error(ex, "Unable to send test message"); return new ValidationFailure("BaseUrl", "Unable to complete application test"); } diff --git a/src/NzbDrone.Core/Applications/Radarr/RadarrV3Proxy.cs b/src/NzbDrone.Core/Applications/Radarr/RadarrV3Proxy.cs index fc1fd76c4..c5445c7d0 100644 --- a/src/NzbDrone.Core/Applications/Radarr/RadarrV3Proxy.cs +++ b/src/NzbDrone.Core/Applications/Radarr/RadarrV3Proxy.cs @@ -116,6 +116,12 @@ namespace NzbDrone.Core.Applications.Radarr return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Radarr cannot connect to Prowlarr"); } + if (ex.Response.StatusCode == HttpStatusCode.SeeOther) + { + _logger.Error(ex, "Radarr returned redirect and is invalid"); + return new ValidationFailure("BaseUrl", "Radarr url is invalid, Prowlarr cannot connect to Radarr - are you missing a url base?"); + } + _logger.Error(ex, "Unable to send test message"); return new ValidationFailure("BaseUrl", "Unable to complete application test"); } diff --git a/src/NzbDrone.Core/Applications/Readarr/ReadarrV1Proxy.cs b/src/NzbDrone.Core/Applications/Readarr/ReadarrV1Proxy.cs index 11c764d4a..0a5319a47 100644 --- a/src/NzbDrone.Core/Applications/Readarr/ReadarrV1Proxy.cs +++ b/src/NzbDrone.Core/Applications/Readarr/ReadarrV1Proxy.cs @@ -116,6 +116,12 @@ namespace NzbDrone.Core.Applications.Readarr return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Readarr cannot connect to Prowlarr"); } + if (ex.Response.StatusCode == HttpStatusCode.SeeOther) + { + _logger.Error(ex, "Readarr returned redirect and is invalid"); + return new ValidationFailure("BaseUrl", "Readarr url is invalid, Prowlarr cannot connect to Readarr - are you missing a url base?"); + } + _logger.Error(ex, "Unable to send test message"); return new ValidationFailure("BaseUrl", "Unable to complete application test"); } diff --git a/src/NzbDrone.Core/Applications/Sonarr/SonarrV3Proxy.cs b/src/NzbDrone.Core/Applications/Sonarr/SonarrV3Proxy.cs index 47c06f71a..9e8436f56 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/SonarrV3Proxy.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/SonarrV3Proxy.cs @@ -116,6 +116,18 @@ namespace NzbDrone.Core.Applications.Sonarr return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Sonarr cannot connect to Prowlarr"); } + if (ex.Response.StatusCode == HttpStatusCode.SeeOther) + { + _logger.Error(ex, "Sonarr returned redirect and is invalid"); + return new ValidationFailure("BaseUrl", "Sonarr url is invalid, Prowlarr cannot connect to Sonarr - are you missing a url base?"); + } + + if (ex.Response.StatusCode == HttpStatusCode.NotFound) + { + _logger.Error(ex, "Sonarr not found"); + return new ValidationFailure("BaseUrl", "Sonarr url is invalid, Prowlarr cannot connect to Sonarr. Is Sonarr running and accessible? Sonarr v2 is not supported."); + } + _logger.Error(ex, "Unable to send test message"); return new ValidationFailure("BaseUrl", "Unable to complete application test"); } diff --git a/src/NzbDrone.Core/Applications/Whisparr/WhisparrV3Proxy.cs b/src/NzbDrone.Core/Applications/Whisparr/WhisparrV3Proxy.cs index cedd8fc29..cd3a715de 100644 --- a/src/NzbDrone.Core/Applications/Whisparr/WhisparrV3Proxy.cs +++ b/src/NzbDrone.Core/Applications/Whisparr/WhisparrV3Proxy.cs @@ -116,6 +116,12 @@ namespace NzbDrone.Core.Applications.Whisparr return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Whisparr cannot connect to Prowlarr"); } + if (ex.Response.StatusCode == HttpStatusCode.SeeOther) + { + _logger.Error(ex, "Whisparr returned redirect and is invalid"); + return new ValidationFailure("BaseUrl", "Whisparr url is invalid, Prowlarr cannot connect to Whisparr - are you missing a url base?"); + } + _logger.Error(ex, "Unable to send test message"); return new ValidationFailure("BaseUrl", "Unable to complete application test"); } From e07ea8097790ea2ac6d6e052133322a33c38b405 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 24 Jan 2022 11:34:02 -0600 Subject: [PATCH 0407/2320] Fixed: (BTN) Handle Query Limit Error --- .../BroadcastheNet/BroadcastheNetParser.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNetParser.cs b/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNetParser.cs index e510480b0..242c51a27 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNetParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNetParser.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Text.RegularExpressions; +using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Parser.Model; @@ -25,8 +26,9 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var results = new List<ReleaseInfo>(); + var indexerHttpResponse = indexerResponse.HttpResponse; - switch (indexerResponse.HttpResponse.StatusCode) + switch (indexerHttpResponse.StatusCode) { case HttpStatusCode.Unauthorized: throw new IndexerAuthException("API Key invalid or not authorized"); @@ -35,25 +37,30 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet case HttpStatusCode.ServiceUnavailable: throw new RequestLimitReachedException(indexerResponse, "Cannot do more than 150 API requests per hour."); default: - if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) + if (indexerHttpResponse.StatusCode != HttpStatusCode.OK) { - throw new IndexerException(indexerResponse, "Indexer API call returned an unexpected StatusCode [{0}]", indexerResponse.HttpResponse.StatusCode); + throw new IndexerException(indexerResponse, "Indexer API call returned an unexpected StatusCode [{0}]", indexerHttpResponse.StatusCode); } break; } - if (indexerResponse.HttpResponse.Headers.ContentType != null && indexerResponse.HttpResponse.Headers.ContentType.Contains("text/html")) + if (indexerHttpResponse.Headers.ContentType != null && indexerHttpResponse.Headers.ContentType.Contains("text/html")) { throw new IndexerException(indexerResponse, "Indexer responded with html content. Site is likely blocked or unavailable."); } + if (indexerResponse.Content.ContainsIgnoreCase("Call Limit Exceeded")) + { + throw new RequestLimitReachedException(indexerResponse, "Cannot do more than 150 API requests per hour."); + } + if (indexerResponse.Content == "Query execution was interrupted") { throw new IndexerException(indexerResponse, "Indexer API returned an internal server error"); } - JsonRpcResponse<BroadcastheNetTorrents> jsonResponse = new HttpResponse<JsonRpcResponse<BroadcastheNetTorrents>>(indexerResponse.HttpResponse).Resource; + JsonRpcResponse<BroadcastheNetTorrents> jsonResponse = new HttpResponse<JsonRpcResponse<BroadcastheNetTorrents>>(indexerHttpResponse).Resource; if (jsonResponse.Error != null || jsonResponse.Result == null) { From 8762d94ddaef24bf50d1f294624385e8539716d6 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 24 Jan 2022 11:37:28 -0600 Subject: [PATCH 0408/2320] New: (BTN) Rate Limit to 1 Query per 5 Seconds --- .../Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs b/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs index bf5762aaa..183e3c00c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using NLog; using NzbDrone.Common.Http; @@ -16,6 +17,7 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet public override bool SupportsSearch => true; public override int PageSize => 100; public override IndexerCapabilities Capabilities => SetCapabilities(); + public override TimeSpan RateLimit => TimeSpan.FromSeconds(5); public override string[] IndexerUrls => new string[] { "http://api.broadcasthe.net/" }; public override string Description => "BroadcasTheNet (BTN) is an invite-only torrent tracker focused on TV shows"; From c4468b9cbb5c98376e8c165d019cfe428419dd7a Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 24 Jan 2022 00:09:21 -0600 Subject: [PATCH 0409/2320] Fixed: (PTP) Treat 403 as Query Limit --- .../PassThePopcorn/PassThePopcornParser.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornParser.cs b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornParser.cs index 7086788b0..46273b077 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornParser.cs @@ -25,26 +25,32 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List<ReleaseInfo>(); + var indexerHttpResponse = indexerResponse.HttpResponse; - if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) + if (indexerHttpResponse.StatusCode != HttpStatusCode.OK) { // Remove cookie cache - if (indexerResponse.HttpResponse.HasHttpRedirect && indexerResponse.HttpResponse.RedirectUrl + if (indexerHttpResponse.HasHttpRedirect && indexerHttpResponse.RedirectUrl .ContainsIgnoreCase("login.php")) { CookiesUpdater(null, null); - throw new IndexerException(indexerResponse, "We are being redirected to the PTP login page. Most likely your session expired or was killed. Try testing the indexer in the settings."); + throw new IndexerAuthException("We are being redirected to the PTP login page. Most likely your session expired or was killed. Try testing the indexer in the settings."); + } + + if (indexerHttpResponse.StatusCode == HttpStatusCode.Forbidden) + { + throw new RequestLimitReachedException(indexerResponse, "PTP Query Limit Reached. Please try again later."); } throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request"); } - if (indexerResponse.HttpResponse.Headers.ContentType != HttpAccept.Json.Value) + if (indexerHttpResponse.Headers.ContentType != HttpAccept.Json.Value) { - if (indexerResponse.HttpResponse.Request.Url.Path.ContainsIgnoreCase("login.php")) + if (indexerHttpResponse.Request.Url.Path.ContainsIgnoreCase("login.php")) { CookiesUpdater(null, null); - throw new IndexerException(indexerResponse, "We are currently on the login page. Most likely your session expired or was killed. Try testing the indexer in the settings."); + throw new IndexerAuthException("We are currently on the login page. Most likely your session expired or was killed. Try testing the indexer in the settings."); } // Remove cookie cache From 1959efbd09ca76ed18c733e3b3022eb7614c07b9 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 24 Jan 2022 11:29:32 -0600 Subject: [PATCH 0410/2320] Fixed: (HDBits) Treat 403 as Query Limit --- .../Definitions/HDBits/HDBitsParser.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsParser.cs b/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsParser.cs index ad76e0970..2819df47c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsParser.cs @@ -23,29 +23,29 @@ namespace NzbDrone.Core.Indexers.HDBits public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { var torrentInfos = new List<ReleaseInfo>(); + var indexerHttpResponse = indexerResponse.HttpResponse; - if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) + if (indexerHttpResponse.StatusCode == HttpStatusCode.Forbidden) { - throw new IndexerException(indexerResponse, - "Unexpected response status {0} code from API request", - indexerResponse.HttpResponse.StatusCode); + throw new RequestLimitReachedException(indexerResponse, "HDBits Query Limit Reached. Please try again later."); + } + + if (indexerHttpResponse.StatusCode != HttpStatusCode.OK) + { + throw new IndexerException(indexerResponse, "Unexpected response status {0} code from API request", indexerHttpResponse.StatusCode); } var jsonResponse = JsonConvert.DeserializeObject<HDBitsResponse>(indexerResponse.Content); if (jsonResponse.Status != StatusCode.Success) { - throw new IndexerException(indexerResponse, - "HDBits API request returned status code {0}: {1}", - jsonResponse.Status, - jsonResponse.Message ?? string.Empty); + throw new IndexerException(indexerResponse, "HDBits API request returned status code {0}: {1}", jsonResponse.Status, jsonResponse.Message ?? string.Empty); } var responseData = jsonResponse.Data as JArray; if (responseData == null) { - throw new IndexerException(indexerResponse, - "Indexer API call response missing result data"); + throw new IndexerException(indexerResponse, "Indexer API call response missing result data"); } var queryResults = responseData.ToObject<TorrentQueryResponse[]>(); From 710c3d6deb01a47551e9e776826b5d9f4cce04fb Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 2 Apr 2022 15:34:36 -0500 Subject: [PATCH 0411/2320] Fix indent from 37c393a659 --- src/NzbDrone.Core/Applications/Whisparr/WhisparrV3Proxy.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Applications/Whisparr/WhisparrV3Proxy.cs b/src/NzbDrone.Core/Applications/Whisparr/WhisparrV3Proxy.cs index cd3a715de..bb3d01616 100644 --- a/src/NzbDrone.Core/Applications/Whisparr/WhisparrV3Proxy.cs +++ b/src/NzbDrone.Core/Applications/Whisparr/WhisparrV3Proxy.cs @@ -116,7 +116,7 @@ namespace NzbDrone.Core.Applications.Whisparr return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Whisparr cannot connect to Prowlarr"); } - if (ex.Response.StatusCode == HttpStatusCode.SeeOther) + if (ex.Response.StatusCode == HttpStatusCode.SeeOther) { _logger.Error(ex, "Whisparr returned redirect and is invalid"); return new ValidationFailure("BaseUrl", "Whisparr url is invalid, Prowlarr cannot connect to Whisparr - are you missing a url base?"); From a5c7c6cbcb5efc538cf21ed20aeb42b3654ac967 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 2 Apr 2022 16:30:29 -0500 Subject: [PATCH 0412/2320] We don't have two Radarrs --- src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs b/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs index fe0f294ab..f665905cc 100644 --- a/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs +++ b/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs @@ -12,7 +12,7 @@ using NzbDrone.Core.Indexers; namespace NzbDrone.Core.Applications.Whisparr { - public class Radarr : ApplicationBase<WhisparrSettings> + public class Whisparr : ApplicationBase<WhisparrSettings> { public override string Name => "Whisparr"; @@ -20,7 +20,7 @@ namespace NzbDrone.Core.Applications.Whisparr private readonly ICached<List<WhisparrIndexer>> _schemaCache; private readonly IConfigFileProvider _configFileProvider; - public Radarr(ICacheManager cacheManager, IWhisparrV3Proxy whisparrV3Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, Logger logger) + public Whisparr(ICacheManager cacheManager, IWhisparrV3Proxy whisparrV3Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, Logger logger) : base(appIndexerMapService, logger) { _schemaCache = cacheManager.GetCache<List<WhisparrIndexer>>(GetType()); From d440bc079ff20b96e775ac6b3a679e91c2c276da Mon Sep 17 00:00:00 2001 From: missingfile <102856208+missingfile@users.noreply.github.com> Date: Sat, 2 Apr 2022 21:06:26 +0200 Subject: [PATCH 0413/2320] Fixed: MoreThanTV indexer from browse page layout changes (#922) --- .../Indexers/Definitions/MoreThanTV.cs | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs b/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs index 63069e75c..3b7273447 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs @@ -150,14 +150,14 @@ public class MoreThanTVRequestGenerator : IIndexerRequestGenerator qc.Add("filter_cat[2]", "1"); // SD Movies break; case TvSearchCriteria: - qc.Add("filter_cat[3]", "1"); // HD EPISODE + qc.Add("filter_cat[3]", "1"); // HD Episode qc.Add("filter_cat[4]", "1"); // SD Episode qc.Add("filter_cat[5]", "1"); // HD Season qc.Add("filter_cat[6]", "1"); // SD Season break; } - return $"{Settings.BaseUrl}torrents.php?{qc.GetQueryString()}"; + return $"{Settings.BaseUrl}torrents/browse?{qc.GetQueryString()}"; } private string GetSearchString(string input) @@ -188,28 +188,25 @@ public class MoreThanTVParser : IParseIndexerResponse foreach (var torrent in torrents) { // Parse required data - var torrentGroup = torrent.QuerySelectorAll("table a[href^=\"/torrents.php?action=download\"]"); - foreach (var downloadAnchor in torrentGroup) + var downloadAnchor = torrent.QuerySelector("span a[href^=\"/torrents.php?action=download\"]"); + var title = downloadAnchor.ParentElement.ParentElement.ParentElement.QuerySelector("a[class=\"overlay_torrent\"]").TextContent.Trim(); + title = CleanUpTitle(title); + + var category = torrent.QuerySelector(".cats_col div").GetAttribute("title"); + + // default to Other + var indexerCategory = NewznabStandardCategory.Other; + + if (movies.Any(category.Contains)) { - var title = downloadAnchor.ParentElement.ParentElement.ParentElement.TextContent.Trim(); - title = CleanUpTitle(title); - - var category = torrent.QuerySelector(".cats_col div").GetAttribute("title"); - - // default to Other - var indexerCategory = NewznabStandardCategory.Other; - - if (movies.Any(category.Contains)) - { - indexerCategory = NewznabStandardCategory.Movies; - } - else if (tv.Any(category.Contains)) - { - indexerCategory = NewznabStandardCategory.TV; - } - - releases.Add(GetReleaseInfo(torrent, downloadAnchor, title, indexerCategory)); + indexerCategory = NewznabStandardCategory.Movies; } + else if (tv.Any(category.Contains)) + { + indexerCategory = NewznabStandardCategory.TV; + } + + releases.Add(GetReleaseInfo(torrent, downloadAnchor, title, indexerCategory)); } return releases; @@ -231,7 +228,7 @@ public class MoreThanTVParser : IParseIndexerResponse private ReleaseInfo GetReleaseInfo(IElement row, IElement downloadAnchor, string title, IndexerCategory category) { // count from bottom - const int FILES_COL = 8; + const int FILES_COL = 7; /*const int COMMENTS_COL = 7;*/ const int DATE_COL = 6; const int FILESIZE_COL = 5; From 4f8311641376f8304112e565ad980ab9679c286f Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 3 Apr 2022 10:35:57 -0500 Subject: [PATCH 0414/2320] Fixed: (BHD) TMDb Parsing Exception --- src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs b/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs index c09a0aede..f1d708b46 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs @@ -218,7 +218,7 @@ namespace NzbDrone.Core.Indexers.Definitions Grabs = row.Grabs, Seeders = row.Seeders, ImdbId = ParseUtil.GetImdbID(row.ImdbId).GetValueOrDefault(), - TmdbId = row.TmdbId.IsNullOrWhiteSpace() ? 0 : ParseUtil.CoerceInt(row.TmdbId.Split("/")[1]), + TmdbId = row.TmdbId.IsNullOrWhiteSpace() ? 0 : (int)ParseUtil.CoerceLong(row.TmdbId.Split("/")[1]), Peers = row.Leechers + row.Seeders, DownloadVolumeFactor = row.Freeleech || row.Limited ? 0 : row.Promo75 ? 0.25 : row.Promo50 ? 0.5 : row.Promo25 ? 0.75 : 1, UploadVolumeFactor = 1, From 60d9f028305bf2a636c27f0953a4f2329a743bc9 Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Thu, 7 Apr 2022 21:11:32 +0100 Subject: [PATCH 0415/2320] New: MyAnonamouse freeleech support --- .../Indexers/Definitions/MyAnonamouse.cs | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs b/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs index eb7f716ea..adce185e1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs @@ -4,10 +4,13 @@ using System.Collections.Specialized; using System.Globalization; using System.Linq; using System.Net; +using System.Text.RegularExpressions; +using System.Threading.Tasks; using FluentValidation; using Newtonsoft.Json; using NLog; using NzbDrone.Common.Http; +using NzbDrone.Common.Serializer; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; @@ -21,6 +24,8 @@ namespace NzbDrone.Core.Indexers.Definitions { public class MyAnonamouse : TorrentIndexerBase<MyAnonamouseSettings> { + private static readonly Regex TorrentIdRegex = new Regex(@"tor/download.php\?tid=(?<id>\d+)$"); + public override string Name => "MyAnonamouse"; public override string[] IndexerUrls => new string[] { "https://www.myanonamouse.net/" }; @@ -44,6 +49,47 @@ namespace NzbDrone.Core.Indexers.Definitions return new MyAnonamouseParser(Settings, Capabilities.Categories); } + public override async Task<byte[]> Download(Uri link) + { + if (Settings.Freeleech) + { + _logger.Debug($"Attempting to use freeleech token for {link.AbsoluteUri}"); + + var idMatch = TorrentIdRegex.Match(link.AbsoluteUri); + if (idMatch.Success) + { + var id = int.Parse(idMatch.Groups["id"].Value); + var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds(); + var freeleechUrl = Settings.BaseUrl + $"json/bonusBuy.php/{timestamp}"; + + var freeleechRequest = new HttpRequestBuilder(freeleechUrl) + .AddQueryParam("spendtype", "personalFL") + .AddQueryParam("torrentid", id) + .AddQueryParam("timestamp", timestamp.ToString()) + .Build(); + + var indexerReq = new IndexerRequest(freeleechRequest); + var response = await FetchIndexerResponse(indexerReq).ConfigureAwait(false); + var resource = Json.Deserialize<MyAnonamouseFreeleechResponse>(response.Content); + + if (resource.Success) + { + _logger.Debug($"Successfully to used freeleech token for torrentid ${id}"); + } + else + { + _logger.Debug($"Failed to use freeleech token: ${resource.Error}"); + } + } + else + { + _logger.Debug($"Could not get torrent id from link ${link.AbsoluteUri}, skipping freeleech"); + } + } + + return await base.Download(link).ConfigureAwait(false); + } + protected override IDictionary<string, string> GetCookies() { return CookieUtil.CookieHeaderToDictionary("mam_id=" + Settings.MamId); @@ -400,7 +446,10 @@ namespace NzbDrone.Core.Indexers.Definitions [FieldDefinition(3, Type = FieldType.Checkbox, Label = "Exclude VIP", HelpText = "Exclude VIP Torrents from search results")] public bool ExcludeVip { get; set; } - [FieldDefinition(4)] + [FieldDefinition(4, Type = FieldType.Checkbox, Label = "Freeleech", HelpText = "Use freeleech token for download")] + public bool Freeleech { get; set; } + + [FieldDefinition(5)] public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); public NzbDroneValidationResult Validate() @@ -438,4 +487,10 @@ namespace NzbDrone.Core.Indexers.Definitions public string Error { get; set; } public List<MyAnonamouseTorrent> Data { get; set; } } + + public class MyAnonamouseFreeleechResponse + { + public bool Success { get; set; } + public string Error { get; set; } + } } From b4e0608b3bb81a78ec5ff57a30d9e84f8b58e82c Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Wed, 6 Apr 2022 20:09:12 +0100 Subject: [PATCH 0416/2320] Fix .editorconfig to disallow `this` [common] --- .editorconfig | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.editorconfig b/.editorconfig index e324f2b01..aa031494e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -19,10 +19,10 @@ indent_size = 4 dotnet_sort_system_directives_first = true # Avoid "this." and "Me." if not necessary -dotnet_style_qualification_for_field = false:refactoring -dotnet_style_qualification_for_property = false:refactoring -dotnet_style_qualification_for_method = false:refactoring -dotnet_style_qualification_for_event = false:refactoring +dotnet_style_qualification_for_field = false:warning +dotnet_style_qualification_for_property = false:warning +dotnet_style_qualification_for_method = false:warning +dotnet_style_qualification_for_event = false:warning # Indentation preferences csharp_indent_block_contents = true @@ -32,10 +32,6 @@ csharp_indent_case_contents_when_block = true csharp_indent_switch_labels = true csharp_indent_labels = flush_left -dotnet_style_qualification_for_field = false:suggestion -dotnet_style_qualification_for_property = false:suggestion -dotnet_style_qualification_for_method = false:suggestion -dotnet_style_qualification_for_event = false:suggestion dotnet_naming_style.instance_field_style.capitalization = camel_case dotnet_naming_style.instance_field_style.required_prefix = _ From fb8b65a91b734dc59a8cd17cd4117fdb12f161cc Mon Sep 17 00:00:00 2001 From: Vladimir Tasic <8029868+utajum@users.noreply.github.com> Date: Fri, 25 Mar 2022 15:31:20 +0100 Subject: [PATCH 0417/2320] #834 #256 fix for unable to load the Indexes page #834 #256 fix for unable to load the Indexes page --- frontend/src/Indexer/Index/Table/IndexerIndexRow.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Indexer/Index/Table/IndexerIndexRow.js b/frontend/src/Indexer/Index/Table/IndexerIndexRow.js index fda726182..a21f0f47c 100644 --- a/frontend/src/Indexer/Index/Table/IndexerIndexRow.js +++ b/frontend/src/Indexer/Index/Table/IndexerIndexRow.js @@ -190,7 +190,7 @@ class IndexerIndexRow extends Component { key={name} className={styles[column.name]} > - {appProfile.name} + {appProfile?.name || ''} </VirtualTableRowCell> ); } From ca0de18413b5f6243d76e361cea0b199443f1f38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 Apr 2022 03:30:49 +0000 Subject: [PATCH 0418/2320] Bump moment from 2.29.1 to 2.29.2 Bumps [moment](https://github.com/moment/moment) from 2.29.1 to 2.29.2. - [Release notes](https://github.com/moment/moment/releases) - [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md) - [Commits](https://github.com/moment/moment/compare/2.29.1...2.29.2) --- updated-dependencies: - dependency-name: moment dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ba04e56d3..99af4c1b3 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "jquery": "3.6.0", "lodash": "4.17.21", "mobile-detect": "1.4.5", - "moment": "2.29.1", + "moment": "2.29.2", "mousetrap": "1.6.5", "normalize.css": "8.0.1", "prop-types": "15.8.1", diff --git a/yarn.lock b/yarn.lock index 7f82d8e8b..a8670f28f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4648,10 +4648,10 @@ mobile-detect@1.4.5: resolved "https://registry.yarnpkg.com/mobile-detect/-/mobile-detect-1.4.5.tgz#da393c3c413ca1a9bcdd9ced653c38281c0fb6ad" integrity sha512-yc0LhH6tItlvfLBugVUEtgawwFU2sIe+cSdmRJJCTMZ5GEJyLxNyC/NIOAOGk67Fa8GNpOttO3Xz/1bHpXFD/g== -moment@2.29.1: - version "2.29.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" - integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== +moment@2.29.2: + version "2.29.2" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.2.tgz#00910c60b20843bcba52d37d58c628b47b1f20e4" + integrity sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg== mousetrap@1.6.5: version "1.6.5" From 3b7bafb78e169976fd3dff89fe96b42d098a0acc Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 10 Apr 2022 12:17:13 -0500 Subject: [PATCH 0419/2320] Bump version to 0.3.0 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index dc11bc975..224e38029 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,7 +7,7 @@ variables: outputFolder: './_output' artifactsFolder: './_artifacts' testsFolder: './_tests' - majorVersion: '0.2.0' + majorVersion: '0.3.0' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From e1b924ab08c772f22c5101fbd3d46937a76def78 Mon Sep 17 00:00:00 2001 From: 3744111 <37441111a@gmail.com> Date: Thu, 7 Apr 2022 21:59:53 -0400 Subject: [PATCH 0420/2320] Fixed: (Indexer) HDTorrents search imdbid + season/episode --- src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs index 3fdbc97cd..b17e0f518 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs @@ -151,9 +151,11 @@ namespace NzbDrone.Core.Indexers.Definitions { var searchUrl = Settings.BaseUrl + "torrents.php?" + string.Join(string.Empty, Capabilities.Categories.MapTorznabCapsToTrackers(categories).Select(cat => $"category[]={cat}&")); + var search = new[] { imdbId, term }; + var queryCollection = new NameValueCollection { - { "search", imdbId ?? term }, + { "search", string.Join(" ", search.Where(s => !string.IsNullOrEmpty(s))) }, { "active", "0" }, { "options", "0" } }; @@ -188,7 +190,7 @@ namespace NzbDrone.Core.Indexers.Definitions { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId)); + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId)); return pageableRequests; } From ce78f916574400d9dad0140b76a221d676d09d6c Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Thu, 7 Apr 2022 14:22:42 -0500 Subject: [PATCH 0421/2320] Fixed: (exoticaz) Category Parsing based on jackett fa2025cfd4b538d24a4a11bec6f5b13f8711fce0 --- .../Indexers/Definitions/ExoticaZ.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/ExoticaZ.cs b/src/NzbDrone.Core/Indexers/Definitions/ExoticaZ.cs index 61fc89751..524ef8361 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ExoticaZ.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ExoticaZ.cs @@ -40,14 +40,14 @@ namespace NzbDrone.Core.Indexers.Definitions } }; - caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.XXXx264); - caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.XXXPack); - caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.XXXPack); - caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.XXXPack); - caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.XXXDVD); - caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.XXXx264); - caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.XXXImageSet); - caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.XXXImageSet); + caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.XXXx264, "Video Clip"); + caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.XXXPack, "Video Pack"); + caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.XXXPack, "Siterip Pack"); + caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.XXXPack, "Pornstar Pack"); + caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.XXXDVD, "DVD"); + caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.XXXx264, "BluRay"); + caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.XXXImageSet, "Photo Pack"); + caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.XXXImageSet, "Books & Magazines"); return caps; } From 9f5d8517e5a2b2c476b576a72f5050abb974aa35 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Thu, 7 Apr 2022 14:10:56 -0500 Subject: [PATCH 0422/2320] Fixed: (CinemaZ and ExoticaZ) Better Log Cleansing --- src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index 60f266e66..565ed4385 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -51,7 +51,7 @@ namespace NzbDrone.Common.Instrumentation new Regex(@"(?<=\?|&)(X-Plex-Client-Identifier|X-Plex-Token)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), // Indexer Responses - new Regex(@"avistaz\.[a-z]{2,3}\\\/rss\\\/download\\\/(?<secret>[^&=]+?)\\\/(?<secret>[^&=]+?)\.torrent", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"(?:avistaz|exoticaz|cinemaz|privatehd)\.[a-z]{2,3}\\\/rss\\\/download\\\/(?<secret>[^&=]+?)\\\/(?<secret>[^&=]+?)\.torrent", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@",""info_hash"":""(?<secret>[^&=]+?)"",", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@",""pass[- _]?key"":""(?<secret>[^&=]+?)"",", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@",""rss[- _]?key"":""(?<secret>[^&=]+?)"",", RegexOptions.Compiled | RegexOptions.IgnoreCase), From b85cd92cca626b95fa07a7d63287e6bfcbe18388 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 2 Feb 2022 16:07:09 -0600 Subject: [PATCH 0423/2320] Fixed: (TorrentDay) TV Search returning Series not S/E Results Fixes #816 --- src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs index af9c444d0..778f12f23 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs @@ -153,16 +153,15 @@ namespace NzbDrone.Core.Indexers.Definitions var catStr = string.Join(";", cats); searchUrl = searchUrl + "?" + catStr; + searchUrl += ";q="; if (imdbId.IsNotNullOrWhiteSpace()) { - searchUrl += ";q=" + imdbId; - } - else - { - searchUrl += ";q=" + term.UrlEncode(Encoding.UTF8); + searchUrl += imdbId + " ".UrlEncode(Encoding.UTF8); } + searchUrl += term.UrlEncode(Encoding.UTF8); + var request = new IndexerRequest(searchUrl, HttpAccept.Rss); yield return request; From bb6c068d918859933fb711e46cccf0f639dc3f4e Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Thu, 14 Apr 2022 00:58:41 +0000 Subject: [PATCH 0424/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 89 ++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index 0995a4529..35a0c0207 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -4559,6 +4559,14 @@ ], "type": "string" }, + "BookSearchParam": { + "enum": [ + "q", + "title", + "author" + ], + "type": "string" + }, "CertificateValidationType": { "enum": [ "enabled", @@ -5259,6 +5267,44 @@ "$ref": "#/components/schemas/IndexerCategory" }, "nullable": true + }, + "supportsRawSearch": { + "type": "boolean" + }, + "searchParams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchParam" + }, + "nullable": true + }, + "tvSearchParams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TvSearchParam" + }, + "nullable": true + }, + "movieSearchParams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MovieSearchParam" + }, + "nullable": true + }, + "musicSearchParams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MusicSearchParam" + }, + "nullable": true + }, + "bookSearchParams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BookSearchParam" + }, + "nullable": true } }, "additionalProperties": false @@ -5748,6 +5794,29 @@ }, "additionalProperties": false }, + "MovieSearchParam": { + "enum": [ + "q", + "imdbId", + "tmdbId", + "imdbTitle", + "imdbYear", + "traktId", + "genre" + ], + "type": "string" + }, + "MusicSearchParam": { + "enum": [ + "q", + "album", + "artist", + "label", + "year", + "genre" + ], + "type": "string" + }, "NotificationResource": { "type": "object", "properties": { @@ -5992,6 +6061,12 @@ }, "additionalProperties": false }, + "SearchParam": { + "enum": [ + "q" + ], + "type": "string" + }, "SelectOption": { "type": "object", "properties": { @@ -6176,6 +6251,20 @@ }, "additionalProperties": false }, + "TvSearchParam": { + "enum": [ + "q", + "season", + "ep", + "imdbId", + "tvdbId", + "rId", + "tvMazeId", + "traktId", + "tmdbId" + ], + "type": "string" + }, "UiConfigResource": { "type": "object", "properties": { From 1b83459927d4174a7cddba7100a34d53ab5352b1 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 16 Apr 2022 12:33:34 -0500 Subject: [PATCH 0425/2320] Fixed: (BeyondHD) Use TryCoerceInt for tmdbId Fixes #960 --- src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs b/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs index f1d708b46..dd602d155 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs @@ -205,6 +205,10 @@ namespace NzbDrone.Core.Indexers.Definitions var details = row.InfoUrl; var link = row.DownloadLink; + // BHD can return crazy values for tmdb + var tmdbId = row.TmdbId.IsNullOrWhiteSpace() ? 0 : ParseUtil.TryCoerceInt(row.TmdbId.Split("/")[1], out var tmdbResult) ? tmdbResult : 0; + var imdbId = ParseUtil.GetImdbID(row.ImdbId).GetValueOrDefault(); + var release = new TorrentInfo { Title = row.Name, @@ -217,8 +221,8 @@ namespace NzbDrone.Core.Indexers.Definitions Size = row.Size, Grabs = row.Grabs, Seeders = row.Seeders, - ImdbId = ParseUtil.GetImdbID(row.ImdbId).GetValueOrDefault(), - TmdbId = row.TmdbId.IsNullOrWhiteSpace() ? 0 : (int)ParseUtil.CoerceLong(row.TmdbId.Split("/")[1]), + ImdbId = imdbId, + TmdbId = tmdbId, Peers = row.Leechers + row.Seeders, DownloadVolumeFactor = row.Freeleech || row.Limited ? 0 : row.Promo75 ? 0.25 : row.Promo50 ? 0.5 : row.Promo25 ? 0.75 : 1, UploadVolumeFactor = 1, From 18189d086babc6d3140d5097f3e4580d5e40d999 Mon Sep 17 00:00:00 2001 From: Zack Eckersley Pallett <40175773+ZackaryH8@users.noreply.github.com> Date: Mon, 21 Feb 2022 20:11:12 +0000 Subject: [PATCH 0426/2320] New: Add backup size information Closes #957 (cherry picked from commit 78aeda1a2cc217c367c5c3c6fd281c101b28413c) --- frontend/src/System/Backup/BackupRow.js | 7 +++++++ frontend/src/System/Backup/Backups.js | 7 +++++++ src/NzbDrone.Core/Backup/Backup.cs | 1 + src/NzbDrone.Core/Backup/BackupService.cs | 1 + src/Prowlarr.Api.V1/System/Backup/BackupController.cs | 1 + src/Prowlarr.Api.V1/System/Backup/BackupResource.cs | 1 + 6 files changed, 18 insertions(+) diff --git a/frontend/src/System/Backup/BackupRow.js b/frontend/src/System/Backup/BackupRow.js index 8bbfaf172..089f6bcb9 100644 --- a/frontend/src/System/Backup/BackupRow.js +++ b/frontend/src/System/Backup/BackupRow.js @@ -8,6 +8,7 @@ import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellCo import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableRow from 'Components/Table/TableRow'; import { icons, kinds } from 'Helpers/Props'; +import formatBytes from 'Utilities/Number/formatBytes'; import translate from 'Utilities/String/translate'; import RestoreBackupModalConnector from './RestoreBackupModalConnector'; import styles from './BackupRow.css'; @@ -65,6 +66,7 @@ class BackupRow extends Component { type, name, path, + size, time } = this.props; @@ -104,6 +106,10 @@ class BackupRow extends Component { </Link> </TableRowCell> + <TableRowCell> + {formatBytes(size)} + </TableRowCell> + <RelativeDateCellConnector date={time} /> @@ -147,6 +153,7 @@ BackupRow.propTypes = { type: PropTypes.string.isRequired, name: PropTypes.string.isRequired, path: PropTypes.string.isRequired, + size: PropTypes.number.isRequired, time: PropTypes.string.isRequired, onDeleteBackupPress: PropTypes.func.isRequired }; diff --git a/frontend/src/System/Backup/Backups.js b/frontend/src/System/Backup/Backups.js index 541c09253..3f1e2b4eb 100644 --- a/frontend/src/System/Backup/Backups.js +++ b/frontend/src/System/Backup/Backups.js @@ -23,6 +23,11 @@ const columns = [ label: translate('Name'), isVisible: true }, + { + name: 'size', + label: 'Size', + isVisible: true + }, { name: 'time', label: translate('Time'), @@ -127,6 +132,7 @@ class Backups extends Component { type, name, path, + size, time } = item; @@ -137,6 +143,7 @@ class Backups extends Component { type={type} name={name} path={path} + size={size} time={time} onDeleteBackupPress={onDeleteBackupPress} /> diff --git a/src/NzbDrone.Core/Backup/Backup.cs b/src/NzbDrone.Core/Backup/Backup.cs index 5d148648e..4c6200436 100644 --- a/src/NzbDrone.Core/Backup/Backup.cs +++ b/src/NzbDrone.Core/Backup/Backup.cs @@ -6,6 +6,7 @@ namespace NzbDrone.Core.Backup { public string Name { get; set; } public BackupType Type { get; set; } + public long Size { get; set; } public DateTime Time { get; set; } } } diff --git a/src/NzbDrone.Core/Backup/BackupService.cs b/src/NzbDrone.Core/Backup/BackupService.cs index e1b7fe008..80f779c6c 100644 --- a/src/NzbDrone.Core/Backup/BackupService.cs +++ b/src/NzbDrone.Core/Backup/BackupService.cs @@ -109,6 +109,7 @@ namespace NzbDrone.Core.Backup { Name = Path.GetFileName(b), Type = backupType, + Size = _diskProvider.GetFileSize(b), Time = _diskProvider.FileGetLastWrite(b) })); } diff --git a/src/Prowlarr.Api.V1/System/Backup/BackupController.cs b/src/Prowlarr.Api.V1/System/Backup/BackupController.cs index 88bc79a59..8c70239e5 100644 --- a/src/Prowlarr.Api.V1/System/Backup/BackupController.cs +++ b/src/Prowlarr.Api.V1/System/Backup/BackupController.cs @@ -42,6 +42,7 @@ namespace Prowlarr.Api.V1.System.Backup Name = b.Name, Path = $"/backup/{b.Type.ToString().ToLower()}/{b.Name}", Type = b.Type, + Size = b.Size, Time = b.Time }) .OrderByDescending(b => b.Time) diff --git a/src/Prowlarr.Api.V1/System/Backup/BackupResource.cs b/src/Prowlarr.Api.V1/System/Backup/BackupResource.cs index 2736b1689..a4e7c159a 100644 --- a/src/Prowlarr.Api.V1/System/Backup/BackupResource.cs +++ b/src/Prowlarr.Api.V1/System/Backup/BackupResource.cs @@ -9,6 +9,7 @@ namespace Prowlarr.Api.V1.System.Backup public string Name { get; set; } public string Path { get; set; } public BackupType Type { get; set; } + public long Size { get; set; } public DateTime Time { get; set; } } } From 1af5beff315eb374373b647d592c59051c7f54a0 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 14 Apr 2022 21:06:29 -0500 Subject: [PATCH 0427/2320] Remove old DotNetVersion method and dep --- .../EnvironmentInfo/PlatformInfo.cs | 109 +----------------- src/NzbDrone.Common/Prowlarr.Common.csproj | 1 - 2 files changed, 1 insertion(+), 109 deletions(-) diff --git a/src/NzbDrone.Common/EnvironmentInfo/PlatformInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/PlatformInfo.cs index 5c28231fe..0c39b4937 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/PlatformInfo.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/PlatformInfo.cs @@ -1,7 +1,4 @@ -using System; -using System.Reflection; -using System.Text.RegularExpressions; -using Microsoft.Win32; +using System; namespace NzbDrone.Common.EnvironmentInfo { @@ -19,8 +16,6 @@ namespace NzbDrone.Common.EnvironmentInfo public class PlatformInfo : IPlatformInfo { - private static readonly Regex MonoVersionRegex = new Regex(@"(?<=\W|^)(?<version>\d+\.\d+(\.\d+)?(\.\d+)?)(?=\W)", RegexOptions.Compiled | RegexOptions.IgnoreCase); - private static PlatformType _platform; private static Version _version; @@ -60,107 +55,5 @@ namespace NzbDrone.Common.EnvironmentInfo { return _version; } - - private static Version GetMonoVersion() - { - try - { - var type = Type.GetType("Mono.Runtime"); - - if (type != null) - { - var displayNameMethod = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static); - if (displayNameMethod != null) - { - var displayName = displayNameMethod.Invoke(null, null).ToString(); - var versionMatch = MonoVersionRegex.Match(displayName); - - if (versionMatch.Success) - { - return new Version(versionMatch.Groups["version"].Value); - } - } - } - } - catch (Exception ex) - { - Console.WriteLine("Couldnt get Mono version: " + ex.ToString()); - } - - return new Version(); - } - - private static Version GetDotNetVersion() - { - try - { - const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\"; - using (var ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey)) - { - if (ndpKey == null) - { - return new Version(4, 0); - } - - var releaseKey = (int)ndpKey.GetValue("Release"); - - if (releaseKey >= 528040) - { - return new Version(4, 8, 0); - } - - if (releaseKey >= 461808) - { - return new Version(4, 7, 2); - } - - if (releaseKey >= 461308) - { - return new Version(4, 7, 1); - } - - if (releaseKey >= 460798) - { - return new Version(4, 7); - } - - if (releaseKey >= 394802) - { - return new Version(4, 6, 2); - } - - if (releaseKey >= 394254) - { - return new Version(4, 6, 1); - } - - if (releaseKey >= 393295) - { - return new Version(4, 6); - } - - if (releaseKey >= 379893) - { - return new Version(4, 5, 2); - } - - if (releaseKey >= 378675) - { - return new Version(4, 5, 1); - } - - if (releaseKey >= 378389) - { - return new Version(4, 5); - } - } - } - catch (Exception ex) - { - Console.WriteLine("Couldnt get .NET framework version: " + ex.ToString()); - } - - return new Version(4, 0); - } } } diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index e54678861..0bd5a78ff 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -18,7 +18,6 @@ <PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" /> <PackageReference Include="System.Runtime.Loader" Version="4.3.0" /> <PackageReference Include="System.ServiceProcess.ServiceController" Version="6.0.0" /> - <PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" /> </ItemGroup> <ItemGroup> <Compile Update="EnsureThat\Resources\ExceptionMessages.Designer.cs"> From 35e561e2c01cec7f02b770e1a8323e2b3fc1019f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 11 Apr 2022 19:18:01 -0500 Subject: [PATCH 0428/2320] Bump Monotorrent to 2.0.5 --- src/NzbDrone.Core/Prowlarr.Core.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index ad20d2f50..17c69bd06 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -21,7 +21,7 @@ <PackageReference Include="Kveer.XmlRPC" Version="1.1.1" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> <PackageReference Include="System.Text.Json" Version="6.0.2" /> - <PackageReference Include="MonoTorrent" Version="1.0.29" /> + <PackageReference Include="MonoTorrent" Version="2.0.5" /> <PackageReference Include="YamlDotNet" Version="11.2.1" /> <PackageReference Include="AngleSharp" Version="0.16.1" /> </ItemGroup> From a6eb1bf546ec92eaf2a9345d5f957748edbbb618 Mon Sep 17 00:00:00 2001 From: Douglas R Andreani <andreani.dr@gmail.com> Date: Sun, 10 Apr 2022 01:15:02 -0300 Subject: [PATCH 0429/2320] New: Add date picker for custom filter dates (cherry picked from commit 5a08d5dc248bf1dbaa43264a2a470149cf716a3c) --- .../src/Components/Filter/Builder/DateFilterBuilderRowValue.js | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/Components/Filter/Builder/DateFilterBuilderRowValue.js b/frontend/src/Components/Filter/Builder/DateFilterBuilderRowValue.js index 6300dd917..0193cf44f 100644 --- a/frontend/src/Components/Filter/Builder/DateFilterBuilderRowValue.js +++ b/frontend/src/Components/Filter/Builder/DateFilterBuilderRowValue.js @@ -160,6 +160,7 @@ class DateFilterBuilderRowValue extends Component { <TextInput name={NAME} value={filterValue} + type="date" placeholder="yyyy-mm-dd" onChange={this.onValueChange} /> From 9a1bf54c143cb3d818ab67b1938d49571b870189 Mon Sep 17 00:00:00 2001 From: Mark McDowall <mark@mcdowall.ca> Date: Sun, 6 Mar 2022 21:26:13 -0800 Subject: [PATCH 0430/2320] Fixed: Delay health check notifications on startup (cherry picked from commit 07f0db477a91b39c1f4b884775c08a55ada487cf) --- .../HealthCheck/HealthCheckFailedEvent.cs | 4 ++- .../HealthCheck/HealthCheckService.cs | 33 ++++++++++++++++++- .../Notifications/NotificationService.cs | 7 ++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/HealthCheck/HealthCheckFailedEvent.cs b/src/NzbDrone.Core/HealthCheck/HealthCheckFailedEvent.cs index 1fc2af1a9..8abb156a5 100644 --- a/src/NzbDrone.Core/HealthCheck/HealthCheckFailedEvent.cs +++ b/src/NzbDrone.Core/HealthCheck/HealthCheckFailedEvent.cs @@ -5,10 +5,12 @@ namespace NzbDrone.Core.HealthCheck public class HealthCheckFailedEvent : IEvent { public HealthCheck HealthCheck { get; private set; } + public bool IsInStartupGraceperiod { get; private set; } - public HealthCheckFailedEvent(HealthCheck healthCheck) + public HealthCheckFailedEvent(HealthCheck healthCheck, bool isInStartupGraceperiod) { HealthCheck = healthCheck; + IsInStartupGraceperiod = isInStartupGraceperiod; } } } diff --git a/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs b/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs index 679044083..da1a5a678 100644 --- a/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs +++ b/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using NLog; using NzbDrone.Common.Cache; +using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Messaging; using NzbDrone.Common.Reflection; using NzbDrone.Core.Lifecycle; @@ -21,6 +22,7 @@ namespace NzbDrone.Core.HealthCheck IHandleAsync<ApplicationStartedEvent>, IHandleAsync<IEvent> { + private readonly DateTime _startupGracePeriodEndTime; private readonly IProvideHealthCheck[] _healthChecks; private readonly IProvideHealthCheck[] _startupHealthChecks; private readonly IProvideHealthCheck[] _scheduledHealthChecks; @@ -32,10 +34,14 @@ namespace NzbDrone.Core.HealthCheck private readonly ICached<HealthCheck> _healthCheckResults; + private bool _hasRunHealthChecksAfterGracePeriod = false; + private bool _isRunningHealthChecksAfterGracePeriod = false; + public HealthCheckService(IEnumerable<IProvideHealthCheck> healthChecks, IServerSideNotificationService serverSideNotificationService, IEventAggregator eventAggregator, ICacheManager cacheManager, + IRuntimeInfo runtimeInfo, Logger logger) { _healthChecks = healthChecks.ToArray(); @@ -49,6 +55,7 @@ namespace NzbDrone.Core.HealthCheck _startupHealthChecks = _healthChecks.Where(v => v.CheckOnStartup).ToArray(); _scheduledHealthChecks = _healthChecks.Where(v => v.CheckOnSchedule).ToArray(); _eventDrivenHealthChecks = GetEventDrivenHealthChecks(); + _startupGracePeriodEndTime = runtimeInfo.StartTime + TimeSpan.FromMinutes(15); } public List<HealthCheck> Results() @@ -87,7 +94,7 @@ namespace NzbDrone.Core.HealthCheck { if (_healthCheckResults.Find(result.Source.Name) == null) { - _eventAggregator.PublishEvent(new HealthCheckFailedEvent(result)); + _eventAggregator.PublishEvent(new HealthCheckFailedEvent(result, !_hasRunHealthChecksAfterGracePeriod)); } _healthCheckResults.Set(result.Source.Name, result); @@ -121,6 +128,30 @@ namespace NzbDrone.Core.HealthCheck return; } + // If we haven't previously re-run health checks after startup grace period run startup checks again and track so they aren't run again. + // Return early after re-running checks to avoid triggering checks multiple times. + if (!_hasRunHealthChecksAfterGracePeriod && !_isRunningHealthChecksAfterGracePeriod && DateTime.UtcNow > _startupGracePeriodEndTime) + { + _isRunningHealthChecksAfterGracePeriod = true; + + PerformHealthCheck(_startupHealthChecks); + + // Update after running health checks so new failure notifications aren't sent 2x. + _hasRunHealthChecksAfterGracePeriod = true; + + // Explicitly notify for any failed checks since existing failed results would not have sent events. + var results = _healthCheckResults.Values.ToList(); + + foreach (var result in results) + { + _eventAggregator.PublishEvent(new HealthCheckFailedEvent(result, false)); + } + + _isRunningHealthChecksAfterGracePeriod = false; + + return; + } + IEventDrivenHealthCheck[] checks; if (!_eventDrivenHealthChecks.TryGetValue(message.GetType(), out checks)) { diff --git a/src/NzbDrone.Core/Notifications/NotificationService.cs b/src/NzbDrone.Core/Notifications/NotificationService.cs index aa17b2a28..a8ca54af5 100644 --- a/src/NzbDrone.Core/Notifications/NotificationService.cs +++ b/src/NzbDrone.Core/Notifications/NotificationService.cs @@ -37,6 +37,13 @@ namespace NzbDrone.Core.Notifications public void Handle(HealthCheckFailedEvent message) { + // Don't send health check notifications during the start up grace period, + // once that duration expires they they'll be retested and fired off if necessary. + if (message.IsInStartupGraceperiod) + { + return; + } + foreach (var notification in _notificationFactory.OnHealthIssueEnabled()) { try From 0f3559e55637b884286cea07c94951ef849519ca Mon Sep 17 00:00:00 2001 From: Mark McDowall <mark@mcdowall.ca> Date: Sun, 20 Mar 2022 00:21:07 -0700 Subject: [PATCH 0431/2320] Don't return early after re-running checks after startup grace period Fixes #7147 (cherry picked from commit 06464d720c0d31c22865629062d6da0911d2a01f) --- src/NzbDrone.Core/HealthCheck/HealthCheckService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs b/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs index da1a5a678..26442f9e7 100644 --- a/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs +++ b/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs @@ -148,8 +148,6 @@ namespace NzbDrone.Core.HealthCheck } _isRunningHealthChecksAfterGracePeriod = false; - - return; } IEventDrivenHealthCheck[] checks; From b31e27a7aea70de2615ddd67c107f3bf75f7c572 Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Thu, 20 Jan 2022 21:40:40 +0000 Subject: [PATCH 0432/2320] Centralise image choice, update to latest images (cherry picked from commit fa1985509d77dedd108286a159749fd5cf9d8599) --- azure-pipelines.yml | 62 ++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 224e38029..3b9866693 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,6 +7,8 @@ variables: outputFolder: './_output' artifactsFolder: './_artifacts' testsFolder: './_tests' + yarnCacheFolder: $(Pipeline.Workspace)/.yarn + nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages majorVersion: '0.3.0' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' @@ -16,7 +18,9 @@ variables: dotnetVersion: '6.0.201' innoVersion: '6.2.0' nodeVersion: '16.x' - yarnCacheFolder: $(Pipeline.Workspace)/.yarn + windowsImage: 'windows-2022' + linuxImage: 'ubuntu-20.04' + macImage: 'macOS-11' trigger: branches: @@ -40,7 +44,7 @@ stages: - job: displayName: Build Variables pool: - vmImage: 'ubuntu-18.04' + vmImage: ${{ variables.linuxImage }} steps: # Set the build name properly. The 'name' property won't recursively expand so hack here: - bash: echo "##vso[build.updatebuildnumber]$PROWLARRVERSION" @@ -66,15 +70,15 @@ stages: matrix: Linux: osName: 'Linux' - imageName: 'ubuntu-18.04' + imageName: ${{ variables.linuxImage }} enableAnalysis: 'true' Mac: osName: 'Mac' - imageName: 'macos-10.15' + imageName: ${{ variables.macImage }} enableAnalysis: 'false' Windows: osName: 'Windows' - imageName: 'windows-2019' + imageName: ${{ variables.windowsImage }} enableAnalysis: 'false' pool: @@ -144,13 +148,13 @@ stages: matrix: Linux: osName: 'Linux' - imageName: 'ubuntu-18.04' + imageName: ${{ variables.linuxImage }} Mac: osName: 'Mac' - imageName: 'macos-10.15' + imageName: ${{ variables.macImage }} Windows: osName: 'Windows' - imageName: 'windows-2019' + imageName: ${{ variables.windowsImage }} pool: vmImage: $(imageName) steps: @@ -186,7 +190,7 @@ stages: - job: Windows_Installer displayName: Create Installer pool: - vmImage: 'windows-2019' + vmImage: ${{ variables.windowsImage }} steps: - checkout: self fetchDepth: 1 @@ -219,7 +223,7 @@ stages: - job: Other_Packages displayName: Create Standard Packages pool: - vmImage: 'ubuntu-18.04' + vmImage: ${{ variables.linuxImage }} steps: - checkout: self fetchDepth: 1 @@ -379,7 +383,7 @@ stages: jobs: - job: Prepare pool: - vmImage: 'ubuntu-18.04' + vmImage: ${{ variables.linuxImage }} steps: - checkout: none - task: DownloadPipelineArtifact@2 @@ -403,17 +407,17 @@ stages: osName: 'Mac' testName: 'MacCore' poolName: 'Azure Pipelines' - imageName: 'macos-10.15' + imageName: ${{ variables.macImage }} WindowsCore: osName: 'Windows' testName: 'WindowsCore' poolName: 'Azure Pipelines' - imageName: 'windows-2019' + imageName: ${{ variables.windowsImage }} LinuxCore: osName: 'Linux' testName: 'LinuxCore' poolName: 'Azure Pipelines' - imageName: 'ubuntu-18.04' + imageName: ${{ variables.linuxImage }} FreebsdCore: osName: 'Linux' testName: 'FreebsdCore' @@ -469,7 +473,7 @@ stages: containerImage: ghcr.io/servarr/testimages:alpine pool: - vmImage: 'ubuntu-18.04' + vmImage: ${{ variables.linuxImage }} container: $[ variables['containerImage'] ] @@ -510,7 +514,7 @@ stages: jobs: - job: Prepare pool: - vmImage: 'ubuntu-18.04' + vmImage: ${{ variables.linuxImage }} steps: - checkout: none - task: DownloadPipelineArtifact@2 @@ -530,17 +534,17 @@ stages: MacCore: osName: 'Mac' testName: 'MacCore' - imageName: 'macos-10.15' + imageName: ${{ variables.macImage }} pattern: 'Prowlarr.*.osx-core-x64.tar.gz' WindowsCore: osName: 'Windows' testName: 'WindowsCore' - imageName: 'windows-2019' + imageName: ${{ variables.windowsImage }} pattern: 'Prowlarr.*.windows-core-x64.zip' LinuxCore: osName: 'Linux' testName: 'LinuxCore' - imageName: 'ubuntu-18.04' + imageName: ${{ variables.linuxImage }} pattern: 'Prowlarr.*.linux-core-x64.tar.gz' pool: @@ -645,7 +649,7 @@ stages: pattern: 'Prowlarr.*.linux-musl-core-x64.tar.gz' pool: - vmImage: 'ubuntu-18.04' + vmImage: ${{ variables.linuxImage }} container: $[ variables['containerImage'] ] @@ -701,17 +705,17 @@ stages: matrix: Linux: osName: 'Linux' - imageName: 'ubuntu-18.04' + imageName: ${{ variables.linuxImage }} pattern: 'Prowlarr.*.linux-core-x64.tar.gz' failBuild: true Mac: osName: 'Mac' - imageName: 'macos-10.15' + imageName: ${{ variables.macImage }} pattern: 'Prowlarr.*.osx-core-x64.tar.gz' failBuild: true Windows: osName: 'Windows' - imageName: 'windows-2019' + imageName: ${{ variables.windowsImage }} pattern: 'Prowlarr.*.windows-core-x64.zip' failBuild: true @@ -777,7 +781,7 @@ stages: jobs: - job: Prepare pool: - vmImage: 'ubuntu-18.04' + vmImage: ${{ variables.linuxImage }} steps: - checkout: none - task: DownloadPipelineArtifact@2 @@ -794,10 +798,10 @@ stages: matrix: Linux: osName: 'Linux' - imageName: 'ubuntu-18.04' + imageName: ${{ variables.linuxImage }} Windows: osName: 'Windows' - imageName: 'windows-2019' + imageName: ${{ variables.windowsImage }} pool: vmImage: $(imageName) steps: @@ -832,7 +836,7 @@ stages: ) pool: - vmImage: windows-2019 + vmImage: ${{ variables.windowsImage }} steps: - task: UseDotNet@2 @@ -884,7 +888,7 @@ stages: EnableAnalyzers: 'false' pool: - vmImage: windows-2019 + vmImage: ${{ variables.windowsImage }} steps: - task: UseDotNet@2 @@ -941,7 +945,7 @@ stages: - job: displayName: Discord Notification pool: - vmImage: 'ubuntu-18.04' + vmImage: ${{ variables.linuxImage }} steps: - task: DownloadPipelineArtifact@2 continueOnError: true From 828aea14a9405c962200d07583fdec6111982345 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 31 Mar 2022 21:21:02 -0500 Subject: [PATCH 0433/2320] New: Schedule refresh and process monitored download tasks at high priority Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com> --- src/NzbDrone.Core/Datastore/TableMapping.cs | 3 +- src/NzbDrone.Core/Jobs/ScheduledTask.cs | 7 ++++ src/NzbDrone.Core/Jobs/Scheduler.cs | 4 +- src/NzbDrone.Core/Jobs/TaskManager.cs | 41 +++++++++++++++---- .../Commands/CommandPriorityComparer.cs | 32 +++++++++++++++ .../Commands/CommandController.cs | 7 +++- 6 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 src/NzbDrone.Core/Messaging/Commands/CommandPriorityComparer.cs diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index 27c70fb9e..85ab151de 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -41,7 +41,8 @@ namespace NzbDrone.Core.Datastore Mapper.Entity<Config>("Config").RegisterModel(); - Mapper.Entity<ScheduledTask>("ScheduledTasks").RegisterModel(); + Mapper.Entity<ScheduledTask>("ScheduledTasks").RegisterModel() + .Ignore(i => i.Priority); Mapper.Entity<IndexerDefinition>("Indexers").RegisterModel() .Ignore(x => x.ImplementationName) diff --git a/src/NzbDrone.Core/Jobs/ScheduledTask.cs b/src/NzbDrone.Core/Jobs/ScheduledTask.cs index 3cdfa3132..82c948b2f 100644 --- a/src/NzbDrone.Core/Jobs/ScheduledTask.cs +++ b/src/NzbDrone.Core/Jobs/ScheduledTask.cs @@ -1,5 +1,6 @@ using System; using NzbDrone.Core.Datastore; +using NzbDrone.Core.Messaging.Commands; namespace NzbDrone.Core.Jobs { @@ -9,5 +10,11 @@ namespace NzbDrone.Core.Jobs public int Interval { get; set; } public DateTime LastExecution { get; set; } public DateTime LastStartTime { get; set; } + public CommandPriority Priority { get; set; } + + public ScheduledTask() + { + Priority = CommandPriority.Low; + } } } diff --git a/src/NzbDrone.Core/Jobs/Scheduler.cs b/src/NzbDrone.Core/Jobs/Scheduler.cs index dffe4dba7..54e243467 100644 --- a/src/NzbDrone.Core/Jobs/Scheduler.cs +++ b/src/NzbDrone.Core/Jobs/Scheduler.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using System.Threading; using System.Threading.Tasks; using NLog; @@ -39,7 +39,7 @@ namespace NzbDrone.Core.Jobs foreach (var task in tasks) { - _commandQueueManager.Push(task.TypeName, task.LastExecution, task.LastStartTime, CommandPriority.Low, CommandTrigger.Scheduled); + _commandQueueManager.Push(task.TypeName, task.LastExecution, task.LastStartTime, task.Priority, CommandTrigger.Scheduled); } } finally diff --git a/src/NzbDrone.Core/Jobs/TaskManager.cs b/src/NzbDrone.Core/Jobs/TaskManager.cs index 7882d7fd4..9fc059696 100644 --- a/src/NzbDrone.Core/Jobs/TaskManager.cs +++ b/src/NzbDrone.Core/Jobs/TaskManager.cs @@ -2,9 +2,11 @@ using System; using System.Collections.Generic; using System.Linq; using NLog; +using NzbDrone.Common.Cache; using NzbDrone.Core.Applications; using NzbDrone.Core.Backup; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Configuration.Events; using NzbDrone.Core.HealthCheck; using NzbDrone.Core.History; using NzbDrone.Core.Housekeeping; @@ -28,35 +30,38 @@ namespace NzbDrone.Core.Jobs private readonly IScheduledTaskRepository _scheduledTaskRepository; private readonly IConfigService _configService; private readonly Logger _logger; + private readonly ICached<ScheduledTask> _cache; - public TaskManager(IScheduledTaskRepository scheduledTaskRepository, IConfigService configService, Logger logger) + public TaskManager(IScheduledTaskRepository scheduledTaskRepository, IConfigService configService, ICacheManager cacheManager, Logger logger) { _scheduledTaskRepository = scheduledTaskRepository; _configService = configService; + _cache = cacheManager.GetCache<ScheduledTask>(GetType()); _logger = logger; } public IList<ScheduledTask> GetPending() { - return _scheduledTaskRepository.All() - .Where(c => c.Interval > 0 && c.LastExecution.AddMinutes(c.Interval) < DateTime.UtcNow) - .ToList(); + return _cache.Values + .Where(c => c.Interval > 0 && c.LastExecution.AddMinutes(c.Interval) < DateTime.UtcNow) + .ToList(); } public List<ScheduledTask> GetAll() { - return _scheduledTaskRepository.All().ToList(); + return _cache.Values.ToList(); } public DateTime GetNextExecution(Type type) { - var scheduledTask = _scheduledTaskRepository.All().Single(v => v.TypeName == type.FullName); + var scheduledTask = _cache.Find(type.FullName); + return scheduledTask.LastExecution.AddMinutes(scheduledTask.Interval); } public void Handle(ApplicationStartedEvent message) { - var defaultTasks = new[] + var defaultTasks = new List<ScheduledTask> { new ScheduledTask { Interval = 5, TypeName = typeof(MessagingCleanupCommand).FullName }, new ScheduledTask { Interval = 6 * 60, TypeName = typeof(ApplicationCheckUpdateCommand).FullName }, @@ -75,7 +80,7 @@ namespace NzbDrone.Core.Jobs var currentTasks = _scheduledTaskRepository.All().ToList(); - _logger.Trace("Initializing jobs. Available: {0} Existing: {1}", defaultTasks.Length, currentTasks.Count); + _logger.Trace("Initializing jobs. Available: {0} Existing: {1}", defaultTasks.Count, currentTasks.Count); foreach (var job in currentTasks) { @@ -97,6 +102,9 @@ namespace NzbDrone.Core.Jobs currentDefinition.LastExecution = DateTime.UtcNow; } + currentDefinition.Priority = defaultTask.Priority; + + _cache.Set(currentDefinition.TypeName, currentDefinition); _scheduledTaskRepository.Upsert(currentDefinition); } } @@ -115,8 +123,23 @@ namespace NzbDrone.Core.Jobs if (scheduledTask != null && message.Command.Body.UpdateScheduledTask) { _logger.Trace("Updating last run time for: {0}", scheduledTask.TypeName); - _scheduledTaskRepository.SetLastExecutionTime(scheduledTask.Id, DateTime.UtcNow, message.Command.StartedAt.Value); + + var lastExecution = DateTime.UtcNow; + + _scheduledTaskRepository.SetLastExecutionTime(scheduledTask.Id, lastExecution, message.Command.StartedAt.Value); + _cache.Find(scheduledTask.TypeName).LastExecution = lastExecution; + _cache.Find(scheduledTask.TypeName).LastStartTime = message.Command.StartedAt.Value; } } + + public void HandleAsync(ConfigSavedEvent message) + { + var backup = _scheduledTaskRepository.GetDefinition(typeof(BackupCommand)); + backup.Interval = GetBackupInterval(); + + _scheduledTaskRepository.UpdateMany(new List<ScheduledTask> { backup }); + + _cache.Find(backup.TypeName).Interval = backup.Interval; + } } } diff --git a/src/NzbDrone.Core/Messaging/Commands/CommandPriorityComparer.cs b/src/NzbDrone.Core/Messaging/Commands/CommandPriorityComparer.cs new file mode 100644 index 000000000..5d8d5f13e --- /dev/null +++ b/src/NzbDrone.Core/Messaging/Commands/CommandPriorityComparer.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; + +namespace NzbDrone.Core.Messaging.Commands +{ + public class CommandPriorityComparer : IComparer<CommandStatus> + { + public int Compare(CommandStatus x, CommandStatus y) + { + if (x == CommandStatus.Started && y != CommandStatus.Started) + { + return -1; + } + + if (x != CommandStatus.Started && y == CommandStatus.Started) + { + return 1; + } + + if (x < y) + { + return -1; + } + + if (x > y) + { + return 1; + } + + return 0; + } + } +} diff --git a/src/Prowlarr.Api.V1/Commands/CommandController.cs b/src/Prowlarr.Api.V1/Commands/CommandController.cs index eb9ee70cf..6859c94cc 100644 --- a/src/Prowlarr.Api.V1/Commands/CommandController.cs +++ b/src/Prowlarr.Api.V1/Commands/CommandController.cs @@ -26,6 +26,8 @@ namespace Prowlarr.Api.V1.Commands private readonly Debouncer _debouncer; private readonly Dictionary<int, CommandResource> _pendingUpdates; + private readonly CommandPriorityComparer _commandPriorityComparer = new CommandPriorityComparer(); + public CommandController(IManageCommandQueue commandQueueManager, IBroadcastSignalRMessage signalRBroadcaster, KnownTypes knownTypes) @@ -73,7 +75,10 @@ namespace Prowlarr.Api.V1.Commands [Produces("application/json")] public List<CommandResource> GetStartedCommands() { - return _commandQueueManager.All().ToResource(); + return _commandQueueManager.All() + .OrderBy(c => c.Status, _commandPriorityComparer) + .ThenByDescending(c => c.Priority) + .ToResource(); } [RestDeleteById] From 7e3dcb338c1f598bfa78b594f50c349bd3faa779 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 16 Apr 2022 13:09:21 -0500 Subject: [PATCH 0434/2320] Fixed: (Cardigann) Handle json field selector that returns arrays Closes #950 --- .../Indexers/Definitions/Cardigann/CardigannBase.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index 3dc12d51a..8c1a63019 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -256,7 +256,16 @@ namespace NzbDrone.Core.Indexers.Cardigann return null; } - value = selection.Value<string>(); + if (selection.Type is JTokenType.Array) + { + // turn this json array into a comma delimited string + var valueArray = selection.Value<JArray>(); + value = string.Join(",", valueArray); + } + else + { + value = selection.Value<string>(); + } } if (selector.Case != null) From 16f0486da2d84f52453d0f4dd9b0b16df9d909be Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 16 Apr 2022 13:34:16 -0500 Subject: [PATCH 0435/2320] Cleanup Config Values Closes #894 --- src/NzbDrone.Core/Configuration/ConfigService.cs | 13 ------------- src/NzbDrone.Core/Configuration/IConfigService.cs | 4 ---- .../Datastore/Migration/016_cleanup_config.cs | 15 +++++++++++++++ .../Config/DownloadClientConfigResource.cs | 2 -- src/Prowlarr.Api.V1/Config/UiConfigResource.cs | 2 -- 5 files changed, 15 insertions(+), 21 deletions(-) create mode 100644 src/NzbDrone.Core/Datastore/Migration/016_cleanup_config.cs diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index 9541c3d6a..1d83118a2 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -90,12 +90,6 @@ namespace NzbDrone.Core.Configuration set { SetValue("LogIndexerResponse", value); } } - public string DownloadClientWorkingFolders - { - get { return GetValue("DownloadClientWorkingFolders", "_UNPACK_|_FAILED_"); } - set { SetValue("DownloadClientWorkingFolders", value); } - } - public int FirstDayOfWeek { get { return GetValueInt("FirstDayOfWeek", (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek); } @@ -145,13 +139,6 @@ namespace NzbDrone.Core.Configuration set { SetValue("EnableColorImpairedMode", value); } } - public int MovieInfoLanguage - { - get { return GetValueInt("MovieInfoLanguage", (int)Language.English); } - - set { SetValue("MovieInfoLanguage", value); } - } - public int UILanguage { get { return GetValueInt("UILanguage", (int)Language.English); } diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index d2556901d..fb330e41e 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -10,9 +10,6 @@ namespace NzbDrone.Core.Configuration bool IsDefined(string key); - //Download Client - string DownloadClientWorkingFolders { get; set; } - //History int HistoryCleanupDays { get; set; } @@ -25,7 +22,6 @@ namespace NzbDrone.Core.Configuration string TimeFormat { get; set; } bool ShowRelativeDates { get; set; } bool EnableColorImpairedMode { get; set; } - int MovieInfoLanguage { get; set; } int UILanguage { get; set; } //Internal diff --git a/src/NzbDrone.Core/Datastore/Migration/016_cleanup_config.cs b/src/NzbDrone.Core/Datastore/Migration/016_cleanup_config.cs new file mode 100644 index 000000000..f8d91788d --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/016_cleanup_config.cs @@ -0,0 +1,15 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(016)] + public class cleanup_config : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Delete.FromTable("Config").Row(new { Key = "movieinfolanguage" }); + Delete.FromTable("Config").Row(new { Key = "downloadclientworkingfolders" }); + } + } +} diff --git a/src/Prowlarr.Api.V1/Config/DownloadClientConfigResource.cs b/src/Prowlarr.Api.V1/Config/DownloadClientConfigResource.cs index b779340a1..d958d7057 100644 --- a/src/Prowlarr.Api.V1/Config/DownloadClientConfigResource.cs +++ b/src/Prowlarr.Api.V1/Config/DownloadClientConfigResource.cs @@ -5,7 +5,6 @@ namespace Prowlarr.Api.V1.Config { public class DownloadClientConfigResource : RestResource { - public string DownloadClientWorkingFolders { get; set; } } public static class DownloadClientConfigResourceMapper @@ -14,7 +13,6 @@ namespace Prowlarr.Api.V1.Config { return new DownloadClientConfigResource { - DownloadClientWorkingFolders = model.DownloadClientWorkingFolders }; } } diff --git a/src/Prowlarr.Api.V1/Config/UiConfigResource.cs b/src/Prowlarr.Api.V1/Config/UiConfigResource.cs index b1ea90f03..d2e9e786b 100644 --- a/src/Prowlarr.Api.V1/Config/UiConfigResource.cs +++ b/src/Prowlarr.Api.V1/Config/UiConfigResource.cs @@ -16,7 +16,6 @@ namespace Prowlarr.Api.V1.Config public bool ShowRelativeDates { get; set; } public bool EnableColorImpairedMode { get; set; } - public int MovieInfoLanguage { get; set; } public int UILanguage { get; set; } } @@ -35,7 +34,6 @@ namespace Prowlarr.Api.V1.Config ShowRelativeDates = model.ShowRelativeDates, EnableColorImpairedMode = model.EnableColorImpairedMode, - MovieInfoLanguage = model.MovieInfoLanguage, UILanguage = model.UILanguage }; } From cf01c52c3491529d735156f70c435911a076fbea Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 16 Apr 2022 15:23:23 -0500 Subject: [PATCH 0436/2320] Fixed: Sync Indexers on App Edit --- .../Applications/ApplicationService.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/NzbDrone.Core/Applications/ApplicationService.cs b/src/NzbDrone.Core/Applications/ApplicationService.cs index 80b7c840d..f3a80161c 100644 --- a/src/NzbDrone.Core/Applications/ApplicationService.cs +++ b/src/NzbDrone.Core/Applications/ApplicationService.cs @@ -17,6 +17,7 @@ namespace NzbDrone.Core.Applications IHandleAsync<ProviderDeletedEvent<IIndexer>>, IHandleAsync<ProviderAddedEvent<IApplication>>, IHandleAsync<ProviderUpdatedEvent<IIndexer>>, + IHandleAsync<ProviderUpdatedEvent<IApplication>>, IHandleAsync<ProviderBulkUpdatedEvent<IIndexer>>, IHandleAsync<ApiKeyChangedEvent>, IExecute<ApplicationIndexerSyncCommand> @@ -49,6 +50,19 @@ namespace NzbDrone.Core.Applications } } + public void HandleAsync(ProviderUpdatedEvent<IApplication> message) + { + var appDefinition = (ApplicationDefinition)message.Definition; + + if (appDefinition.Enable) + { + var app = _applicationsFactory.GetInstance(appDefinition); + var indexers = _indexerFactory.Enabled().Select(i => (IndexerDefinition)i.Definition).ToList(); + + SyncIndexers(new List<IApplication> { app }, indexers); + } + } + public void HandleAsync(ProviderAddedEvent<IIndexer> message) { var enabledApps = _applicationsFactory.SyncEnabled(); From 302ed91d05d9296fde0e3963d059be4881fa21ef Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 16 Apr 2022 15:32:37 -0500 Subject: [PATCH 0437/2320] Fixed: Remove Indexer if categories were changed to not include in sync Applies to Full Sync Update Fixes #912 --- .../IndexerCapabilitiesCategoriesFixture.cs | 87 +++++++++++++++++++ .../Applications/Lidarr/Lidarr.cs | 12 ++- .../Applications/Radarr/Radarr.cs | 12 ++- .../Applications/Readarr/Readarr.cs | 12 ++- .../Applications/Sonarr/Sonarr.cs | 12 ++- .../Applications/Whisparr/Whisparr.cs | 20 +++-- 6 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 src/NzbDrone.Core.Test/IndexerTests/IndexerCapabilitiesCategoriesFixture.cs diff --git a/src/NzbDrone.Core.Test/IndexerTests/IndexerCapabilitiesCategoriesFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/IndexerCapabilitiesCategoriesFixture.cs new file mode 100644 index 000000000..a571e0477 --- /dev/null +++ b/src/NzbDrone.Core.Test/IndexerTests/IndexerCapabilitiesCategoriesFixture.cs @@ -0,0 +1,87 @@ +using System.Linq; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.IndexerTests +{ + [TestFixture] + public class IndexerCapabilitiesCategoriesFixture : CoreTest<IndexerCapabilitiesCategories> + { + [Test] + public void should_support_parent_if_child_mapping() + { + Subject.AddCategoryMapping(1, NewznabStandardCategory.MoviesSD, "Filme SD"); + + var categories = new int[] { 2000 }; + + var supported = Subject.SupportedCategories(categories); + + supported.Should().HaveCount(1); + } + + [Test] + public void should_support_category_if_mapped() + { + Subject.AddCategoryMapping(1, NewznabStandardCategory.MoviesSD, "Filme SD"); + + var categories = new int[] { 2030 }; + + var supported = Subject.SupportedCategories(categories); + + supported.Should().HaveCount(1); + } + + [Test] + public void should_not_support_category_if_not_mapped() + { + Subject.AddCategoryMapping(1, NewznabStandardCategory.MoviesSD, "Filme SD"); + + var categories = new int[] { 2040 }; + + var supported = Subject.SupportedCategories(categories); + + supported.Should().HaveCount(0); + } + + [Test] + public void should_get_tracker_category_list() + { + Subject.AddCategoryMapping(1, NewznabStandardCategory.MoviesSD, "Filme SD"); + Subject.AddCategoryMapping(2, NewznabStandardCategory.MoviesHD, "Filme HD"); + + var supported = Subject.GetTrackerCategories(); + + supported.Should().HaveCount(2); + supported.First().Should().NotBeNull(); + supported.First().Should().Be("1"); + } + + [Test] + public void should_get_category_by_tracker_id() + { + Subject.AddCategoryMapping(1, NewznabStandardCategory.MoviesSD, "Filme SD"); + Subject.AddCategoryMapping(2, NewznabStandardCategory.MoviesHD, "Filme HD"); + + var supported = Subject.MapTrackerCatToNewznab(2.ToString()); + + supported.Should().HaveCount(2); + supported.First().Should().NotBeNull(); + supported.First().Id.Should().Be(NewznabStandardCategory.MoviesHD.Id); + } + + [Test] + public void should_get_category_by_tracker_desc() + { + Subject.AddCategoryMapping(1, NewznabStandardCategory.MoviesSD, "Filme SD"); + Subject.AddCategoryMapping(2, NewznabStandardCategory.MoviesHD, "Filme HD"); + + var supported = Subject.MapTrackerCatDescToNewznab("Filme HD"); + + supported.Should().HaveCount(2); + supported.First().Should().NotBeNull(); + supported.First().Id.Should().Be(NewznabStandardCategory.MoviesHD.Id); + } + } +} diff --git a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs index 1af2b7901..e275f8d09 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs @@ -124,7 +124,17 @@ namespace NzbDrone.Core.Applications.Lidarr if (!lidarrIndexer.Equals(remoteIndexer)) { - _lidarrV1Proxy.UpdateIndexer(lidarrIndexer, Settings); + if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) + { + // Update the indexer if it still has categories that match + _lidarrV1Proxy.UpdateIndexer(lidarrIndexer, Settings); + } + else + { + // Else remove it, it no longer should be used + _lidarrV1Proxy.RemoveIndexer(remoteIndexer.Id, Settings); + _appIndexerMapService.Delete(indexerMapping.Id); + } } } else diff --git a/src/NzbDrone.Core/Applications/Radarr/Radarr.cs b/src/NzbDrone.Core/Applications/Radarr/Radarr.cs index e5c8c25ab..e5719736e 100644 --- a/src/NzbDrone.Core/Applications/Radarr/Radarr.cs +++ b/src/NzbDrone.Core/Applications/Radarr/Radarr.cs @@ -124,7 +124,17 @@ namespace NzbDrone.Core.Applications.Radarr if (!radarrIndexer.Equals(remoteIndexer)) { - _radarrV3Proxy.UpdateIndexer(radarrIndexer, Settings); + if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) + { + // Update the indexer if it still has categories that match + _radarrV3Proxy.UpdateIndexer(radarrIndexer, Settings); + } + else + { + // Else remove it, it no longer should be used + _radarrV3Proxy.RemoveIndexer(remoteIndexer.Id, Settings); + _appIndexerMapService.Delete(indexerMapping.Id); + } } } else diff --git a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs index f3603886d..606304a11 100644 --- a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs +++ b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs @@ -124,7 +124,17 @@ namespace NzbDrone.Core.Applications.Readarr if (!readarrIndexer.Equals(remoteIndexer)) { - _readarrV1Proxy.UpdateIndexer(readarrIndexer, Settings); + if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) + { + // Update the indexer if it still has categories that match + _readarrV1Proxy.UpdateIndexer(readarrIndexer, Settings); + } + else + { + // Else remove it, it no longer should be used + _readarrV1Proxy.RemoveIndexer(remoteIndexer.Id, Settings); + _appIndexerMapService.Delete(indexerMapping.Id); + } } } else diff --git a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs index 196b6f14a..9538cee90 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs @@ -124,7 +124,17 @@ namespace NzbDrone.Core.Applications.Sonarr if (!sonarrIndexer.Equals(remoteIndexer)) { - _sonarrV3Proxy.UpdateIndexer(sonarrIndexer, Settings); + if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexer.Capabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any()) + { + // Update the indexer if it still has categories that match + _sonarrV3Proxy.UpdateIndexer(sonarrIndexer, Settings); + } + else + { + // Else remove it, it no longer should be used + _sonarrV3Proxy.RemoveIndexer(remoteIndexer.Id, Settings); + _appIndexerMapService.Delete(indexerMapping.Id); + } } } else diff --git a/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs b/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs index f665905cc..a9a45c06a 100644 --- a/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs +++ b/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs @@ -114,7 +114,7 @@ namespace NzbDrone.Core.Applications.Whisparr var appMappings = _appIndexerMapService.GetMappingsForApp(Definition.Id); var indexerMapping = appMappings.FirstOrDefault(m => m.IndexerId == indexer.Id); - var radarrIndexer = BuildWhisparrIndexer(indexer, indexer.Protocol, indexerMapping?.RemoteIndexerId ?? 0); + var whisparrIndexer = BuildWhisparrIndexer(indexer, indexer.Protocol, indexerMapping?.RemoteIndexerId ?? 0); var remoteIndexer = _whisparrV3Proxy.GetIndexer(indexerMapping.RemoteIndexerId, Settings); @@ -122,9 +122,19 @@ namespace NzbDrone.Core.Applications.Whisparr { _logger.Debug("Remote indexer found, syncing with current settings"); - if (!radarrIndexer.Equals(remoteIndexer)) + if (!whisparrIndexer.Equals(remoteIndexer)) { - _whisparrV3Proxy.UpdateIndexer(radarrIndexer, Settings); + if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) + { + // Update the indexer if it still has categories that match + _whisparrV3Proxy.UpdateIndexer(whisparrIndexer, Settings); + } + else + { + // Else remove it, it no longer should be used + _whisparrV3Proxy.RemoveIndexer(remoteIndexer.Id, Settings); + _appIndexerMapService.Delete(indexerMapping.Id); + } } } else @@ -134,8 +144,8 @@ namespace NzbDrone.Core.Applications.Whisparr if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) { _logger.Debug("Remote indexer not found, re-adding {0} to Whisparr", indexer.Name); - radarrIndexer.Id = 0; - var newRemoteIndexer = _whisparrV3Proxy.AddIndexer(radarrIndexer, Settings); + whisparrIndexer.Id = 0; + var newRemoteIndexer = _whisparrV3Proxy.AddIndexer(whisparrIndexer, Settings); _appIndexerMapService.Insert(new AppIndexerMap { AppId = Definition.Id, IndexerId = indexer.Id, RemoteIndexerId = newRemoteIndexer.Id }); } else From 51e73205ba94102ea15ac7f241845957771cc2d6 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Thu, 3 Feb 2022 23:59:56 -0600 Subject: [PATCH 0438/2320] Fixed: (MaM) Handle Auth Errors & Session Expiry --- src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs b/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs index adce185e1..19876a71f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs @@ -317,6 +317,12 @@ namespace NzbDrone.Core.Indexers.Definitions public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { + // Throw auth errors here before we try to parse + if (indexerResponse.HttpResponse.StatusCode == HttpStatusCode.Forbidden) + { + throw new IndexerAuthException("[403 Forbidden] - mam_session_id expired or invalid"); + } + // Throw common http errors here before we try to parse if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) { From 71e42dafa7ad967c4bd27412892a784a1efa1a24 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Fri, 8 Apr 2022 17:28:11 +0000 Subject: [PATCH 0439/2320] Translated using Weblate (Chinese (Simplified)) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 9.6% (43 of 446 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (446 of 446 strings) Translated using Weblate (French) Currently translated at 99.7% (445 of 446 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (446 of 446 strings) Translated using Weblate (Ukrainian) Currently translated at 16.1% (72 of 446 strings) Translated using Weblate (Ukrainian) Currently translated at 16.1% (72 of 446 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 2.9% (13 of 446 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 100.0% (446 of 446 strings) Translated using Weblate (Arabic) Currently translated at 74.6% (333 of 446 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (446 of 446 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (446 of 446 strings) Translated using Weblate (Vietnamese) Currently translated at 74.6% (333 of 446 strings) Translated using Weblate (Turkish) Currently translated at 74.4% (332 of 446 strings) Translated using Weblate (Thai) Currently translated at 74.6% (333 of 446 strings) Translated using Weblate (Swedish) Currently translated at 91.2% (407 of 446 strings) Translated using Weblate (Russian) Currently translated at 75.5% (337 of 446 strings) Translated using Weblate (Romanian) Currently translated at 74.4% (332 of 446 strings) Translated using Weblate (Portuguese) Currently translated at 80.7% (360 of 446 strings) Translated using Weblate (Polish) Currently translated at 74.6% (333 of 446 strings) Translated using Weblate (Dutch) Currently translated at 91.4% (408 of 446 strings) Translated using Weblate (Korean) Currently translated at 74.6% (333 of 446 strings) Translated using Weblate (Japanese) Currently translated at 74.6% (333 of 446 strings) Translated using Weblate (Italian) Currently translated at 78.4% (350 of 446 strings) Translated using Weblate (Icelandic) Currently translated at 74.6% (333 of 446 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (446 of 446 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (446 of 446 strings) Translated using Weblate (Hindi) Currently translated at 74.6% (333 of 446 strings) Translated using Weblate (Hebrew) Currently translated at 74.6% (333 of 446 strings) Translated using Weblate (French) Currently translated at 96.6% (431 of 446 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (446 of 446 strings) Translated using Weblate (Spanish) Currently translated at 80.7% (360 of 446 strings) Translated using Weblate (Spanish) Currently translated at 80.7% (360 of 446 strings) Translated using Weblate (Greek) Currently translated at 74.4% (332 of 446 strings) Translated using Weblate (German) Currently translated at 97.9% (437 of 446 strings) Translated using Weblate (Danish) Currently translated at 74.4% (332 of 446 strings) Translated using Weblate (Czech) Currently translated at 74.6% (333 of 446 strings) Translated using Weblate (Bulgarian) Currently translated at 69.7% (311 of 446 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 99.7% (445 of 446 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 99.7% (445 of 446 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 99.7% (445 of 446 strings) Co-authored-by: Ana <phampyk@gmail.com> Co-authored-by: Anonymous <noreply@weblate.org> Co-authored-by: Csaba <csab0825@gmail.com> Co-authored-by: Havok Dan <havokdan@yahoo.com.br> Co-authored-by: Oskari Lavinto <olavinto@protonmail.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: andrey4korop <andrey999@i.ua> Co-authored-by: jianjam <jianjam@qq.com> Co-authored-by: killsover <w904202822@163.com> Co-authored-by: neoestremi <remidu34070@hotmail.fr> Co-authored-by: 破晓天 <284062404@qq.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ar/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/bg/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/cs/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/da/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/el/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/he/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/is/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/it/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ja/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ko/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pl/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ro/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ru/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sv/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/th/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/uk/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/vi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_Hans/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/ar.json | 9 +- src/NzbDrone.Core/Localization/Core/bg.json | 10 +- src/NzbDrone.Core/Localization/Core/cs.json | 8 +- src/NzbDrone.Core/Localization/Core/da.json | 9 +- src/NzbDrone.Core/Localization/Core/de.json | 11 ++- src/NzbDrone.Core/Localization/Core/el.json | 9 +- src/NzbDrone.Core/Localization/Core/es.json | 35 ++++++- src/NzbDrone.Core/Localization/Core/fi.json | 18 +++- src/NzbDrone.Core/Localization/Core/fr.json | 34 +++++-- src/NzbDrone.Core/Localization/Core/he.json | 10 +- src/NzbDrone.Core/Localization/Core/hi.json | 10 +- src/NzbDrone.Core/Localization/Core/hu.json | 20 +++- src/NzbDrone.Core/Localization/Core/is.json | 10 +- src/NzbDrone.Core/Localization/Core/it.json | 8 +- src/NzbDrone.Core/Localization/Core/ja.json | 10 +- src/NzbDrone.Core/Localization/Core/ko.json | 93 ++++++++++++++++++- src/NzbDrone.Core/Localization/Core/nl.json | 9 +- src/NzbDrone.Core/Localization/Core/pl.json | 10 +- src/NzbDrone.Core/Localization/Core/pt.json | 11 ++- .../Localization/Core/pt_BR.json | 32 +++++-- src/NzbDrone.Core/Localization/Core/ro.json | 9 +- src/NzbDrone.Core/Localization/Core/ru.json | 9 +- src/NzbDrone.Core/Localization/Core/sv.json | 9 +- src/NzbDrone.Core/Localization/Core/th.json | 10 +- src/NzbDrone.Core/Localization/Core/tr.json | 10 +- src/NzbDrone.Core/Localization/Core/uk.json | 75 ++++++++++++++- src/NzbDrone.Core/Localization/Core/vi.json | 10 +- .../Localization/Core/zh_CN.json | 35 +++++-- .../Localization/Core/zh_Hans.json | 38 +++++++- 29 files changed, 517 insertions(+), 54 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/ar.json b/src/NzbDrone.Core/Localization/Core/ar.json index 63da90fbc..b5aa9f620 100644 --- a/src/NzbDrone.Core/Localization/Core/ar.json +++ b/src/NzbDrone.Core/Localization/Core/ar.json @@ -324,5 +324,12 @@ "HistoryCleanupDaysHelpTextWarning": "سيتم تنظيف الملفات الموجودة في سلة المحذوفات الأقدم من عدد الأيام المحدد تلقائيًا", "OnGrab": "عند الاستيلاء", "OnHealthIssue": "في قضية الصحة", - "TestAllIndexers": "اختبار كافة المفهرسات" + "TestAllIndexers": "اختبار كافة المفهرسات", + "ConnectionLostMessage": "فقد Whisparr اتصاله بالواجهة الخلفية وسيحتاج إلى إعادة تحميله لاستعادة الوظائف.", + "Link": "الروابط", + "MappedDrivesRunningAsService": "لا تتوفر محركات أقراص الشبكة المعينة عند التشغيل كخدمة Windows. يرجى الاطلاع على التعليمات لمزيد من المعلومات", + "UnableToLoadIndexers": "تعذر تحميل المفهرسات", + "Yes": "نعم", + "GrabReleases": "انتزاع الإصدار", + "No": "لا" } diff --git a/src/NzbDrone.Core/Localization/Core/bg.json b/src/NzbDrone.Core/Localization/Core/bg.json index 999107fb9..c078b4e50 100644 --- a/src/NzbDrone.Core/Localization/Core/bg.json +++ b/src/NzbDrone.Core/Localization/Core/bg.json @@ -323,5 +323,13 @@ "HistoryCleanupDaysHelpTextWarning": "Файловете в кошчето, по-стари от избрания брой дни, ще се почистват автоматично", "OnGrab": "На Граб", "OnHealthIssue": "По здравен въпрос", - "TestAllIndexers": "Тествайте всички индексатори" + "TestAllIndexers": "Тествайте всички индексатори", + "NetCore": ".NET Core", + "GrabReleases": "Grab Release", + "Link": "Връзки", + "No": "Не", + "UnableToLoadIndexers": "Индексаторите не могат да се заредят", + "Yes": "Да", + "ConnectionLostMessage": "Whisparr е загубил връзката си с бекенда и ще трябва да се презареди, за да възстанови функционалността.", + "MappedDrivesRunningAsService": "Картографираните мрежови устройства не са налични, когато се изпълняват като услуга на Windows. Моля, вижте често задаваните въпроси за повече информация" } diff --git a/src/NzbDrone.Core/Localization/Core/cs.json b/src/NzbDrone.Core/Localization/Core/cs.json index a8716cb79..773932d12 100644 --- a/src/NzbDrone.Core/Localization/Core/cs.json +++ b/src/NzbDrone.Core/Localization/Core/cs.json @@ -325,5 +325,11 @@ "MaintenanceRelease": "Údržbové vydání: opravy chyb a další vylepšení. Další podrobnosti najdete v GitHub Commit History", "OnGrab": "Chyť", "OnHealthIssue": "K otázce zdraví", - "TestAllIndexers": "Vyzkoušejte všechny indexery" + "TestAllIndexers": "Vyzkoušejte všechny indexery", + "Link": "Odkazy", + "MappedDrivesRunningAsService": "Mapované síťové jednotky nejsou k dispozici, když běží jako služba Windows. Další informace najdete v častých dotazech", + "No": "Ne", + "UnableToLoadIndexers": "Nelze načíst indexery", + "Yes": "Ano", + "GrabReleases": "Uchopte uvolnění" } diff --git a/src/NzbDrone.Core/Localization/Core/da.json b/src/NzbDrone.Core/Localization/Core/da.json index 7020e54fc..affc9dc4d 100644 --- a/src/NzbDrone.Core/Localization/Core/da.json +++ b/src/NzbDrone.Core/Localization/Core/da.json @@ -327,5 +327,12 @@ "HistoryCleanupDaysHelpTextWarning": "Filer i papirkurven, der er ældre end det valgte antal dage, renses automatisk", "OnGrab": "On Grab", "OnHealthIssue": "Om sundhedsspørgsmål", - "TestAllIndexers": "Test alle indeksører" + "TestAllIndexers": "Test alle indeksører", + "GrabReleases": "Grab Release", + "Link": "Links", + "MappedDrivesRunningAsService": "Kortlagte netværksdrev er ikke tilgængelige, når de kører som en Windows-tjeneste. Se FAQ for mere information", + "No": "Ingen", + "NetCore": ".NET Core", + "UnableToLoadIndexers": "Kan ikke indlæse indeksatorer", + "Yes": "Ja" } diff --git a/src/NzbDrone.Core/Localization/Core/de.json b/src/NzbDrone.Core/Localization/Core/de.json index 4ef76a47f..114071e91 100644 --- a/src/NzbDrone.Core/Localization/Core/de.json +++ b/src/NzbDrone.Core/Localization/Core/de.json @@ -426,5 +426,14 @@ "SemiPrivate": "Halbprivat", "UnableToLoadApplicationList": "Anwendungsliste kann nicht geladen werden", "UnableToLoadIndexerProxies": "Indexer-Proxies können nicht geladen werden", - "Website": "Webseite" + "Website": "Webseite", + "Application": "Anwendungen", + "GrabReleases": "Release erfassen", + "Link": "Links", + "MappedDrivesRunningAsService": "Zugeordnete Netzlaufwerke sind nicht verfügbar, wenn Radarr als Windows-Dienst ausgeführt wird. Bitte lesen Sie die FAQ für weitere Informationen", + "No": "Nein", + "SearchTypes": "Suchtyp", + "TVSearchTypes": "Suchtyp", + "UnableToLoadIndexers": "Indexer konnten nicht geladen werden", + "Yes": "Ja" } diff --git a/src/NzbDrone.Core/Localization/Core/el.json b/src/NzbDrone.Core/Localization/Core/el.json index 5e65f50a2..f8392c395 100644 --- a/src/NzbDrone.Core/Localization/Core/el.json +++ b/src/NzbDrone.Core/Localization/Core/el.json @@ -327,5 +327,12 @@ "OnHealthIssue": "Σχετικά με το θέμα της υγείας", "TestAllIndexers": "Δοκιμάστε όλους τους δείκτες", "MaintenanceRelease": "Έκδοση συντήρησης: επιδιορθώσεις σφαλμάτων και άλλες βελτιώσεις. Δείτε το Github Commit History για περισσότερες λεπτομέρειες", - "ConnectionLostMessage": "Το Radarr έχασε τη σύνδεσή του με το backend και θα χρειαστεί να επαναφορτωθεί για να αποκαταστήσει τη λειτουργικότητά του." + "ConnectionLostMessage": "Το Radarr έχασε τη σύνδεσή του με το backend και θα χρειαστεί να επαναφορτωθεί για να αποκαταστήσει τη λειτουργικότητά του.", + "NetCore": ".NET Core", + "GrabReleases": "Πιάσε την απελευθέρωση", + "Link": "Συνδέσεις", + "MappedDrivesRunningAsService": "Οι αντιστοιχισμένες μονάδες δίσκου δικτύου δεν είναι διαθέσιμες κατά την εκτέλεση ως υπηρεσία Windows. Ανατρέξτε στις Συχνές Ερωτήσεις για περισσότερες πληροφορίες", + "No": "Οχι", + "UnableToLoadIndexers": "Δεν είναι δυνατή η φόρτωση του ευρετηρίου", + "Yes": "Ναί" } diff --git a/src/NzbDrone.Core/Localization/Core/es.json b/src/NzbDrone.Core/Localization/Core/es.json index 8abe1ca42..2126c05e6 100644 --- a/src/NzbDrone.Core/Localization/Core/es.json +++ b/src/NzbDrone.Core/Localization/Core/es.json @@ -18,7 +18,7 @@ "Date": "Fecha", "CustomFilters": "Filtros Personalizados", "Connections": "Conexiones", - "Connect": "Conectar", + "Connect": "Notificaciones", "Clear": "Borrar", "BackupNow": "Hacer copia de seguridad", "Backup": "Backup", @@ -146,7 +146,7 @@ "ClientPriority": "Prioridad de Cliente", "ChangeHasNotBeenSavedYet": "El cambio aún no se ha guardado", "CertificateValidationHelpText": "Cambiar la rigidez de la validación de la certificación HTTPS", - "CertificateValidation": "Validación de certificado", + "CertificateValidation": "Validación del certificado", "BypassProxyForLocalAddresses": "Omitir Proxy para Direcciones Locales", "Branch": "Rama", "BindAddressHelpText": "Dirección IP4 válida o '*' para todas las interfaces", @@ -318,7 +318,7 @@ "Yesterday": "Ayer", "ApplicationStatusCheckAllClientMessage": "Las listas no están disponibles debido a errores", "ApplicationStatusCheckSingleClientMessage": "Listas no disponibles debido a errores: {0}", - "AllIndexersHiddenDueToFilter": "Todas las películas están ocultas debido al filtro aplicado.", + "AllIndexersHiddenDueToFilter": "Todos los indexadores están ocultas debido al filtro aplicado.", "DeleteApplicationMessageText": "Seguro que quieres elminiar la notificación '{0}'?", "IndexerProxyStatusCheckAllClientMessage": "Los indexers no están disponibles debido a errores", "IndexerProxyStatusCheckSingleClientMessage": "Indexers no disponibles debido a errores: {0}", @@ -337,5 +337,32 @@ "TestAllIndexers": "Comprobar Todos los Indexers", "NotificationTriggersHelpText": "Seleccione qué eventos deben activar esta notificación", "OnApplicationUpdate": "Al actualizar la aplicación", - "OnApplicationUpdateHelpText": "Al actualizar la aplicación" + "OnApplicationUpdateHelpText": "Al actualizar la aplicación", + "AddAppProfile": "Añadir sincronización de perfil de aplicación", + "AddRemoveOnly": "Sólo añadir y eliminar", + "AddedToDownloadClient": "Descarga añadida al cliente", + "AddNewIndexer": "Añadir nuevo indexador", + "AddToDownloadClient": "Añadir descarga al cliente de descargas", + "Applications": "Aplicaciones", + "AppProfileDeleteConfirm": "¿Seguro que quieres eliminar {0}?", + "AppProfileInUse": "Perfil de aplicación en uso", + "AddDownloadClientToProwlarr": "Añadir un cliente de descargas permite a Prowlarr enviar descargas directamente desde la interfaz en una búsqueda manual.", + "Category": "Categoría", + "Application": "Aplicación", + "AppProfile": "Perfil de aplicación", + "AppProfiles": "Perfiles de aplicaciones", + "BookSearch": "Búsqueda de libros", + "BookSearchTypes": "Tipos de búsqueda de libros", + "Categories": "Categorías", + "AddIndexerProxy": "Añadir proxy del indexador", + "Encoding": "Codificación", + "GrabReleases": "Capturar Estreno", + "Link": "Enlaces", + "MappedDrivesRunningAsService": "Las unidades de red asignadas no están disponibles cuando se ejecutan como un servicio de Windows. Consulte las preguntas frecuentes para obtener más información", + "No": "No", + "Notification": "Notificaciones", + "Notifications": "Notificaciones", + "UnableToLoadIndexers": "No se pueden cargar los indexers", + "Yes": "si", + "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent proporcionado por la aplicación llamó a la API" } diff --git a/src/NzbDrone.Core/Localization/Core/fi.json b/src/NzbDrone.Core/Localization/Core/fi.json index 3ba4ee2c4..4c946fe9d 100644 --- a/src/NzbDrone.Core/Localization/Core/fi.json +++ b/src/NzbDrone.Core/Localization/Core/fi.json @@ -2,7 +2,7 @@ "IndexerProxyStatusCheckSingleClientMessage": "Välityspalvelimet eivät ole käytettävissä virheiden vuoksi: {0}", "Logging": "Kirjaus", "LogLevel": "Kirjauksen taso", - "MovieIndexScrollTop": "Elokuvahakemisto: vieritä ylös", + "MovieIndexScrollTop": "Elokuvakirjasto: vieritä ylös", "Apply": "Käytä", "ClientPriority": "Lataustyökalun painotus", "IndexerPriorityHelpText": "Tietolähteen painotus: 1 (korkein) - 50 (matalin). Oletusarvo on 25. Käytetään muutoin tasaveroisten julkaisujen sieppauspäätökseen. Kaikkia käytössä olevia tietolähteitä käytetään edelleen RSS-synkronointiin ja hakuun.", @@ -10,7 +10,7 @@ "Add": "Lisää", "Reload": "Lataa uudelleen", "Indexers": "Tietolähteet", - "MovieIndexScrollBottom": "Elokuvahakemisto: vieritä alas", + "MovieIndexScrollBottom": "Elokuvakirjasto: vieritä alas", "PtpOldSettingsCheckMessage": "Seuraavat PassThePopcorn-tietolähteet sisältävät vanhentuneita asetuksia, jotka olisi syytä päivittää: {0}", "SSLCertPassword": "SSL-varmenteen salasana", "Style": "Tyyli", @@ -432,7 +432,17 @@ "Link": "Linkit", "SearchTypes": "Mitä etsitään", "UnableToLoadIndexers": "Tietolähteiden lataus epäonnistui.", - "Yes": "Joo", + "Yes": "Kyllä", "MappedDrivesRunningAsService": "Yhdistetyt verkkoasemat eivät ole käytettävissä, kun niitä käytetään Windows-palveluna. Katso lisätietoja UKK: sta", - "No": "Ei" + "No": "Ei", + "BookSearchTypes": "Kirjojen hakutyypit", + "IndexerDetails": "Tietolähteen tiedot", + "IndexerName": "Tietolähteen nimi", + "IndexerSite": "Tietolähteen sivusto", + "MovieSearchTypes": "Elokuvien hakutyypit", + "MusicSearchTypes": "Musiikin hakutyypit", + "NotSupported": "Ei tuettu", + "RawSearchSupported": "Raakahaku tuettu", + "SearchCapabilities": "Hakuominaisuudet", + "TVSearchTypes": "Televisiosarjojen hakutyypit" } diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index 3a7c62e5b..122027f7b 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -12,7 +12,7 @@ "Events": "Événements", "Edit": "Éditer", "DownloadClientStatusCheckAllClientMessage": "Aucun client de téléchargement n'est disponible en raison d'échecs", - "DownloadClients": "Clients Télécharg.", + "DownloadClients": "Clients de téléchargement", "Dates": "Dates", "Date": "Date", "Delete": "Supprimer", @@ -22,11 +22,11 @@ "Clear": "Effacer", "BackupNow": "Sauvegarder maintenant", "Backup": "Sauvegarde", - "AppDataLocationHealthCheckMessage": "Mettre à jour ne sera pas possible pour éviter la suppression AppData lors de la mise à jour", + "AppDataLocationHealthCheckMessage": "Mettre à jour ne sera pas possible afin d'éviter de supprimer le dossier AppData lors de la mise à jour", "Analytics": "Analytique", "All": "Tout", "About": "À propos", - "IndexerStatusCheckSingleClientMessage": "Indexeurs indisponibles en raison d'échecs : {0}", + "IndexerStatusCheckSingleClientMessage": "Indexeurs indisponibles en raison d'échecs : {0}", "DownloadClientStatusCheckSingleClientMessage": "Clients de Téléchargement indisponibles en raison d'échecs : {0}", "SetTags": "Définir Tags", "ReleaseStatus": "Statut de la version", @@ -354,7 +354,7 @@ "Applications": "Applications", "AppProfileDeleteConfirm": "Voulez-vous vraiment supprimer {0} ?", "AppProfileInUse": "Profil d'application en cours d'utilisation", - "Apps": "Apps", + "Apps": "Applications", "Auth": "Auth", "Category": "Catégorie", "Custom": "Personnalisé", @@ -373,7 +373,7 @@ "UnableToAddANewAppProfilePleaseTryAgain": "Impossible d'ajouter un nouveau profil d'application, veuillez réessayer.", "UnableToLoadAppProfiles": "Impossible de charger les profils d'application", "Add": "Ajouter", - "SyncLevelFull": "Synchronisation complète : gardera cette application entièrement synchronisée. Les modifications apportées dans Prowlarr sont ensuite synchronisées avec cette application. Toute modification effectuée à distance sera annulée par Prowlarr lors de la prochaine synchronisation.", + "SyncLevelFull": "Synchronisation complète : Maintiendra les indexeurs de cette application entièrement synchronisés. Les modifications apportées aux indexeurs dans Prowlarr sont ensuite synchronisées avec cette application. Toute modification effectuée sur les indexeurs dans l'application sera annulée par Prowlarr lors de la prochaine synchronisation.", "SyncLevelAddRemove": "Ajouter et supprimer uniquement : lorsque les indexeurs sont ajoutés ou supprimés de Prowlarr, ils mettront à jour cette application à distance.", "SyncLevel": "Niveau de synchronisation", "FullSync": "Synchronisation complète", @@ -407,7 +407,7 @@ "Database": "Base de données", "HistoryCleanup": "Nettoyage de l'historique", "IndexerAlreadySetup": "Au moins une instance de l'indexeur est déjà configurée", - "IndexerInfo": "Info de l'indexeur", + "IndexerInfo": "Info sur l'indexeur", "Private": "Privé", "Proxies": "Proxies", "Public": "Publique", @@ -417,7 +417,7 @@ "QueryOptions": "Options de recherche", "SearchType": "Type de recherche", "Categories": "Catégories", - "MassEditor": "Éditeur de masse", + "MassEditor": "Éditer en masse", "UnableToLoadApplicationList": "Impossible de charger la liste des applications", "Website": "Site internet", "AudioSearch": "Recherche de musique", @@ -426,5 +426,23 @@ "OnApplicationUpdateHelpText": "Lors de la mise à jour de l'app", "IndexerNoDefCheckMessage": "Les indexeurs ne sont pas définis et ne fonctionneront pas :Merci de les retirer et (ou) les ajouter à nouveau à Prowlarr", "MovieSearch": "Recherche de films", - "TvSearch": "Recherche de séries TV" + "TvSearch": "Recherche de séries TV", + "Application": "Applications", + "GrabReleases": "Télécharger la/les version(s)", + "Link": "Lien", + "No": "Non", + "SearchTypes": "Types de recherche", + "TVSearchTypes": "Types de recherche de séries/émissions", + "UnableToLoadIndexers": "Impossible de charger les indexeurs", + "Yes": "Oui", + "MappedDrivesRunningAsService": "Les lecteurs réseau mappés ne sont pas disponibles en fonctionnement en tant que service Windows. Veuillez consulter la FAQ pour plus d'informations", + "IndexerDetails": "Détails sur l'indexeur", + "RawSearchSupported": "Recherche brute supportée", + "BookSearchTypes": "Type de recherche de livres", + "IndexerName": "Nom de l'indexeur", + "IndexerSite": "Site de l'indexeur", + "MovieSearchTypes": "Types de recherches de films", + "MusicSearchTypes": "Type de recherche de musiques", + "NotSupported": "Non supporté", + "SearchCapabilities": "Capacités de recherche" } diff --git a/src/NzbDrone.Core/Localization/Core/he.json b/src/NzbDrone.Core/Localization/Core/he.json index abf33af18..d4531004a 100644 --- a/src/NzbDrone.Core/Localization/Core/he.json +++ b/src/NzbDrone.Core/Localization/Core/he.json @@ -323,5 +323,13 @@ "HistoryCleanupDaysHelpTextWarning": "קבצים בסל המיחזור ישנים יותר ממספר הימים שנבחר ינוקו באופן אוטומטי", "OnGrab": "על לתפוס", "OnHealthIssue": "בנושא הבריאות", - "TestAllIndexers": "בדוק את כל האינדקסים" + "TestAllIndexers": "בדוק את כל האינדקסים", + "ConnectionLostMessage": "Whisparr איבד את החיבור ל- backend ויהיה צורך לטעון אותו מחדש כדי לשחזר את הפונקציונליות.", + "GrabReleases": "שחרור תפוס", + "Link": "קישורים", + "NetCore": ".NET Core", + "No": "לא", + "UnableToLoadIndexers": "לא ניתן לטעון אינדקסים", + "Yes": "כן", + "MappedDrivesRunningAsService": "כונני רשת ממופים אינם זמינים כאשר הם פועלים כשירות Windows. אנא עיין בשאלות הנפוצות למידע נוסף" } diff --git a/src/NzbDrone.Core/Localization/Core/hi.json b/src/NzbDrone.Core/Localization/Core/hi.json index 64e9d50fa..2a8e8b547 100644 --- a/src/NzbDrone.Core/Localization/Core/hi.json +++ b/src/NzbDrone.Core/Localization/Core/hi.json @@ -323,5 +323,13 @@ "MaintenanceRelease": "रखरखाव रिलीज: बग फिक्स और अन्य सुधार। अधिक जानकारी के लिए गितुब कमिट इतिहास देखें", "Filters": "फ़िल्टर", "HistoryCleanupDaysHelpText": "स्वचालित सफाई को अक्षम करने के लिए 0 पर सेट करें", - "HistoryCleanupDaysHelpTextWarning": "रीसायकल बिन में चयनित दिनों की तुलना में पुरानी फाइलें अपने आप साफ हो जाएंगी" + "HistoryCleanupDaysHelpTextWarning": "रीसायकल बिन में चयनित दिनों की तुलना में पुरानी फाइलें अपने आप साफ हो जाएंगी", + "NetCore": ".NET कोर", + "ConnectionLostMessage": "रैडियर ने बैकएंड से कनेक्शन खो दिया है और कार्यक्षमता को बहाल करने के लिए इसे फिर से लोड करना होगा।", + "GrabReleases": "पकड़ो रिलीज", + "Yes": "हाँ", + "Link": "लिंक", + "MappedDrivesRunningAsService": "विंडोज सर्विस के रूप में चलने पर मैप्ड नेटवर्क ड्राइव उपलब्ध नहीं हैं। अधिक जानकारी के लिए कृपया FAQ देखें", + "No": "नहीं", + "UnableToLoadIndexers": "अनुक्रमणिका लोड करने में असमर्थ" } diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index c327f5027..cd3ec05bf 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -426,5 +426,23 @@ "UnableToLoadApplicationList": "Nem sikerült betölteni az alkalmazáslistát", "Url": "URL", "UserAgentProvidedByTheAppThatCalledTheAPI": "Az API-t hívó alkalmazás biztosítja a User-Agent szolgáltatást", - "Website": "Weboldal" + "Website": "Weboldal", + "Application": "Alkalmazások", + "GrabReleases": "Release megragadása", + "UnableToLoadIndexers": "Nem lehet betölteni az indexereket", + "Yes": "Igen", + "Link": "Linkek", + "MappedDrivesRunningAsService": "A hozzárendelt hálózati meghajtók nem érhetők el, ha Windows szolgáltatásként futnak. További információkért olvasd át a GYIK-et", + "No": "Nem", + "SearchTypes": "Keresés típusa", + "BookSearchTypes": "Könyvkeresés típusai", + "IndexerDetails": "Indexer adatai", + "IndexerName": "Indexer neve", + "IndexerSite": "Indexer oldal", + "MovieSearchTypes": "Filmkeresés típusai", + "MusicSearchTypes": "Zenekeresés típusai", + "NotSupported": "Nem támogatott", + "RawSearchSupported": "Nyers keresés támogatott", + "SearchCapabilities": "Keresési lehetőségek", + "TVSearchTypes": "TV-Sorozat keresési típusok" } diff --git a/src/NzbDrone.Core/Localization/Core/is.json b/src/NzbDrone.Core/Localization/Core/is.json index d05dcf9d9..e40299d16 100644 --- a/src/NzbDrone.Core/Localization/Core/is.json +++ b/src/NzbDrone.Core/Localization/Core/is.json @@ -323,5 +323,13 @@ "HistoryCleanupDaysHelpTextWarning": "Skrár í ruslakörfunni eldri en valinn fjöldi daga verða hreinsaðir upp sjálfkrafa", "OnGrab": "Á grípa", "OnHealthIssue": "Um heilbrigðismál", - "TestAllIndexers": "Prófaðu alla verðtryggjendur" + "TestAllIndexers": "Prófaðu alla verðtryggjendur", + "NetCore": ".NET algerlega", + "GrabReleases": "Grípa losun", + "Link": "Krækjur", + "MappedDrivesRunningAsService": "Kortlagðar netdrif eru ekki fáanlegar þegar þær eru keyrðar sem Windows þjónusta. Vinsamlegast skoðaðu algengar spurningar fyrir frekari upplýsingar", + "No": "Nei", + "UnableToLoadIndexers": "Ekki er hægt að hlaða Indexers", + "Yes": "Já", + "ConnectionLostMessage": "Whisparr hefur misst tenginguna við bakendann og þarf að endurhlaða hann til að endurheimta virkni." } diff --git a/src/NzbDrone.Core/Localization/Core/it.json b/src/NzbDrone.Core/Localization/Core/it.json index 83eefad49..19f52e8ce 100644 --- a/src/NzbDrone.Core/Localization/Core/it.json +++ b/src/NzbDrone.Core/Localization/Core/it.json @@ -349,5 +349,11 @@ "OnGrab": "Quando viene prelevato", "OnHealthIssue": "Quando c'è un problema", "TestAllIndexers": "Testa tutti gli indexer", - "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent esposto dalla app che ha chiamato la API" + "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent esposto dalla app che ha chiamato la API", + "GrabReleases": "Preleva Release", + "Link": "Collegamenti", + "MappedDrivesRunningAsService": "I drive di rete mappati non sono disponibili eseguendo come servizio di Windows. Vedere le FAQ per maggiori informazioni", + "No": "No", + "UnableToLoadIndexers": "Non riesco a caricare l'indexer", + "Yes": "Si" } diff --git a/src/NzbDrone.Core/Localization/Core/ja.json b/src/NzbDrone.Core/Localization/Core/ja.json index ae21ed5e2..1de5c2d9c 100644 --- a/src/NzbDrone.Core/Localization/Core/ja.json +++ b/src/NzbDrone.Core/Localization/Core/ja.json @@ -323,5 +323,13 @@ "HistoryCleanupDaysHelpText": "自動クリーンアップを無効にするには、0に設定します", "OnGrab": "グラブで", "TestAllIndexers": "すべてのインデクサーをテストする", - "MaintenanceRelease": "メンテナンスリリース:バグ修正およびその他の改善。詳細については、Githubのコミット履歴を参照してください" + "MaintenanceRelease": "メンテナンスリリース:バグ修正およびその他の改善。詳細については、Githubのコミット履歴を参照してください", + "NetCore": ".NET Core", + "GrabReleases": "グラブリリース", + "Link": "リンク", + "MappedDrivesRunningAsService": "マップされたネットワークドライブは、Windowsサービスとして実行している場合は使用できません。詳細については、FAQを参照してください", + "No": "番号", + "UnableToLoadIndexers": "インデクサーを読み込めません", + "Yes": "はい", + "ConnectionLostMessage": "Whisparrはバックエンドへの接続を失ったため、機能を復元するには再ロードする必要があります。" } diff --git a/src/NzbDrone.Core/Localization/Core/ko.json b/src/NzbDrone.Core/Localization/Core/ko.json index c02ca4982..d5cc1fea2 100644 --- a/src/NzbDrone.Core/Localization/Core/ko.json +++ b/src/NzbDrone.Core/Localization/Core/ko.json @@ -240,5 +240,96 @@ "HistoryCleanupDaysHelpTextWarning": "선택한 일 수보다 오래된 휴지통에있는 파일은 자동으로 정리됩니다.", "OnGrab": "잡기", "OnHealthIssue": "건강 문제", - "TestAllIndexers": "모든 인덱서 테스트" + "TestAllIndexers": "모든 인덱서 테스트", + "Filters": "필터", + "FocusSearchBox": "포커스 검색 창", + "GeneralSettingsSummary": "포트, SSL, 사용자 이름 / 암호, 프록시, 분석 및 업데이트", + "HideAdvanced": "고급 숨기기", + "IndexerStatusCheckAllClientMessage": "오류로 인해 모든 인덱서를 사용할 수 없습니다.", + "InteractiveSearch": "대화형 검색", + "LastWriteTime": "마지막 쓰기 시간", + "Link": "연결", + "MaintenanceRelease": "유지 관리 출시 : 버그 수정 및 기타 개선. 자세한 내용은 Github 커밋 내역을 참조하십시오.", + "Manual": "설명서", + "MappedDrivesRunningAsService": "Windows 서비스로 실행할 때는 매핑 된 네트워크 드라이브를 사용할 수 없습니다. 자세한 내용은 FAQ를 참조하십시오.", + "No": "아니", + "NoLinks": "링크 없음", + "PendingChangesMessage": "저장하지 않은 변경 사항이 있습니다.이 페이지에서 나가시겠습니까?", + "PendingChangesStayReview": "변경 사항 유지 및 검토", + "Presets": "사전 설정", + "ProxyCheckResolveIpMessage": "구성된 프록시 호스트 {0}의 IP 주소를 확인하지 못했습니다.", + "PtpOldSettingsCheckMessage": "다음 PassThePopcorn 인덱서에는 더 이상 사용되지 않는 설정이 있으며 업데이트해야합니다. {0}", + "Reddit": "레딧", + "TagsSettingsSummary": "모든 태그와 사용 방법을 확인하십시오. 사용하지 않는 태그는 제거 할 수 있습니다.", + "Yesterday": "어제", + "ApplicationStatusCheckAllClientMessage": "실패로 인해 모든 목록을 사용할 수 없습니다.", + "ApplicationStatusCheckSingleClientMessage": "실패로 인해 사용할 수없는 목록 : {0}", + "ReleaseBranchCheckOfficialBranchMessage": "{0} 분기는 유효한 Whisparr 출시 분기가 아닙니다. 업데이트를받을 수 없습니다.", + "ProxyCheckBadRequestMessage": "프록시를 테스트하지 못했습니다. StatusCode : {0}", + "ProxyCheckFailedToTestMessage": "프록시 테스트 실패 : {0}", + "ReleaseStatus": "출시 상태", + "RSS": "RSS", + "Sort": "종류", + "UnsavedChanges": "저장되지 않은 변경 사항", + "UnselectAll": "모두 선택 해제", + "Shutdown": "종료", + "Grabbed": "잡았다", + "General": "일반", + "OAuthPopupMessage": "브라우저에서 팝업을 차단하고 있습니다.", + "Ok": "확인", + "OpenThisModal": "이 모달 열기", + "RefreshMovie": "영화 새로 고침", + "SuggestTranslationChange": "번역 변경 제안", + "Level": "수평", + "UpdateCheckStartupTranslocationMessage": "시작 폴더 '{0}'이 (가) App Translocation 폴더에 있으므로 업데이트를 설치할 수 없습니다.", + "UrlBaseHelpText": "역방향 프록시 지원의 경우 기본값은 비어 있습니다.", + "MovieIndexScrollBottom": "영화 색인 : 아래로 스크롤", + "View": "전망", + "Wiki": "위키", + "EditIndexer": "인덱서 편집", + "Filter": "필터", + "Health": "건강", + "HealthNoIssues": "구성에 문제 없음", + "Info": "정보", + "KeyboardShortcuts": "키보드 단축키", + "MovieIndexScrollTop": "영화 색인 : 상단 스크롤", + "NoTagsHaveBeenAddedYet": "아직 추가 된 태그가 없습니다.", + "PendingChangesDiscardChanges": "변경 사항을 취소하고 나가기", + "Priority": "우선 순위", + "PriorityHelpText": "여러 다운로드 클라이언트의 우선 순위를 지정합니다. 라운드 로빈은 우선 순위가 같은 클라이언트에 사용됩니다.", + "PrioritySettings": "우선 순위", + "SetTags": "태그 설정", + "System": "체계", + "UpdateCheckUINotWritableMessage": "사용자 '{1}'이 (가) UI 폴더 '{0}'에 쓸 수 없기 때문에 업데이트를 설치할 수 없습니다.", + "Warn": "경고", + "HomePage": "홈 페이지", + "Peers": "동료", + "Discord": "불일치", + "Error": "오류", + "Events": "이벤트", + "EventType": "이벤트 유형", + "Failed": "실패한", + "FeatureRequests": "기능 요청", + "IndexerFlags": "인덱서 플래그", + "IndexerLongTermStatusCheckAllClientMessage": "6 시간 이상 오류로 인해 모든 인덱서를 사용할 수 없습니다.", + "IndexerLongTermStatusCheckSingleClientMessage": "6 시간 이상 오류로 인해 인덱서를 사용할 수 없음 : {0}", + "IndexerProxyStatusCheckAllClientMessage": "오류로 인해 모든 인덱서를 사용할 수 없습니다.", + "IndexerProxyStatusCheckSingleClientMessage": "오류로 인해 인덱서를 사용할 수 없음 : {0}", + "IndexerStatusCheckSingleClientMessage": "오류로 인해 인덱서를 사용할 수 없음 : {0}", + "NetCore": ".NET Core", + "Save": "저장", + "SaveSettings": "설정 저장", + "Seeders": "시더", + "SelectAll": "모두 선택", + "ShowAdvanced": "고급보기", + "SystemTimeCheckMessage": "시스템 시간이 1 일 이상 꺼져 있습니다. 예약 된 작업은 시간이 수정 될 때까지 올바르게 실행되지 않을 수 있습니다.", + "TableOptions": "테이블 옵션", + "TableOptionsColumnsMessage": "표시되는 열과 표시되는 순서 선택", + "TagsHelpText": "일치하는 태그가 하나 이상있는 영화에 적용됩니다.", + "Test": "테스트", + "Time": "시간", + "UnableToLoadIndexers": "인덱서를로드 할 수 없습니다.", + "UpdateCheckStartupNotWritableMessage": "'{1}'사용자가 '{0}'시작 폴더에 쓸 수 없기 때문에 업데이트를 설치할 수 없습니다.", + "Yes": "예", + "GrabReleases": "그랩 릴리스" } diff --git a/src/NzbDrone.Core/Localization/Core/nl.json b/src/NzbDrone.Core/Localization/Core/nl.json index 33f00afe8..667be8413 100644 --- a/src/NzbDrone.Core/Localization/Core/nl.json +++ b/src/NzbDrone.Core/Localization/Core/nl.json @@ -403,5 +403,12 @@ "OnHealthIssue": "Bij Gezondheidsprobleem", "Filters": "Filter", "TestAllIndexers": "Test Alle Indexeerders", - "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent geleverd door de app die de API heeft aangeroepen" + "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent geleverd door de app die de API heeft aangeroepen", + "Application": "Applicaties", + "Link": "Koppelingen", + "MappedDrivesRunningAsService": "Toegewezen netwerkstation is niet beschikbaar wanneer Radarr wordt uitgevoerd als een Windows Service. Bekijk de Veelgestelde Vragen voor meer informatie", + "No": "Nee", + "UnableToLoadIndexers": "Indexeerders kunnen niet worden geladen", + "GrabReleases": "Uitgave Ophalen", + "Yes": "Ja" } diff --git a/src/NzbDrone.Core/Localization/Core/pl.json b/src/NzbDrone.Core/Localization/Core/pl.json index 7cfe991b0..16364bee5 100644 --- a/src/NzbDrone.Core/Localization/Core/pl.json +++ b/src/NzbDrone.Core/Localization/Core/pl.json @@ -323,5 +323,13 @@ "HistoryCleanupDaysHelpText": "Ustaw na 0, aby wyłączyć automatyczne czyszczenie", "OnGrab": "Na Grab", "OnHealthIssue": "W kwestii zdrowia", - "TestAllIndexers": "Przetestuj wszystkie indeksatory" + "TestAllIndexers": "Przetestuj wszystkie indeksatory", + "ConnectionLostMessage": "Whisparr utracił połączenie z zapleczem i będzie musiał zostać ponownie załadowany, aby przywrócić funkcjonalność.", + "GrabReleases": "Grab Release", + "No": "Nie", + "NetCore": ".NET Core", + "UnableToLoadIndexers": "Nie można załadować indeksatorów", + "Link": "Spinki do mankietów", + "MappedDrivesRunningAsService": "Zmapowane dyski sieciowe nie są dostępne, gdy działają jako usługa systemu Windows. Więcej informacji można znaleźć w FAQ", + "Yes": "tak" } diff --git a/src/NzbDrone.Core/Localization/Core/pt.json b/src/NzbDrone.Core/Localization/Core/pt.json index 2aacd72e6..0f3cd4c13 100644 --- a/src/NzbDrone.Core/Localization/Core/pt.json +++ b/src/NzbDrone.Core/Localization/Core/pt.json @@ -395,5 +395,14 @@ "TestAllIndexers": "Testar todos os indexadores", "UserAgentProvidedByTheAppThatCalledTheAPI": "Par Utilizador-Agente fornecido pela aplicação que chamou a API", "OnApplicationUpdate": "Quando a aplicação atualizar", - "OnApplicationUpdateHelpText": "Quando a aplicação atualizar" + "OnApplicationUpdateHelpText": "Quando a aplicação atualizar", + "Database": "base de dados", + "HistoryCleanupDaysHelpTextWarning": "Ficheiros na reciclagem serão eliminados automaticamente após o número de dias selecionado", + "Application": "Aplicações", + "Link": "Ligações", + "MappedDrivesRunningAsService": "As unidades de rede mapeadas não estão disponíveis quando executadas como um serviço do Windows. Veja as Perguntas mais frequentes para obter mais informações", + "No": "Não", + "UnableToLoadIndexers": "Não foi possível carregar os indexadores", + "Yes": "Sim", + "GrabReleases": "Capturar versão" } diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index 5612af34d..e82afa703 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -40,13 +40,13 @@ "SSLCertPasswordHelpText": "Senha para arquivo pfx", "StartupDirectory": "Diretório de inicialização", "SuggestTranslationChange": "Sugerir alteração para a tradução", - "SystemTimeCheckMessage": "A hora do sistema está errada por mais de 1 dia. As tarefas agendadas podem não funcionar corretamente até que a hora seja corrigida", + "SystemTimeCheckMessage": "A hora do sistema está desligada por mais de 1 dia. As tarefas agendadas podem não ser executadas corretamente até que a hora seja corrigida", "TagsHelpText": "Aplica-se a indexadores com pelo menos uma tag correspondente", "UILanguageHelpText": "Idioma que o Prowlarr usará para a interface", "UnableToAddANewIndexerPleaseTryAgain": "Não foi possível adicionar um novo indexador, tente novamente.", "UnableToLoadGeneralSettings": "Não foi possível carregar as configurações gerais", "UpdateAutomaticallyHelpText": "Baixar e instalar atualizações automaticamente. Você ainda poderá instalar a partir de Sistema: Atualizações", - "UpdateCheckStartupTranslocationMessage": "Não é possível instalar a atualização porque a pasta de inicialização \"{0}\" está em uma pasta de transposição de aplicativos.", + "UpdateCheckStartupTranslocationMessage": "Não é possível instalar a atualização porque a pasta de inicialização '{0}' está em uma pasta App Translocation.", "UrlBaseHelpText": "Para suporte de proxy reverso, o padrão é vazio", "Actions": "Ações", "Added": "Adicionado", @@ -174,7 +174,7 @@ "Logging": "Registro em log", "LogLevel": "Nível do log", "LogLevelTraceHelpTextWarning": "O registro de rastreamento deve ser ativado apenas temporariamente", - "Logs": "Logs", + "Logs": "Registros", "MaintenanceRelease": "Lançamento de manutenção: correções de bugs e outras melhorias. Veja o histórico de mudanças no github para mais detalhes", "Manual": "Manual", "Mechanism": "Mecanismo", @@ -211,9 +211,9 @@ "ProwlarrSupportsAnyDownloadClient": "O Prowlarr é compatível com todos os clientes de download listados abaixo.", "Proxy": "Proxy", "ProxyBypassFilterHelpText": "Usar \",\" como separador e \"*.\" como curinga para subdomínios", - "ProxyCheckBadRequestMessage": "Falha ao testar o proxy. StatusCode: {0}", + "ProxyCheckBadRequestMessage": "Falha ao testar o proxy. Código de Status: {0}", "ProxyCheckFailedToTestMessage": "Falha ao testar o proxy: {0}", - "ProxyCheckResolveIpMessage": "Falha ao solucionar o Endereço IP para o Host de proxy configurado {0}", + "ProxyCheckResolveIpMessage": "Falha ao resolver o endereço IP para o host proxy configurado {0}", "ProxyPasswordHelpText": "Você só precisa inserir um nome de usuário e uma senha se solicitado. Caso contrário, deixe em branco.", "ProxyType": "Tipo de proxy", "PtpOldSettingsCheckMessage": "As configurações dos seguintes indexadores do PassThePopcorn são obsoletas e devem ser atualizadas: {0}", @@ -306,7 +306,7 @@ "UnableToLoadUISettings": "Não foi possível carregar as configurações da interface", "UnsavedChanges": "Alterações não salvas", "UnselectAll": "Desmarcar tudo", - "UpdateCheckStartupNotWritableMessage": "Não é possível instalar a atualização porque a pasta de inicialização \"{0}\" não pode ser acessada pelo usuário \"{1}\".", + "UpdateCheckStartupNotWritableMessage": "Não é possível instalar a atualização porque a pasta de inicialização '{0}' não pode ser gravada pelo usuário '{1}'.", "UpdateCheckUINotWritableMessage": "Não é possível instalar a atualização porque a pasta de interface do usuário '{0}' não é gravável pelo usuário '{1}'.", "UpdateMechanismHelpText": "Usar o atualizador embutido do Prowlarr ou um script", "Updates": "Atualizações", @@ -426,5 +426,23 @@ "SemiPrivate": "Semi-Privado", "UnableToLoadApplicationList": "Não é possível carregar a lista de aplicativos", "Url": "Url", - "Website": "Website" + "Website": "Website", + "IndexerDetails": "Detalhes do Indexador", + "IndexerName": "Nome do Indexador", + "IndexerSite": "Site do Indexador", + "MovieSearchTypes": "Tipos de Pesquisa de Filmes", + "MusicSearchTypes": "Tipos de Pesquisa de Músicas", + "NotSupported": "Não Suportado", + "RawSearchSupported": "Pesquisa Bruta Suportada", + "SearchCapabilities": "Recursos de Pesquisa", + "TVSearchTypes": "Tipos de Pesquisa de Seriados", + "BookSearchTypes": "Tipos de Pesquisa de Livros", + "SearchTypes": "Tipo de Pesquisa", + "UnableToLoadIndexers": "Não foi possível carregar os indexadores", + "Yes": "Sim", + "Application": "Aplicativos", + "GrabReleases": "Capturar Versão", + "Link": "Link", + "MappedDrivesRunningAsService": "As unidades de rede mapeadas não estão disponíveis quando executadas como um serviço do Windows. Consulte as Perguntas frequentes para saber mais", + "No": "Não" } diff --git a/src/NzbDrone.Core/Localization/Core/ro.json b/src/NzbDrone.Core/Localization/Core/ro.json index 0fc1b4b45..87d681064 100644 --- a/src/NzbDrone.Core/Localization/Core/ro.json +++ b/src/NzbDrone.Core/Localization/Core/ro.json @@ -328,5 +328,12 @@ "HistoryCleanupDaysHelpTextWarning": "Fișierele din coșul de reciclare mai vechi de numărul de zile selectat vor fi curățate automat", "OnGrab": "Pe Grab", "OnHealthIssue": "Cu privire la problema sănătății", - "TestAllIndexers": "Testați toți indexatorii" + "TestAllIndexers": "Testați toți indexatorii", + "Link": "Link-uri", + "NetCore": ".NET Core", + "UnableToLoadIndexers": "Imposibil de încărcat indexatori", + "GrabReleases": "Grab Release", + "MappedDrivesRunningAsService": "Unitățile de rețea mapate nu sunt disponibile atunci când rulează ca serviciu Windows. Vă rugăm să consultați FAQ pentru mai multe informații", + "No": "Nu", + "Yes": "da" } diff --git a/src/NzbDrone.Core/Localization/Core/ru.json b/src/NzbDrone.Core/Localization/Core/ru.json index ed612afa9..b49a2165e 100644 --- a/src/NzbDrone.Core/Localization/Core/ru.json +++ b/src/NzbDrone.Core/Localization/Core/ru.json @@ -328,5 +328,12 @@ "OnApplicationUpdate": "О обновлении приложения", "TestAllIndexers": "Тестировать все индексаторы", "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent, представленный приложением, который вызывает API", - "NotificationTriggersHelpText": "Выберите, какие события должны вызвать это уведомление" + "NotificationTriggersHelpText": "Выберите, какие события должны вызвать это уведомление", + "NetCore": ".NET", + "GrabReleases": "Захватить релиз", + "UnableToLoadIndexers": "Не удалось загрузить индексаторы", + "Link": "Ссылки", + "MappedDrivesRunningAsService": "Подключённые сетевые диски недоступны, если программа запущена как сервис. Обратитесь в FAQ за дополнительной информацией", + "No": "Нет", + "Yes": "Да" } diff --git a/src/NzbDrone.Core/Localization/Core/sv.json b/src/NzbDrone.Core/Localization/Core/sv.json index 9eca93d66..e8adfbc51 100644 --- a/src/NzbDrone.Core/Localization/Core/sv.json +++ b/src/NzbDrone.Core/Localization/Core/sv.json @@ -402,5 +402,12 @@ "HistoryCleanupDaysHelpTextWarning": "Filer i papperskorgen som är äldre än det valda antalet dagar rensas automatiskt", "OnGrab": "Vid hämtning", "OnHealthIssue": "På hälsofrågan", - "TestAllIndexers": "Testa samtliga indexerare" + "TestAllIndexers": "Testa samtliga indexerare", + "GrabReleases": "Hämta utgåva", + "UnableToLoadIndexers": "Det går inte att ladda indexerare", + "Yes": "Ja", + "Application": "Applikationer", + "Link": "Länkar", + "MappedDrivesRunningAsService": "Mappade nätverksenheter är inte tillgängliga när de körs som en Windows-tjänst. Se FAQ för mer information", + "No": "Nej" } diff --git a/src/NzbDrone.Core/Localization/Core/th.json b/src/NzbDrone.Core/Localization/Core/th.json index 87f40407c..21cbf51ac 100644 --- a/src/NzbDrone.Core/Localization/Core/th.json +++ b/src/NzbDrone.Core/Localization/Core/th.json @@ -323,5 +323,13 @@ "HistoryCleanupDaysHelpText": "ตั้งค่าเป็น 0 เพื่อปิดใช้งานการล้างข้อมูลอัตโนมัติ", "OnGrab": "บน Grab", "OnHealthIssue": "เกี่ยวกับปัญหาสุขภาพ", - "TestAllIndexers": "ทดสอบดัชนีทั้งหมด" + "TestAllIndexers": "ทดสอบดัชนีทั้งหมด", + "ConnectionLostMessage": "Whisparr สูญเสียการเชื่อมต่อกับแบ็กเอนด์และจะต้องโหลดใหม่เพื่อกู้คืนฟังก์ชันการทำงาน", + "GrabReleases": "คว้ารีลีส", + "NetCore": ".NET Core", + "MappedDrivesRunningAsService": "ไดรฟ์เครือข่ายที่แมปไม่พร้อมใช้งานเมื่อเรียกใช้เป็นบริการ Windows โปรดดูคำถามที่พบบ่อยสำหรับข้อมูลเพิ่มเติม", + "No": "ไม่", + "Link": "ลิงค์", + "UnableToLoadIndexers": "ไม่สามารถโหลด Indexers", + "Yes": "ใช่" } diff --git a/src/NzbDrone.Core/Localization/Core/tr.json b/src/NzbDrone.Core/Localization/Core/tr.json index af4ead78e..efaa4e0e6 100644 --- a/src/NzbDrone.Core/Localization/Core/tr.json +++ b/src/NzbDrone.Core/Localization/Core/tr.json @@ -326,5 +326,13 @@ "Filters": "Filtre", "OnGrab": "Yakalandığında", "OnHealthIssue": "Sağlık Sorunu Hakkında", - "TestAllIndexers": "Tüm Dizinleyicileri Test Et" + "TestAllIndexers": "Tüm Dizinleyicileri Test Et", + "ConnectionLostMessage": "Whisparr arka uçla olan bağlantısını kaybetti ve işlevselliği geri yüklemek için yeniden yüklenmesi gerekecek.", + "GrabReleases": "Bırakma", + "No": "Hayır", + "NetCore": ".NET Çekirdeği", + "UnableToLoadIndexers": "Dizinleyiciler yüklenemiyor", + "Yes": "Evet", + "Link": "Bağlantılar", + "MappedDrivesRunningAsService": "Eşlenen ağ sürücüleri, bir Windows Hizmeti olarak çalışırken kullanılamaz. Daha fazla bilgi için lütfen SSS bölümüne bakın" } diff --git a/src/NzbDrone.Core/Localization/Core/uk.json b/src/NzbDrone.Core/Localization/Core/uk.json index 0967ef424..9d0fa3331 100644 --- a/src/NzbDrone.Core/Localization/Core/uk.json +++ b/src/NzbDrone.Core/Localization/Core/uk.json @@ -1 +1,74 @@ -{} +{ + "BranchUpdateMechanism": "Гілка, що використовується зовнішнім механізмом оновлення", + "CancelPendingTask": "Ви впевнені, що хочете скасувати це незавершене завдання?", + "About": "Деталі", + "AcceptConfirmationModal": "Вікно підтвердження", + "Actions": "Дії", + "Add": "Додати", + "AddDownloadClient": "Додати клієнт завантаження", + "Age": "Вік", + "All": "Всі", + "Analytics": "Аналітика", + "ApiKey": "API Ключ", + "Added": "Додано", + "AddIndexer": "Додати індексатор", + "AddingTag": "Додавання тегу", + "AppDataDirectory": "Каталог AppData", + "AppDataLocationHealthCheckMessage": "Оновлення буде неможливим, щоб запобігти видаленню AppData під час оновлення", + "Apply": "Застосувати", + "ApplyTags": "Застосувати теги", + "BackupNow": "Зробити резервну копію", + "BackupRetentionHelpText": "Автоматичні резервні копії, старіші за період зберігання, очищаються автоматично", + "Component": "Компонент", + "ConnectionLost": "Зв'язок втрачений", + "Connections": "З'єднання", + "ConnectSettings": "Налаштування підключення", + "CouldNotConnectSignalR": "Не вдалося підключитися до SignalR, інтерфейс користувача не оновиться", + "Custom": "Настроюваний", + "CustomFilters": "Користувацькі фільтри", + "Database": "База даних", + "Date": "Дата", + "Dates": "Дати", + "DBMigration": "Міграція БД", + "DeleteBackup": "Видалити резервну копію", + "DeleteBackupMessageText": "Ви впевнені, що хочете видалити резервну копію '{0}'?", + "DeleteDownloadClient": "Видалити клієнт завантаження", + "DeleteDownloadClientMessageText": "Ви впевнені, що хочете видалити клієнт завантаження '{0}'?", + "ApplyTagsHelpTexts3": "Видалити: видалити введені теги", + "ApplyTagsHelpTexts4": "Замінити: Змінити наявні теги на введені теги (залишіть порожнім, щоб очистити всі теги)", + "AreYouSureYouWantToResetYourAPIKey": "Ви впевнені, що хочете скинути свій ключ API?", + "Authentication": "Аутентифікація", + "Automatic": "Автоматичний", + "AutomaticSearch": "Автоматичний пошук", + "Backup": "Резервне копіювання", + "BackupIntervalHelpText": "Інтервал між автоматичним резервним копіюванням", + "Backups": "Резервні копії", + "BeforeUpdate": "Перед оновленням", + "BindAddress": "Прив'язувати адресу", + "Branch": "Гілка", + "BypassProxyForLocalAddresses": "Обійти проксі для локальних адрес", + "Cancel": "Скасувати", + "CertificateValidation": "Перевірка сертифіката", + "ChangeHasNotBeenSavedYet": "Зміни ще не набрали чинності", + "Clear": "Очистити", + "ClientPriority": "Пріоритет клієнта", + "CloneProfile": "Клонувати профіль", + "Close": "Закрити", + "CloseCurrentModal": "Закрити поточне вікно", + "Columns": "Колонки", + "ApplyTagsHelpTexts1": "Як застосувати теги до вибраних фільмів", + "ApplyTagsHelpTexts2": "Додати: додати теги до наявного списку тегів", + "AuthenticationMethodHelpText": "Для доступу до Radarr потрібні ім’я користувача та пароль", + "BackupFolderHelpText": "Відносні шляхи будуть у каталозі AppData Radarr", + "BindAddressHelpText": "Дійсна адреса IPv4 або '*' для всіх інтерфейсів", + "BranchUpdate": "Гілка для оновлення Radarr", + "AllIndexersHiddenDueToFilter": "Всі фільми заховані відповідно до фільтра.", + "AnalyticsEnabledHelpText": "Надсилайте анонімну інформацію про використання та помилки на сервери Radarr. Це включає інформацію про ваш веб-переглядач, які сторінки Radarr WebUI ви використовуєте, звіти про помилки, а також версію ОС і часу виконання. Ми будемо використовувати цю інформацію, щоб визначити пріоритети функцій і виправлення помилок.", + "ConnectionLostAutomaticMessage": "Radarr спробує підключитися автоматично, або ви можете натиснути перезавантажити нижче.", + "ConnectionLostMessage": "Radarr втратив зв’язок із бекендом, і його потрібно перезавантажити, щоб відновити функціональність.", + "Delete": "Видалити", + "DeleteApplicationMessageText": "Ви впевнені, що хочете видалити клієнт завантаження '{0}'?", + "DeleteTagMessageText": "Ви впевнені, що хочете видалити тег {0} ?", + "DeleteIndexerProxyMessageText": "Ви впевнені, що хочете видалити тег {0} ?", + "DeleteNotificationMessageText": "Ви впевнені, що хочете видалити клієнт завантаження '{0}'?" +} diff --git a/src/NzbDrone.Core/Localization/Core/vi.json b/src/NzbDrone.Core/Localization/Core/vi.json index e0372485d..d2621cdf7 100644 --- a/src/NzbDrone.Core/Localization/Core/vi.json +++ b/src/NzbDrone.Core/Localization/Core/vi.json @@ -323,5 +323,13 @@ "OnHealthIssue": "Về vấn đề sức khỏe", "Filters": "Bộ lọc", "OnGrab": "Trên Grab", - "TestAllIndexers": "Kiểm tra tất cả các chỉ mục" + "TestAllIndexers": "Kiểm tra tất cả các chỉ mục", + "ConnectionLostMessage": "Whisparr đã mất kết nối với phần phụ trợ và sẽ cần được tải lại để khôi phục chức năng.", + "GrabReleases": "Lấy bản phát hành", + "Link": "Liên kết", + "No": "Không", + "MappedDrivesRunningAsService": "Các ổ đĩa mạng được ánh xạ không khả dụng khi chạy dưới dạng Dịch vụ Windows. Vui lòng xem Câu hỏi thường gặp để biết thêm thông tin", + "UnableToLoadIndexers": "Không thể tải Trình chỉ mục", + "Yes": "Đúng", + "NetCore": ".NET Core" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index 96db6ba5e..913e8209b 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -272,7 +272,7 @@ "Wiki": "Wiki", "Yesterday": "昨天", "Torrent": "Torrents", - "Torrents": "Torrents", + "Torrents": "种子", "Type": "类型", "UnableToLoadNotifications": "无法加载通知连接", "RefreshMovie": "刷新影片", @@ -377,15 +377,15 @@ "Notifications": "通知", "Notification": "通知", "NoSearchResultsFound": "无搜索结果,请在下面尝试新的搜索。", - "IndexerVipCheckExpiringClientMessage": "搜刮器VIP特权即将过期:{0}", - "IndexerVipCheckExpiredClientMessage": "搜刮器VIP特权已过期:{0}", + "IndexerVipCheckExpiringClientMessage": "索引器VIP特权即将过期:{0}", + "IndexerVipCheckExpiredClientMessage": "索引器VIP特权已过期:{0}", "IndexerProxy": "搜刮器代理", "IndexerProxies": "搜刮器代理", "DeleteIndexerProxy": "删除搜刮器代理", "AddIndexerProxy": "添加搜刮器代理", "AppSettingsSummary": "配置Prowlarr与PVR程序交互方式的应用和设置", - "SyncLevelFull": "完全同步:将保持此应用程序完全同步。当在Prowlarr中所做的更改将同步到与此关联的应用程序。任何关联应用上的更改都将在下次同步时被Prowlarr覆盖。", - "SyncLevelAddRemove": "仅添加和删除:当它从 Prowlarr 添加或删除时,它将更新与此关联的应用程序。", + "SyncLevelFull": "完全同步:将保持此应用的索引器完全同步。当在Prowlarr中所做的更改将同步到与此关联的应用程序。任何关联应用上的更改都将在下次同步时被Prowlarr覆盖。", + "SyncLevelAddRemove": "仅添加和删除:当索引器从 Prowlarr 添加或删除时,它将更新与此关联的应用程序。", "SyncAppIndexers": "同步应用索引", "Stats": "统计数据", "SettingsSqlLoggingHelpText": "记录来自Prowlarr的所有SQL查询", @@ -395,7 +395,7 @@ "SettingsIndexerLoggingHelpText": "记录额外的搜刮器数据,包括响应", "SettingsFilterSentryEventsHelpText": "过滤已知的用户错误事件,不让其作为分析报告发送", "RedirectHelpText": "重定向搜刮器的传入下载请求并直接传递抓取,而不是通过Prowlarr代理请求搜刮器", - "IndexerTagsHelpText": "使用标签来指定默认客户端、搜刮器代理或仅群组搜刮器。", + "IndexerTagsHelpText": "‎使用标签‎‎指定‎‎索引器‎‎代理或仅用于你组织的‎‎索引器.", "IndexerSettingsSummary": "配置全局索引器设置,包括代理。", "HistoryCleanupDaysHelpTextWarning": "回收站中的文件在超出选择的天数后会被自动清理", "UserAgentProvidedByTheAppThatCalledTheAPI": "由调用API的应用程序提供的User-Agent", @@ -423,5 +423,26 @@ "Proxies": "代理", "SearchType": "搜索类型", "TvSearch": "搜索剧集", - "UnableToLoadApplicationList": "123" + "UnableToLoadApplicationList": "123", + "BookSearchTypes": "搜索图书类型", + "IndexerDetails": "‎索引器‎‎详细信息‎", + "IndexerName": "‎索引‎‎名字‎", + "IndexerSite": "‎索引‎‎网站‎", + "MovieSearchTypes": "‎影片‎‎搜索‎‎类型‎", + "MusicSearchTypes": "‎音乐‎‎搜索‎‎类型‎", + "NotSupported": "‎不支持‎", + "RawSearchSupported": "‎支持原始‎‎搜索‎", + "SearchCapabilities": "‎搜索‎‎能力‎", + "SemiPrivate": "‎半私有‎", + "TVSearchTypes": "‎电视‎‎搜索‎‎类型‎", + "Url": "Url", + "Website": "‎网站‎", + "GrabReleases": "抓取版本", + "Link": "链接", + "MappedDrivesRunningAsService": "映射的网络驱动器在作为Windows服务运行时不可用。请参阅常见问题解答了解更多信息", + "No": "否", + "Yes": "是", + "Application": "程序", + "SearchTypes": "搜索类型", + "UnableToLoadIndexers": "无法加载搜刮器" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_Hans.json b/src/NzbDrone.Core/Localization/Core/zh_Hans.json index fd0464c12..ed82cb65a 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_Hans.json +++ b/src/NzbDrone.Core/Localization/Core/zh_Hans.json @@ -5,5 +5,41 @@ "About": "关于", "Analytics": "分析", "AddIndexer": "添加索引器", - "ApiKey": "API密钥" + "ApiKey": "API密钥", + "AddingTag": "添加标签", + "AddAppProfile": "‎添加应用‎‎同步‎‎配置文件‎", + "AddNewIndexer": "添加新的索引器", + "AddRemoveOnly": "仅读写", + "AddIndexerProxy": "添加索引器代理", + "Apply": "应用", + "AddDownloadClientToProwlarr": "允许Prowlarr在执行手动‎‎搜索‎‎时直接从 ‎‎UI‎‎ 发送版本添加一个下载客户端", + "AddedToDownloadClient": "‎已添加到‎‎客户端‎‎的版本‎", + "ApplyTagsHelpTexts1": "‎如何将标记‎‎应用于‎‎选定的‎‎索引器‎", + "AppProfileInUse": "‎正在使用中的应用配置文件‎", + "Apps": "‎应用程序‎", + "AppSettingsSummary": "‎用于‎‎配置 ‎‎Prowlarr‎‎ 如何与您的 PVR 程序交互的应用程序和‎‎设置‎", + "AreYouSureYouWantToResetYourAPIKey": "你‎是否确实要重置 ‎‎API‎‎ 密钥‎‎‎?", + "Auth": "‎认证‎", + "Age": "年龄", + "All": "全部", + "AllIndexersHiddenDueToFilter": "所有‎‎索引器‎‎都处于隐藏状态,‎由于应用了‎‎筛选器‎‎。‎", + "AnalyticsEnabledHelpText": "‎将匿名使用情况和错误‎‎信息‎‎发送到‎‎Prowlarr‎‎的服务器。这包括有关您的‎‎浏览器中的‎‎Prowlarr‎‎ ‎‎WebUI‎‎页面,错误‎‎报告‎‎以及‎‎操作系统‎‎和‎‎运行时‎‎版本。我们将使用‎‎此信息‎‎来确定功能和‎‎错误‎‎修复的优先级。‎", + "AppDataDirectory": "‎应用程序数据‎‎目录‎", + "AppDataLocationHealthCheckMessage": "‎无法进行更新以防止在‎‎更新‎‎时删除‎‎应用程序数据‎", + "Applications": "‎应用‎", + "ApplicationStatusCheckAllClientMessage": "‎所有‎‎应用程序‎‎都因故障而不可用‎", + "ApplicationStatusCheckSingleClientMessage": "‎应用程序‎‎因故障而不可用:{0}‎", + "ApplyTags": "‎应用‎‎标签‎", + "AppProfile": "‎应用配置文件‎", + "AcceptConfirmationModal": "‎接受默认模式‎", + "Actions": "行为", + "AddToDownloadClient": "‎添加‎‎版本以‎‎下载‎‎客户端‎", + "Application": "‎应用‎", + "ApplyTagsHelpTexts2": "‎添加‎‎:将标签‎‎添加到‎‎现有的标签‎‎列表中‎", + "ApplyTagsHelpTexts3": "‎移除‎‎:‎‎移除‎‎输入的标签‎", + "ApplyTagsHelpTexts4": "‎替换‎‎:‎‎将标记替换为‎‎输入的标记(不输入任何标记以‎‎清除‎‎所有标记)‎", + "AppProfileDeleteConfirm": "你‎是否确实要‎‎删除‎‎{0}?‎", + "AppProfiles": "‎应用配置文件‎", + "AppProfileSelectHelpText": "‎应用程序配置文件用于控制应用程序‎‎同步‎‎时‎‎的 RSS‎‎、自动‎‎搜索‎‎和‎‎交互式‎‎搜索‎‎设置‎", + "AudioSearch": "‎音频‎‎搜索‎" } From d11e043270706ee32d5381bce64544401a3bb204 Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Sat, 16 Apr 2022 20:37:39 +0000 Subject: [PATCH 0440/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index 35a0c0207..0c9106668 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -4544,6 +4544,10 @@ "type": { "$ref": "#/components/schemas/BackupType" }, + "size": { + "type": "integer", + "format": "int64" + }, "time": { "type": "string", "format": "date-time" @@ -4792,10 +4796,6 @@ "id": { "type": "integer", "format": "int32" - }, - "downloadClientWorkingFolders": { - "type": "string", - "nullable": true } }, "additionalProperties": false @@ -6298,10 +6298,6 @@ "enableColorImpairedMode": { "type": "boolean" }, - "movieInfoLanguage": { - "type": "integer", - "format": "int32" - }, "uiLanguage": { "type": "integer", "format": "int32" From 20cc6e3bfb7d0b7faf1b6f8af3342bd3e36abfc3 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 16 Apr 2022 17:44:59 -0500 Subject: [PATCH 0441/2320] New: SceneHD Indexer --- .../Indexers/Definitions/SceneHD.cs | 266 ++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 src/NzbDrone.Core/Indexers/Definitions/SceneHD.cs diff --git a/src/NzbDrone.Core/Indexers/Definitions/SceneHD.cs b/src/NzbDrone.Core/Indexers/Definitions/SceneHD.cs new file mode 100644 index 000000000..273884a69 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/SceneHD.cs @@ -0,0 +1,266 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Globalization; +using System.Linq; +using System.Text; +using FluentValidation; +using Newtonsoft.Json.Linq; +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Indexers.Definitions +{ + public class SceneHD : TorrentIndexerBase<SceneHDSettings> + { + public override string Name => "SceneHD"; + public override string[] IndexerUrls => new[] { "https://scenehd.org/" }; + public override string Description => "SceneHD is Private site for HD TV / MOVIES"; + public override string Language => "en-US"; + public override Encoding Encoding => Encoding.UTF8; + public override DownloadProtocol Protocol => DownloadProtocol.Torrent; + public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + public override IndexerCapabilities Capabilities => SetCapabilities(); + + public SceneHD(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) + { + } + + public override IIndexerRequestGenerator GetRequestGenerator() + { + return new SceneHDRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; + } + + public override IParseIndexerResponse GetParser() + { + return new SceneHDParser(Settings, Capabilities.Categories); + } + + protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) + { + return false; + } + + private IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities + { + TvSearchParams = new List<TvSearchParam> + { + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep + }, + MovieSearchParams = new List<MovieSearchParam> + { + MovieSearchParam.Q, MovieSearchParam.ImdbId + }, + MusicSearchParams = new List<MusicSearchParam> + { + MusicSearchParam.Q + } + }; + + caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.MoviesUHD, "Movie/2160"); + caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesHD, "Movie/1080"); + caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.MoviesHD, "Movie/720"); + caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.MoviesBluRay, "Movie/BD5/9"); + caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.TVUHD, "TV/2160"); + caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.TVHD, "TV/1080"); + caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.TVHD, "TV/720"); + caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.MoviesBluRay, "Bluray/Complete"); + caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.XXX, "XXX"); + caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.MoviesOther, "Subpacks"); + caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.AudioVideo, "MVID"); + caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.Other, "Other"); + + return caps; + } + } + + public class SceneHDRequestGenerator : IIndexerRequestGenerator + { + public SceneHDSettings Settings { get; set; } + public IndexerCapabilities Capabilities { get; set; } + public string BaseUrl { get; set; } + + public SceneHDRequestGenerator() + { + } + + private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null) + { + var search = new[] { imdbId, term }; + + var qc = new NameValueCollection + { + { "api", "" }, + { "passkey", Settings.Passkey }, + { "search", string.Join(" ", search.Where(s => s.IsNotNullOrWhiteSpace())) } + }; + + foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories)) + { + qc.Add("categories[" + cat + "]", "1"); + } + + var searchUrl = string.Format("{0}/browse.php?{1}", Settings.BaseUrl.TrimEnd('/'), qc.GetQueryString()); + + var request = new IndexerRequest(searchUrl, HttpAccept.Json); + + yield return request; + } + + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public Func<IDictionary<string, string>> GetCookies { get; set; } + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + } + + public class SceneHDParser : IParseIndexerResponse + { + private readonly SceneHDSettings _settings; + private readonly IndexerCapabilitiesCategories _categories; + + public SceneHDParser(SceneHDSettings settings, IndexerCapabilitiesCategories categories) + { + _settings = settings; + _categories = categories; + } + + public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) + { + var torrentInfos = new List<ReleaseInfo>(); + + var detailsUrl = _settings.BaseUrl + "details.php?"; + var downloadUrl = _settings.BaseUrl + "download.php?"; + + if (indexerResponse.Content?.Contains("User not found or passkey not set") == true) + { + throw new IndexerAuthException("The passkey is invalid. Check the indexer configuration."); + } + + var jsonContent = JArray.Parse(indexerResponse.Content); + + foreach (var item in jsonContent) + { + var title = item.Value<string>("name"); + + var id = item.Value<long>("id"); + var details = new Uri(detailsUrl + "id=" + id).AbsoluteUri; + var link = new Uri(downloadUrl + "id=" + id + "&passkey=" + _settings.Passkey).AbsoluteUri; + var publishDate = DateTime.ParseExact(item.Value<string>("added"), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + var dlVolumeFactor = item.Value<int>("is_freeleech") == 1 ? 0 : 1; + + var release = new TorrentInfo + { + Title = title, + DownloadUrl = link, + InfoUrl = details, + Guid = details, + Categories = _categories.MapTrackerCatToNewznab(item.Value<string>("category")), + PublishDate = publishDate, + Size = item.Value<long>("size"), + Grabs = item.Value<int>("times_completed"), + Files = item.Value<int>("numfiles"), + Seeders = item.Value<int>("seeders"), + Peers = item.Value<int>("leechers") + item.Value<int>("seeders"), + ImdbId = ParseUtil.GetImdbID(item.Value<string>("imdbid")) ?? 0, + MinimumRatio = 1, + MinimumSeedTime = 0, + DownloadVolumeFactor = dlVolumeFactor, + UploadVolumeFactor = 1 + }; + + torrentInfos.Add(release); + } + + return torrentInfos.ToArray(); + } + + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + } + + public class SceneHDSettingsValidator : AbstractValidator<SceneHDSettings> + { + public SceneHDSettingsValidator() + { + RuleFor(c => c.Passkey).NotEmpty().Length(32); + } + } + + public class SceneHDSettings : IIndexerSettings + { + private static readonly SceneHDSettingsValidator Validator = new SceneHDSettingsValidator(); + + public SceneHDSettings() + { + Passkey = ""; + } + + [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] + public string BaseUrl { get; set; } + + [FieldDefinition(2, Label = "Passkey", Advanced = false, HelpText = "Site Passkey")] + public string Passkey { get; set; } + + [FieldDefinition(3)] + public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} From 9d3ee4af6d19776ba25e2da17707d5c23829ce95 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 2 Apr 2022 17:12:15 -0500 Subject: [PATCH 0442/2320] Fixed: (MoreThanTV) Better Response Cleansing Fixes #928 --- .../InstrumentationTests/CleanseLogMessageFixture.cs | 6 +++++- src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs index 1f098dee0..d26e4e0d9 100644 --- a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs +++ b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs @@ -25,7 +25,7 @@ namespace NzbDrone.Common.Test.InstrumentationTests [TestCase(@"Req: [POST] https://www3.yggtorrent.nz/user/login: id=mySecret&pass=mySecret&ci_csrf_token=2b51db35e1912ffc138825a12b9933d2")] [TestCase(@"https://torrentseeds.org/api/torrents/filter?api_token=2b51db35e1912ffc138825a12b9933d2&name=&sortField=created_at&sortDirection=desc&perPage=100&page=1")] - //Indexer Responses + // Indexer and Download Client Responses // avistaz response [TestCase(@"""download"":""https:\/\/avistaz.to\/rss\/download\/2b51db35e1910123321025a12b9933d2\/tb51db35e1910123321025a12b9933d2.torrent"",")] @@ -46,6 +46,10 @@ namespace NzbDrone.Common.Test.InstrumentationTests [TestCase(@"{ ""Name"" : ""ControlUsername"", ""Value"" : ""mySecret"" }, { ""Name"" : ""ControlPassword"", ""Value"" : ""mySecret"" }, ")] [TestCase(@"{ ""Name"" : ""Server1.Username"", ""Value"" : ""mySecret"" }, { ""Name"" : ""Server1.Password"", ""Value"" : ""mySecret"" }, ")] + // MTV + [TestCase(@"<link rel=""alternate"" type=""application/rss+xml"" href=""/feeds.php?feed=torrents_notify_2b51db35e1910123321025a12b9933d2&user=(removed)&auth=(removed)&passkey=(removed)&authkey=(removed) title=""MoreThanTV - P.T.N."" />")] + [TestCase(@"href=""/torrents.php?action=download&id=(removed)&authkey=(removed)&torrent_pass=2b51db35e1910123321025a12b9933d2"" title=""Download Torrent""")] + // Sabnzbd [TestCase(@"http://127.0.0.1:1234/api/call?vv=1&apikey=mySecret")] [TestCase(@"http://127.0.0.1:1234/api/call?vv=1&ma_username=mySecret&ma_password=mySecret")] diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index 565ed4385..e9d726537 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -42,10 +42,10 @@ namespace NzbDrone.Common.Instrumentation // Deluge new Regex(@"auth.login\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase), - // BroadcastheNet + // BroadcastheNet (;torrent_pass|torrents_notify_ is for MTV) new Regex(@"""?method""?\s*:\s*""(getTorrents)"",\s*""?params""?\s*:\s*\[\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"getTorrents\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase), - new Regex(@"(?<=\?|&)(authkey|torrent_pass)=(?<secret>[^&=]+?)(?=""|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"(?<=\?|&|;|=)(authkey|torrent_pass|torrents_notify)[_=](?<secret>[^&=]+?)(?=""|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), // Plex new Regex(@"(?<=\?|&)(X-Plex-Client-Identifier|X-Plex-Token)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), From f9bd842d41da5972a1bd7a51e71cc4c66ae2a9bc Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sun, 24 Apr 2022 07:36:51 +0000 Subject: [PATCH 0443/2320] Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 100.0% (446 of 446 strings) Translated using Weblate (Dutch) Currently translated at 91.9% (410 of 446 strings) Translated using Weblate (Dutch) Currently translated at 91.4% (408 of 446 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 15.2% (68 of 446 strings) Co-authored-by: M1C <webnar@gmail.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: lhquark <lhquark@gmail.com> Co-authored-by: marcosteam <wdy71608161@gmail.com> Co-authored-by: minermartijn <minermartijn@gmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_Hans/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/nl.json | 9 ++++-- .../Localization/Core/zh_CN.json | 4 +-- .../Localization/Core/zh_Hans.json | 30 +++++++++++++++++-- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/nl.json b/src/NzbDrone.Core/Localization/Core/nl.json index 667be8413..8c0e5f8aa 100644 --- a/src/NzbDrone.Core/Localization/Core/nl.json +++ b/src/NzbDrone.Core/Localization/Core/nl.json @@ -50,7 +50,7 @@ "Logging": "Logbeheer", "LogFiles": "Logbestanden", "Language": "Taal", - "ShowAdvanced": "Toon Gevorderd", + "ShowAdvanced": "Toon Geavanceerd", "UpdateCheckUINotWritableMessage": "Kan de update niet installeren omdat de UI map '{0}' niet schrijfbaar is voor de gebruiker '{1}'.", "UpdateCheckStartupTranslocationMessage": "Kan de update niet installeren omdat de map '{0}' zich in een 'App Translocation' map bevindt.", "UpdateCheckStartupNotWritableMessage": "Kan de update niet installeren omdat de map '{0}' niet schrijfbaar is voor de gebruiker '{1}'.", @@ -401,7 +401,7 @@ "HistoryCleanupDaysHelpTextWarning": "Bestanden in de prullenbak ouder dan het geselecteerde aantal dagen zullen automatisch opgeschoond worden", "OnGrab": "Bij Ophalen", "OnHealthIssue": "Bij Gezondheidsprobleem", - "Filters": "Filter", + "Filters": "Filters", "TestAllIndexers": "Test Alle Indexeerders", "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent geleverd door de app die de API heeft aangeroepen", "Application": "Applicaties", @@ -410,5 +410,8 @@ "No": "Nee", "UnableToLoadIndexers": "Indexeerders kunnen niet worden geladen", "GrabReleases": "Uitgave Ophalen", - "Yes": "Ja" + "Yes": "Ja", + "OnApplicationUpdateHelpText": "Bij applicatie update", + "Database": "Databasis", + "OnApplicationUpdate": "Bij applicatie update" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index 913e8209b..ce1650b89 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -413,8 +413,8 @@ "IndexerInfo": "索引器信息", "IndexerNoDefCheckMessage": "索引器没有定义,将无法工作: {0}. 请删除或重新添加到Prowlarr", "MovieSearch": "搜索电影", - "OnApplicationUpdate": "应用更新中", - "OnApplicationUpdateHelpText": "应用更新中,请耐心等待", + "OnApplicationUpdate": "程序更新时", + "OnApplicationUpdateHelpText": "在程序更新时", "Private": "私有", "Public": "公开", "QueryOptions": "查询选项", diff --git a/src/NzbDrone.Core/Localization/Core/zh_Hans.json b/src/NzbDrone.Core/Localization/Core/zh_Hans.json index ed82cb65a..24e95b4dd 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_Hans.json +++ b/src/NzbDrone.Core/Localization/Core/zh_Hans.json @@ -12,7 +12,7 @@ "AddRemoveOnly": "仅读写", "AddIndexerProxy": "添加索引器代理", "Apply": "应用", - "AddDownloadClientToProwlarr": "允许Prowlarr在执行手动‎‎搜索‎‎时直接从 ‎‎UI‎‎ 发送版本添加一个下载客户端", + "AddDownloadClientToProwlarr": "添加一个支持 Prowlarr 在执行手动‎‎搜索‎‎时发送资源的下载客户端", "AddedToDownloadClient": "‎已添加到‎‎客户端‎‎的版本‎", "ApplyTagsHelpTexts1": "‎如何将标记‎‎应用于‎‎选定的‎‎索引器‎", "AppProfileInUse": "‎正在使用中的应用配置文件‎", @@ -41,5 +41,31 @@ "AppProfileDeleteConfirm": "你‎是否确实要‎‎删除‎‎{0}?‎", "AppProfiles": "‎应用配置文件‎", "AppProfileSelectHelpText": "‎应用程序配置文件用于控制应用程序‎‎同步‎‎时‎‎的 RSS‎‎、自动‎‎搜索‎‎和‎‎交互式‎‎搜索‎‎设置‎", - "AudioSearch": "‎音频‎‎搜索‎" + "AudioSearch": "‎音频‎‎搜索‎", + "Authentication": "认证", + "AuthenticationMethodHelpText": "访问 Prowlarr 时需要提供用户名和密码", + "Automatic": "自动化", + "AutomaticSearch": "自动搜索", + "Backup": "备份", + "BackupIntervalHelpText": "自动备份时间间隔", + "Clear": "清除", + "Categories": "目录", + "BackupNow": "立即备份", + "BackupRetentionHelpText": "超过保留时间的自动备份将被自动清除", + "Backups": "备份", + "BindAddressHelpText": "填入有效 IP 地址或使用 '*' 接受所有连接", + "BookSearch": "图书搜索", + "BranchUpdate": "Prowlarr 更新时使用的 Branch", + "Branch": "", + "CertificateValidationHelpText": "设置 HTTPS 认证等级", + "CertificateValidation": "证书认证", + "Category": "目录", + "CancelPendingTask": "取消这个进行的任务?", + "Cancel": "取消", + "BypassProxyForLocalAddresses": "不代理本地 IP 地址", + "BackupFolderHelpText": "Prowlarr 安装目录下的相对路径", + "BindAddress": "绑定地址", + "ChangeHasNotBeenSavedYet": "设置未保存", + "Close": "关闭", + "CloneProfile": "复制配置文件" } From 70fd9b4e302dbea7ec064eae9b3b3d32a31c58b4 Mon Sep 17 00:00:00 2001 From: David Newhall <david@sleepers.pro> Date: Sat, 30 Apr 2022 17:45:30 -0700 Subject: [PATCH 0444/2320] Typo for myanonamouse. --- src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs b/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs index 19876a71f..3af4df15a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs @@ -446,7 +446,7 @@ namespace NzbDrone.Core.Indexers.Definitions [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "Mam Id", HelpText = "Mam Session Id (Created Under Profile -> Security)")] + [FieldDefinition(2, Label = "Mam Id", HelpText = "Mam Session Id (Created Under Preferences -> Security)")] public string MamId { get; set; } [FieldDefinition(3, Type = FieldType.Checkbox, Label = "Exclude VIP", HelpText = "Exclude VIP Torrents from search results")] From 2820ef9375e632388c891832600ae7dca1123f4d Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 1 May 2022 15:39:35 -0500 Subject: [PATCH 0445/2320] Fixed: (BTN) Move to HTTPS Fixes #979 --- .../Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs b/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs index 183e3c00c..a7c9c00dd 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs @@ -19,7 +19,7 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet public override IndexerCapabilities Capabilities => SetCapabilities(); public override TimeSpan RateLimit => TimeSpan.FromSeconds(5); - public override string[] IndexerUrls => new string[] { "http://api.broadcasthe.net/" }; + public override string[] IndexerUrls => new string[] { "https://api.broadcasthe.net/" }; public override string Description => "BroadcasTheNet (BTN) is an invite-only torrent tracker focused on TV shows"; public BroadcastheNet(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) From 4002cb764b1892796f493fad531dd4bb6bcc7938 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 1 May 2022 16:41:48 -0500 Subject: [PATCH 0446/2320] New: Auto map known legacy BaseUrls for non-Cardigann --- src/NzbDrone.Core/Datastore/TableMapping.cs | 1 + .../Definitions/BroadcastheNet/BroadcastheNet.cs | 2 ++ .../Indexers/Definitions/Cardigann/Cardigann.cs | 1 + src/NzbDrone.Core/Indexers/HttpIndexerBase.cs | 1 + src/NzbDrone.Core/Indexers/IIndexer.cs | 1 + src/NzbDrone.Core/Indexers/IndexerBase.cs | 13 +++++++++++-- src/NzbDrone.Core/Indexers/IndexerDefinition.cs | 1 + src/NzbDrone.Core/Indexers/IndexerFactory.cs | 2 ++ src/Prowlarr.Api.V1/Indexers/IndexerResource.cs | 2 ++ 9 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index 85ab151de..126c02740 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -50,6 +50,7 @@ namespace NzbDrone.Core.Datastore .Ignore(i => i.Language) .Ignore(i => i.Encoding) .Ignore(i => i.IndexerUrls) + .Ignore(i => i.LegacyUrls) .Ignore(i => i.Protocol) .Ignore(i => i.Privacy) .Ignore(i => i.SupportsRss) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs b/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs index a7c9c00dd..45f036260 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNet.cs @@ -20,6 +20,8 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet public override TimeSpan RateLimit => TimeSpan.FromSeconds(5); public override string[] IndexerUrls => new string[] { "https://api.broadcasthe.net/" }; + public override string[] LegacyUrls => new string[] { "http://api.broadcasthe.net/" }; + public override string Description => "BroadcasTheNet (BTN) is an invite-only torrent tracker focused on TV shows"; public BroadcastheNet(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs index 6f4797c77..23285b6c3 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs @@ -126,6 +126,7 @@ namespace NzbDrone.Core.Indexers.Cardigann Description = definition.Description, Implementation = GetType().Name, IndexerUrls = definition.Links.ToArray(), + LegacyUrls = definition.Legacylinks.ToArray(), Settings = new CardigannSettings { DefinitionFile = definition.File }, Protocol = DownloadProtocol.Torrent, Privacy = definition.Type switch diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index f69755bc3..0e0d435fb 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -33,6 +33,7 @@ namespace NzbDrone.Core.Indexers public override Encoding Encoding => Encoding.UTF8; public override string Language => "en-US"; + public override string[] LegacyUrls => new string[] { }; public override bool FollowRedirect => false; public override IndexerCapabilities Capabilities { get; protected set; } diff --git a/src/NzbDrone.Core/Indexers/IIndexer.cs b/src/NzbDrone.Core/Indexers/IIndexer.cs index 1e02c896d..f2bf11c6e 100644 --- a/src/NzbDrone.Core/Indexers/IIndexer.cs +++ b/src/NzbDrone.Core/Indexers/IIndexer.cs @@ -14,6 +14,7 @@ namespace NzbDrone.Core.Indexers IndexerCapabilities Capabilities { get; } string[] IndexerUrls { get; } + string[] LegacyUrls { get; } string Description { get; } Encoding Encoding { get; } string Language { get; } diff --git a/src/NzbDrone.Core/Indexers/IndexerBase.cs b/src/NzbDrone.Core/Indexers/IndexerBase.cs index 9f29f8bdd..655f6e534 100644 --- a/src/NzbDrone.Core/Indexers/IndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/IndexerBase.cs @@ -22,6 +22,7 @@ namespace NzbDrone.Core.Indexers public abstract string Name { get; } public abstract string[] IndexerUrls { get; } + public abstract string[] LegacyUrls { get; } public abstract string Description { get; } public abstract Encoding Encoding { get; } public abstract string Language { get; } @@ -147,9 +148,17 @@ namespace NzbDrone.Core.Indexers protected TSettings GetDefaultBaseUrl(TSettings settings) { - if (settings.BaseUrl.IsNullOrWhiteSpace() && IndexerUrls.First().IsNotNullOrWhiteSpace()) + var defaultLink = IndexerUrls.FirstOrDefault(); + + if (settings.BaseUrl.IsNullOrWhiteSpace() && defaultLink.IsNotNullOrWhiteSpace()) { - settings.BaseUrl = IndexerUrls.First(); + settings.BaseUrl = defaultLink; + } + + if (settings.BaseUrl.IsNotNullOrWhiteSpace() && LegacyUrls.Contains(settings.BaseUrl)) + { + _logger.Debug(string.Format("Changing legacy site link from {0} to {1}", settings.BaseUrl, defaultLink)); + settings.BaseUrl = defaultLink; } return settings; diff --git a/src/NzbDrone.Core/Indexers/IndexerDefinition.cs b/src/NzbDrone.Core/Indexers/IndexerDefinition.cs index 597ac0d2e..4979bf32b 100644 --- a/src/NzbDrone.Core/Indexers/IndexerDefinition.cs +++ b/src/NzbDrone.Core/Indexers/IndexerDefinition.cs @@ -11,6 +11,7 @@ namespace NzbDrone.Core.Indexers public class IndexerDefinition : ProviderDefinition { public string[] IndexerUrls { get; set; } + public string[] LegacyUrls { get; set; } public string Description { get; set; } public Encoding Encoding { get; set; } public string Language { get; set; } diff --git a/src/NzbDrone.Core/Indexers/IndexerFactory.cs b/src/NzbDrone.Core/Indexers/IndexerFactory.cs index d08d57031..022b203b4 100644 --- a/src/NzbDrone.Core/Indexers/IndexerFactory.cs +++ b/src/NzbDrone.Core/Indexers/IndexerFactory.cs @@ -110,6 +110,7 @@ namespace NzbDrone.Core.Indexers } definition.IndexerUrls = defFile.Links.ToArray(); + definition.LegacyUrls = defFile.Legacylinks.ToArray(); definition.Description = defFile.Description; definition.Language = defFile.Language; definition.Encoding = Encoding.GetEncoding(defFile.Encoding); @@ -205,6 +206,7 @@ namespace NzbDrone.Core.Indexers if (definition.Implementation != typeof(Cardigann.Cardigann).Name) { definition.IndexerUrls = provider.IndexerUrls; + definition.LegacyUrls = provider.LegacyUrls; definition.Privacy = provider.Privacy; definition.Description = provider.Description; definition.Encoding = provider.Encoding; diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs b/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs index 4dc7cbb08..eb1e88c97 100644 --- a/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs +++ b/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs @@ -15,6 +15,7 @@ namespace Prowlarr.Api.V1.Indexers public class IndexerResource : ProviderResource<IndexerResource> { public string[] IndexerUrls { get; set; } + public string[] LegacyUrls { get; set; } public string DefinitionName { get; set; } public string Description { get; set; } public string Language { get; set; } @@ -81,6 +82,7 @@ namespace Prowlarr.Api.V1.Indexers resource.InfoLink = string.Format("https://wiki.servarr.com/prowlarr/supported-indexers#{0}", infoLinkName.ToLower().Replace(' ', '-')); resource.AppProfileId = definition.AppProfileId; resource.IndexerUrls = definition.IndexerUrls; + resource.LegacyUrls = definition.LegacyUrls; resource.Description = definition.Description; resource.Language = definition.Language; resource.Encoding = definition.Encoding?.EncodingName ?? null; From 895c7c200b72a25d99cb7cdb78736a60691fb382 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 1 May 2022 17:53:10 -0500 Subject: [PATCH 0447/2320] Fixed: Default List for Cardigann LegacyLinks --- .../Indexers/Definitions/Cardigann/CardigannDefinition.cs | 5 +++++ .../Indexers/Definitions/Cardigann/CardigannMetaDef.cs | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs index 9b00b4043..72d15a16c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs @@ -29,6 +29,11 @@ namespace NzbDrone.Core.Indexers.Cardigann // Cardigann yaml classes public class CardigannDefinition { + public CardigannDefinition() + { + Legacylinks = new List<string>(); + } + public string Id { get; set; } public List<SettingsField> Settings { get; set; } public string Name { get; set; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannMetaDef.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannMetaDef.cs index 18d6ac4e3..32ca9ee67 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannMetaDef.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannMetaDef.cs @@ -4,6 +4,11 @@ namespace NzbDrone.Core.Indexers.Cardigann { public class CardigannMetaDefinition { + public CardigannMetaDefinition() + { + Legacylinks = new List<string>(); + } + public string Id { get; set; } public string File { get; set; } public string Name { get; set; } From 88ddb373cc67dfbcb15d309e7c64f76828a9fb3d Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Sun, 1 May 2022 22:57:39 +0000 Subject: [PATCH 0448/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index 0c9106668..7a131196e 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -5510,6 +5510,13 @@ }, "nullable": true }, + "legacyUrls": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, "definitionName": { "type": "string", "nullable": true From dc3fa51d8845ba46dda0f3ddebbf84a005c8b2e3 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 1 May 2022 21:01:51 -0500 Subject: [PATCH 0449/2320] Fixed: Prevent endless loop when calling IndexerUrls for Newznab Fixes #982 --- src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs | 5 +++++ src/NzbDrone.Core/Indexers/IndexerBase.cs | 5 ++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs index 045a4a7ef..00a2daec1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs @@ -57,6 +57,11 @@ namespace NzbDrone.Core.Indexers.Newznab return new string[] { Settings.BaseUrl }; } + protected override NewznabSettings GetDefaultBaseUrl(NewznabSettings settings) + { + return settings; + } + public IndexerCapabilities GetCapabilitiesFromSettings() { var caps = new IndexerCapabilities(); diff --git a/src/NzbDrone.Core/Indexers/IndexerBase.cs b/src/NzbDrone.Core/Indexers/IndexerBase.cs index 655f6e534..923a0598a 100644 --- a/src/NzbDrone.Core/Indexers/IndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/IndexerBase.cs @@ -146,7 +146,7 @@ namespace NzbDrone.Core.Indexers return result.DistinctBy(v => v.Guid).ToList(); } - protected TSettings GetDefaultBaseUrl(TSettings settings) + protected virtual TSettings GetDefaultBaseUrl(TSettings settings) { var defaultLink = IndexerUrls.FirstOrDefault(); @@ -154,8 +154,7 @@ namespace NzbDrone.Core.Indexers { settings.BaseUrl = defaultLink; } - - if (settings.BaseUrl.IsNotNullOrWhiteSpace() && LegacyUrls.Contains(settings.BaseUrl)) + else if (settings.BaseUrl.IsNotNullOrWhiteSpace() && LegacyUrls.Contains(settings.BaseUrl)) { _logger.Debug(string.Format("Changing legacy site link from {0} to {1}", settings.BaseUrl, defaultLink)); settings.BaseUrl = defaultLink; From b0376c07f592da1df83af6e37dbe6ffea2ad082c Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 1 May 2022 22:20:59 -0500 Subject: [PATCH 0450/2320] Fix some translations Fixes #975 --- src/NzbDrone.Core/Languages/Language.cs | 8 ++- .../Localization/Core/zh_Hans.json | 71 ------------------- src/NzbDrone.Core/Parser/IsoLanguages.cs | 10 ++- 3 files changed, 15 insertions(+), 74 deletions(-) delete mode 100644 src/NzbDrone.Core/Localization/Core/zh_Hans.json diff --git a/src/NzbDrone.Core/Languages/Language.cs b/src/NzbDrone.Core/Languages/Language.cs index 87de7e019..0265858e0 100644 --- a/src/NzbDrone.Core/Languages/Language.cs +++ b/src/NzbDrone.Core/Languages/Language.cs @@ -80,7 +80,7 @@ namespace NzbDrone.Core.Languages public static Language Dutch => new Language(7, "Dutch"); public static Language Japanese => new Language(8, "Japanese"); public static Language Icelandic => new Language(9, "Icelandic"); - public static Language Chinese => new Language(10, "Chinese"); + public static Language Chinese => new Language(10, "Chinese (Simplified)"); public static Language Russian => new Language(11, "Russian"); public static Language Polish => new Language(12, "Polish"); public static Language Vietnamese => new Language(13, "Vietnamese"); @@ -100,6 +100,12 @@ namespace NzbDrone.Core.Languages public static Language Romanian => new Language(27, "Romanian"); public static Language Thai => new Language(28, "Thai"); public static Language Bulgarian => new Language(29, "Bulgarian"); + public static Language PortugueseBR => new Language(30, "Portuguese (Brazil)"); + public static Language Arabic => new Language(31, "Arabic"); + public static Language Ukrainian => new Language(32, "Ukrainian"); + public static Language Persian => new Language(33, "Persian"); + public static Language Bengali => new Language(34, "Bengali"); + public static Language ChineseTW => new Language(35, "Chinese (Traditional)"); public static Language Any => new Language(-1, "Any"); public static Language Original => new Language(-2, "Original"); diff --git a/src/NzbDrone.Core/Localization/Core/zh_Hans.json b/src/NzbDrone.Core/Localization/Core/zh_Hans.json deleted file mode 100644 index 24e95b4dd..000000000 --- a/src/NzbDrone.Core/Localization/Core/zh_Hans.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "Added": "已添加", - "AddDownloadClient": "添加下载客户端", - "Add": "添加", - "About": "关于", - "Analytics": "分析", - "AddIndexer": "添加索引器", - "ApiKey": "API密钥", - "AddingTag": "添加标签", - "AddAppProfile": "‎添加应用‎‎同步‎‎配置文件‎", - "AddNewIndexer": "添加新的索引器", - "AddRemoveOnly": "仅读写", - "AddIndexerProxy": "添加索引器代理", - "Apply": "应用", - "AddDownloadClientToProwlarr": "添加一个支持 Prowlarr 在执行手动‎‎搜索‎‎时发送资源的下载客户端", - "AddedToDownloadClient": "‎已添加到‎‎客户端‎‎的版本‎", - "ApplyTagsHelpTexts1": "‎如何将标记‎‎应用于‎‎选定的‎‎索引器‎", - "AppProfileInUse": "‎正在使用中的应用配置文件‎", - "Apps": "‎应用程序‎", - "AppSettingsSummary": "‎用于‎‎配置 ‎‎Prowlarr‎‎ 如何与您的 PVR 程序交互的应用程序和‎‎设置‎", - "AreYouSureYouWantToResetYourAPIKey": "你‎是否确实要重置 ‎‎API‎‎ 密钥‎‎‎?", - "Auth": "‎认证‎", - "Age": "年龄", - "All": "全部", - "AllIndexersHiddenDueToFilter": "所有‎‎索引器‎‎都处于隐藏状态,‎由于应用了‎‎筛选器‎‎。‎", - "AnalyticsEnabledHelpText": "‎将匿名使用情况和错误‎‎信息‎‎发送到‎‎Prowlarr‎‎的服务器。这包括有关您的‎‎浏览器中的‎‎Prowlarr‎‎ ‎‎WebUI‎‎页面,错误‎‎报告‎‎以及‎‎操作系统‎‎和‎‎运行时‎‎版本。我们将使用‎‎此信息‎‎来确定功能和‎‎错误‎‎修复的优先级。‎", - "AppDataDirectory": "‎应用程序数据‎‎目录‎", - "AppDataLocationHealthCheckMessage": "‎无法进行更新以防止在‎‎更新‎‎时删除‎‎应用程序数据‎", - "Applications": "‎应用‎", - "ApplicationStatusCheckAllClientMessage": "‎所有‎‎应用程序‎‎都因故障而不可用‎", - "ApplicationStatusCheckSingleClientMessage": "‎应用程序‎‎因故障而不可用:{0}‎", - "ApplyTags": "‎应用‎‎标签‎", - "AppProfile": "‎应用配置文件‎", - "AcceptConfirmationModal": "‎接受默认模式‎", - "Actions": "行为", - "AddToDownloadClient": "‎添加‎‎版本以‎‎下载‎‎客户端‎", - "Application": "‎应用‎", - "ApplyTagsHelpTexts2": "‎添加‎‎:将标签‎‎添加到‎‎现有的标签‎‎列表中‎", - "ApplyTagsHelpTexts3": "‎移除‎‎:‎‎移除‎‎输入的标签‎", - "ApplyTagsHelpTexts4": "‎替换‎‎:‎‎将标记替换为‎‎输入的标记(不输入任何标记以‎‎清除‎‎所有标记)‎", - "AppProfileDeleteConfirm": "你‎是否确实要‎‎删除‎‎{0}?‎", - "AppProfiles": "‎应用配置文件‎", - "AppProfileSelectHelpText": "‎应用程序配置文件用于控制应用程序‎‎同步‎‎时‎‎的 RSS‎‎、自动‎‎搜索‎‎和‎‎交互式‎‎搜索‎‎设置‎", - "AudioSearch": "‎音频‎‎搜索‎", - "Authentication": "认证", - "AuthenticationMethodHelpText": "访问 Prowlarr 时需要提供用户名和密码", - "Automatic": "自动化", - "AutomaticSearch": "自动搜索", - "Backup": "备份", - "BackupIntervalHelpText": "自动备份时间间隔", - "Clear": "清除", - "Categories": "目录", - "BackupNow": "立即备份", - "BackupRetentionHelpText": "超过保留时间的自动备份将被自动清除", - "Backups": "备份", - "BindAddressHelpText": "填入有效 IP 地址或使用 '*' 接受所有连接", - "BookSearch": "图书搜索", - "BranchUpdate": "Prowlarr 更新时使用的 Branch", - "Branch": "", - "CertificateValidationHelpText": "设置 HTTPS 认证等级", - "CertificateValidation": "证书认证", - "Category": "目录", - "CancelPendingTask": "取消这个进行的任务?", - "Cancel": "取消", - "BypassProxyForLocalAddresses": "不代理本地 IP 地址", - "BackupFolderHelpText": "Prowlarr 安装目录下的相对路径", - "BindAddress": "绑定地址", - "ChangeHasNotBeenSavedYet": "设置未保存", - "Close": "关闭", - "CloneProfile": "复制配置文件" -} diff --git a/src/NzbDrone.Core/Parser/IsoLanguages.cs b/src/NzbDrone.Core/Parser/IsoLanguages.cs index ecd0d92b5..141075c31 100644 --- a/src/NzbDrone.Core/Parser/IsoLanguages.cs +++ b/src/NzbDrone.Core/Parser/IsoLanguages.cs @@ -17,7 +17,8 @@ namespace NzbDrone.Core.Parser new IsoLanguage("nl", "", "nld", "Dutch", Language.Dutch), new IsoLanguage("ja", "", "jpn", "Japanese", Language.Japanese), new IsoLanguage("is", "", "isl", "Icelandic", Language.Icelandic), - new IsoLanguage("zh", "", "zho", "Chinese", Language.Chinese), + new IsoLanguage("zh", "cn", "zho", "Chinese (Simplified)", Language.Chinese), + new IsoLanguage("zh", "tw", "zho", "Chinese (Traditional)", Language.ChineseTW), new IsoLanguage("ru", "", "rus", "Russian", Language.Russian), new IsoLanguage("pl", "", "pol", "Polish", Language.Polish), new IsoLanguage("vi", "", "vie", "Vietnamese", Language.Vietnamese), @@ -35,7 +36,12 @@ namespace NzbDrone.Core.Parser new IsoLanguage("hi", "", "hin", "Hindi", Language.Hindi), new IsoLanguage("th", "", "tha", "Thai", Language.Thai), new IsoLanguage("bg", "", "bul", "Bulgarian", Language.Bulgarian), - new IsoLanguage("ro", "", "ron", "Romanian", Language.Romanian) + new IsoLanguage("ro", "", "ron", "Romanian", Language.Romanian), + new IsoLanguage("pt", "br", "", "Portuguese (Brazil)", Language.PortugueseBR), + new IsoLanguage("ar", "", "ara", "Arabic", Language.Arabic), + new IsoLanguage("uk", "", "ukr", "Ukrainian", Language.Ukrainian), + new IsoLanguage("fa", "", "fas", "Persian", Language.Persian), + new IsoLanguage("be", "", "ben", "Bengali", Language.Bengali) }; public static IsoLanguage Find(string isoCode) From bbc3e6df13e6ea4b477cb7043b4a2c2c2c2b72a4 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 2 May 2022 03:26:54 +0000 Subject: [PATCH 0451/2320] Deleted translation using Weblate (Chinese (Min Nan)) --- src/NzbDrone.Core/Localization/Core/nan.json | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/NzbDrone.Core/Localization/Core/nan.json diff --git a/src/NzbDrone.Core/Localization/Core/nan.json b/src/NzbDrone.Core/Localization/Core/nan.json deleted file mode 100644 index 0967ef424..000000000 --- a/src/NzbDrone.Core/Localization/Core/nan.json +++ /dev/null @@ -1 +0,0 @@ -{} From a0f7d5e30918854bb07625e9690613cbd288bb76 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 1 May 2022 23:02:30 -0500 Subject: [PATCH 0452/2320] Fixed: Prevent endless loop when calling IndexerUrls for Torznab --- src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs index a7a97ea8e..47d9584ff 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs @@ -56,6 +56,11 @@ namespace NzbDrone.Core.Indexers.Torznab return new string[] { Settings.BaseUrl }; } + protected override TorznabSettings GetDefaultBaseUrl(TorznabSettings settings) + { + return settings; + } + public IndexerCapabilities GetCapabilitiesFromSettings() { var caps = new IndexerCapabilities(); From d0803bc51bc8c1acddc930e1113c1e11f9fb9d6e Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 6 May 2022 08:38:38 -0500 Subject: [PATCH 0453/2320] Fixed: Correct User-Agent api logging --- src/Prowlarr.Http/Middleware/LoggingMiddleware.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Prowlarr.Http/Middleware/LoggingMiddleware.cs b/src/Prowlarr.Http/Middleware/LoggingMiddleware.cs index 19ea1124c..9ec733a39 100644 --- a/src/Prowlarr.Http/Middleware/LoggingMiddleware.cs +++ b/src/Prowlarr.Http/Middleware/LoggingMiddleware.cs @@ -79,13 +79,13 @@ namespace Prowlarr.Http.Middleware private static string GetOrigin(HttpContext context) { - if (context.Request.Headers["UserAgent"].ToString().IsNullOrWhiteSpace()) + if (context.Request.Headers["User-Agent"].ToString().IsNullOrWhiteSpace()) { return context.GetRemoteIP(); } else { - return $"{context.GetRemoteIP()} {context.Request.Headers["UserAgent"]}"; + return $"{context.GetRemoteIP()} {context.Request.Headers["User-Agent"]}"; } } } From 57996666a3119dede4254a1942240c60133a2b27 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sun, 8 May 2022 02:52:58 +0000 Subject: [PATCH 0454/2320] Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 100.0% (446 of 446 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 100.0% (446 of 446 strings) Translated using Weblate (Russian) Currently translated at 77.1% (344 of 446 strings) Translated using Weblate (Italian) Currently translated at 84.3% (376 of 446 strings) Translated using Weblate (Italian) Currently translated at 84.3% (376 of 446 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 100.0% (446 of 446 strings) Co-authored-by: Casselluu <jack10193@163.com> Co-authored-by: DarkFighterLuke <luca-consoli@live.it> Co-authored-by: Giorgio <sannagiorgio1997@gmail.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: ZakiZtraki <vovanjudo@gmail.com> Co-authored-by: lhquark <lhquark@gmail.com> Co-authored-by: wubinbin0403 <wubinbin0403@gmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/it/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ru/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/it.json | 96 ++++++++++++------- src/NzbDrone.Core/Localization/Core/ru.json | 9 +- .../Localization/Core/zh_CN.json | 8 +- 3 files changed, 72 insertions(+), 41 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/it.json b/src/NzbDrone.Core/Localization/Core/it.json index 19f52e8ce..4007fde2d 100644 --- a/src/NzbDrone.Core/Localization/Core/it.json +++ b/src/NzbDrone.Core/Localization/Core/it.json @@ -17,10 +17,10 @@ "Health": "Salute", "Grabbed": "Recuperato", "Clear": "Cancella", - "AppDataLocationHealthCheckMessage": "Non è possibile effettuare l'aggiornamento per evitare di cancellare AppData", - "Analytics": "Statistiche", + "AppDataLocationHealthCheckMessage": "L'aggiornamento non sarà possibile per evitare la cancellazione di AppData durante l'aggiornamento", + "Analytics": "Analitica", "Added": "Aggiunto", - "About": "Versione", + "About": "Informazioni", "Updates": "Aggiornamenti", "UpdateCheckUINotWritableMessage": "Impossibile installare l'aggiornamento perché l'utente '{1}' non ha i permessi di scrittura per la cartella di interfaccia '{0}'.", "UpdateCheckStartupNotWritableMessage": "Impossibile installare l'aggiornamento perché l'utente '{1}' non ha i permessi di scrittura per la cartella di avvio '{0}'.", @@ -76,10 +76,10 @@ "Dates": "Date", "Date": "Data", "CustomFilters": "Filtri Personalizzati", - "Connect": "Collega", + "Connect": "Notifiche", "Connections": "Collegamenti", - "ConnectSettingsSummary": "Notifiche, collegamenti a media server/player e script personalizzati", - "BackupNow": "Effettua ora il Backup", + "ConnectSettingsSummary": "Notifiche e script personalizzati", + "BackupNow": "Effettua il Backup adesso", "Backup": "Backup", "All": "Tutti", "Actions": "Azioni", @@ -87,27 +87,27 @@ "Close": "Chiudi", "CloneProfile": "Clona il Profilo", "ClientPriority": "Priorità del Client", - "ChangeHasNotBeenSavedYet": "Il cambiamento non è stato ancora salvato", - "CertificateValidationHelpText": "Cambiare il \"grado di severità\" della convalida del certificato HTTPS", + "ChangeHasNotBeenSavedYet": "Il cambiamento non è ancora stato ancora salvato", + "CertificateValidationHelpText": "Cambia quanto è rigorosa la convalida della certificazione HTTPS", "CertificateValidation": "Convalida del certificato", "Cancel": "Cancella", "BypassProxyForLocalAddresses": "Evita il Proxy per gli indirizzi locali", "Branch": "Ramo", "BindAddressHelpText": "Indirizzo IPV4 valido o '*' per tutte le interfacce", - "BindAddress": "Indirizzo per il collegamento", + "BindAddress": "Indirizzo di Bind", "Backups": "I Backup", "BackupRetentionHelpText": "I backup automatici più vecchi del periodo di conservazione verranno eliminati automaticamente", "BackupIntervalHelpText": "Intervallo tra i backup automatici", - "BackupFolderHelpText": "I percorsi relativi saranno sotto la directory AppData di Prowlarr", + "BackupFolderHelpText": "I percorsi relativi saranno nella directory AppData di Prowlarr", "Automatic": "Automatico", - "AuthenticationMethodHelpText": "Utilizza nome utente e password per accedere a Prowlarr", + "AuthenticationMethodHelpText": "Richiedi Nome Utente e Password per accedere a Prowlarr", "Authentication": "Autenticazione", "AreYouSureYouWantToResetYourAPIKey": "Sei sicuro di voler reimpostare la tua chiave API?", "ApplyTags": "Applica Etichette", "Apply": "Applica", "AppDataDirectory": "Cartella AppData", "ApiKey": "Chiave API", - "AnalyticsEnabledHelpText": "Inviare informazioni anonime sull'utilizzo e sugli errori ai server di Prowlarr. Ciò include informazioni sul tuo browser, come le pagine di Prowlarr che utilizzi, la segnalazione di errori e la versione del sistema operativo e del runtime. Utilizzeremo queste informazioni per dare priorità alle funzioni e alle correzioni di bug.", + "AnalyticsEnabledHelpText": "Invia informazioni anonime sull'uso e sugli errori ai server di Prowlarr. Questo include informazioni sul tuo browser, quali pagine della WebUI di Prowlarr utilizzi, la segnalazione di errori così come il sistema operativo e la versione di runtime. Useremo queste informazioni per dare priorità alle funzionalità e alle correzioni dei bug.", "Warn": "Attenzione", "Type": "Tipo", "Title": "Titolo", @@ -138,22 +138,22 @@ "DownloadClientSettings": "Impostazioni del client di download", "Docker": "Docker", "DeleteTag": "Cancella Tag", - "DeleteNotification": "Cancellare la notifica", - "DeleteDownloadClient": "Cancellare il client di download", - "DeleteBackup": "Cancellare il backup", - "DBMigration": "Migrazione del DataBase", - "ConnectSettings": "Impostazioni di connessione", + "DeleteNotification": "Cancella la notifica", + "DeleteDownloadClient": "Cancella il Client di Download", + "DeleteBackup": "Cancella Backup", + "DBMigration": "Migrazione DB", + "ConnectSettings": "Impostazioni di Connessione", "ConnectionLostMessage": "Prowlarr ha perso la connessione al backend e dovrà essere ricaricato per ripristinare la funzionalità.", - "ConnectionLostAutomaticMessage": "Prowlarr cercherà di connettersi automaticamente, oppure potete cliccare su ricarica qui sotto.", + "ConnectionLostAutomaticMessage": "Prowlarr cercherà di connettersi automaticamente, oppure clicca su ricarica qui sotto.", "ConnectionLost": "Connessione persa", "Component": "Componente", "Columns": "Colonne", "DeleteBackupMessageText": "Sei sicuro di voler cancellare il backup '{0}'?", "CancelPendingTask": "Sei sicuro di voler cancellare questa operazione in sospeso?", - "BranchUpdateMechanism": "Branch utilizzato dal sistema di aggiornamento esterno", - "BranchUpdate": "Branch da utilizzare per aggiornare Prowlarr", - "ApplyTagsHelpTexts2": "Aggiungi: Aggiungere i tag la lista esistente di tag", - "ApplyTagsHelpTexts1": "Come applicare i tag ai film selezionati", + "BranchUpdateMechanism": "Ramo utilizzato dal sistema di aggiornamento esterno", + "BranchUpdate": "Ramo da usare per aggiornare Prowlarr", + "ApplyTagsHelpTexts2": "Aggiungi: Aggiungere le etichette alla lista esistente di etichette", + "ApplyTagsHelpTexts1": "Come applicare etichette agli indexer selezionati", "AddingTag": "Aggiungi tag", "Password": "Password", "OnHealthIssueHelpText": "Quando c'è un problema", @@ -206,7 +206,7 @@ "Mode": "Modo", "Mechanism": "Meccanismo", "Manual": "Manuale", - "MaintenanceRelease": "Release di Manutenzione", + "MaintenanceRelease": "Release di Manutenzione: correzione di bug e altre miglioramenti. Vedi la storia dei Commit su Github per maggiori dettagli", "LogLevelTraceHelpTextWarning": "Il Trace Log dovrebbe essere abilitato solo temporaneamente", "LogLevel": "Livello di Log", "LaunchBrowserHelpText": " Apri un browser e vai all'homepage di Prowlarr all'avvio dell'app.", @@ -231,8 +231,8 @@ "DeleteNotificationMessageText": "Sei sicuro di voler eliminare la notifica '{0}'?", "DeleteDownloadClientMessageText": "Sei sicuro di voler eliminare il client di download '{0}'?", "BeforeUpdate": "Prima di aggiornare", - "ApplyTagsHelpTexts4": "Sostituire: sostituisci le tag con le tag inserite (non inserire nessuna tag per pulirle tutte)", - "ApplyTagsHelpTexts3": "Rimuovere: rimuovi le tag inserite", + "ApplyTagsHelpTexts4": "Sostituire: Sostituisce le etichette con quelle inserite (non inserire nessuna etichette per eliminarle tutte)", + "ApplyTagsHelpTexts3": "Rimuovere: rimuovi le etichette inserite", "Usenet": "Usenet", "Uptime": "Tempo di attività", "YesCancel": "Si, annulla", @@ -286,15 +286,15 @@ "IndexerPriority": "Priorità dell'indexer", "EditIndexer": "Edita Indexer", "Disabled": "Disabilitato", - "AutomaticSearch": "Ricerca automatica", + "AutomaticSearch": "Ricerca Automatica", "AddIndexer": "Aggiungi Indexer", "SaveSettings": "Salva impostazioni", "OpenThisModal": "Apri questa modalità", "MovieIndexScrollTop": "Elenco film: scorri in alto", "MovieIndexScrollBottom": "Elenco film: scorri in basso", "FocusSearchBox": "Attiva casella di ricerca", - "CloseCurrentModal": "Chiudi la modalità corrente", - "AcceptConfirmationModal": "Accetta modalità di conferma", + "CloseCurrentModal": "Chiudi la Modale Attuale", + "AcceptConfirmationModal": "Acetta Conferma Modale", "IndexerLongTermStatusCheckSingleClientMessage": "Alcuni indexer non disponibili da più di 6 ore a causa di errori: {0}", "IndexerLongTermStatusCheckAllClientMessage": "Nessun indexer è disponibile da più di 6 ore a causa di errori", "PrioritySettings": "Priorità", @@ -305,9 +305,9 @@ "EnableIndexer": "Abilita Indexer", "AddNewIndexer": "Aggiungi nuovo Indexer", "IndexerAuth": "Autenticazione Indexer", - "AddDownloadClient": "Aggiungi client di download", + "AddDownloadClient": "Aggiungi Client di Download", "Category": "Categoria", - "ClearHistory": "Pulisci cronologia", + "ClearHistory": "Cancella cronologia", "ClearHistoryMessageText": "Sei sicuro di voler cancellare tutta la cronologia di Prowlarr?", "Discord": "Discord", "Donations": "Donazioni", @@ -319,17 +319,17 @@ "NoLinks": "Nessun collegamento", "RSS": "RSS", "Wiki": "Wiki", - "AllIndexersHiddenDueToFilter": "Tutti i film sono nascosti a causa del filtro applicato.", - "DeleteApplicationMessageText": "Sei sicuro di voler eliminare la notifica '{0}'?", - "DeleteIndexerProxyMessageText": "Sei sicuro di voler eliminare la lista '{0}'?", + "AllIndexersHiddenDueToFilter": "Tutti gli indexer sono nascosti a causa del filtro applicato.", + "DeleteApplicationMessageText": "Sei sicuro di voler eliminare l'applicazione '{0}'?", + "DeleteIndexerProxyMessageText": "Sei sicuro di voler eliminare il proxy '{0}'?", "Presets": "Preset", "SearchIndexers": "Cerca Films", "UnableToAddANewIndexerProxyPleaseTryAgain": "Non riesco ad aggiungere un nuovo indexer, riprova.", "Yesterday": "Ieri", - "ApplicationStatusCheckSingleClientMessage": "Liste non disponibili a causa di errori: {0}", + "ApplicationStatusCheckSingleClientMessage": "Applicazioni non disponibili a causa di errori: {0}", "Today": "Oggi", "Tomorrow": "Domani", - "ApplicationStatusCheckAllClientMessage": "Tutte le liste non sono disponibili a causa di errori", + "ApplicationStatusCheckAllClientMessage": "Tutte le applicazioni non sono disponibili a causa di errori", "CouldNotConnectSignalR": "Non ho potuto connettermi a SignalR, la UI non si aggiornerà", "Custom": "Personalizzato", "FeatureRequests": "Richieste di funzionalità", @@ -355,5 +355,29 @@ "MappedDrivesRunningAsService": "I drive di rete mappati non sono disponibili eseguendo come servizio di Windows. Vedere le FAQ per maggiori informazioni", "No": "No", "UnableToLoadIndexers": "Non riesco a caricare l'indexer", - "Yes": "Si" + "Yes": "Si", + "AddIndexerProxy": "Aggiungi proxy dell'Indexer", + "AudioSearch": "Ricerca Audio", + "BookSearch": "Ricerca Libri", + "AddRemoveOnly": "Solo Aggiunta e Rimozione", + "AppProfileSelectHelpText": "I profili delle App sono utilizzati per controllare la sincronizzazione delle impostazioni RSS, Ricerca Automatica e Ricerca Interattiva", + "DeleteApplication": "Cancella Applicazione", + "DeleteAppProfile": "Cancella Profilo App", + "AddAppProfile": "Aggiungi Profilo di Personalizzazione dell'App", + "AddedToDownloadClient": "Release aggiunta al client", + "AddToDownloadClient": "Aggiungi release al client di download", + "Categories": "Categorie", + "Database": "Database", + "DeleteIndexerProxy": "Cancella il Proxy dell'Indice", + "Auth": "Auth", + "AddDownloadClientToProwlarr": "L'aggiunta di un client di download permette a Prowlarr di inviare la release direttamente dall'interfaccia utente mentre si fa una ricerca manuale.", + "Applications": "Applicazioni", + "AppProfileInUse": "Profilo App in Uso", + "Application": "Applicazione", + "BookSearchTypes": "Tipi di Ricerca Libri", + "AppProfile": "Profilo App", + "AppProfileDeleteConfirm": "Sicuro di voler eliminare {0}?", + "AppProfiles": "Profili delle App", + "AppSettingsSummary": "Applicazioni e impostazioni per configurare come Prowlarr interagisce con i tuoi programmi PVR", + "Apps": "Le App" } diff --git a/src/NzbDrone.Core/Localization/Core/ru.json b/src/NzbDrone.Core/Localization/Core/ru.json index b49a2165e..cd83c0537 100644 --- a/src/NzbDrone.Core/Localization/Core/ru.json +++ b/src/NzbDrone.Core/Localization/Core/ru.json @@ -335,5 +335,12 @@ "Link": "Ссылки", "MappedDrivesRunningAsService": "Подключённые сетевые диски недоступны, если программа запущена как сервис. Обратитесь в FAQ за дополнительной информацией", "No": "Нет", - "Yes": "Да" + "Yes": "Да", + "AddRemoveOnly": "Добавить и Удалить Только", + "AddAppProfile": "Добавить профиль синхронизации приложения", + "AddNewIndexer": "Добавить Новый Индексатор", + "AddToDownloadClient": "Добавить выпуск в Загрузочный клиент", + "AddedToDownloadClient": "Выпуск добавлен в клиент", + "AddDownloadClientToProwlarr": "Добавление клиента загрузки позволяет Prowlarr отправлять выпуски прямо из пользовательского интерфейса, выполняя поиск вручную.", + "AddIndexerProxy": "Добавить индексатор прокси" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index ce1650b89..e14370240 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -47,7 +47,7 @@ "Indexers": "搜刮器", "IndexerRss": "搜刮器RSS", "IndexerQuery": "搜刮器查询", - "IndexerPriorityHelpText": "搜刮器优先级从1(最高)到50(最低),默认25。", + "IndexerPriorityHelpText": "索引器优先级从1(最高)到50(最低),默认25。", "IndexerPriority": "搜刮器优先级", "IndexerObsoleteCheckMessage": "搜刮器已过弃用或已更新:{0}。请将其删除和(或)重新添加到 Prowlarr", "IndexerLongTermStatusCheckSingleClientMessage": "由于故障6小时,下列搜刮器都已不可用:{0}", @@ -185,7 +185,7 @@ "ApplyTagsHelpTexts3": "删除:移除输入的标签", "ApplyTagsHelpTexts2": "添加:将标签添加到现有标签列表", "Applications": "程序", - "AppDataLocationHealthCheckMessage": "更新将无法阻止在更新时删除应用数据", + "AppDataLocationHealthCheckMessage": "更新将无法阻止在更新时删除 AppData", "AddRemoveOnly": "仅添加和删除", "AddDownloadClientToProwlarr": "添加下载客户端允许 Prowlarr 在进行手动搜索时从 UI直接发送结果.", "AddDownloadClient": "添加下载客户端", @@ -243,7 +243,7 @@ "IndexerProxyStatusCheckAllClientMessage": "所有搜刮器都因错误不可用", "SettingsShowRelativeDates": "显示相对日期", "SettingsShowRelativeDatesHelpText": "显示相对日期(今天昨天等)或绝对日期", - "Source": "源路径", + "Source": "源", "SSLCertPasswordHelpText": "pfx文件密码", "TagCannotBeDeletedWhileInUse": "使用中无法删除", "TagIsNotUsedAndCanBeDeleted": "标签未被使用,可删除", @@ -339,7 +339,7 @@ "UILanguage": "UI界面语言", "UILanguageHelpText": "Radarr使用的UI界面语言", "UpdateCheckUINotWritableMessage": "无法安装升级,因为用户“{1}”不可写入界面文件夹“{0}”。", - "UpdateMechanismHelpText": "使用Radarr内置的更新器或者脚本", + "UpdateMechanismHelpText": "使用 Prowlarr 的内置程序或脚本进行程序升级", "Updates": "更新", "UpdateScriptPathHelpText": "自定义脚本的路径,该脚本处理获取的更新包并处理更新过程的其余部分", "Uptime": "运行时间", From 8e4082a60d04bbe64907b3fdd7577ec54c3d8aed Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 9 May 2022 17:41:29 -0500 Subject: [PATCH 0455/2320] Bump version to 0.3.1 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3b9866693..4855aaf00 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: testsFolder: './_tests' yarnCacheFolder: $(Pipeline.Workspace)/.yarn nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages - majorVersion: '0.3.0' + majorVersion: '0.3.1' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From f87aa820c77719f1794b0189b44f2a6457cda20a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 10 May 2022 19:31:47 -0500 Subject: [PATCH 0456/2320] Bump version to 0.4.0 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 4855aaf00..51c5f6ad2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: testsFolder: './_tests' yarnCacheFolder: $(Pipeline.Workspace)/.yarn nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages - majorVersion: '0.3.1' + majorVersion: '0.4.0' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From 1a71375c3f9275b942a4b69a122659f16100d258 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 1 May 2022 18:49:42 -0500 Subject: [PATCH 0457/2320] Indexer Cleanup --- .../Migration/017_indexer_cleanup.cs | 56 +++ .../Indexers/Definitions/Aither.cs | 61 --- .../Indexers/Definitions/Anidub.cs | 46 +-- .../Indexers/Definitions/Anilibria.cs | 296 -------------- .../Indexers/Definitions/AnimeBytes.cs | 11 +- .../Indexers/Definitions/AnimeTorrents.cs | 46 +-- .../Indexers/Definitions/AnimeWorld.cs | 66 --- .../Indexers/Definitions/Animedia.cs | 32 +- .../Indexers/Definitions/Anthelion.cs | 46 +-- .../Definitions/Avistaz/AvistazSettings.cs | 11 +- src/NzbDrone.Core/Indexers/Definitions/BB.cs | 46 +-- .../Indexers/Definitions/BakaBT.cs | 33 +- .../Indexers/Definitions/BeyondHD.cs | 11 +- .../Indexers/Definitions/BitHDTV.cs | 41 +- .../Indexers/Definitions/Blutopia.cs | 54 --- .../BroadcastheNet/BroadcastheNetSettings.cs | 11 +- .../Cardigann/CardigannSettings.cs | 13 +- .../Indexers/Definitions/DanishBytes.cs | 342 ---------------- .../Indexers/Definitions/DesiTorrents.cs | 84 ---- .../Indexers/Definitions/DigitalCore.cs | 348 ---------------- .../Definitions/FileList/FileListSettings.cs | 11 +- .../Definitions/Gazelle/GazelleSettings.cs | 31 +- .../Indexers/Definitions/GazelleGames.cs | 28 +- .../Definitions/HDBits/HDBitsSettings.cs | 11 +- .../Indexers/Definitions/HDSpace.cs | 46 +-- .../Indexers/Definitions/HDTorrents.cs | 46 +-- .../Indexers/Definitions/IPTorrents.cs | 28 +- .../Indexers/Definitions/ImmortalSeed.cs | 46 +-- .../Indexers/Definitions/InternetArchive.cs | 330 --------------- .../Indexers/Definitions/LatTeam.cs | 51 --- .../Indexers/Definitions/Milkie.cs | 270 ------------- .../Indexers/Definitions/MoreThanTV.cs | 41 +- .../Indexers/Definitions/MyAnonamouse.cs | 11 +- .../Indexers/Definitions/Nebulance.cs | 33 +- .../Indexers/Definitions/NorBits.cs | 33 +- .../PassThePopcorn/PassThePopcornSettings.cs | 11 +- .../Indexers/Definitions/PornoLab.cs | 33 +- .../Indexers/Definitions/PreToMe.cs | 11 +- .../Definitions/Rarbg/RarbgSettings.cs | 23 +- .../Indexers/Definitions/Redacted.cs | 11 +- .../Indexers/Definitions/RevolutionTT.cs | 46 +-- .../Indexers/Definitions/RuTracker.cs | 33 +- .../Indexers/Definitions/SceneHD.cs | 11 +- .../Indexers/Definitions/SceneTime.cs | 28 +- .../Indexers/Definitions/ShareIsland.cs | 59 --- .../Indexers/Definitions/Shizaproject.cs | 32 +- .../Indexers/Definitions/ShowRSS.cs | 29 +- .../Indexers/Definitions/SpeedApp.cs | 11 +- .../Indexers/Definitions/SpeedCD.cs | 46 +-- .../Indexers/Definitions/SubsPlease.cs | 29 +- .../Indexers/Definitions/SuperBits.cs | 354 ---------------- .../Indexers/Definitions/TVVault.cs | 46 +-- .../Indexers/Definitions/ThePirateBay.cs | 322 --------------- .../Indexers/Definitions/TorrentDay.cs | 41 +- .../Indexers/Definitions/TorrentLeech.cs | 380 ------------------ .../Indexers/Definitions/TorrentParadiseMl.cs | 246 ------------ .../TorrentPotato/TorrentPotatoSettings.cs | 23 +- .../Indexers/Definitions/TorrentSeeds.cs | 378 ----------------- .../Indexers/Definitions/TorrentSyndikat.cs | 11 +- .../Indexers/Definitions/TorrentsCSV.cs | 29 +- .../Definitions/UNIT3D/Unit3dSettings.cs | 11 +- .../Definitions/Xthor/XthorSettings.cs | 12 +- src/NzbDrone.Core/Indexers/Definitions/YTS.cs | 308 -------------- .../Indexers/Definitions/ZonaQ.cs | 46 +-- .../Settings/CookieTorrentBaseSettings.cs | 38 ++ .../Settings/NoAuthTorrentBaseSettings.cs | 26 ++ .../Settings/UserPassTorrentBaseSettings.cs | 43 ++ 67 files changed, 329 insertions(+), 5068 deletions(-) create mode 100644 src/NzbDrone.Core/Datastore/Migration/017_indexer_cleanup.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/Aither.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/LatTeam.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/Milkie.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/YTS.cs create mode 100644 src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs create mode 100644 src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs create mode 100644 src/NzbDrone.Core/Indexers/Settings/UserPassTorrentBaseSettings.cs diff --git a/src/NzbDrone.Core/Datastore/Migration/017_indexer_cleanup.cs b/src/NzbDrone.Core/Datastore/Migration/017_indexer_cleanup.cs new file mode 100644 index 000000000..fefc24aeb --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/017_indexer_cleanup.cs @@ -0,0 +1,56 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(017)] + public class indexer_cleanup : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + //Remove v3 yml transfers + Delete.FromTable("Indexers").Row(new { Implementation = "Aither" }); + Delete.FromTable("Indexers").Row(new { Implementation = "Anilibria" }); + Delete.FromTable("Indexers").Row(new { Implementation = "AnimeWorld" }); + Delete.FromTable("Indexers").Row(new { Implementation = "LatTeam" }); + Delete.FromTable("Indexers").Row(new { Implementation = "Blutopia" }); + Delete.FromTable("Indexers").Row(new { Implementation = "DanishBytes" }); + Delete.FromTable("Indexers").Row(new { Implementation = "DesiTorrents" }); + Delete.FromTable("Indexers").Row(new { Implementation = "DigitalCore" }); + Delete.FromTable("Indexers").Row(new { Implementation = "InternetArchive" }); + Delete.FromTable("Indexers").Row(new { Implementation = "Milkie" }); + Delete.FromTable("Indexers").Row(new { Implementation = "ShareIsland" }); + Delete.FromTable("Indexers").Row(new { Implementation = "SuperBits" }); + Delete.FromTable("Indexers").Row(new { Implementation = "ThePirateBay" }); + Delete.FromTable("Indexers").Row(new { Implementation = "TorrentLeech" }); + Delete.FromTable("Indexers").Row(new { Implementation = "TorrentSeeds" }); + Delete.FromTable("Indexers").Row(new { Implementation = "TorrentParadiseMI" }); + Delete.FromTable("Indexers").Row(new { Implementation = "YTS" }); + + //Change settings to shared classes + Update.Table("Indexers").Set(new { ConfigContract = "NoAuthTorrentBaseSettings" }).Where(new { Implementation = "Animedia" }); + Update.Table("Indexers").Set(new { ConfigContract = "NoAuthTorrentBaseSettings" }).Where(new { Implementation = "Shizaproject" }); + Update.Table("Indexers").Set(new { ConfigContract = "NoAuthTorrentBaseSettings" }).Where(new { Implementation = "ShowRSS" }); + Update.Table("Indexers").Set(new { ConfigContract = "NoAuthTorrentBaseSettings" }).Where(new { Implementation = "SubsPlease" }); + Update.Table("Indexers").Set(new { ConfigContract = "NoAuthTorrentBaseSettings" }).Where(new { Implementation = "TorrentsCSV" }); + + //Change settings to shared classes + Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "Anidub" }); + Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "AnimeTorrents" }); + Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "Anthelion" }); + Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "BB" }); + Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "HDSpace" }); + Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "HDTorrents" }); + Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "ImmortalSeed" }); + Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "RevolutionTT" }); + Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "SpeedCD" }); + Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "TVVault" }); + Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "ZonaQ" }); + + //Change settings to shared classes + Update.Table("Indexers").Set(new { ConfigContract = "CookieTorrentBaseSettings" }).Where(new { Implementation = "TorrentDay" }); + Update.Table("Indexers").Set(new { ConfigContract = "CookieTorrentBaseSettings" }).Where(new { Implementation = "MoreThanTV" }); + Update.Table("Indexers").Set(new { ConfigContract = "CookieTorrentBaseSettings" }).Where(new { Implementation = "BitHDTV" }); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Aither.cs b/src/NzbDrone.Core/Indexers/Definitions/Aither.cs deleted file mode 100644 index c84b177dd..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/Aither.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Collections.Generic; -using NLog; -using NzbDrone.Common.Http; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Indexers.Definitions.UNIT3D; -using NzbDrone.Core.Messaging.Events; - -namespace NzbDrone.Core.Indexers.Definitions -{ - [Obsolete("Moved to YML for Cardigann v3")] - public class Aither : Unit3dBase - { - public override string Name => "Aither"; - public override string[] IndexerUrls => new string[] { "https://aither.cc/" }; - public override string Description => "Aither is a Private Torrent Tracker for HD MOVIES / TV"; - public override string Language => "en-US"; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - - public Aither(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - protected override IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId - }, - MusicSearchParams = new List<MusicSearchParam> - { - MusicSearchParam.Q - }, - BookSearchParams = new List<BookSearchParam> - { - BookSearchParam.Q - } - }; - - caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movie"); - caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "TV"); - caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Music"); - caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.PCGames, "Games"); - caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.XXX, "XXX"); - caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.TVSport, "Sport"); - caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.PC, "Software/Apps"); - caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.BooksEBook, "Ebooks/Magazines"); - caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.AudioAudiobook, "AudioBooks"); - caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.Other, "Education"); - - return caps; - } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs b/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs index ab7aff29c..323942b75 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs @@ -14,6 +14,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -22,7 +23,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class Anidub : TorrentIndexerBase<AnidubSettings> + public class Anidub : TorrentIndexerBase<UserPassTorrentBaseSettings> { public override string Name => "Anidub"; public override string[] IndexerUrls => new string[] { "https://tr.anidub.com/" }; @@ -142,7 +143,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class AnidubRequestGenerator : IIndexerRequestGenerator { - public AnidubSettings Settings { get; set; } + public UserPassTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public AnidubRequestGenerator() @@ -252,7 +253,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class AnidubParser : IParseIndexerResponse { - private readonly AnidubSettings _settings; + private readonly UserPassTorrentBaseSettings _settings; private readonly IndexerCapabilitiesCategories _categories; public IIndexerHttpClient HttpClient { get; set; } public Logger Logger { get; set; } @@ -277,7 +278,7 @@ namespace NzbDrone.Core.Indexers.Definitions { "/anons_ongoing", "12" } }; - public AnidubParser(AnidubSettings settings, IndexerCapabilitiesCategories categories) + public AnidubParser(UserPassTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; _categories = categories; @@ -510,41 +511,4 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - - public class AnidubSettingsValidator : AbstractValidator<AnidubSettings> - { - public AnidubSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class AnidubSettings : IIndexerSettings - { - private static readonly AnidubSettingsValidator Validator = new AnidubSettingsValidator(); - - public AnidubSettings() - { - Username = ""; - Password = ""; - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs b/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs deleted file mode 100644 index a76e15f48..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/Anilibria.cs +++ /dev/null @@ -1,296 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Text; -using System.Text.RegularExpressions; -using FluentValidation; -using Newtonsoft.Json; -using NLog; -using NzbDrone.Common.Http; -using NzbDrone.Core.Annotations; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.Parser; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Validation; - -namespace NzbDrone.Core.Indexers.Definitions -{ - [Obsolete("Moved to YML for Cardigann v3")] - public class Anilibria : TorrentIndexerBase<AnilibriaSettings> - { - public override string Name => "Anilibria"; - public override string[] IndexerUrls => new string[] { "https://anilibria.tv/" }; - public override string Description => "Anilibria is russian anime voiceover group and eponymous anime tracker."; - public override string Language => "ru-RU"; - public override Encoding Encoding => Encoding.UTF8; - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerPrivacy Privacy => IndexerPrivacy.Public; - public override IndexerCapabilities Capabilities => SetCapabilities(); - - public Anilibria(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new AnilibriaRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; - } - - public override IParseIndexerResponse GetParser() - { - return new AnilibriaParser(Settings, Capabilities.Categories); - } - - private IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q - } - }; - caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.TVAnime, "ТВ"); - caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.TVAnime, "ONA"); - caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.TVAnime, "OVA"); - caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Movies, "Фильм"); - return caps; - } - } - - public class AnilibriaRequestGenerator : IIndexerRequestGenerator - { - public AnilibriaSettings Settings { get; set; } - public IndexerCapabilities Capabilities { get; set; } - - public AnilibriaRequestGenerator() - { - } - - private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories) - { - var apiUrl = Regex.Replace(Settings.BaseUrl, @"(https?:\/\/)(.*)", "$1api.$2v2"); - var queryCollection = new NameValueCollection - { - { "limit", "100" }, - { "filter", "names,code,torrents.list,season.year,type.string" } - }; - - if (string.IsNullOrWhiteSpace(term)) - { - apiUrl += "/getUpdates?" + queryCollection.GetQueryString(); - } - else - { - apiUrl += "/searchTitles?" + queryCollection.GetQueryString() + "&search=" + Uri.EscapeDataString(term); - } - - var request = new IndexerRequest(apiUrl, HttpAccept.Json); - yield return request; - } - - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - // Anilibria doesn't support music, but this function required by interface - public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) - { - return new IndexerPageableRequestChain(); - } - - // Anilibria doesn't support books, but this function required by interface - public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) - { - return new IndexerPageableRequestChain(); - } - - public Func<IDictionary<string, string>> GetCookies { get; set; } - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class AnilibriaParser : IParseIndexerResponse - { - private readonly AnilibriaSettings _settings; - private readonly IndexerCapabilitiesCategories _categories; - - public AnilibriaParser(AnilibriaSettings settings, IndexerCapabilitiesCategories categories) - { - _settings = settings; - _categories = categories; - } - - private string composeTitle(AnilibriaTitle tl, AnilibriaTorrent tr) - { - var title = tl.Names.Ru; - title += " / " + tl.Names.En; - if (tl.Names.Alternative is string) - { - title += " / " + tl.Names.Alternative; - } - - title += " " + tl.Season.Year; - title += " [" + tr.Quality.String + "]"; - if (!string.IsNullOrWhiteSpace(tr.Series.String)) - { - title += " - E" + tr.Series.String; - } - - return title; - } - - public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) - { - var torrentInfos = new List<ReleaseInfo>(); - var queryResponseItems = JsonConvert.DeserializeObject<List<AnilibriaTitle>>(indexerResponse.Content); - var wwwUrl = Regex.Replace(_settings.BaseUrl, @"(https?:\/\/)(.*)", "$1www.$2/"); - - foreach (var tl in queryResponseItems) - { - foreach (var tr in tl.Torrents.List) - { - var torrentInfo = new TorrentInfo - { - Title = composeTitle(tl, tr), - InfoUrl = string.Format("{0}/release/{1}.html", _settings.BaseUrl.TrimEnd('/'), tl.Code), - DownloadVolumeFactor = 0, - UploadVolumeFactor = 1, - Seeders = tr.Seeders, - Peers = tr.Leechers + tr.Seeders, - Grabs = tr.Downloads, - Categories = _categories.MapTrackerCatDescToNewznab(tl.Type.String), - - // API provides timestamp in UTC+3 timezone, so we need to substract 3 hours - PublishDate = DateTimeUtil.UnixTimestampToDateTime(tr.UploadedTimestamp).AddHours(-3), - Guid = wwwUrl + tr.Url, - DownloadUrl = wwwUrl + tr.Url, - Size = tr.TotalSize, - Resolution = tr.Quality.Resolution, - Codec = tr.Quality.Encoder - }; - - torrentInfos.Add(torrentInfo); - } - } - - return torrentInfos.ToArray(); - } - - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class AnilibriaSettingsValidator : AbstractValidator<AnilibriaSettings> - { - public AnilibriaSettingsValidator() - { - } - } - - public class AnilibriaSettings : IIndexerSettings - { - private static readonly AnilibriaSettingsValidator Validator = new AnilibriaSettingsValidator(); - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } - - public class AnilibriaTitle - { - public AnilibriaNames Names { get; set; } - public string Code { get; set; } - public AnilibriaTorrents Torrents { get; set; } - public AnilibriaSeason Season { get; set; } - public AnilibriaTitleType Type { get; set; } - } - - public class AnilibriaTitleType - { - public string String { get; set; } - } - - public class AnilibriaNames - { - public string Ru { get; set; } - public string En { get; set; } - public object Alternative { get; set; } - } - - public class AnilibriaSeason - { - public long Year { get; set; } - } - - public class AnilibriaTorrents - { - public AnilibriaTorrent[] List { get; set; } - } - - public class AnilibriaTorrent - { - public AnilibriaSeries Series { get; set; } - public AnilibriaQuality Quality { get; set; } - public int Leechers { get; set; } - public int Seeders { get; set; } - public int Downloads { get; set; } - - [JsonProperty("total_size")] - public long TotalSize { get; set; } - public string Url { get; set; } - - [JsonProperty("uploaded_timestamp")] - public long UploadedTimestamp { get; set; } - } - - public class AnilibriaQuality - { - public string String { get; set; } - public string Type { get; set; } - public string Resolution { get; set; } - public string Encoder { get; set; } - } - - public class AnilibriaSeries - { - public long First { get; set; } - public long Last { get; set; } - public string String { get; set; } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs index 15219662e..0e81c0ac9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs @@ -15,6 +15,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -474,7 +475,7 @@ namespace NzbDrone.Core.Indexers.Definitions } } - public class AnimeBytesSettings : IIndexerSettings + public class AnimeBytesSettings : NoAuthTorrentBaseSettings { private static readonly AnimeBytesSettingsValidator Validator = new AnimeBytesSettingsValidator(); @@ -485,9 +486,6 @@ namespace NzbDrone.Core.Indexers.Definitions EnableSonarrCompatibility = true; } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "Passkey", HelpText = "Site Passkey", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] public string Passkey { get; set; } @@ -497,10 +495,7 @@ namespace NzbDrone.Core.Indexers.Definitions [FieldDefinition(4, Label = "Enable Sonarr Compatibility", Type = FieldType.Checkbox, HelpText = "Makes Prowlarr try to add Season information into Release names, without this Sonarr can't match any Seasons, but it has a lot of false positives as well")] public bool EnableSonarrCompatibility { get; set; } - [FieldDefinition(5)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs index 87c92d73a..a7636df97 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeTorrents.cs @@ -13,6 +13,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -21,7 +22,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class AnimeTorrents : TorrentIndexerBase<AnimeTorrentsSettings> + public class AnimeTorrents : TorrentIndexerBase<UserPassTorrentBaseSettings> { public override string Name => "AnimeTorrents"; @@ -134,7 +135,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class AnimeTorrentsRequestGenerator : IIndexerRequestGenerator { - public AnimeTorrentsSettings Settings { get; set; } + public UserPassTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public AnimeTorrentsRequestGenerator() @@ -227,10 +228,10 @@ namespace NzbDrone.Core.Indexers.Definitions public class AnimeTorrentsParser : IParseIndexerResponse { - private readonly AnimeTorrentsSettings _settings; + private readonly UserPassTorrentBaseSettings _settings; private readonly IndexerCapabilitiesCategories _categories; - public AnimeTorrentsParser(AnimeTorrentsSettings settings, IndexerCapabilitiesCategories categories) + public AnimeTorrentsParser(UserPassTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; _categories = categories; @@ -328,41 +329,4 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - - public class AnimeTorrentsSettingsValidator : AbstractValidator<AnimeTorrentsSettings> - { - public AnimeTorrentsSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class AnimeTorrentsSettings : IIndexerSettings - { - private static readonly AnimeTorrentsSettingsValidator Validator = new AnimeTorrentsSettingsValidator(); - - public AnimeTorrentsSettings() - { - Username = ""; - Password = ""; - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs deleted file mode 100644 index 52dd2a23d..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeWorld.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using NLog; -using NzbDrone.Common.Http; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Indexers.Definitions.UNIT3D; -using NzbDrone.Core.Messaging.Events; - -namespace NzbDrone.Core.Indexers.Definitions -{ - [Obsolete("Moved to YML for Cardigann v3")] - public class AnimeWorld : Unit3dBase - { - public override string Name => "AnimeWorld"; - public override string[] IndexerUrls => new string[] { "https://animeworld.cx/" }; - public override string Description => "AnimeWorld (AW) is a GERMAN Private site for ANIME / MANGA / HENTAI"; - public override string Language => "de-DE"; - - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public AnimeWorld(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - protected override IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId - }, - MusicSearchParams = new List<MusicSearchParam> - { - MusicSearchParam.Q - }, - BookSearchParams = new List<BookSearchParam> - { - BookSearchParam.Q - } - }; - - caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Anime Movie"); - caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVAnime, "Anime Series"); - caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Anime Musik/OST"); - caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.PCGames, "Anime Spiele"); - caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.XXX, "Anime Hentai"); - caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.PCGames, "Software"); - caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.Other, "Sonstiges"); - caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.Movies, "Filme"); - caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.TV, "Serien"); - caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.PCGames, "Spiele"); - caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.Audio, "Musik"); - caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.BooksComics, "Mangas"); - caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.Movies, "Cartoon Filme"); - caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.TV, "Cartoon Serie"); - caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.XXX, "H-Manga / Doujinshi"); - - return caps; - } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs b/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs index cb4980a5d..3b73777a8 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs @@ -10,6 +10,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -18,7 +19,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class Animedia : TorrentIndexerBase<AnimediaSettings> + public class Animedia : TorrentIndexerBase<NoAuthTorrentBaseSettings> { public override string Name => "Animedia"; public override string[] IndexerUrls => new string[] { "https://tt.animedia.tv/" }; @@ -67,7 +68,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class AnimediaRequestGenerator : IIndexerRequestGenerator { - public AnimediaSettings Settings { get; set; } + public NoAuthTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public AnimediaRequestGenerator() @@ -144,7 +145,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class AnimediaParser : IParseIndexerResponse { - private readonly AnimediaSettings _settings; + private readonly NoAuthTorrentBaseSettings _settings; private readonly IndexerCapabilitiesCategories _categories; private static readonly Regex EpisodesInfoQueryRegex = new Regex(@"сери[ия] (\d+)(?:-(\d+))? из.*", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex ResolutionInfoQueryRegex = new Regex(@"качество (\d+)", RegexOptions.Compiled | RegexOptions.IgnoreCase); @@ -156,7 +157,7 @@ namespace NzbDrone.Core.Indexers.Definitions public IIndexerHttpClient HttpClient { get; set; } public Logger Logger { get; set; } - public AnimediaParser(AnimediaSettings settings, IndexerCapabilitiesCategories categories) + public AnimediaParser(NoAuthTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; _categories = categories; @@ -324,27 +325,4 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - - public class AnimediaSettingsValidator : AbstractValidator<AnimediaSettings> - { - public AnimediaSettingsValidator() - { - } - } - - public class AnimediaSettings : IIndexerSettings - { - private static readonly AnimediaSettingsValidator Validator = new AnimediaSettingsValidator(); - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs b/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs index 28e195e8c..cb1cdde92 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs @@ -13,6 +13,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -22,7 +23,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class Anthelion : TorrentIndexerBase<AnthelionSettings> + public class Anthelion : TorrentIndexerBase<UserPassTorrentBaseSettings> { public override string Name => "Anthelion"; public override string[] IndexerUrls => new string[] { "https://anthelion.me/" }; @@ -130,7 +131,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class AnthelionRequestGenerator : IIndexerRequestGenerator { - public AnthelionSettings Settings { get; set; } + public UserPassTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public AnthelionRequestGenerator() @@ -212,10 +213,10 @@ namespace NzbDrone.Core.Indexers.Definitions public class AnthelionParser : IParseIndexerResponse { - private readonly AnthelionSettings _settings; + private readonly UserPassTorrentBaseSettings _settings; private readonly IndexerCapabilitiesCategories _categories; - public AnthelionParser(AnthelionSettings settings, IndexerCapabilitiesCategories categories) + public AnthelionParser(UserPassTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; _categories = categories; @@ -297,41 +298,4 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - - public class AnthelionSettingsValidator : AbstractValidator<AnthelionSettings> - { - public AnthelionSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class AnthelionSettings : IIndexerSettings - { - private static readonly AnthelionSettingsValidator Validator = new AnthelionSettingsValidator(); - - public AnthelionSettings() - { - Username = ""; - Password = ""; - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazSettings.cs index 749a36830..2f81274f6 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazSettings.cs @@ -1,5 +1,6 @@ using FluentValidation; using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions.Avistaz @@ -14,7 +15,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz } } - public class AvistazSettings : IIndexerSettings + public class AvistazSettings : NoAuthTorrentBaseSettings { private static readonly AvistazSettingsValidator Validator = new AvistazSettingsValidator(); @@ -25,9 +26,6 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz public string Token { get; set; } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] public string Username { get; set; } @@ -37,10 +35,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz [FieldDefinition(4, Label = "PID", HelpText = "PID from My Account or My Profile page")] public string Pid { get; set; } - [FieldDefinition(5)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/BB.cs b/src/NzbDrone.Core/Indexers/Definitions/BB.cs index e849cfade..7c3b0a78f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BB.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BB.cs @@ -13,6 +13,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -21,7 +22,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class BB : TorrentIndexerBase<BBSettings> + public class BB : TorrentIndexerBase<UserPassTorrentBaseSettings> { public override string Name => "BB"; public override string[] IndexerUrls => new string[] { StringUtil.FromBase64("aHR0cHM6Ly9iYWNvbmJpdHMub3JnLw==") }; @@ -159,7 +160,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class BBRequestGenerator : IIndexerRequestGenerator { - public BBSettings Settings { get; set; } + public UserPassTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public BBRequestGenerator() @@ -247,10 +248,10 @@ namespace NzbDrone.Core.Indexers.Definitions public class BBParser : IParseIndexerResponse { - private readonly BBSettings _settings; + private readonly UserPassTorrentBaseSettings _settings; private readonly IndexerCapabilitiesCategories _categories; - public BBParser(BBSettings settings, IndexerCapabilitiesCategories categories) + public BBParser(UserPassTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; _categories = categories; @@ -330,41 +331,4 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - - public class BBSettingsValidator : AbstractValidator<BBSettings> - { - public BBSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class BBSettings : IIndexerSettings - { - private static readonly BBSettingsValidator Validator = new BBSettingsValidator(); - - public BBSettings() - { - Username = ""; - Password = ""; - } - - [FieldDefinition(1, Label = "Base Url", HelpText = "Select which baseurl Prowlarr will use for requests to the site", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs index 8595a16d1..38feb1be8 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs @@ -14,6 +14,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -412,34 +413,12 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - public class BakaBTSettingsValidator : AbstractValidator<BakaBTSettings> + public class BakaBTSettings : UserPassTorrentBaseSettings { - public BakaBTSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class BakaBTSettings : IIndexerSettings - { - private static readonly BakaBTSettingsValidator Validator = new BakaBTSettingsValidator(); - public BakaBTSettings() { - Username = ""; - Password = ""; } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - [FieldDefinition(4, Label = "Add Romaji Title", Type = FieldType.Checkbox, HelpText = "Add releases for Romaji Title")] public bool AddRomajiTitle { get; set; } @@ -448,13 +427,5 @@ namespace NzbDrone.Core.Indexers.Definitions [FieldDefinition(6, Label = "Adult Content", Type = FieldType.Checkbox, HelpText = "Allow Adult Content (Must be enabled in BakaBT settings)")] public bool AdultContent { get; set; } - - [FieldDefinition(7)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs b/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs index dd602d155..66c8feab9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs @@ -13,6 +13,7 @@ using NzbDrone.Common.Serializer; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -249,7 +250,7 @@ namespace NzbDrone.Core.Indexers.Definitions } } - public class BeyondHDSettings : IIndexerSettings + public class BeyondHDSettings : NoAuthTorrentBaseSettings { private static readonly BeyondHDSettingsValidator Validator = new BeyondHDSettingsValidator(); @@ -257,19 +258,13 @@ namespace NzbDrone.Core.Indexers.Definitions { } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "API Key", HelpText = "API Key from the Site (Found in My Security => API Key)", Privacy = PrivacyLevel.ApiKey)] public string ApiKey { get; set; } [FieldDefinition(3, Label = "RSS Key", HelpText = "RSS Key from the Site (Found in My Security => RSS Key)", Privacy = PrivacyLevel.ApiKey)] public string RssKey { get; set; } - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/BitHDTV.cs b/src/NzbDrone.Core/Indexers/Definitions/BitHDTV.cs index c457e9021..e3a90251d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BitHDTV.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BitHDTV.cs @@ -12,6 +12,7 @@ using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -21,7 +22,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class BitHDTV : TorrentIndexerBase<BitHDTVSettings> + public class BitHDTV : TorrentIndexerBase<CookieTorrentBaseSettings> { public override string Name => "BitHDTV"; public override string[] IndexerUrls => new string[] { "https://www.bit-hdtv.com/" }; @@ -89,7 +90,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class BitHDTVRequestGenerator : IIndexerRequestGenerator { - public BitHDTVSettings Settings { get; set; } + public CookieTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public BitHDTVRequestGenerator() @@ -179,10 +180,10 @@ namespace NzbDrone.Core.Indexers.Definitions public class BitHDTVParser : IParseIndexerResponse { - private readonly BitHDTVSettings _settings; + private readonly CookieTorrentBaseSettings _settings; private readonly IndexerCapabilitiesCategories _categories; - public BitHDTVParser(BitHDTVSettings settings, IndexerCapabilitiesCategories categories) + public BitHDTVParser(CookieTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; _categories = categories; @@ -267,36 +268,4 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - - public class BitHDTVSettingsValidator : AbstractValidator<BitHDTVSettings> - { - public BitHDTVSettingsValidator() - { - RuleFor(c => c.Cookie).NotEmpty(); - } - } - - public class BitHDTVSettings : IIndexerSettings - { - private static readonly BitHDTVSettingsValidator Validator = new BitHDTVSettingsValidator(); - - public BitHDTVSettings() - { - Cookie = ""; - } - - [FieldDefinition(1, Label = "Base Url", HelpText = "Select which baseurl Prowlarr will use for requests to the site", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Cookie", HelpText = "Login cookie from website")] - public string Cookie { get; set; } - - [FieldDefinition(3)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs b/src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs deleted file mode 100644 index e854ed96b..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/Blutopia.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Collections.Generic; -using NLog; -using NzbDrone.Common.Http; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Indexers.Definitions.UNIT3D; -using NzbDrone.Core.Messaging.Events; - -namespace NzbDrone.Core.Indexers.Definitions -{ - [Obsolete("Moved to YML for Cardigann v3")] - public class Blutopia : Unit3dBase - { - public override string Name => "Blutopia"; - public override string[] IndexerUrls => new string[] { "https://blutopia.xyz/" }; - public override string Description => "Blutopia (BLU) is a Private Torrent Tracker for HD MOVIES / TV"; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - - public Blutopia(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - protected override IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId - }, - MusicSearchParams = new List<MusicSearchParam> - { - MusicSearchParam.Q - }, - BookSearchParams = new List<BookSearchParam> - { - BookSearchParam.Q - } - }; - - caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movie"); - caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "TV Show"); - caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.MoviesOther, "FANRES"); - caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.MoviesOther, "Trailer"); - - return caps; - } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNetSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNetSettings.cs index a6d8eea03..965f04a7f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNetSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BroadcastheNet/BroadcastheNetSettings.cs @@ -1,5 +1,6 @@ using FluentValidation; using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.BroadcastheNet @@ -12,7 +13,7 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet } } - public class BroadcastheNetSettings : IIndexerSettings + public class BroadcastheNetSettings : NoAuthTorrentBaseSettings { private static readonly BroadcastheNetSettingsValidator Validator = new BroadcastheNetSettingsValidator(); @@ -20,16 +21,10 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet { } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey)] public string ApiKey { get; set; } - [FieldDefinition(3)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannSettings.cs index a5a650a09..9b1ef4e15 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannSettings.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using FluentValidation; using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Cardigann @@ -12,7 +13,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } } - public class CardigannSettings : IIndexerSettings + public class CardigannSettings : NoAuthTorrentBaseSettings { private static readonly CardigannSettingsValidator Validator = new CardigannSettingsValidator(); @@ -24,17 +25,9 @@ namespace NzbDrone.Core.Indexers.Cardigann [FieldDefinition(0, Hidden = HiddenType.Hidden)] public string DefinitionFile { get; set; } - [FieldDefinition(2, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(1)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - public Dictionary<string, object> ExtraFieldData { get; set; } - // Field 8 is used by TorznabSettings MinimumSeeders - // If you need to add another field here, update TorznabSettings as well and this comment - public virtual NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs deleted file mode 100644 index 7c7ce7f7f..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/DanishBytes.cs +++ /dev/null @@ -1,342 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Linq; -using System.Net; -using FluentValidation; -using Newtonsoft.Json; -using NLog; -using NzbDrone.Common.Extensions; -using NzbDrone.Common.Http; -using NzbDrone.Core.Annotations; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Indexers.Exceptions; -using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.Parser; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Validation; - -namespace NzbDrone.Core.Indexers.Definitions -{ - [Obsolete("Moved to YML")] - public class DanishBytes : TorrentIndexerBase<DanishBytesSettings> - { - public override string Name => "DanishBytes"; - public override string[] IndexerUrls => new string[] { "https://danishbytes.club/", "https://danishbytes2.org/" }; - public override string Description => "DanishBytes is a Private Danish Tracker"; - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public override IndexerCapabilities Capabilities => SetCapabilities(); - - public DanishBytes(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new DanishBytesRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; - } - - public override IParseIndexerResponse GetParser() - { - return new DanishBytesParser(Settings, Capabilities.Categories); - } - - private IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId - }, - MusicSearchParams = new List<MusicSearchParam> - { - MusicSearchParam.Q - }, - BookSearchParams = new List<BookSearchParam> - { - BookSearchParam.Q - } - }; - - caps.Categories.AddCategoryMapping("1", NewznabStandardCategory.Movies, "Movies"); - caps.Categories.AddCategoryMapping("2", NewznabStandardCategory.TV, "TV"); - caps.Categories.AddCategoryMapping("3", NewznabStandardCategory.Audio, "Music"); - caps.Categories.AddCategoryMapping("4", NewznabStandardCategory.PCGames, "Games"); - caps.Categories.AddCategoryMapping("5", NewznabStandardCategory.PC0day, "Appz"); - caps.Categories.AddCategoryMapping("8", NewznabStandardCategory.Books, "Bookz"); - - return caps; - } - } - - public class DanishBytesRequestGenerator : IIndexerRequestGenerator - { - public DanishBytesSettings Settings { get; set; } - public IndexerCapabilities Capabilities { get; set; } - - public DanishBytesRequestGenerator() - { - } - - private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null, int tmdbId = 0, int tvdbId = 0) - { - var qc = new NameValueCollection - { - { "search", term }, - { "api_token", Settings.ApiKey }, - }; - - if (imdbId.IsNotNullOrWhiteSpace()) - { - qc.Add("imdb", imdbId); - } - - if (tmdbId > 0) - { - qc.Add("tmdb", tmdbId.ToString()); - } - - if (tvdbId > 0) - { - qc.Add("tvdb", tvdbId.ToString()); - } - - var searchUrl = string.Format("{0}/api/torrents/v2/filter?{1}", Settings.BaseUrl.TrimEnd('/'), qc.GetQueryString()); - - foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories)) - { - searchUrl += $"&categories[]={cat}"; - } - - var request = new HttpRequest(searchUrl, HttpAccept.Json); - - var indexerRequest = new IndexerRequest(request); - - yield return indexerRequest; - } - - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId, searchCriteria.TmdbId.GetValueOrDefault(0))); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId, 0, searchCriteria.TvdbId.GetValueOrDefault(0))); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public Func<IDictionary<string, string>> GetCookies { get; set; } - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class DanishBytesParser : IParseIndexerResponse - { - private readonly DanishBytesSettings _settings; - private readonly IndexerCapabilitiesCategories _categories; - - public DanishBytesParser(DanishBytesSettings settings, IndexerCapabilitiesCategories categories) - { - _settings = settings; - _categories = categories; - } - - public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) - { - var torrentInfos = new List<TorrentInfo>(); - - if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) - { - throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request"); - } - - if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value)) - { - throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}"); - } - - var jsonResponse = new HttpResponse<DanishBytesResponse>(indexerResponse.HttpResponse); - - foreach (var row in jsonResponse.Resource.Torrents) - { - var infoUrl = $"{_settings.BaseUrl}torrents/{row.Id}"; - - var release = new TorrentInfo - { - Title = row.Name, - InfoUrl = infoUrl, - DownloadUrl = $"{_settings.BaseUrl}torrent/download/{row.Id}.{jsonResponse.Resource.Rsskey}", - Guid = infoUrl, - PosterUrl = row.PosterImage, - PublishDate = row.CreatedAt, - Categories = _categories.MapTrackerCatToNewznab(row.CategoryId), - Size = row.Size, - Seeders = row.Seeders, - Peers = row.Leechers + row.Seeders, - Grabs = row.TimesCompleted, - DownloadVolumeFactor = row.Free ? 0 : 1, - UploadVolumeFactor = row.Doubleup ? 2 : 1 - }; - - torrentInfos.Add(release); - } - - // order by date - return torrentInfos.OrderByDescending(o => o.PublishDate).ToArray(); - } - - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class DanishBytesSettingsValidator : AbstractValidator<DanishBytesSettings> - { - public DanishBytesSettingsValidator() - { - RuleFor(c => c.ApiKey).NotEmpty(); - } - } - - public class DanishBytesSettings : IIndexerSettings - { - private static readonly DanishBytesSettingsValidator Validator = new DanishBytesSettingsValidator(); - - public DanishBytesSettings() - { - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "API Key", HelpText = "API Key from Site", Privacy = PrivacyLevel.ApiKey)] - public string ApiKey { get; set; } - - [FieldDefinition(3)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } - - public class DanishBytesTorrent - { - public int Id { get; set; } - public string Name { get; set; } - - [JsonProperty(PropertyName = "info_hash")] - public string InfoHash { get; set; } - public long Size { get; set; } - public int Leechers { get; set; } - public int Seeders { get; set; } - - [JsonProperty(PropertyName = "times_completed")] - public int TimesCompleted { get; set; } - - [JsonProperty(PropertyName = "category_id")] - public string CategoryId { get; set; } - public string Tmdb { get; set; } - public string Igdb { get; set; } - public string Mal { get; set; } - public string Tvdb { get; set; } - public string Imdb { get; set; } - public int Stream { get; set; } - public bool Free { get; set; } - - [JsonProperty(PropertyName = "on_fire")] - public bool OnFire { get; set; } - public bool Doubleup { get; set; } - public bool Highspeed { get; set; } - public bool Featured { get; set; } - public bool Webstream { get; set; } - public bool Anon { get; set; } - public bool Sticky { get; set; } - public bool Sd { get; set; } - - [JsonProperty(PropertyName = "created_at")] - public DateTime CreatedAt { get; set; } - - [JsonProperty(PropertyName = "resolution_id")] - public int ResolutionId { get; set; } - - [JsonProperty(PropertyName = "poster_image")] - public string PosterImage { get; set; } - public string Video { get; set; } - - [JsonProperty(PropertyName = "thanks_count")] - public int ThanksCount { get; set; } - - [JsonProperty(PropertyName = "comments_count")] - public int CommentsCount { get; set; } - public string GetSize { get; set; } - - [JsonProperty(PropertyName = "created_at_human")] - public string CreatedAtHuman { get; set; } - public bool Bookmarked { get; set; } - public bool Liked { get; set; } - - [JsonProperty(PropertyName = "show_last_torrents")] - public bool ShowLastTorrents { get; set; } - } - - public class DanishBytesPageLinks - { - public int To { get; set; } - public string Qty { get; set; } - - [JsonProperty(PropertyName = "current_page")] - public int CurrentPage { get; set; } - } - - public class DanishBytesResponse - { - public DanishBytesTorrent[] Torrents { get; set; } - public int ResultsCount { get; set; } - public DanishBytesPageLinks Links { get; set; } - public string CurrentCount { get; set; } - public int TorrentCountTotal { get; set; } - public string Rsskey { get; set; } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs deleted file mode 100644 index 571d3e904..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/DesiTorrents.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using NLog; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Indexers.Definitions.UNIT3D; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.Parser.Model; - -namespace NzbDrone.Core.Indexers.Definitions -{ - [Obsolete("Moved to YML for Cardigann v3")] - public class DesiTorrents : Unit3dBase - { - public override string Name => "DesiTorrents"; - public override string Language => "en-US"; - public override string[] IndexerUrls => new[] { "https://desitorrents.tv/", "https://desitorrents.rocks/" }; - public override string Description => "Desitorrents is a Private Torrent Tracker for BOLLYWOOD / TOLLYWOOD / GENERAL"; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - - public DesiTorrents(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - public override IParseIndexerResponse GetParser() - { - return new DesiTorrentsParser(Settings, Capabilities.Categories); - } - - protected override IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q - }, - MusicSearchParams = new List<MusicSearchParam> - { - MusicSearchParam.Q - }, - BookSearchParams = new List<BookSearchParam> - { - BookSearchParam.Q - } - }; - - caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movies"); - caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "TV"); - caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Music"); - caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.BooksEBook, "ebooks"); - caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.TVSport, "Sports"); - caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.PCGames, "Games"); - - return caps; - } - } - - public class DesiTorrentsParser : Unit3dParser - { - public DesiTorrentsParser(Unit3dSettings settings, IndexerCapabilitiesCategories categories) - : base(settings, categories) - { - } - - public override IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) - { - var releases = base.ParseResponse(indexerResponse); - - foreach (TorrentInfo release in releases) - { - release.MinimumRatio = 0.6; - release.MinimumSeedTime = 259200; - } - - return releases; - } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs b/src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs deleted file mode 100644 index e14dce86e..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/DigitalCore.cs +++ /dev/null @@ -1,348 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Globalization; -using System.Linq; -using System.Net; -using FluentValidation; -using Newtonsoft.Json; -using NLog; -using NzbDrone.Common.Extensions; -using NzbDrone.Common.Http; -using NzbDrone.Core.Annotations; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Indexers.Exceptions; -using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.Parser; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Validation; - -namespace NzbDrone.Core.Indexers.Definitions -{ - [Obsolete("Moved to YML for Cardigann v3")] - public class DigitalCore : TorrentIndexerBase<DigitalCoreSettings> - { - public override string Name => "DigitalCore"; - public override string[] IndexerUrls => new string[] { "https://digitalcore.club/" }; - public override string Description => "DigitalCore is a Private Torrent Tracker for MOVIES / TV / GENERAL"; - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public override IndexerCapabilities Capabilities => SetCapabilities(); - - public DigitalCore(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new DigitalCoreRequestGenerator() { Settings = Settings, PageSize = PageSize, Capabilities = Capabilities }; - } - - public override IParseIndexerResponse GetParser() - { - return new DigitalCoreParser(Settings, Capabilities.Categories); - } - - protected override IDictionary<string, string> GetCookies() - { - var cookies = new Dictionary<string, string>(); - - cookies.Add("uid", Settings.UId); - cookies.Add("pass", Settings.Passphrase); - - return cookies; - } - - private IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q, MovieSearchParam.ImdbId - }, - MusicSearchParams = new List<MusicSearchParam> - { - MusicSearchParam.Q - }, - BookSearchParams = new List<BookSearchParam> - { - BookSearchParam.Q - } - }; - - caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesDVD, "Movies/DVDR"); - caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.MoviesSD, "Movies/SD"); - caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.MoviesBluRay, "Movies/BluRay"); - caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.MoviesUHD, "Movies/4K"); - caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.MoviesHD, "Movies/720p"); - caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.MoviesHD, "Movies/1080p"); - caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.MoviesHD, "Movies/PACKS"); - - caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.TVHD, "TV/720p"); - caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.TVHD, "TV/1080p"); - caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.TVSD, "TV/SD"); - caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.TVSD, "TV/DVDR"); - caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.TVHD, "TV/PACKS"); - caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.TVUHD, "TV/4K"); - caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.TVHD, "TV/BluRay"); - - caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.Other, "Unknown"); - caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.PC0day, "Apps/0day"); - caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.PCISO, "Apps/PC"); - caps.Categories.AddCategoryMapping(21, NewznabStandardCategory.PCMac, "Apps/Mac"); - caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.PC, "Apps/Tutorials"); - - caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.AudioMP3, "Music/MP3"); - caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.AudioLossless, "Music/FLAC"); - caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.Audio, "Music/MTV"); - caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.Audio, "Music/PACKS"); - - caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.PCGames, "Games/PC"); - caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.Console, "Games/NSW"); - caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.PCMac, "Games/Mac"); - - caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.Books, "Ebooks"); - - caps.Categories.AddCategoryMapping(30, NewznabStandardCategory.XXXSD, "XXX/SD"); - caps.Categories.AddCategoryMapping(31, NewznabStandardCategory.XXX, "XXX/HD"); - caps.Categories.AddCategoryMapping(32, NewznabStandardCategory.XXXUHD, "XXX/4K"); - caps.Categories.AddCategoryMapping(35, NewznabStandardCategory.XXXSD, "XXX/Movies/SD"); - caps.Categories.AddCategoryMapping(36, NewznabStandardCategory.XXX, "XXX/Movies/HD"); - caps.Categories.AddCategoryMapping(37, NewznabStandardCategory.XXXUHD, "XXX/Movies/4K"); - caps.Categories.AddCategoryMapping(34, NewznabStandardCategory.XXXImageSet, "XXX/Imagesets"); - - return caps; - } - } - - public class DigitalCoreRequestGenerator : IIndexerRequestGenerator - { - public DigitalCoreSettings Settings { get; set; } - public IndexerCapabilities Capabilities { get; set; } - - public int MaxPages { get; set; } - public int PageSize { get; set; } - - public DigitalCoreRequestGenerator() - { - MaxPages = 30; - PageSize = 100; - } - - private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null) - { - var searchUrl = string.Format("{0}/api/v1/torrents", Settings.BaseUrl.TrimEnd('/')); - - var parameters = new NameValueCollection(); - - parameters.Add("extendedSearch", "false"); - parameters.Add("freeleech", "false"); - parameters.Add("index", "0"); - parameters.Add("limit", "100"); - parameters.Add("order", "desc"); - parameters.Add("page", "search"); - - if (imdbId.IsNotNullOrWhiteSpace()) - { - parameters.Add("searchText", imdbId); - } - else - { - parameters.Add("searchText", term); - } - - parameters.Add("sort", "d"); - parameters.Add("section", "all"); - parameters.Add("stereoscopic", "false"); - parameters.Add("watchview", "false"); - - searchUrl += "?" + parameters.GetQueryString(); - - foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories)) - { - searchUrl += "&categories[]=" + cat; - } - - var request = new IndexerRequest(searchUrl, HttpAccept.Json); - - yield return request; - } - - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public Func<IDictionary<string, string>> GetCookies { get; set; } - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class DigitalCoreParser : IParseIndexerResponse - { - private readonly DigitalCoreSettings _settings; - private readonly IndexerCapabilitiesCategories _categories; - - public DigitalCoreParser(DigitalCoreSettings settings, IndexerCapabilitiesCategories categories) - { - _settings = settings; - _categories = categories; - } - - public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) - { - var torrentInfos = new List<ReleaseInfo>(); - - if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) - { - throw new IndexerException(indexerResponse, - "Unexpected response status {0} code from API request", - indexerResponse.HttpResponse.StatusCode); - } - - try - { - //var json = JArray.Parse(results.Content); - var json = JsonConvert.DeserializeObject<dynamic>(indexerResponse.Content); - - foreach (var row in json ?? Enumerable.Empty<dynamic>()) - { - var release = new TorrentInfo(); - var descriptions = new List<string>(); - var tags = new List<string>(); - - release.MinimumRatio = 1.1; - release.MinimumSeedTime = 432000; // 120 hours - release.Title = row.name; - release.Categories = _categories.MapTrackerCatToNewznab(row.category.ToString()); - release.Size = row.size; - release.Seeders = row.seeders; - release.Peers = row.leechers + release.Seeders; - release.PublishDate = DateTime.ParseExact(row.added.ToString() + " +01:00", "yyyy-MM-dd HH:mm:ss zzz", CultureInfo.InvariantCulture); - release.Files = row.numfiles; - release.Grabs = row.times_completed; - - var infoUrl = _settings.BaseUrl + "torrent/" + row.id.ToString() + "/"; - - release.Guid = infoUrl; - release.DownloadUrl = _settings.BaseUrl + "api/v1/torrents/download/" + row.id.ToString(); - release.InfoUrl = infoUrl; - - if (row.frileech == 1) - { - release.DownloadVolumeFactor = 0; - } - else - { - release.DownloadVolumeFactor = 1; - } - - release.UploadVolumeFactor = 1; - - if (row.imdbid2 != null && row.imdbid2.ToString().StartsWith("tt")) - { - if (int.TryParse((string)row.imdbid2, out int imdbNumber)) - { - release.ImdbId = imdbNumber; - } - } - - torrentInfos.Add(release); - } - } - catch (Exception ex) - { - throw new IndexerException(indexerResponse, - "Unable to parse response from DigitalCore: {0}", - ex.Message); - } - - return torrentInfos.ToArray(); - } - - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class DigitalCoreSettingsValidator : AbstractValidator<DigitalCoreSettings> - { - public DigitalCoreSettingsValidator() - { - RuleFor(c => c.UId).NotEmpty(); - RuleFor(c => c.Passphrase).NotEmpty(); - } - } - - public class DigitalCoreSettings : IIndexerSettings - { - private static readonly DigitalCoreSettingsValidator Validator = new DigitalCoreSettingsValidator(); - - public DigitalCoreSettings() - { - UId = ""; - Passphrase = ""; - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "UID", HelpText = "UID from login cookie", Privacy = PrivacyLevel.UserName)] - public string UId { get; set; } - - [FieldDefinition(3, Label = "Passphrase", HelpText = "Passphrase from login cookie", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Passphrase { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListSettings.cs index fa906afef..a64fc257a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListSettings.cs @@ -1,5 +1,6 @@ using FluentValidation; using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.FileList @@ -13,7 +14,7 @@ namespace NzbDrone.Core.Indexers.FileList } } - public class FileListSettings : IIndexerSettings + public class FileListSettings : NoAuthTorrentBaseSettings { private static readonly FileListSettingsValidator Validator = new FileListSettingsValidator(); @@ -22,19 +23,13 @@ namespace NzbDrone.Core.Indexers.FileList BaseUrl = "https://filelist.io"; } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] public string Username { get; set; } [FieldDefinition(3, Label = "Passkey", HelpText = "Site Passkey", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] public string Passkey { get; set; } - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleSettings.cs index 73b9058b4..3461543d8 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleSettings.cs @@ -1,22 +1,12 @@ using FluentValidation; using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Gazelle { - public class GazelleSettingsValidator : AbstractValidator<GazelleSettings> + public class GazelleSettings : UserPassTorrentBaseSettings { - public GazelleSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class GazelleSettings : IIndexerSettings - { - private static readonly GazelleSettingsValidator Validator = new GazelleSettingsValidator(); - public GazelleSettings() { } @@ -24,24 +14,7 @@ namespace NzbDrone.Core.Indexers.Gazelle public string AuthKey; public string PassKey; - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - [FieldDefinition(4, Type = FieldType.Checkbox, Label = "Use Freeleech Token", HelpText = "Use Freeleech Token")] public bool UseFreeleechToken { get; set; } - - [FieldDefinition(5)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs b/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs index 0a85320d2..13ec8dd5c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs @@ -10,6 +10,7 @@ using NLog; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -392,39 +393,14 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - public class GazelleGamesSettingsValidator : AbstractValidator<GazelleGamesSettings> + public class GazelleGamesSettings : CookieTorrentBaseSettings { - public GazelleGamesSettingsValidator() - { - RuleFor(c => c.Cookie).NotEmpty(); - } - } - - public class GazelleGamesSettings : IIndexerSettings - { - private static readonly GazelleGamesSettingsValidator Validator = new GazelleGamesSettingsValidator(); - public GazelleGamesSettings() { - Cookie = ""; SearchGroupNames = false; } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Cookie", HelpText = "Login cookie from website")] - public string Cookie { get; set; } - [FieldDefinition(3, Label = "Search Group Names", Type = FieldType.Checkbox, HelpText = "Search Group Names Only")] public bool SearchGroupNames { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsSettings.cs index 78b8a47ac..386613626 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDBits/HDBitsSettings.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using FluentValidation; using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.HDBits @@ -13,7 +14,7 @@ namespace NzbDrone.Core.Indexers.HDBits } } - public class HDBitsSettings : IIndexerSettings + public class HDBitsSettings : NoAuthTorrentBaseSettings { private static readonly HDBitsSettingsValidator Validator = new HDBitsSettingsValidator(); @@ -23,9 +24,6 @@ namespace NzbDrone.Core.Indexers.HDBits Mediums = System.Array.Empty<int>(); } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] public string Username { get; set; } @@ -38,10 +36,7 @@ namespace NzbDrone.Core.Indexers.HDBits [FieldDefinition(5, Label = "Mediums", Type = FieldType.TagSelect, SelectOptions = typeof(HdBitsMedium), Advanced = true, HelpText = "Options: BluRay, Encode, Capture, Remux, WebDL. If unspecified, all options are used.")] public IEnumerable<int> Mediums { get; set; } - [FieldDefinition(6)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs b/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs index 8dead0def..14293fbd0 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs @@ -13,6 +13,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -21,7 +22,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class HDSpace : TorrentIndexerBase<HDSpaceSettings> + public class HDSpace : TorrentIndexerBase<UserPassTorrentBaseSettings> { public override string Name => "HD-Space"; public override string[] IndexerUrls => new string[] { "https://hd-space.org/" }; @@ -146,7 +147,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class HDSpaceRequestGenerator : IIndexerRequestGenerator { - public HDSpaceSettings Settings { get; set; } + public UserPassTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public HDSpaceRequestGenerator() @@ -228,10 +229,10 @@ namespace NzbDrone.Core.Indexers.Definitions public class HDSpaceParser : IParseIndexerResponse { - private readonly HDSpaceSettings _settings; + private readonly UserPassTorrentBaseSettings _settings; private readonly IndexerCapabilitiesCategories _categories; - public HDSpaceParser(HDSpaceSettings settings, IndexerCapabilitiesCategories categories) + public HDSpaceParser(UserPassTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; _categories = categories; @@ -313,41 +314,4 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - - public class HDSpaceSettingsValidator : AbstractValidator<HDSpaceSettings> - { - public HDSpaceSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class HDSpaceSettings : IIndexerSettings - { - private static readonly HDSpaceSettingsValidator Validator = new HDSpaceSettingsValidator(); - - public HDSpaceSettings() - { - Username = ""; - Password = ""; - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs index b17e0f518..0cb886afc 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDTorrents.cs @@ -12,6 +12,7 @@ using NLog; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -20,7 +21,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class HDTorrents : TorrentIndexerBase<HDTorrentsSettings> + public class HDTorrents : TorrentIndexerBase<UserPassTorrentBaseSettings> { public override string Name => "HD-Torrents"; @@ -140,7 +141,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class HDTorrentsRequestGenerator : IIndexerRequestGenerator { - public HDTorrentsSettings Settings { get; set; } + public UserPassTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public HDTorrentsRequestGenerator() @@ -219,7 +220,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class HDTorrentsParser : IParseIndexerResponse { - private readonly HDTorrentsSettings _settings; + private readonly UserPassTorrentBaseSettings _settings; private readonly IndexerCapabilitiesCategories _categories; private readonly Regex _posterRegex = new Regex(@"src=\\'./([^']+)\\'", RegexOptions.IgnoreCase); @@ -233,7 +234,7 @@ namespace NzbDrone.Core.Indexers.Definitions "Owner" }; - public HDTorrentsParser(HDTorrentsSettings settings, IndexerCapabilitiesCategories categories) + public HDTorrentsParser(UserPassTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; _categories = categories; @@ -356,41 +357,4 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - - public class HDTorrentsSettingsValidator : AbstractValidator<HDTorrentsSettings> - { - public HDTorrentsSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class HDTorrentsSettings : IIndexerSettings - { - private static readonly HDTorrentsSettingsValidator Validator = new HDTorrentsSettingsValidator(); - - public HDTorrentsSettings() - { - Username = ""; - Password = ""; - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs index 445a0980a..43c95e5cf 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs @@ -9,6 +9,7 @@ using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -348,38 +349,13 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - public class IPTorrentsSettingsValidator : AbstractValidator<IPTorrentsSettings> + public class IPTorrentsSettings : CookieTorrentBaseSettings { - public IPTorrentsSettingsValidator() - { - RuleFor(c => c.Cookie).NotEmpty(); - } - } - - public class IPTorrentsSettings : IIndexerSettings - { - private static readonly IPTorrentsSettingsValidator Validator = new IPTorrentsSettingsValidator(); - public IPTorrentsSettings() { - Cookie = ""; } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Cookie", HelpText = "Enter the cookie for the site. Example: `cf_clearance=0f7e7f10c62fd069323da10dcad545b828a44b6-1622730685-9-100; uid=123456789; pass=passhashwillbehere`", HelpLink = "https://wiki.servarr.com/prowlarr/faq#finding-cookies")] - public string Cookie { get; set; } - [FieldDefinition(3, Label = "FreeLeech Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Search Freeleech torrents only")] public bool FreeLeechOnly { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs b/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs index 4c370e31e..6eeb09599 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ImmortalSeed.cs @@ -13,6 +13,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -22,7 +23,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class ImmortalSeed : TorrentIndexerBase<ImmortalSeedSettings> + public class ImmortalSeed : TorrentIndexerBase<UserPassTorrentBaseSettings> { public override string Name => "ImmortalSeed"; @@ -161,7 +162,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class ImmortalSeedRequestGenerator : IIndexerRequestGenerator { - public ImmortalSeedSettings Settings { get; set; } + public UserPassTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public ImmortalSeedRequestGenerator() @@ -243,10 +244,10 @@ namespace NzbDrone.Core.Indexers.Definitions public class ImmortalSeedParser : IParseIndexerResponse { - private readonly ImmortalSeedSettings _settings; + private readonly UserPassTorrentBaseSettings _settings; private readonly IndexerCapabilitiesCategories _categories; - public ImmortalSeedParser(ImmortalSeedSettings settings, IndexerCapabilitiesCategories categories) + public ImmortalSeedParser(UserPassTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; _categories = categories; @@ -333,41 +334,4 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - - public class ImmortalSeedSettingsValidator : AbstractValidator<ImmortalSeedSettings> - { - public ImmortalSeedSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class ImmortalSeedSettings : IIndexerSettings - { - private static readonly ImmortalSeedSettingsValidator Validator = new ImmortalSeedSettingsValidator(); - - public ImmortalSeedSettings() - { - Username = ""; - Password = ""; - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs b/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs deleted file mode 100644 index f59b52f35..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/InternetArchive.cs +++ /dev/null @@ -1,330 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Net; -using Newtonsoft.Json; -using NLog; -using NzbDrone.Common.Extensions; -using NzbDrone.Common.Http; -using NzbDrone.Core.Annotations; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Indexers.Exceptions; -using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.Parser; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Validation; - -namespace NzbDrone.Core.Indexers.Definitions -{ - [Obsolete("Moved to YML for Cardigann v3")] - public class InternetArchive : TorrentIndexerBase<InternetArchiveSettings> - { - public override string Name => "Internet Archive"; - - public override string[] IndexerUrls => new string[] { "https://archive.org/" }; - - public override string Description => "Internet Archive is a non-profit library of millions of free books, movies, software, music, websites, and more."; - - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - - public override IndexerPrivacy Privacy => IndexerPrivacy.Public; - - public override IndexerCapabilities Capabilities => SetCapabilities(); - - public override bool FollowRedirect => true; - - public InternetArchive(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - public override IParseIndexerResponse GetParser() - { - return new InternetArchiveParser(Settings, Capabilities.Categories); - } - - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new InternetArchiveRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; - } - - private IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q - }, - BookSearchParams = new List<BookSearchParam> - { - BookSearchParam.Q - }, - MusicSearchParams = new List<MusicSearchParam> - { - MusicSearchParam.Q - } - }; - - // c.f. https://archive.org/services/docs/api/metadata-schema/index.html?highlight=mediatype#mediatype - // "Movies" is a catch all category for videos - caps.Categories.AddCategoryMapping("texts", NewznabStandardCategory.Books); - caps.Categories.AddCategoryMapping("etree", NewznabStandardCategory.Audio); - caps.Categories.AddCategoryMapping("audio", NewznabStandardCategory.Audio); - caps.Categories.AddCategoryMapping("movies", NewznabStandardCategory.Movies); - caps.Categories.AddCategoryMapping("movies", NewznabStandardCategory.TV); - caps.Categories.AddCategoryMapping("software", NewznabStandardCategory.PC); - caps.Categories.AddCategoryMapping("image", NewznabStandardCategory.OtherMisc); - caps.Categories.AddCategoryMapping("data", NewznabStandardCategory.Other); - caps.Categories.AddCategoryMapping("web", NewznabStandardCategory.Other); - caps.Categories.AddCategoryMapping("collection", NewznabStandardCategory.Other); - caps.Categories.AddCategoryMapping("account", NewznabStandardCategory.Other); - - caps.Categories.AddCategoryMapping("other", NewznabStandardCategory.Other); - return caps; - } - } - - public class InternetArchiveRequestGenerator : IIndexerRequestGenerator - { - public InternetArchiveSettings Settings { get; set; } - public IndexerCapabilities Capabilities { get; set; } - - public InternetArchiveRequestGenerator() - { - } - - private IEnumerable<IndexerRequest> GetPagedRequests(string searchTerm, SearchCriteriaBase searchCriteria) - { - var query = "format:(\"Archive BitTorrent\")"; - - if (searchTerm.IsNotNullOrWhiteSpace()) - { - if (Settings.TitleOnly) - { - query = string.Format("title:({0}) AND {1}", searchTerm, query); - } - else - { - query = string.Format("{0} AND {1}", searchTerm, query); - } - } - - var categories = Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories); - if (categories.Count > 0) - { - query = string.Format("{0} AND mediatype:({1})", query, string.Join(" OR ", categories)); - } - - string sortBy = (InternetArchiveSort)Settings.SortBy switch - { - InternetArchiveSort.PublicDate => "publicdate", - InternetArchiveSort.Downloads => "downloads", - InternetArchiveSort.Size => "item_size", - _ => "publicdate", - }; - - string sortOrder = (InternetArchiveSortOrder)Settings.SortOrder switch - { - InternetArchiveSortOrder.Descending => "desc", - InternetArchiveSortOrder.Ascending => "asc", - _ => "desc", - }; - - var parameters = new NameValueCollection - { - { "q", query }, - { "fields", "btih,downloads,identifier,item_size,mediatype,publicdate,title" }, - { "count", searchCriteria.Limit.GetValueOrDefault(100).ToString() }, // API default is 5000, don't think thats viable at all. - { "sorts", string.Format("{0} {1}", sortBy, sortOrder) } - }; - - var searchUrl = string.Format("{0}/services/search/v1/scrape?{1}", Settings.BaseUrl.TrimEnd('/'), parameters.GetQueryString()); - var request = new IndexerRequest(searchUrl, HttpAccept.Json); - - yield return request; - } - - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria)); - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria)); - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria)); - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria)); - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria)); - return pageableRequests; - } - - public Func<IDictionary<string, string>> GetCookies { get; set; } - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class InternetArchiveParser : IParseIndexerResponse - { - private readonly InternetArchiveSettings _settings; - private readonly IndexerCapabilitiesCategories _categories; - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - - public InternetArchiveParser(InternetArchiveSettings settings, IndexerCapabilitiesCategories categories) - { - _settings = settings; - _categories = categories; - } - - public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) - { - var torrentInfos = new List<TorrentInfo>(); - - if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) - { - throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request"); - } - - if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value)) - { - throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}"); - } - - var jsonResponse = new HttpResponse<InternetArchiveResponse>(indexerResponse.HttpResponse); - - foreach (var searchResult in jsonResponse.Resource.SearchResults) - { - var title = searchResult.Title ?? searchResult.Identifier; - - var downloadUrl = string.Format("{0}/download/{1}/{1}_archive.torrent", _settings.BaseUrl.TrimEnd('/'), searchResult.Identifier); - var detailsUrl = string.Format("{0}/details/{1}", _settings.BaseUrl.TrimEnd('/'), searchResult.Identifier); - - var category = _categories.MapTrackerCatToNewznab(searchResult.MediaType ?? "other"); - - var release = new TorrentInfo - { - Categories = category, - CommentUrl = detailsUrl, - DownloadUrl = downloadUrl, - DownloadVolumeFactor = 0, - Guid = detailsUrl, - Grabs = searchResult.Downloads, - InfoHash = searchResult.InfoHash, - InfoUrl = detailsUrl, - Peers = 2, - PublishDate = searchResult.PublicDate, - Seeders = 1, - Size = searchResult.Size, - Title = title, - UploadVolumeFactor = 1 - }; - - if (!_settings.TorrentFileOnly && searchResult.InfoHash != null) - { - release.MagnetUrl = MagnetLinkBuilder.BuildPublicMagnetLink(searchResult.InfoHash, title); - } - - torrentInfos.Add(release); - } - - return torrentInfos.ToArray(); - } - } - - public class InternetArchiveResponse - { - [JsonProperty(PropertyName = "items")] - public List<InternetArchiveTorrent> SearchResults { get; set; } - - public string Cursor { get; set; } - public int Count { get; set; } - public int Total { get; set; } - } - - public class InternetArchiveTorrent - { - public int Downloads { get; set; } - public string Identifier { get; set; } - - [JsonProperty(PropertyName = "btih")] - public string InfoHash { get; set; } - public string MediaType { get; set; } - public DateTime PublicDate { get; set; } - - [JsonProperty(PropertyName = "item_size")] - public long Size { get; set; } - public string Title { get; set; } - } - - public class InternetArchiveSettings : IIndexerSettings - { - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Sort By", Type = FieldType.Select, Advanced = true, SelectOptions = typeof(InternetArchiveSort), HelpText = "Field used to sort the search results.")] - public int SortBy { get; set; } - - [FieldDefinition(3, Label = "Sort Order", Type = FieldType.Select, Advanced = true, SelectOptions = typeof(InternetArchiveSortOrder), HelpText = "Order to use when sorting results.")] - public int SortOrder { get; set; } - - [FieldDefinition(4, Label = "Title Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Whether to search in title only.")] - public bool TitleOnly { get; set; } - - [FieldDefinition(5, Label = "Torrent File Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Only use torrent files, not magnet links.")] - public bool TorrentFileOnly { get; set; } - - [FieldDefinition(6)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public InternetArchiveSettings() - { - SortBy = (int)InternetArchiveSort.PublicDate; - SortOrder = (int)InternetArchiveSortOrder.Descending; - TitleOnly = false; - TorrentFileOnly = false; - } - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(); - } - } - - public enum InternetArchiveSort - { - PublicDate, - Downloads, - Size - } - - public enum InternetArchiveSortOrder - { - Descending, - Ascending - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/LatTeam.cs b/src/NzbDrone.Core/Indexers/Definitions/LatTeam.cs deleted file mode 100644 index 9874e8338..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/LatTeam.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System.Collections.Generic; -using NLog; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Indexers.Definitions.UNIT3D; -using NzbDrone.Core.Messaging.Events; - -namespace NzbDrone.Core.Indexers.Definitions -{ - public class LatTeam : Unit3dBase - { - public override string Name => "Lat-Team"; - public override string Language => "es"; - public override string[] IndexerUrls => new[] { "https://lat-team.com/" }; - public override string Description => "Lat-Team is a Private Torrent Tracker for HD MOVIES / TV"; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - - public LatTeam(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - protected override IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId - }, - MusicSearchParams = new List<MusicSearchParam> - { - MusicSearchParam.Q - }, - }; - - caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Peliculas"); - caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.MoviesOther, "Retro Pelicula"); - caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.TVAnime, "Anime"); - caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "TV Series"); - caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.TVOther, "Retro Serie TV"); - caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.TVForeign, "Telenovelas y Teleseries"); - caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Musica"); - - return caps; - } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Milkie.cs b/src/NzbDrone.Core/Indexers/Definitions/Milkie.cs deleted file mode 100644 index 89cbf2bad..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/Milkie.cs +++ /dev/null @@ -1,270 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using FluentValidation; -using Newtonsoft.Json; -using NLog; -using NzbDrone.Common.Http; -using NzbDrone.Core.Annotations; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.Parser; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Validation; - -namespace NzbDrone.Core.Indexers.Definitions -{ - [Obsolete("Moved to YML for Cardigann v3")] - public class Milkie : TorrentIndexerBase<MilkieSettings> - { - public override string Name => "Milkie"; - - public override string[] IndexerUrls => new string[] { "https://milkie.cc/" }; - public override string Description => "Milkie is a general tracker providing unpacked and 0day/0sec scene content."; - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public override IndexerCapabilities Capabilities => SetCapabilities(); - - public Milkie(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new MilkieRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; - } - - public override IParseIndexerResponse GetParser() - { - return new MilkieParser(Settings, Capabilities.Categories); - } - - private IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q - }, - MusicSearchParams = new List<MusicSearchParam> - { - MusicSearchParam.Q - }, - BookSearchParams = new List<BookSearchParam> - { - BookSearchParam.Q - } - }; - - caps.Categories.AddCategoryMapping("1", NewznabStandardCategory.Movies, "Movies"); - caps.Categories.AddCategoryMapping("2", NewznabStandardCategory.TV, "TV"); - caps.Categories.AddCategoryMapping("3", NewznabStandardCategory.Audio, "Music"); - caps.Categories.AddCategoryMapping("4", NewznabStandardCategory.PCGames, "Games"); - caps.Categories.AddCategoryMapping("5", NewznabStandardCategory.Books, "Ebook"); - caps.Categories.AddCategoryMapping("6", NewznabStandardCategory.PC, "Apps"); - caps.Categories.AddCategoryMapping("7", NewznabStandardCategory.XXX, "Adult"); - return caps; - } - } - - public class MilkieRequestGenerator : IIndexerRequestGenerator - { - public MilkieSettings Settings { get; set; } - public IndexerCapabilities Capabilities { get; set; } - - public MilkieRequestGenerator() - { - } - - private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null) - { - var searchUrl = Settings.BaseUrl + "api/v1/torrents"; - - var qc = new NameValueCollection - { - { "ps", "100" } - }; - - if (!string.IsNullOrWhiteSpace(term)) - { - qc.Add("query", term); - } - - if (categories != null && categories.Length > 0) - { - qc.Add("categories", string.Join(",", Capabilities.Categories.MapTorznabCapsToTrackers(categories))); - } - - searchUrl = searchUrl + "?" + qc.GetQueryString(); - - var request = new IndexerRequest(searchUrl, HttpAccept.Json); - - request.HttpRequest.Headers.Add("x-milkie-auth", Settings.ApiKey); - - yield return request; - } - - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public Func<IDictionary<string, string>> GetCookies { get; set; } - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class MilkieParser : IParseIndexerResponse - { - private readonly MilkieSettings _settings; - private readonly IndexerCapabilitiesCategories _categories; - - public MilkieParser(MilkieSettings settings, IndexerCapabilitiesCategories categories) - { - _settings = settings; - _categories = categories; - } - - public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) - { - var torrentInfos = new List<TorrentInfo>(); - - var response = JsonConvert.DeserializeObject<MilkieResponse>(indexerResponse.Content); - - var dlQueryParams = new NameValueCollection - { - { "key", _settings.ApiKey } - }; - - foreach (var torrent in response.Torrents) - { - var torrentUrl = _settings.BaseUrl + "api/v1/torrents"; - var link = $"{torrentUrl}/{torrent.Id}/torrent?{dlQueryParams.GetQueryString()}"; - var details = $"{_settings.BaseUrl}browse/{torrent.Id}"; - var publishDate = DateTimeUtil.FromUnknown(torrent.CreatedAt); - - var release = new TorrentInfo - { - Title = torrent.ReleaseName, - DownloadUrl = link, - InfoUrl = details, - Guid = details, - PublishDate = publishDate, - Categories = _categories.MapTrackerCatToNewznab(torrent.Category.ToString()), - Size = torrent.Size, - Seeders = torrent.Seeders, - Peers = torrent.Seeders + torrent.PartialSeeders + torrent.Leechers, - Grabs = torrent.Downloaded, - UploadVolumeFactor = 1, - DownloadVolumeFactor = 0, - MinimumRatio = 1, - MinimumSeedTime = 172800 // 48 hours - }; - - torrentInfos.Add(release); - } - - return torrentInfos.ToArray(); - } - - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class MilkieSettingsValidator : AbstractValidator<MilkieSettings> - { - public MilkieSettingsValidator() - { - RuleFor(c => c.ApiKey).NotEmpty(); - } - } - - public class MilkieSettings : IIndexerSettings - { - private static readonly MilkieSettingsValidator Validator = new MilkieSettingsValidator(); - - public MilkieSettings() - { - ApiKey = ""; - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "API Key", HelpText = "Site API Key", Privacy = PrivacyLevel.ApiKey)] - public string ApiKey { get; set; } - - [FieldDefinition(3)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } - - public class MilkieResponse - { - public int Hits { get; set; } - public int Took { get; set; } - public MilkieTorrent[] Torrents { get; set; } - } - - public class MilkieTorrent - { - public string Id { get; set; } - public string ReleaseName { get; set; } - public int Category { get; set; } - public int Downloaded { get; set; } - public int Seeders { get; set; } - public int PartialSeeders { get; set; } - public int Leechers { get; set; } - public long Size { get; set; } - public string CreatedAt { get; set; } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs b/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs index 3b7273447..2db6042c5 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs @@ -14,6 +14,7 @@ using NLog; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -22,7 +23,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions; -public class MoreThanTV : TorrentIndexerBase<MoreThanTVSettings> +public class MoreThanTV : TorrentIndexerBase<CookieTorrentBaseSettings> { public override string Name => "MoreThanTV"; public override string[] IndexerUrls => new[] { "https://www.morethantv.me/" }; @@ -74,12 +75,12 @@ public class MoreThanTV : TorrentIndexerBase<MoreThanTVSettings> public class MoreThanTVRequestGenerator : IIndexerRequestGenerator { - private MoreThanTVSettings Settings { get; } + private CookieTorrentBaseSettings Settings { get; } private IndexerCapabilities Capabilities { get; } private NameValueCollection BrowserHeaders { get; } - public MoreThanTVRequestGenerator(MoreThanTVSettings settings, IndexerCapabilities capabilities) + public MoreThanTVRequestGenerator(CookieTorrentBaseSettings settings, IndexerCapabilities capabilities) { Settings = settings; Capabilities = capabilities; @@ -170,7 +171,7 @@ public class MoreThanTVRequestGenerator : IIndexerRequestGenerator public class MoreThanTVParser : IParseIndexerResponse { - public MoreThanTVSettings Settings { get; init; } + public CookieTorrentBaseSettings Settings { get; init; } public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) { @@ -304,35 +305,3 @@ public class MoreThanTVParser : IParseIndexerResponse public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - -public class MoreThanTVSettingsValidator : AbstractValidator<MoreThanTVSettings> -{ - public MoreThanTVSettingsValidator() - { - RuleFor(c => c.Cookie).NotEmpty(); - } -} - -public class MoreThanTVSettings : IIndexerSettings -{ - private static readonly MoreThanTVSettingsValidator Validator = new (); - - public MoreThanTVSettings() - { - Cookie = ""; - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Cookie", HelpText = "Enter the cookies for the site, just copy everything after 'cookie:' from the request headers to the site", HelpLink = "https://wiki.servarr.com/prowlarr/faq#finding-cookies")] - public string Cookie { get; set; } - - [FieldDefinition(3)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs b/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs index 3af4df15a..6a476d815 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/MyAnonamouse.cs @@ -14,6 +14,7 @@ using NzbDrone.Common.Serializer; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -434,7 +435,7 @@ namespace NzbDrone.Core.Indexers.Definitions } } - public class MyAnonamouseSettings : IIndexerSettings + public class MyAnonamouseSettings : NoAuthTorrentBaseSettings { private static readonly MyAnonamouseSettingsValidator Validator = new MyAnonamouseSettingsValidator(); @@ -443,9 +444,6 @@ namespace NzbDrone.Core.Indexers.Definitions MamId = ""; } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "Mam Id", HelpText = "Mam Session Id (Created Under Preferences -> Security)")] public string MamId { get; set; } @@ -455,10 +453,7 @@ namespace NzbDrone.Core.Indexers.Definitions [FieldDefinition(4, Type = FieldType.Checkbox, Label = "Freeleech", HelpText = "Use freeleech token for download")] public bool Freeleech { get; set; } - [FieldDefinition(5)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs index 4d6d231c6..7613c74f6 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs @@ -12,6 +12,7 @@ using NLog; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -267,44 +268,14 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - public class NebulanceSettingsValidator : AbstractValidator<NebulanceSettings> + public class NebulanceSettings : UserPassTorrentBaseSettings { - public NebulanceSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class NebulanceSettings : IIndexerSettings - { - private static readonly NebulanceSettingsValidator Validator = new NebulanceSettingsValidator(); - public NebulanceSettings() { - Username = ""; - Password = ""; TwoFactorAuth = ""; } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - [FieldDefinition(4, Label = "Two Factor Auth", HelpText = "Two-Factor Auth")] public string TwoFactorAuth { get; set; } - - [FieldDefinition(5)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs b/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs index 392fedc67..d80e3b032 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/NorBits.cs @@ -16,6 +16,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -393,43 +394,13 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - public class NorBitsSettingsValidator : AbstractValidator<NorBitsSettings> + public class NorBitsSettings : UserPassTorrentBaseSettings { - public NorBitsSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class NorBitsSettings : IIndexerSettings - { - private static readonly NorBitsSettingsValidator Validator = new NorBitsSettingsValidator(); - public NorBitsSettings() { - Username = ""; - Password = ""; } - [FieldDefinition(1, Label = "Base Url", HelpText = "Select which baseurl Prowlarr will use for requests to the site", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - [FieldDefinition(4, Label = "Use Full Search", HelpText = "Use Full Search from Site", Type = FieldType.Checkbox)] public bool UseFullSearch { get; set; } - - [FieldDefinition(5)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornSettings.cs index d95988540..cf0ea42e5 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornSettings.cs @@ -1,5 +1,6 @@ using FluentValidation; using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.PassThePopcorn @@ -13,7 +14,7 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn } } - public class PassThePopcornSettings : IIndexerSettings + public class PassThePopcornSettings : NoAuthTorrentBaseSettings { private static readonly PassThePopcornSettingsValidator Validator = new PassThePopcornSettingsValidator(); @@ -21,19 +22,13 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn { } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "APIUser", HelpText = "These settings are found in your PassThePopcorn security settings (Edit Profile > Security).", Privacy = PrivacyLevel.UserName)] public string APIUser { get; set; } [FieldDefinition(3, Label = "API Key", HelpText = "Site API Key", Privacy = PrivacyLevel.ApiKey)] public string APIKey { get; set; } - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs b/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs index 1cd899998..8293a42c0 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs @@ -12,6 +12,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -420,43 +421,13 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - public class PornoLabSettingsValidator : AbstractValidator<PornoLabSettings> + public class PornoLabSettings : UserPassTorrentBaseSettings { - public PornoLabSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class PornoLabSettings : IIndexerSettings - { - private static readonly PornoLabSettingsValidator Validator = new PornoLabSettingsValidator(); - public PornoLabSettings() { - Username = ""; - Password = ""; } - [FieldDefinition(1, Label = "Base Url", HelpText = "Select which baseurl Prowlarr will use for requests to the site", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - [FieldDefinition(4, Label = "Strip Russian Letters", HelpLink = "Strip Cyrillic letters from release names", Type = FieldType.Checkbox)] public bool StripRussianLetters { get; set; } - - [FieldDefinition(5)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs b/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs index e80dbad09..8e9198486 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs @@ -13,6 +13,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -387,7 +388,7 @@ namespace NzbDrone.Core.Indexers.Definitions } } - public class PreToMeSettings : IIndexerSettings + public class PreToMeSettings : NoAuthTorrentBaseSettings { private static readonly PreToMeSettingsValidator Validator = new PreToMeSettingsValidator(); @@ -398,9 +399,6 @@ namespace NzbDrone.Core.Indexers.Definitions Password = ""; } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "Pin", HelpText = "Site Pin", Privacy = PrivacyLevel.Password)] public string Pin { get; set; } @@ -410,10 +408,7 @@ namespace NzbDrone.Core.Indexers.Definitions [FieldDefinition(4, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] public string Password { get; set; } - [FieldDefinition(5)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgSettings.cs index 20bd89811..6eef9727a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgSettings.cs @@ -1,40 +1,21 @@ using FluentValidation; using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Rarbg { - public class RarbgSettingsValidator : AbstractValidator<RarbgSettings> + public class RarbgSettings : NoAuthTorrentBaseSettings { - public RarbgSettingsValidator() - { - } - } - - public class RarbgSettings : IIndexerSettings - { - private static readonly RarbgSettingsValidator Validator = new RarbgSettingsValidator(); - public RarbgSettings() { RankedOnly = false; } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Type = FieldType.Checkbox, Label = "Ranked Only", HelpText = "Only include ranked results.")] public bool RankedOnly { get; set; } [FieldDefinition(3, Type = FieldType.Captcha, Label = "CAPTCHA Token", HelpText = "CAPTCHA Clearance token used to handle CloudFlare Anti-DDOS measures on shared-ip VPNs.")] public string CaptchaToken { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs b/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs index bc6e8a7fd..e33077de8 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs @@ -13,6 +13,7 @@ using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Gazelle; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser.Model; @@ -338,7 +339,7 @@ namespace NzbDrone.Core.Indexers.Definitions } } - public class RedactedSettings : IIndexerSettings + public class RedactedSettings : NoAuthTorrentBaseSettings { private static readonly RedactedSettingsValidator Validator = new RedactedSettingsValidator(); @@ -349,21 +350,15 @@ namespace NzbDrone.Core.Indexers.Definitions UseFreeleechToken = false; } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "API Key", HelpText = "API Key from the Site (Found in Settings => Access Settings)", Privacy = PrivacyLevel.ApiKey)] public string Apikey { get; set; } [FieldDefinition(3, Label = "Use Freeleech Tokens", HelpText = "Use freeleech tokens when available", Type = FieldType.Checkbox)] public bool UseFreeleechToken { get; set; } - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - public string Passkey { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs b/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs index 7c48ab38f..8c0268708 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs @@ -13,6 +13,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -21,7 +22,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class RevolutionTT : TorrentIndexerBase<RevolutionTTSettings> + public class RevolutionTT : TorrentIndexerBase<UserPassTorrentBaseSettings> { public override string Name => "RevolutionTT"; @@ -154,7 +155,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class RevolutionTTRequestGenerator : IIndexerRequestGenerator { - public RevolutionTTSettings Settings { get; set; } + public UserPassTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public RevolutionTTRequestGenerator() @@ -247,10 +248,10 @@ namespace NzbDrone.Core.Indexers.Definitions public class RevolutionTTParser : IParseIndexerResponse { - private readonly RevolutionTTSettings _settings; + private readonly UserPassTorrentBaseSettings _settings; private readonly IndexerCapabilitiesCategories _categories; - public RevolutionTTParser(RevolutionTTSettings settings, IndexerCapabilitiesCategories categories) + public RevolutionTTParser(UserPassTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; _categories = categories; @@ -327,41 +328,4 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - - public class RevolutionTTSettingsValidator : AbstractValidator<RevolutionTTSettings> - { - public RevolutionTTSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class RevolutionTTSettings : IIndexerSettings - { - private static readonly RevolutionTTSettingsValidator Validator = new RevolutionTTSettingsValidator(); - - public RevolutionTTSettings() - { - Username = ""; - Password = ""; - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs index 8e93bace9..81ab51813 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs @@ -14,6 +14,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -1728,44 +1729,14 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - public class RuTrackerSettingsValidator : AbstractValidator<RuTrackerSettings> + public class RuTrackerSettings : UserPassTorrentBaseSettings { - public RuTrackerSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class RuTrackerSettings : IIndexerSettings - { - private static readonly RuTrackerSettingsValidator Validator = new RuTrackerSettingsValidator(); - public RuTrackerSettings() { - Username = ""; - Password = ""; RussianLetters = false; } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", Advanced = false, HelpText = "Site Username")] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password, HelpText = "Site Password")] - public string Password { get; set; } - [FieldDefinition(4, Label = "Strip Russian letters", Type = FieldType.Checkbox, SelectOptionsProviderAction = "stripRussian", HelpText = "Removes russian letters")] public bool RussianLetters { get; set; } - - [FieldDefinition(5)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/SceneHD.cs b/src/NzbDrone.Core/Indexers/Definitions/SceneHD.cs index 273884a69..28c479133 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SceneHD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SceneHD.cs @@ -12,6 +12,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -240,7 +241,7 @@ namespace NzbDrone.Core.Indexers.Definitions } } - public class SceneHDSettings : IIndexerSettings + public class SceneHDSettings : NoAuthTorrentBaseSettings { private static readonly SceneHDSettingsValidator Validator = new SceneHDSettingsValidator(); @@ -249,16 +250,10 @@ namespace NzbDrone.Core.Indexers.Definitions Passkey = ""; } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "Passkey", Advanced = false, HelpText = "Site Passkey")] public string Passkey { get; set; } - [FieldDefinition(3)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs b/src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs index 890881000..13f8dab30 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SceneTime.cs @@ -11,6 +11,7 @@ using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -277,38 +278,13 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - public class SceneTimeSettingsValidator : AbstractValidator<SceneTimeSettings> + public class SceneTimeSettings : CookieTorrentBaseSettings { - public SceneTimeSettingsValidator() - { - RuleFor(c => c.Cookie).NotEmpty(); - } - } - - public class SceneTimeSettings : IIndexerSettings - { - private static readonly SceneTimeSettingsValidator Validator = new SceneTimeSettingsValidator(); - public SceneTimeSettings() { - Cookie = ""; } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Cookie", HelpText = "Login cookie from website")] - public string Cookie { get; set; } - [FieldDefinition(3, Label = "FreeLeech Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Search Freeleech torrents only")] public bool FreeLeechOnly { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs b/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs deleted file mode 100644 index 1a289e8b6..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Generic; -using NLog; -using NzbDrone.Common.Http; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Indexers.Definitions.UNIT3D; -using NzbDrone.Core.Messaging.Events; - -namespace NzbDrone.Core.Indexers.Definitions -{ - [Obsolete("Moved to YML for Cardigann v3")] - public class ShareIsland : Unit3dBase - { - public override string Name => "ShareIsland"; - public override string[] IndexerUrls => new string[] { "https://shareisland.org/" }; - public override string Description => "A general italian tracker."; - public override string Language => "it-IT"; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - - public ShareIsland(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - protected override IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId - }, - MusicSearchParams = new List<MusicSearchParam> - { - MusicSearchParam.Q - }, - BookSearchParams = new List<BookSearchParam> - { - BookSearchParam.Q - } - }; - - caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movie"); - caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "Serie TV"); - caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.BooksEBook, "Ebook"); - caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.BooksMags, "Riviste e Giornali"); - caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.XXX, "XXX"); - caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Music"); - caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.PCGames, "Games"); - caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.PC, "Software"); - - return caps; - } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Shizaproject.cs b/src/NzbDrone.Core/Indexers/Definitions/Shizaproject.cs index deff683cb..573514c60 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Shizaproject.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Shizaproject.cs @@ -10,6 +10,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -18,7 +19,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class Shizaproject : TorrentIndexerBase<ShizaprojectSettings> + public class Shizaproject : TorrentIndexerBase<NoAuthTorrentBaseSettings> { public override string Name => "ShizaProject"; public override string[] IndexerUrls => new string[] { "https://shiza-project.com/" }; @@ -69,7 +70,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class ShizaprojectRequestGenerator : IIndexerRequestGenerator { - public ShizaprojectSettings Settings { get; set; } + public NoAuthTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public ShizaprojectRequestGenerator() @@ -172,10 +173,10 @@ namespace NzbDrone.Core.Indexers.Definitions public class ShizaprojectParser : IParseIndexerResponse { - private readonly ShizaprojectSettings _settings; + private readonly NoAuthTorrentBaseSettings _settings; private readonly IndexerCapabilitiesCategories _categories; - public ShizaprojectParser(ShizaprojectSettings settings, IndexerCapabilitiesCategories categories) + public ShizaprojectParser(NoAuthTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; _categories = categories; @@ -266,29 +267,6 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - public class ShizaprojectSettingsValidator : AbstractValidator<ShizaprojectSettings> - { - public ShizaprojectSettingsValidator() - { - } - } - - public class ShizaprojectSettings : IIndexerSettings - { - private static readonly ShizaprojectSettingsValidator Validator = new ShizaprojectSettingsValidator(); - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } - public class ShizaprojectReleasesResponse { public ShizaprojectData Data { get; set; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs b/src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs index 6791b4276..5c4508665 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs @@ -8,6 +8,7 @@ using NLog; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser.Model; @@ -16,7 +17,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class ShowRSS : TorrentIndexerBase<ShowRSSSettings> + public class ShowRSS : TorrentIndexerBase<NoAuthTorrentBaseSettings> { public override string Name => "ShowRSS"; public override string[] IndexerUrls => new string[] { "https://showrss.info/" }; @@ -62,7 +63,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class ShowRSSRequestGenerator : IIndexerRequestGenerator { - public ShowRSSSettings Settings { get; set; } + public NoAuthTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public ShowRSSRequestGenerator() @@ -123,10 +124,10 @@ namespace NzbDrone.Core.Indexers.Definitions public class ShowRSSParser : IParseIndexerResponse { - private readonly ShowRSSSettings _settings; + private readonly NoAuthTorrentBaseSettings _settings; private string BrowseUrl => _settings.BaseUrl + "browse/"; - public ShowRSSParser(ShowRSSSettings settings) + public ShowRSSParser(NoAuthTorrentBaseSettings settings) { _settings = settings; } @@ -179,24 +180,4 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - - public class ShowRSSSettingsValidator : AbstractValidator<ShowRSSSettings> - { - } - - public class ShowRSSSettings : IIndexerSettings - { - private static readonly ShowRSSSettingsValidator Validator = new ShowRSSSettingsValidator(); - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs index 67e393e39..2bd83027b 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs @@ -16,6 +16,7 @@ using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Exceptions; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -406,7 +407,7 @@ namespace NzbDrone.Core.Indexers.Definitions } } - public class SpeedAppSettings : IIndexerSettings + public class SpeedAppSettings : NoAuthTorrentBaseSettings { private static readonly SpeedAppSettingsValidator Validator = new (); @@ -416,9 +417,6 @@ namespace NzbDrone.Core.Indexers.Definitions Password = ""; } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "Email", HelpText = "Site Email", Privacy = PrivacyLevel.UserName)] public string Email { get; set; } @@ -428,10 +426,7 @@ namespace NzbDrone.Core.Indexers.Definitions [FieldDefinition(4, Label = "API Key", Hidden = HiddenType.Hidden)] public string ApiKey { get; set; } - [FieldDefinition(5)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs index 04b176a0a..dac4e810b 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedCD.cs @@ -14,6 +14,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -22,7 +23,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class SpeedCD : TorrentIndexerBase<SpeedCDSettings> + public class SpeedCD : TorrentIndexerBase<UserPassTorrentBaseSettings> { public override string Name => "SpeedCD"; public override string[] IndexerUrls => new string[] @@ -181,7 +182,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class SpeedCDRequestGenerator : IIndexerRequestGenerator { - public SpeedCDSettings Settings { get; set; } + public UserPassTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public Encoding Encoding { get; set; } @@ -271,10 +272,10 @@ namespace NzbDrone.Core.Indexers.Definitions public class SpeedCDParser : IParseIndexerResponse { - private readonly SpeedCDSettings _settings; + private readonly UserPassTorrentBaseSettings _settings; private readonly IndexerCapabilitiesCategories _categories; - public SpeedCDParser(SpeedCDSettings settings, IndexerCapabilitiesCategories categories) + public SpeedCDParser(UserPassTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; _categories = categories; @@ -332,41 +333,4 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - - public class SpeedCDSettingsValidator : AbstractValidator<SpeedCDSettings> - { - public SpeedCDSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class SpeedCDSettings : IIndexerSettings - { - private static readonly SpeedCDSettingsValidator Validator = new SpeedCDSettingsValidator(); - - public SpeedCDSettings() - { - Username = ""; - Password = ""; - } - - [FieldDefinition(1, Label = "Base Url", HelpText = "Select which baseurl Prowlarr will use for requests to the site", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/SubsPlease.cs b/src/NzbDrone.Core/Indexers/Definitions/SubsPlease.cs index 6c55b795c..969c65b7e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SubsPlease.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SubsPlease.cs @@ -11,6 +11,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -19,7 +20,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class SubsPlease : TorrentIndexerBase<SubsPleaseSettings> + public class SubsPlease : TorrentIndexerBase<NoAuthTorrentBaseSettings> { public override string Name => "SubsPlease"; public override string[] IndexerUrls => new[] @@ -67,7 +68,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class SubsPleaseRequestGenerator : IIndexerRequestGenerator { - public SubsPleaseSettings Settings { get; set; } + public NoAuthTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } private IEnumerable<IndexerRequest> GetSearchRequests(string term) @@ -159,10 +160,10 @@ namespace NzbDrone.Core.Indexers.Definitions public class SubsPleaseParser : IParseIndexerResponse { - private readonly SubsPleaseSettings _settings; + private readonly NoAuthTorrentBaseSettings _settings; private readonly IndexerCapabilitiesCategories _categories; - public SubsPleaseParser(SubsPleaseSettings settings, IndexerCapabilitiesCategories categories) + public SubsPleaseParser(NoAuthTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; _categories = categories; @@ -237,26 +238,6 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - public class SubsPleaseSettingsValidator : AbstractValidator<SubsPleaseSettings> - { - } - - public class SubsPleaseSettings : IIndexerSettings - { - private static readonly SubsPleaseSettingsValidator Validator = new SubsPleaseSettingsValidator(); - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } - public class SubPleaseRelease { public string Time { get; set; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs b/src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs deleted file mode 100644 index 46fc865a1..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/SuperBits.cs +++ /dev/null @@ -1,354 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Globalization; -using System.Linq; -using FluentValidation; -using Newtonsoft.Json; -using NLog; -using NzbDrone.Common.Extensions; -using NzbDrone.Common.Http; -using NzbDrone.Core.Annotations; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.Parser; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Validation; - -namespace NzbDrone.Core.Indexers.Definitions -{ - [Obsolete("Moved to YML for Cardigann v3")] - public class SuperBits : TorrentIndexerBase<SuperBitsSettings> - { - public override string Name => "SuperBits"; - - public override string[] IndexerUrls => new string[] { "https://superbits.org/" }; - public override string Description => "Superbits is a SWEDISH Private Torrent Tracker for MOVIES / TV / GENERAL"; - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public override IndexerCapabilities Capabilities => SetCapabilities(); - - public SuperBits(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new SuperBitsRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; - } - - public override IParseIndexerResponse GetParser() - { - return new SuperBitsParser(Settings, Capabilities.Categories); - } - - protected override IDictionary<string, string> GetCookies() - { - return CookieUtil.CookieHeaderToDictionary(Settings.Cookie); - } - - private IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q, MovieSearchParam.ImdbId - }, - MusicSearchParams = new List<MusicSearchParam> - { - MusicSearchParam.Q - }, - BookSearchParams = new List<BookSearchParam> - { - BookSearchParam.Q - } - }; - - caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesDVD, "DVD-R Swesub"); - caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "DVD-R TV"); - caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.BooksEBook, "eBok"); - caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.MoviesHD, "Film 1080"); - caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Movies3D, "Film 3D"); - caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.MoviesHD, "Film 720"); - caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.MoviesBluRay, "Film Bluray"); - caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.TV, "Svensk TV"); - caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.AudioAudiobook, "Ljudböcker"); - caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.AudioVideo, "Musikvideos"); - caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.BooksMags, "E-tidningar"); - caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.Audio, "Musik"); - caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.Other, "Omslag"); - caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.Other, "Övrigt"); - caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.PCGames, "PC-Spel"); - caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.PC0day, "Program"); - caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.ConsolePS3, "PS3"); - caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.TV, "TV"); - caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.ConsoleWii, "Wii"); - caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.ConsoleXBox, "Xbox"); - caps.Categories.AddCategoryMapping(21, NewznabStandardCategory.MoviesOther, "Xvid"); - caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.XXX, "XXX"); - caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.MoviesUHD, "Film 4K"); - caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.TV, "TV DK"); - caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.TV, "TV NO"); - caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.TV, "TV FI"); - return caps; - } - } - - public class SuperBitsRequestGenerator : IIndexerRequestGenerator - { - public SuperBitsSettings Settings { get; set; } - public IndexerCapabilities Capabilities { get; set; } - - public SuperBitsRequestGenerator() - { - } - - private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null) - { - var searchUrl = Settings.BaseUrl + "api/v1/torrents"; - - // And this was option one from - // https://github.com/Jackett/Jackett/pull/7166#discussion_r376817517 - var queryCollection = new NameValueCollection(); - var searchString = term; - - queryCollection.Add("extendedSearch", "false"); - queryCollection.Add("freeleech", "false"); - queryCollection.Add("index", "0"); - queryCollection.Add("limit", "100"); - queryCollection.Add("order", "desc"); - queryCollection.Add("page", "search"); - - if (imdbId.IsNotNullOrWhiteSpace()) - { - queryCollection.Add("searchText", imdbId); - } - else - { - queryCollection.Add("searchText", searchString); - } - - queryCollection.Add("sort", "d"); - queryCollection.Add("section", "all"); - queryCollection.Add("stereoscopic", "false"); - queryCollection.Add("sweaudio", "false"); - queryCollection.Add("swesub", "false"); - queryCollection.Add("watchview", "false"); - - searchUrl += "?" + queryCollection.GetQueryString(); - - foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories)) - { - searchUrl += "&categories[]=" + cat; - } - - var request = new IndexerRequest(searchUrl, HttpAccept.Json); - - request.HttpRequest.Headers.Add("Referer", Settings.BaseUrl); - - yield return request; - } - - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public Func<IDictionary<string, string>> GetCookies { get; set; } - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class SuperBitsParser : IParseIndexerResponse - { - private readonly SuperBitsSettings _settings; - private readonly IndexerCapabilitiesCategories _categories; - - public SuperBitsParser(SuperBitsSettings settings, IndexerCapabilitiesCategories categories) - { - _settings = settings; - _categories = categories; - } - - public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) - { - var torrentInfos = new List<TorrentInfo>(); - - var json = JsonConvert.DeserializeObject<dynamic>(indexerResponse.Content); - foreach (var row in json ?? Enumerable.Empty<dynamic>()) - { - var release = new TorrentInfo(); - var descriptions = new List<string>(); - var tags = new List<string>(); - - release.MinimumRatio = 1.1; - release.MinimumSeedTime = 172800; // 48 hours - release.Title = row.name; - release.Categories = _categories.MapTrackerCatToNewznab(row.category.ToString()); - release.Size = row.size; - release.Seeders = row.seeders; - release.Peers = row.leechers + release.Seeders; - release.PublishDate = DateTime.ParseExact(row.added.ToString() + " +01:00", "yyyy-MM-dd HH:mm:ss zzz", CultureInfo.InvariantCulture); - release.Files = row.numfiles; - release.Grabs = row.times_completed; - - release.InfoUrl = _settings.BaseUrl + "torrent/" + row.id.ToString() + "/"; - release.Guid = release.InfoUrl; - release.DownloadUrl = _settings.BaseUrl + "api/v1/torrents/download/" + row.id.ToString(); - - if (row.frileech == 1) - { - release.DownloadVolumeFactor = 0; - } - else - { - release.DownloadVolumeFactor = 1; - } - - release.UploadVolumeFactor = 1; - - if (!string.IsNullOrWhiteSpace(row.customcover.ToString())) - { - release.PosterUrl = _settings.BaseUrl + row.customcover; - } - - if (row.imdbid2 != null && row.imdbid2.ToString().StartsWith("tt")) - { - release.ImdbId = ParseUtil.CoerceInt(row.imdbid2.ToString().Substring(2)); - descriptions.Add("Title: " + row.title); - descriptions.Add("Year: " + row.year); - descriptions.Add("Genres: " + row.genres); - descriptions.Add("Tagline: " + row.tagline); - descriptions.Add("Cast: " + row.cast); - descriptions.Add("Rating: " + row.rating); - descriptions.Add("Plot: " + row.plot); - - release.PosterUrl = _settings.BaseUrl + "img/imdb/" + row.imdbid2 + ".jpg"; - } - - if ((int)row.p2p == 1) - { - tags.Add("P2P"); - } - - if ((int)row.pack == 1) - { - tags.Add("Pack"); - } - - if ((int)row.reqid != 0) - { - tags.Add("Request"); - } - - if ((int)row.sweaudio != 0) - { - tags.Add("Swedish audio"); - } - - if ((int)row.swesub != 0) - { - tags.Add("Swedish subtitles"); - } - - if (tags.Count > 0) - { - descriptions.Add("Tags: " + string.Join(", ", tags)); - } - - var preDate = row.preDate.ToString(); - if (!string.IsNullOrWhiteSpace(preDate) && preDate != "1970-01-01 01:00:00") - { - descriptions.Add("PRE: " + preDate); - } - - descriptions.Add("Section: " + row.section); - - //release.Description = string.Join("<br>\n", descriptions); - torrentInfos.Add(release); - } - - return torrentInfos.ToArray(); - } - - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class SuperBitsSettingsValidator : AbstractValidator<SuperBitsSettings> - { - public SuperBitsSettingsValidator() - { - RuleFor(c => c.Cookie).NotEmpty(); - } - } - - public class SuperBitsSettings : IIndexerSettings - { - private static readonly SuperBitsSettingsValidator Validator = new SuperBitsSettingsValidator(); - - public SuperBitsSettings() - { - Cookie = ""; - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Cookie", HelpText = "Site Cookie")] - public string Cookie { get; set; } - - [FieldDefinition(3)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs b/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs index 1d56f6110..01f3359ba 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TVVault.cs @@ -15,6 +15,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -24,7 +25,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { [Obsolete("Remove per Site Request Prowlarr Issue 573")] - public class TVVault : TorrentIndexerBase<TVVaultSettings> + public class TVVault : TorrentIndexerBase<UserPassTorrentBaseSettings> { public override string Name => "TVVault"; public override string[] IndexerUrls => new[] { "https://tv-vault.me/" }; @@ -136,7 +137,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class TVVaultRequestGenerator : IIndexerRequestGenerator { - public TVVaultSettings Settings { get; set; } + public UserPassTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public string BaseUrl { get; set; } @@ -230,10 +231,10 @@ namespace NzbDrone.Core.Indexers.Definitions public class TVVaultParser : IParseIndexerResponse { - private readonly TVVaultSettings _settings; + private readonly UserPassTorrentBaseSettings _settings; private readonly IndexerCapabilitiesCategories _categories; - public TVVaultParser(TVVaultSettings settings, IndexerCapabilitiesCategories categories) + public TVVaultParser(UserPassTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; _categories = categories; @@ -304,41 +305,4 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - - public class TVVaultSettingsValidator : AbstractValidator<TVVaultSettings> - { - public TVVaultSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class TVVaultSettings : IIndexerSettings - { - private static readonly TVVaultSettingsValidator Validator = new TVVaultSettingsValidator(); - - public TVVaultSettings() - { - Username = ""; - Password = ""; - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs b/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs deleted file mode 100644 index 7f937a98a..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/ThePirateBay.cs +++ /dev/null @@ -1,322 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Linq; -using System.Text; -using Newtonsoft.Json; -using NLog; -using NzbDrone.Common.Http; -using NzbDrone.Core.Annotations; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.Parser; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Validation; - -namespace NzbDrone.Core.Indexers.Definitions -{ - [Obsolete("Moved to YML for Cardigann v3")] - public class ThePirateBay : TorrentIndexerBase<ThePirateBaySettings> - { - public override string Name => "ThePirateBay"; - public override string[] IndexerUrls => new string[] { "https://thepiratebay.org/" }; - public override string Description => "Pirate Bay(TPB) is the galaxy’s most resilient Public BitTorrent site"; - public override string Language => "en-US"; - public override Encoding Encoding => Encoding.UTF8; - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerPrivacy Privacy => IndexerPrivacy.Public; - public override IndexerCapabilities Capabilities => SetCapabilities(); - - public ThePirateBay(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new ThePirateBayRequestGenerator() { Capabilities = Capabilities }; - } - - public override IParseIndexerResponse GetParser() - { - return new ThePirateBayParser(Capabilities.Categories, Settings); - } - - private IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q - }, - MusicSearchParams = new List<MusicSearchParam> - { - MusicSearchParam.Q - }, - BookSearchParams = new List<BookSearchParam> - { - BookSearchParam.Q - } - }; - - caps.Categories.AddCategoryMapping(100, NewznabStandardCategory.Audio, "Audio"); - caps.Categories.AddCategoryMapping(101, NewznabStandardCategory.Audio, "Music"); - caps.Categories.AddCategoryMapping(102, NewznabStandardCategory.AudioAudiobook, "Audio Books"); - caps.Categories.AddCategoryMapping(103, NewznabStandardCategory.Audio, "Sound Clips"); - caps.Categories.AddCategoryMapping(104, NewznabStandardCategory.AudioLossless, "FLAC"); - caps.Categories.AddCategoryMapping(199, NewznabStandardCategory.AudioOther, "Audio Other"); - caps.Categories.AddCategoryMapping(200, NewznabStandardCategory.Movies, "Video"); - caps.Categories.AddCategoryMapping(201, NewznabStandardCategory.Movies, "Movies"); - caps.Categories.AddCategoryMapping(202, NewznabStandardCategory.Movies, "Movies"); - caps.Categories.AddCategoryMapping(203, NewznabStandardCategory.AudioVideo, "Music Videos"); - caps.Categories.AddCategoryMapping(204, NewznabStandardCategory.MoviesOther, "Movie Clips"); - caps.Categories.AddCategoryMapping(205, NewznabStandardCategory.TV, "TV"); - caps.Categories.AddCategoryMapping(206, NewznabStandardCategory.TVOther, "Handheld"); - caps.Categories.AddCategoryMapping(207, NewznabStandardCategory.MoviesHD, "HD - Movies"); - caps.Categories.AddCategoryMapping(208, NewznabStandardCategory.TVHD, "HD - TV shows"); - caps.Categories.AddCategoryMapping(209, NewznabStandardCategory.Movies3D, "3D"); - caps.Categories.AddCategoryMapping(299, NewznabStandardCategory.MoviesOther, "Video Other"); - caps.Categories.AddCategoryMapping(300, NewznabStandardCategory.PC, "Applications"); - caps.Categories.AddCategoryMapping(301, NewznabStandardCategory.PC, "Windows"); - caps.Categories.AddCategoryMapping(302, NewznabStandardCategory.PCMac, "Mac"); - caps.Categories.AddCategoryMapping(303, NewznabStandardCategory.PC, "UNIX"); - caps.Categories.AddCategoryMapping(304, NewznabStandardCategory.PCMobileOther, "Handheld"); - caps.Categories.AddCategoryMapping(305, NewznabStandardCategory.PCMobileiOS, "IOS (iPad/iPhone)"); - caps.Categories.AddCategoryMapping(306, NewznabStandardCategory.PCMobileAndroid, "Android"); - caps.Categories.AddCategoryMapping(399, NewznabStandardCategory.PC, "Other OS"); - caps.Categories.AddCategoryMapping(400, NewznabStandardCategory.Console, "Games"); - caps.Categories.AddCategoryMapping(401, NewznabStandardCategory.PCGames, "PC"); - caps.Categories.AddCategoryMapping(402, NewznabStandardCategory.PCMac, "Mac"); - caps.Categories.AddCategoryMapping(403, NewznabStandardCategory.ConsolePS4, "PSx"); - caps.Categories.AddCategoryMapping(404, NewznabStandardCategory.ConsoleXBox, "XBOX360"); - caps.Categories.AddCategoryMapping(405, NewznabStandardCategory.ConsoleWii, "Wii"); - caps.Categories.AddCategoryMapping(406, NewznabStandardCategory.ConsoleOther, "Handheld"); - caps.Categories.AddCategoryMapping(407, NewznabStandardCategory.ConsoleOther, "IOS (iPad/iPhone)"); - caps.Categories.AddCategoryMapping(408, NewznabStandardCategory.ConsoleOther, "Android"); - caps.Categories.AddCategoryMapping(499, NewznabStandardCategory.ConsoleOther, "Games Other"); - caps.Categories.AddCategoryMapping(500, NewznabStandardCategory.XXX, "Porn"); - caps.Categories.AddCategoryMapping(501, NewznabStandardCategory.XXX, "Movies"); - caps.Categories.AddCategoryMapping(502, NewznabStandardCategory.XXXDVD, "Movies DVDR"); - caps.Categories.AddCategoryMapping(503, NewznabStandardCategory.XXXImageSet, "Pictures"); - caps.Categories.AddCategoryMapping(504, NewznabStandardCategory.XXX, "Games"); - caps.Categories.AddCategoryMapping(505, NewznabStandardCategory.XXX, "HD - Movies"); - caps.Categories.AddCategoryMapping(506, NewznabStandardCategory.XXX, "Movie Clips"); - caps.Categories.AddCategoryMapping(599, NewznabStandardCategory.XXXOther, "Porn other"); - caps.Categories.AddCategoryMapping(600, NewznabStandardCategory.Other, "Other"); - caps.Categories.AddCategoryMapping(601, NewznabStandardCategory.Books, "E-books"); - caps.Categories.AddCategoryMapping(602, NewznabStandardCategory.BooksComics, "Comics"); - caps.Categories.AddCategoryMapping(603, NewznabStandardCategory.Books, "Pictures"); - caps.Categories.AddCategoryMapping(604, NewznabStandardCategory.Books, "Covers"); - caps.Categories.AddCategoryMapping(605, NewznabStandardCategory.Books, "Physibles"); - caps.Categories.AddCategoryMapping(699, NewznabStandardCategory.BooksOther, "Other Other"); - - return caps; - } - } - - public class ThePirateBayRequestGenerator : IIndexerRequestGenerator - { - public IndexerCapabilities Capabilities { get; set; } - - private static string ApiUrl => "https://apibay.org/"; - - public ThePirateBayRequestGenerator() - { - } - - private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, bool rssSearch) - { - if (rssSearch) - { - yield return new IndexerRequest($"{ApiUrl.TrimEnd('/')}/precompiled/data_top100_recent.json", HttpAccept.Html); - } - else - { - var cats = Capabilities.Categories.MapTorznabCapsToTrackers(categories); - - var queryStringCategories = string.Join( - ",", - cats.Count == 0 - ? Capabilities.Categories.GetTrackerCategories() - : cats); - - var queryCollection = new NameValueCollection - { - { "q", term }, - { "cat", queryStringCategories } - }; - - var searchUrl = string.Format("{0}/q.php?{1}", ApiUrl.TrimEnd('/'), queryCollection.GetQueryString()); - - var request = new IndexerRequest(searchUrl, HttpAccept.Json); - - yield return request; - } - } - - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.RssSearch)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.RssSearch)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.RssSearch)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.RssSearch)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.RssSearch)); - - return pageableRequests; - } - - public Func<IDictionary<string, string>> GetCookies { get; set; } - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class ThePirateBayParser : IParseIndexerResponse - { - private readonly ThePirateBaySettings _settings; - private readonly IndexerCapabilitiesCategories _categories; - - public ThePirateBayParser(IndexerCapabilitiesCategories categories, ThePirateBaySettings settings) - { - _settings = settings; - _categories = categories; - } - - public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) - { - var torrentInfos = new List<ReleaseInfo>(); - - var queryResponseItems = JsonConvert.DeserializeObject<List<ThePirateBayTorrent>>(indexerResponse.Content); - - // The API returns a single item to represent a state of no results. Avoid returning this result. - if (queryResponseItems.Count == 1 && queryResponseItems.First().Id == 0) - { - return torrentInfos; - } - - foreach (var item in queryResponseItems) - { - var details = item.Id == 0 ? null : $"{_settings.BaseUrl}description.php?id={item.Id}"; - var imdbId = string.IsNullOrEmpty(item.Imdb) ? null : ParseUtil.GetImdbID(item.Imdb); - var torrentItem = new TorrentInfo - { - Title = item.Name, - Categories = _categories.MapTrackerCatToNewznab(item.Category.ToString()), - Guid = details, - InfoUrl = details, - InfoHash = item.InfoHash, // magnet link is auto generated from infohash - PublishDate = DateTimeUtil.UnixTimestampToDateTime(item.Added), - Seeders = item.Seeders, - Peers = item.Seeders + item.Leechers, - Size = item.Size, - Files = item.NumFiles, - DownloadVolumeFactor = 0, - UploadVolumeFactor = 1, - ImdbId = imdbId.GetValueOrDefault() - }; - - if (item.InfoHash != null) - { - torrentItem.MagnetUrl = MagnetLinkBuilder.BuildPublicMagnetLink(item.InfoHash, item.Name); - } - - torrentInfos.Add(torrentItem); - } - - return torrentInfos.ToArray(); - } - - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class ThePirateBaySettings : IIndexerSettings - { - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(); - } - } - - public class ThePirateBayTorrent - { - [JsonProperty("id")] - public long Id { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("info_hash")] - public string InfoHash { get; set; } - - [JsonProperty("leechers")] - public int Leechers { get; set; } - - [JsonProperty("seeders")] - public int Seeders { get; set; } - - [JsonProperty("num_files")] - public int NumFiles { get; set; } - - [JsonProperty("size")] - public long Size { get; set; } - - [JsonProperty("username")] - public string Username { get; set; } - - [JsonProperty("added")] - public long Added { get; set; } - - [JsonProperty("status")] - public string Status { get; set; } - - [JsonProperty("category")] - public long Category { get; set; } - - [JsonProperty("imdb")] - public string Imdb { get; set; } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs index 778f12f23..22d136e9a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentDay.cs @@ -8,6 +8,7 @@ using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -16,7 +17,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class TorrentDay : TorrentIndexerBase<TorrentDaySettings> + public class TorrentDay : TorrentIndexerBase<CookieTorrentBaseSettings> { public override string Name => "TorrentDay"; @@ -134,7 +135,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class TorrentDayRequestGenerator : IIndexerRequestGenerator { - public TorrentDaySettings Settings { get; set; } + public CookieTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public TorrentDayRequestGenerator() @@ -218,10 +219,10 @@ namespace NzbDrone.Core.Indexers.Definitions public class TorrentDayParser : IParseIndexerResponse { - private readonly TorrentDaySettings _settings; + private readonly CookieTorrentBaseSettings _settings; private readonly IndexerCapabilitiesCategories _categories; - public TorrentDayParser(TorrentDaySettings settings, IndexerCapabilitiesCategories categories) + public TorrentDayParser(CookieTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; _categories = categories; @@ -274,36 +275,4 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - - public class TorrentDaySettingsValidator : AbstractValidator<TorrentDaySettings> - { - public TorrentDaySettingsValidator() - { - RuleFor(c => c.Cookie).NotEmpty(); - } - } - - public class TorrentDaySettings : IIndexerSettings - { - private static readonly TorrentDaySettingsValidator Validator = new TorrentDaySettingsValidator(); - - public TorrentDaySettings() - { - Cookie = ""; - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Cookie", HelpText = "Site Cookie")] - public string Cookie { get; set; } - - [FieldDefinition(3)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs deleted file mode 100644 index 065ab7481..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentLeech.cs +++ /dev/null @@ -1,380 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using FluentValidation; -using Newtonsoft.Json; -using NLog; -using NzbDrone.Common.Extensions; -using NzbDrone.Common.Http; -using NzbDrone.Core.Annotations; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.Parser; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Validation; - -namespace NzbDrone.Core.Indexers.Definitions -{ - [Obsolete("Moved to YML for Cardigann v3")] - public class TorrentLeech : TorrentIndexerBase<TorrentLeechSettings> - { - public override string Name => "TorrentLeech"; - - public override string[] IndexerUrls => new string[] { "https://www.torrentleech.org/" }; - public override string Description => "This is what happens when you seed"; - private string LoginUrl => Settings.BaseUrl + "user/account/login/"; - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public override IndexerCapabilities Capabilities => SetCapabilities(); - - public TorrentLeech(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new TorrentLeechRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; - } - - public override IParseIndexerResponse GetParser() - { - return new TorrentLeechParser(Settings, Capabilities.Categories); - } - - protected override async Task DoLogin() - { - var requestBuilder = new HttpRequestBuilder(LoginUrl) - { - LogResponseContent = true - }; - - requestBuilder.Method = HttpMethod.Post; - requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); - - var cookies = Cookies; - - Cookies = null; - var authLoginRequest = requestBuilder - .AddFormParameter("username", Settings.Username) - .AddFormParameter("password", Settings.Password) - .SetHeader("Content-Type", "multipart/form-data") - .Build(); - - var response = await ExecuteAuth(authLoginRequest); - - cookies = response.GetCookies(); - UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); - - _logger.Debug("TorrentLeech authentication succeeded."); - } - - protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) - { - if (httpResponse.Content.Contains("/user/account/login")) - { - return true; - } - - return false; - } - - private IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - // Torrentleech does technically support ImdbId Search but only with no other params - // ImdbId + S/E search returns unrelated results - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q, MovieSearchParam.ImdbId - }, - MusicSearchParams = new List<MusicSearchParam> - { - MusicSearchParam.Q - }, - BookSearchParams = new List<BookSearchParam> - { - BookSearchParam.Q - } - }; - - caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movies"); - caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.MoviesSD, "Movies Cam"); - caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.MoviesSD, "Movies TS/TC"); - caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.MoviesSD, "Movies DVDRip/DVDScreener"); - caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.MoviesDVD, "Movies DVD-R"); - caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.MoviesBluRay, "Movies Bluray"); - caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.MoviesHD, "Movies BlurayRip"); - caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.Movies, "Movies Boxsets"); - caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.TVDocumentary, "Documentaries"); - caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.MoviesUHD, "Movies 4K"); - caps.Categories.AddCategoryMapping(36, NewznabStandardCategory.MoviesForeign, "Movies Foreign"); - caps.Categories.AddCategoryMapping(37, NewznabStandardCategory.MoviesWEBDL, "Movies WEBRip"); - caps.Categories.AddCategoryMapping(43, NewznabStandardCategory.MoviesHD, "Movies HDRip"); - - caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "TV"); - caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.TVSD, "TV Episodes"); - caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.TV, "TV Boxsets"); - caps.Categories.AddCategoryMapping(32, NewznabStandardCategory.TVHD, "TV Episodes HD"); - caps.Categories.AddCategoryMapping(44, NewznabStandardCategory.TVForeign, "TV Foreign"); - - caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.PCGames, "Games"); - caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.PCGames, "Games PC"); - caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.ConsoleXBox, "Games XBOX"); - caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.ConsoleXBox360, "Games XBOX360"); - caps.Categories.AddCategoryMapping(40, NewznabStandardCategory.ConsoleXBoxOne, "Games XBOXONE"); - caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.ConsolePS3, "Games PS2"); - caps.Categories.AddCategoryMapping(21, NewznabStandardCategory.ConsolePS3, "Games Mac"); - caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.ConsolePSP, "Games PSP"); - caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.ConsoleWii, "Games Wii"); - caps.Categories.AddCategoryMapping(30, NewznabStandardCategory.ConsoleNDS, "Games Nintendo DS"); - caps.Categories.AddCategoryMapping(39, NewznabStandardCategory.ConsolePS4, "Games PS4"); - caps.Categories.AddCategoryMapping(42, NewznabStandardCategory.PCMac, "Games Mac"); - caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.ConsoleOther, "Games Nintendo Switch"); - - caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.Audio, "Music"); - caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.AudioVideo, "Music videos"); - caps.Categories.AddCategoryMapping(31, NewznabStandardCategory.Audio, "Audio"); - - caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.TV, "Animation"); - caps.Categories.AddCategoryMapping(34, NewznabStandardCategory.TVAnime, "TV Anime"); - caps.Categories.AddCategoryMapping(35, NewznabStandardCategory.TV, "TV Cartoons"); - - caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Books, "Books"); - caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.BooksEBook, "Books EBooks"); - caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.BooksComics, "Books Comics"); - - caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.PC, "Apps"); - caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.PCISO, "PC ISO"); - caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.PCMac, "PC Mac"); - caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.PCMobileOther, "PC Mobile"); - caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.PC0day, "PC 0-day"); - caps.Categories.AddCategoryMapping(38, NewznabStandardCategory.Other, "Education"); - - return caps; - } - } - - public class TorrentLeechRequestGenerator : IIndexerRequestGenerator - { - public TorrentLeechSettings Settings { get; set; } - public IndexerCapabilities Capabilities { get; set; } - - public TorrentLeechRequestGenerator() - { - } - - private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null) - { - var searchString = Regex.Replace(term, @"(^|\s)-", " "); - - var searchUrl = Settings.BaseUrl + "torrents/browse/list/"; - - if (Settings.FreeLeechOnly) - { - searchUrl += "facets/tags%3AFREELEECH/"; - } - - if (imdbId.IsNotNullOrWhiteSpace()) - { - searchUrl += "imdbID/" + imdbId + "/"; - } - else if (!string.IsNullOrWhiteSpace(searchString)) - { - searchUrl += "exact/1/query/" + WebUtility.UrlEncode(searchString) + "/"; - } - - var cats = Capabilities.Categories.MapTorznabCapsToTrackers(categories); - if (cats.Count > 0) - { - searchUrl += "categories/" + string.Join(",", cats); - } - else - { - searchUrl += "newfilter/2"; // include 0day and music - } - - var request = new IndexerRequest(searchUrl, HttpAccept.Rss); - - yield return request; - } - - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public Func<IDictionary<string, string>> GetCookies { get; set; } - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class TorrentLeechParser : IParseIndexerResponse - { - private readonly TorrentLeechSettings _settings; - private readonly IndexerCapabilitiesCategories _categories; - - public TorrentLeechParser(TorrentLeechSettings settings, IndexerCapabilitiesCategories categories) - { - _settings = settings; - _categories = categories; - } - - public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) - { - var torrentInfos = new List<TorrentInfo>(); - - var rows = JsonConvert.DeserializeObject<dynamic>(indexerResponse.Content).torrentList; - foreach (var row in rows ?? Enumerable.Empty<dynamic>()) - { - var title = row.name.ToString(); - - var torrentId = row.fid.ToString(); - var details = new Uri(_settings.BaseUrl + "torrent/" + torrentId); - var link = new Uri(_settings.BaseUrl + "download/" + torrentId + "/" + row.filename); - var publishDate = DateTime.ParseExact(row.addedTimestamp.ToString(), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); - var seeders = (int)row.seeders; - var leechers = (int)row.leechers; - var grabs = (int)row.completed; - var size = (long)row.size; - var cats = _categories.MapTrackerCatToNewznab(((int)row.categoryID).ToString()); - var imdb = (string)row.imdbID; - var imdbId = 0; - if (imdb.Length > 2) - { - imdbId = int.Parse(imdb.Substring(2)); - } - - // freeleech #6579 #6624 #7367 - string dlMultiplier = row.download_multiplier.ToString(); - var dlVolumeFactor = dlMultiplier.IsNullOrWhiteSpace() ? 1 : ParseUtil.CoerceInt(dlMultiplier); - - var release = new TorrentInfo - { - Title = title, - InfoUrl = details.AbsoluteUri, - Guid = details.AbsoluteUri, - DownloadUrl = link.AbsoluteUri, - PublishDate = publishDate, - Categories = cats, - Size = size, - Grabs = grabs, - Seeders = seeders, - Peers = seeders + leechers, - ImdbId = imdbId, - UploadVolumeFactor = 1, - DownloadVolumeFactor = dlVolumeFactor, - MinimumRatio = 1, - MinimumSeedTime = 864000 // 10 days for registered users, less for upgraded users - }; - - torrentInfos.Add(release); - } - - return torrentInfos.ToArray(); - } - - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class TorrentLeechSettingsValidator : AbstractValidator<TorrentLeechSettings> - { - public TorrentLeechSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - - RuleFor(c => c.VipExpiration).Must(c => c.IsValidDate()) - .When(c => c.VipExpiration.IsNotNullOrWhiteSpace()) - .WithMessage("Correctly formatted date is required"); - - RuleFor(c => c.VipExpiration).Must(c => c.IsFutureDate()) - .When(c => c.VipExpiration.IsNotNullOrWhiteSpace()) - .WithMessage("Must be a future date"); - } - } - - public class TorrentLeechSettings : IIndexerSettings - { - private static readonly TorrentLeechSettingsValidator Validator = new TorrentLeechSettingsValidator(); - - public TorrentLeechSettings() - { - Username = ""; - Password = ""; - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - - [FieldDefinition(4, Label = "FreeLeech Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Search Freeleech torrents only")] - public bool FreeLeechOnly { get; set; } - - [FieldDefinition(5, Label = "VIP Expiration", HelpText = "Enter date (yyyy-mm-dd) for VIP Expiration or blank, Prowlarr will notify 1 week from expiration of VIP")] - public string VipExpiration { get; set; } - - [FieldDefinition(6)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs deleted file mode 100644 index 00a052014..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentParadiseMl.cs +++ /dev/null @@ -1,246 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Net; -using System.Text; -using FluentValidation; -using Newtonsoft.Json; -using NLog; -using NzbDrone.Common.Http; -using NzbDrone.Core.Annotations; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Indexers.Exceptions; -using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.Parser; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Validation; - -namespace NzbDrone.Core.Indexers.Definitions -{ - [Obsolete("Moved to YML for Cardigann v3")] - public class TorrentParadiseMl : TorrentIndexerBase<TorrentParadiseMlSettings> - { - public override string Name => "TorrentParadiseMl"; - public override string[] IndexerUrls => new[] { "https://torrent-paradise.ml/" }; - public override string Language => "en-US"; - public override string Description => "The most innovative torrent site"; - public override Encoding Encoding => Encoding.UTF8; - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerPrivacy Privacy => IndexerPrivacy.Public; - public override IndexerCapabilities Capabilities => SetCapabilities(); - - public TorrentParadiseMl(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new TorrentParadiseMlRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; - } - - public override IParseIndexerResponse GetParser() - { - return new TorrentParadiseMlParser(Settings); - } - - private IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q - }, - MusicSearchParams = new List<MusicSearchParam> - { - MusicSearchParam.Q - }, - BookSearchParams = new List<BookSearchParam> - { - BookSearchParam.Q - } - }; - - caps.Categories.AddCategoryMapping(8000, NewznabStandardCategory.Other); - - return caps; - } - } - - public class TorrentParadiseMlRequestGenerator : IIndexerRequestGenerator - { - public TorrentParadiseMlSettings Settings { get; set; } - public IndexerCapabilities Capabilities { get; set; } - - public TorrentParadiseMlRequestGenerator() - { - } - - private IEnumerable<IndexerRequest> GetPagedRequests(string term) - { - var searchTerm = term; - - if (string.IsNullOrWhiteSpace(searchTerm)) - { - searchTerm = DateTime.Now.Year.ToString(); - } - - var qc = new NameValueCollection - { - { "q", searchTerm } - }; - - var searchUrl = string.Format("{0}/api/search?{1}", Settings.BaseUrl.TrimEnd('/'), qc.GetQueryString()); - - var request = new IndexerRequest(searchUrl, HttpAccept.Json); - - yield return request; - } - - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm))); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm))); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString))); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm))); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm))); - - return pageableRequests; - } - - public Func<IDictionary<string, string>> GetCookies { get; set; } - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class TorrentParadiseMlParser : IParseIndexerResponse - { - private readonly TorrentParadiseMlSettings _settings; - - public TorrentParadiseMlParser(TorrentParadiseMlSettings settings) - { - _settings = settings; - } - - public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) - { - var torrentInfos = new List<ReleaseInfo>(); - - if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) - { - // Remove cookie cache - CookiesUpdater(null, null); - - throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request"); - } - - var results = JsonConvert.DeserializeObject<List<TorrentParadiseResult>>(indexerResponse.Content); - - if (results == null) - { - return torrentInfos; - } - - foreach (var result in results) - { - var magnetUrl = MagnetLinkBuilder.BuildPublicMagnetLink(result.Id, result.Text); - - var release = new TorrentInfo - { - Title = result.Text, - Size = result.Size, - Seeders = result.Seeders, - Peers = result.Seeders + result.Leechers, - InfoHash = result.Id, - Guid = magnetUrl, - MagnetUrl = magnetUrl, - PublishDate = DateTime.UtcNow, - InfoUrl = _settings.BaseUrl, - DownloadVolumeFactor = 0, - UploadVolumeFactor = 1, - Categories = new List<IndexerCategory> { NewznabStandardCategory.Other } - }; - - torrentInfos.Add(release); - } - - return torrentInfos.ToArray(); - } - - private class TorrentParadiseResult - { - public string Id { get; set; } - public string Text { get; set; } - - [JsonProperty(PropertyName = "len")] - public long? Size { get; set; } - - [JsonProperty(PropertyName = "s")] - public int? Seeders { get; set; } - - [JsonProperty(PropertyName = "l")] - public int? Leechers { get; set; } - } - - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class TorrentParadiseMlSettingsValidator : AbstractValidator<TorrentParadiseMlSettings> - { - } - - public class TorrentParadiseMlSettings : IIndexerSettings - { - private static readonly TorrentParadiseMlSettingsValidator Validator = new TorrentParadiseMlSettingsValidator(); - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentPotato/TorrentPotatoSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentPotato/TorrentPotatoSettings.cs index dc9e87b3f..e7bf2f8dc 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentPotato/TorrentPotatoSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentPotato/TorrentPotatoSettings.cs @@ -1,39 +1,20 @@ using FluentValidation; using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.TorrentPotato { - public class TorrentPotatoSettingsValidator : AbstractValidator<TorrentPotatoSettings> + public class TorrentPotatoSettings : NoAuthTorrentBaseSettings { - public TorrentPotatoSettingsValidator() - { - } - } - - public class TorrentPotatoSettings : IIndexerSettings - { - private static readonly TorrentPotatoSettingsValidator Validator = new TorrentPotatoSettingsValidator(); - public TorrentPotatoSettings() { } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "Username", HelpText = "Indexer Username", Privacy = PrivacyLevel.UserName)] public string User { get; set; } [FieldDefinition(3, Label = "Passkey", HelpText = "Indexer Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] public string Passkey { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs deleted file mode 100644 index 87cca4876..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentSeeds.cs +++ /dev/null @@ -1,378 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using AngleSharp.Html.Parser; -using FluentValidation; -using Newtonsoft.Json.Linq; -using NLog; -using NzbDrone.Common.Http; -using NzbDrone.Core.Annotations; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Indexers.Exceptions; -using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.Parser; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Validation; - -namespace NzbDrone.Core.Indexers.Definitions -{ - [Obsolete("Moved to YML for Cardigann v3")] - public class TorrentSeeds : TorrentIndexerBase<TorrentSeedsSettings> - { - public override string Name => "TorrentSeeds"; - - public override string[] IndexerUrls => new string[] { "https://torrentseeds.org/" }; - public override string Description => "TorrentSeeds is a Private site for MOVIES / TV / GENERAL"; - private string LoginUrl => Settings.BaseUrl + "takelogin.php"; - private string CaptchaUrl => Settings.BaseUrl + "simpleCaptcha.php?numImages=1"; - private string TokenUrl => Settings.BaseUrl + "login.php"; - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public override IndexerCapabilities Capabilities => SetCapabilities(); - - public TorrentSeeds(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new TorrentSeedsRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; - } - - public override IParseIndexerResponse GetParser() - { - return new TorrentSeedsParser(Settings, Capabilities.Categories); - } - - protected override async Task DoLogin() - { - var requestBuilder = new HttpRequestBuilder(LoginUrl) - { - LogResponseContent = true - }; - - Cookies = null; - - var loginPage = await ExecuteAuth(new HttpRequest(CaptchaUrl)); - var json1 = JObject.Parse(loginPage.Content); - var captchaSelection = json1["images"][0]["hash"]; - - requestBuilder.Method = HttpMethod.Post; - requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); - requestBuilder.SetCookies(loginPage.GetCookies()); - - var authLoginRequest = requestBuilder - .AddFormParameter("username", Settings.Username) - .AddFormParameter("password", Settings.Password) - .AddFormParameter("submitme", "X") - .AddFormParameter("captchaSelection", (string)captchaSelection) - .SetHeader("Content-Type", "multipart/form-data") - .Build(); - - var response = await ExecuteAuth(authLoginRequest); - - if (CheckIfLoginNeeded(response)) - { - throw new IndexerAuthException("TorrentSeeds Login Failed"); - } - - var cookies = response.GetCookies(); - UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); - - _logger.Debug("TorrentSeeds authentication succeeded."); - } - - protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) - { - if ((httpResponse.HasHttpRedirect && httpResponse.Headers.GetSingleValue("Location").Contains("/login.php?")) || - (!httpResponse.HasHttpRedirect && !httpResponse.Content.Contains("/logout.php?"))) - { - return true; - } - - return false; - } - - private IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep - }, - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q - }, - MusicSearchParams = new List<MusicSearchParam> - { - MusicSearchParam.Q - }, - BookSearchParams = new List<BookSearchParam> - { - BookSearchParam.Q - } - }; - - caps.Categories.AddCategoryMapping(37, NewznabStandardCategory.TVAnime, "Anime/HD"); - caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.TVAnime, "Anime/SD"); - caps.Categories.AddCategoryMapping(72, NewznabStandardCategory.TVAnime, "Anime/UHD"); - caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.PC0day, "Apps/0DAY"); - caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.Books, "Apps/Bookware"); - caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.PCISO, "Apps/ISO"); - caps.Categories.AddCategoryMapping(73, NewznabStandardCategory.AudioAudiobook, "Music/Audiobooks"); - caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.ConsoleOther, "Console/NSW"); - caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.ConsolePS3, "Console/PS3"); - caps.Categories.AddCategoryMapping(30, NewznabStandardCategory.ConsolePS4, "Console/PS4"); - caps.Categories.AddCategoryMapping(71, NewznabStandardCategory.ConsolePS4, "Console/PS5"); - caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.ConsolePSP, "Console/PSP"); - caps.Categories.AddCategoryMapping(70, NewznabStandardCategory.ConsolePSVita, "Console/PSV"); - caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.ConsoleWii, "Console/WII"); - caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.ConsoleWiiU, "Console/WIIU"); - caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.ConsoleXBox360, "Console/XBOX360"); - caps.Categories.AddCategoryMapping(32, NewznabStandardCategory.BooksEBook, "E-books"); - caps.Categories.AddCategoryMapping(63, NewznabStandardCategory.ConsoleOther, "Games/DOX"); - caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.PCGames, "Games/ISO"); - caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.PCGames, "Games/PC Rips"); - caps.Categories.AddCategoryMapping(31, NewznabStandardCategory.MoviesBluRay, "Movies/Bluray"); - caps.Categories.AddCategoryMapping(50, NewznabStandardCategory.MoviesBluRay, "Movies/Bluray-UHD"); - caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.MoviesDVD, "Movies/DVDR"); - caps.Categories.AddCategoryMapping(69, NewznabStandardCategory.MoviesForeign, "Movies/DVDR-Foreign"); - caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.MoviesHD, "Movies/HD"); - caps.Categories.AddCategoryMapping(39, NewznabStandardCategory.MoviesForeign, "Movies/HD-Foreign"); - caps.Categories.AddCategoryMapping(74, NewznabStandardCategory.MoviesHD, "Movies/Remuxes"); - caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.MoviesSD, "Movies/SD"); - caps.Categories.AddCategoryMapping(62, NewznabStandardCategory.MoviesForeign, "Movies/SD-Foreign"); - caps.Categories.AddCategoryMapping(49, NewznabStandardCategory.MoviesUHD, "Movies/UHD"); - caps.Categories.AddCategoryMapping(76, NewznabStandardCategory.MoviesForeign, "Movies/UHD-Foreign"); - caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.AudioLossless, "Music/FLAC"); - caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.AudioOther, "Music/MBluRay-Rips"); - caps.Categories.AddCategoryMapping(34, NewznabStandardCategory.AudioOther, "Music/MDVDR"); - caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.AudioMP3, "Music/MP3"); - caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.AudioVideo, "Music/MVID"); - caps.Categories.AddCategoryMapping(77, NewznabStandardCategory.TVAnime, "Anime/Packs"); - caps.Categories.AddCategoryMapping(78, NewznabStandardCategory.BooksEBook, "Books/Packs"); - caps.Categories.AddCategoryMapping(80, NewznabStandardCategory.MoviesHD, "Movies/HD-Packs"); - caps.Categories.AddCategoryMapping(81, NewznabStandardCategory.MoviesHD, "Movies/Remux-Packs"); - caps.Categories.AddCategoryMapping(79, NewznabStandardCategory.MoviesSD, "Movies/SD-Packs"); - caps.Categories.AddCategoryMapping(68, NewznabStandardCategory.Audio, "Music/Packs"); - caps.Categories.AddCategoryMapping(67, NewznabStandardCategory.TVHD, "TV/HD-Packs"); - caps.Categories.AddCategoryMapping(82, NewznabStandardCategory.TVHD, "TV/Remux-Packs"); - caps.Categories.AddCategoryMapping(65, NewznabStandardCategory.TVSD, "TV/SD-Packs"); - caps.Categories.AddCategoryMapping(84, NewznabStandardCategory.TVUHD, "TV/UHD-Packs"); - caps.Categories.AddCategoryMapping(85, NewznabStandardCategory.XXX, "XXX/Packs"); - caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.TVSD, "TV/DVDR"); - caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.TVHD, "TV/HD"); - caps.Categories.AddCategoryMapping(64, NewznabStandardCategory.TVForeign, "TV/HD-Foreign"); - caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.TVHD, "TV/HD-Retail"); - caps.Categories.AddCategoryMapping(36, NewznabStandardCategory.TVSport, "TV/HD-Sport"); - caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.TVSD, "TV/SD"); - caps.Categories.AddCategoryMapping(86, NewznabStandardCategory.TVForeign, "TV/SD-Foreign"); - caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.TVSD, "TV/SD-Retail"); - caps.Categories.AddCategoryMapping(35, NewznabStandardCategory.TVSport, "TV/SD-Sport"); - caps.Categories.AddCategoryMapping(61, NewznabStandardCategory.TVUHD, "TV/UHD"); - caps.Categories.AddCategoryMapping(87, NewznabStandardCategory.TVForeign, "TV/UHD-Foreign"); - caps.Categories.AddCategoryMapping(53, NewznabStandardCategory.XXX, "XXX/HD"); - caps.Categories.AddCategoryMapping(88, NewznabStandardCategory.XXXImageSet, "XXX/Image-Sets"); - caps.Categories.AddCategoryMapping(57, NewznabStandardCategory.XXX, "XXX/Paysite"); - caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.XXX, "XXX/SD"); - - return caps; - } - } - - public class TorrentSeedsRequestGenerator : IIndexerRequestGenerator - { - public TorrentSeedsSettings Settings { get; set; } - public IndexerCapabilities Capabilities { get; set; } - - public TorrentSeedsRequestGenerator() - { - } - - private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories) - { - // remove operator characters - var cleanSearchString = Regex.Replace(term.Trim(), "[ _.+-]+", " ", RegexOptions.Compiled); - - var searchUrl = Settings.BaseUrl + "browse_elastic.php"; - var queryCollection = new NameValueCollection - { - { "search_in", "name" }, - { "search_mode", "all" }, - { "order_by", "added" }, - { "order_way", "desc" } - }; - - if (!string.IsNullOrWhiteSpace(cleanSearchString)) - { - queryCollection.Add("query", cleanSearchString); - } - - foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories)) - { - queryCollection.Add($"cat[{cat}]", "1"); - } - - searchUrl += "?" + queryCollection.GetQueryString(); - - var request = new IndexerRequest(searchUrl, HttpAccept.Html); - - yield return request; - } - - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public Func<IDictionary<string, string>> GetCookies { get; set; } - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class TorrentSeedsParser : IParseIndexerResponse - { - private readonly TorrentSeedsSettings _settings; - private readonly IndexerCapabilitiesCategories _categories; - - public TorrentSeedsParser(TorrentSeedsSettings settings, IndexerCapabilitiesCategories categories) - { - _settings = settings; - _categories = categories; - } - - public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) - { - var torrentInfos = new List<TorrentInfo>(); - - var parser = new HtmlParser(); - var dom = parser.ParseDocument(indexerResponse.Content); - var rows = dom.QuerySelectorAll("table.table-bordered > tbody > tr[class*=\"torrent_row_\"]"); - foreach (var row in rows) - { - var release = new TorrentInfo(); - release.MinimumRatio = 1; - release.MinimumSeedTime = 72 * 60 * 60; - var qCatLink = row.QuerySelector("a[href^=\"/browse_elastic.php?cat=\"]"); - var catStr = qCatLink.GetAttribute("href").Split('=')[1]; - release.Categories = _categories.MapTrackerCatToNewznab(catStr); - var qDetailsLink = row.QuerySelector("a[href^=\"/details.php?id=\"]"); - var qDetailsTitle = row.QuerySelector("td:has(a[href^=\"/details.php?id=\"]) b"); - release.Title = qDetailsTitle.TextContent.Trim(); - var qDlLink = row.QuerySelector("a[href^=\"/download.php?torrent=\"]"); - - release.DownloadUrl = _settings.BaseUrl + qDlLink.GetAttribute("href").TrimStart('/'); - release.InfoUrl = _settings.BaseUrl + qDetailsLink.GetAttribute("href").TrimStart('/'); - release.Guid = release.InfoUrl; - - var qColumns = row.QuerySelectorAll("td"); - release.Files = ParseUtil.CoerceInt(qColumns[3].TextContent); - release.PublishDate = DateTimeUtil.FromUnknown(qColumns[5].TextContent); - release.Size = ParseUtil.GetBytes(qColumns[6].TextContent); - release.Grabs = ParseUtil.CoerceInt(qColumns[7].TextContent.Replace("Times", "")); - release.Seeders = ParseUtil.CoerceInt(qColumns[8].TextContent); - release.Peers = ParseUtil.CoerceInt(qColumns[9].TextContent) + release.Seeders; - - var qImdb = row.QuerySelector("a[href*=\"www.imdb.com\"]"); - if (qImdb != null) - { - var deRefUrl = qImdb.GetAttribute("href"); - release.ImdbId = ParseUtil.GetImdbID(WebUtility.UrlDecode(deRefUrl).Split('/').Last()) ?? 0; - } - - release.DownloadVolumeFactor = row.QuerySelector("span.freeleech") != null ? 0 : 1; - release.UploadVolumeFactor = 1; - torrentInfos.Add(release); - } - - return torrentInfos.ToArray(); - } - - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class TorrentSeedsSettingsValidator : AbstractValidator<TorrentSeedsSettings> - { - public TorrentSeedsSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class TorrentSeedsSettings : IIndexerSettings - { - private static readonly TorrentSeedsSettingsValidator Validator = new TorrentSeedsSettingsValidator(); - - public TorrentSeedsSettings() - { - Username = ""; - Password = ""; - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs index 517ed183f..05585779b 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentSyndikat.cs @@ -10,6 +10,7 @@ using NLog; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -330,7 +331,7 @@ namespace NzbDrone.Core.Indexers.Definitions } } - public class TorrentSyndikatSettings : IIndexerSettings + public class TorrentSyndikatSettings : NoAuthTorrentBaseSettings { private static readonly TorrentSyndikatSettingsValidator Validator = new TorrentSyndikatSettingsValidator(); @@ -340,9 +341,6 @@ namespace NzbDrone.Core.Indexers.Definitions ReleaseTypes = new List<int>(); } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpText = "Site API Key")] public string ApiKey { get; set; } @@ -352,10 +350,7 @@ namespace NzbDrone.Core.Indexers.Definitions [FieldDefinition(4, Label = "Release Types", Type = FieldType.Select, SelectOptions = typeof(TorrentSyndikatReleaseTypes))] public IEnumerable<int> ReleaseTypes { get; set; } - [FieldDefinition(5)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentsCSV.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentsCSV.cs index 648523ba8..9daddda0c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/TorrentsCSV.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentsCSV.cs @@ -9,6 +9,7 @@ using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -17,7 +18,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class TorrentsCSV : TorrentIndexerBase<TorrentsCSVSettings> + public class TorrentsCSV : TorrentIndexerBase<NoAuthTorrentBaseSettings> { public override string Name => "TorrentsCSV"; public override string[] IndexerUrls => new[] { "https://torrents-csv.ml/" }; @@ -66,7 +67,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class TorrentsCSVRequestGenerator : IIndexerRequestGenerator { - public TorrentsCSVSettings Settings { get; set; } + public NoAuthTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public TorrentsCSVRequestGenerator() @@ -137,9 +138,9 @@ namespace NzbDrone.Core.Indexers.Definitions public class TorrentsCSVParser : IParseIndexerResponse { - private readonly TorrentsCSVSettings _settings; + private readonly NoAuthTorrentBaseSettings _settings; - public TorrentsCSVParser(TorrentsCSVSettings settings) + public TorrentsCSVParser(NoAuthTorrentBaseSettings settings) { _settings = settings; } @@ -193,24 +194,4 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - - public class TorrentsCSVSettingsValidator : AbstractValidator<TorrentsCSVSettings> - { - } - - public class TorrentsCSVSettings : IIndexerSettings - { - private static readonly TorrentsCSVSettingsValidator Validator = new TorrentsCSVSettingsValidator(); - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/UNIT3D/Unit3dSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/UNIT3D/Unit3dSettings.cs index b953d2d04..d15f409ef 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/UNIT3D/Unit3dSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/UNIT3D/Unit3dSettings.cs @@ -1,5 +1,6 @@ using FluentValidation; using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions.UNIT3D @@ -12,7 +13,7 @@ namespace NzbDrone.Core.Indexers.Definitions.UNIT3D } } - public class Unit3dSettings : IIndexerSettings + public class Unit3dSettings : NoAuthTorrentBaseSettings { private static readonly Unit3dSettingsValidator Validator = new Unit3dSettingsValidator(); @@ -20,16 +21,10 @@ namespace NzbDrone.Core.Indexers.Definitions.UNIT3D { } - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "API Key", HelpText = "Site API Key generated in My Security", Privacy = PrivacyLevel.ApiKey)] public string ApiKey { get; set; } - [FieldDefinition(3)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Xthor/XthorSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Xthor/XthorSettings.cs index 8c7e40f4b..0ec5a5e16 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Xthor/XthorSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Xthor/XthorSettings.cs @@ -1,9 +1,10 @@ -using NzbDrone.Core.Annotations; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions.Xthor { - public class XthorSettings : IIndexerSettings + public class XthorSettings : NoAuthTorrentBaseSettings { private static readonly XthorSettingsValidator Validator = new XthorSettingsValidator(); @@ -22,9 +23,6 @@ namespace NzbDrone.Core.Indexers.Definitions.Xthor MaxPages = 1; } - [FieldDefinition(1, Label = "Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - [FieldDefinition(2, Label = "Passkey", Privacy = PrivacyLevel.Password, Type = FieldType.Password, HelpText = "Site Passkey")] public string Passkey { get; set; } @@ -55,11 +53,9 @@ namespace NzbDrone.Core.Indexers.Definitions.Xthor [FieldDefinition(11, Label = "How many pages do you want to follow?", Type = FieldType.Select, SelectOptions = typeof(XthorPagesNumber), HelpText = "(not recommended) you can increase max pages to follow when making a request. But be aware that this API is very buggy on tracker side, most of time, results of next pages are same as the first page. Even if we deduplicate rows, you will loose performance for the same results.", Advanced = true)] public int MaxPages { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } - - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/YTS.cs b/src/NzbDrone.Core/Indexers/Definitions/YTS.cs deleted file mode 100644 index 73c00416a..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/YTS.cs +++ /dev/null @@ -1,308 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Globalization; -using System.Text; -using FluentValidation; -using Newtonsoft.Json.Linq; -using NLog; -using NzbDrone.Common.Extensions; -using NzbDrone.Common.Http; -using NzbDrone.Core.Annotations; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.Parser; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Validation; - -namespace NzbDrone.Core.Indexers.Definitions -{ - [Obsolete("Moved to YML for Cardigann v3")] - public class YTS : TorrentIndexerBase<YTSSettings> - { - public override string Name => "YTS"; - public override string[] IndexerUrls => new string[] { "https://yts.mx/" }; - public override string Language => "en-US"; - public override string Description => "YTS is a Public torrent site specialising in HD movies of small size"; - public override Encoding Encoding => Encoding.GetEncoding("windows-1252"); - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerPrivacy Privacy => IndexerPrivacy.Public; - - public override TimeSpan RateLimit => TimeSpan.FromSeconds(2.5); - public override IndexerCapabilities Capabilities => SetCapabilities(); - - public YTS(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new YTSRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; - } - - public override IParseIndexerResponse GetParser() - { - return new YTSParser(Settings, Capabilities.Categories); - } - - private IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - }, - MovieSearchParams = new List<MovieSearchParam> { MovieSearchParam.Q, MovieSearchParam.ImdbId }, - MusicSearchParams = new List<MusicSearchParam> - { - }, - BookSearchParams = new List<BookSearchParam> - { - } - }; - - caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.MoviesHD, "Movies/x264/720p"); - caps.Categories.AddCategoryMapping(44, NewznabStandardCategory.MoviesHD, "Movies/x264/1080p"); - caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.MoviesUHD, "Movies/x264/2160p"); - caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.Movies3D, "Movies/x264/3D"); - - return caps; - } - } - - public class YTSRequestGenerator : IIndexerRequestGenerator - { - public YTSSettings Settings { get; set; } - public IndexerCapabilities Capabilities { get; set; } - - public YTSRequestGenerator() - { - } - - private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null) - { - var searchUrl = string.Format("{0}/api/v2/list_movies.json", Settings.BaseUrl.TrimEnd('/')); - - var searchString = term; - - var queryCollection = new NameValueCollection - { - // without this the API sometimes returns nothing - { "sort", "date_added" }, - { "limit", "50" } - }; - - if (imdbId.IsNotNullOrWhiteSpace()) - { - queryCollection.Add("query_term", imdbId); - } - else if (!string.IsNullOrWhiteSpace(searchString)) - { - searchString = searchString.Replace("'", ""); // ignore ' (e.g. search for america's Next Top Model) - queryCollection.Add("query_term", searchString); - } - - searchUrl = searchUrl + "?" + queryCollection.GetQueryString(); - - var request = new IndexerRequest(searchUrl, HttpAccept.Html); - - yield return request; - } - - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public Func<IDictionary<string, string>> GetCookies { get; set; } - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class YTSParser : IParseIndexerResponse - { - private readonly YTSSettings _settings; - private readonly IndexerCapabilitiesCategories _categories; - - public YTSParser(YTSSettings settings, IndexerCapabilitiesCategories categories) - { - _settings = settings; - _categories = categories; - } - - public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) - { - var torrentInfos = new List<ReleaseInfo>(); - - var contentString = indexerResponse.Content; - - // returned content might start with an html error message, remove it first - var jsonStart = contentString.IndexOf('{'); - var jsonContentStr = contentString.Remove(0, jsonStart); - - var jsonContent = JObject.Parse(jsonContentStr); - - var result = jsonContent.Value<string>("status"); - - // query was not successful - if (result != "ok") - { - return new List<ReleaseInfo>(); - } - - var dataItems = jsonContent.Value<JToken>("data"); - var movieCount = dataItems.Value<int>("movie_count"); - - // no results found in query - if (movieCount < 1) - { - return new List<ReleaseInfo>(); - } - - var movies = dataItems.Value<JToken>("movies"); - if (movies == null) - { - return new List<ReleaseInfo>(); - } - - foreach (var movie in movies) - { - var torrents = movie.Value<JArray>("torrents"); - if (torrents == null) - { - continue; - } - - foreach (var torrent in torrents) - { - var release = new TorrentInfo(); - - // append type: BRRip or WEBRip, resolves #3558 via #4577 - var type = torrent.Value<string>("type"); - switch (type) - { - case "web": - type = "WEBRip"; - break; - default: - type = "BRRip"; - break; - } - - var quality = torrent.Value<string>("quality"); - var title = movie.Value<string>("title").Replace(":", "").Replace(' ', '.'); - var year = movie.Value<int>("year"); - release.Title = $"{title}.{year}.{quality}.{type}-YTS"; - - var imdb = movie.Value<string>("imdb_code"); - release.ImdbId = ParseUtil.GetImdbID(imdb).Value; - - release.InfoHash = torrent.Value<string>("hash"); // magnet link is auto generated from infohash - - // ex: 2015-08-16 21:25:08 +0000 - var dateStr = torrent.Value<string>("date_uploaded"); - var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - release.PublishDate = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc).ToLocalTime(); - - release.DownloadUrl = torrent.Value<string>("url"); - release.Seeders = torrent.Value<int>("seeds"); - release.Peers = torrent.Value<int>("peers") + release.Seeders; - release.Size = torrent.Value<long>("size_bytes"); - release.DownloadVolumeFactor = 0; - release.UploadVolumeFactor = 1; - - release.InfoUrl = movie.Value<string>("url"); - - release.PosterUrl = new Uri(movie.Value<string>("large_cover_image")).AbsoluteUri; - release.Guid = release.DownloadUrl; - - // map the quality to a newznab category for torznab compatibility (for Radarr, etc) - switch (quality) - { - case "720p": - release.Categories = _categories.MapTrackerCatToNewznab("45"); - break; - case "1080p": - release.Categories = _categories.MapTrackerCatToNewznab("44"); - break; - case "2160p": - release.Categories = _categories.MapTrackerCatToNewznab("46"); - break; - case "3D": - release.Categories = _categories.MapTrackerCatToNewznab("47"); - break; - default: - release.Categories = _categories.MapTrackerCatToNewznab("45"); - break; - } - - if (release == null) - { - continue; - } - - torrentInfos.Add(release); - } - } - - return torrentInfos.ToArray(); - } - - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class YTSSettingsValidator : AbstractValidator<YTSSettings> - { - } - - public class YTSSettings : IIndexerSettings - { - private static readonly YTSSettingsValidator Validator = new YTSSettingsValidator(); - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs b/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs index 48497b75a..8247e66b8 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ZonaQ.cs @@ -17,6 +17,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -25,7 +26,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class ZonaQ : TorrentIndexerBase<ZonaQSettings> + public class ZonaQ : TorrentIndexerBase<UserPassTorrentBaseSettings> { public override string Name => "ZonaQ"; public override string[] IndexerUrls => new string[] { "https://www.zonaq.pw/" }; @@ -234,7 +235,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class ZonaQRequestGenerator : IIndexerRequestGenerator { - public ZonaQSettings Settings { get; set; } + public UserPassTorrentBaseSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } public ZonaQRequestGenerator() @@ -316,10 +317,10 @@ namespace NzbDrone.Core.Indexers.Definitions public class ZonaQParser : IParseIndexerResponse { - private readonly ZonaQSettings _settings; + private readonly UserPassTorrentBaseSettings _settings; private readonly IndexerCapabilitiesCategories _categories; - public ZonaQParser(ZonaQSettings settings, IndexerCapabilitiesCategories categories) + public ZonaQParser(UserPassTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) { _settings = settings; _categories = categories; @@ -397,41 +398,4 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - - public class ZonaQSettingsValidator : AbstractValidator<ZonaQSettings> - { - public ZonaQSettingsValidator() - { - RuleFor(c => c.Username).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class ZonaQSettings : IIndexerSettings - { - private static readonly ZonaQSettingsValidator Validator = new ZonaQSettingsValidator(); - - public ZonaQSettings() - { - Username = ""; - Password = ""; - } - - [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] - public string BaseUrl { get; set; } - - [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] - public string Username { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - - [FieldDefinition(4)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } } diff --git a/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs new file mode 100644 index 000000000..92e5e9983 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs @@ -0,0 +1,38 @@ +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Indexers.Settings +{ + public class CookieTorrentBaseSettings : IIndexerSettings + { + public class CookieBaseSettingsValidator : AbstractValidator<CookieTorrentBaseSettings> + { + public CookieBaseSettingsValidator() + { + RuleFor(c => c.Cookie).NotEmpty(); + } + } + + private static readonly CookieBaseSettingsValidator Validator = new CookieBaseSettingsValidator(); + + public CookieTorrentBaseSettings() + { + Cookie = ""; + } + + [FieldDefinition(1, Label = "Base Url", HelpText = "Select which baseurl Prowlarr will use for requests to the site", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls")] + public string BaseUrl { get; set; } + + [FieldDefinition(2, Label = "Cookie", HelpText = "Site Cookie", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] + public string Cookie { get; set; } + + [FieldDefinition(3)] + public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs new file mode 100644 index 000000000..eed3a814d --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs @@ -0,0 +1,26 @@ +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Indexers.Settings +{ + public class NoAuthSettingsValidator : AbstractValidator<NoAuthTorrentBaseSettings> + { + } + + public class NoAuthTorrentBaseSettings : IIndexerSettings + { + private static readonly NoAuthSettingsValidator Validator = new NoAuthSettingsValidator(); + + [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] + public string BaseUrl { get; set; } + + [FieldDefinition(2)] + public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); + + public virtual NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Settings/UserPassTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/Settings/UserPassTorrentBaseSettings.cs new file mode 100644 index 000000000..552376e07 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Settings/UserPassTorrentBaseSettings.cs @@ -0,0 +1,43 @@ +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Indexers.Settings +{ + public class UserPassTorrentBaseSettings : IIndexerSettings + { + public class UserPassBaseSettingsValidator : AbstractValidator<UserPassTorrentBaseSettings> + { + public UserPassBaseSettingsValidator() + { + RuleFor(c => c.Username).NotEmpty(); + RuleFor(c => c.Password).NotEmpty(); + } + } + + private static readonly UserPassBaseSettingsValidator Validator = new UserPassBaseSettingsValidator(); + + public UserPassTorrentBaseSettings() + { + Username = ""; + Password = ""; + } + + [FieldDefinition(1, Label = "Base Url", HelpText = "Select which baseurl Prowlarr will use for requests to the site", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls")] + public string BaseUrl { get; set; } + + [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] + public string Username { get; set; } + + [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] + public string Password { get; set; } + + [FieldDefinition(4)] + public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} From af50a1d3a8405e8d79a82dd9535909cb3f4213f5 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 1 May 2022 20:10:27 -0500 Subject: [PATCH 0458/2320] New: Only sync indexers with matching app tags --- .../Applications/ApplicationService.cs | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Applications/ApplicationService.cs b/src/NzbDrone.Core/Applications/ApplicationService.cs index f3a80161c..a6a20f5dc 100644 --- a/src/NzbDrone.Core/Applications/ApplicationService.cs +++ b/src/NzbDrone.Core/Applications/ApplicationService.cs @@ -9,6 +9,7 @@ using NzbDrone.Core.Configuration.Events; using NzbDrone.Core.Indexers; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider.Events; namespace NzbDrone.Core.Applications @@ -69,7 +70,10 @@ namespace NzbDrone.Core.Applications foreach (var app in enabledApps) { - ExecuteAction(a => a.AddIndexer((IndexerDefinition)message.Definition), app); + if (ShouldHandleIndexer(app.Definition, message.Definition)) + { + ExecuteAction(a => a.AddIndexer((IndexerDefinition)message.Definition), app); + } } } @@ -157,14 +161,14 @@ namespace NzbDrone.Core.Applications if (indexerMappings.Any(x => x.IndexerId == definition.Id)) { - if (((ApplicationDefinition)app.Definition).SyncLevel == ApplicationSyncLevel.FullSync) + if (((ApplicationDefinition)app.Definition).SyncLevel == ApplicationSyncLevel.FullSync && ShouldHandleIndexer(app.Definition, indexer)) { ExecuteAction(a => a.UpdateIndexer(definition), app); } } else { - if (indexer.Enable) + if (indexer.Enable && ShouldHandleIndexer(app.Definition, indexer)) { ExecuteAction(a => a.AddIndexer(definition), app); } @@ -187,6 +191,24 @@ namespace NzbDrone.Core.Applications } } + private bool ShouldHandleIndexer(ProviderDefinition app, ProviderDefinition indexer) + { + if (app.Tags.Empty()) + { + _logger.Debug("No tags set for this application."); + return true; + } + + if (app.Tags.Intersect(indexer.Tags).Any()) + { + _logger.Debug("Application and indexer have one or more intersecting tags."); + return true; + } + + _logger.Debug("{0} does not have any intersecting tags with {1}. Indexer will not be synced", app.Name, indexer.Name); + return false; + } + private void ExecuteAction(Action<IApplication> applicationAction, IApplication application) { try From e90a796b27dc5e9d0dfe0335a7f873428d16e22a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 1 May 2022 17:56:07 -0500 Subject: [PATCH 0459/2320] New: Seed Settings Sync --- .../Indexer/Edit/EditIndexerModalContent.js | 2 +- .../src/Indexer/Editor/IndexerEditorFooter.js | 2 +- .../Index/Menus/IndexerIndexSortMenu.js | 2 +- .../src/Settings/Profiles/App/AppProfiles.js | 2 +- .../App/EditAppProfileModalContent.js | 19 +++++++- .../src/Store/Actions/indexerIndexActions.js | 4 +- .../Cloud/ProwlarrCloudRequestBuilder.cs | 6 +++ .../Applications/Lidarr/Lidarr.cs | 7 +++ .../Applications/Lidarr/LidarrIndexer.cs | 15 +++++- .../Applications/Radarr/Radarr.cs | 7 +++ .../Applications/Radarr/RadarrIndexer.cs | 15 +++++- .../Applications/Readarr/Readarr.cs | 7 +++ .../Applications/Readarr/ReadarrIndexer.cs | 15 +++++- .../Applications/Sonarr/Sonarr.cs | 7 +++ .../Applications/Sonarr/SonarrIndexer.cs | 15 +++++- .../Applications/Whisparr/Whisparr.cs | 7 +++ .../Applications/Whisparr/WhisparrIndexer.cs | 15 +++++- .../Migration/018_minimum_seeders.cs | 15 ++++++ .../IndexerSearch/ReleaseAnalyticsService.cs | 48 +++++++++++++++++++ .../Definitions/Torznab/TorznabSettings.cs | 6 ++- .../Indexers/ITorrentIndexerSettings.cs | 13 +++++ .../Indexers/IndexerTorrentBaseSettings.cs | 47 ++++++++++++++++++ .../Settings/CookieTorrentBaseSettings.cs | 5 +- .../Settings/NoAuthTorrentBaseSettings.cs | 5 +- .../Settings/UserPassTorrentBaseSettings.cs | 5 +- src/NzbDrone.Core/Localization/Core/en.json | 10 ++-- src/NzbDrone.Core/Profiles/AppSyncProfile.cs | 1 + .../Profiles/AppSyncProfileService.cs | 3 +- .../Profiles/App/AppProfileResource.cs | 7 ++- 29 files changed, 288 insertions(+), 24 deletions(-) create mode 100644 src/NzbDrone.Core/Datastore/Migration/018_minimum_seeders.cs create mode 100644 src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs create mode 100644 src/NzbDrone.Core/Indexers/ITorrentIndexerSettings.cs create mode 100644 src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs diff --git a/frontend/src/Indexer/Edit/EditIndexerModalContent.js b/frontend/src/Indexer/Edit/EditIndexerModalContent.js index 08a097127..b83522fcf 100644 --- a/frontend/src/Indexer/Edit/EditIndexerModalContent.js +++ b/frontend/src/Indexer/Edit/EditIndexerModalContent.js @@ -112,7 +112,7 @@ function EditIndexerModalContent(props) { </FormGroup> <FormGroup> - <FormLabel>{translate('AppProfile')}</FormLabel> + <FormLabel>{translate('SyncProfile')}</FormLabel> <FormInputGroup type={inputTypes.APP_PROFILE_SELECT} diff --git a/frontend/src/Indexer/Editor/IndexerEditorFooter.js b/frontend/src/Indexer/Editor/IndexerEditorFooter.js index 1818eae72..05f16c23b 100644 --- a/frontend/src/Indexer/Editor/IndexerEditorFooter.js +++ b/frontend/src/Indexer/Editor/IndexerEditorFooter.js @@ -133,7 +133,7 @@ class IndexerEditorFooter extends Component { <div className={styles.inputContainer}> <IndexerEditorFooterLabel - label={translate('AppProfile')} + label={translate('SyncProfile')} isSaving={isSaving && appProfileId !== NO_CHANGE} /> diff --git a/frontend/src/Indexer/Index/Menus/IndexerIndexSortMenu.js b/frontend/src/Indexer/Index/Menus/IndexerIndexSortMenu.js index 3afd08e01..3ce324ff3 100644 --- a/frontend/src/Indexer/Index/Menus/IndexerIndexSortMenu.js +++ b/frontend/src/Indexer/Index/Menus/IndexerIndexSortMenu.js @@ -53,7 +53,7 @@ function IndexerIndexSortMenu(props) { sortDirection={sortDirection} onPress={onSortSelect} > - {translate('AppProfile')} + {translate('SyncProfile')} </SortMenuItem> <SortMenuItem diff --git a/frontend/src/Settings/Profiles/App/AppProfiles.js b/frontend/src/Settings/Profiles/App/AppProfiles.js index b93b0fe51..8a1bb1cbc 100644 --- a/frontend/src/Settings/Profiles/App/AppProfiles.js +++ b/frontend/src/Settings/Profiles/App/AppProfiles.js @@ -52,7 +52,7 @@ class AppProfiles extends Component { } = this.props; return ( - <FieldSet legend={translate('AppProfiles')}> + <FieldSet legend={translate('SyncProfiles')}> <PageSectionContent errorMessage={translate('UnableToLoadAppProfiles')} {...otherProps}c={true} diff --git a/frontend/src/Settings/Profiles/App/EditAppProfileModalContent.js b/frontend/src/Settings/Profiles/App/EditAppProfileModalContent.js index c3722c7e0..aace8e039 100644 --- a/frontend/src/Settings/Profiles/App/EditAppProfileModalContent.js +++ b/frontend/src/Settings/Profiles/App/EditAppProfileModalContent.js @@ -40,14 +40,15 @@ class EditAppProfileModalContent extends Component { name, enableRss, enableInteractiveSearch, - enableAutomaticSearch + enableAutomaticSearch, + minimumSeeders } = item; return ( <ModalContent onModalClose={onModalClose}> <ModalHeader> - {id ? translate('EditAppProfile') : translate('AddAppProfile')} + {id ? translate('EditSyncProfile') : translate('AddSyncProfile')} </ModalHeader> <ModalBody> @@ -123,6 +124,20 @@ class EditAppProfileModalContent extends Component { onChange={onInputChange} /> </FormGroup> + + <FormGroup> + <FormLabel> + {translate('MinimumSeeders')} + </FormLabel> + + <FormInputGroup + type={inputTypes.NUMBER} + name="minimumSeeders" + {...minimumSeeders} + helpText={translate('MinimumSeedersHelpText')} + onChange={onInputChange} + /> + </FormGroup> </Form> } </div> diff --git a/frontend/src/Store/Actions/indexerIndexActions.js b/frontend/src/Store/Actions/indexerIndexActions.js index fb5cd8c43..9a0c7679d 100644 --- a/frontend/src/Store/Actions/indexerIndexActions.js +++ b/frontend/src/Store/Actions/indexerIndexActions.js @@ -76,7 +76,7 @@ export const defaultState = { }, { name: 'appProfileId', - label: translate('AppProfile'), + label: translate('SyncProfile'), isSortable: true, isVisible: true }, @@ -152,7 +152,7 @@ export const defaultState = { }, { name: 'appProfileId', - label: translate('AppProfile'), + label: translate('SyncProfile'), type: filterBuilderTypes.EXACT, valueType: filterBuilderValueTypes.APP_PROFILE }, diff --git a/src/NzbDrone.Common/Cloud/ProwlarrCloudRequestBuilder.cs b/src/NzbDrone.Common/Cloud/ProwlarrCloudRequestBuilder.cs index 86ced4c84..11356dde0 100644 --- a/src/NzbDrone.Common/Cloud/ProwlarrCloudRequestBuilder.cs +++ b/src/NzbDrone.Common/Cloud/ProwlarrCloudRequestBuilder.cs @@ -5,6 +5,7 @@ namespace NzbDrone.Common.Cloud public interface IProwlarrCloudRequestBuilder { IHttpRequestBuilderFactory Services { get; } + IHttpRequestBuilderFactory Releases { get; } } public class ProwlarrCloudRequestBuilder : IProwlarrCloudRequestBuilder @@ -13,8 +14,13 @@ namespace NzbDrone.Common.Cloud { Services = new HttpRequestBuilder("https://prowlarr.servarr.com/v1/") .CreateFactory(); + + Releases = new HttpRequestBuilder("https://releases.servarr.com/v1/") + .CreateFactory(); } public IHttpRequestBuilderFactory Services { get; private set; } + + public IHttpRequestBuilderFactory Releases { get; private set; } } } diff --git a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs index e275f8d09..0b03058d9 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs @@ -183,6 +183,13 @@ namespace NzbDrone.Core.Applications.Lidarr lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey; lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray())); + if (indexer.Protocol == DownloadProtocol.Torrent) + { + lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value = indexer.AppProfile.Value.MinimumSeeders; + lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedRatio; + lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; + } + return lidarrIndexer; } } diff --git a/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs b/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs index ccd3c0db3..3fd8456eb 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; @@ -31,6 +32,18 @@ namespace NzbDrone.Core.Applications.Lidarr var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey").Value; var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value); + var minimumSeeders = Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); + var otherMinimumSeeders = other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); + var minimumSeedersCompare = minimumSeeders == otherMinimumSeeders; + + var seedTime = Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value); + var otherSeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value); + var seedTimeCompare = seedTime == otherSeedTime; + + var seedRatio = Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); + var otherSeedRatio = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); + var seedRatioCompare = seedRatio == otherSeedRatio; + return other.EnableRss == EnableRss && other.EnableAutomaticSearch == EnableAutomaticSearch && other.EnableInteractiveSearch == EnableInteractiveSearch && @@ -38,7 +51,7 @@ namespace NzbDrone.Core.Applications.Lidarr other.Implementation == Implementation && other.Priority == Priority && other.Id == Id && - apiKey && apiPath && baseUrl && cats; + apiKey && apiPath && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare; } } } diff --git a/src/NzbDrone.Core/Applications/Radarr/Radarr.cs b/src/NzbDrone.Core/Applications/Radarr/Radarr.cs index e5719736e..13e4ffe8a 100644 --- a/src/NzbDrone.Core/Applications/Radarr/Radarr.cs +++ b/src/NzbDrone.Core/Applications/Radarr/Radarr.cs @@ -183,6 +183,13 @@ namespace NzbDrone.Core.Applications.Radarr radarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey; radarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray())); + if (indexer.Protocol == DownloadProtocol.Torrent) + { + radarrIndexer.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value = indexer.AppProfile.Value.MinimumSeeders; + radarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedRatio; + radarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; + } + return radarrIndexer; } } diff --git a/src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs b/src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs index 025b06044..c9b649913 100644 --- a/src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; @@ -31,6 +32,18 @@ namespace NzbDrone.Core.Applications.Radarr var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey").Value; var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value); + var minimumSeeders = Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); + var otherMinimumSeeders = other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); + var minimumSeedersCompare = minimumSeeders == otherMinimumSeeders; + + var seedTime = Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value); + var otherSeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value); + var seedTimeCompare = seedTime == otherSeedTime; + + var seedRatio = Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); + var otherSeedRatio = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); + var seedRatioCompare = seedRatio == otherSeedRatio; + return other.EnableRss == EnableRss && other.EnableAutomaticSearch == EnableAutomaticSearch && other.EnableInteractiveSearch == EnableInteractiveSearch && @@ -38,7 +51,7 @@ namespace NzbDrone.Core.Applications.Radarr other.Implementation == Implementation && other.Priority == Priority && other.Id == Id && - apiKey && apiPath && baseUrl && cats; + apiKey && apiPath && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare; } } } diff --git a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs index 606304a11..13cc761c8 100644 --- a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs +++ b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs @@ -183,6 +183,13 @@ namespace NzbDrone.Core.Applications.Readarr readarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey; readarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray())); + if (indexer.Protocol == DownloadProtocol.Torrent) + { + readarrIndexer.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value = indexer.AppProfile.Value.MinimumSeeders; + readarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedRatio; + readarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; + } + return readarrIndexer; } } diff --git a/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs b/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs index 641a53e80..7e7d51dff 100644 --- a/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; @@ -31,6 +32,18 @@ namespace NzbDrone.Core.Applications.Readarr var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey").Value; var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value); + var minimumSeeders = Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); + var otherMinimumSeeders = other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); + var minimumSeedersCompare = minimumSeeders == otherMinimumSeeders; + + var seedTime = Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value); + var otherSeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value); + var seedTimeCompare = seedTime == otherSeedTime; + + var seedRatio = Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); + var otherSeedRatio = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); + var seedRatioCompare = seedRatio == otherSeedRatio; + return other.EnableRss == EnableRss && other.EnableAutomaticSearch == EnableAutomaticSearch && other.EnableInteractiveSearch == EnableInteractiveSearch && @@ -38,7 +51,7 @@ namespace NzbDrone.Core.Applications.Readarr other.Implementation == Implementation && other.Priority == Priority && other.Id == Id && - apiKey && apiPath && baseUrl && cats; + apiKey && apiPath && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare; } } } diff --git a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs index 9538cee90..8fa513656 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs @@ -184,6 +184,13 @@ namespace NzbDrone.Core.Applications.Sonarr sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray())); sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "animeCategories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray())); + if (indexer.Protocol == DownloadProtocol.Torrent) + { + sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value = indexer.AppProfile.Value.MinimumSeeders; + sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedRatio; + sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; + } + return sonarrIndexer; } } diff --git a/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs b/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs index fe0bfebf3..842af9776 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; @@ -32,6 +33,18 @@ namespace NzbDrone.Core.Applications.Sonarr var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value); var animeCats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "animeCategories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "animeCategories").Value); + var minimumSeeders = Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); + var otherMinimumSeeders = other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); + var minimumSeedersCompare = minimumSeeders == otherMinimumSeeders; + + var seedTime = Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value); + var otherSeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value); + var seedTimeCompare = seedTime == otherSeedTime; + + var seedRatio = Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); + var otherSeedRatio = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); + var seedRatioCompare = seedRatio == otherSeedRatio; + return other.EnableRss == EnableRss && other.EnableAutomaticSearch == EnableAutomaticSearch && other.EnableInteractiveSearch == EnableInteractiveSearch && @@ -39,7 +52,7 @@ namespace NzbDrone.Core.Applications.Sonarr other.Implementation == Implementation && other.Priority == Priority && other.Id == Id && - apiKey && apiPath && baseUrl && cats && animeCats; + apiKey && apiPath && baseUrl && cats && animeCats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare; } } } diff --git a/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs b/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs index a9a45c06a..ff6a5966a 100644 --- a/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs +++ b/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs @@ -183,6 +183,13 @@ namespace NzbDrone.Core.Applications.Whisparr whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey; whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray())); + if (indexer.Protocol == DownloadProtocol.Torrent) + { + whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value = indexer.AppProfile.Value.MinimumSeeders; + whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedRatio; + whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; + } + return whisparrIndexer; } } diff --git a/src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs b/src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs index cd8c5df01..5898b1c96 100644 --- a/src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; @@ -31,6 +32,18 @@ namespace NzbDrone.Core.Applications.Whisparr var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey").Value; var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value); + var minimumSeeders = Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); + var otherMinimumSeeders = other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); + var minimumSeedersCompare = minimumSeeders == otherMinimumSeeders; + + var seedTime = Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value); + var otherSeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value); + var seedTimeCompare = seedTime == otherSeedTime; + + var seedRatio = Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); + var otherSeedRatio = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); + var seedRatioCompare = seedRatio == otherSeedRatio; + return other.EnableRss == EnableRss && other.EnableAutomaticSearch == EnableAutomaticSearch && other.EnableInteractiveSearch == EnableInteractiveSearch && @@ -38,7 +51,7 @@ namespace NzbDrone.Core.Applications.Whisparr other.Implementation == Implementation && other.Priority == Priority && other.Id == Id && - apiKey && apiPath && baseUrl && cats; + apiKey && apiPath && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare; } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/018_minimum_seeders.cs b/src/NzbDrone.Core/Datastore/Migration/018_minimum_seeders.cs new file mode 100644 index 000000000..9569db660 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/018_minimum_seeders.cs @@ -0,0 +1,15 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(18)] + public class minimum_seeders : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Alter.Table("AppSyncProfiles") + .AddColumn("MinimumSeeders").AsInt32().NotNullable().WithDefaultValue(1); + } + } +} diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs new file mode 100644 index 000000000..f4840ffcc --- /dev/null +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs @@ -0,0 +1,48 @@ +using System.Linq; +using System.Net.Http; +using NzbDrone.Common.Cloud; +using NzbDrone.Common.Http; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Analytics; +using NzbDrone.Core.Indexers.Events; +using NzbDrone.Core.Messaging.Events; + +namespace NzbDrone.Core.IndexerSearch +{ + public class ReleaseAnalyticsService : IHandleAsync<IndexerQueryEvent> + { + private readonly IHttpClient _httpClient; + private readonly IHttpRequestBuilderFactory _requestBuilder; + private readonly IAnalyticsService _analyticsService; + + public ReleaseAnalyticsService(IHttpClient httpClient, IProwlarrCloudRequestBuilder requestBuilder, IAnalyticsService analyticsService) + { + _analyticsService = analyticsService; + _requestBuilder = requestBuilder.Releases; + _httpClient = httpClient; + } + + public void HandleAsync(IndexerQueryEvent message) + { + if (_analyticsService.IsEnabled) + { + var request = _requestBuilder.Create().Resource("release/push").Build(); + request.Method = HttpMethod.Post; + request.Headers.ContentType = "application/json"; + request.SuppressHttpError = true; + + var body = message.QueryResult.Releases.Select(x => new + { + Title = x.Title, + Categories = x.Categories.Where(c => c.Id < 10000).Select(c => c.Id), + Protocol = x.DownloadProtocol.ToString(), + Size = x.Size, + PublishDate = x.PublishDate + }); + + request.SetContent(body.ToJson()); + _httpClient.Post(request); + } + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabSettings.cs index d2b7c1bb5..c1ea89cc9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabSettings.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Text.RegularExpressions; using FluentValidation; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Annotations; using NzbDrone.Core.Indexers.Newznab; using NzbDrone.Core.Validation; @@ -36,7 +37,7 @@ namespace NzbDrone.Core.Indexers.Torznab } } - public class TorznabSettings : NewznabSettings + public class TorznabSettings : NewznabSettings, ITorrentIndexerSettings { private static readonly TorznabSettingsValidator Validator = new TorznabSettingsValidator(); @@ -44,6 +45,9 @@ namespace NzbDrone.Core.Indexers.Torznab { } + [FieldDefinition(3)] + public IndexerTorrentBaseSettings TorrentBaseSettings { get; set; } = new IndexerTorrentBaseSettings(); + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/ITorrentIndexerSettings.cs b/src/NzbDrone.Core/Indexers/ITorrentIndexerSettings.cs new file mode 100644 index 000000000..11f0d543a --- /dev/null +++ b/src/NzbDrone.Core/Indexers/ITorrentIndexerSettings.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NzbDrone.Core.Indexers +{ + public interface ITorrentIndexerSettings : IIndexerSettings + { + IndexerTorrentBaseSettings TorrentBaseSettings { get; set; } + } +} diff --git a/src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs new file mode 100644 index 000000000..228b38858 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs @@ -0,0 +1,47 @@ +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Indexers +{ + public class IndexerTorrentSettingsValidator : AbstractValidator<IndexerTorrentBaseSettings> + { + public IndexerTorrentSettingsValidator(double seedRatioMinimum = 0.0, int seedTimeMinimum = 0, int seasonPackSeedTimeMinimum = 0) + { + RuleFor(c => c.SeedRatio).GreaterThan(0.0) + .When(c => c.SeedRatio.HasValue) + .AsWarning().WithMessage("Should be greater than zero"); + + RuleFor(c => c.SeedTime).GreaterThan(0) + .When(c => c.SeedTime.HasValue) + .AsWarning().WithMessage("Should be greater than zero"); + + if (seedRatioMinimum != 0.0) + { + RuleFor(c => c.SeedRatio).GreaterThanOrEqualTo(seedRatioMinimum) + .When(c => c.SeedRatio > 0.0) + .AsWarning() + .WithMessage($"Under {seedRatioMinimum} leads to H&R"); + } + + if (seedTimeMinimum != 0) + { + RuleFor(c => c.SeedTime).GreaterThanOrEqualTo(seedTimeMinimum) + .When(c => c.SeedTime > 0) + .AsWarning() + .WithMessage($"Under {seedTimeMinimum} leads to H&R"); + } + } + } + + public class IndexerTorrentBaseSettings + { + private static readonly IndexerTorrentSettingsValidator Validator = new IndexerTorrentSettingsValidator(); + + [FieldDefinition(1, Type = FieldType.Textbox, Label = "Seed Ratio", HelpText = "The ratio a torrent should reach before stopping, empty is app's default", Advanced = true)] + public double? SeedRatio { get; set; } + + [FieldDefinition(2, Type = FieldType.Number, Label = "Seed Time", HelpText = "The time a torrent should be seeded before stopping, empty is app's default", Advanced = true)] + public int? SeedTime { get; set; } + } +} diff --git a/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs index 92e5e9983..653127007 100644 --- a/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs @@ -4,7 +4,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Settings { - public class CookieTorrentBaseSettings : IIndexerSettings + public class CookieTorrentBaseSettings : ITorrentIndexerSettings { public class CookieBaseSettingsValidator : AbstractValidator<CookieTorrentBaseSettings> { @@ -30,6 +30,9 @@ namespace NzbDrone.Core.Indexers.Settings [FieldDefinition(3)] public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); + [FieldDefinition(4)] + public IndexerTorrentBaseSettings TorrentBaseSettings { get; set; } = new IndexerTorrentBaseSettings(); + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs index eed3a814d..9aff60db1 100644 --- a/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Indexers.Settings { } - public class NoAuthTorrentBaseSettings : IIndexerSettings + public class NoAuthTorrentBaseSettings : ITorrentIndexerSettings { private static readonly NoAuthSettingsValidator Validator = new NoAuthSettingsValidator(); @@ -18,6 +18,9 @@ namespace NzbDrone.Core.Indexers.Settings [FieldDefinition(2)] public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); + [FieldDefinition(3)] + public IndexerTorrentBaseSettings TorrentBaseSettings { get; set; } = new IndexerTorrentBaseSettings(); + public virtual NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/Settings/UserPassTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/Settings/UserPassTorrentBaseSettings.cs index 552376e07..7b03f66ee 100644 --- a/src/NzbDrone.Core/Indexers/Settings/UserPassTorrentBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/Settings/UserPassTorrentBaseSettings.cs @@ -4,7 +4,7 @@ using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Settings { - public class UserPassTorrentBaseSettings : IIndexerSettings + public class UserPassTorrentBaseSettings : ITorrentIndexerSettings { public class UserPassBaseSettingsValidator : AbstractValidator<UserPassTorrentBaseSettings> { @@ -35,6 +35,9 @@ namespace NzbDrone.Core.Indexers.Settings [FieldDefinition(4)] public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); + [FieldDefinition(5)] + public IndexerTorrentBaseSettings TorrentBaseSettings { get; set; } = new IndexerTorrentBaseSettings(); + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 7c0408572..f66aa4eb6 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -3,7 +3,6 @@ "AcceptConfirmationModal": "Accept Confirmation Modal", "Actions": "Actions", "Add": "Add", - "AddAppProfile": "Add App Sync Profile", "AddDownloadClient": "Add Download Client", "AddDownloadClientToProwlarr": "Adding a download client allows Prowlarr to send releases direct from the UI while doing a manual search.", "Added": "Added", @@ -13,6 +12,7 @@ "AddingTag": "Adding tag", "AddNewIndexer": "Add New Indexer", "AddRemoveOnly": "Add and Remove Only", + "AddSyncProfile": "Add Sync Profile", "AddToDownloadClient": "Add release to download client", "Age": "Age", "All": "All", @@ -32,10 +32,8 @@ "ApplyTagsHelpTexts2": "Add: Add the tags the existing list of tags", "ApplyTagsHelpTexts3": "Remove: Remove the entered tags", "ApplyTagsHelpTexts4": "Replace: Replace the tags with the entered tags (enter no tags to clear all tags)", - "AppProfile": "App Profile", "AppProfileDeleteConfirm": "Are you sure you want to delete {0}?", "AppProfileInUse": "App Profile in Use", - "AppProfiles": "App Profiles", "AppProfileSelectHelpText": "App profiles are used to control RSS, Automatic Search and Interactive Search settings on application sync", "Apps": "Apps", "AppSettingsSummary": "Applications and settings to configure how Prowlarr interacts with your PVR programs", @@ -119,8 +117,8 @@ "DownloadClientStatusCheckAllClientMessage": "All download clients are unavailable due to failures", "DownloadClientStatusCheckSingleClientMessage": "Download clients unavailable due to failures: {0}", "Edit": "Edit", - "EditAppProfile": "Edit App Profile", "EditIndexer": "Edit Indexer", + "EditSyncProfile": "Edit Sync Profile", "Enable": "Enable", "EnableAutomaticSearch": "Enable Automatic Search", "EnableAutomaticSearchHelpText": "Will be used when automatic searches are performed via the UI or by Prowlarr", @@ -222,6 +220,8 @@ "Mechanism": "Mechanism", "Message": "Message", "MIA": "MIA", + "MinimumSeeders": "Minimum Seeders", + "MinimumSeedersHelpText": "Minimum seeders required by the Appliction for the indexer to grab", "Mode": "Mode", "MoreInfo": "More Info", "MovieIndexScrollBottom": "Movie Index: Scroll Bottom", @@ -372,6 +372,8 @@ "SyncLevel": "Sync Level", "SyncLevelAddRemove": "Add and Remove Only: When indexers are added or removed from Prowlarr, it will update this remote app.", "SyncLevelFull": "Full Sync: Will keep this app's indexers fully in sync. Changes made to indexers in Prowlarr are then synced to this app. Any change made to indexers remotely within this app will be overridden by Prowlarr on the next sync.", + "SyncProfile": "Sync Profile", + "SyncProfiles": "Sync Profiles", "System": "System", "SystemTimeCheckMessage": "System time is off by more than 1 day. Scheduled tasks may not run correctly until the time is corrected", "TableOptions": "Table Options", diff --git a/src/NzbDrone.Core/Profiles/AppSyncProfile.cs b/src/NzbDrone.Core/Profiles/AppSyncProfile.cs index e7a7e896e..a37a99c70 100644 --- a/src/NzbDrone.Core/Profiles/AppSyncProfile.cs +++ b/src/NzbDrone.Core/Profiles/AppSyncProfile.cs @@ -8,5 +8,6 @@ namespace NzbDrone.Core.Profiles public bool EnableRss { get; set; } public bool EnableAutomaticSearch { get; set; } public bool EnableInteractiveSearch { get; set; } + public int MinimumSeeders { get; set; } } } diff --git a/src/NzbDrone.Core/Profiles/AppSyncProfileService.cs b/src/NzbDrone.Core/Profiles/AppSyncProfileService.cs index 952a06d8e..73c07d0a8 100644 --- a/src/NzbDrone.Core/Profiles/AppSyncProfileService.cs +++ b/src/NzbDrone.Core/Profiles/AppSyncProfileService.cs @@ -88,7 +88,8 @@ namespace NzbDrone.Core.Profiles Name = name, EnableAutomaticSearch = true, EnableInteractiveSearch = true, - EnableRss = true + EnableRss = true, + MinimumSeeders = 1 }; return qualityProfile; diff --git a/src/Prowlarr.Api.V1/Profiles/App/AppProfileResource.cs b/src/Prowlarr.Api.V1/Profiles/App/AppProfileResource.cs index ebc968b48..aa88dfac6 100644 --- a/src/Prowlarr.Api.V1/Profiles/App/AppProfileResource.cs +++ b/src/Prowlarr.Api.V1/Profiles/App/AppProfileResource.cs @@ -11,6 +11,7 @@ namespace Prowlarr.Api.V1.Profiles.App public bool EnableRss { get; set; } public bool EnableInteractiveSearch { get; set; } public bool EnableAutomaticSearch { get; set; } + public int MinimumSeeders { get; set; } } public static class ProfileResourceMapper @@ -28,7 +29,8 @@ namespace Prowlarr.Api.V1.Profiles.App Name = model.Name, EnableRss = model.EnableRss, EnableInteractiveSearch = model.EnableInteractiveSearch, - EnableAutomaticSearch = model.EnableAutomaticSearch + EnableAutomaticSearch = model.EnableAutomaticSearch, + MinimumSeeders = model.MinimumSeeders }; } @@ -45,7 +47,8 @@ namespace Prowlarr.Api.V1.Profiles.App Name = resource.Name, EnableRss = resource.EnableRss, EnableInteractiveSearch = resource.EnableInteractiveSearch, - EnableAutomaticSearch = resource.EnableAutomaticSearch + EnableAutomaticSearch = resource.EnableAutomaticSearch, + MinimumSeeders = resource.MinimumSeeders }; } From 452f32d46bd09fb874601e90df3bf1b43ca33590 Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Wed, 11 May 2022 00:41:57 +0000 Subject: [PATCH 0460/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index 7a131196e..f3ddca832 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -4435,6 +4435,10 @@ }, "enableAutomaticSearch": { "type": "boolean" + }, + "minimumSeeders": { + "type": "integer", + "format": "int32" } }, "additionalProperties": false From ac7896b67b4a8633a47f7f492939f9217f844e12 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 10 May 2022 20:11:03 -0500 Subject: [PATCH 0461/2320] Fixed: Indexer Tags Helptext --- src/NzbDrone.Core/Localization/Core/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index f66aa4eb6..da609f3b6 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -196,7 +196,7 @@ "IndexersSelectedInterp": "{0} Indexer(s) Selected", "IndexerStatusCheckAllClientMessage": "All indexers are unavailable due to failures", "IndexerStatusCheckSingleClientMessage": "Indexers unavailable due to failures: {0}", - "IndexerTagsHelpText": "Use tags to specify Indexer Proxies or just to organize your indexers.", + "IndexerTagsHelpText": "Use tags to specify Indexer Proxies, which apps the indexer is synced to, or just to organize your indexers.", "IndexerVipCheckExpiredClientMessage": "Indexer VIP benefits have expired: {0}", "IndexerVipCheckExpiringClientMessage": "Indexer VIP benefits expiring soon: {0}", "Info": "Info", From f5685c1ca6b59a23d453eba955d540bc14519f7a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 11 May 2022 21:52:13 -0500 Subject: [PATCH 0462/2320] New: Add Sonarr SeasonSeedTime Sync --- src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs | 1 + src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs index 8fa513656..4b62bdad7 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs @@ -189,6 +189,7 @@ namespace NzbDrone.Core.Applications.Sonarr sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value = indexer.AppProfile.Value.MinimumSeeders; sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedRatio; sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; + sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seasonPackSeedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; } return sonarrIndexer; diff --git a/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs b/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs index 842af9776..dc1282112 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs @@ -41,6 +41,10 @@ namespace NzbDrone.Core.Applications.Sonarr var otherSeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value); var seedTimeCompare = seedTime == otherSeedTime; + var seasonSeedTime = Fields.FirstOrDefault(x => x.Name == "seedCriteria.seasonPackSeedTime")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seasonPackSeedTime").Value); + var otherSeasonSeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seasonPackSeedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seasonPackSeedTime").Value); + var seasonSeedTimeCompare = seasonSeedTime == otherSeasonSeedTime; + var seedRatio = Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); var otherSeedRatio = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); var seedRatioCompare = seedRatio == otherSeedRatio; @@ -52,7 +56,7 @@ namespace NzbDrone.Core.Applications.Sonarr other.Implementation == Implementation && other.Priority == Priority && other.Id == Id && - apiKey && apiPath && baseUrl && cats && animeCats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare; + apiKey && apiPath && baseUrl && cats && animeCats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && seasonSeedTimeCompare; } } } From bb9969feb5297c6043468392f44c11da8518d6d3 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 11 May 2022 22:02:37 -0500 Subject: [PATCH 0463/2320] New: Add Lidarr and Readarr DiscographySeedTime Sync --- src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs | 5 +++++ src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs | 6 +++++- src/NzbDrone.Core/Applications/Readarr/Readarr.cs | 5 +++++ src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs | 6 +++++- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs index 0b03058d9..8ff099786 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs @@ -188,6 +188,11 @@ namespace NzbDrone.Core.Applications.Lidarr lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value = indexer.AppProfile.Value.MinimumSeeders; lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedRatio; lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; + + if (lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime") != null) + { + lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; + } } return lidarrIndexer; diff --git a/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs b/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs index 3fd8456eb..63023d2f9 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs @@ -40,6 +40,10 @@ namespace NzbDrone.Core.Applications.Lidarr var otherSeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value); var seedTimeCompare = seedTime == otherSeedTime; + var discographySeedTime = Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seasonPackSeedTime").Value); + var otherDiscographySeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seasonPackSeedTime").Value); + var discographySeedTimeCompare = discographySeedTime == otherDiscographySeedTime; + var seedRatio = Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); var otherSeedRatio = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); var seedRatioCompare = seedRatio == otherSeedRatio; @@ -51,7 +55,7 @@ namespace NzbDrone.Core.Applications.Lidarr other.Implementation == Implementation && other.Priority == Priority && other.Id == Id && - apiKey && apiPath && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare; + apiKey && apiPath && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && discographySeedTimeCompare; } } } diff --git a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs index 13cc761c8..40cc9cc35 100644 --- a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs +++ b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs @@ -188,6 +188,11 @@ namespace NzbDrone.Core.Applications.Readarr readarrIndexer.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value = indexer.AppProfile.Value.MinimumSeeders; readarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedRatio; readarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; + + if (readarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime") != null) + { + readarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; + } } return readarrIndexer; diff --git a/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs b/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs index 7e7d51dff..d41073717 100644 --- a/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs @@ -40,6 +40,10 @@ namespace NzbDrone.Core.Applications.Readarr var otherSeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value); var seedTimeCompare = seedTime == otherSeedTime; + var discographySeedTime = Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seasonPackSeedTime").Value); + var otherDiscographySeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seasonPackSeedTime").Value); + var discographySeedTimeCompare = discographySeedTime == otherDiscographySeedTime; + var seedRatio = Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); var otherSeedRatio = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); var seedRatioCompare = seedRatio == otherSeedRatio; @@ -51,7 +55,7 @@ namespace NzbDrone.Core.Applications.Readarr other.Implementation == Implementation && other.Priority == Priority && other.Id == Id && - apiKey && apiPath && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare; + apiKey && apiPath && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && discographySeedTimeCompare; } } } From 52075277168854db3cceb922390e507dedaa0508 Mon Sep 17 00:00:00 2001 From: "Amos (LFlare) Ng" <amosng1@gmail.com> Date: Fri, 13 May 2022 09:44:42 +0800 Subject: [PATCH 0464/2320] Fixed: (AnimeBytes) Handle series synonyms with commas (#984) Fixed: (AnimeBytes) Avoid repeating synonyms on key "3" --- .../Indexers/Definitions/AnimeBytes.cs | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs index 0e81c0ac9..e698adb33 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs @@ -228,11 +228,37 @@ namespace NzbDrone.Core.Indexers.Definitions if (syn.StringArray != null) { - synonyms.AddRange(syn.StringArray); + if (syn.StringArray.Count >= 1) + { + synonyms.Add(syn.StringArray[0]); + } + + if (syn.StringArray.Count >= 2) + { + synonyms.Add(syn.StringArray[1]); + } + + if (syn.StringArray.Count == 3) + { + synonyms.AddRange(syn.StringArray[2].Split(',').Select(t => t.Trim())); + } } else { - synonyms.AddRange(syn.StringMap.Values); + if (syn.StringMap.ContainsKey("0")) + { + synonyms.Add(syn.StringMap["0"]); + } + + if (syn.StringMap.ContainsKey("1")) + { + synonyms.Add(syn.StringMap["1"]); + } + + if (syn.StringMap.ContainsKey("2")) + { + synonyms.AddRange(syn.StringMap["2"].Split(',').Select(t => t.Trim())); + } } } @@ -492,7 +518,7 @@ namespace NzbDrone.Core.Indexers.Definitions [FieldDefinition(3, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] public string Username { get; set; } - [FieldDefinition(4, Label = "Enable Sonarr Compatibility", Type = FieldType.Checkbox, HelpText = "Makes Prowlarr try to add Season information into Release names, without this Sonarr can't match any Seasons, but it has a lot of false positives as well")] + [FieldDefinition(4, Label = "Enable Sonarr Compatibility", Type = FieldType.Checkbox, HelpText = "Makes Prowlarr try to add Season information into Release names, without this Sonarr can't match any Seasons, but it has a lot of false positives as well")] public bool EnableSonarrCompatibility { get; set; } public override NzbDroneValidationResult Validate() From 166038a3b8f495cd5af1d891e3785add33fec1c8 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 13 May 2022 17:49:27 -0500 Subject: [PATCH 0465/2320] Fixed: Localization for two part language dialects Fixes #999 --- .../Localization/LocalizationService.cs | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Core/Localization/LocalizationService.cs b/src/NzbDrone.Core/Localization/LocalizationService.cs index beba6aff9..66fda0b60 100644 --- a/src/NzbDrone.Core/Localization/LocalizationService.cs +++ b/src/NzbDrone.Core/Localization/LocalizationService.cs @@ -45,14 +45,14 @@ namespace NzbDrone.Core.Localization public Dictionary<string, string> GetLocalizationDictionary() { - var language = IsoLanguages.Get((Language)_configService.UILanguage).TwoLetterCode; + var language = GetSetLanguageFileName(); return GetLocalizationDictionary(language); } public string GetLocalizedString(string phrase) { - var language = IsoLanguages.Get((Language)_configService.UILanguage).TwoLetterCode; + var language = GetSetLanguageFileName(); return GetLocalizedString(phrase, language); } @@ -66,7 +66,7 @@ namespace NzbDrone.Core.Localization if (language.IsNullOrWhiteSpace()) { - language = IsoLanguages.Get((Language)_configService.UILanguage).TwoLetterCode; + language = GetSetLanguageFileName(); } if (language == null) @@ -84,6 +84,19 @@ namespace NzbDrone.Core.Localization return phrase; } + private string GetSetLanguageFileName() + { + var isoLanguage = IsoLanguages.Get((Language)_configService.UILanguage); + var language = isoLanguage.TwoLetterCode; + + if (isoLanguage.CountryCode.IsNotNullOrWhiteSpace()) + { + language = string.Format("{0}_{1}", language, isoLanguage.CountryCode); + } + + return language; + } + private Dictionary<string, string> GetLocalizationDictionary(string language) { if (string.IsNullOrEmpty(language)) @@ -109,9 +122,17 @@ namespace NzbDrone.Core.Localization var dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); var baseFilenamePath = Path.Combine(prefix, baseFilename); + var alternativeFilenamePath = Path.Combine(prefix, GetResourceFilename(culture)); await CopyInto(dictionary, baseFilenamePath).ConfigureAwait(false); + + if (culture.Contains("_")) + { + var languageBaseFilenamePath = Path.Combine(prefix, GetResourceFilename(culture.Split('_')[0])); + await CopyInto(dictionary, languageBaseFilenamePath).ConfigureAwait(false); + } + await CopyInto(dictionary, alternativeFilenamePath).ConfigureAwait(false); return dictionary; @@ -145,11 +166,11 @@ namespace NzbDrone.Core.Localization private static string GetResourceFilename(string culture) { - var parts = culture.Split('-'); + var parts = culture.Split('_'); if (parts.Length == 2) { - culture = parts[0].ToLowerInvariant() + "-" + parts[1].ToUpperInvariant(); + culture = parts[0].ToLowerInvariant() + "_" + parts[1].ToUpperInvariant(); } else { From bc50fd937da06d28c85788885e5c534e21c467e4 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 13 May 2022 17:56:23 -0500 Subject: [PATCH 0466/2320] Fixed: (RuTracker) Support Raw search from apps Fixes #987 --- src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs index 81ab51813..054acbda3 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs @@ -117,6 +117,8 @@ namespace NzbDrone.Core.Indexers.Definitions } }; + caps.SupportsRawSearch = true; + caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.Movies, "Наше кино"); caps.Categories.AddCategoryMapping(941, NewznabStandardCategory.Movies, "|- Кино СССР"); caps.Categories.AddCategoryMapping(1666, NewznabStandardCategory.Movies, "|- Детские отечественные фильмы"); From 67835145250daaa007cb06c4eee876401c2a55bc Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 13 May 2022 18:41:36 -0500 Subject: [PATCH 0467/2320] Fixed: Use separate guid for download protection Fixes #963 --- src/NzbDrone.Core/Configuration/ConfigService.cs | 2 ++ src/NzbDrone.Core/Configuration/IConfigService.cs | 3 +++ src/NzbDrone.Core/Security/ProtectionService.cs | 8 ++++---- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index 1d83118a2..8cedd7b26 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -156,6 +156,8 @@ namespace NzbDrone.Core.Configuration public string HmacSalt => GetValue("HmacSalt", Guid.NewGuid().ToString(), true); + public string DownloadProtectionKey => GetValue("DownloadProtectionKey", Guid.NewGuid().ToString().Replace("-", ""), true); + public bool ProxyEnabled => GetValueBoolean("ProxyEnabled", false); public ProxyType ProxyType => GetValueEnum<ProxyType>("ProxyType", ProxyType.Http); diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index fb330e41e..8da617821 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -33,6 +33,9 @@ namespace NzbDrone.Core.Configuration string RijndaelSalt { get; } string HmacSalt { get; } + //Link Protection + string DownloadProtectionKey { get; } + //Proxy bool ProxyEnabled { get; } ProxyType ProxyType { get; } diff --git a/src/NzbDrone.Core/Security/ProtectionService.cs b/src/NzbDrone.Core/Security/ProtectionService.cs index 196f028c2..dc9c468c9 100644 --- a/src/NzbDrone.Core/Security/ProtectionService.cs +++ b/src/NzbDrone.Core/Security/ProtectionService.cs @@ -15,16 +15,16 @@ namespace NzbDrone.Core.Security public class ProtectionService : IProtectionService { - private readonly IConfigFileProvider _configService; + private readonly IConfigService _configService; - public ProtectionService(IConfigFileProvider configService) + public ProtectionService(IConfigService configService) { _configService = configService; } public string Protect(string text) { - var key = Encoding.UTF8.GetBytes(_configService.ApiKey); + var key = Encoding.UTF8.GetBytes(_configService.DownloadProtectionKey); using (var aesAlg = Aes.Create()) { @@ -70,7 +70,7 @@ namespace NzbDrone.Core.Security Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length); Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, fullCipher.Length - iv.Length); - var key = Encoding.UTF8.GetBytes(_configService.ApiKey); + var key = Encoding.UTF8.GetBytes(_configService.DownloadProtectionKey); using (var aesAlg = Aes.Create()) { From 9d5d92b74c8caa81808d935b04233c50c485a8a6 Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Thu, 12 May 2022 17:10:10 +0100 Subject: [PATCH 0468/2320] New: Set Instance Name --- frontend/src/Settings/General/HostSettings.js | 17 +++++++++++++++++ .../Configuration/ConfigFileProvider.cs | 6 ++++++ src/NzbDrone.Core/Localization/Core/en.json | 2 ++ .../Validation/RuleBuilderExtensions.cs | 6 ++++++ .../Config/HostConfigController.cs | 1 + .../Config/HostConfigResource.cs | 2 ++ 6 files changed, 34 insertions(+) diff --git a/frontend/src/Settings/General/HostSettings.js b/frontend/src/Settings/General/HostSettings.js index a750d4bb9..5445808b0 100644 --- a/frontend/src/Settings/General/HostSettings.js +++ b/frontend/src/Settings/General/HostSettings.js @@ -20,6 +20,7 @@ function HostSettings(props) { bindAddress, port, urlBase, + instanceName, enableSsl, sslPort, sslCertPath, @@ -72,6 +73,22 @@ function HostSettings(props) { /> </FormGroup> + <FormGroup + advancedSettings={advancedSettings} + isAdvanced={true} + > + <FormLabel>{translate('InstanceName')}</FormLabel> + + <FormInputGroup + type={inputTypes.TEXT} + name="instanceName" + helpText={translate('InstanceNameHelpText')} + helpTextWarning={translate('RestartRequiredHelpTextWarning')} + onChange={onInputChange} + {...instanceName} + /> + </FormGroup> + <FormGroup advancedSettings={advancedSettings} isAdvanced={true} diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index 9570aa2fc..2a065b194 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -42,11 +42,13 @@ namespace NzbDrone.Core.Configuration string SslCertPassword { get; } string UrlBase { get; } string UiFolder { get; } + string InstanceName { get; } bool UpdateAutomatically { get; } UpdateMechanism UpdateMechanism { get; } string UpdateScriptPath { get; } string SyslogServer { get; } int SyslogPort { get; } + string SyslogLevel { get; } string PostgresHost { get; } int PostgresPort { get; } string PostgresUser { get; } @@ -220,6 +222,7 @@ namespace NzbDrone.Core.Configuration } public string UiFolder => BuildInfo.IsDebug ? Path.Combine("..", "UI") : "UI"; + public string InstanceName => GetValue("InstanceName", BuildInfo.AppName); public bool UpdateAutomatically => GetValueBoolean("UpdateAutomatically", false, false); @@ -228,8 +231,11 @@ namespace NzbDrone.Core.Configuration public string UpdateScriptPath => GetValue("UpdateScriptPath", "", false); public string SyslogServer => GetValue("SyslogServer", "", persist: false); + public int SyslogPort => GetValueInt("SyslogPort", 514, persist: false); + public string SyslogLevel => GetValue("SyslogLevel", LogLevel).ToLowerInvariant(); + public int GetValueInt(string key, int defaultValue, bool persist = true) { return Convert.ToInt32(GetValue(key, defaultValue, persist)); diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index da609f3b6..2d2616bce 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -200,6 +200,8 @@ "IndexerVipCheckExpiredClientMessage": "Indexer VIP benefits have expired: {0}", "IndexerVipCheckExpiringClientMessage": "Indexer VIP benefits expiring soon: {0}", "Info": "Info", + "InstanceName": "Instance Name", + "InstanceNameHelpText": "Instance name in tab and for Syslog app name", "InteractiveSearch": "Interactive Search", "Interval": "Interval", "KeyboardShortcuts": "Keyboard Shortcuts", diff --git a/src/NzbDrone.Core/Validation/RuleBuilderExtensions.cs b/src/NzbDrone.Core/Validation/RuleBuilderExtensions.cs index 1149f51db..3c577d95c 100644 --- a/src/NzbDrone.Core/Validation/RuleBuilderExtensions.cs +++ b/src/NzbDrone.Core/Validation/RuleBuilderExtensions.cs @@ -61,5 +61,11 @@ namespace NzbDrone.Core.Validation { return ruleBuilder.WithState(v => NzbDroneValidationState.Warning); } + + public static IRuleBuilderOptions<T, string> ContainsProwlarr<T>(this IRuleBuilder<T, string> ruleBuilder) + { + ruleBuilder.SetValidator(new NotEmptyValidator(null)); + return ruleBuilder.SetValidator(new RegularExpressionValidator("prowlarr", RegexOptions.IgnoreCase)).WithMessage("Must contain Prowlarr"); + } } } diff --git a/src/Prowlarr.Api.V1/Config/HostConfigController.cs b/src/Prowlarr.Api.V1/Config/HostConfigController.cs index 26fa1acc4..b55163f67 100644 --- a/src/Prowlarr.Api.V1/Config/HostConfigController.cs +++ b/src/Prowlarr.Api.V1/Config/HostConfigController.cs @@ -40,6 +40,7 @@ namespace Prowlarr.Api.V1.Config SharedValidator.RuleFor(c => c.Port).ValidPort(); SharedValidator.RuleFor(c => c.UrlBase).ValidUrlBase(); + SharedValidator.RuleFor(c => c.InstanceName).ContainsProwlarr().When(c => c.InstanceName.IsNotNullOrWhiteSpace()); SharedValidator.RuleFor(c => c.Username).NotEmpty().When(c => c.AuthenticationMethod != AuthenticationType.None); SharedValidator.RuleFor(c => c.Password).NotEmpty().When(c => c.AuthenticationMethod != AuthenticationType.None); diff --git a/src/Prowlarr.Api.V1/Config/HostConfigResource.cs b/src/Prowlarr.Api.V1/Config/HostConfigResource.cs index 568756bb4..820552533 100644 --- a/src/Prowlarr.Api.V1/Config/HostConfigResource.cs +++ b/src/Prowlarr.Api.V1/Config/HostConfigResource.cs @@ -25,6 +25,7 @@ namespace Prowlarr.Api.V1.Config public string SslCertPath { get; set; } public string SslCertPassword { get; set; } public string UrlBase { get; set; } + public string InstanceName { get; set; } public bool UpdateAutomatically { get; set; } public UpdateMechanism UpdateMechanism { get; set; } public string UpdateScriptPath { get; set; } @@ -67,6 +68,7 @@ namespace Prowlarr.Api.V1.Config SslCertPath = model.SslCertPath, SslCertPassword = model.SslCertPassword, UrlBase = model.UrlBase, + InstanceName = model.InstanceName, UpdateAutomatically = model.UpdateAutomatically, UpdateMechanism = model.UpdateMechanism, UpdateScriptPath = model.UpdateScriptPath, From fc55aa4bd821723bf121b1f9b81ec6031077f878 Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Thu, 12 May 2022 17:10:27 +0100 Subject: [PATCH 0469/2320] New: Instance Name used for Syslog --- src/NzbDrone.Core/Configuration/ConfigFileProvider.cs | 2 +- src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index 2a065b194..ddd653000 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -234,7 +234,7 @@ namespace NzbDrone.Core.Configuration public int SyslogPort => GetValueInt("SyslogPort", 514, persist: false); - public string SyslogLevel => GetValue("SyslogLevel", LogLevel).ToLowerInvariant(); + public string SyslogLevel => GetValue("SyslogLevel", LogLevel, false).ToLowerInvariant(); public int GetValueInt(string key, int defaultValue, bool persist = true) { diff --git a/src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs b/src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs index 1f3cfcba1..b2f80d8d1 100644 --- a/src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs +++ b/src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs @@ -44,7 +44,8 @@ namespace NzbDrone.Core.Instrumentation if (_configFileProvider.SyslogServer.IsNotNullOrWhiteSpace()) { - SetSyslogParameters(_configFileProvider.SyslogServer, _configFileProvider.SyslogPort, minimumLogLevel); + var syslogLevel = LogLevel.FromString(_configFileProvider.SyslogLevel); + SetSyslogParameters(_configFileProvider.SyslogServer, _configFileProvider.SyslogPort, syslogLevel); } var rules = LogManager.Configuration.LoggingRules; @@ -118,7 +119,7 @@ namespace NzbDrone.Core.Instrumentation syslogTarget.MessageSend.Udp.Server = syslogServer; syslogTarget.MessageSend.Udp.ReconnectInterval = 500; syslogTarget.MessageCreation.Rfc = RfcNumber.Rfc5424; - syslogTarget.MessageCreation.Rfc5424.AppName = "Prowlarr"; + syslogTarget.MessageCreation.Rfc5424.AppName = _configFileProvider.InstanceName; var loggingRule = new LoggingRule("*", minimumLogLevel, syslogTarget); From 96d64afccad26c4ab703b06f75740ed557720eb5 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 12 May 2022 19:06:14 -0500 Subject: [PATCH 0470/2320] New: Instance name for Page Title --- frontend/src/App/App.js | 2 +- frontend/src/Components/Page/PageContent.js | 2 +- src/Prowlarr.Http/Frontend/InitializeJsController.cs | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/src/App/App.js b/frontend/src/App/App.js index ae1e4f31b..37c453f45 100644 --- a/frontend/src/App/App.js +++ b/frontend/src/App/App.js @@ -8,7 +8,7 @@ import AppRoutes from './AppRoutes'; function App({ store, history }) { return ( - <DocumentTitle title="Prowlarr"> + <DocumentTitle title={window.Prowlarr.instanceName}> <Provider store={store}> <ConnectedRouter history={history}> <PageConnector> diff --git a/frontend/src/Components/Page/PageContent.js b/frontend/src/Components/Page/PageContent.js index d21304991..e79643497 100644 --- a/frontend/src/Components/Page/PageContent.js +++ b/frontend/src/Components/Page/PageContent.js @@ -14,7 +14,7 @@ function PageContent(props) { return ( <ErrorBoundary errorComponent={PageContentError}> - <DocumentTitle title={title ? `${title} - Prowlarr` : 'Prowlarr'}> + <DocumentTitle title={title ? `${title} - ${window.Prowlarr.instanceName}` : window.Prowlarr.instanceName}> <div className={className}> {children} </div> diff --git a/src/Prowlarr.Http/Frontend/InitializeJsController.cs b/src/Prowlarr.Http/Frontend/InitializeJsController.cs index 947371e88..fc3dcf302 100644 --- a/src/Prowlarr.Http/Frontend/InitializeJsController.cs +++ b/src/Prowlarr.Http/Frontend/InitializeJsController.cs @@ -49,6 +49,7 @@ namespace Prowlarr.Http.Frontend builder.AppendLine($" apiKey: '{_apiKey}',"); builder.AppendLine($" release: '{BuildInfo.Release}',"); builder.AppendLine($" version: '{BuildInfo.Version.ToString()}',"); + builder.AppendLine($" instanceName: '{_configFileProvider.InstanceName.ToString()}',"); builder.AppendLine($" branch: '{_configFileProvider.Branch.ToLower()}',"); builder.AppendLine($" analytics: {_analyticsService.IsEnabled.ToString().ToLowerInvariant()},"); builder.AppendLine($" userHash: '{HashUtil.AnonymousToken()}',"); From ba2d1b3e6841723e253d5242eca13ed8c57518fc Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 12 May 2022 19:07:40 -0500 Subject: [PATCH 0471/2320] New: Instance name in System/Status API endpoint --- src/Prowlarr.Api.V1/System/SystemController.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Prowlarr.Api.V1/System/SystemController.cs b/src/Prowlarr.Api.V1/System/SystemController.cs index 387ffd5c6..1f0860457 100644 --- a/src/Prowlarr.Api.V1/System/SystemController.cs +++ b/src/Prowlarr.Api.V1/System/SystemController.cs @@ -59,6 +59,7 @@ namespace Prowlarr.Api.V1.System return new { AppName = BuildInfo.AppName, + InstanceName = _configFileProvider.InstanceName, Version = BuildInfo.Version.ToString(), BuildTime = BuildInfo.BuildDateTime, IsDebug = BuildInfo.IsDebug, From adf38f256b402e1fd8f57cc6a415b881dd96e5c6 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 14 May 2022 10:05:25 -0500 Subject: [PATCH 0472/2320] Clean lingering Postgres Connections on Close --- src/NzbDrone.Host/Bootstrap.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index 4b3717c11..42b434cef 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -9,13 +9,12 @@ using System.Security.Cryptography.X509Certificates; using System.Text; using DryIoc; using DryIoc.Microsoft.DependencyInjection; -using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting.WindowsServices; using NLog; +using Npgsql; using NzbDrone.Common.Composition.Extensions; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Exceptions; @@ -105,6 +104,7 @@ namespace NzbDrone.Host GC.Collect(); GC.WaitForPendingFinalizers(); SQLiteConnection.ClearAllPools(); + NpgsqlConnection.ClearAllPools(); } public static IHostBuilder CreateConsoleHostBuilder(string[] args, StartupContext context) From a738cfb23a8833a578766f86905ad644f6d47537 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 14 May 2022 10:05:42 -0500 Subject: [PATCH 0473/2320] Catch Postgres log connection errors --- src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs b/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs index ecd41cceb..971d939d4 100644 --- a/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs +++ b/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs @@ -97,6 +97,11 @@ namespace NzbDrone.Core.Instrumentation WritePostgresLog(log, connectionString); } } + catch (NpgsqlException ex) + { + InternalLogger.Error("Unable to save log event to database: {0}", ex); + throw; + } catch (SQLiteException ex) { InternalLogger.Error("Unable to save log event to database: {0}", ex); From d56dc313b470d8a31d9c6e2abce3f68d79fe1973 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Fri, 13 May 2022 22:49:42 +0000 Subject: [PATCH 0474/2320] Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 99.7% (447 of 448 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (448 of 448 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 99.3% (445 of 448 strings) Translated using Weblate (Italian) Currently translated at 100.0% (448 of 448 strings) Translated using Weblate (Spanish) Currently translated at 79.6% (357 of 448 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (448 of 448 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (448 of 448 strings) Update translation files Updated by "Cleanup translation files" hook in Weblate. Translated using Weblate (Russian) Currently translated at 77.9% (349 of 448 strings) Update translation files Updated by "Cleanup translation files" hook in Weblate. Update translation files Updated by "Cleanup translation files" hook in Weblate. Translated using Weblate (Italian) Currently translated at 100.0% (446 of 446 strings) Translated using Weblate (Italian) Currently translated at 100.0% (446 of 446 strings) Translated using Weblate (Italian) Currently translated at 100.0% (446 of 446 strings) Translated using Weblate (Italian) Currently translated at 84.5% (377 of 446 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (446 of 446 strings) Co-authored-by: Anonymous <noreply@weblate.org> Co-authored-by: Csaba <csab0825@gmail.com> Co-authored-by: Francesco <francy.ammirati@hotmail.com> Co-authored-by: Giorgio <sannagiorgio1997@gmail.com> Co-authored-by: Havok Dan <havokdan@yahoo.com.br> Co-authored-by: Oskari Lavinto <olavinto@protonmail.com> Co-authored-by: RqLiu <sukiqwq@gmail.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: zpengcom <z.peng.com@gmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/it/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ru/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/ca.json | 1 - src/NzbDrone.Core/Localization/Core/de.json | 4 - src/NzbDrone.Core/Localization/Core/es.json | 5 +- src/NzbDrone.Core/Localization/Core/fi.json | 24 +- src/NzbDrone.Core/Localization/Core/fr.json | 4 - src/NzbDrone.Core/Localization/Core/hu.json | 14 +- src/NzbDrone.Core/Localization/Core/it.json | 361 +++++++++++------- .../Localization/Core/nb_NO.json | 1 - src/NzbDrone.Core/Localization/Core/nl.json | 4 - src/NzbDrone.Core/Localization/Core/pt.json | 4 - .../Localization/Core/pt_BR.json | 14 +- src/NzbDrone.Core/Localization/Core/ru.json | 9 +- src/NzbDrone.Core/Localization/Core/sv.json | 4 - .../Localization/Core/zh_CN.json | 12 +- 14 files changed, 258 insertions(+), 203 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/ca.json b/src/NzbDrone.Core/Localization/Core/ca.json index 1dc2adb33..69ec76ef5 100644 --- a/src/NzbDrone.Core/Localization/Core/ca.json +++ b/src/NzbDrone.Core/Localization/Core/ca.json @@ -1,5 +1,4 @@ { - "AddAppProfile": "Afegiu un perfil de sincronització d'aplicacions", "Add": "Afegeix", "Actions": "Accions", "AcceptConfirmationModal": "Accepta el mètode de confirmació", diff --git a/src/NzbDrone.Core/Localization/Core/de.json b/src/NzbDrone.Core/Localization/Core/de.json index 114071e91..df8b323ec 100644 --- a/src/NzbDrone.Core/Localization/Core/de.json +++ b/src/NzbDrone.Core/Localization/Core/de.json @@ -331,12 +331,8 @@ "AddToDownloadClient": "Release zum Downloader hinzufügen", "AddNewIndexer": "Neuen Indexer hinzufügen", "AddedToDownloadClient": "Release zum Client hinzugefügt", - "AddAppProfile": "App synchronisier Profil hinzufügen", - "AppProfile": "App-Profil", - "AppProfiles": "App-Profile", "EnableRssHelpText": "RSS-Feed für Indexer aktivieren", "EnableRss": "RSS aktivieren", - "EditAppProfile": "App-Profil bearbeiten", "Wiki": "Wiki", "RSS": "RSS", "RedirectHelpText": "Eingehende Download-Anfragen für den Indexer umleiten, anstatt Proxying mit Prowlarr", diff --git a/src/NzbDrone.Core/Localization/Core/es.json b/src/NzbDrone.Core/Localization/Core/es.json index 2126c05e6..ceedcd52e 100644 --- a/src/NzbDrone.Core/Localization/Core/es.json +++ b/src/NzbDrone.Core/Localization/Core/es.json @@ -301,7 +301,7 @@ "Reddit": "Reddit", "UnableToAddANewAppProfilePleaseTryAgain": "No se ha podido añadir un nuevo perfil de calidad, prueba otra vez.", "DeleteIndexerProxyMessageText": "Seguro que quieres eliminar la etiqueta '{0}'?", - "Discord": "Discordia", + "Discord": "Discord", "Add": "Añadir", "Custom": "Personalizado", "Donations": "Donaciones", @@ -338,7 +338,6 @@ "NotificationTriggersHelpText": "Seleccione qué eventos deben activar esta notificación", "OnApplicationUpdate": "Al actualizar la aplicación", "OnApplicationUpdateHelpText": "Al actualizar la aplicación", - "AddAppProfile": "Añadir sincronización de perfil de aplicación", "AddRemoveOnly": "Sólo añadir y eliminar", "AddedToDownloadClient": "Descarga añadida al cliente", "AddNewIndexer": "Añadir nuevo indexador", @@ -349,8 +348,6 @@ "AddDownloadClientToProwlarr": "Añadir un cliente de descargas permite a Prowlarr enviar descargas directamente desde la interfaz en una búsqueda manual.", "Category": "Categoría", "Application": "Aplicación", - "AppProfile": "Perfil de aplicación", - "AppProfiles": "Perfiles de aplicaciones", "BookSearch": "Búsqueda de libros", "BookSearchTypes": "Tipos de búsqueda de libros", "Categories": "Categorías", diff --git a/src/NzbDrone.Core/Localization/Core/fi.json b/src/NzbDrone.Core/Localization/Core/fi.json index 4c946fe9d..fc6fa9a2f 100644 --- a/src/NzbDrone.Core/Localization/Core/fi.json +++ b/src/NzbDrone.Core/Localization/Core/fi.json @@ -323,7 +323,6 @@ "RedirectHelpText": "Uudelleenohjaa tietolähteeltä saapuvat latauspyynnöt ja ohjaa sieppaus suoraan sen sijaan, että se välitettäisiin Prowlarin kautta.", "FullSync": "Täysi synkronointi", "SyncLevelFull": "Täysi synkronointi: Pitää sovelluksen tietolähteet täysin synkronoituna. Tietolähteisiin Prowlarrissa tehdyt muutokset synkronoidaan etäsovelluksen kanssa ja kaikki etäsovelluksessa tehdyt muutokset korvataan seuraavan synkronoinnin yhteydessä.", - "AppProfile": "Sovellusprofiili", "EnableIndexer": "Tietolähteen tila", "FilterPlaceHolder": "Suodata tietolähteitä", "IndexerHealthCheckNoIndexers": "Yhtään tietolähdettä ei ole käytössä, eikä Prowlarr tämän vuoksi löydä tuloksia.", @@ -336,11 +335,9 @@ "AddIndexerProxy": "Lisää tiedonhaun välityspalvelin", "UISettingsSummary": "Päiväyksen ja kielen sekä heikentyneen värinäön asetukset", "SettingsIndexerLoggingHelpText": "Kirjaa tarkempia tietoja tietolähteiden toiminnasta, mukaanlukien vastaukset", - "IndexerTagsHelpText": "Tunnisteiden avulla voit määrittää ensisijaiset lataustyökalut ja tiedonhaun välityspalvelimet sekä järjestellä tietolähteitäsi.", + "IndexerTagsHelpText": "Tunnisteiden avulla voit määrittää tiedonhaun välityspalvelimet, mihin sovelluksiin tietolähteet synkronoidaan tai yksikertaisesti järjestellä tietolähteitäsi.", "UnableToLoadAppProfiles": "Sovellusprofiilien lataus epäonnistui", "AppProfileSelectHelpText": "Sovellusprofiilieilla määritetään tietolähteelle sovellussynkronoinnin yhteydessä aktivoitavat hakutavat (RSS/automaatti/vuorovaikutteinen).", - "AddAppProfile": "Lisää sovelluksen synkronointiprofiili", - "AppProfiles": "Sovellusprofiilit", "IndexerQuery": "Tietolähteen kysely", "IndexerRss": "Tietolähteen RSS-syöte", "SearchIndexers": "Etsi tietolähteistä", @@ -394,7 +391,6 @@ "Stats": "Tilastot", "UnableToLoadDevelopmentSettings": "Kehittäjäasetusten lataus epäonnistui", "AppSettingsSummary": "Sovellukset ja asetukset, joilla määritetään miten Prowlarr viestii PVR-sovellustesi kanssa.", - "EditAppProfile": "Muokkaa sovellusprofiilia", "Privacy": "Yksityisyys", "NetCore": ".NET", "BookSearch": "Etsi kirjoja", @@ -427,13 +423,13 @@ "IndexerNoDefCheckMessage": "Tietolähteillä ei ole määritystä, eivätkä ne toimi: {0}. Poista ja/tai lisää Prowlarriin uudelleen", "Private": "Yksityinen", "QueryResults": "Kyselyn tulokset", - "Application": "Sovellukset", - "GrabReleases": "Sieppaa julkaisu", - "Link": "Linkit", + "Application": "Sovellus", + "GrabReleases": "Sieppaa julkaisu(t)", + "Link": "Linkki", "SearchTypes": "Mitä etsitään", - "UnableToLoadIndexers": "Tietolähteiden lataus epäonnistui.", + "UnableToLoadIndexers": "Tietolähteiden lataus epäonnistui", "Yes": "Kyllä", - "MappedDrivesRunningAsService": "Yhdistetyt verkkoasemat eivät ole käytettävissä, kun niitä käytetään Windows-palveluna. Katso lisätietoja UKK: sta", + "MappedDrivesRunningAsService": "Yhdistetyt verkkoasemat eivät ole käytettävissä, kun sovellus suoritetaan Windows-palveluna. Lisätietoja löydät UKK:stä.", "No": "Ei", "BookSearchTypes": "Kirjojen hakutyypit", "IndexerDetails": "Tietolähteen tiedot", @@ -444,5 +440,11 @@ "NotSupported": "Ei tuettu", "RawSearchSupported": "Raakahaku tuettu", "SearchCapabilities": "Hakuominaisuudet", - "TVSearchTypes": "Televisiosarjojen hakutyypit" + "TVSearchTypes": "Televisiosarjojen hakutyypit", + "MinimumSeeders": "Jakajien vähimmäismäärä", + "MinimumSeedersHelpText": "Sovelluksen edellyttämä jakajien vähimmäismäärä tietolähteestä kaappaukseen.", + "SyncProfile": "Synkronointiprofiili", + "SyncProfiles": "Synkronointiprofiilit", + "AddSyncProfile": "Lisää synkronointiprofiili", + "EditSyncProfile": "Muokkaa synkronointiprofiilia" } diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index 122027f7b..79fa29f3b 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -322,9 +322,6 @@ "EnableRssHelpText": "Activer le flux RSS pour l'indexeur", "EnableRss": "Activer RSS", "EnableIndexer": "Activer l'indexeur", - "EditAppProfile": "Modifier profil de l'App", - "AppProfiles": "Profils d'application", - "AddAppProfile": "Ajouter un profil de synchronisation d'App", "DevelopmentSettings": "Paramètres de développement", "DeleteApplicationMessageText": "Etes-vous sûr de vouloir supprimer l'application '{0}' ?", "DeleteApplication": "Supprimer l'application", @@ -336,7 +333,6 @@ "AddToDownloadClient": "Ajouter un release au client", "AddedToDownloadClient": "Release ajoutée au client", "AddNewIndexer": "Ajouter un nouvel indexeur", - "AppProfile": "Profils d'application", "Wiki": "Wiki", "RSS": "RSS", "RedirectHelpText": "Rediriger la demande de téléchargement entrante pour l'indexeur et transmettre la capture directement au lieu de transmettre la demande par proxy via Prowlarr", diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index cd3ec05bf..4318311a5 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -333,10 +333,6 @@ "AddedToDownloadClient": "Kiadás hozzáadva a klienshez", "EnableRssHelpText": "RSS Engedélyezése az Indexerekhez", "EnableRss": "RSS Engedélyezése", - "EditAppProfile": "App profil szerkesztése", - "AppProfiles": "App profilok", - "AddAppProfile": "Szinkronizálási profil hozzáadása", - "AppProfile": "App Profil", "Wiki": "Wiki", "RSS": "RSS", "RedirectHelpText": "Átirányítja a bejövő letöltési kérelmet az indexelő számára, és közvetlenül adja át a fájlt ahelyett, hogy a kérést a Prowlarr-en keresztül proxyba tenné", @@ -386,7 +382,7 @@ "IndexerProxies": "Indexer Proxy(k)", "IndexerProxyStatusCheckAllClientMessage": "Az összes Proxy elérhetetlen, hiba miatt", "IndexerProxyStatusCheckSingleClientMessage": "Proxyk elérhetetlenek az alábbi hibák miatt: {0}", - "IndexerTagsHelpText": "A címkék segítségével megadhatja az indexelő proxykat, vagy egyszerűen rendezheti az indexelőket.", + "IndexerTagsHelpText": "Címkék segítségével megadhatod az indexer proxykat amelyekkel az indexer szinkronizálva van, vagy egyszerűen az indexelők rendszerezéséhez.", "UnableToLoadIndexerProxies": "Nem lehet betölteni az Indexer Proxyt", "AddIndexerProxy": "Indexer Proxy hozzáadása", "IndexerSettingsSummary": "Konfigurálja a különböző globális indexer beállításokat, beleértve a proxykat is.", @@ -444,5 +440,11 @@ "NotSupported": "Nem támogatott", "RawSearchSupported": "Nyers keresés támogatott", "SearchCapabilities": "Keresési lehetőségek", - "TVSearchTypes": "TV-Sorozat keresési típusok" + "TVSearchTypes": "TV-Sorozat keresési típusok", + "MinimumSeeders": "Minimális Seederek Száma", + "SyncProfile": "Szinkronizálási profil", + "SyncProfiles": "Szinkronizálási profilok", + "AddSyncProfile": "Szinkronizálási profil hozzáadása", + "EditSyncProfile": "Szinkronizálási profil szerkesztése", + "MinimumSeedersHelpText": "Az Alkalmazás által megkövetelt minimális Seeder az indexer számára" } diff --git a/src/NzbDrone.Core/Localization/Core/it.json b/src/NzbDrone.Core/Localization/Core/it.json index 4007fde2d..e562a967b 100644 --- a/src/NzbDrone.Core/Localization/Core/it.json +++ b/src/NzbDrone.Core/Localization/Core/it.json @@ -1,38 +1,38 @@ { - "View": "Guarda", + "View": "Vista", "UnselectAll": "Deseleziona Tutto", - "UISettingsSummary": "Opzioni calendario, data e visione dei colori", - "TagsSettingsSummary": "Controlla tutti i tag e come vengono utilizzati. I tag non utilizzati possono essere rimossi", - "SetTags": "Imposta Tag", + "UISettingsSummary": "Opzioni data, lingua e visione dei colori", + "TagsSettingsSummary": "Vedi tutte le etichette e come vengono utilizzate. Le etichette non utilizzate possono essere rimosse", + "SetTags": "Imposta Etichette", "SelectAll": "Seleziona Tutto", - "Scheduled": "In Programma", - "ReleaseBranchCheckOfficialBranchMessage": "Il Branch {0} non è un branch valido per le release di Prowlarr, non riceverai aggiornamenti", - "PtpOldSettingsCheckMessage": "Il seguente indexer PassThePopcorn ha delle impostazioni obsolete e deve essere aggiornato: {0}", - "ProxyCheckResolveIpMessage": "Impossibile risolvere l'indirizzo IP per il Proxy {0}", + "Scheduled": "Programmato", + "ReleaseBranchCheckOfficialBranchMessage": "La versione {0} non è una versione valida per le release di Prowlarr, non riceverai aggiornamenti", + "PtpOldSettingsCheckMessage": "I seguenti indicizzatori di PassThePopcorn hanno delle impostazioni obsolete e devono essere aggiornati: {0}", + "ProxyCheckResolveIpMessage": "Impossibile risolvere l'indirizzo IP per l'Host Configurato del Proxy {0}", "NoChanges": "Nessuna Modifica", "NoChange": "Nessuna Modifica", "LastWriteTime": "Orario di Ultima Scrittura", "Indexer": "Indicizzatore", "HideAdvanced": "Nascondi Avanzate", "Health": "Salute", - "Grabbed": "Recuperato", + "Grabbed": "Preso", "Clear": "Cancella", "AppDataLocationHealthCheckMessage": "L'aggiornamento non sarà possibile per evitare la cancellazione di AppData durante l'aggiornamento", "Analytics": "Analitica", "Added": "Aggiunto", "About": "Informazioni", "Updates": "Aggiornamenti", - "UpdateCheckUINotWritableMessage": "Impossibile installare l'aggiornamento perché l'utente '{1}' non ha i permessi di scrittura per la cartella di interfaccia '{0}'.", + "UpdateCheckUINotWritableMessage": "Impossibile installare l'aggiornamento perché l'utente '{1}' non ha i permessi di scrittura per la cartella dell'interfaccia '{0}'.", "UpdateCheckStartupNotWritableMessage": "Impossibile installare l'aggiornamento perché l'utente '{1}' non ha i permessi di scrittura per la cartella di avvio '{0}'.", - "UpdateCheckStartupTranslocationMessage": "Impossibile installare l'aggiornamento perché la cartella '{0}' si trova in una cartella App Translocation.", + "UpdateCheckStartupTranslocationMessage": "Impossibile installare l'aggiornamento perché la cartella '{0}' si trova in una cartella di \"App Translocation\".", "UI": "Interfaccia", - "Tasks": "Funzioni", - "Tags": "Tag", + "Tasks": "Attività", + "Tags": "Etichette", "System": "Sistema", "Style": "Stile", "Status": "Stato", "Sort": "Ordina", - "Size": "Dimensioni", + "Size": "Dimensione", "ShowAdvanced": "Mostra Avanzate", "Settings": "Impostazioni", "Security": "Sicurezza", @@ -43,7 +43,7 @@ "Refresh": "Aggiorna", "Queue": "Coda", "ProxyCheckFailedToTestMessage": "Test del proxy fallito: {0}", - "ProxyCheckBadRequestMessage": "Il test del proxy è fallito. Stato: {0}", + "ProxyCheckBadRequestMessage": "Il test del proxy è fallito. Codice Stato: {0}", "Proxy": "Proxy", "Protocol": "Protocollo", "Options": "Opzioni", @@ -51,12 +51,12 @@ "Logging": "Logging", "LogFiles": "File di Log", "Language": "Lingua", - "IndexerStatusCheckSingleClientMessage": "Indexer non disponibili a causa di errori: {0}", - "IndexerStatusCheckAllClientMessage": "Tutti gli indexer non sono disponibili a causa di errori", - "Indexers": "Indexer", + "IndexerStatusCheckSingleClientMessage": "Indicizzatori non disponibili a causa di errori: {0}", + "IndexerStatusCheckAllClientMessage": "Nessun Indicizzatore disponibile a causa di errori", + "Indexers": "Indicizzatori", "Host": "Host", "History": "Storia", - "GeneralSettingsSummary": "Porta, SSL, Nome utente/password, proxy, statistiche e aggiornamenti", + "GeneralSettingsSummary": "Porta, SSL, nome utente/password, proxy, analitiche, e aggiornamenti", "General": "Generale", "Folder": "Cartella", "Filter": "Filtro", @@ -66,11 +66,11 @@ "EventType": "Tipo di Evento", "Events": "Eventi", "Edit": "Modifica", - "DownloadClientStatusCheckSingleClientMessage": "Client per il download non disponibile per errori: {0}", - "DownloadClientStatusCheckAllClientMessage": "Tutti i client per il download non sono disponibili a causa di errori", - "DownloadClientsSettingsSummary": "Configurazione client di download per integrazione nella ricerca di Prowlarr", - "DownloadClients": "Client Download", - "DownloadClient": "Client Download", + "DownloadClientStatusCheckSingleClientMessage": "Client per il download non disponibili per errori: {0}", + "DownloadClientStatusCheckAllClientMessage": "Nessun client di download è disponibile a causa di errori", + "DownloadClientsSettingsSummary": "Configurazione dei client di download per l'integrazione nella ricerca di Prowlarr", + "DownloadClients": "Clients di Download", + "DownloadClient": "Client di Download", "Details": "Dettagli", "Delete": "Cancella", "Dates": "Date", @@ -87,22 +87,22 @@ "Close": "Chiudi", "CloneProfile": "Clona il Profilo", "ClientPriority": "Priorità del Client", - "ChangeHasNotBeenSavedYet": "Il cambiamento non è ancora stato ancora salvato", - "CertificateValidationHelpText": "Cambia quanto è rigorosa la convalida della certificazione HTTPS", - "CertificateValidation": "Convalida del certificato", - "Cancel": "Cancella", - "BypassProxyForLocalAddresses": "Evita il Proxy per gli indirizzi locali", + "ChangeHasNotBeenSavedYet": "Il cambio non è stato ancora salvato", + "CertificateValidationHelpText": "Cambia quanto è rigorosa la convalida del certificato HTTPS", + "CertificateValidation": "Convalida del Certificato", + "Cancel": "Annulla", + "BypassProxyForLocalAddresses": "Evita il Proxy per gli Indirizzi Locali", "Branch": "Ramo", - "BindAddressHelpText": "Indirizzo IPV4 valido o '*' per tutte le interfacce", + "BindAddressHelpText": "Indirizzo IPv4 valido o '*' per tutte le interfacce", "BindAddress": "Indirizzo di Bind", "Backups": "I Backup", "BackupRetentionHelpText": "I backup automatici più vecchi del periodo di conservazione verranno eliminati automaticamente", "BackupIntervalHelpText": "Intervallo tra i backup automatici", - "BackupFolderHelpText": "I percorsi relativi saranno nella directory AppData di Prowlarr", + "BackupFolderHelpText": "I percorsi relativi saranno nella cartella AppData di Prowlarr", "Automatic": "Automatico", "AuthenticationMethodHelpText": "Richiedi Nome Utente e Password per accedere a Prowlarr", "Authentication": "Autenticazione", - "AreYouSureYouWantToResetYourAPIKey": "Sei sicuro di voler reimpostare la tua chiave API?", + "AreYouSureYouWantToResetYourAPIKey": "Sei sicuro di voler reimpostare la tua Chiave API?", "ApplyTags": "Applica Etichette", "Apply": "Applica", "AppDataDirectory": "Cartella AppData", @@ -111,12 +111,12 @@ "Warn": "Attenzione", "Type": "Tipo", "Title": "Titolo", - "Time": "Orario", - "TestAll": "Prova Tutti", - "Test": "Prova", + "Time": "Ora", + "TestAll": "Testa Tutti", + "Test": "Test", "TableOptionsColumnsMessage": "Scegli quali colonne rendere visibili ed il loro ordine", "TableOptions": "Opzioni della tabella", - "SystemTimeCheckMessage": "L'orario di sistema è spento da più di 1 giorno. I task schedulati potrebbero non essere correttamente eseguiti fino al suo ripristino", + "SystemTimeCheckMessage": "L'orario di sistema è sbagliato di più di un giorno. Le attività pianificate potrebbero non essere eseguite correttamente fino alla correzione", "Source": "Fonte", "Shutdown": "Spegni", "Seeders": "Seeders", @@ -126,7 +126,7 @@ "Peers": "Peers", "PageSize": "Dimensione Pagina", "Ok": "Ok", - "OAuthPopupMessage": "I Pop-ups sono bloccati dal tuo browser", + "OAuthPopupMessage": "I Pop-up sono bloccati dal tuo browser", "Name": "Nome", "Message": "Messaggio", "Level": "Livello", @@ -135,249 +135,316 @@ "HealthNoIssues": "La tua configurazione non presenta problemi", "Error": "Errore", "Enable": "Abilita", - "DownloadClientSettings": "Impostazioni del client di download", + "DownloadClientSettings": "Impostazioni del Client di Download", "Docker": "Docker", - "DeleteTag": "Cancella Tag", - "DeleteNotification": "Cancella la notifica", + "DeleteTag": "Elimina Etichetta", + "DeleteNotification": "Cancella la Notifica", "DeleteDownloadClient": "Cancella il Client di Download", "DeleteBackup": "Cancella Backup", "DBMigration": "Migrazione DB", "ConnectSettings": "Impostazioni di Connessione", "ConnectionLostMessage": "Prowlarr ha perso la connessione al backend e dovrà essere ricaricato per ripristinare la funzionalità.", "ConnectionLostAutomaticMessage": "Prowlarr cercherà di connettersi automaticamente, oppure clicca su ricarica qui sotto.", - "ConnectionLost": "Connessione persa", + "ConnectionLost": "Connessione Persa", "Component": "Componente", "Columns": "Colonne", "DeleteBackupMessageText": "Sei sicuro di voler cancellare il backup '{0}'?", "CancelPendingTask": "Sei sicuro di voler cancellare questa operazione in sospeso?", "BranchUpdateMechanism": "Ramo utilizzato dal sistema di aggiornamento esterno", "BranchUpdate": "Ramo da usare per aggiornare Prowlarr", - "ApplyTagsHelpTexts2": "Aggiungi: Aggiungere le etichette alla lista esistente di etichette", - "ApplyTagsHelpTexts1": "Come applicare etichette agli indexer selezionati", - "AddingTag": "Aggiungi tag", + "ApplyTagsHelpTexts2": "Aggiungi: Aggiunge le etichette alla lista esistente di etichette", + "ApplyTagsHelpTexts1": "Come applicare etichette agli Indicizzatori selezionati", + "AddingTag": "Aggiungi etichetta", "Password": "Password", "OnHealthIssueHelpText": "Quando c'è un problema", - "NotificationTriggers": "Selettori di notifica", + "NotificationTriggers": "Attivatori di Notifica", "NetCore": ".NET", "Logs": "Logs", - "Hostname": "Hostname", + "Hostname": "Nome Host", "MIA": "MIA", - "IndexerFlags": "Etichetta indexer", + "IndexerFlags": "Flags dell'Indicizzatore", "EnableSSL": "Abilita SSL", - "SettingsLongDateFormat": "Formato Data Lungo", - "SettingsEnableColorImpairedMode": "Abilità la modalità colori alternati", - "SendAnonymousUsageData": "Invia dati sull'uso anonimamente", + "SettingsLongDateFormat": "Formato Data Esteso", + "SettingsEnableColorImpairedMode": "Abilità la Modalità Daltonica", + "SendAnonymousUsageData": "Invia dati anonimi sull'uso", "ScriptPath": "Percorso dello script", - "RSSIsNotSupportedWithThisIndexer": "RSS non è supportato con questo indexer", - "Retention": "Memorizzazione", + "RSSIsNotSupportedWithThisIndexer": "RSS non è supportato con questo Indicizzatore", + "Retention": "Ritenzione", "Result": "Risultato", "Restore": "Ripristina", - "RestartRequiredHelpTextWarning": "Richiede il riavvio per avere effetti", + "RestartRequiredHelpTextWarning": "Richiede il riavvio per avere effetto", "RestartProwlarr": "Riavvia Prowlarr", "RestartNow": "Riavvia adesso", "ResetAPIKey": "Resetta la Chiave API", "Reset": "Resetta", - "RemovingTag": "Sto eliminando il tag", + "RemovingTag": "Eliminando l'etichetta", "RemoveFilter": "Rimuovi filtro", - "RemovedFromTaskQueue": "Rimuovi dalla coda di lavoro", + "RemovedFromTaskQueue": "Rimosso dalla coda lavori", "RefreshMovie": "Aggiorna il Film", - "ReadTheWikiForMoreInformation": "Leggi le Wiki per maggiori informazioni", - "ProwlarrSupportsAnyIndexer": "Prowlarr supporta qualunque indexer che usi gli standard Newznab, cosi come gli altri Indexer sotto.", - "ProwlarrSupportsAnyDownloadClient": "Prowlarr supporta qualunque client di download che usi gli standard Newznab, cosi come gli altri client sotto.", + "ReadTheWikiForMoreInformation": "Leggi la Wiki per maggiori informazioni", + "ProwlarrSupportsAnyIndexer": "Prowlarr supporta molti indicizzatori oltre a qualsiasi indicizzatore che utilizza lo standard Newznab/Torznab utilizzando \"Generic Newznab\" (per usenet) o \"Generic Torznab\" (per torrent). Cerca e seleziona il tuo indicizzatore da qua sotto.", + "ProwlarrSupportsAnyDownloadClient": "Prowlarr supporta qualunque client di download elencato sotto.", "ProxyUsernameHelpText": "Devi inserire nome utente e password solo se richiesto. Altrimenti lascia vuoto.", - "ProxyType": "Tipo di proxy", + "ProxyType": "Tipo di Proxy", "ProxyPasswordHelpText": "Devi inserire nome utente e password solo se richiesto. Altrimenti lascia vuoto.", "ProxyBypassFilterHelpText": "Usa ',' come separatore, e '*.' come jolly per i sottodomini", - "PriorityHelpText": "Dai priorità ai client di download multipli. Round-Robin è usato per i client con la stessa priorità.", + "PriorityHelpText": "Dai priorità a multipli Client di download. Round-Robin è usato per i client con la stessa priorità.", "PortNumber": "Numero di porta", "Port": "Porta", "PendingChangesStayReview": "Rimani e rivedi modifiche", "PendingChangesMessage": "Hai cambiamenti non salvati, sicuro di voler abbandonare la pagina?", "PendingChangesDiscardChanges": "Abbandona le modifiche ed esci", "PageSizeHelpText": "Numero di voci da mostrare in ogni pagina", - "PackageVersion": "Versione del pacchetto", + "PackageVersion": "Versione del Pacchetto", "OpenBrowserOnStart": "Apri il browser all'avvio", "NoUpdatesAreAvailable": "Nessun aggiornamento disponibile", - "NoTagsHaveBeenAddedYet": "Nessun tag è ancora stato aggiunto", + "NoTagsHaveBeenAddedYet": "Nessuna etichetta è ancora stata aggiunta", "NoLogFiles": "Nessun file di log", - "NoLeaveIt": "No, lascialo", + "NoLeaveIt": "No, Lascialo", "NoBackupsAreAvailable": "Nessun Backup disponibile", "New": "Nuovo", "Mode": "Modo", "Mechanism": "Meccanismo", "Manual": "Manuale", - "MaintenanceRelease": "Release di Manutenzione: correzione di bug e altre miglioramenti. Vedi la storia dei Commit su Github per maggiori dettagli", + "MaintenanceRelease": "Release di Manutenzione: correzione di bug e altri miglioramenti. Vedi la storia dei Commit su Github per maggiori dettagli", "LogLevelTraceHelpTextWarning": "Il Trace Log dovrebbe essere abilitato solo temporaneamente", "LogLevel": "Livello di Log", "LaunchBrowserHelpText": " Apri un browser e vai all'homepage di Prowlarr all'avvio dell'app.", "Interval": "Intervallo", "IncludeHealthWarningsHelpText": "Includi gli avvisi di salute", "IllRestartLater": "Riavvierò più tardi", - "IgnoredAddresses": "Indirizzi ignorati", + "IgnoredAddresses": "Indirizzi Ignorati", "HiddenClickToShow": "Nascosto, premi per mostrare", "GeneralSettings": "Impostazioni Generali", - "ForMoreInformationOnTheIndividualDownloadClients": "Per maggiori informazioni sui singoli client di download clicca sul pulsante info.", + "ForMoreInformationOnTheIndividualDownloadClients": "Per più informazioni sui singoli client di download clicca sui pulsanti info.", "Fixed": "Fissato", - "FilterPlaceHolder": "Cerca Films", - "ExistingTag": "Tag esistente", + "FilterPlaceHolder": "Cerca Indicizzatori", + "ExistingTag": "Etichetta esistente", "Exception": "Eccezione", "ErrorLoadingContents": "Errore nel caricare i contenuti", "EnableSslHelpText": " Richiede il riavvio come amministratore per avere effetto", - "EnableInteractiveSearchHelpText": "Verrà usato quando la ricerca interattiva sarà utilizzata", - "EnableInteractiveSearch": "Abilita la ricerca interattiva", - "EnableAutomaticSearchHelpText": "Sarà usata quando la ricerca automatica è eseguita dalla UI o da Prowlarr", - "EnableAutomaticSearch": "Attiva la ricerca automatica", - "DeleteTagMessageText": "Sei sicuro di voler eliminare il tag '{0}'?", + "EnableInteractiveSearchHelpText": "Verrà usato durante la ricerca interattiva", + "EnableInteractiveSearch": "Abilita la Ricerca Interattiva", + "EnableAutomaticSearchHelpText": "Sarà usata quando la ricerca automatica è eseguita dalla l'intrfaccia o da Prowlarr", + "EnableAutomaticSearch": "Attiva la Ricerca Automatica", + "DeleteTagMessageText": "Sei sicuro di voler eliminare l'etichetta '{0}'?", "DeleteNotificationMessageText": "Sei sicuro di voler eliminare la notifica '{0}'?", "DeleteDownloadClientMessageText": "Sei sicuro di voler eliminare il client di download '{0}'?", "BeforeUpdate": "Prima di aggiornare", "ApplyTagsHelpTexts4": "Sostituire: Sostituisce le etichette con quelle inserite (non inserire nessuna etichette per eliminarle tutte)", - "ApplyTagsHelpTexts3": "Rimuovere: rimuovi le etichette inserite", + "ApplyTagsHelpTexts3": "Rimuovi: Rimuove le etichette inserite", "Usenet": "Usenet", "Uptime": "Tempo di attività", - "YesCancel": "Si, annulla", + "YesCancel": "Si, Cancella", "Version": "Versione", "Username": "Nome utente", "UseProxy": "Usa Proxy", "UrlBaseHelpText": "Per il supporto al reverse proxy, di default è vuoto", - "URLBase": "URL di Base", - "UpdateScriptPathHelpText": "Percorso verso uno script che prende un pacchetto di aggiornamento estratto e gestisce il resto del processo di aggiornamento", - "UpdateMechanismHelpText": "Usa il programma di aggiornamento incorporato in Prowlarr o uno script", - "UpdateAutomaticallyHelpText": "Download e installazione automatica degli aggiornamenti. Sarai comunque in grado in installarli dal menu Sistema: Aggiornamenti", + "URLBase": "Base Url", + "UpdateScriptPathHelpText": "Percorso verso uno script personalizzato che prende un pacchetto di aggiornamento estratto e gestisce il resto del processo di aggiornamento", + "UpdateMechanismHelpText": "Usa l'aggiornamento integrato in Prowlarr o uno script", + "UpdateAutomaticallyHelpText": "Scarica e installa automaticamente gli aggiornamenti. Sarai comunque in grado in installarli da Sistema: Aggiornamenti", "UnsavedChanges": "Modifiche non salvate", - "UnableToLoadUISettings": "Non riesco a caricare le impostazioni della UI", - "UnableToLoadTags": "Non riesco a caricare i tag", - "UnableToLoadNotifications": "Non riesco a caricare le notifiche", - "UnableToLoadHistory": "Non riesco a caricare la storia", - "UnableToLoadGeneralSettings": "Non riesco a caricare le impostazioni generali", - "UnableToLoadDownloadClients": "Non riesco a caricare i client di download", - "UnableToLoadBackups": "Non riesco a caricare i backup", - "UnableToAddANewNotificationPleaseTryAgain": "Non riesco ad aggiungere una nuova notifica, riprova.", - "UnableToAddANewIndexerPleaseTryAgain": "Non riesco ad aggiungere un nuovo indexer, riprova.", - "UnableToAddANewDownloadClientPleaseTryAgain": "Non riesco ad aggiungere un nuovo client di download, riprova.", - "UISettings": "Impostazioni UI", - "UILanguageHelpTextWarning": "E' richiesto il reload del browser", - "UILanguageHelpText": "Lingua che Prowlarr userà per la UI", - "UILanguage": "Lingua della UI", - "Torrents": "Torrent", - "TestAllClients": "Testa tutti i client", - "TagsHelpText": "Si applica ai film con almeno un tag corrispondente", - "TagIsNotUsedAndCanBeDeleted": "Il tag non è usato e può essere eliminato", + "UnableToLoadUISettings": "Impossibile caricare le impostazioni interfaccia", + "UnableToLoadTags": "Impossibile caricare le Etichette", + "UnableToLoadNotifications": "Impossibile caricare le Notifiche", + "UnableToLoadHistory": "Impossibile caricare la storia", + "UnableToLoadGeneralSettings": "Impossibile caricare le impostazioni Generali", + "UnableToLoadDownloadClients": "Impossibile caricare i client di download", + "UnableToLoadBackups": "Impossibile caricare i backup", + "UnableToAddANewNotificationPleaseTryAgain": "Impossibile aggiungere una nuova notifica, riprova.", + "UnableToAddANewIndexerPleaseTryAgain": "Impossibile aggiungere un nuovo Indicizzatore, riprova.", + "UnableToAddANewDownloadClientPleaseTryAgain": "Impossibile aggiungere un nuovo client di download, riprova.", + "UISettings": "Impostazioni Interfaccia", + "UILanguageHelpTextWarning": "Ricaricamento del browser richiesto", + "UILanguageHelpText": "Lingua che Prowlarr userà per l'interfaccia", + "UILanguage": "Lingua dell'Interfaccia", + "Torrents": "Torrents", + "TestAllClients": "Testa Tutti i Client", + "TagsHelpText": "Si applica agli Indicizzatori con almeno un etichetta corrispondente", + "TagIsNotUsedAndCanBeDeleted": "L'etichetta non è in uso e può essere eliminata", "TagCannotBeDeletedWhileInUse": "Non può essere cancellato mentre è in uso", - "SuggestTranslationChange": "Richiedi cambio di traduzione", + "SuggestTranslationChange": "Suggerisci un cambio nella traduzione", "StartupDirectory": "Cartella di avvio", "StartTypingOrSelectAPathBelow": "Comincia a digitare o seleziona un percorso sotto", "SSLPort": "Porta SSL", "SSLCertPathHelpText": "Percorso file pfx", - "SSLCertPath": "Percorso Cert SSL", + "SSLCertPath": "Percorso Certificato SSL", "SSLCertPasswordHelpText": "Password del file pfx", - "SSLCertPassword": "Password Cert SSL", + "SSLCertPassword": "Password Certificato SSL", "ShowSearchHelpText": "Mostra pulsante ricerca al passaggio", - "ShowSearch": "Mostra ricerca", + "ShowSearch": "Mostra Ricerca", "ShownClickToHide": "Visibile, clicca per nascondere", - "SettingsTimeFormat": "Formato orario", + "SettingsTimeFormat": "Formato Ora", "SettingsShowRelativeDatesHelpText": "Mostra date relative (Oggi/Ieri/ecc) o assolute", - "SettingsShowRelativeDates": "Mostra date relative", + "SettingsShowRelativeDates": "Mostra Date Relative", "SettingsShortDateFormat": "Formato Data Corto", - "SettingsEnableColorImpairedModeHelpText": "Stile alterato per permettere agli utenti daltonici di distinguere meglio le informazioni con colori codificati", + "SettingsEnableColorImpairedModeHelpText": "Stile alterato per permettere agli utenti daltonici di distinguere meglio le informazioni codificate a colori", "Priority": "Priorità", "InteractiveSearch": "Ricerca interattiva", - "IndexerPriorityHelpText": "Priorità dell'indexer da 1 (più alto) a 50 (più basso). Default: 25.", - "IndexerPriority": "Priorità dell'indexer", - "EditIndexer": "Edita Indexer", + "IndexerPriorityHelpText": "Priorità dell'Indicizzatore da 1 (più alto) a 50 (più basso). Predefinita: 25.", + "IndexerPriority": "Priorità dell'Indicizzatore", + "EditIndexer": "Modifica Indicizzatore", "Disabled": "Disabilitato", "AutomaticSearch": "Ricerca Automatica", - "AddIndexer": "Aggiungi Indexer", - "SaveSettings": "Salva impostazioni", - "OpenThisModal": "Apri questa modalità", - "MovieIndexScrollTop": "Elenco film: scorri in alto", - "MovieIndexScrollBottom": "Elenco film: scorri in basso", - "FocusSearchBox": "Attiva casella di ricerca", + "AddIndexer": "Aggiungi Indicizzatore", + "SaveSettings": "Salva Impostazioni", + "OpenThisModal": "Apri questa Modale", + "MovieIndexScrollTop": "Indice film: scorri in alto", + "MovieIndexScrollBottom": "Indice Film: scorri in basso", + "FocusSearchBox": "Evidenzia casella di ricerca", "CloseCurrentModal": "Chiudi la Modale Attuale", "AcceptConfirmationModal": "Acetta Conferma Modale", - "IndexerLongTermStatusCheckSingleClientMessage": "Alcuni indexer non disponibili da più di 6 ore a causa di errori: {0}", - "IndexerLongTermStatusCheckAllClientMessage": "Nessun indexer è disponibile da più di 6 ore a causa di errori", + "IndexerLongTermStatusCheckSingleClientMessage": "Alcuni Indicizzatori non sono disponibili da più di 6 ore a causa di errori: {0}", + "IndexerLongTermStatusCheckAllClientMessage": "Nessun Indicizzatore è disponibile da più di 6 ore a causa di errori", "PrioritySettings": "Priorità", "Description": "Descrizione", "Add": "Aggiungi", "Enabled": "Abilitato", "Encoding": "Codifica", - "EnableIndexer": "Abilita Indexer", - "AddNewIndexer": "Aggiungi nuovo Indexer", - "IndexerAuth": "Autenticazione Indexer", + "EnableIndexer": "Abilita Indicizzatore", + "AddNewIndexer": "Aggiungi nuovo Indicizzatore", + "IndexerAuth": "Autenticazione dell'Indicizzatore", "AddDownloadClient": "Aggiungi Client di Download", "Category": "Categoria", "ClearHistory": "Cancella cronologia", "ClearHistoryMessageText": "Sei sicuro di voler cancellare tutta la cronologia di Prowlarr?", "Discord": "Discord", "Donations": "Donazioni", - "EnableRssHelpText": "Abilita feed RSS per Indexer", - "HomePage": "Home Page", + "EnableRssHelpText": "Abilita feed RSS per l'Indicizzatore", + "HomePage": "Pagina Iniziale", "Id": "Id", - "IndexerHealthCheckNoIndexers": "Nessun indexer abilitato Prowlarr non ritornerà risultati di ricerca", + "IndexerHealthCheckNoIndexers": "Nessun Indicizzatore abilitato, Prowlarr non restituirà risultati di ricerca", "EnableRss": "Abilita RSS", - "NoLinks": "Nessun collegamento", + "NoLinks": "Nessun Collegamento", "RSS": "RSS", "Wiki": "Wiki", - "AllIndexersHiddenDueToFilter": "Tutti gli indexer sono nascosti a causa del filtro applicato.", + "AllIndexersHiddenDueToFilter": "Tutti gli Indicizzatori sono nascosti a causa del filtro applicato.", "DeleteApplicationMessageText": "Sei sicuro di voler eliminare l'applicazione '{0}'?", "DeleteIndexerProxyMessageText": "Sei sicuro di voler eliminare il proxy '{0}'?", "Presets": "Preset", - "SearchIndexers": "Cerca Films", - "UnableToAddANewIndexerProxyPleaseTryAgain": "Non riesco ad aggiungere un nuovo indexer, riprova.", + "SearchIndexers": "Cerca Indicizzatori", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Impossibile aggiungere un nuovo proxy per l'Indicizzatore, riprova.", "Yesterday": "Ieri", "ApplicationStatusCheckSingleClientMessage": "Applicazioni non disponibili a causa di errori: {0}", "Today": "Oggi", "Tomorrow": "Domani", "ApplicationStatusCheckAllClientMessage": "Tutte le applicazioni non sono disponibili a causa di errori", - "CouldNotConnectSignalR": "Non ho potuto connettermi a SignalR, la UI non si aggiornerà", + "CouldNotConnectSignalR": "Non ho potuto connettermi a SignalR, l'interfaccia non si aggiornerà", "Custom": "Personalizzato", "FeatureRequests": "Richieste di funzionalità", - "Grabs": "Preleva", - "IndexerProxyStatusCheckAllClientMessage": "Tutti gli indexer non sono disponibili a causa di errori", - "IndexerProxyStatusCheckSingleClientMessage": "Indexer non disponibili a causa di errori: {0}", + "Grabs": "Prendere", + "IndexerProxyStatusCheckAllClientMessage": "Tutti i Proxy non sono disponibili a causa di errori", + "IndexerProxyStatusCheckSingleClientMessage": "Proxy non disponibili a causa di errori: {0}", "Reddit": "Reddit", "Torrent": "Torrent", - "UnableToAddANewApplicationPleaseTryAgain": "Non riesco ad aggiungere una nuova notifica, riprova.", - "UnableToAddANewAppProfilePleaseTryAgain": "Non riesco ad aggiungere un nuovo profilo di qualità, riprova.", - "NotificationTriggersHelpText": "Selezionare quali eventi attiveranno questa notifica", - "HistoryCleanupDaysHelpTextWarning": "I file nel cestino più vecchi del numero selezionato di giorni saranno eliminati automaticamente", + "UnableToAddANewApplicationPleaseTryAgain": "Impossibile aggiungere una nuova applicazione, riprova.", + "UnableToAddANewAppProfilePleaseTryAgain": "Impossibile aggiungere un nuovo profilo applicazione, riprova.", + "NotificationTriggersHelpText": "Seleziona quali eventi attiveranno questa notifica", + "HistoryCleanupDaysHelpTextWarning": "I file dello storico più vecchi del numero selezionato di giorni saranno eliminati automaticamente", "OnApplicationUpdate": "All'aggiornamento dell'applicazione", - "Filters": "Filtro", + "Filters": "Filtri", "HistoryCleanupDaysHelpText": "Imposta a 0 per disabilitare la pulizia automatica", "OnApplicationUpdateHelpText": "All'aggiornamento dell'applicazione", - "OnGrab": "Quando viene prelevato", + "OnGrab": "Al Prelievo", "OnHealthIssue": "Quando c'è un problema", - "TestAllIndexers": "Testa tutti gli indexer", - "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent esposto dalla app che ha chiamato la API", - "GrabReleases": "Preleva Release", + "TestAllIndexers": "Testa tutti gli Indicizzatori", + "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent fornito dalla app che ha chiamato la API", + "GrabReleases": "Prendi Release(s)", "Link": "Collegamenti", - "MappedDrivesRunningAsService": "I drive di rete mappati non sono disponibili eseguendo come servizio di Windows. Vedere le FAQ per maggiori informazioni", + "MappedDrivesRunningAsService": "Le unità di rete mappate non sono disponibili eseguendo come servizio di Windows. Vedere le FAQ per maggiori informazioni", "No": "No", - "UnableToLoadIndexers": "Non riesco a caricare l'indexer", + "UnableToLoadIndexers": "Impossibile caricare gli Indicizzatori", "Yes": "Si", - "AddIndexerProxy": "Aggiungi proxy dell'Indexer", + "AddIndexerProxy": "Aggiungi proxy dell'Indicizzatore", "AudioSearch": "Ricerca Audio", "BookSearch": "Ricerca Libri", "AddRemoveOnly": "Solo Aggiunta e Rimozione", "AppProfileSelectHelpText": "I profili delle App sono utilizzati per controllare la sincronizzazione delle impostazioni RSS, Ricerca Automatica e Ricerca Interattiva", "DeleteApplication": "Cancella Applicazione", "DeleteAppProfile": "Cancella Profilo App", - "AddAppProfile": "Aggiungi Profilo di Personalizzazione dell'App", "AddedToDownloadClient": "Release aggiunta al client", "AddToDownloadClient": "Aggiungi release al client di download", "Categories": "Categorie", "Database": "Database", - "DeleteIndexerProxy": "Cancella il Proxy dell'Indice", + "DeleteIndexerProxy": "Cancella il Proxy dell'Indicizzatore", "Auth": "Auth", - "AddDownloadClientToProwlarr": "L'aggiunta di un client di download permette a Prowlarr di inviare la release direttamente dall'interfaccia utente mentre si fa una ricerca manuale.", + "AddDownloadClientToProwlarr": "L'aggiunta di un client di download permette a Prowlarr di inviare le release direttamente dall'interfaccia mentre si fa una ricerca manuale.", "Applications": "Applicazioni", "AppProfileInUse": "Profilo App in Uso", "Application": "Applicazione", "BookSearchTypes": "Tipi di Ricerca Libri", - "AppProfile": "Profilo App", "AppProfileDeleteConfirm": "Sicuro di voler eliminare {0}?", - "AppProfiles": "Profili delle App", "AppSettingsSummary": "Applicazioni e impostazioni per configurare come Prowlarr interagisce con i tuoi programmi PVR", - "Apps": "Le App" + "Apps": "Le App", + "DevelopmentSettings": "Impostazioni di Sviluppo", + "RedirectHelpText": "Reindirizza le richieste di download per l'Indicizzatore e passa il prelievo direttamente invece di inoltrare la richiesta tramite Prowlarr", + "IndexerVipCheckExpiredClientMessage": "I benefici VIP dell'Indicizzatore sono scaduti: {0}", + "IndexerVipCheckExpiringClientMessage": "I benefici VIP dell'Indicizzatore scadranno a breve: {0}", + "IndexerProxies": "Proxy degli Indicizzatori", + "Stats": "Statistiche", + "SyncAppIndexers": "Sincronizza gli Indicizzatori dell'App", + "SyncLevel": "Livello Sincronizzazione", + "IndexerProxy": "Proxy dell'Indicizzatore", + "Proxies": "Proxy", + "UnableToLoadApplicationList": "Impossibile careicare la lista applicazioni", + "Website": "Sito", + "IndexersSelectedInterp": "{0} Indicizzatore(i) Selezionato(i)", + "Privacy": "Privacy", + "SettingsIndexerLogging": "Logging Migliorato dell'Indicizzatore", + "TestAllApps": "Testa Tutte le App", + "UnableToLoadAppProfiles": "Impossibile caricare i profili delle app", + "UnableToLoadIndexerProxies": "Impossibile caricare i Proxy degli Indicizzatori", + "FullSync": "Sincronizzazione completa", + "IndexerAlreadySetup": "Almeno un'istanza dell'indicizzatore è già configurata", + "IndexerDetails": "Dettagli dell'Indicizzatore", + "IndexerInfo": "Info sull'Indicizzatore", + "IndexerName": "Nome dell'Indicizzatore", + "IndexerNoDefCheckMessage": "Gli indicizzatori non hanno una definizione e non funzioneranno: {0}. Si prega di rimuoverli e/o di riaggiungerli a Prowlarr", + "HistoryCleanup": "Pulizia della Cronologia", + "IndexerRss": "RSS dell'Indicizzatore", + "IndexerSite": "Sito dell'Indicizzatore", + "MassEditor": "Editor di Massa", + "IndexerTagsHelpText": "Usa le etichette per specificare i Proxy degli Indicizzatori, con che app un indicizzatore si sincronizza o semplcemente per organizzarli.", + "MovieSearch": "Ricerca Film", + "MovieSearchTypes": "Tipi di Ricerca Film", + "MusicSearchTypes": "Tipi di Ricerca Musica", + "Notification": "Notifica", + "Notifications": "Notifica", + "NotSupported": "Non Supportato", + "Private": "Privato", + "Public": "Pubblico", + "QueryOptions": "Opzioni Query", + "QueryResults": "Risultati Query", + "RawSearchSupported": "Ricerca Raw Supportata", + "Redirect": "Reindirizzamento", + "SearchType": "Tipo di Ricerca", + "SearchTypes": "Tipi di Ricerca", + "SemiPrivate": "Semi-Privato", + "SettingsFilterSentryEvents": "Filtrare gli eventi analitici", + "SettingsFilterSentryEventsHelpText": "Filtra gli eventi noti come errore utente dall'essere inviati come Analitica", + "SettingsLogRotate": "Rotazione Log", + "SettingsLogRotateHelpText": "Numero massimo di file di log da tenere salvati nella cartella log", + "SettingsLogSql": "Log Sql", + "TvSearch": "Ricerca Serie TV", + "TVSearchTypes": "Tipi Ricerca Serie TV", + "UnableToLoadDevelopmentSettings": "Impossibile caricare le Impostazioni di Sviluppo", + "Url": "Url", + "NoSearchResultsFound": "Nessun risultato di ricerca trovato, prova a eseguire una nuova ricerca qui sotto.", + "SettingsConsoleLogLevel": "Livello di Log della Console", + "IndexerObsoleteCheckMessage": "Gli indicizzatori sono obsoleti e sono stati aggiornati: {0}. Si prega di rimuoverli e/o di riaggiungerli a Prowlarr", + "IndexerQuery": "Query dell'Indicizzatore", + "IndexerSettingsSummary": "Configura varie impostazioni globali degli Indicizzatori, anche i Proxy.", + "Query": "Query", + "SearchCapabilities": "Capacità di Ricerca", + "SettingsIndexerLoggingHelpText": "Logga i dati aggiuntivi dell'indicizzatore includendo la risposta", + "SettingsSqlLoggingHelpText": "Scrivi a log tutte le query SQL di Prowlarr", + "SyncLevelAddRemove": "Solo aggiunte e rimozioni: Quando gli indicizzatori vengono aggiunti o rimossi da Prowlarr, verrà aggiornata questa applicazione remota.", + "SyncLevelFull": "Sincronizzazione completa: Manterrà gli indicizzatori di questa app completamente sincronizzati. Le modifiche apportate agli indicizzatori in Prowlarr sono poi sincronizzate con questa applicazione. Qualsiasi cambiamento fatto agli indicizzatori da remoto all'interno di questa applicazione sarà sovrascritto da Prowlarr alla prossima sincronizzazione.", + "MinimumSeedersHelpText": "Seeder minimi richiesti dall'Applicazione per far si che l'indicizzatore li prenda", + "SyncProfile": "Profilo Sincronizzazione", + "SyncProfiles": "Profili Sincronizzazione", + "AddSyncProfile": "Aggiungi Profilo di Sincronizzazione", + "EditSyncProfile": "Modifica Profilo di Sincronizzazione", + "MinimumSeeders": "Seeder Minimi" } diff --git a/src/NzbDrone.Core/Localization/Core/nb_NO.json b/src/NzbDrone.Core/Localization/Core/nb_NO.json index 97a9e9d95..7a013984d 100644 --- a/src/NzbDrone.Core/Localization/Core/nb_NO.json +++ b/src/NzbDrone.Core/Localization/Core/nb_NO.json @@ -1,6 +1,5 @@ { "Add": "Legge til", - "AddAppProfile": "Legg til app -synkroniseringsprofil", "AddDownloadClient": "Legg til nedlastingsklient", "Added": "La til", "AddingTag": "Legger til tag", diff --git a/src/NzbDrone.Core/Localization/Core/nl.json b/src/NzbDrone.Core/Localization/Core/nl.json index 8c0e5f8aa..68b223a87 100644 --- a/src/NzbDrone.Core/Localization/Core/nl.json +++ b/src/NzbDrone.Core/Localization/Core/nl.json @@ -330,7 +330,6 @@ "UnableToLoadAppProfiles": "Kan app-profielen niet laden", "UnableToLoadDevelopmentSettings": "Kan ontwikkelingsinstellingen niet laden", "UnableToLoadIndexerProxies": "Kan Indexeerder-proxy's niet laden", - "AppProfile": "App-profiel", "SettingsFilterSentryEventsHelpText": "Filter bekende gebruikersfoutgebeurtenissen zodat ze niet als Analytiek worden verzonden", "HomePage": "Startpagina", "IndexerProxies": "Indexer-proxy's", @@ -375,18 +374,15 @@ "Wiki": "Wiki", "Grabs": "Gegrepen", "NotificationTriggersHelpText": "Selecteer welke gebeurtenissen deze melding moeten activeren", - "AddAppProfile": "Profiel voor app-synchronisatie toevoegen", "AddDownloadClientToProwlarr": "Door een downloadclient toe te voegen, kan Prowlarr releases rechtstreeks vanuit de gebruikersinterface verzenden tijdens een handmatige zoekopdracht.", "AddIndexerProxy": "Indexeerproxy toevoegen", "AppProfileInUse": "App-profiel in gebruik", - "AppProfiles": "App-profielen", "AppProfileSelectHelpText": "App-profielen worden gebruikt om de instellingen voor RSS, Automatisch zoeken en Interactief zoeken bij applicatiesynchronisatie te beheren", "CouldNotConnectSignalR": "Kan geen verbinding maken met SignalR, gebruikersinterface wordt niet bijgewerkt", "DeleteApplication": "Applicatie verwijderen", "DeleteApplicationMessageText": "Weet u zeker dat u de applicatie '{0}' wilt verwijderen?", "DeleteIndexerProxy": "Indexeerproxy verwijderen", "DeleteIndexerProxyMessageText": "Weet u zeker dat u de proxy '{0}' wilt verwijderen?", - "EditAppProfile": "App-profiel bewerken", "Enabled": "Ingeschakeld", "EnableIndexer": "Indexer inschakelen", "Encoding": "Coderen", diff --git a/src/NzbDrone.Core/Localization/Core/pt.json b/src/NzbDrone.Core/Localization/Core/pt.json index 0f3cd4c13..cc09232aa 100644 --- a/src/NzbDrone.Core/Localization/Core/pt.json +++ b/src/NzbDrone.Core/Localization/Core/pt.json @@ -308,21 +308,17 @@ "EnableRssHelpText": "Ativar feed RSS para o indexador", "EnableIndexer": "Ativar indexador", "EnableRss": "Ativar RSS", - "EditAppProfile": "Editar perfil da aplicação", "DevelopmentSettings": "Definições de desenvolvimento", "DeleteApplicationMessageText": "Tem a certeza que deseja eliminar a aplicação \"{0}\"?", "DeleteApplication": "Eliminar aplicação", "ClearHistoryMessageText": "Tem a certeza que deseja limpar todo o histórico do Prowlarr?", "ClearHistory": "Limpar histórico", - "AppProfiles": "Perfis de aplicações", "ApplicationStatusCheckSingleClientMessage": "Aplicações indisponíveis devido a falhas: {0}", "ApplicationStatusCheckAllClientMessage": "Todas as aplicações estão indisponíveis devido a falhas", "AllIndexersHiddenDueToFilter": "Todos os indexadores estão ocultos devido ao filtro aplicado.", "AddToDownloadClient": "Adicionar versão ao cliente de transferências", "AddNewIndexer": "Adicionar novo indexador", "AddedToDownloadClient": "Versão adicionada ao cliente", - "AppProfile": "Perfil da aplicação", - "AddAppProfile": "Adicionar perfil de sincronização da aplicação", "SettingsFilterSentryEventsHelpText": "Filtrar eventos de erro de utilizador conhecidos para que não sejam enviados para análise", "Yesterday": "Ontem", "Wiki": "Wiki", diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index e82afa703..7f5370c0f 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -323,10 +323,6 @@ "Yesterday": "Ontem", "EnableRssHelpText": "Habilitar feed RSS para o indexador", "EnableRss": "Habilitar RSS", - "EditAppProfile": "Editar perfil do aplicativo", - "AppProfiles": "Perfis de aplicativo", - "AddAppProfile": "Adicionar perfil de sincronização do aplicativo", - "AppProfile": "Perfil do aplicativo", "Wiki": "Wiki", "RSS": "RSS", "RedirectHelpText": "Redirecionar a solicitação de download de entrada para o indexador e passar diretamente para a obtenção, em vez de por proxy usando o Prowlarr", @@ -388,7 +384,7 @@ "IndexerSettingsSummary": "Defina várias configurações globais do Indexador, incluindo Proxies.", "IndexerProxyStatusCheckAllClientMessage": "Todos os proxies estão indisponíveis devido a falhas", "IndexerProxyStatusCheckSingleClientMessage": "Proxies indisponíveis devido a falhas: {0}", - "IndexerTagsHelpText": "Use etiquetas para especificar proxies de indexador ou apenas para organizar seus indexadores.", + "IndexerTagsHelpText": "Usar etiquetas para especificar proxies do indexador, com quais aplicativos o indexador é sincronizado ou apenas para organizar seus indexadores.", "Notifications": "Notificações", "UnableToAddANewIndexerProxyPleaseTryAgain": "Não foi possível adicionar um novo proxy indexador, tente novamente.", "UnableToLoadIndexerProxies": "Incapaz de carregar proxies indexadores", @@ -444,5 +440,11 @@ "GrabReleases": "Capturar Versão", "Link": "Link", "MappedDrivesRunningAsService": "As unidades de rede mapeadas não estão disponíveis quando executadas como um serviço do Windows. Consulte as Perguntas frequentes para saber mais", - "No": "Não" + "No": "Não", + "EditSyncProfile": "Editar Perfil de Sincronização", + "SyncProfile": "Perfil de Sincronização", + "SyncProfiles": "Perfis de Sincronização", + "AddSyncProfile": "Adicionar Perfil de Sincronização", + "MinimumSeeders": "Mínimo de Seeders", + "MinimumSeedersHelpText": "Mínimo de seeders requeridos pelo Aplicativo para o indexador baixar" } diff --git a/src/NzbDrone.Core/Localization/Core/ru.json b/src/NzbDrone.Core/Localization/Core/ru.json index cd83c0537..c98499754 100644 --- a/src/NzbDrone.Core/Localization/Core/ru.json +++ b/src/NzbDrone.Core/Localization/Core/ru.json @@ -337,10 +337,15 @@ "No": "Нет", "Yes": "Да", "AddRemoveOnly": "Добавить и Удалить Только", - "AddAppProfile": "Добавить профиль синхронизации приложения", "AddNewIndexer": "Добавить Новый Индексатор", "AddToDownloadClient": "Добавить выпуск в Загрузочный клиент", "AddedToDownloadClient": "Выпуск добавлен в клиент", "AddDownloadClientToProwlarr": "Добавление клиента загрузки позволяет Prowlarr отправлять выпуски прямо из пользовательского интерфейса, выполняя поиск вручную.", - "AddIndexerProxy": "Добавить индексатор прокси" + "AddIndexerProxy": "Добавить индексатор прокси", + "Connect": "Оповещения", + "Notification": "Оповещения", + "Encoding": "Кодирование", + "Applications": "Приложения", + "Application": "Приложения", + "Notifications": "Оповещения" } diff --git a/src/NzbDrone.Core/Localization/Core/sv.json b/src/NzbDrone.Core/Localization/Core/sv.json index e8adfbc51..662ba3a92 100644 --- a/src/NzbDrone.Core/Localization/Core/sv.json +++ b/src/NzbDrone.Core/Localization/Core/sv.json @@ -372,7 +372,6 @@ "Encoding": "Enkodering", "EnableRssHelpText": "Aktiverea Rss feed för Indexer", "EnableIndexer": "Aktivera Indexer", - "EditAppProfile": "Hantera App Profil", "DevelopmentSettings": "Utvecklingsinställningar", "Description": "Beskrivning", "DeleteIndexerProxy": "Radera Indexer Proxy", @@ -382,18 +381,15 @@ "ClearHistoryMessageText": "Är du säker på att du vill rensa all Prowlarr historik?", "ClearHistory": "Rensa Historik", "Category": "Kategori", - "AppProfile": "App Profil", "AddToDownloadClient": "Lägg till nyutgåva i nedladdningsklienten", "AddRemoveOnly": "Lägg till och Ta bort Endast", "AddNewIndexer": "Lägg till Ny Indexer", "AddIndexerProxy": "Lägg till Indexer Proxy", "AddedToDownloadClient": "Nyutgåva lades till i klienten", - "AddAppProfile": "Lägg till App Sync Profil", "Auth": "Förafa", "AppSettingsSummary": "Applikationer och inställningar för att konfigurera hur Prowlarr interagerar med PVR program", "Apps": "Appar", "AppProfileSelectHelpText": "App profiler är använda för att kontrollera RSS, Automatisk Sökning och interaktiv Sökningsinställningar på applikationen sync", - "AppProfiles": "App Profiler", "AppProfileInUse": "App Profil i användning", "AppProfileDeleteConfirm": "Är du säker på att du vill radera {0}?", "Applications": "Applikationer", diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index e14370240..9a9a6f617 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -17,8 +17,6 @@ "AddIndexer": "添加索引器", "AddedToDownloadClient": "发布已添加档案到客户端", "Added": "已添加", - "AddAppProfile": "添加应用同步档案", - "AppProfile": "程序档案", "Actions": "操作", "About": "关于", "MoreInfo": "更多信息", @@ -103,7 +101,6 @@ "EnableAutomaticSearch": "启用自动搜索", "Enable": "启用", "EditIndexer": "编辑搜刮器", - "EditAppProfile": "编辑应用配置", "Edit": "编辑", "DownloadClientStatusCheckSingleClientMessage": "所有下载客户端都不可用: {0}", "DownloadClientStatusCheckAllClientMessage": "所有下载客户端都不可用", @@ -178,7 +175,6 @@ "AreYouSureYouWantToResetYourAPIKey": "你确认希望重置API密钥吗?", "Apps": "应用程序", "AppProfileSelectHelpText": "应用程序配置用于控制应用程序同步设置 RSS、自动搜索和交互式搜索设置", - "AppProfiles": "应用配置文件", "AppProfileInUse": "正在使用的应用程序配置文件", "AppProfileDeleteConfirm": "您确认您想删除吗?", "ApplyTagsHelpTexts4": "替换:用输入的标签替换标签(不输入标签将清除所有标签)", @@ -444,5 +440,11 @@ "Yes": "是", "Application": "程序", "SearchTypes": "搜索类型", - "UnableToLoadIndexers": "无法加载搜刮器" + "UnableToLoadIndexers": "无法加载搜刮器", + "AddSyncProfile": "添加同步配置文件", + "SyncProfiles": "同步配置文件", + "EditSyncProfile": "编辑同步配置文件", + "SyncProfile": "同步配置文件", + "MinimumSeeders": "最少播种量", + "MinimumSeedersHelpText": "用于索引器抓取的应用程序所需的最小播种量" } From beabd10f064a163bbf6820ad96a65ea9e095b042 Mon Sep 17 00:00:00 2001 From: twolaw <twolaw@free.fr> Date: Sat, 14 May 2022 19:39:24 +0200 Subject: [PATCH 0475/2320] diversify chartcolors for doughnut & stackedbar --- frontend/src/Components/Chart/DoughnutChart.js | 2 +- frontend/src/Components/Chart/StackedBarChart.js | 4 ++-- frontend/src/Styles/Variables/colors.js | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/src/Components/Chart/DoughnutChart.js b/frontend/src/Components/Chart/DoughnutChart.js index 8a15fa5b2..d358b97c2 100644 --- a/frontend/src/Components/Chart/DoughnutChart.js +++ b/frontend/src/Components/Chart/DoughnutChart.js @@ -29,7 +29,7 @@ class DoughnutChart extends Component { datasets: [{ label: this.props.title, data: this.props.data.map((d) => d.value), - backgroundColor: colors.chartColors + backgroundColor: colors.chartColorsDiversified }] } }); diff --git a/frontend/src/Components/Chart/StackedBarChart.js b/frontend/src/Components/Chart/StackedBarChart.js index e4531464f..6b5ed083f 100644 --- a/frontend/src/Components/Chart/StackedBarChart.js +++ b/frontend/src/Components/Chart/StackedBarChart.js @@ -41,7 +41,7 @@ class StackedBarChart extends Component { return { label: d.label, data: d.data, - backgroundColor: colors.chartColors[index] + backgroundColor: colors.chartColorsDiversified[index] }; }) } @@ -54,7 +54,7 @@ class StackedBarChart extends Component { return { label: d.label, data: d.data, - backgroundColor: colors.chartColors[index] + backgroundColor: colors.chartColorsDiversified[index] }; }); this.myChart.update(); diff --git a/frontend/src/Styles/Variables/colors.js b/frontend/src/Styles/Variables/colors.js index b5fd0433f..ff2bedb3a 100644 --- a/frontend/src/Styles/Variables/colors.js +++ b/frontend/src/Styles/Variables/colors.js @@ -187,5 +187,6 @@ module.exports = { // Charts failedColors: ['#ffbeb2', '#feb4a6', '#fdab9b', '#fca290', '#fb9984', '#fa8f79', '#f9856e', '#f77b66', '#f5715d', '#f36754', '#f05c4d', '#ec5049', '#e74545', '#e13b42', '#da323f', '#d3293d', '#ca223c', '#c11a3b', '#b8163a', '#ae123a'], + chartColorsDiversified: ['#90caf9', '#f4d166', '#ff8a65', '#ce93d8', '#80cba9', '#ffab91', '#8097ea', '#bcaaa4', '#a57583', '#e4e498', '#9e96af', '#c6ab81', '#6972c6', '#619fc6', '#81ad81', '#f48fb1', '#82afca', '#b5b071', '#8b959b', '#7ec0b4'], chartColors: ['#f4d166', '#f6c760', '#f8bc58', '#f8b252', '#f7a84a', '#f69e41', '#f49538', '#f38b2f', '#f28026', '#f0751e', '#eb6c1c', '#e4641e', '#de5d1f', '#d75521', '#cf4f22', '#c64a22', '#bc4623', '#b24223', '#a83e24', '#9e3a26'] }; From 8d39d5c6bb2420168215b2e13c3746bce48199b7 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 20 Nov 2021 17:15:30 -0600 Subject: [PATCH 0476/2320] New: Native Theme Engine --- frontend/src/App/App.js | 9 +- frontend/src/App/ApplyTheme.js | 49 +++++ frontend/src/Settings/UI/UISettings.js | 16 ++ frontend/src/Styles/Themes/index.js | 5 + frontend/src/Styles/Themes/light.js | 191 ++++++++++++++++++ .../Configuration/ConfigFileProvider.cs | 2 + src/NzbDrone.Core/Localization/Core/en.json | 1 + .../Config/UiConfigController.cs | 24 ++- .../Config/UiConfigResource.cs | 6 +- .../Frontend/InitializeJsController.cs | 1 + 10 files changed, 297 insertions(+), 7 deletions(-) create mode 100644 frontend/src/App/ApplyTheme.js create mode 100644 frontend/src/Styles/Themes/index.js create mode 100644 frontend/src/Styles/Themes/light.js diff --git a/frontend/src/App/App.js b/frontend/src/App/App.js index 37c453f45..1eea6e082 100644 --- a/frontend/src/App/App.js +++ b/frontend/src/App/App.js @@ -4,6 +4,7 @@ import React from 'react'; import DocumentTitle from 'react-document-title'; import { Provider } from 'react-redux'; import PageConnector from 'Components/Page/PageConnector'; +import ApplyTheme from './ApplyTheme'; import AppRoutes from './AppRoutes'; function App({ store, history }) { @@ -11,9 +12,11 @@ function App({ store, history }) { <DocumentTitle title={window.Prowlarr.instanceName}> <Provider store={store}> <ConnectedRouter history={history}> - <PageConnector> - <AppRoutes app={App} /> - </PageConnector> + <ApplyTheme> + <PageConnector> + <AppRoutes app={App} /> + </PageConnector> + </ApplyTheme> </ConnectedRouter> </Provider> </DocumentTitle> diff --git a/frontend/src/App/ApplyTheme.js b/frontend/src/App/ApplyTheme.js new file mode 100644 index 000000000..339032d4a --- /dev/null +++ b/frontend/src/App/ApplyTheme.js @@ -0,0 +1,49 @@ +import PropTypes from 'prop-types'; +import React, { Fragment, useEffect } from 'react'; +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import themes from 'Styles/Themes'; + +function createMapStateToProps() { + return createSelector( + (state) => state.settings.ui.item.theme || window.Prowlarr.theme, + ( + theme + ) => { + return { + theme + }; + } + ); +} + +function ApplyTheme({ theme, children }) { + // Update the CSS Variables + function updateCSSVariables() { + const arrayOfVariableKeys = Object.keys(themes[theme]); + const arrayOfVariableValues = Object.values(themes[theme]); + + // Loop through each array key and set the CSS Variables + arrayOfVariableKeys.forEach((cssVariableKey, index) => { + // Based on our snippet from MDN + document.documentElement.style.setProperty( + `--${cssVariableKey}`, + arrayOfVariableValues[index] + ); + }); + } + + // On Component Mount and Component Update + useEffect(() => { + updateCSSVariables(theme); + }, [theme]); + + return <Fragment>{children}</Fragment>; +} + +ApplyTheme.propTypes = { + theme: PropTypes.string.isRequired, + children: PropTypes.object.isRequired +}; + +export default connect(createMapStateToProps)(ApplyTheme); diff --git a/frontend/src/Settings/UI/UISettings.js b/frontend/src/Settings/UI/UISettings.js index 1b9be3964..7b395225b 100644 --- a/frontend/src/Settings/UI/UISettings.js +++ b/frontend/src/Settings/UI/UISettings.js @@ -10,6 +10,8 @@ import PageContent from 'Components/Page/PageContent'; import PageContentBody from 'Components/Page/PageContentBody'; import { inputTypes } from 'Helpers/Props'; import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector'; +import themes from 'Styles/Themes'; +import titleCase from 'Utilities/String/titleCase'; import translate from 'Utilities/String/translate'; export const firstDayOfWeekOptions = [ @@ -62,6 +64,9 @@ class UISettings extends Component { const uiLanguages = languages.filter((item) => item.value !== 'Original'); + const themeOptions = Object.keys(themes) + .map((theme) => ({ key: theme, value: titleCase(theme) })); + return ( <PageContent title={translate('UISettings')}> <SettingsToolbarConnector @@ -138,6 +143,17 @@ class UISettings extends Component { </FieldSet> <FieldSet legend={translate('Style')}> + <FormGroup> + <FormLabel>{translate('Theme')}</FormLabel> + <FormInputGroup + type={inputTypes.SELECT} + name="theme" + helpText={translate('ThemeHelpText', ['Theme.Park'])} + values={themeOptions} + onChange={onInputChange} + {...settings.theme} + /> + </FormGroup> <FormGroup> <FormLabel>{translate('SettingsEnableColorImpairedMode')}</FormLabel> <FormInputGroup diff --git a/frontend/src/Styles/Themes/index.js b/frontend/src/Styles/Themes/index.js new file mode 100644 index 000000000..9e5cacb1b --- /dev/null +++ b/frontend/src/Styles/Themes/index.js @@ -0,0 +1,5 @@ +import * as light from './light'; + +export default { + light +}; diff --git a/frontend/src/Styles/Themes/light.js b/frontend/src/Styles/Themes/light.js new file mode 100644 index 000000000..b5fd0433f --- /dev/null +++ b/frontend/src/Styles/Themes/light.js @@ -0,0 +1,191 @@ +const prowlarrOrange = '#e66000'; + +module.exports = { + textColor: '#515253', + defaultColor: '#333', + disabledColor: '#999', + dimColor: '#555', + black: '#000', + white: '#fff', + offWhite: '#f5f7fa', + primaryColor: '#5d9cec', + selectedColor: '#f9be03', + successColor: '#27c24c', + dangerColor: '#f05050', + warningColor: '#ffa500', + infoColor: '#5d9cec', + queueColor: '#7a43b6', + purple: '#7a43b6', + pink: '#ff69b4', + prowlarrOrange, + helpTextColor: '#909293', + darkGray: '#888', + gray: '#adadad', + lightGray: '#ddd', + disabledInputColor: '#808080', + + // Theme Colors + + themeBlue: prowlarrOrange, + themeRed: '#c4273c', + themeDarkColor: '#595959', + themeLightColor: '#707070', + + torrentColor: '#00853d', + usenetColor: '#17b1d9', + + // Links + defaultLinkHoverColor: '#fff', + linkColor: '#5d9cec', + linkHoverColor: '#1b72e2', + + // Sidebar + + sidebarColor: '#e1e2e3', + sidebarBackgroundColor: '#595959', + sidebarActiveBackgroundColor: '#333333', + + // Toolbar + toolbarColor: '#e1e2e3', + toolbarBackgroundColor: '#707070', + toolbarMenuItemBackgroundColor: '#606060', + toolbarMenuItemHoverBackgroundColor: '#515151', + toolbarLabelColor: '#e1e2e3', + + // Accents + borderColor: '#e5e5e5', + inputBorderColor: '#dde6e9', + inputBoxShadowColor: 'rgba(0, 0, 0, 0.075)', + inputFocusBorderColor: '#66afe9', + inputFocusBoxShadowColor: 'rgba(102, 175, 233, 0.6)', + inputErrorBorderColor: '#f05050', + inputErrorBoxShadowColor: 'rgba(240, 80, 80, 0.6)', + inputWarningBorderColor: '#ffa500', + inputWarningBoxShadowColor: 'rgba(255, 165, 0, 0.6)', + colorImpairedGradient: '#ffffff', + colorImpairedGradientDark: '#f4f5f6', + + // + // Buttons + + defaultBackgroundColor: '#fff', + defaultBorderColor: '#eaeaea', + defaultHoverBackgroundColor: '#f5f5f5', + defaultHoverBorderColor: '#d6d6d6;', + + primaryBackgroundColor: '#5d9cec', + primaryBorderColor: '#5899eb', + primaryHoverBackgroundColor: '#4b91ea', + primaryHoverBorderColor: '#3483e7;', + + successBackgroundColor: '#27c24c', + successBorderColor: '#26be4a', + successHoverBackgroundColor: '#24b145', + successHoverBorderColor: '#1f9c3d;', + + warningBackgroundColor: '#ff902b', + warningBorderColor: '#ff8d26', + warningHoverBackgroundColor: '#ff8517', + warningHoverBorderColor: '#fc7800;', + + dangerBackgroundColor: '#f05050', + dangerBorderColor: '#f04b4b', + dangerHoverBackgroundColor: '#ee3d3d', + dangerHoverBorderColor: '#ec2626;', + + iconButtonDisabledColor: '#7a7a7a', + iconButtonHoverColor: '#666', + iconButtonHoverLightColor: '#ccc', + + // + // Modal + + modalBackdropBackgroundColor: 'rgba(0, 0, 0, 0.6)', + modalBackgroundColor: '#fff', + modalCloseButtonHoverColor: '#888', + + // + // Menu + menuItemColor: '#e1e2e3', + menuItemHoverColor: '#fbfcfc', + menuItemHoverBackgroundColor: '#f5f7fa', + + // + // Toolbar + + toobarButtonHoverColor: '#e66000', + toobarButtonSelectedColor: '#e66000', + + // + // Scroller + + scrollbarBackgroundColor: '#9ea4b9', + scrollbarHoverBackgroundColor: '#656d8c', + + // + // Card + + cardShadowColor: '#e1e1e1', + cardAlternateBackgroundColor: '#f5f5f5', + + // + // Alert + + alertDangerBorderColor: '#ebccd1', + alertDangerBackgroundColor: '#f2dede', + alertDangerColor: '#a94442', + + alertInfoBorderColor: '#bce8f1', + alertInfoBackgroundColor: '#d9edf7', + alertInfoColor: '#31708f', + + alertSuccessBorderColor: '#d6e9c6', + alertSuccessBackgroundColor: '#dff0d8', + alertSuccessColor: '#3c763d', + + alertWarningBorderColor: '#faebcc', + alertWarningBackgroundColor: '#fcf8e3', + alertWarningColor: '#8a6d3b', + + // + // Slider + + sliderAccentColor: '#5d9cec', + + // + // Form + + advancedFormLabelColor: '#ff902b', + disabledCheckInputColor: '#ddd', + + // + // Popover + + popoverTitleBackgroundColor: '#f7f7f7', + popoverTitleBorderColor: '#ebebeb', + popoverShadowColor: 'rgba(0, 0, 0, 0.2)', + popoverArrowBorderColor: '#fff', + + popoverTitleBackgroundInverseColor: '#595959', + popoverTitleBorderInverseColor: '#707070', + popoverShadowInverseColor: 'rgba(0, 0, 0, 0.2)', + popoverArrowBorderInverseColor: 'rgba(58, 63, 81, 0.75)', + + // + // Calendar + + calendarTodayBackgroundColor: '#ddd', + calendarBorderColor: '#cecece', + calendarTextDim: '#666', + + // + // Table + + tableRowHoverBackgroundColor: '#fafbfc', + + // + // Charts + + failedColors: ['#ffbeb2', '#feb4a6', '#fdab9b', '#fca290', '#fb9984', '#fa8f79', '#f9856e', '#f77b66', '#f5715d', '#f36754', '#f05c4d', '#ec5049', '#e74545', '#e13b42', '#da323f', '#d3293d', '#ca223c', '#c11a3b', '#b8163a', '#ae123a'], + chartColors: ['#f4d166', '#f6c760', '#f8bc58', '#f8b252', '#f7a84a', '#f69e41', '#f49538', '#f38b2f', '#f28026', '#f0751e', '#eb6c1c', '#e4641e', '#de5d1f', '#d75521', '#cf4f22', '#c64a22', '#bc4623', '#b24223', '#a83e24', '#9e3a26'] +}; diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index ddd653000..796d475c9 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -55,6 +55,7 @@ namespace NzbDrone.Core.Configuration string PostgresPassword { get; } string PostgresMainDb { get; } string PostgresLogDb { get; } + string Theme { get; } } public class ConfigFileProvider : IConfigFileProvider @@ -199,6 +200,7 @@ namespace NzbDrone.Core.Configuration public string PostgresPassword => GetValue("PostgresPassword", string.Empty, persist: false); public string PostgresMainDb => GetValue("PostgresMainDb", "prowlarr-main", persist: false); public string PostgresLogDb => GetValue("PostgresLogDb", "prowlarr-log", persist: false); + public string Theme => GetValue("Theme", "light", persist: false); public int PostgresPort => GetValueInt("PostgresPort", 5432, persist: false); public bool LogSql => GetValueBoolean("LogSql", false, persist: false); public int LogRotate => GetValueInt("LogRotate", 50, persist: false); diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 2d2616bce..dc6dfb8ba 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -391,6 +391,7 @@ "TestAllApps": "Test All Apps", "TestAllClients": "Test All Clients", "TestAllIndexers": "Test All Indexers", + "ThemeHelpText": "Change Prowlarr UI theme, inspired by {0}", "Time": "Time", "Title": "Title", "Today": "Today", diff --git a/src/Prowlarr.Api.V1/Config/UiConfigController.cs b/src/Prowlarr.Api.V1/Config/UiConfigController.cs index 436b5717f..eda73e967 100644 --- a/src/Prowlarr.Api.V1/Config/UiConfigController.cs +++ b/src/Prowlarr.Api.V1/Config/UiConfigController.cs @@ -1,4 +1,8 @@ +using System.Linq; +using System.Reflection; +using Microsoft.AspNetCore.Mvc; using NzbDrone.Core.Configuration; +using NzbDrone.Http.REST.Attributes; using Prowlarr.Http; namespace Prowlarr.Api.V1.Config @@ -6,14 +10,30 @@ namespace Prowlarr.Api.V1.Config [V1ApiController("config/ui")] public class UiConfigController : ConfigController<UiConfigResource> { - public UiConfigController(IConfigService configService) + private readonly IConfigFileProvider _configFileProvider; + + public UiConfigController(IConfigFileProvider configFileProvider, IConfigService configService) : base(configService) { + _configFileProvider = configFileProvider; + } + + [RestPutById] + public override ActionResult<UiConfigResource> SaveConfig(UiConfigResource resource) + { + var dictionary = resource.GetType() + .GetProperties(BindingFlags.Instance | BindingFlags.Public) + .ToDictionary(prop => prop.Name, prop => prop.GetValue(resource, null)); + + _configFileProvider.SaveConfigDictionary(dictionary); + _configService.SaveConfigDictionary(dictionary); + + return Accepted(resource.Id); } protected override UiConfigResource ToResource(IConfigService model) { - return UiConfigResourceMapper.ToResource(model); + return UiConfigResourceMapper.ToResource(_configFileProvider, model); } } } diff --git a/src/Prowlarr.Api.V1/Config/UiConfigResource.cs b/src/Prowlarr.Api.V1/Config/UiConfigResource.cs index d2e9e786b..ae63a6d43 100644 --- a/src/Prowlarr.Api.V1/Config/UiConfigResource.cs +++ b/src/Prowlarr.Api.V1/Config/UiConfigResource.cs @@ -17,11 +17,12 @@ namespace Prowlarr.Api.V1.Config public bool EnableColorImpairedMode { get; set; } public int UILanguage { get; set; } + public string Theme { get; set; } } public static class UiConfigResourceMapper { - public static UiConfigResource ToResource(IConfigService model) + public static UiConfigResource ToResource(IConfigFileProvider config, IConfigService model) { return new UiConfigResource { @@ -34,7 +35,8 @@ namespace Prowlarr.Api.V1.Config ShowRelativeDates = model.ShowRelativeDates, EnableColorImpairedMode = model.EnableColorImpairedMode, - UILanguage = model.UILanguage + UILanguage = model.UILanguage, + Theme = config.Theme }; } } diff --git a/src/Prowlarr.Http/Frontend/InitializeJsController.cs b/src/Prowlarr.Http/Frontend/InitializeJsController.cs index fc3dcf302..c979d7525 100644 --- a/src/Prowlarr.Http/Frontend/InitializeJsController.cs +++ b/src/Prowlarr.Http/Frontend/InitializeJsController.cs @@ -50,6 +50,7 @@ namespace Prowlarr.Http.Frontend builder.AppendLine($" release: '{BuildInfo.Release}',"); builder.AppendLine($" version: '{BuildInfo.Version.ToString()}',"); builder.AppendLine($" instanceName: '{_configFileProvider.InstanceName.ToString()}',"); + builder.AppendLine($" theme: '{_configFileProvider.Theme.ToString()}',"); builder.AppendLine($" branch: '{_configFileProvider.Branch.ToLower()}',"); builder.AppendLine($" analytics: {_analyticsService.IsEnabled.ToString().ToLowerInvariant()},"); builder.AppendLine($" userHash: '{HashUtil.AnonymousToken()}',"); From 2b58f3131eab20800d6feb1e82b81103ad8f733a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 21 Nov 2021 17:00:02 -0600 Subject: [PATCH 0477/2320] New: Move to CSS Variables for Colorings --- frontend/postcss.config.js | 3 +- frontend/src/Components/Alert.css | 24 +-- frontend/src/Components/Card.css | 6 +- frontend/src/Components/Chart/BarChart.js | 7 +- .../src/Components/Chart/DoughnutChart.js | 9 +- .../src/Components/Chart/StackedBarChart.js | 11 +- frontend/src/Components/FieldSet.css | 2 +- .../FileBrowser/FileBrowserModalContent.css | 2 +- .../Filter/Builder/FilterBuilderRow.css | 2 +- .../Builder/FilterBuilderRowValueTag.css | 2 +- .../Filter/CustomFilters/CustomFilter.css | 2 +- .../src/Components/Form/AutoSuggestInput.css | 8 +- frontend/src/Components/Form/CheckInput.css | 32 +-- .../Components/Form/EnhancedSelectInput.css | 14 +- .../Form/EnhancedSelectInputOption.css | 10 +- .../Form/EnhancedSelectInputSelectedValue.css | 2 +- .../src/Components/Form/FormInputGroup.css | 2 +- .../src/Components/Form/FormInputHelpText.css | 10 +- frontend/src/Components/Form/FormLabel.css | 4 +- .../Form/HintedSelectInputOption.css | 2 +- .../Form/HintedSelectInputSelectedValue.css | 2 +- frontend/src/Components/Form/Input.css | 19 +- .../src/Components/Form/KeyValueListInput.css | 4 +- .../Components/Form/KeyValueListInputItem.css | 2 +- frontend/src/Components/Form/TagInput.css | 6 +- frontend/src/Components/Form/TextArea.css | 2 +- frontend/src/Components/Form/TextInput.css | 2 +- frontend/src/Components/Icon.css | 16 +- frontend/src/Components/InfoLabel.css | 6 +- frontend/src/Components/Label.css | 65 +++--- frontend/src/Components/Link/Button.css | 60 +++--- frontend/src/Components/Link/IconButton.css | 4 +- frontend/src/Components/Link/Link.css | 4 +- .../Components/Loading/LoadingIndicator.css | 2 +- frontend/src/Components/Menu/MenuButton.css | 4 +- frontend/src/Components/Menu/MenuContent.css | 2 +- frontend/src/Components/Menu/MenuItem.css | 10 +- .../src/Components/Menu/MenuItemSeparator.css | 2 +- frontend/src/Components/Modal/Modal.css | 2 +- .../src/Components/Modal/ModalContent.css | 4 +- frontend/src/Components/Modal/ModalFooter.css | 2 +- frontend/src/Components/Modal/ModalHeader.css | 2 +- .../Page/Header/IndexerSearchInput.css | 20 +- .../Page/Header/IndexerSearchResult.css | 2 +- .../Header/KeyboardShortcutsModalContent.css | 4 +- .../src/Components/Page/Header/PageHeader.css | 6 +- .../Page/Header/PageHeaderActionsMenu.css | 2 +- frontend/src/Components/Page/LoadingPage.css | 2 + .../src/Components/Page/PageContentFooter.css | 2 +- .../src/Components/Page/PageJumpBarItem.css | 2 +- .../Page/Sidebar/Messages/Message.css | 12 +- .../Components/Page/Sidebar/PageSidebar.css | 6 +- .../Page/Sidebar/PageSidebarItem.css | 12 +- .../Components/Page/Toolbar/PageToolbar.css | 4 +- .../Page/Toolbar/PageToolbarButton.css | 8 +- frontend/src/Components/ProgressBar.css | 24 +-- .../Components/Scroller/OverlayScroller.css | 4 +- .../Table/TableOptions/TableOptionsColumn.css | 2 +- frontend/src/Components/Table/TablePager.css | 4 +- frontend/src/Components/Table/TableRow.css | 2 +- .../src/Components/Table/VirtualTableRow.css | 2 +- frontend/src/Components/Tooltip/Popover.css | 4 +- frontend/src/Components/Tooltip/Tooltip.css | 40 ++-- frontend/src/Helpers/Props/kinds.js | 2 - frontend/src/History/HistoryRowParameter.css | 8 +- .../Delete/DeleteIndexerModalContent.css | 2 +- .../src/Indexer/Index/IndexerIndexFooter.css | 10 +- .../Indexer/Index/Table/IndexerIndexRow.css | 2 +- .../src/Indexer/Index/Table/ProtocolLabel.css | 8 +- frontend/src/Search/QueryParameterModal.css | 4 +- frontend/src/Search/QueryParameterOption.css | 10 +- frontend/src/Search/Table/ProtocolLabel.css | 8 +- frontend/src/Search/Table/SearchIndexRow.css | 2 +- .../src/Settings/AdvancedSettingsButton.css | 6 +- .../Applications/Applications.css | 8 +- .../DownloadClients/DownloadClients.css | 8 +- .../IndexerProxies/IndexerProxies.css | 8 +- .../Notifications/Notifications.css | 8 +- .../src/Settings/Profiles/App/AppProfiles.css | 8 +- frontend/src/Settings/Settings.css | 4 +- .../Tags/Details/TagDetailsModalContent.css | 2 +- frontend/src/Styles/Mixins/scroller.css | 4 +- frontend/src/Styles/Themes/index.js | 4 +- frontend/src/Styles/Themes/light.js | 37 ++-- frontend/src/Styles/Variables/colors.js | 192 ------------------ frontend/src/Styles/scaffolding.css | 2 +- .../System/Events/LogsTableDetailsModal.css | 2 +- frontend/src/System/Events/LogsTableRow.css | 6 +- frontend/src/System/Status/styles.css | 4 +- frontend/src/index.css | 2 +- 90 files changed, 354 insertions(+), 547 deletions(-) delete mode 100644 frontend/src/Styles/Variables/colors.js diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js index 6d15f7369..f657adf28 100644 --- a/frontend/postcss.config.js +++ b/frontend/postcss.config.js @@ -1,7 +1,6 @@ const reload = require('require-nocache')(module); const cssVarsFiles = [ - './src/Styles/Variables/colors', './src/Styles/Variables/dimensions', './src/Styles/Variables/fonts', './src/Styles/Variables/animations', @@ -29,4 +28,4 @@ module.exports = { 'postcss-color-function', 'postcss-nested' ] -}; \ No newline at end of file +}; diff --git a/frontend/src/Components/Alert.css b/frontend/src/Components/Alert.css index 312fbb4f2..135d1ee2b 100644 --- a/frontend/src/Components/Alert.css +++ b/frontend/src/Components/Alert.css @@ -7,25 +7,25 @@ } .danger { - border-color: $alertDangerBorderColor; - background-color: $alertDangerBackgroundColor; - color: $alertDangerColor; + border-color: var(--alertDangerBorderColor); + background-color: var(--alertDangerBackgroundColor); + color: var(--alertDangerColor); } .info { - border-color: $alertInfoBorderColor; - background-color: $alertInfoBackgroundColor; - color: $alertInfoColor; + border-color: var(--alertInfoBorderColor); + background-color: var(--alertInfoBackgroundColor); + color: var(--alertInfoColor); } .success { - border-color: $alertSuccessBorderColor; - background-color: $alertSuccessBackgroundColor; - color: $alertSuccessColor; + border-color: var(--alertSuccessBorderColor); + background-color: var(--alertSuccessBackgroundColor); + color: var(--alertSuccessColor); } .warning { - border-color: $alertWarningBorderColor; - background-color: $alertWarningBackgroundColor; - color: $alertWarningColor; + border-color: var(--alertWarningBorderColor); + background-color: var(--alertWarningBackgroundColor); + color: var(--alertWarningColor); } diff --git a/frontend/src/Components/Card.css b/frontend/src/Components/Card.css index b54bbcdf4..49a9abd76 100644 --- a/frontend/src/Components/Card.css +++ b/frontend/src/Components/Card.css @@ -3,9 +3,9 @@ margin: 10px; padding: 10px; border-radius: 3px; - background-color: $white; - box-shadow: 0 0 10px 1px $cardShadowColor; - color: $defaultColor; + background-color: var(--cardBackgroundColor); + box-shadow: 0 0 10px 1px var(--cardShadowColor); + color: var(--defaultColor); } .underlay { diff --git a/frontend/src/Components/Chart/BarChart.js b/frontend/src/Components/Chart/BarChart.js index f52bd8a94..b9d7f0acc 100644 --- a/frontend/src/Components/Chart/BarChart.js +++ b/frontend/src/Components/Chart/BarChart.js @@ -2,15 +2,16 @@ import Chart from 'chart.js/auto'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { kinds } from 'Helpers/Props'; -import colors from 'Styles/Variables/colors'; function getColors(kind) { + const style = getComputedStyle(document.body); + if (kind === kinds.WARNING) { - return colors.failedColors.reverse(); + return style.getPropertyValue('--failedColors').split(','); } - return colors.chartColors; + return style.getPropertyValue('--chartColors').split(','); } class BarChart extends Component { diff --git a/frontend/src/Components/Chart/DoughnutChart.js b/frontend/src/Components/Chart/DoughnutChart.js index d358b97c2..dd5052e23 100644 --- a/frontend/src/Components/Chart/DoughnutChart.js +++ b/frontend/src/Components/Chart/DoughnutChart.js @@ -1,7 +1,12 @@ import Chart from 'chart.js/auto'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; -import colors from 'Styles/Variables/colors'; + +function getColors(kind) { + + const style = getComputedStyle(document.body); + return style.getPropertyValue('--chartColorsDiversified').split(','); +} class DoughnutChart extends Component { constructor(props) { @@ -29,7 +34,7 @@ class DoughnutChart extends Component { datasets: [{ label: this.props.title, data: this.props.data.map((d) => d.value), - backgroundColor: colors.chartColorsDiversified + backgroundColor: getColors() }] } }); diff --git a/frontend/src/Components/Chart/StackedBarChart.js b/frontend/src/Components/Chart/StackedBarChart.js index 6b5ed083f..d6e4879d2 100644 --- a/frontend/src/Components/Chart/StackedBarChart.js +++ b/frontend/src/Components/Chart/StackedBarChart.js @@ -1,7 +1,12 @@ import Chart from 'chart.js/auto'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; -import colors from 'Styles/Variables/colors'; + +function getColors(index) { + + const style = getComputedStyle(document.body); + return style.getPropertyValue('--chartColorsDiversified').split(',')[index]; +} class StackedBarChart extends Component { constructor(props) { @@ -41,7 +46,7 @@ class StackedBarChart extends Component { return { label: d.label, data: d.data, - backgroundColor: colors.chartColorsDiversified[index] + backgroundColor: getColors(index) }; }) } @@ -54,7 +59,7 @@ class StackedBarChart extends Component { return { label: d.label, data: d.data, - backgroundColor: colors.chartColorsDiversified[index] + backgroundColor: getColors(index) }; }); this.myChart.update(); diff --git a/frontend/src/Components/FieldSet.css b/frontend/src/Components/FieldSet.css index daf3bdf2e..c9a567c0e 100644 --- a/frontend/src/Components/FieldSet.css +++ b/frontend/src/Components/FieldSet.css @@ -13,7 +13,7 @@ width: 100%; border: 0; border-bottom: 1px solid #e5e5e5; - color: #3a3f51; + color: var(--textColor); font-size: 21px; line-height: inherit; } diff --git a/frontend/src/Components/FileBrowser/FileBrowserModalContent.css b/frontend/src/Components/FileBrowser/FileBrowserModalContent.css index 7ddb9e806..db31d6f86 100644 --- a/frontend/src/Components/FileBrowser/FileBrowserModalContent.css +++ b/frontend/src/Components/FileBrowser/FileBrowserModalContent.css @@ -13,7 +13,7 @@ } .faqLink { - color: $alertWarningColor; + color: var(--alertWarningColor); font-weight: bold; } diff --git a/frontend/src/Components/Filter/Builder/FilterBuilderRow.css b/frontend/src/Components/Filter/Builder/FilterBuilderRow.css index c5471b253..bcfc3b04e 100644 --- a/frontend/src/Components/Filter/Builder/FilterBuilderRow.css +++ b/frontend/src/Components/Filter/Builder/FilterBuilderRow.css @@ -3,7 +3,7 @@ margin-bottom: 5px; &:hover { - background-color: $tableRowHoverBackgroundColor; + background-color: var(--tableRowHoverBackgroundColor); } } diff --git a/frontend/src/Components/Filter/Builder/FilterBuilderRowValueTag.css b/frontend/src/Components/Filter/Builder/FilterBuilderRowValueTag.css index 461a54aaa..56294d6f5 100644 --- a/frontend/src/Components/Filter/Builder/FilterBuilderRowValueTag.css +++ b/frontend/src/Components/Filter/Builder/FilterBuilderRowValueTag.css @@ -17,5 +17,5 @@ .or { margin: 0 3px; - color: $themeDarkColor; + color: var(--themeDarkColor); } diff --git a/frontend/src/Components/Filter/CustomFilters/CustomFilter.css b/frontend/src/Components/Filter/CustomFilters/CustomFilter.css index 7acb69dc7..e2b8c72bf 100644 --- a/frontend/src/Components/Filter/CustomFilters/CustomFilter.css +++ b/frontend/src/Components/Filter/CustomFilters/CustomFilter.css @@ -4,7 +4,7 @@ padding: 5px; &:hover { - background-color: $tableRowHoverBackgroundColor; + background-color: var(--tableRowHoverBackgroundColor); } } diff --git a/frontend/src/Components/Form/AutoSuggestInput.css b/frontend/src/Components/Form/AutoSuggestInput.css index 0f3279cb9..7dc416960 100644 --- a/frontend/src/Components/Form/AutoSuggestInput.css +++ b/frontend/src/Components/Form/AutoSuggestInput.css @@ -27,10 +27,10 @@ overflow-y: auto; max-height: 200px; width: 100%; - border: 1px solid $inputBorderColor; + border: 1px solid var(--inputBorderColor); border-radius: 4px; - background-color: $white; - box-shadow: inset 0 1px 1px $inputBoxShadowColor; + background-color: var(--inputBackgroundColor); + box-shadow: inset 0 1px 1px var(--inputBoxShadowColor); } } @@ -46,5 +46,5 @@ } .suggestionHighlighted { - background-color: $menuItemHoverBackgroundColor; + background-color: var(--menuItemHoverBackgroundColor); } diff --git a/frontend/src/Components/Form/CheckInput.css b/frontend/src/Components/Form/CheckInput.css index e0b05eca3..171121482 100644 --- a/frontend/src/Components/Form/CheckInput.css +++ b/frontend/src/Components/Form/CheckInput.css @@ -32,21 +32,21 @@ height: 20px; border: 1px solid #ccc; border-radius: 2px; - background-color: $white; - color: $white; + background-color: var(--white); + color: var(--white); text-align: center; line-height: 20px; } .checkbox:focus + .input { outline: 0; - border-color: $inputFocusBorderColor; - box-shadow: inset 0 1px 1px $inputBoxShadowColor, 0 0 8px $inputFocusBoxShadowColor; + border-color: var(--inputFocusBorderColor); + box-shadow: inset 0 1px 1px var(--inputBoxShadowColor), 0 0 8px var(--inputFocusBoxShadowColor); } .dangerIsChecked { - border-color: $dangerColor; - background-color: $dangerColor; + border-color: var(--dangerColor); + background-color: var(--dangerColor); &.isDisabled { opacity: 0.7; @@ -54,8 +54,8 @@ } .primaryIsChecked { - border-color: $primaryColor; - background-color: $primaryColor; + border-color: var(--primaryColor); + background-color: var(--primaryColor); &.isDisabled { opacity: 0.7; @@ -63,8 +63,8 @@ } .successIsChecked { - border-color: $successColor; - background-color: $successColor; + border-color: var(--successColor); + background-color: var(--successColor); &.isDisabled { opacity: 0.7; @@ -72,8 +72,8 @@ } .warningIsChecked { - border-color: $warningColor; - background-color: $warningColor; + border-color: var(--warningColor); + background-color: var(--warningColor); &.isDisabled { opacity: 0.7; @@ -82,15 +82,15 @@ .isNotChecked { &.isDisabled { - border-color: $disabledCheckInputColor; - background-color: $disabledCheckInputColor; + border-color: var(--disabledCheckInputColor); + background-color: var(--disabledCheckInputColor); opacity: 0.7; } } .isIndeterminate { - border-color: $gray; - background-color: $gray; + border-color: var(--gray); + background-color: var(--gray); } .helpText { diff --git a/frontend/src/Components/Form/EnhancedSelectInput.css b/frontend/src/Components/Form/EnhancedSelectInput.css index f971f6517..cb841eb67 100644 --- a/frontend/src/Components/Form/EnhancedSelectInput.css +++ b/frontend/src/Components/Form/EnhancedSelectInput.css @@ -39,7 +39,7 @@ .dropdownArrowContainerDisabled { composes: dropdownArrowContainer; - color: $disabledInputColor; + color: var(--disabledInputColor); } .optionsContainer { @@ -50,9 +50,9 @@ .options { composes: scroller from '~Components/Scroller/Scroller.css'; - border: 1px solid $inputBorderColor; + border: 1px solid var(--inputBorderColor); border-radius: 4px; - background-color: $white; + background-color: var(--inputBackgroundColor); } .optionsModal { @@ -76,9 +76,9 @@ .optionsModalScroller { composes: scroller from '~Components/Scroller/Scroller.css'; - border: 1px solid $inputBorderColor; + border: 1px solid var(--inputBorderColor); border-radius: 4px; - background-color: $white; + background-color: var(--white); } .loading { @@ -90,7 +90,7 @@ display: flex; justify-content: flex-end; height: 40px; - border-bottom: 1px solid $borderColor; + border-bottom: 1px solid var(--borderColor); } .mobileCloseButton { @@ -100,6 +100,6 @@ line-height: 40px; &:hover { - color: $modalCloseButtonHoverColor; + color: var(--modalCloseButtonHoverColor); } } diff --git a/frontend/src/Components/Form/EnhancedSelectInputOption.css b/frontend/src/Components/Form/EnhancedSelectInputOption.css index f6b6136ae..8dcfa25d5 100644 --- a/frontend/src/Components/Form/EnhancedSelectInputOption.css +++ b/frontend/src/Components/Form/EnhancedSelectInputOption.css @@ -7,7 +7,7 @@ cursor: default; &:hover { - background-color: #f8f8f8; + background-color: var(--inputHoverBackgroundColor); } } @@ -24,17 +24,17 @@ } .isSelected { - background-color: #e2e2e2; + background-color: var(--inputSelectedBackgroundColor); &:hover { - background-color: #e2e2e2; + background-color: var(--inputSelectedBackgroundColor); } &.isMobile { background-color: inherit; .iconContainer { - color: $primaryColor; + color: var(--primaryColor); } } } @@ -49,7 +49,7 @@ .isMobile { height: 50px; - border-bottom: 1px solid $borderColor; + border-bottom: 1px solid var(--borderColor); &:last-child { border: none; diff --git a/frontend/src/Components/Form/EnhancedSelectInputSelectedValue.css b/frontend/src/Components/Form/EnhancedSelectInputSelectedValue.css index 6b8b73af9..908126689 100644 --- a/frontend/src/Components/Form/EnhancedSelectInputSelectedValue.css +++ b/frontend/src/Components/Form/EnhancedSelectInputSelectedValue.css @@ -3,5 +3,5 @@ } .isDisabled { - color: $disabledInputColor; + color: var(--disabledInputColor); } diff --git a/frontend/src/Components/Form/FormInputGroup.css b/frontend/src/Components/Form/FormInputGroup.css index 1a1b104e6..32d91e29b 100644 --- a/frontend/src/Components/Form/FormInputGroup.css +++ b/frontend/src/Components/Form/FormInputGroup.css @@ -40,7 +40,7 @@ } .pendingChangesIcon { - color: $warningColor; + color: var(--warningColor); font-size: 20px; line-height: 35px; } diff --git a/frontend/src/Components/Form/FormInputHelpText.css b/frontend/src/Components/Form/FormInputHelpText.css index 756fd90db..0a6897d27 100644 --- a/frontend/src/Components/Form/FormInputHelpText.css +++ b/frontend/src/Components/Form/FormInputHelpText.css @@ -1,14 +1,14 @@ .helpText { margin-top: 5px; - color: $helpTextColor; + color: var(--helpTextColor); line-height: 20px; } .isError { - color: $dangerColor; + color: var(--dangerColor); .link { - color: $dangerColor; + color: var(--dangerColor); &:hover { color: #e01313; @@ -17,10 +17,10 @@ } .isWarning { - color: $warningColor; + color: var(--warningColor); .link { - color: $warningColor; + color: var(--warningColor); &:hover { color: #e36c00; diff --git a/frontend/src/Components/Form/FormLabel.css b/frontend/src/Components/Form/FormLabel.css index 236f4aab0..074b6091d 100644 --- a/frontend/src/Components/Form/FormLabel.css +++ b/frontend/src/Components/Form/FormLabel.css @@ -7,11 +7,11 @@ } .hasError { - color: $dangerColor; + color: var(--dangerColor); } .isAdvanced { - color: $advancedFormLabelColor; + color: var(--advancedFormLabelColor); } @media only screen and (max-width: $breakpointLarge) { diff --git a/frontend/src/Components/Form/HintedSelectInputOption.css b/frontend/src/Components/Form/HintedSelectInputOption.css index 74d1fb088..74bf6a86e 100644 --- a/frontend/src/Components/Form/HintedSelectInputOption.css +++ b/frontend/src/Components/Form/HintedSelectInputOption.css @@ -18,6 +18,6 @@ @add-mixin truncate; margin-left: 15px; - color: $darkGray; + color: var(--darkGray); font-size: $smallFontSize; } diff --git a/frontend/src/Components/Form/HintedSelectInputSelectedValue.css b/frontend/src/Components/Form/HintedSelectInputSelectedValue.css index a31970a9e..f779b83d7 100644 --- a/frontend/src/Components/Form/HintedSelectInputSelectedValue.css +++ b/frontend/src/Components/Form/HintedSelectInputSelectedValue.css @@ -18,7 +18,7 @@ flex: 1 10 0; margin-left: 15px; - color: $gray; + color: var(--gray); text-align: right; font-size: $smallFontSize; } diff --git a/frontend/src/Components/Form/Input.css b/frontend/src/Components/Form/Input.css index e9ca23d8f..dd9ee888d 100644 --- a/frontend/src/Components/Form/Input.css +++ b/frontend/src/Components/Form/Input.css @@ -2,26 +2,27 @@ padding: 6px 16px; width: 100%; height: 35px; - border: 1px solid $inputBorderColor; + border: 1px solid var(--inputBorderColor); border-radius: 4px; - background-color: $white; - box-shadow: inset 0 1px 1px $inputBoxShadowColor; + background-color: var(--inputBackgroundColor); + box-shadow: inset 0 1px 1px var(--inputBoxShadowColor); + color: var(--textColor); &:focus { outline: 0; - border-color: $inputFocusBorderColor; - box-shadow: inset 0 1px 1px $inputBoxShadowColor, 0 0 8px $inputFocusBoxShadowColor; + border-color: var(--inputFocusBorderColor); + box-shadow: inset 0 1px 1px var(--inputBoxShadowColor), 0 0 8px var(--inputFocusBoxShadowColor); } } .hasError { - border-color: $inputErrorBorderColor; - box-shadow: inset 0 1px 1px $inputBoxShadowColor, 0 0 8px $inputErrorBoxShadowColor; + border-color: var(--inputErrorBorderColor); + box-shadow: inset 0 1px 1px var(--inputBoxShadowColor), 0 0 8px var(--inputErrorBoxShadowColor); } .hasWarning { - border-color: $inputWarningBorderColor; - box-shadow: inset 0 1px 1px $inputBoxShadowColor, 0 0 8px $inputWarningBoxShadowColor; + border-color: var(--inputWarningBorderColor); + box-shadow: inset 0 1px 1px var(--inputBoxShadowColor), 0 0 8px var(--inputWarningBoxShadowColor); } .hasButton { diff --git a/frontend/src/Components/Form/KeyValueListInput.css b/frontend/src/Components/Form/KeyValueListInput.css index 8bf23610b..d86e6a512 100644 --- a/frontend/src/Components/Form/KeyValueListInput.css +++ b/frontend/src/Components/Form/KeyValueListInput.css @@ -7,8 +7,8 @@ &.isFocused { outline: 0; - border-color: $inputFocusBorderColor; - box-shadow: inset 0 1px 1px $inputBoxShadowColor, 0 0 8px $inputFocusBoxShadowColor; + border-color: var(--inputFocusBorderColor); + box-shadow: inset 0 1px 1px var(--inputBoxShadowColor), 0 0 8px var(--inputFocusBoxShadowColor); } } diff --git a/frontend/src/Components/Form/KeyValueListInputItem.css b/frontend/src/Components/Form/KeyValueListInputItem.css index e136823c2..88c5847ee 100644 --- a/frontend/src/Components/Form/KeyValueListInputItem.css +++ b/frontend/src/Components/Form/KeyValueListInputItem.css @@ -1,7 +1,7 @@ .itemContainer { display: flex; margin-bottom: 3px; - border-bottom: 1px solid $inputBorderColor; + border-bottom: 1px solid var(--inputBorderColor); &:last-child { margin-bottom: 0; diff --git a/frontend/src/Components/Form/TagInput.css b/frontend/src/Components/Form/TagInput.css index 1516bfb1d..83ff2a02c 100644 --- a/frontend/src/Components/Form/TagInput.css +++ b/frontend/src/Components/Form/TagInput.css @@ -7,8 +7,8 @@ &.isFocused { outline: 0; - border-color: $inputFocusBorderColor; - box-shadow: inset 0 1px 1px $inputBoxShadowColor, 0 0 8px $inputFocusBoxShadowColor; + border-color: var(--inputFocusBorderColor); + box-shadow: inset 0 1px 1px var(--inputBoxShadowColor), 0 0 8px var(--inputFocusBoxShadowColor); } } @@ -20,4 +20,6 @@ width: 0%; height: 31px; border: none; + background-color: var(--inputBackground); + color: var(--textColor); } diff --git a/frontend/src/Components/Form/TextArea.css b/frontend/src/Components/Form/TextArea.css index 7a4961c07..5f357cef6 100644 --- a/frontend/src/Components/Form/TextArea.css +++ b/frontend/src/Components/Form/TextArea.css @@ -7,7 +7,7 @@ } .readOnly { - background-color: #eee; + background-color: var(--inputReadOnlyBackgroundColor); } .hasError { diff --git a/frontend/src/Components/Form/TextInput.css b/frontend/src/Components/Form/TextInput.css index 80503704d..a3d9692c6 100644 --- a/frontend/src/Components/Form/TextInput.css +++ b/frontend/src/Components/Form/TextInput.css @@ -3,7 +3,7 @@ } .readOnly { - background-color: #eee; + background-color: var(--inputReadOnlyBackgroundColor); } .hasError { diff --git a/frontend/src/Components/Icon.css b/frontend/src/Components/Icon.css index db95e019b..9dbbfef76 100644 --- a/frontend/src/Components/Icon.css +++ b/frontend/src/Components/Icon.css @@ -1,5 +1,5 @@ .danger { - color: $dangerColor; + color: var(--dangerColor); } .default { @@ -7,25 +7,21 @@ } .disabled { - color: $disabledColor; + color: var(--disabledColor); } .info { - color: $infoColor; -} - -.pink { - color: $pink; + color: var(--infoColor); } .success { - color: $successColor; + color: var(--successColor); } .warning { - color: $warningColor; + color: var(--warningColor); } .purple { - color: $purple; + color: var(--purple); } diff --git a/frontend/src/Components/InfoLabel.css b/frontend/src/Components/InfoLabel.css index c75044b66..6a2f5601b 100644 --- a/frontend/src/Components/InfoLabel.css +++ b/frontend/src/Components/InfoLabel.css @@ -1,7 +1,7 @@ .label { display: inline-block; margin: 2px; - color: $white; + color: var(--white); /** text-align: center; **/ white-space: nowrap; line-height: 1; @@ -10,7 +10,7 @@ .title { margin-bottom: 2px; - color: $helpTextColor; + color: var(--helpTextColor); font-size: 10px; } @@ -36,5 +36,5 @@ /** Outline **/ .outline { - background-color: $white; + background-color: var(--white); } diff --git a/frontend/src/Components/Label.css b/frontend/src/Components/Label.css index b54bba63b..84b12552b 100644 --- a/frontend/src/Components/Label.css +++ b/frontend/src/Components/Label.css @@ -3,7 +3,7 @@ margin: 2px; border: 1px solid; border-radius: 2px; - color: $white; + color: var(--white); text-align: center; white-space: nowrap; line-height: 1; @@ -13,86 +13,77 @@ /** Kinds **/ .danger { - border-color: $dangerColor; - background-color: $dangerColor; + border-color: var(--dangerColor); + background-color: var(--dangerColor); &.outline { - color: $dangerColor; + color: var(--dangerColor); } } .default { - border-color: $themeLightColor; - background-color: $themeLightColor; + border-color: var(--themeLightColor); + background-color: var(--themeLightColor); &.outline { - color: $themeLightColor; + color: var(--themeLightColor); } } .disabled { - border-color: $disabledColor; - background-color: $disabledColor; + border-color: var(--disabledColor); + background-color: var(--disabledColor); &.outline { - color: $disabledColor; + color: var(--disabledColor); } } .info { - border-color: $infoColor; - background-color: $infoColor; + border-color: var(--infoColor); + background-color: var(--infoColor); &.outline { - color: $infoColor; + color: var(--infoColor); } } .inverse { - border-color: $lightGray; - background-color: $lightGray; - color: $defaultColor; + border-color: var(--inverseLabelColor); + background-color: var(--inverseLabelColor); + color: var(--inverseLabelTextColor); &.outline { - background-color: $defaultColor !important; - color: $lightGray; + background-color: var(--inverseLabelTextColor) !important; + color: var(--inverseLabelColor); } } .primary { - border-color: $primaryColor; - background-color: $primaryColor; + border-color: var(--primaryColor); + background-color: var(--primaryColor); &.outline { - color: $primaryColor; + color: var(--primaryColor); } } .success { - border-color: $successColor; - background-color: $successColor; + border-color: var(--successColor); + background-color: var(--successColor); color: #eee; &.outline { - color: $successColor; + color: var(--successColor); } } .warning { - border-color: $warningColor; - background-color: $warningColor; + border-color: var(--warningColor); + background-color: var(--warningColor); &.outline { - color: $warningColor; - } -} - -.queue { - border-color: $queueColor; - background-color: $queueColor; - - &.outline { - color: $queueColor; + color: var(--warningColor); } } @@ -117,5 +108,5 @@ /** Outline **/ .outline { - background-color: $white; + background-color: var(--white); } diff --git a/frontend/src/Components/Link/Button.css b/frontend/src/Components/Link/Button.css index d5b7e8200..1ef2eb4b3 100644 --- a/frontend/src/Components/Link/Button.css +++ b/frontend/src/Components/Link/Button.css @@ -19,62 +19,62 @@ } .danger { - border-color: $dangerBorderColor; - background-color: $dangerBackgroundColor; - color: $white; + border-color: var(--dangerBorderColor); + background-color: var(--dangerBackgroundColor); + color: var(--white); &:hover { - border-color: $dangerHoverBorderColor; - background-color: $dangerHoverBackgroundColor; - color: $white; + border-color: var(--dangerHoverBorderColor); + background-color: var(--dangerHoverBackgroundColor); + color: var(--white); } } .default { - border-color: $defaultBorderColor; - background-color: $defaultBackgroundColor; - color: $defaultColor; + border-color: var(--defaultBorderColor); + background-color: var(--defaultButtonBackgroundColor); + color: var(--defaultButtonTextColor); &:hover { - border-color: $defaultHoverBorderColor; - background-color: $defaultHoverBackgroundColor; - color: $defaultColor; + border-color: var(--defaultHoverBorderColor); + background-color: var(--defaultHoverBackgroundColor); + color: var(--defaultButtonTextColor); } } .primary { - border-color: $primaryBorderColor; - background-color: $primaryBackgroundColor; - color: $white; + border-color: var(--primaryBorderColor); + background-color: var(--primaryBackgroundColor); + color: var(--white); &:hover { - border-color: $primaryHoverBorderColor; - background-color: $primaryHoverBackgroundColor; - color: $white; + border-color: var(--primaryHoverBorderColor); + background-color: var(--primaryHoverBackgroundColor); + color: var(--white); } } .success { - border-color: $successBorderColor; - background-color: $successBackgroundColor; - color: $white; + border-color: var(--successBorderColor); + background-color: var(--successBackgroundColor); + color: var(--white); &:hover { - border-color: $successHoverBorderColor; - background-color: $successHoverBackgroundColor; - color: $white; + border-color: var(--successHoverBorderColor); + background-color: var(--successHoverBackgroundColor); + color: var(--white); } } .warning { - border-color: $warningBorderColor; - background-color: $warningBackgroundColor; - color: $white; + border-color: var(--warningBorderColor); + background-color: var(--warningBackgroundColor); + color: var(--white); &:hover { - border-color: $warningHoverBorderColor; - background-color: $warningHoverBackgroundColor; - color: $white; + border-color: var(--warningHoverBorderColor); + background-color: var(--warningHoverBackgroundColor); + color: var(--white); } } diff --git a/frontend/src/Components/Link/IconButton.css b/frontend/src/Components/Link/IconButton.css index 2061243ee..b697e3bd4 100644 --- a/frontend/src/Components/Link/IconButton.css +++ b/frontend/src/Components/Link/IconButton.css @@ -12,10 +12,10 @@ &:hover { border: none; background-color: inherit; - color: $iconButtonHoverColor; + color: var(--iconButtonHoverColor); } &.isDisabled { - color: $iconButtonDisabledColor; + color: var(--iconButtonDisabledColor); } } diff --git a/frontend/src/Components/Link/Link.css b/frontend/src/Components/Link/Link.css index ff0ed8d0c..47b6fb852 100644 --- a/frontend/src/Components/Link/Link.css +++ b/frontend/src/Components/Link/Link.css @@ -15,10 +15,10 @@ } .to { - color: $linkColor; + color: var(--linkColor); &:hover { - color: $linkHoverColor; + color: var(--linkHoverColor); text-decoration: underline; } } diff --git a/frontend/src/Components/Loading/LoadingIndicator.css b/frontend/src/Components/Loading/LoadingIndicator.css index fd224b1d6..8732d786b 100644 --- a/frontend/src/Components/Loading/LoadingIndicator.css +++ b/frontend/src/Components/Loading/LoadingIndicator.css @@ -26,7 +26,7 @@ .ripple { position: absolute; - border: 2px solid #3a3f51; + border: 2px solid var(--themeDarkColor); border-radius: 100%; animation: rippleContainer 1.25s 0s infinite cubic-bezier(0.21, 0.53, 0.56, 0.8); animation-fill-mode: both; diff --git a/frontend/src/Components/Menu/MenuButton.css b/frontend/src/Components/Menu/MenuButton.css index 38812cfb7..ef7a8a5ff 100644 --- a/frontend/src/Components/Menu/MenuButton.css +++ b/frontend/src/Components/Menu/MenuButton.css @@ -10,12 +10,12 @@ } &:hover { - color: $toobarButtonHoverColor; + color: var(--toobarButtonHoverColor); } } .isDisabled { - color: $disabledColor; + color: var(--disabledColor); pointer-events: none; } diff --git a/frontend/src/Components/Menu/MenuContent.css b/frontend/src/Components/Menu/MenuContent.css index b9327fdd7..d6c990131 100644 --- a/frontend/src/Components/Menu/MenuContent.css +++ b/frontend/src/Components/Menu/MenuContent.css @@ -2,7 +2,7 @@ z-index: $popperZIndex; display: flex; flex-direction: column; - background-color: $toolbarMenuItemBackgroundColor; + background-color: var(--toolbarMenuItemBackgroundColor); line-height: 20px; } diff --git a/frontend/src/Components/Menu/MenuItem.css b/frontend/src/Components/Menu/MenuItem.css index 2eb2817af..a14a06014 100644 --- a/frontend/src/Components/Menu/MenuItem.css +++ b/frontend/src/Components/Menu/MenuItem.css @@ -5,19 +5,19 @@ padding: 10px 20px; min-width: 150px; max-width: 250px; - background-color: $toolbarMenuItemBackgroundColor; - color: $menuItemColor; + background-color: var(--toolbarMenuItemBackgroundColor); + color: var(--menuItemColor); line-height: 20px; &:hover, &:focus { - background-color: $toolbarMenuItemHoverBackgroundColor; - color: $menuItemHoverColor; + background-color: var(--toolbarMenuItemHoverBackgroundColor); + color: var(--menuItemHoverColor); text-decoration: none; } } .isDisabled { - color: $disabledColor; + color: var(--disabledColor); pointer-events: none; } diff --git a/frontend/src/Components/Menu/MenuItemSeparator.css b/frontend/src/Components/Menu/MenuItemSeparator.css index e48e7f16f..199b15b56 100644 --- a/frontend/src/Components/Menu/MenuItemSeparator.css +++ b/frontend/src/Components/Menu/MenuItemSeparator.css @@ -2,5 +2,5 @@ overflow: hidden; min-height: 1px; height: 1px; - background-color: $themeDarkColor; + background-color: var(--themeDarkColor); } diff --git a/frontend/src/Components/Modal/Modal.css b/frontend/src/Components/Modal/Modal.css index d7269ea46..33f849945 100644 --- a/frontend/src/Components/Modal/Modal.css +++ b/frontend/src/Components/Modal/Modal.css @@ -12,7 +12,7 @@ justify-content: center; width: 100%; height: 100%; - background-color: $modalBackdropBackgroundColor; + background-color: var(--modalBackdropBackgroundColor); opacity: 1; } diff --git a/frontend/src/Components/Modal/ModalContent.css b/frontend/src/Components/Modal/ModalContent.css index afd798dfa..d7a1212ec 100644 --- a/frontend/src/Components/Modal/ModalContent.css +++ b/frontend/src/Components/Modal/ModalContent.css @@ -4,7 +4,7 @@ flex-direction: column; flex-grow: 1; width: 100%; - background-color: $modalBackgroundColor; + background-color: var(--modalBackgroundColor); } .closeButton { @@ -18,6 +18,6 @@ line-height: 60px; &:hover { - color: $modalCloseButtonHoverColor; + color: var(--modalCloseButtonHoverColor); } } diff --git a/frontend/src/Components/Modal/ModalFooter.css b/frontend/src/Components/Modal/ModalFooter.css index 3b817d2bf..9ce992b2e 100644 --- a/frontend/src/Components/Modal/ModalFooter.css +++ b/frontend/src/Components/Modal/ModalFooter.css @@ -4,7 +4,7 @@ justify-content: flex-end; flex-shrink: 0; padding: 15px 30px; - border-top: 1px solid $borderColor; + border-top: 1px solid var(--borderColor); a, button { diff --git a/frontend/src/Components/Modal/ModalHeader.css b/frontend/src/Components/Modal/ModalHeader.css index eab77a9f8..cd1e54d84 100644 --- a/frontend/src/Components/Modal/ModalHeader.css +++ b/frontend/src/Components/Modal/ModalHeader.css @@ -3,6 +3,6 @@ flex-shrink: 0; padding: 15px 50px 15px 30px; - border-bottom: 1px solid $borderColor; + border-bottom: 1px solid var(--borderColor); font-size: 18px; } diff --git a/frontend/src/Components/Page/Header/IndexerSearchInput.css b/frontend/src/Components/Page/Header/IndexerSearchInput.css index fb1b876e2..5ce43e503 100644 --- a/frontend/src/Components/Page/Header/IndexerSearchInput.css +++ b/frontend/src/Components/Page/Header/IndexerSearchInput.css @@ -12,22 +12,22 @@ .ripple { composes: ripple from '~Components/Loading/LoadingIndicator.css'; - border: 1px solid $toolbarColor; + border: 1px solid var(--toolbarColor); } .input { margin-left: 8px; width: 200px; border: none; - border-bottom: solid 1px $white; + border-bottom: solid 1px var(--white); border-radius: 0; background-color: transparent; box-shadow: none; - color: $white; + color: var(--white); transition: border 0.3s ease-out; &::placeholder { - color: $white; + color: var(--white); transition: color 0.3s ease-out; } @@ -60,13 +60,13 @@ overflow-y: auto; min-width: 100%; max-height: 230px; - border: 1px solid $themeDarkColor; + border: 1px solid var(--themeDarkColor); border-radius: 4px; border-top-left-radius: 0; border-top-right-radius: 0; - background-color: $themeDarkColor; - box-shadow: inset 0 1px 1px $inputBoxShadowColor; - color: $menuItemColor; + background-color: var(--themeDarkColor); + box-shadow: inset 0 1px 1px var(--inputBoxShadowColor); + color: var(--menuItemColor); } } @@ -82,12 +82,12 @@ } .highlighted { - background-color: $themeLightColor; + background-color: var(--themeLightColor); } .sectionTitle { padding: 5px 8px; - color: $disabledColor; + color: var(--disabledColor); } .addNewMovieSuggestion { diff --git a/frontend/src/Components/Page/Header/IndexerSearchResult.css b/frontend/src/Components/Page/Header/IndexerSearchResult.css index 29edc382b..5a5343633 100644 --- a/frontend/src/Components/Page/Header/IndexerSearchResult.css +++ b/frontend/src/Components/Page/Header/IndexerSearchResult.css @@ -21,7 +21,7 @@ .alternateTitle { composes: title; - color: $disabledColor; + color: var(--disabledColor); font-size: $smallFontSize; } diff --git a/frontend/src/Components/Page/Header/KeyboardShortcutsModalContent.css b/frontend/src/Components/Page/Header/KeyboardShortcutsModalContent.css index 4425e0e0d..e8a2b0ce2 100644 --- a/frontend/src/Components/Page/Header/KeyboardShortcutsModalContent.css +++ b/frontend/src/Components/Page/Header/KeyboardShortcutsModalContent.css @@ -8,8 +8,8 @@ .key { padding: 2px 4px; border-radius: 3px; - background-color: $defaultColor; + background-color: var(--defaultColor); box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25); - color: $white; + color: var(--white); font-size: 16px; } diff --git a/frontend/src/Components/Page/Header/PageHeader.css b/frontend/src/Components/Page/Header/PageHeader.css index 36a5847c8..b5830594b 100644 --- a/frontend/src/Components/Page/Header/PageHeader.css +++ b/frontend/src/Components/Page/Header/PageHeader.css @@ -4,9 +4,9 @@ align-items: center; flex: 0 0 auto; height: $headerHeight; - background-color: $prowlarrOrange; + background-color: var(--pageHeaderBackgroundColor); box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); - color: $white; + color: var(--white); } .logoContainer { @@ -80,7 +80,7 @@ align-items: center; justify-content: center; width: 30px; - color: $themeRed; + color: var(--themeRed); text-align: center; line-height: 60px; diff --git a/frontend/src/Components/Page/Header/PageHeaderActionsMenu.css b/frontend/src/Components/Page/Header/PageHeaderActionsMenu.css index d2cece6e5..26a5d37da 100644 --- a/frontend/src/Components/Page/Header/PageHeaderActionsMenu.css +++ b/frontend/src/Components/Page/Header/PageHeaderActionsMenu.css @@ -5,7 +5,7 @@ text-align: center; &:hover { - color: $toobarButtonHoverColor; + color: var(--toobarButtonHoverColor); } } diff --git a/frontend/src/Components/Page/LoadingPage.css b/frontend/src/Components/Page/LoadingPage.css index 337f77f1a..8683ed41e 100644 --- a/frontend/src/Components/Page/LoadingPage.css +++ b/frontend/src/Components/Page/LoadingPage.css @@ -1,5 +1,7 @@ .page { composes: page from '~./Page.css'; + + background-color: var(--pageBackground); } .logoFull { diff --git a/frontend/src/Components/Page/PageContentFooter.css b/frontend/src/Components/Page/PageContentFooter.css index 74bdb3811..cd942ea7d 100644 --- a/frontend/src/Components/Page/PageContentFooter.css +++ b/frontend/src/Components/Page/PageContentFooter.css @@ -2,7 +2,7 @@ display: flex; flex: 0 0 auto; padding: 20px; - background-color: #f1f1f1; + background-color: var(--pageFooterBackground); } @media only screen and (max-width: $breakpointSmall) { diff --git a/frontend/src/Components/Page/PageJumpBarItem.css b/frontend/src/Components/Page/PageJumpBarItem.css index f1a0c3699..235562a2e 100644 --- a/frontend/src/Components/Page/PageJumpBarItem.css +++ b/frontend/src/Components/Page/PageJumpBarItem.css @@ -1,6 +1,6 @@ .jumpBarItem { flex: 1 1 $jumpBarItemHeight; - border-bottom: 1px solid $borderColor; + border-bottom: 1px solid var(--borderColor); text-align: center; font-weight: bold; diff --git a/frontend/src/Components/Page/Sidebar/Messages/Message.css b/frontend/src/Components/Page/Sidebar/Messages/Message.css index 7d53adb69..d1d94ce08 100644 --- a/frontend/src/Components/Page/Sidebar/Messages/Message.css +++ b/frontend/src/Components/Page/Sidebar/Messages/Message.css @@ -1,6 +1,6 @@ .message { display: flex; - border-left: 3px solid $infoColor; + border-left: 3px solid var(--infoColor); } .iconContainer, @@ -9,7 +9,7 @@ justify-content: center; flex-direction: column; padding: 2px 0; - color: $sidebarColor; + color: var(--sidebarColor); } .iconContainer { @@ -26,17 +26,17 @@ /* Types */ .error { - border-left-color: $dangerColor; + border-left-color: var(--dangerColor); } .info { - border-left-color: $infoColor; + border-left-color: var(--infoColor); } .success { - border-left-color: $successColor; + border-left-color: var(--successColor); } .warning { - border-left-color: $warningColor; + border-left-color: var(--warningColor); } diff --git a/frontend/src/Components/Page/Sidebar/PageSidebar.css b/frontend/src/Components/Page/Sidebar/PageSidebar.css index 3f2abeee7..ee44c0407 100644 --- a/frontend/src/Components/Page/Sidebar/PageSidebar.css +++ b/frontend/src/Components/Page/Sidebar/PageSidebar.css @@ -2,7 +2,7 @@ flex: 0 0 $sidebarWidth; overflow: hidden; width: $sidebarWidth; - background-color: $sidebarBackgroundColor; + background-color: var(--sidebarBackgroundColor); transition: transform 300ms ease-in-out; transform: translateX(0); } @@ -11,8 +11,8 @@ display: flex; flex-direction: column; overflow: hidden; - background-color: $sidebarBackgroundColor; - color: $white; + background-color: var(--sidebarBackgroundColor); + color: var(--white); } @media only screen and (max-width: $breakpointSmall) { diff --git a/frontend/src/Components/Page/Sidebar/PageSidebarItem.css b/frontend/src/Components/Page/Sidebar/PageSidebarItem.css index dac40927f..5e3e3b52c 100644 --- a/frontend/src/Components/Page/Sidebar/PageSidebarItem.css +++ b/frontend/src/Components/Page/Sidebar/PageSidebarItem.css @@ -1,21 +1,21 @@ .item { border-left: 3px solid transparent; - color: $sidebarColor; + color: var(--sidebarColor); transition: border-left 0.3s ease-in-out; } .isActiveItem { - border-left: 3px solid $themeBlue; + border-left: 3px solid var(--themeBlue); } .link { display: block; padding: 12px 24px; - color: $sidebarColor; + color: var(--sidebarColor); &:hover, &:focus { - color: $themeBlue; + color: var(--themeBlue); text-decoration: none; } } @@ -27,11 +27,11 @@ } .isActiveLink { - color: $themeBlue; + color: var(--themeBlue); } .isActiveParentLink { - background-color: $sidebarActiveBackgroundColor; + background-color: var(--sidebarActiveBackgroundColor); } .iconContainer { diff --git a/frontend/src/Components/Page/Toolbar/PageToolbar.css b/frontend/src/Components/Page/Toolbar/PageToolbar.css index e040bc884..d7fb0d5d8 100644 --- a/frontend/src/Components/Page/Toolbar/PageToolbar.css +++ b/frontend/src/Components/Page/Toolbar/PageToolbar.css @@ -4,8 +4,8 @@ flex: 0 0 auto; padding: 0 20px; height: $toolbarHeight; - background-color: $toolbarBackgroundColor; - color: $toolbarColor; + background-color: var(--toolbarBackgroundColor); + color: var(--toolbarColor); line-height: 60px; } diff --git a/frontend/src/Components/Page/Toolbar/PageToolbarButton.css b/frontend/src/Components/Page/Toolbar/PageToolbarButton.css index e729ed000..0b6918296 100644 --- a/frontend/src/Components/Page/Toolbar/PageToolbarButton.css +++ b/frontend/src/Components/Page/Toolbar/PageToolbarButton.css @@ -6,16 +6,16 @@ text-align: center; &:hover { - color: $toobarButtonHoverColor; + color: var(--toobarButtonHoverColor); } &.isDisabled { - color: $disabledColor; + color: var(--disabledColor); } } .isDisabled { - color: $disabledColor; + color: var(--disabledColor); } .labelContainer { @@ -27,7 +27,7 @@ .label { padding: 0 3px; - color: $toolbarLabelColor; + color: var(--toolbarLabelColor); font-size: $extraSmallFontSize; line-height: calc($extraSmallFontSize + 1px); } diff --git a/frontend/src/Components/ProgressBar.css b/frontend/src/Components/ProgressBar.css index f95514478..81510545a 100644 --- a/frontend/src/Components/ProgressBar.css +++ b/frontend/src/Components/ProgressBar.css @@ -14,13 +14,13 @@ width: 0; height: 100%; box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); - color: $white; + color: var(--white); transition: width 0.6s ease; } .frontTextContainer { z-index: 1; - color: $white; + color: var(--white); } .backTextContainer, @@ -42,39 +42,35 @@ } .primary { - background-color: $primaryColor; + background-color: var(--primaryColor); } .danger { - background-color: $dangerColor; + background-color: var(--dangerColor); &:global(.colorImpaired) { - background: repeating-linear-gradient(90deg, color($dangerColor shade(5%)), color($dangerColor shade(5%)) 5px, color($dangerColor shade(15%)) 5px, color($dangerColor shade(15%)) 10px); + background: repeating-linear-gradient(90deg, color(var(--dangerColor) shade(5%)), color(var(--dangerColor) shade(5%)) 5px, color(var(--dangerColor) shade(15%)) 5px, color(var(--dangerColor) shade(15%)) 10px); } } .success { - background-color: $successColor; + background-color: var(--successColor); } .purple { - background-color: $purple; + background-color: var(--purple); } .warning { - background-color: $warningColor; + background-color: var(--warningColor); &:global(.colorImpaired) { - background: repeating-linear-gradient(45deg, $warningColor, $warningColor 5px, color($warningColor tint(15%)) 5px, color($warningColor tint(15%)) 10px); + background: repeating-linear-gradient(45deg, var(--warningColor), var(--warningColor) 5px, color(var(--warningColor) tint(15%)) 5px, color(var(--warningColor) tint(15%)) 10px); } } .info { - background-color: $infoColor; -} - -.queue { - background-color: $queueColor; + background-color: var(--infoColor); } .small { diff --git a/frontend/src/Components/Scroller/OverlayScroller.css b/frontend/src/Components/Scroller/OverlayScroller.css index 0e8a2ffd7..c1836d365 100644 --- a/frontend/src/Components/Scroller/OverlayScroller.css +++ b/frontend/src/Components/Scroller/OverlayScroller.css @@ -10,10 +10,10 @@ min-height: 100px; border: 1px solid transparent; border-radius: 5px; - background-color: $scrollbarBackgroundColor; + background-color: var(--scrollbarBackgroundColor); background-clip: padding-box; &:hover { - background-color: $scrollbarHoverBackgroundColor; + background-color: var(--scrollbarHoverBackgroundColor); } } diff --git a/frontend/src/Components/Table/TableOptions/TableOptionsColumn.css b/frontend/src/Components/Table/TableOptions/TableOptionsColumn.css index 204773c3d..ef3d9b062 100644 --- a/frontend/src/Components/Table/TableOptions/TableOptionsColumn.css +++ b/frontend/src/Components/Table/TableOptions/TableOptionsColumn.css @@ -4,7 +4,7 @@ width: 100%; border: 1px solid #aaa; border-radius: 4px; - background: #fafafa; + background: var(--inputBackgroundColor); } .checkContainer { diff --git a/frontend/src/Components/Table/TablePager.css b/frontend/src/Components/Table/TablePager.css index 19f5a8f6b..d73a0d0c0 100644 --- a/frontend/src/Components/Table/TablePager.css +++ b/frontend/src/Components/Table/TablePager.css @@ -46,11 +46,11 @@ } .records { - color: $disabledColor; + color: var(--disabledColor); } .disabledPageButton { - color: $disabledColor; + color: var(--disabledColor); } .pageSelect { diff --git a/frontend/src/Components/Table/TableRow.css b/frontend/src/Components/Table/TableRow.css index dcc6ad8cf..df297a5fe 100644 --- a/frontend/src/Components/Table/TableRow.css +++ b/frontend/src/Components/Table/TableRow.css @@ -2,6 +2,6 @@ transition: background-color 500ms; &:hover { - background-color: $tableRowHoverBackgroundColor; + background-color: var(--tableRowHoverBackgroundColor); } } diff --git a/frontend/src/Components/Table/VirtualTableRow.css b/frontend/src/Components/Table/VirtualTableRow.css index f4c825b64..fcae53bf6 100644 --- a/frontend/src/Components/Table/VirtualTableRow.css +++ b/frontend/src/Components/Table/VirtualTableRow.css @@ -3,7 +3,7 @@ transition: background-color 500ms; &:hover { - background-color: #fafbfc; + background-color: var(--tableRowHoverBackgroundColor); } } diff --git a/frontend/src/Components/Tooltip/Popover.css b/frontend/src/Components/Tooltip/Popover.css index 7b0592844..d392bab46 100644 --- a/frontend/src/Components/Tooltip/Popover.css +++ b/frontend/src/Components/Tooltip/Popover.css @@ -1,7 +1,7 @@ .title { padding: 10px 20px; - border-bottom: 1px solid $popoverTitleBorderColor; - background-color: $popoverTitleBackgroundColor; + border-bottom: 1px solid var(--popoverTitleBorderColor); + background-color: var(--popoverTitleBackgroundColor); font-size: 16px; } diff --git a/frontend/src/Components/Tooltip/Tooltip.css b/frontend/src/Components/Tooltip/Tooltip.css index c5ddc7272..82c80752a 100644 --- a/frontend/src/Components/Tooltip/Tooltip.css +++ b/frontend/src/Components/Tooltip/Tooltip.css @@ -7,13 +7,13 @@ position: relative; &.default { - background-color: $white; - box-shadow: 0 5px 10px $popoverShadowColor; + background-color: var(--white); + box-shadow: 0 5px 10px var(--popoverShadowColor); } &.inverse { - background-color: $themeDarkColor; - box-shadow: 0 5px 10px $popoverShadowInverseColor; + background-color: var(--themeDarkColor); + box-shadow: 0 5px 10px var(--popoverShadowInverseColor); } } @@ -49,20 +49,20 @@ content: ' '; &.default { - border-top-color: $popoverArrowBorderColor; + border-top-color: var(--popoverArrowBorderColor); } &.inverse { - border-top-color: $popoverArrowBorderInverseColor; + border-top-color: var(--popoverArrowBorderInverseColor); } } &.default { - border-top-color: $popoverArrowBorderColor; + border-top-color: var(--popoverArrowBorderColor); } &.inverse { - border-top-color: $popoverArrowBorderInverseColor; + border-top-color: var(--popoverArrowBorderInverseColor); } } @@ -78,20 +78,20 @@ content: ' '; &.default { - border-right-color: $popoverArrowBorderColor; + border-right-color: var(--popoverArrowBorderColor); } &.inverse { - border-right-color: $popoverArrowBorderInverseColor; + border-right-color: var(--popoverArrowBorderInverseColor); } } &.default { - border-right-color: $popoverArrowBorderColor; + border-right-color: var(--popoverArrowBorderColor); } &.inverse { - border-right-color: $popoverArrowBorderInverseColor; + border-right-color: var(--popoverArrowBorderInverseColor); } } @@ -107,20 +107,20 @@ content: ' '; &.default { - border-bottom-color: $popoverArrowBorderColor; + border-bottom-color: var(--popoverArrowBorderColor); } &.inverse { - border-bottom-color: $popoverArrowBorderInverseColor; + border-bottom-color: var(--popoverArrowBorderInverseColor); } } &.default { - border-bottom-color: $popoverArrowBorderColor; + border-bottom-color: var(--popoverArrowBorderColor); } &.inverse { - border-bottom-color: $popoverArrowBorderInverseColor; + border-bottom-color: var(--popoverArrowBorderInverseColor); } } @@ -136,20 +136,20 @@ content: ' '; &.default { - border-left-color: $popoverArrowBorderColor; + border-left-color: var(--popoverArrowBorderColor); } &.inverse { - border-left-color: $popoverArrowBorderInverseColor; + border-left-color: var(--popoverArrowBorderInverseColor); } } &.default { - border-left-color: $popoverArrowBorderColor; + border-left-color: var(--popoverArrowBorderColor); } &.inverse { - border-left-color: $popoverArrowBorderInverseColor; + border-left-color: var(--popoverArrowBorderInverseColor); } } diff --git a/frontend/src/Helpers/Props/kinds.js b/frontend/src/Helpers/Props/kinds.js index d7d61c9f4..b0f5ac87f 100644 --- a/frontend/src/Helpers/Props/kinds.js +++ b/frontend/src/Helpers/Props/kinds.js @@ -3,7 +3,6 @@ export const DEFAULT = 'default'; export const DISABLED = 'disabled'; export const INFO = 'info'; export const INVERSE = 'inverse'; -export const PINK = 'pink'; export const PRIMARY = 'primary'; export const PURPLE = 'purple'; export const SUCCESS = 'success'; @@ -16,7 +15,6 @@ export const all = [ DISABLED, INFO, INVERSE, - PINK, PRIMARY, PURPLE, SUCCESS, diff --git a/frontend/src/History/HistoryRowParameter.css b/frontend/src/History/HistoryRowParameter.css index 9418eccef..5262769e7 100644 --- a/frontend/src/History/HistoryRowParameter.css +++ b/frontend/src/History/HistoryRowParameter.css @@ -3,9 +3,9 @@ align-items: stretch; overflow: hidden; margin: 2px 4px; - border: 1px solid $borderColor; + border: 1px solid var(--borderColor); border-radius: 4px; - background-color: #eee; + background-color: var(--defaultHoverBackgroundColor); cursor: default; } @@ -16,7 +16,7 @@ .value { padding: 0 4px; - background-color: $white; - color: $defaultColor; + background-color: var(--defaultButtonBackgroundColor); + color: var(--defaultColor); white-space: nowrap; } diff --git a/frontend/src/Indexer/Editor/Delete/DeleteIndexerModalContent.css b/frontend/src/Indexer/Editor/Delete/DeleteIndexerModalContent.css index 950fdc27d..02a0514be 100644 --- a/frontend/src/Indexer/Editor/Delete/DeleteIndexerModalContent.css +++ b/frontend/src/Indexer/Editor/Delete/DeleteIndexerModalContent.css @@ -9,5 +9,5 @@ .path { margin-left: 5px; - color: $dangerColor; + color: var(--dangerColor); } diff --git a/frontend/src/Indexer/Index/IndexerIndexFooter.css b/frontend/src/Indexer/Index/IndexerIndexFooter.css index ee77a0480..d9da8112e 100644 --- a/frontend/src/Indexer/Index/IndexerIndexFooter.css +++ b/frontend/src/Indexer/Index/IndexerIndexFooter.css @@ -21,28 +21,28 @@ .disabled { composes: legendItemColor; - background-color: $darkGray; + background-color: var(--darkGray); } .enabled { composes: legendItemColor; - background-color: $successColor; + background-color: var(--successColor); } .redirected { composes: legendItemColor; - background-color: $infoColor; + background-color: var(--infoColor); } .error { composes: legendItemColor; - background-color: $dangerColor; + background-color: var(--dangerColor); &:global(.colorImpaired) { - background: repeating-linear-gradient(90deg, color($dangerColor shade(5%)), color($dangerColor shade(5%)) 5px, color($dangerColor shade(15%)) 5px, color($dangerColor shade(15%)) 10px); + background: repeating-linear-gradient(90deg, color(var(--dangerColor) shade(5%)), color(var(--dangerColor) shade(5%)) 5px, color(var(--dangerColor) shade(15%)) 5px, color(var(--dangerColor) shade(15%)) 10px); } } diff --git a/frontend/src/Indexer/Index/Table/IndexerIndexRow.css b/frontend/src/Indexer/Index/Table/IndexerIndexRow.css index 985411c04..308b87cc7 100644 --- a/frontend/src/Indexer/Index/Table/IndexerIndexRow.css +++ b/frontend/src/Indexer/Index/Table/IndexerIndexRow.css @@ -65,5 +65,5 @@ .externalLink { composes: link from '~Components/Link/Link.css'; - color: $textColor; + color: var(--textColor); } diff --git a/frontend/src/Indexer/Index/Table/ProtocolLabel.css b/frontend/src/Indexer/Index/Table/ProtocolLabel.css index 259fd5c65..110c7e01c 100644 --- a/frontend/src/Indexer/Index/Table/ProtocolLabel.css +++ b/frontend/src/Indexer/Index/Table/ProtocolLabel.css @@ -1,13 +1,13 @@ .torrent { composes: label from '~Components/Label.css'; - border-color: $torrentColor; - background-color: $torrentColor; + border-color: var(--torrentColor); + background-color: var(--torrentColor); } .usenet { composes: label from '~Components/Label.css'; - border-color: $usenetColor; - background-color: $usenetColor; + border-color: var(--usenetColor); + background-color: var(--usenetColor); } diff --git a/frontend/src/Search/QueryParameterModal.css b/frontend/src/Search/QueryParameterModal.css index 66e9bd73a..f65bed4df 100644 --- a/frontend/src/Search/QueryParameterModal.css +++ b/frontend/src/Search/QueryParameterModal.css @@ -19,7 +19,7 @@ .footNote { display: flex; - color: $helpTextColor; + color: var(--helpTextColor); .icon { margin-top: 3px; @@ -29,7 +29,7 @@ code { padding: 0 1px; - border: 1px solid $borderColor; + border: 1px solid var(--borderColor); background-color: #f7f7f7; } } diff --git a/frontend/src/Search/QueryParameterOption.css b/frontend/src/Search/QueryParameterOption.css index cdfb186db..022abda1f 100644 --- a/frontend/src/Search/QueryParameterOption.css +++ b/frontend/src/Search/QueryParameterOption.css @@ -3,15 +3,15 @@ align-items: stretch; flex-wrap: wrap; margin: 3px; - border: 1px solid $borderColor; + border: 1px solid var(--borderColor); &:hover { .token { - background-color: #ddd; + background-color: rgba(0, 0, 0, 0.01); } .example { - background-color: #ccc; + background-color: rgba(0, 0, 0, 0.01); } } } @@ -27,7 +27,7 @@ .token { flex: 0 0 50%; padding: 6px 16px; - background-color: #eee; + background-color: var(--defaultButtonBackgroundColor); font-family: $monoSpaceFontFamily; } @@ -37,7 +37,7 @@ justify-content: space-between; flex: 0 0 50%; padding: 6px 16px; - background-color: #ddd; + background-color: var(--defaultHoverBackgroundColor); .footNote { padding: 2px; diff --git a/frontend/src/Search/Table/ProtocolLabel.css b/frontend/src/Search/Table/ProtocolLabel.css index 259fd5c65..110c7e01c 100644 --- a/frontend/src/Search/Table/ProtocolLabel.css +++ b/frontend/src/Search/Table/ProtocolLabel.css @@ -1,13 +1,13 @@ .torrent { composes: label from '~Components/Label.css'; - border-color: $torrentColor; - background-color: $torrentColor; + border-color: var(--torrentColor); + background-color: var(--torrentColor); } .usenet { composes: label from '~Components/Label.css'; - border-color: $usenetColor; - background-color: $usenetColor; + border-color: var(--usenetColor); + background-color: var(--usenetColor); } diff --git a/frontend/src/Search/Table/SearchIndexRow.css b/frontend/src/Search/Table/SearchIndexRow.css index 205ed42df..8f676213c 100644 --- a/frontend/src/Search/Table/SearchIndexRow.css +++ b/frontend/src/Search/Table/SearchIndexRow.css @@ -58,7 +58,7 @@ margin: 0 2px; width: 22px; - color: $textColor; + color: var(--textColor); } .externalLinks { diff --git a/frontend/src/Settings/AdvancedSettingsButton.css b/frontend/src/Settings/AdvancedSettingsButton.css index 5f0d3b9f2..f08bdc017 100644 --- a/frontend/src/Settings/AdvancedSettingsButton.css +++ b/frontend/src/Settings/AdvancedSettingsButton.css @@ -19,13 +19,13 @@ } .indicatorBackground { - color: $themeDarkColor; + color: var(--themeDarkColor); } .enabled { - color: $successColor; + color: var(--successColor); } .disabled { - color: $dangerColor; + color: var(--dangerColor); } diff --git a/frontend/src/Settings/Applications/Applications/Applications.css b/frontend/src/Settings/Applications/Applications/Applications.css index bd7348438..960537063 100644 --- a/frontend/src/Settings/Applications/Applications/Applications.css +++ b/frontend/src/Settings/Applications/Applications/Applications.css @@ -6,15 +6,15 @@ .addApplication { composes: application from '~./Application.css'; - background-color: $cardAlternateBackgroundColor; - color: $gray; + background-color: var(--cardAlternateBackgroundColor); + color: var(--gray); text-align: center; } .center { display: inline-block; padding: 5px 20px 0; - border: 1px solid $borderColor; + border: 1px solid var(--borderColor); border-radius: 4px; - background-color: $white; + background-color: var(--cardCenterBackgroundColor); } diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/DownloadClients.css b/frontend/src/Settings/DownloadClients/DownloadClients/DownloadClients.css index 81b4f1510..5f650aaf9 100644 --- a/frontend/src/Settings/DownloadClients/DownloadClients/DownloadClients.css +++ b/frontend/src/Settings/DownloadClients/DownloadClients/DownloadClients.css @@ -6,15 +6,15 @@ .addDownloadClient { composes: downloadClient from '~./DownloadClient.css'; - background-color: $cardAlternateBackgroundColor; - color: $gray; + background-color: var(--cardAlternateBackgroundColor); + color: var(--gray); text-align: center; } .center { display: inline-block; padding: 5px 20px 0; - border: 1px solid $borderColor; + border: 1px solid var(--borderColor); border-radius: 4px; - background-color: $white; + background-color: var(--cardCenterBackgroundColor); } diff --git a/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.css b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.css index 4a80c6128..fcfca425f 100644 --- a/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.css +++ b/frontend/src/Settings/Indexers/IndexerProxies/IndexerProxies.css @@ -6,15 +6,15 @@ .addIndexerProxy { composes: indexerProxy from '~./IndexerProxy.css'; - background-color: $cardAlternateBackgroundColor; - color: $gray; + background-color: var(--cardAlternateBackgroundColor); + color: var(--gray); text-align: center; } .center { display: inline-block; padding: 5px 20px 0; - border: 1px solid $borderColor; + border: 1px solid var(--borderColor); border-radius: 4px; - background-color: $white; + background-color: var(--cardCenterBackgroundColor); } diff --git a/frontend/src/Settings/Notifications/Notifications/Notifications.css b/frontend/src/Settings/Notifications/Notifications/Notifications.css index 11ea6e11f..986226ad8 100644 --- a/frontend/src/Settings/Notifications/Notifications/Notifications.css +++ b/frontend/src/Settings/Notifications/Notifications/Notifications.css @@ -6,15 +6,15 @@ .addNotification { composes: notification from '~./Notification.css'; - background-color: $cardAlternateBackgroundColor; - color: $gray; + background-color: var(--cardAlternateBackgroundColor); + color: var(--gray); text-align: center; } .center { display: inline-block; padding: 5px 20px 0; - border: 1px solid $borderColor; + border: 1px solid var(--borderColor); border-radius: 4px; - background-color: $white; + background-color: var(--cardCenterBackgroundColor); } diff --git a/frontend/src/Settings/Profiles/App/AppProfiles.css b/frontend/src/Settings/Profiles/App/AppProfiles.css index 7d7e52246..8a03c273e 100644 --- a/frontend/src/Settings/Profiles/App/AppProfiles.css +++ b/frontend/src/Settings/Profiles/App/AppProfiles.css @@ -6,8 +6,8 @@ .addAppProfile { composes: appProfile from '~./AppProfile.css'; - background-color: $cardAlternateBackgroundColor; - color: $gray; + background-color: var(--cardAlternateBackgroundColor); + color: var(--gray); text-align: center; font-size: 45px; } @@ -15,7 +15,7 @@ .center { display: inline-block; padding: 5px 20px 0; - border: 1px solid $borderColor; + border: 1px solid var(--borderColor); border-radius: 4px; - background-color: $white; + background-color: var(--cardCenterBackgroundColor); } diff --git a/frontend/src/Settings/Settings.css b/frontend/src/Settings/Settings.css index 38e88e67f..ef69e9674 100644 --- a/frontend/src/Settings/Settings.css +++ b/frontend/src/Settings/Settings.css @@ -2,7 +2,7 @@ composes: link from '~Components/Link/Link.css'; border-bottom: 1px solid #e5e5e5; - color: #3a3f51; + color: var(--textColor); font-size: 21px; &:hover { @@ -14,5 +14,5 @@ .summary { margin-top: 10px; margin-bottom: 30px; - color: $dimColor; + color: var(--helpTextColor); } diff --git a/frontend/src/Settings/Tags/Details/TagDetailsModalContent.css b/frontend/src/Settings/Tags/Details/TagDetailsModalContent.css index d11136863..75b157063 100644 --- a/frontend/src/Settings/Tags/Details/TagDetailsModalContent.css +++ b/frontend/src/Settings/Tags/Details/TagDetailsModalContent.css @@ -10,7 +10,7 @@ .restriction { margin-bottom: 5px; padding-bottom: 5px; - border-bottom: 1px solid $borderColor; + border-bottom: 1px solid var(--borderColor); &:last-child { margin: 0; diff --git a/frontend/src/Styles/Mixins/scroller.css b/frontend/src/Styles/Mixins/scroller.css index 7a296c27f..09d26d083 100644 --- a/frontend/src/Styles/Mixins/scroller.css +++ b/frontend/src/Styles/Mixins/scroller.css @@ -16,11 +16,11 @@ min-height: 100px; border: 1px solid transparent; border-radius: 5px; - background-color: $scrollbarBackgroundColor; + background-color: var(--scrollbarBackgroundColor); background-clip: padding-box; &:hover { - background-color: $scrollbarHoverBackgroundColor; + background-color: var(--scrollbarHoverBackgroundColor); } } } diff --git a/frontend/src/Styles/Themes/index.js b/frontend/src/Styles/Themes/index.js index 9e5cacb1b..02068cc4c 100644 --- a/frontend/src/Styles/Themes/index.js +++ b/frontend/src/Styles/Themes/index.js @@ -1,5 +1,7 @@ +import * as dark from './dark'; import * as light from './light'; export default { - light + light, + dark }; diff --git a/frontend/src/Styles/Themes/light.js b/frontend/src/Styles/Themes/light.js index b5fd0433f..e48bcd40c 100644 --- a/frontend/src/Styles/Themes/light.js +++ b/frontend/src/Styles/Themes/light.js @@ -7,22 +7,17 @@ module.exports = { dimColor: '#555', black: '#000', white: '#fff', - offWhite: '#f5f7fa', primaryColor: '#5d9cec', selectedColor: '#f9be03', successColor: '#27c24c', dangerColor: '#f05050', warningColor: '#ffa500', infoColor: '#5d9cec', - queueColor: '#7a43b6', purple: '#7a43b6', - pink: '#ff69b4', prowlarrOrange, helpTextColor: '#909293', darkGray: '#888', gray: '#adadad', - lightGray: '#ddd', - disabledInputColor: '#808080', // Theme Colors @@ -30,15 +25,24 @@ module.exports = { themeRed: '#c4273c', themeDarkColor: '#595959', themeLightColor: '#707070', + pageBackground: '#f5f7fa', + pageFooterBackgroud: '#f1f1f1', torrentColor: '#00853d', usenetColor: '#17b1d9', + // Labels + inverseLabelColor: '#ddd', + inverseLabelTextColor: '#333', + // Links defaultLinkHoverColor: '#fff', linkColor: '#5d9cec', linkHoverColor: '#1b72e2', + // Header + pageHeaderBackgroundColor: prowlarrOrange, + // Sidebar sidebarColor: '#e1e2e3', @@ -68,7 +72,8 @@ module.exports = { // // Buttons - defaultBackgroundColor: '#fff', + defaultButtonTextColor: '#333', + defaultButtonBackgroundColor: '#fff', defaultBorderColor: '#eaeaea', defaultHoverBackgroundColor: '#f5f5f5', defaultHoverBorderColor: '#d6d6d6;', @@ -125,8 +130,10 @@ module.exports = { // // Card + cardBackgroundColor: '#fff', cardShadowColor: '#e1e1e1', cardAlternateBackgroundColor: '#f5f5f5', + cardCenterBackgroundColor: '#fff', // // Alert @@ -147,16 +154,16 @@ module.exports = { alertWarningBackgroundColor: '#fcf8e3', alertWarningColor: '#8a6d3b', - // - // Slider - - sliderAccentColor: '#5d9cec', - // // Form + inputBackgroundColor: '#fff', + inputReadOnlyBackgroundColor: '#eee', + inputHoverBackgroundColor: '#f8f8f8', + inputSelectedBackgroundColor: '#e2e2e2', advancedFormLabelColor: '#ff902b', disabledCheckInputColor: '#ddd', + disabledInputColor: '#808080', // // Popover @@ -171,13 +178,6 @@ module.exports = { popoverShadowInverseColor: 'rgba(0, 0, 0, 0.2)', popoverArrowBorderInverseColor: 'rgba(58, 63, 81, 0.75)', - // - // Calendar - - calendarTodayBackgroundColor: '#ddd', - calendarBorderColor: '#cecece', - calendarTextDim: '#666', - // // Table @@ -187,5 +187,6 @@ module.exports = { // Charts failedColors: ['#ffbeb2', '#feb4a6', '#fdab9b', '#fca290', '#fb9984', '#fa8f79', '#f9856e', '#f77b66', '#f5715d', '#f36754', '#f05c4d', '#ec5049', '#e74545', '#e13b42', '#da323f', '#d3293d', '#ca223c', '#c11a3b', '#b8163a', '#ae123a'], + chartColorsDiversified: ['#90caf9', '#f4d166', '#ff8a65', '#ce93d8', '#80cba9', '#ffab91', '#8097ea', '#bcaaa4', '#a57583', '#e4e498', '#9e96af', '#c6ab81', '#6972c6', '#619fc6', '#81ad81', '#f48fb1', '#82afca', '#b5b071', '#8b959b', '#7ec0b4'], chartColors: ['#f4d166', '#f6c760', '#f8bc58', '#f8b252', '#f7a84a', '#f69e41', '#f49538', '#f38b2f', '#f28026', '#f0751e', '#eb6c1c', '#e4641e', '#de5d1f', '#d75521', '#cf4f22', '#c64a22', '#bc4623', '#b24223', '#a83e24', '#9e3a26'] }; diff --git a/frontend/src/Styles/Variables/colors.js b/frontend/src/Styles/Variables/colors.js deleted file mode 100644 index ff2bedb3a..000000000 --- a/frontend/src/Styles/Variables/colors.js +++ /dev/null @@ -1,192 +0,0 @@ -const prowlarrOrange = '#e66000'; - -module.exports = { - textColor: '#515253', - defaultColor: '#333', - disabledColor: '#999', - dimColor: '#555', - black: '#000', - white: '#fff', - offWhite: '#f5f7fa', - primaryColor: '#5d9cec', - selectedColor: '#f9be03', - successColor: '#27c24c', - dangerColor: '#f05050', - warningColor: '#ffa500', - infoColor: '#5d9cec', - queueColor: '#7a43b6', - purple: '#7a43b6', - pink: '#ff69b4', - prowlarrOrange, - helpTextColor: '#909293', - darkGray: '#888', - gray: '#adadad', - lightGray: '#ddd', - disabledInputColor: '#808080', - - // Theme Colors - - themeBlue: prowlarrOrange, - themeRed: '#c4273c', - themeDarkColor: '#595959', - themeLightColor: '#707070', - - torrentColor: '#00853d', - usenetColor: '#17b1d9', - - // Links - defaultLinkHoverColor: '#fff', - linkColor: '#5d9cec', - linkHoverColor: '#1b72e2', - - // Sidebar - - sidebarColor: '#e1e2e3', - sidebarBackgroundColor: '#595959', - sidebarActiveBackgroundColor: '#333333', - - // Toolbar - toolbarColor: '#e1e2e3', - toolbarBackgroundColor: '#707070', - toolbarMenuItemBackgroundColor: '#606060', - toolbarMenuItemHoverBackgroundColor: '#515151', - toolbarLabelColor: '#e1e2e3', - - // Accents - borderColor: '#e5e5e5', - inputBorderColor: '#dde6e9', - inputBoxShadowColor: 'rgba(0, 0, 0, 0.075)', - inputFocusBorderColor: '#66afe9', - inputFocusBoxShadowColor: 'rgba(102, 175, 233, 0.6)', - inputErrorBorderColor: '#f05050', - inputErrorBoxShadowColor: 'rgba(240, 80, 80, 0.6)', - inputWarningBorderColor: '#ffa500', - inputWarningBoxShadowColor: 'rgba(255, 165, 0, 0.6)', - colorImpairedGradient: '#ffffff', - colorImpairedGradientDark: '#f4f5f6', - - // - // Buttons - - defaultBackgroundColor: '#fff', - defaultBorderColor: '#eaeaea', - defaultHoverBackgroundColor: '#f5f5f5', - defaultHoverBorderColor: '#d6d6d6;', - - primaryBackgroundColor: '#5d9cec', - primaryBorderColor: '#5899eb', - primaryHoverBackgroundColor: '#4b91ea', - primaryHoverBorderColor: '#3483e7;', - - successBackgroundColor: '#27c24c', - successBorderColor: '#26be4a', - successHoverBackgroundColor: '#24b145', - successHoverBorderColor: '#1f9c3d;', - - warningBackgroundColor: '#ff902b', - warningBorderColor: '#ff8d26', - warningHoverBackgroundColor: '#ff8517', - warningHoverBorderColor: '#fc7800;', - - dangerBackgroundColor: '#f05050', - dangerBorderColor: '#f04b4b', - dangerHoverBackgroundColor: '#ee3d3d', - dangerHoverBorderColor: '#ec2626;', - - iconButtonDisabledColor: '#7a7a7a', - iconButtonHoverColor: '#666', - iconButtonHoverLightColor: '#ccc', - - // - // Modal - - modalBackdropBackgroundColor: 'rgba(0, 0, 0, 0.6)', - modalBackgroundColor: '#fff', - modalCloseButtonHoverColor: '#888', - - // - // Menu - menuItemColor: '#e1e2e3', - menuItemHoverColor: '#fbfcfc', - menuItemHoverBackgroundColor: '#f5f7fa', - - // - // Toolbar - - toobarButtonHoverColor: '#e66000', - toobarButtonSelectedColor: '#e66000', - - // - // Scroller - - scrollbarBackgroundColor: '#9ea4b9', - scrollbarHoverBackgroundColor: '#656d8c', - - // - // Card - - cardShadowColor: '#e1e1e1', - cardAlternateBackgroundColor: '#f5f5f5', - - // - // Alert - - alertDangerBorderColor: '#ebccd1', - alertDangerBackgroundColor: '#f2dede', - alertDangerColor: '#a94442', - - alertInfoBorderColor: '#bce8f1', - alertInfoBackgroundColor: '#d9edf7', - alertInfoColor: '#31708f', - - alertSuccessBorderColor: '#d6e9c6', - alertSuccessBackgroundColor: '#dff0d8', - alertSuccessColor: '#3c763d', - - alertWarningBorderColor: '#faebcc', - alertWarningBackgroundColor: '#fcf8e3', - alertWarningColor: '#8a6d3b', - - // - // Slider - - sliderAccentColor: '#5d9cec', - - // - // Form - - advancedFormLabelColor: '#ff902b', - disabledCheckInputColor: '#ddd', - - // - // Popover - - popoverTitleBackgroundColor: '#f7f7f7', - popoverTitleBorderColor: '#ebebeb', - popoverShadowColor: 'rgba(0, 0, 0, 0.2)', - popoverArrowBorderColor: '#fff', - - popoverTitleBackgroundInverseColor: '#595959', - popoverTitleBorderInverseColor: '#707070', - popoverShadowInverseColor: 'rgba(0, 0, 0, 0.2)', - popoverArrowBorderInverseColor: 'rgba(58, 63, 81, 0.75)', - - // - // Calendar - - calendarTodayBackgroundColor: '#ddd', - calendarBorderColor: '#cecece', - calendarTextDim: '#666', - - // - // Table - - tableRowHoverBackgroundColor: '#fafbfc', - - // - // Charts - - failedColors: ['#ffbeb2', '#feb4a6', '#fdab9b', '#fca290', '#fb9984', '#fa8f79', '#f9856e', '#f77b66', '#f5715d', '#f36754', '#f05c4d', '#ec5049', '#e74545', '#e13b42', '#da323f', '#d3293d', '#ca223c', '#c11a3b', '#b8163a', '#ae123a'], - chartColorsDiversified: ['#90caf9', '#f4d166', '#ff8a65', '#ce93d8', '#80cba9', '#ffab91', '#8097ea', '#bcaaa4', '#a57583', '#e4e498', '#9e96af', '#c6ab81', '#6972c6', '#619fc6', '#81ad81', '#f48fb1', '#82afca', '#b5b071', '#8b959b', '#7ec0b4'], - chartColors: ['#f4d166', '#f6c760', '#f8bc58', '#f8b252', '#f7a84a', '#f69e41', '#f49538', '#f38b2f', '#f28026', '#f0751e', '#eb6c1c', '#e4641e', '#de5d1f', '#d75521', '#cf4f22', '#c64a22', '#bc4623', '#b24223', '#a83e24', '#9e3a26'] -}; diff --git a/frontend/src/Styles/scaffolding.css b/frontend/src/Styles/scaffolding.css index 1810037cf..3f5f0fa65 100644 --- a/frontend/src/Styles/scaffolding.css +++ b/frontend/src/Styles/scaffolding.css @@ -15,7 +15,7 @@ html, body { - color: #515253; + color: var(--textColor); font-family: 'Roboto', 'open sans', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif; } diff --git a/frontend/src/System/Events/LogsTableDetailsModal.css b/frontend/src/System/Events/LogsTableDetailsModal.css index b6e0dd24d..887403249 100644 --- a/frontend/src/System/Events/LogsTableDetailsModal.css +++ b/frontend/src/System/Events/LogsTableDetailsModal.css @@ -7,7 +7,7 @@ border: 1px solid #ccc; border-radius: 4px; background-color: #f5f5f5; - color: #3a3f51; + color: var(--themeDarkColor); white-space: pre; word-wrap: break-word; word-break: break-all; diff --git a/frontend/src/System/Events/LogsTableRow.css b/frontend/src/System/Events/LogsTableRow.css index 8efd99abc..0c5a3e1c6 100644 --- a/frontend/src/System/Events/LogsTableRow.css +++ b/frontend/src/System/Events/LogsTableRow.css @@ -17,15 +17,15 @@ } .warn { - color: $warningColor; + color: var(--warningColor); } .error { - color: $dangerColor; + color: var(--dangerColor); } .fatal { - color: $purple; + color: var(--purple); } .actions { diff --git a/frontend/src/System/Status/styles.css b/frontend/src/System/Status/styles.css index 44fe69bad..49253297c 100644 --- a/frontend/src/System/Status/styles.css +++ b/frontend/src/System/Status/styles.css @@ -9,9 +9,9 @@ width: 50px; height: 50px; outline: none; - border: solid 1px #e6e6e6; + border: solid 1px #e5e5e5; border-radius: 0.5em; - background: #f8f8ff; + background: var(--pageBackgroundColor); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); cursor: pointer; } diff --git a/frontend/src/index.css b/frontend/src/index.css index 04e0e11ef..2a94ba941 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -5,7 +5,7 @@ body { body { overflow: hidden; - background-color: #f5f7fa; + background-color: var(--pageBackground); } @media only screen and (max-width: $breakpointSmall) { From 86f2f074e7a9c9e64e57de1d8174bc5e6245452f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 14 May 2022 21:26:16 -0500 Subject: [PATCH 0478/2320] New: Dark Theme --- frontend/src/Styles/Themes/dark.js | 192 +++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 frontend/src/Styles/Themes/dark.js diff --git a/frontend/src/Styles/Themes/dark.js b/frontend/src/Styles/Themes/dark.js new file mode 100644 index 000000000..0bbb9e3ca --- /dev/null +++ b/frontend/src/Styles/Themes/dark.js @@ -0,0 +1,192 @@ +const prowlarrOrange = '#e66000'; + +module.exports = { + textColor: '#ccc', + defaultColor: '#ccc', + disabledColor: '#999', + dimColor: '#555', + black: '#000', + white: '#fff', + primaryColor: '#5d9cec', + selectedColor: '#f9be03', + successColor: '#00853d', + dangerColor: '#f05050', + warningColor: '#ffa500', + infoColor: '#5d9cec', + purple: '#7a43b6', + prowlarrOrange, + helpTextColor: '#909293', + darkGray: '#888', + gray: '#adadad', + + // Theme Colors + + themeBlue: prowlarrOrange, + themeRed: '#c4273c', + themeDarkColor: '#595959', + themeLightColor: prowlarrOrange, + pageBackground: '#202020', + pageFooterBackgroud: 'rgba(0, 0, 0, .25)', + + torrentColor: '#00853d', + usenetColor: '#17b1d9', + + // Labels + inverseLabelColor: '#ddd', + inverseLabelTextColor: prowlarrOrange, + + // Links + defaultLinkHoverColor: '#fff', + linkColor: '#rgb(230, 96, 0)', + linkHoverColor: '#rgb(230, 96, 0, .8)', + + // Header + pageHeaderBackgroundColor: '#2a2a2a', + + // Sidebar + + sidebarColor: '#e1e2e3', + sidebarBackgroundColor: '#2a2a2a', + sidebarActiveBackgroundColor: '#333333', + + // Toolbar + toolbarColor: '#e1e2e3', + toolbarBackgroundColor: '#262626', + toolbarMenuItemBackgroundColor: '#333', + toolbarMenuItemHoverBackgroundColor: '#414141', + toolbarLabelColor: '#e1e2e3', + + // Accents + borderColor: '#e5e5e5', + inputBorderColor: '#dde6e9', + inputBoxShadowColor: 'rgba(0, 0, 0, 0.075)', + inputFocusBorderColor: '#66afe9', + inputFocusBoxShadowColor: 'rgba(102, 175, 233, 0.6)', + inputErrorBorderColor: '#f05050', + inputErrorBoxShadowColor: 'rgba(240, 80, 80, 0.6)', + inputWarningBorderColor: '#ffa500', + inputWarningBoxShadowColor: 'rgba(255, 165, 0, 0.6)', + colorImpairedGradient: '#ffffff', + colorImpairedGradientDark: '#f4f5f6', + + // + // Buttons + + defaultButtonTextColor: '#eee', + defaultButtonBackgroundColor: '#333', + defaultBorderColor: '#eaeaea', + defaultHoverBackgroundColor: '#444', + defaultHoverBorderColor: '#d6d6d6;', + + primaryBackgroundColor: '#5d9cec', + primaryBorderColor: '#5899eb', + primaryHoverBackgroundColor: '#4b91ea', + primaryHoverBorderColor: '#3483e7;', + + successBackgroundColor: '#27c24c', + successBorderColor: '#26be4a', + successHoverBackgroundColor: '#24b145', + successHoverBorderColor: '#1f9c3d;', + + warningBackgroundColor: '#ff902b', + warningBorderColor: '#ff8d26', + warningHoverBackgroundColor: '#ff8517', + warningHoverBorderColor: '#fc7800;', + + dangerBackgroundColor: '#f05050', + dangerBorderColor: '#f04b4b', + dangerHoverBackgroundColor: '#ee3d3d', + dangerHoverBorderColor: '#ec2626;', + + iconButtonDisabledColor: '#7a7a7a', + iconButtonHoverColor: '#666', + iconButtonHoverLightColor: '#ccc', + + // + // Modal + + modalBackdropBackgroundColor: 'rgba(0, 0, 0, 0.6)', + modalBackgroundColor: '#2a2a2a', + modalCloseButtonHoverColor: '#888', + + // + // Menu + menuItemColor: '#e1e2e3', + menuItemHoverColor: '#e66000', + menuItemHoverBackgroundColor: '#606060', + + // + // Toolbar + + toobarButtonHoverColor: '#e66000', + toobarButtonSelectedColor: '#e66000', + + // + // Scroller + + scrollbarBackgroundColor: '#707070', + scrollbarHoverBackgroundColor: '#606060', + + // + // Card + + cardBackgroundColor: '#333333', + cardShadowColor: '#111', + cardAlternateBackgroundColor: '#333333', + cardCenterBackgroundColor: '#2a2a2a', + + // + // Alert + + alertDangerBorderColor: '#a94442', + alertDangerBackgroundColor: 'rgba(255,0,0,0.1)', + alertDangerColor: '#ccc', + + alertInfoBorderColor: '#31708f', + alertInfoBackgroundColor: 'rgba(0,0,255,0.1)', + alertInfoColor: '#ccc', + + alertSuccessBorderColor: '#3c763d', + alertSuccessBackgroundColor: 'rgba(0,255,0,0.1)', + alertSuccessColor: '#ccc', + + alertWarningBorderColor: '#8a6d3b', + alertWarningBackgroundColor: 'rgba(255,255,0,0.1)', + alertWarningColor: '#ccc', + + // + // Form + + inputBackgroundColor: '#333', + inputReadOnlyBackgroundColor: '#222', + inputHoverBackgroundColor: 'rgba(255, 255, 255, 0.20)', + inputSelectedBackgroundColor: 'rgba(255, 255, 255, 0.05)', + advancedFormLabelColor: '#ff902b', + disabledCheckInputColor: '#ddd', + disabledInputColor: '#808080', + + // + // Popover + + popoverTitleBackgroundColor: '#f7f7f7', + popoverTitleBorderColor: '#ebebeb', + popoverShadowColor: 'rgba(0, 0, 0, 0.2)', + popoverArrowBorderColor: '#fff', + + popoverTitleBackgroundInverseColor: '#595959', + popoverTitleBorderInverseColor: '#707070', + popoverShadowInverseColor: 'rgba(0, 0, 0, 0.2)', + popoverArrowBorderInverseColor: 'rgba(58, 63, 81, 0.75)', + + // + // Table + + tableRowHoverBackgroundColor: 'rgba(255, 255, 255, 0.08)', + + // + // Charts + + failedColors: ['#ffbeb2', '#feb4a6', '#fdab9b', '#fca290', '#fb9984', '#fa8f79', '#f9856e', '#f77b66', '#f5715d', '#f36754', '#f05c4d', '#ec5049', '#e74545', '#e13b42', '#da323f', '#d3293d', '#ca223c', '#c11a3b', '#b8163a', '#ae123a'], + chartColorsDiversified: ['#90caf9', '#f4d166', '#ff8a65', '#ce93d8', '#80cba9', '#ffab91', '#8097ea', '#bcaaa4', '#a57583', '#e4e498', '#9e96af', '#c6ab81', '#6972c6', '#619fc6', '#81ad81', '#f48fb1', '#82afca', '#b5b071', '#8b959b', '#7ec0b4'], + chartColors: ['#f4d166', '#f6c760', '#f8bc58', '#f8b252', '#f7a84a', '#f69e41', '#f49538', '#f38b2f', '#f28026', '#f0751e', '#eb6c1c', '#e4641e', '#de5d1f', '#d75521', '#cf4f22', '#c64a22', '#bc4623', '#b24223', '#a83e24', '#9e3a26'] +}; From a3a8f1417d418ca6f0ef27a0799f9772179438e1 Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Sun, 15 May 2022 00:45:32 +0000 Subject: [PATCH 0479/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index f3ddca832..690134c0b 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -5127,6 +5127,10 @@ "type": "string", "nullable": true }, + "instanceName": { + "type": "string", + "nullable": true + }, "updateAutomatically": { "type": "boolean" }, From ed46c5c86d24d8a5a57bfd7a21cb5a865f7406bf Mon Sep 17 00:00:00 2001 From: gofaster <felix.gofaster@gmail.com> Date: Wed, 18 May 2022 13:36:16 -0400 Subject: [PATCH 0480/2320] Fixed: Update AltHub API URL (#1010) --- src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs index 00a2daec1..367076cf1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs @@ -90,7 +90,7 @@ namespace NzbDrone.Core.Indexers.Newznab get { yield return GetDefinition("abNZB", GetSettings("https://abnzb.com")); - yield return GetDefinition("altHUB", GetSettings("https://althub.co.za")); + yield return GetDefinition("altHUB", GetSettings("https://api.althub.co.za")); yield return GetDefinition("AnimeTosho (Usenet)", GetSettings("https://feed.animetosho.org")); yield return GetDefinition("DOGnzb", GetSettings("https://api.dognzb.cr")); yield return GetDefinition("DrunkenSlug", GetSettings("https://drunkenslug.com")); From 5d14d2c134766aa1cb002f745c16ab1c8c725d1c Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 18 May 2022 15:47:17 -0400 Subject: [PATCH 0481/2320] Fixed: Input options background color on mobile --- frontend/src/Components/Form/EnhancedSelectInput.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Components/Form/EnhancedSelectInput.css b/frontend/src/Components/Form/EnhancedSelectInput.css index cb841eb67..56f5564b9 100644 --- a/frontend/src/Components/Form/EnhancedSelectInput.css +++ b/frontend/src/Components/Form/EnhancedSelectInput.css @@ -78,7 +78,7 @@ border: 1px solid var(--inputBorderColor); border-radius: 4px; - background-color: var(--white); + background-color: var(--inputBackgroundColor); } .loading { From d5abde98e1dd9a230e7454c7bd21ebbb88a68d18 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 19 May 2022 21:23:33 -0500 Subject: [PATCH 0482/2320] Fixed: (ExoticaZ) Category Parsing Fixes #938 --- .../Definitions/Avistaz/AvistazApi.cs | 1 + .../Indexers/Definitions/ExoticaZ.cs | 32 ++++++++++++++----- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs index c82c057dd..b8dc82575 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs @@ -8,6 +8,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz { public string Url { get; set; } public string Download { get; set; } + public string Category { get; set; } [JsonProperty(PropertyName = "movie_tv")] public AvistazIdInfo MovieTvinfo { get; set; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/ExoticaZ.cs b/src/NzbDrone.Core/Indexers/Definitions/ExoticaZ.cs index 524ef8361..6c1f85777 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ExoticaZ.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ExoticaZ.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; +using System.Linq; using NLog; -using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Definitions.Avistaz; using NzbDrone.Core.Messaging.Events; @@ -30,15 +30,14 @@ namespace NzbDrone.Core.Indexers.Definitions }; } + public override IParseIndexerResponse GetParser() + { + return new ExoticaZParser(Capabilities.Categories); + } + protected override IndexerCapabilities SetCapabilities() { - var caps = new IndexerCapabilities - { - MovieSearchParams = new List<MovieSearchParam> - { - MovieSearchParam.Q - } - }; + var caps = new IndexerCapabilities(); caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.XXXx264, "Video Clip"); caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.XXXPack, "Video Pack"); @@ -52,4 +51,21 @@ namespace NzbDrone.Core.Indexers.Definitions return caps; } } + + public class ExoticaZParser : AvistazParser + { + private readonly IndexerCapabilitiesCategories _categories; + + public ExoticaZParser(IndexerCapabilitiesCategories categories) + { + _categories = categories; + } + + protected override List<IndexerCategory> ParseCategories(AvistazRelease row) + { + var cat = row.Category; + + return _categories.MapTrackerCatToNewznab(cat).ToList(); + } + } } From 95a2bd3d03a2c66563e31c243e4e54dff2e5be1a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 19 May 2022 21:58:35 -0500 Subject: [PATCH 0483/2320] Fixed: (Gazelle) Parse grouptime as long or date Closes #973 Fixes #773 Closes #1008 --- src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleApi.cs | 2 +- .../Indexers/Definitions/Gazelle/GazelleParser.cs | 3 ++- src/NzbDrone.Core/Indexers/Definitions/Redacted.cs | 3 ++- src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleApi.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleApi.cs index 9dd0e8930..7dd3c6d4c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleApi.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleApi.cs @@ -59,7 +59,7 @@ namespace NzbDrone.Core.Indexers.Gazelle public int TotalSeeders { get; set; } public int TotalSnatched { get; set; } public long MaxSize { get; set; } - public long GroupTime { get; set; } + public string GroupTime { get; set; } public List<GazelleTorrent> Torrents { get; set; } public bool IsFreeLeech { get; set; } public bool IsNeutralLeech { get; set; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs index 04daef331..acf85f3e2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs @@ -5,6 +5,7 @@ using System.Net; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers.Gazelle @@ -120,7 +121,7 @@ namespace NzbDrone.Core.Indexers.Gazelle Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders), Files = result.FileCount, Grabs = result.Snatches, - PublishDate = DateTimeOffset.FromUnixTimeSeconds(result.GroupTime).UtcDateTime, + PublishDate = long.TryParse(result.GroupTime, out var num) ? DateTimeOffset.FromUnixTimeSeconds(num).UtcDateTime : DateTimeUtil.FromFuzzyTime((string)result.GroupTime), PosterUrl = posterUrl, DownloadVolumeFactor = result.IsFreeLeech || result.IsNeutralLeech || result.IsPersonalFreeLeech ? 0 : 1, UploadVolumeFactor = result.IsNeutralLeech ? 0 : 1 diff --git a/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs b/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs index e33077de8..9fe615e10 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs @@ -16,6 +16,7 @@ using NzbDrone.Core.Indexers.Gazelle; using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Validation; @@ -276,7 +277,7 @@ namespace NzbDrone.Core.Indexers.Definitions InfoUrl = infoUrl, Seeders = int.Parse(result.Seeders), Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders), - PublishDate = DateTimeOffset.FromUnixTimeSeconds(result.GroupTime).UtcDateTime, + PublishDate = DateTimeOffset.FromUnixTimeSeconds(ParseUtil.CoerceLong(result.GroupTime)).UtcDateTime, Freeleech = result.IsFreeLeech || result.IsPersonalFreeLeech, Files = result.FileCount, Grabs = result.Snatches, diff --git a/src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs b/src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs index 31553311e..afa3927a4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs @@ -17,6 +17,7 @@ using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Gazelle; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Validation; @@ -182,7 +183,7 @@ namespace NzbDrone.Core.Indexers.Definitions Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders), Files = result.FileCount, Grabs = result.Snatches, - PublishDate = DateTimeOffset.FromUnixTimeSeconds(result.GroupTime).UtcDateTime, + PublishDate = DateTimeOffset.FromUnixTimeSeconds(ParseUtil.CoerceLong(result.GroupTime)).UtcDateTime, }; var category = result.Category; From 3c913eac24acc3615f0f0020a8c4e690b88922ca Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Sun, 29 May 2022 22:51:59 +0100 Subject: [PATCH 0484/2320] Ensure .Mono and .Windows projects have all dependencies in build output Fixes development on linux --- src/NzbDrone.Mono/Prowlarr.Mono.csproj | 1 + src/NzbDrone.Windows/Prowlarr.Windows.csproj | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Mono/Prowlarr.Mono.csproj b/src/NzbDrone.Mono/Prowlarr.Mono.csproj index a5038be86..ede3bd762 100644 --- a/src/NzbDrone.Mono/Prowlarr.Mono.csproj +++ b/src/NzbDrone.Mono/Prowlarr.Mono.csproj @@ -1,6 +1,7 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFrameworks>net6.0</TargetFrameworks> + <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> </PropertyGroup> <ItemGroup> <PackageReference Include="Mono.Posix.NETStandard" Version="5.20.1.34-servarr18" /> diff --git a/src/NzbDrone.Windows/Prowlarr.Windows.csproj b/src/NzbDrone.Windows/Prowlarr.Windows.csproj index 794c0fc9c..2b5a5c955 100644 --- a/src/NzbDrone.Windows/Prowlarr.Windows.csproj +++ b/src/NzbDrone.Windows/Prowlarr.Windows.csproj @@ -1,6 +1,7 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFrameworks>net6.0</TargetFrameworks> + <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> </PropertyGroup> <ItemGroup> <PackageReference Include="NLog" Version="4.7.14" /> @@ -9,4 +10,4 @@ <ItemGroup> <ProjectReference Include="..\NzbDrone.Common\Prowlarr.Common.csproj" /> </ItemGroup> -</Project> \ No newline at end of file +</Project> From 40e7f80be96397bf382285adfc16cbd7b733f834 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 4 Jun 2022 00:42:40 -0500 Subject: [PATCH 0485/2320] Update FE dev dependencies --- package.json | 42 +- yarn.lock | 1929 ++++++++++++++++++++++++++------------------------ 2 files changed, 1008 insertions(+), 963 deletions(-) diff --git a/package.json b/package.json index 99af4c1b3..1d4c831c3 100644 --- a/package.json +++ b/package.json @@ -78,38 +78,38 @@ "reselect": "4.0.0" }, "devDependencies": { - "@babel/core": "7.17.8", - "@babel/eslint-parser": "7.17.0", - "@babel/plugin-proposal-class-properties": "7.16.7", - "@babel/plugin-proposal-decorators": "7.17.8", - "@babel/plugin-proposal-export-default-from": "7.16.7", - "@babel/plugin-proposal-export-namespace-from": "7.16.7", - "@babel/plugin-proposal-function-sent": "7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "7.16.7", + "@babel/core": "7.18.2", + "@babel/eslint-parser": "7.18.2", + "@babel/plugin-proposal-class-properties": "7.17.12", + "@babel/plugin-proposal-decorators": "7.18.2", + "@babel/plugin-proposal-export-default-from": "7.17.12", + "@babel/plugin-proposal-export-namespace-from": "7.17.12", + "@babel/plugin-proposal-function-sent": "7.18.2", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.17.12", "@babel/plugin-proposal-numeric-separator": "7.16.7", - "@babel/plugin-proposal-optional-chaining": "7.16.7", + "@babel/plugin-proposal-optional-chaining": "7.17.12", "@babel/plugin-proposal-throw-expressions": "7.16.7", "@babel/plugin-syntax-dynamic-import": "7.8.3", - "@babel/preset-env": "7.16.11", - "@babel/preset-react": "7.16.7", - "autoprefixer": "10.4.4", - "babel-loader": "8.2.4", + "@babel/preset-env": "7.18.2", + "@babel/preset-react": "7.17.12", + "autoprefixer": "10.4.7", + "babel-loader": "8.2.5", "babel-plugin-inline-classnames": "2.0.1", "babel-plugin-transform-react-remove-prop-types": "0.4.24", - "core-js": "3.21.1", + "core-js": "3.22.8", "css-loader": "6.7.1", - "eslint": "8.11.0", + "eslint": "8.17.0", "eslint-plugin-filenames": "1.3.2", - "eslint-plugin-import": "2.25.4", - "eslint-plugin-react": "7.29.4", + "eslint-plugin-import": "2.26.0", + "eslint-plugin-react": "7.30.0", "eslint-plugin-simple-import-sort": "7.0.0", - "esprint": "3.3.0", + "esprint": "3.6.0", "file-loader": "6.2.0", "filemanager-webpack-plugin": "6.1.7", "html-webpack-plugin": "5.5.0", "loader-utils": "^3.0.0", "mini-css-extract-plugin": "2.6.0", - "postcss": "8.4.12", + "postcss": "8.4.14", "postcss-color-function": "4.1.0", "postcss-loader": "6.2.1", "postcss-mixins": "9.0.2", @@ -121,10 +121,10 @@ "run-sequence": "2.2.1", "streamqueue": "1.1.2", "style-loader": "3.3.1", - "stylelint": "14.6.0", + "stylelint": "14.8.5", "stylelint-order": "5.0.0", "url-loader": "4.1.1", - "webpack": "5.70.0", + "webpack": "5.73.0", "webpack-cli": "4.9.2", "webpack-livereload-plugin": "3.0.2" } diff --git a/yarn.lock b/yarn.lock index a8670f28f..10cca6a46 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,11 +3,12 @@ "@ampproject/remapping@^2.1.0": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34" - integrity sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg== + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== dependencies: - "@jridgewell/trace-mapping" "^0.3.0" + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.7": version "7.16.7" @@ -16,49 +17,49 @@ dependencies: "@babel/highlight" "^7.16.7" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.8", "@babel/compat-data@^7.17.0", "@babel/compat-data@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" - integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ== +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.17.10": + version "7.17.10" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.10.tgz#711dc726a492dfc8be8220028b1b92482362baab" + integrity sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw== -"@babel/core@7.17.8": - version "7.17.8" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a" - integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ== +"@babel/core@7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.2.tgz#87b2fcd7cce9becaa7f5acebdc4f09f3dd19d876" + integrity sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ== dependencies: "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.7" - "@babel/helper-compilation-targets" "^7.17.7" - "@babel/helper-module-transforms" "^7.17.7" - "@babel/helpers" "^7.17.8" - "@babel/parser" "^7.17.8" + "@babel/generator" "^7.18.2" + "@babel/helper-compilation-targets" "^7.18.2" + "@babel/helper-module-transforms" "^7.18.0" + "@babel/helpers" "^7.18.2" + "@babel/parser" "^7.18.0" "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.3" - "@babel/types" "^7.17.0" + "@babel/traverse" "^7.18.2" + "@babel/types" "^7.18.2" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" - json5 "^2.1.2" + json5 "^2.2.1" semver "^6.3.0" -"@babel/eslint-parser@7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz#eabb24ad9f0afa80e5849f8240d0e5facc2d90d6" - integrity sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA== +"@babel/eslint-parser@7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.18.2.tgz#e14dee36c010edfb0153cf900c2b0815e82e3245" + integrity sha512-oFQYkE8SuH14+uR51JVAmdqwKYXGRjEXx7s+WiagVjqQ+HPE+nnwyF2qlVG8evUsUHmPcA+6YXMEDbIhEyQc5A== dependencies: eslint-scope "^5.1.1" eslint-visitor-keys "^2.1.0" semver "^6.3.0" -"@babel/generator@^7.17.3", "@babel/generator@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" - integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== +"@babel/generator@^7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.2.tgz#33873d6f89b21efe2da63fe554460f3df1c5880d" + integrity sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw== dependencies: - "@babel/types" "^7.17.0" + "@babel/types" "^7.18.2" + "@jridgewell/gen-mapping" "^0.3.0" jsesc "^2.5.1" - source-map "^0.5.0" "@babel/helper-annotate-as-pure@^7.16.7": version "7.16.7" @@ -75,33 +76,33 @@ "@babel/helper-explode-assignable-expression" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz#a3c2924f5e5f0379b356d4cfb313d1414dc30e46" - integrity sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w== +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.17.10", "@babel/helper-compilation-targets@^7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz#67a85a10cbd5fc7f1457fec2e7f45441dc6c754b" + integrity sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ== dependencies: - "@babel/compat-data" "^7.17.7" + "@babel/compat-data" "^7.17.10" "@babel/helper-validator-option" "^7.16.7" - browserslist "^4.17.5" + browserslist "^4.20.2" semver "^6.3.0" -"@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7", "@babel/helper-create-class-features-plugin@^7.17.6": - version "7.17.6" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz#3778c1ed09a7f3e65e6d6e0f6fbfcc53809d92c9" - integrity sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg== +"@babel/helper-create-class-features-plugin@^7.17.12", "@babel/helper-create-class-features-plugin@^7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.0.tgz#fac430912606331cb075ea8d82f9a4c145a4da19" + integrity sha512-Kh8zTGR9de3J63e5nS0rQUdRs/kbtwoeQQ0sriS0lItjC96u8XXZN6lKpuyWd2coKSU13py/y+LTmThLuVX0Pg== dependencies: "@babel/helper-annotate-as-pure" "^7.16.7" "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" - "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-function-name" "^7.17.9" + "@babel/helper-member-expression-to-functions" "^7.17.7" "@babel/helper-optimise-call-expression" "^7.16.7" "@babel/helper-replace-supers" "^7.16.7" "@babel/helper-split-export-declaration" "^7.16.7" -"@babel/helper-create-regexp-features-plugin@^7.16.7": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz#1dcc7d40ba0c6b6b25618997c5dbfd310f186fe1" - integrity sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA== +"@babel/helper-create-regexp-features-plugin@^7.16.7", "@babel/helper-create-regexp-features-plugin@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.12.tgz#bb37ca467f9694bbe55b884ae7a5cc1e0084e4fd" + integrity sha512-b2aZrV4zvutr9AIa6/gA3wsZKRwTKYoDxYiFKcESS3Ug2GTXzwBEvMuuFLhCQpEnRXs1zng4ISAXSUxxKBIcxw== dependencies: "@babel/helper-annotate-as-pure" "^7.16.7" regexpu-core "^5.0.1" @@ -120,12 +121,10 @@ resolve "^1.14.2" semver "^6.1.2" -"@babel/helper-environment-visitor@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" - integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== - dependencies: - "@babel/types" "^7.16.7" +"@babel/helper-environment-visitor@^7.16.7", "@babel/helper-environment-visitor@^7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz#8a6d2dedb53f6bf248e31b4baf38739ee4a637bd" + integrity sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ== "@babel/helper-explode-assignable-expression@^7.16.7": version "7.16.7" @@ -134,21 +133,13 @@ dependencies: "@babel/types" "^7.16.7" -"@babel/helper-function-name@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" - integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== +"@babel/helper-function-name@^7.16.7", "@babel/helper-function-name@^7.17.9": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz#136fcd54bc1da82fcb47565cf16fd8e444b1ff12" + integrity sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg== dependencies: - "@babel/helper-get-function-arity" "^7.16.7" "@babel/template" "^7.16.7" - "@babel/types" "^7.16.7" - -"@babel/helper-get-function-arity@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" - integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== - dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.17.0" "@babel/helper-hoist-variables@^7.16.7": version "7.16.7" @@ -157,7 +148,7 @@ dependencies: "@babel/types" "^7.16.7" -"@babel/helper-member-expression-to-functions@^7.16.7": +"@babel/helper-member-expression-to-functions@^7.17.7": version "7.17.7" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz#a34013b57d8542a8c4ff8ba3f747c02452a4d8c4" integrity sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw== @@ -171,10 +162,10 @@ dependencies: "@babel/types" "^7.16.7" -"@babel/helper-module-transforms@^7.16.7", "@babel/helper-module-transforms@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz#3943c7f777139e7954a5355c815263741a9c1cbd" - integrity sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw== +"@babel/helper-module-transforms@^7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz#baf05dec7a5875fb9235bd34ca18bad4e21221cd" + integrity sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA== dependencies: "@babel/helper-environment-visitor" "^7.16.7" "@babel/helper-module-imports" "^7.16.7" @@ -182,8 +173,8 @@ "@babel/helper-split-export-declaration" "^7.16.7" "@babel/helper-validator-identifier" "^7.16.7" "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.3" - "@babel/types" "^7.17.0" + "@babel/traverse" "^7.18.0" + "@babel/types" "^7.18.0" "@babel/helper-optimise-call-expression@^7.16.7": version "7.16.7" @@ -192,10 +183,10 @@ dependencies: "@babel/types" "^7.16.7" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" - integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.17.12", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz#86c2347da5acbf5583ba0a10aed4c9bf9da9cf96" + integrity sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA== "@babel/helper-remap-async-to-generator@^7.16.8": version "7.16.8" @@ -206,23 +197,23 @@ "@babel/helper-wrap-function" "^7.16.8" "@babel/types" "^7.16.8" -"@babel/helper-replace-supers@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz#e9f5f5f32ac90429c1a4bdec0f231ef0c2838ab1" - integrity sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw== +"@babel/helper-replace-supers@^7.16.7", "@babel/helper-replace-supers@^7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.18.2.tgz#41fdfcc9abaf900e18ba6e5931816d9062a7b2e0" + integrity sha512-XzAIyxx+vFnrOxiQrToSUOzUOn0e1J2Li40ntddek1Y69AXUTXoDJ40/D5RdjFu7s7qHiaeoTiempZcbuVXh2Q== dependencies: - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-environment-visitor" "^7.18.2" + "@babel/helper-member-expression-to-functions" "^7.17.7" "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/traverse" "^7.16.7" - "@babel/types" "^7.16.7" + "@babel/traverse" "^7.18.2" + "@babel/types" "^7.18.2" -"@babel/helper-simple-access@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" - integrity sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA== +"@babel/helper-simple-access@^7.17.7", "@babel/helper-simple-access@^7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz#4dc473c2169ac3a1c9f4a51cfcd091d1c36fcff9" + integrity sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ== dependencies: - "@babel/types" "^7.17.0" + "@babel/types" "^7.18.2" "@babel/helper-skip-transparent-expression-wrappers@^7.16.0": version "7.16.0" @@ -248,7 +239,7 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== -"@babel/helper-wrap-function@^7.16.7", "@babel/helper-wrap-function@^7.16.8": +"@babel/helper-wrap-function@^7.16.8": version "7.16.8" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz#58afda087c4cd235de92f7ceedebca2c41274200" integrity sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw== @@ -258,80 +249,81 @@ "@babel/traverse" "^7.16.8" "@babel/types" "^7.16.8" -"@babel/helpers@^7.17.8": - version "7.17.8" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.8.tgz#288450be8c6ac7e4e44df37bcc53d345e07bc106" - integrity sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw== +"@babel/helpers@^7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.2.tgz#970d74f0deadc3f5a938bfa250738eb4ac889384" + integrity sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg== dependencies: "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.3" - "@babel/types" "^7.17.0" + "@babel/traverse" "^7.18.2" + "@babel/types" "^7.18.2" "@babel/highlight@^7.16.7": - version "7.16.10" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" - integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.12.tgz#257de56ee5afbd20451ac0a75686b6b404257351" + integrity sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg== dependencies: "@babel/helper-validator-identifier" "^7.16.7" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.8": - version "7.17.8" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" - integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== +"@babel/parser@^7.16.7", "@babel/parser@^7.18.0": + version "7.18.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.4.tgz#6774231779dd700e0af29f6ad8d479582d7ce5ef" + integrity sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow== -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz#4eda6d6c2a0aa79c70fa7b6da67763dfe2141050" - integrity sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg== +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.17.12.tgz#1dca338caaefca368639c9ffb095afbd4d420b1e" + integrity sha512-xCJQXl4EeQ3J9C4yOmpTrtVGmzpm2iSzyxbkZHw7UCnZBftHpF/hpII80uWVyVrc40ytIClHjgWGTG1g/yB+aw== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz#cc001234dfc139ac45f6bcf801866198c8c72ff9" - integrity sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw== +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.17.12.tgz#0d498ec8f0374b1e2eb54b9cb2c4c78714c77753" + integrity sha512-/vt0hpIw0x4b6BLKUkwlvEoiGZYYLNZ96CzyHYPbtG2jZGz6LBe7/V+drYrc/d+ovrF9NBi0pmtvmNb/FsWtRQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" - "@babel/plugin-proposal-optional-chaining" "^7.16.7" + "@babel/plugin-proposal-optional-chaining" "^7.17.12" -"@babel/plugin-proposal-async-generator-functions@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz#3bdd1ebbe620804ea9416706cd67d60787504bc8" - integrity sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ== +"@babel/plugin-proposal-async-generator-functions@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.17.12.tgz#094a417e31ce7e692d84bab06c8e2a607cbeef03" + integrity sha512-RWVvqD1ooLKP6IqWTA5GyFVX2isGEgC5iFxKzfYOIy/QEFdxYyCybBDtIGjipHpb9bDWHzcqGqFakf+mVmBTdQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/helper-remap-async-to-generator" "^7.16.8" "@babel/plugin-syntax-async-generators" "^7.8.4" -"@babel/plugin-proposal-class-properties@7.16.7", "@babel/plugin-proposal-class-properties@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz#925cad7b3b1a2fcea7e59ecc8eb5954f961f91b0" - integrity sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww== +"@babel/plugin-proposal-class-properties@7.17.12", "@babel/plugin-proposal-class-properties@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.17.12.tgz#84f65c0cc247d46f40a6da99aadd6438315d80a4" + integrity sha512-U0mI9q8pW5Q9EaTHFPwSVusPMV/DV9Mm8p7csqROFLtIE9rBF5piLqyrBGigftALrBcsBGu4m38JneAe7ZDLXw== dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-create-class-features-plugin" "^7.17.12" + "@babel/helper-plugin-utils" "^7.17.12" -"@babel/plugin-proposal-class-static-block@^7.16.7": - version "7.17.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz#164e8fd25f0d80fa48c5a4d1438a6629325ad83c" - integrity sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA== +"@babel/plugin-proposal-class-static-block@^7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.0.tgz#7d02253156e3c3793bdb9f2faac3a1c05f0ba710" + integrity sha512-t+8LsRMMDE74c6sV7KShIw13sqbqd58tlqNrsWoWBTIMw7SVQ0cZ905wLNS/FBCy/3PyooRHLFFlfrUNyyz5lA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.17.6" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-create-class-features-plugin" "^7.18.0" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-syntax-class-static-block" "^7.14.5" -"@babel/plugin-proposal-decorators@7.17.8": - version "7.17.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.8.tgz#4f0444e896bee85d35cf714a006fc5418f87ff00" - integrity sha512-U69odN4Umyyx1xO1rTII0IDkAEC+RNlcKXtqOblfpzqy1C+aOplb76BQNq0+XdpVkOaPlpEDwd++joY8FNFJKA== +"@babel/plugin-proposal-decorators@7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.18.2.tgz#dbe4086d2d42db489399783c3aa9272e9700afd4" + integrity sha512-kbDISufFOxeczi0v4NQP3p5kIeW6izn/6klfWBrIIdGZZe4UpHR+QU03FAoWjGGd9SUXAwbw2pup1kaL4OQsJQ== dependencies: - "@babel/helper-create-class-features-plugin" "^7.17.6" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" - "@babel/plugin-syntax-decorators" "^7.17.0" + "@babel/helper-create-class-features-plugin" "^7.18.0" + "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-replace-supers" "^7.18.2" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/plugin-syntax-decorators" "^7.17.12" charcodes "^0.2.0" "@babel/plugin-proposal-dynamic-import@^7.16.7": @@ -342,53 +334,53 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-dynamic-import" "^7.8.3" -"@babel/plugin-proposal-export-default-from@7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.16.7.tgz#a40ab158ca55627b71c5513f03d3469026a9e929" - integrity sha512-+cENpW1rgIjExn+o5c8Jw/4BuH4eGKKYvkMB8/0ZxFQ9mC0t4z09VsPIwNg6waF69QYC81zxGeAsREGuqQoKeg== +"@babel/plugin-proposal-export-default-from@7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.17.12.tgz#df785e638618d8ffa14e08c78c44d9695d083b73" + integrity sha512-LpsTRw725eBAXXKUOnJJct+SEaOzwR78zahcLuripD2+dKc2Sj+8Q2DzA+GC/jOpOu/KlDXuxrzG214o1zTauQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-syntax-export-default-from" "^7.16.7" -"@babel/plugin-proposal-export-namespace-from@7.16.7", "@babel/plugin-proposal-export-namespace-from@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz#09de09df18445a5786a305681423ae63507a6163" - integrity sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA== +"@babel/plugin-proposal-export-namespace-from@7.17.12", "@babel/plugin-proposal-export-namespace-from@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.17.12.tgz#b22864ccd662db9606edb2287ea5fd1709f05378" + integrity sha512-j7Ye5EWdwoXOpRmo5QmRyHPsDIe6+u70ZYZrd7uz+ebPYFKfRcLcNu3Ro0vOlJ5zuv8rU7xa+GttNiRzX56snQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" -"@babel/plugin-proposal-function-sent@7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-function-sent/-/plugin-proposal-function-sent-7.16.7.tgz#a258face9ce63ee0c14e396c9b96f171a340de89" - integrity sha512-iJ4DQ1TblymT9ylXSxRG9JH+kYWEHcKdKz47kQqZ9Qij6HOOjTbP9ksG1RFtM+CMnmLJaaG/P+YCvgqUt+5hTw== +"@babel/plugin-proposal-function-sent@7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-function-sent/-/plugin-proposal-function-sent-7.18.2.tgz#460a3c6ceac16da8e50a93b6068fd99265e56c75" + integrity sha512-JKAqbpAh6/ZA9satxaP02oL9lmyF1XxzItEONAPHd+jhZtzxBu5sR4L2LhnzjUwR3uJzExaiuHLGuUMNMt/t5A== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-wrap-function" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-wrap-function" "^7.16.8" "@babel/plugin-syntax-function-sent" "^7.16.7" -"@babel/plugin-proposal-json-strings@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz#9732cb1d17d9a2626a08c5be25186c195b6fa6e8" - integrity sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ== +"@babel/plugin-proposal-json-strings@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.17.12.tgz#f4642951792437233216d8c1af370bb0fbff4664" + integrity sha512-rKJ+rKBoXwLnIn7n6o6fulViHMrOThz99ybH+hKHcOZbnN14VuMnH9fo2eHE69C8pO4uX1Q7t2HYYIDmv8VYkg== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-syntax-json-strings" "^7.8.3" -"@babel/plugin-proposal-logical-assignment-operators@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz#be23c0ba74deec1922e639832904be0bea73cdea" - integrity sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg== +"@babel/plugin-proposal-logical-assignment-operators@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.17.12.tgz#c64a1bcb2b0a6d0ed2ff674fd120f90ee4b88a23" + integrity sha512-EqFo2s1Z5yy+JeJu7SFfbIUtToJTVlC61/C7WLKDntSw4Sz6JNAIfL7zQ74VvirxpjB5kz/kIx0gCcb+5OEo2Q== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-proposal-nullish-coalescing-operator@7.16.7", "@babel/plugin-proposal-nullish-coalescing-operator@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz#141fc20b6857e59459d430c850a0011e36561d99" - integrity sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ== +"@babel/plugin-proposal-nullish-coalescing-operator@7.17.12", "@babel/plugin-proposal-nullish-coalescing-operator@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.17.12.tgz#1e93079bbc2cbc756f6db6a1925157c4a92b94be" + integrity sha512-ws/g3FSGVzv+VH86+QvgtuJL/kR67xaEIF2x0iPqdDfYW6ra6JF3lKVBkWynRLcNtIC1oCTfDRVxmm2mKzy+ag== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" "@babel/plugin-proposal-numeric-separator@7.16.7", "@babel/plugin-proposal-numeric-separator@^7.16.7": @@ -399,16 +391,16 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.16.7": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz#d9eb649a54628a51701aef7e0ea3d17e2b9dd390" - integrity sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw== +"@babel/plugin-proposal-object-rest-spread@^7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.0.tgz#79f2390c892ba2a68ec112eb0d895cfbd11155e8" + integrity sha512-nbTv371eTrFabDfHLElkn9oyf9VG+VKK6WMzhY2o4eHKaG19BToD9947zzGMO6I/Irstx9d8CwX6njPNIAR/yw== dependencies: - "@babel/compat-data" "^7.17.0" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/compat-data" "^7.17.10" + "@babel/helper-compilation-targets" "^7.17.10" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.16.7" + "@babel/plugin-transform-parameters" "^7.17.12" "@babel/plugin-proposal-optional-catch-binding@^7.16.7": version "7.16.7" @@ -418,31 +410,31 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-proposal-optional-chaining@7.16.7", "@babel/plugin-proposal-optional-chaining@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz#7cd629564724816c0e8a969535551f943c64c39a" - integrity sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA== +"@babel/plugin-proposal-optional-chaining@7.17.12", "@babel/plugin-proposal-optional-chaining@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.17.12.tgz#f96949e9bacace3a9066323a5cf90cfb9de67174" + integrity sha512-7wigcOs/Z4YWlK7xxjkvaIw84vGhDv/P1dFGQap0nHkc8gFKY/r+hXc8Qzf5k1gY7CvGIcHqAnOagVKJJ1wVOQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -"@babel/plugin-proposal-private-methods@^7.16.11": - version "7.16.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz#e8df108288555ff259f4527dbe84813aac3a1c50" - integrity sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw== +"@babel/plugin-proposal-private-methods@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.17.12.tgz#c2ca3a80beb7539289938da005ad525a038a819c" + integrity sha512-SllXoxo19HmxhDWm3luPz+cPhtoTSKLJE9PXshsfrOzBqs60QP0r8OaJItrPhAj0d7mZMnNF0Y1UUggCDgMz1A== dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.10" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-create-class-features-plugin" "^7.17.12" + "@babel/helper-plugin-utils" "^7.17.12" -"@babel/plugin-proposal-private-property-in-object@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz#b0b8cef543c2c3d57e59e2c611994861d46a3fce" - integrity sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ== +"@babel/plugin-proposal-private-property-in-object@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.17.12.tgz#b02efb7f106d544667d91ae97405a9fd8c93952d" + integrity sha512-/6BtVi57CJfrtDNKfK5b66ydK2J5pXUKBKSPD2G1whamMuEnZWgoOIfO8Vf9F/DoD4izBLD/Au4NMQfruzzykg== dependencies: "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-create-class-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-create-class-features-plugin" "^7.17.12" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" "@babel/plugin-proposal-throw-expressions@7.16.7": @@ -453,13 +445,13 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-throw-expressions" "^7.16.7" -"@babel/plugin-proposal-unicode-property-regex@^7.16.7", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz#635d18eb10c6214210ffc5ff4932552de08188a2" - integrity sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg== +"@babel/plugin-proposal-unicode-property-regex@^7.17.12", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.17.12.tgz#3dbd7a67bd7f94c8238b394da112d86aaf32ad4d" + integrity sha512-Wb9qLjXf3ZazqXA7IvI7ozqRIXIGPtSo+L5coFmEkhTQK18ao4UDDD0zdTGAarmbLj2urpRwrc6893cu5Bfh0A== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-create-regexp-features-plugin" "^7.17.12" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -482,12 +474,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-decorators@^7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.0.tgz#a2be3b2c9fe7d78bd4994e790896bc411e2f166d" - integrity sha512-qWe85yCXsvDEluNP0OyeQjH63DlhAR3W7K9BxxU1MvbDb48tgBG+Ao6IJJ6smPDrrVzSQZrbF6donpkFBMcs3A== +"@babel/plugin-syntax-decorators@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.12.tgz#02e8f678602f0af8222235271efea945cfdb018a" + integrity sha512-D1Hz0qtGTza8K2xGyEdVNCYLdVHukAcbQr4K3/s6r/esadyEriZovpJimQOpu8ju4/jV8dW/1xdaE0UpDroidw== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-syntax-dynamic-import@7.8.3", "@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" @@ -517,6 +509,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-syntax-import-assertions@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.17.12.tgz#58096a92b11b2e4e54b24c6a0cc0e5e607abcedd" + integrity sha512-n/loy2zkq9ZEM8tEOwON9wTQSTNDTDEz6NujPtJGLU7qObzT1N4c4YZZf8E6ATB2AjNQg/Ib2AIpO03EZaCehw== + dependencies: + "@babel/helper-plugin-utils" "^7.17.12" + "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" @@ -524,12 +523,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665" - integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q== +"@babel/plugin-syntax-jsx@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.17.12.tgz#834035b45061983a491f60096f61a2e7c5674a47" + integrity sha512-spyY3E3AURfxh/RHtjx5j6hs8am5NbUBGfcZ2vB3uShSpZdQyXSf5rR5Mk76vbtlAZOelyVQ71Fg0x9SG4fsog== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" @@ -594,20 +593,20 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-arrow-functions@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz#44125e653d94b98db76369de9c396dc14bef4154" - integrity sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ== +"@babel/plugin-transform-arrow-functions@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.17.12.tgz#dddd783b473b1b1537ef46423e3944ff24898c45" + integrity sha512-PHln3CNi/49V+mza4xMwrg+WGYevSF1oaiXaC2EQfdp4HWlSjRsrDXWJiQBKpP7749u6vQ9mcry2uuFOv5CXvA== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" -"@babel/plugin-transform-async-to-generator@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz#b83dff4b970cf41f1b819f8b49cc0cfbaa53a808" - integrity sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg== +"@babel/plugin-transform-async-to-generator@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.17.12.tgz#dbe5511e6b01eee1496c944e35cdfe3f58050832" + integrity sha512-J8dbrWIOO3orDzir57NRsjg4uxucvhby0L/KZuGsWDj0g7twWK3g7JhJhOrXtuXiw8MeiSdJ3E0OW9H8LYEzLQ== dependencies: "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/helper-remap-async-to-generator" "^7.16.8" "@babel/plugin-transform-block-scoped-functions@^7.16.7": @@ -617,40 +616,40 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-block-scoping@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz#f50664ab99ddeaee5bc681b8f3a6ea9d72ab4f87" - integrity sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ== +"@babel/plugin-transform-block-scoping@^7.17.12": + version "7.18.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.4.tgz#7988627b3e9186a13e4d7735dc9c34a056613fb9" + integrity sha512-+Hq10ye+jlvLEogSOtq4mKvtk7qwcUQ1f0Mrueai866C82f844Yom2cttfJdMdqRLTxWpsbfbkIkOIfovyUQXw== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" -"@babel/plugin-transform-classes@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz#8f4b9562850cd973de3b498f1218796eb181ce00" - integrity sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ== +"@babel/plugin-transform-classes@^7.17.12": + version "7.18.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.4.tgz#51310b812a090b846c784e47087fa6457baef814" + integrity sha512-e42NSG2mlKWgxKUAD9EJJSkZxR67+wZqzNxLSpc51T8tRU5SLFHsPmgYR5yr7sdgX4u+iHA1C5VafJ6AyImV3A== dependencies: "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" + "@babel/helper-environment-visitor" "^7.18.2" + "@babel/helper-function-name" "^7.17.9" "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-replace-supers" "^7.18.2" "@babel/helper-split-export-declaration" "^7.16.7" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz#66dee12e46f61d2aae7a73710f591eb3df616470" - integrity sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw== +"@babel/plugin-transform-computed-properties@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.17.12.tgz#bca616a83679698f3258e892ed422546e531387f" + integrity sha512-a7XINeplB5cQUWMg1E/GI1tFz3LfK021IjV1rj1ypE+R7jHm+pIHmHl25VNkZxtx9uuYp7ThGk8fur1HHG7PgQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" -"@babel/plugin-transform-destructuring@^7.16.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz#49dc2675a7afa9a5e4c6bdee636061136c3408d1" - integrity sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ== +"@babel/plugin-transform-destructuring@^7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.0.tgz#dc4f92587e291b4daa78aa20cc2d7a63aa11e858" + integrity sha512-Mo69klS79z6KEfrLg/1WkmVnB8javh75HX4pi2btjvlIoasuxilEyjtsQW6XPrubNd7AQy0MMaNIaQE4e7+PQw== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-dotall-regex@^7.16.7", "@babel/plugin-transform-dotall-regex@^7.4.4": version "7.16.7" @@ -660,12 +659,12 @@ "@babel/helper-create-regexp-features-plugin" "^7.16.7" "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-duplicate-keys@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz#2207e9ca8f82a0d36a5a67b6536e7ef8b08823c9" - integrity sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw== +"@babel/plugin-transform-duplicate-keys@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.17.12.tgz#a09aa709a3310013f8e48e0e23bc7ace0f21477c" + integrity sha512-EA5eYFUG6xeerdabina/xIoB95jJ17mAkR8ivx6ZSu9frKShBjpOGZPn511MTDTkiCO+zXnzNczvUM69YSf3Zw== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-exponentiation-operator@^7.16.7": version "7.16.7" @@ -675,12 +674,12 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.7" "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-for-of@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz#649d639d4617dff502a9a158c479b3b556728d8c" - integrity sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg== +"@babel/plugin-transform-for-of@^7.18.1": + version "7.18.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.1.tgz#ed14b657e162b72afbbb2b4cdad277bf2bb32036" + integrity sha512-+TTB5XwvJ5hZbO8xvl2H4XaMDOAK57zF4miuC9qQJgysPNEAZZ9Z69rdF5LJkozGdZrjBIUAIyKUWRMmebI7vg== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-function-name@^7.16.7": version "7.16.7" @@ -691,12 +690,12 @@ "@babel/helper-function-name" "^7.16.7" "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-literals@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz#254c9618c5ff749e87cb0c0cef1a0a050c0bdab1" - integrity sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ== +"@babel/plugin-transform-literals@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.17.12.tgz#97131fbc6bbb261487105b4b3edbf9ebf9c830ae" + integrity sha512-8iRkvaTjJciWycPIZ9k9duu663FT7VrBdNqNgxnVXEFwOIp55JWcZd23VBRySYbnS3PwQ3rGiabJBBBGj5APmQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-member-expression-literals@^7.16.7": version "7.16.7" @@ -705,57 +704,58 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-modules-amd@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz#b28d323016a7daaae8609781d1f8c9da42b13186" - integrity sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g== +"@babel/plugin-transform-modules-amd@^7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.0.tgz#7ef1002e67e36da3155edc8bf1ac9398064c02ed" + integrity sha512-h8FjOlYmdZwl7Xm2Ug4iX2j7Qy63NANI+NQVWQzv6r25fqgg7k2dZl03p95kvqNclglHs4FZ+isv4p1uXMA+QA== dependencies: - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-module-transforms" "^7.18.0" + "@babel/helper-plugin-utils" "^7.17.12" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-commonjs@^7.16.8": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.7.tgz#d86b217c8e45bb5f2dbc11eefc8eab62cf980d19" - integrity sha512-ITPmR2V7MqioMJyrxUo2onHNC3e+MvfFiFIR0RP21d3PtlVb6sfzoxNKiphSZUOM9hEIdzCcZe83ieX3yoqjUA== +"@babel/plugin-transform-modules-commonjs@^7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.2.tgz#1aa8efa2e2a6e818b6a7f2235fceaf09bdb31e9e" + integrity sha512-f5A865gFPAJAEE0K7F/+nm5CmAE3y8AWlMBG9unu5j9+tk50UQVK0QS8RNxSp7MJf0wh97uYyLWt3Zvu71zyOQ== dependencies: - "@babel/helper-module-transforms" "^7.17.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-simple-access" "^7.17.7" + "@babel/helper-module-transforms" "^7.18.0" + "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-simple-access" "^7.18.2" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-systemjs@^7.16.7": - version "7.17.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz#81fd834024fae14ea78fbe34168b042f38703859" - integrity sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw== +"@babel/plugin-transform-modules-systemjs@^7.18.0": + version "7.18.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.4.tgz#3d6fd9868c735cce8f38d6ae3a407fb7e61e6d46" + integrity sha512-lH2UaQaHVOAeYrUUuZ8i38o76J/FnO8vu21OE+tD1MyP9lxdZoSfz+pDbWkq46GogUrdrMz3tiz/FYGB+bVThg== dependencies: "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-module-transforms" "^7.17.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-module-transforms" "^7.18.0" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/helper-validator-identifier" "^7.16.7" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-umd@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz#23dad479fa585283dbd22215bff12719171e7618" - integrity sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ== +"@babel/plugin-transform-modules-umd@^7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.0.tgz#56aac64a2c2a1922341129a4597d1fd5c3ff020f" + integrity sha512-d/zZ8I3BWli1tmROLxXLc9A6YXvGK8egMxHp+E/rRwMh1Kip0AP77VwZae3snEJ33iiWwvNv2+UIIhfalqhzZA== dependencies: - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-module-transforms" "^7.18.0" + "@babel/helper-plugin-utils" "^7.17.12" -"@babel/plugin-transform-named-capturing-groups-regex@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz#7f860e0e40d844a02c9dcf9d84965e7dfd666252" - integrity sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw== +"@babel/plugin-transform-named-capturing-groups-regex@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.17.12.tgz#9c4a5a5966e0434d515f2675c227fd8cc8606931" + integrity sha512-vWoWFM5CKaTeHrdUJ/3SIOTRV+MBVGybOC9mhJkaprGNt5demMymDW24yC74avb915/mIRe3TgNb/d8idvnCRA== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-create-regexp-features-plugin" "^7.17.12" + "@babel/helper-plugin-utils" "^7.17.12" -"@babel/plugin-transform-new-target@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz#9967d89a5c243818e0800fdad89db22c5f514244" - integrity sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg== +"@babel/plugin-transform-new-target@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.17.12.tgz#10842cd605a620944e81ea6060e9e65c265742e3" + integrity sha512-CaOtzk2fDYisbjAD4Sd1MTKGVIpRtx9bWLyj24Y/k6p4s4gQ3CqDGJauFJxt8M/LEx003d0i3klVqnN73qvK3w== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-object-super@^7.16.7": version "7.16.7" @@ -765,12 +765,12 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/helper-replace-supers" "^7.16.7" -"@babel/plugin-transform-parameters@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz#a1721f55b99b736511cb7e0152f61f17688f331f" - integrity sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw== +"@babel/plugin-transform-parameters@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.17.12.tgz#eb467cd9586ff5ff115a9880d6fdbd4a846b7766" + integrity sha512-6qW4rWo1cyCdq1FkYri7AHpauchbGLXpdwnYsfxFb+KtddHENfsY5JZb35xUwkK5opOLcJ3BNd2l7PhRYGlwIA== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-property-literals@^7.16.7": version "7.16.7" @@ -793,38 +793,39 @@ dependencies: "@babel/plugin-transform-react-jsx" "^7.16.7" -"@babel/plugin-transform-react-jsx@^7.16.7": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.3.tgz#eac1565da176ccb1a715dae0b4609858808008c1" - integrity sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ== +"@babel/plugin-transform-react-jsx@^7.16.7", "@babel/plugin-transform-react-jsx@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.12.tgz#2aa20022709cd6a3f40b45d60603d5f269586dba" + integrity sha512-Lcaw8bxd1DKht3thfD4A12dqo1X16he1Lm8rIv8sTwjAYNInRS1qHa9aJoqvzpscItXvftKDCfaEQzwoVyXpEQ== dependencies: "@babel/helper-annotate-as-pure" "^7.16.7" "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-jsx" "^7.16.7" - "@babel/types" "^7.17.0" + "@babel/helper-plugin-utils" "^7.17.12" + "@babel/plugin-syntax-jsx" "^7.17.12" + "@babel/types" "^7.17.12" "@babel/plugin-transform-react-pure-annotations@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz#232bfd2f12eb551d6d7d01d13fe3f86b45eb9c67" - integrity sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA== + version "7.18.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.0.tgz#ef82c8e310913f3522462c9ac967d395092f1954" + integrity sha512-6+0IK6ouvqDn9bmEG7mEyF/pwlJXVj5lwydybpyyH3D0A7Hftk+NCTdYjnLNZksn261xaOV5ksmp20pQEmc2RQ== dependencies: "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" -"@babel/plugin-transform-regenerator@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz#9e7576dc476cb89ccc5096fff7af659243b4adeb" - integrity sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q== +"@babel/plugin-transform-regenerator@^7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.0.tgz#44274d655eb3f1af3f3a574ba819d3f48caf99d5" + integrity sha512-C8YdRw9uzx25HSIzwA7EM7YP0FhCe5wNvJbZzjVNHHPGVcDJ3Aie+qGYYdS1oVQgn+B3eAIJbWFLrJ4Jipv7nw== dependencies: - regenerator-transform "^0.14.2" + "@babel/helper-plugin-utils" "^7.17.12" + regenerator-transform "^0.15.0" -"@babel/plugin-transform-reserved-words@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz#1d798e078f7c5958eec952059c460b220a63f586" - integrity sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg== +"@babel/plugin-transform-reserved-words@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.17.12.tgz#7dbd349f3cdffba751e817cf40ca1386732f652f" + integrity sha512-1KYqwbJV3Co03NIi14uEHW8P50Md6KqFgt0FfpHdK6oyAHQVTosgPuPSiWud1HX0oYJ1hGRRlk0fP87jFpqXZA== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-shorthand-properties@^7.16.7": version "7.16.7" @@ -833,12 +834,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-spread@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz#a303e2122f9f12e0105daeedd0f30fb197d8ff44" - integrity sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg== +"@babel/plugin-transform-spread@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.17.12.tgz#c112cad3064299f03ea32afed1d659223935d1f5" + integrity sha512-9pgmuQAtFi3lpNUstvG9nGfk9DkrdmWNp9KeKPFmuZCpEnxRzYlS8JgwPjYj+1AWDOSvoGN0H30p1cBOmT/Svg== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" "@babel/plugin-transform-sticky-regex@^7.16.7": @@ -848,19 +849,19 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-template-literals@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz#f3d1c45d28967c8e80f53666fc9c3e50618217ab" - integrity sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA== +"@babel/plugin-transform-template-literals@^7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.2.tgz#31ed6915721864847c48b656281d0098ea1add28" + integrity sha512-/cmuBVw9sZBGZVOMkpAEaVLwm4JmK2GZ1dFKOGGpMzEHWFmyZZ59lUU0PdRr8YNYeQdNzTDwuxP2X2gzydTc9g== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" -"@babel/plugin-transform-typeof-symbol@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz#9cdbe622582c21368bd482b660ba87d5545d4f7e" - integrity sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ== +"@babel/plugin-transform-typeof-symbol@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.17.12.tgz#0f12f57ac35e98b35b4ed34829948d42bd0e6889" + integrity sha512-Q8y+Jp7ZdtSPXCThB6zjQ74N3lj0f6TDh1Hnf5B+sYlzQ8i5Pjp8gW0My79iekSpT4WnI06blqP6DT0OmaXXmw== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-unicode-escapes@^7.16.7": version "7.16.7" @@ -877,37 +878,38 @@ "@babel/helper-create-regexp-features-plugin" "^7.16.7" "@babel/helper-plugin-utils" "^7.16.7" -"@babel/preset-env@7.16.11": - version "7.16.11" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.16.11.tgz#5dd88fd885fae36f88fd7c8342475c9f0abe2982" - integrity sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g== +"@babel/preset-env@7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.18.2.tgz#f47d3000a098617926e674c945d95a28cb90977a" + integrity sha512-PfpdxotV6afmXMU47S08F9ZKIm2bJIQ0YbAAtDfIENX7G1NUAXigLREh69CWDjtgUy7dYn7bsMzkgdtAlmS68Q== dependencies: - "@babel/compat-data" "^7.16.8" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/compat-data" "^7.17.10" + "@babel/helper-compilation-targets" "^7.18.2" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.7" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.7" - "@babel/plugin-proposal-async-generator-functions" "^7.16.8" - "@babel/plugin-proposal-class-properties" "^7.16.7" - "@babel/plugin-proposal-class-static-block" "^7.16.7" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.17.12" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.17.12" + "@babel/plugin-proposal-async-generator-functions" "^7.17.12" + "@babel/plugin-proposal-class-properties" "^7.17.12" + "@babel/plugin-proposal-class-static-block" "^7.18.0" "@babel/plugin-proposal-dynamic-import" "^7.16.7" - "@babel/plugin-proposal-export-namespace-from" "^7.16.7" - "@babel/plugin-proposal-json-strings" "^7.16.7" - "@babel/plugin-proposal-logical-assignment-operators" "^7.16.7" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.7" + "@babel/plugin-proposal-export-namespace-from" "^7.17.12" + "@babel/plugin-proposal-json-strings" "^7.17.12" + "@babel/plugin-proposal-logical-assignment-operators" "^7.17.12" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.17.12" "@babel/plugin-proposal-numeric-separator" "^7.16.7" - "@babel/plugin-proposal-object-rest-spread" "^7.16.7" + "@babel/plugin-proposal-object-rest-spread" "^7.18.0" "@babel/plugin-proposal-optional-catch-binding" "^7.16.7" - "@babel/plugin-proposal-optional-chaining" "^7.16.7" - "@babel/plugin-proposal-private-methods" "^7.16.11" - "@babel/plugin-proposal-private-property-in-object" "^7.16.7" - "@babel/plugin-proposal-unicode-property-regex" "^7.16.7" + "@babel/plugin-proposal-optional-chaining" "^7.17.12" + "@babel/plugin-proposal-private-methods" "^7.17.12" + "@babel/plugin-proposal-private-property-in-object" "^7.17.12" + "@babel/plugin-proposal-unicode-property-regex" "^7.17.12" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-class-properties" "^7.12.13" "@babel/plugin-syntax-class-static-block" "^7.14.5" "@babel/plugin-syntax-dynamic-import" "^7.8.3" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-import-assertions" "^7.17.12" "@babel/plugin-syntax-json-strings" "^7.8.3" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" @@ -917,44 +919,44 @@ "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-transform-arrow-functions" "^7.16.7" - "@babel/plugin-transform-async-to-generator" "^7.16.8" + "@babel/plugin-transform-arrow-functions" "^7.17.12" + "@babel/plugin-transform-async-to-generator" "^7.17.12" "@babel/plugin-transform-block-scoped-functions" "^7.16.7" - "@babel/plugin-transform-block-scoping" "^7.16.7" - "@babel/plugin-transform-classes" "^7.16.7" - "@babel/plugin-transform-computed-properties" "^7.16.7" - "@babel/plugin-transform-destructuring" "^7.16.7" + "@babel/plugin-transform-block-scoping" "^7.17.12" + "@babel/plugin-transform-classes" "^7.17.12" + "@babel/plugin-transform-computed-properties" "^7.17.12" + "@babel/plugin-transform-destructuring" "^7.18.0" "@babel/plugin-transform-dotall-regex" "^7.16.7" - "@babel/plugin-transform-duplicate-keys" "^7.16.7" + "@babel/plugin-transform-duplicate-keys" "^7.17.12" "@babel/plugin-transform-exponentiation-operator" "^7.16.7" - "@babel/plugin-transform-for-of" "^7.16.7" + "@babel/plugin-transform-for-of" "^7.18.1" "@babel/plugin-transform-function-name" "^7.16.7" - "@babel/plugin-transform-literals" "^7.16.7" + "@babel/plugin-transform-literals" "^7.17.12" "@babel/plugin-transform-member-expression-literals" "^7.16.7" - "@babel/plugin-transform-modules-amd" "^7.16.7" - "@babel/plugin-transform-modules-commonjs" "^7.16.8" - "@babel/plugin-transform-modules-systemjs" "^7.16.7" - "@babel/plugin-transform-modules-umd" "^7.16.7" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.16.8" - "@babel/plugin-transform-new-target" "^7.16.7" + "@babel/plugin-transform-modules-amd" "^7.18.0" + "@babel/plugin-transform-modules-commonjs" "^7.18.2" + "@babel/plugin-transform-modules-systemjs" "^7.18.0" + "@babel/plugin-transform-modules-umd" "^7.18.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.17.12" + "@babel/plugin-transform-new-target" "^7.17.12" "@babel/plugin-transform-object-super" "^7.16.7" - "@babel/plugin-transform-parameters" "^7.16.7" + "@babel/plugin-transform-parameters" "^7.17.12" "@babel/plugin-transform-property-literals" "^7.16.7" - "@babel/plugin-transform-regenerator" "^7.16.7" - "@babel/plugin-transform-reserved-words" "^7.16.7" + "@babel/plugin-transform-regenerator" "^7.18.0" + "@babel/plugin-transform-reserved-words" "^7.17.12" "@babel/plugin-transform-shorthand-properties" "^7.16.7" - "@babel/plugin-transform-spread" "^7.16.7" + "@babel/plugin-transform-spread" "^7.17.12" "@babel/plugin-transform-sticky-regex" "^7.16.7" - "@babel/plugin-transform-template-literals" "^7.16.7" - "@babel/plugin-transform-typeof-symbol" "^7.16.7" + "@babel/plugin-transform-template-literals" "^7.18.2" + "@babel/plugin-transform-typeof-symbol" "^7.17.12" "@babel/plugin-transform-unicode-escapes" "^7.16.7" "@babel/plugin-transform-unicode-regex" "^7.16.7" "@babel/preset-modules" "^0.1.5" - "@babel/types" "^7.16.8" + "@babel/types" "^7.18.2" babel-plugin-polyfill-corejs2 "^0.3.0" babel-plugin-polyfill-corejs3 "^0.5.0" babel-plugin-polyfill-regenerator "^0.3.0" - core-js-compat "^3.20.2" + core-js-compat "^3.22.1" semver "^6.3.0" "@babel/preset-modules@^0.1.5": @@ -968,22 +970,22 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-react@7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.16.7.tgz#4c18150491edc69c183ff818f9f2aecbe5d93852" - integrity sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA== +"@babel/preset-react@7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.17.12.tgz#62adbd2d1870c0de3893095757ed5b00b492ab3d" + integrity sha512-h5U+rwreXtZaRBEQhW1hOJLMq8XNJBQ/9oymXiCXTuT/0uOwpbT0gUt+sXeOqoXBgNuUKI7TaObVwoEyWkpFgA== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/helper-validator-option" "^7.16.7" "@babel/plugin-transform-react-display-name" "^7.16.7" - "@babel/plugin-transform-react-jsx" "^7.16.7" + "@babel/plugin-transform-react-jsx" "^7.17.12" "@babel/plugin-transform-react-jsx-development" "^7.16.7" "@babel/plugin-transform-react-pure-annotations" "^7.16.7" "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": - version "7.17.8" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2" - integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA== + version "7.18.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.3.tgz#c7b654b57f6f63cf7f8b418ac9ca04408c4579f4" + integrity sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug== dependencies: regenerator-runtime "^0.13.4" @@ -996,26 +998,26 @@ "@babel/parser" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.3": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" - integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== +"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.18.0", "@babel/traverse@^7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.2.tgz#b77a52604b5cc836a9e1e08dca01cba67a12d2e8" + integrity sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA== dependencies: "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.3" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" + "@babel/generator" "^7.18.2" + "@babel/helper-environment-visitor" "^7.18.2" + "@babel/helper-function-name" "^7.17.9" "@babel/helper-hoist-variables" "^7.16.7" "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.17.3" - "@babel/types" "^7.17.0" + "@babel/parser" "^7.18.0" + "@babel/types" "^7.18.2" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.4.4": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" - integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== +"@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.17.12", "@babel/types@^7.18.0", "@babel/types@^7.18.2", "@babel/types@^7.4.4": + version "7.18.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.4.tgz#27eae9b9fd18e9dccc3f9d6ad051336f307be354" + integrity sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw== dependencies: "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" @@ -1033,19 +1035,19 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@eslint/eslintrc@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.1.tgz#8b5e1c49f4077235516bc9ec7d41378c0f69b8c6" - integrity sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ== +"@eslint/eslintrc@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" + integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.3.1" - globals "^13.9.0" + espree "^9.3.2" + globals "^13.15.0" ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" - minimatch "^3.0.4" + minimatch "^3.1.2" strip-json-comments "^3.1.1" "@fortawesome/fontawesome-common-types@6.1.1": @@ -1100,20 +1102,50 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz#cf92a983c83466b8c0ce9124fadeaf09f7c66ea9" + integrity sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/resolve-uri@^3.0.3": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" - integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== + version "3.0.7" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe" + integrity sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA== + +"@jridgewell/set-array@^1.0.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea" + integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ== + +"@jridgewell/source-map@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" + integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.11" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" - integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== + version "1.4.13" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c" + integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w== -"@jridgewell/trace-mapping@^0.3.0": - version "0.3.4" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz#f6a0832dffd5b8a6aaa633b7d9f8e8e94c83a0c3" - integrity sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ== +"@jridgewell/trace-mapping@^0.3.7", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea" + integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w== dependencies: "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" @@ -1164,9 +1196,9 @@ fastq "^1.6.0" "@react-dnd/asap@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@react-dnd/asap/-/asap-4.0.0.tgz#b300eeed83e9801f51bd66b0337c9a6f04548651" - integrity sha512-0XhqJSc6pPoNnf8DhdsPHtUhRzZALVzYMTzRwV4VI6DJNJ/5xxfL9OQUwb8IH5/2x7lSf7nAZrnzUD+16VyOVQ== + version "4.0.1" + resolved "https://registry.yarnpkg.com/@react-dnd/asap/-/asap-4.0.1.tgz#5291850a6b58ce6f2da25352a64f1b0674871aab" + integrity sha512-kLy0PJDDwvwwTXxqTFNAAllPHD73AycE9ypWeln/IguoGBEbvFcPDbCV03G52bEcC5E+YgupBE0VzHGdC8SIXg== "@react-dnd/invariant@^2.0.0": version "2.0.0" @@ -1263,9 +1295,9 @@ "@types/estree" "*" "@types/eslint@*": - version "8.4.1" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.1.tgz#c48251553e8759db9e656de3efc846954ac32304" - integrity sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA== + version "8.4.2" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.2.tgz#48f2ac58ab9c631cb68845c3d956b28f79fad575" + integrity sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA== dependencies: "@types/estree" "*" "@types/json-schema" "*" @@ -1306,19 +1338,19 @@ integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== "@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": - version "7.0.10" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.10.tgz#9b05b7896166cd00e9cbd59864853abf65d9ac23" - integrity sha512-BLO9bBq59vW3fxCpD4o0N4U+DXsvwvIcl+jofw0frQo/GrBFC+/jRZj1E7kgp6dvTyNmA4y6JCV5Id/r3mNP5A== + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== "@types/lodash@^4.14.159": - version "4.14.180" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.180.tgz#4ab7c9ddfc92ec4a887886483bc14c79fb380670" - integrity sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g== + version "4.14.182" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2" + integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q== "@types/minimatch@*": version "3.0.5" @@ -1331,14 +1363,14 @@ integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== "@types/node@*": - version "17.0.23" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.23.tgz#3b41a6e643589ac6442bdbd7a4a3ded62f33f7da" - integrity sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw== + version "17.0.39" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.39.tgz#3652d82e2a16b4ea679d5ea3143b816c91b7e113" + integrity sha512-JDU3YLlnPK3WDao6/DlXLOgSNpG13ct+CwIO17V8q0/9fWJyeMJJ/VyZ1lv8kDprihvZMydzVwf0tQOqGiY2Nw== "@types/node@^12.12.54": - version "12.20.47" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.47.tgz#ca9237d51f2a2557419688511dab1c8daf475188" - integrity sha512-BzcaRsnFuznzOItW1WpQrDHM7plAa7GIDMZ6b5pnMbkqEtM/6WCOhvZar39oeMQP79gwvFUWjjptE7/KGcNqFg== + version "12.20.54" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.54.tgz#38a3dff8c2a939553f2cdb85dcddc68be46c3c68" + integrity sha512-CFMnEPkSXWALI73t1oIWyb8QOmVrp6RruAqIx349sd+1ImaFwzlKcz55mwrx/yLyOyz1gkq/UKuNOigt27PXqg== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -1351,9 +1383,9 @@ integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== "@types/prop-types@*": - version "15.7.4" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" - integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== + version "15.7.5" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" + integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== "@types/qs@*": version "6.9.7" @@ -1366,9 +1398,9 @@ integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== "@types/react-redux@^7.1.16": - version "7.1.23" - resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.23.tgz#3c2bb1bcc698ae69d70735f33c5a8e95f41ac528" - integrity sha512-D02o3FPfqQlfu2WeEYwh3x2otYd2Dk1o8wAfsA0B1C2AJEFxE663Ozu7JzuWbznGgW248NaOF6wsqCGNq9d3qw== + version "7.1.24" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.24.tgz#6caaff1603aba17b27d20f8ad073e4c077e975c0" + integrity sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ== dependencies: "@types/hoist-non-react-statics" "^3.3.0" "@types/react" "*" @@ -1376,9 +1408,9 @@ redux "^4.0.0" "@types/react@*": - version "17.0.43" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.43.tgz#4adc142887dd4a2601ce730bc56c3436fdb07a55" - integrity sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A== + version "18.0.11" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.11.tgz#94c9b62020caff17d117374d724de853ec711d21" + integrity sha512-JxSwm54IgMW4XTR+zFF5QpNx4JITmFbB4WHR2J0vg9RpjNeyqEMlODXsD2e64br6GX70TL0UYjZJETpyyC1WdA== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -1564,20 +1596,20 @@ acorn-import-assertions@^1.7.6: resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== -acorn-jsx@^5.3.1: +acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" - integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== +acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1: + version "8.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" + integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== add-px-to-style@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/add-px-to-style/-/add-px-to-style-1.0.0.tgz#d0c135441fa8014a8137904531096f67f28f263a" - integrity sha1-0ME1RB+oAUqBN5BFMQlvZ/KPJjo= + integrity sha512-YMyxSlXpPjD8uWekCQGuN40lV4bnZagUwqa2m/uFv1z/tNImSk9fnXVMUI5qwME/zzI3MMQRvjZ+69zyfSSyew== aggregate-error@^3.0.0: version "3.1.0" @@ -1629,28 +1661,28 @@ ajv@^8.0.0, ajv@^8.0.1, ajv@^8.8.0: ansi-cyan@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873" - integrity sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM= + integrity sha512-eCjan3AVo/SxZ0/MyIYRtkpxIu/H3xZN7URr1vXVrISxeyz8fUFz0FJziamK4sS8I+t35y4rHg1b2PklyBe/7A== dependencies: ansi-wrap "0.1.0" ansi-gray@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" - integrity sha1-KWLPVOyXksSFEKPetSRDaGHvclE= + integrity sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw== dependencies: ansi-wrap "0.1.0" ansi-red@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c" - integrity sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw= + integrity sha512-ewaIr5y+9CUTGFwZfpECUbFlGcC0GCw1oqR9RI6h1gQCd9Aj2GxSckCnPsVJnmfMZbwFYE+leZGASgkWl06Jow== dependencies: ansi-wrap "0.1.0" ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== ansi-regex@^5.0.1: version "5.0.1" @@ -1660,7 +1692,7 @@ ansi-regex@^5.0.1: ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA== ansi-styles@^3.2.1: version "3.2.1" @@ -1679,7 +1711,7 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: ansi-wrap@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" - integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768= + integrity sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw== anymatch@^3.1.1: version "3.1.2" @@ -1706,12 +1738,12 @@ archiver-utils@^2.1.0: readable-stream "^2.0.0" archiver@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.0.tgz#dd3e097624481741df626267564f7dd8640a45ba" - integrity sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg== + version "5.3.1" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.1.tgz#21e92811d6f09ecfce649fbefefe8c79e57cbbb6" + integrity sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w== dependencies: archiver-utils "^2.1.0" - async "^3.2.0" + async "^3.2.3" buffer-crc32 "^0.2.1" readable-stream "^3.6.0" readdir-glob "^1.0.0" @@ -1726,7 +1758,7 @@ argparse@^2.0.1: arr-diff@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-1.1.0.tgz#687c32758163588fef7de7b36fabe495eb1a399a" - integrity sha1-aHwydYFjWI/vfeezb6vklesaOZo= + integrity sha512-OQwDZUqYaQwyyhDJHThmzId8daf4/RFNLaeh3AevmSeZ5Y7ug4Ga/yKc6l6kTZOBW781rCj103ZuTh8GAsB3+Q== dependencies: arr-flatten "^1.0.1" array-slice "^0.2.3" @@ -1734,7 +1766,7 @@ arr-diff@^1.0.1: arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA== arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" @@ -1744,33 +1776,33 @@ arr-flatten@^1.0.1, arr-flatten@^1.1.0: arr-union@^2.0.1: version "2.1.0" resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-2.1.0.tgz#20f9eab5ec70f5c7d215b1077b1c39161d292c7d" - integrity sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0= + integrity sha512-t5db90jq+qdgk8aFnxEkjqta0B/GHrM1pxzuuZz2zWsOXc5nKu3t+76s/PQBA8FTcM/ipspIH9jWG4OxCBc2eA== arr-union@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== -array-includes@^3.1.3, array-includes@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" - integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== +array-includes@^3.1.4, array-includes@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.5.tgz#2c320010db8d31031fd2a5f6b3bbd4b1aad31bdb" + integrity sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" + define-properties "^1.1.4" + es-abstract "^1.19.5" get-intrinsic "^1.1.1" is-string "^1.0.7" array-slice@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" - integrity sha1-3Tz7gO15c6dRF82sabC5nshhhvU= + integrity sha512-rlVfZW/1Ph2SNySXwR9QYkChp8EkOEiTMO5Vwx60usw04i4nWemkm9RXmQqgkQFaLHsqLuADvjp6IfgL9l2M8Q== array-union@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + integrity sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng== dependencies: array-uniq "^1.0.1" @@ -1782,35 +1814,37 @@ array-union@^2.1.0: array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ== array.prototype.flat@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" - integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg== + version "1.3.0" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz#0b0c1567bf57b38b56b4c97b8aa72ab45e4adc7b" + integrity sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.19.0" + es-abstract "^1.19.2" + es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" - integrity sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA== +array.prototype.flatmap@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz#a7e8ed4225f4788a70cd910abcf0791e76a5534f" + integrity sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.19.0" + es-abstract "^1.19.2" + es-shim-unscopables "^1.0.0" arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== arrify@^2.0.1: version "2.0.1" @@ -1820,7 +1854,7 @@ arrify@^2.0.1: assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== astral-regex@^2.0.0: version "2.0.0" @@ -1828,13 +1862,13 @@ astral-regex@^2.0.0: integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== async@^2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" - integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + version "2.6.4" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== dependencies: lodash "^4.17.14" -async@^3.2.0: +async@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9" integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g== @@ -1844,22 +1878,22 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -autoprefixer@10.4.4: - version "10.4.4" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.4.tgz#3e85a245b32da876a893d3ac2ea19f01e7ea5a1e" - integrity sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA== +autoprefixer@10.4.7: + version "10.4.7" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.7.tgz#1db8d195f41a52ca5069b7593be167618edbbedf" + integrity sha512-ypHju4Y2Oav95SipEcCcI5J7CGPuvz8oat7sUtYj3ClK44bldfvtvcxK6IEK++7rqB7YchDGzweZIBG+SD0ZAA== dependencies: - browserslist "^4.20.2" - caniuse-lite "^1.0.30001317" + browserslist "^4.20.3" + caniuse-lite "^1.0.30001335" fraction.js "^4.2.0" normalize-range "^0.1.2" picocolors "^1.0.0" postcss-value-parser "^4.2.0" -babel-loader@8.2.4: - version "8.2.4" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.4.tgz#95f5023c791b2e9e2ca6f67b0984f39c82ff384b" - integrity sha512-8dytA3gcvPPPv4Grjhnt8b5IIiTcq/zeXOPk4iTYI0SVXcsmuGg7JtBRDp8S9X+gJfhQ8ektjXZlDu1Bb33U8A== +babel-loader@8.2.5: + version "8.2.5" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.5.tgz#d45f585e654d5a5d90f5350a779d7647c5ed512e" + integrity sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ== dependencies: find-cache-dir "^3.3.1" loader-utils "^2.0.0" @@ -1910,7 +1944,7 @@ babel-plugin-transform-react-remove-prop-types@0.4.24: babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= + integrity sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g== dependencies: core-js "^2.4.0" regenerator-runtime "^0.11.0" @@ -1918,7 +1952,7 @@ babel-runtime@^6.26.0: balanced-match@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.1.0.tgz#b504bd05869b39259dd0c5efc35d843176dccc4a" - integrity sha1-tQS9BYabOSWd0MXvw12EMXbczEo= + integrity sha512-4xb6XqAEo3Z+5pEDJz33R8BZXI8FRJU+cDNLdKgDpmnz+pKKRVYLpdv+VvUAC7yUhBMj4izmyt19eCGv1QGV7A== balanced-match@^1.0.0: version "1.0.2" @@ -1965,7 +1999,7 @@ bl@^4.0.3: body@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" - integrity sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk= + integrity sha512-chUsBxGRtuElD6fmw1gHLpvnKdVLK302peeFa9ZqAEk8TyzZ3fygLyUEDDPTJvL9+Bor0dIwn6ePOsRM2y0zQQ== dependencies: continuable-cache "^0.3.1" error "^7.0.0" @@ -1975,7 +2009,7 @@ body@^5.1.0: boolbase@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== brace-expansion@^1.1.7: version "1.1.11" @@ -2008,15 +2042,15 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.14.5, browserslist@^4.17.5, browserslist@^4.19.1, browserslist@^4.20.2: - version "4.20.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" - integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== +browserslist@^4.14.5, browserslist@^4.20.2, browserslist@^4.20.3: + version "4.20.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.3.tgz#eb7572f49ec430e054f56d52ff0ebe9be915f8bf" + integrity sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg== dependencies: - caniuse-lite "^1.0.30001317" - electron-to-chromium "^1.4.84" + caniuse-lite "^1.0.30001332" + electron-to-chromium "^1.4.118" escalade "^3.1.1" - node-releases "^2.0.2" + node-releases "^2.0.3" picocolors "^1.0.0" bser@2.1.1: @@ -2029,7 +2063,7 @@ bser@2.1.1: buffer-crc32@^0.2.1, buffer-crc32@^0.2.13: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== buffer-from@^1.0.0: version "1.1.2" @@ -2047,7 +2081,7 @@ buffer@^5.5.0: bytes@1: version "1.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" - integrity sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g= + integrity sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ== cache-base@^1.0.1: version "1.0.1" @@ -2075,7 +2109,7 @@ call-bind@^1.0.0, call-bind@^1.0.2: call-me-maybe@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" - integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= + integrity sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw== callsites@^3.0.0: version "3.1.0" @@ -2109,10 +2143,10 @@ camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -caniuse-lite@^1.0.30001317: - version "1.0.30001320" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001320.tgz#8397391bec389b8ccce328636499b7284ee13285" - integrity sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA== +caniuse-lite@^1.0.30001332, caniuse-lite@^1.0.30001335: + version "1.0.30001346" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001346.tgz#e895551b46b9cc9cc9de852facd42f04839a8fbe" + integrity sha512-q6ibZUO2t88QCIPayP/euuDREq+aMAxFE5S70PkrLh0iTDj/zEhgvJRKC2+CvXY6EWc6oQwUR48lL5vCW6jiXQ== capture-exit@^2.0.0: version "2.0.0" @@ -2124,7 +2158,7 @@ capture-exit@^2.0.0: chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A== dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -2180,9 +2214,9 @@ classnames@2.3.1: integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== clean-css@^5.2.2: - version "5.2.4" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.2.4.tgz#982b058f8581adb2ae062520808fb2429bd487a4" - integrity sha512-nKseG8wCzEuji/4yrgM/5cthL9oTDc5UOQyFMvW/Q53oP6gLH690o1NbuTh6Y18nujr7BxlsFuS7gXLnLzKJGg== + version "5.3.0" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.0.tgz#ad3d8238d5f3549e83d5f87205189494bc7cbb59" + integrity sha512-YYuuxv4H/iNb1Z/5IbMRoxgrzjWGhOEFfd+groZ5dMCVkpENiMZmwspdrzBo9286JjM1gZJPAyL7ZIdzuvu2AQ== dependencies: source-map "~0.6.0" @@ -2228,7 +2262,7 @@ clone-regexp@^2.1.0: clone@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== clsx@^1.0.1: version "1.1.1" @@ -2238,7 +2272,7 @@ clsx@^1.0.1: collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + integrity sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw== dependencies: map-visit "^1.0.0" object-visit "^1.0.0" @@ -2260,7 +2294,7 @@ color-convert@^2.0.1: color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" @@ -2270,7 +2304,7 @@ color-name@^1.0.0, color-name@~1.1.4: color-string@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" - integrity sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE= + integrity sha512-sz29j1bmSDfoAxKIEU6zwoIZXN6BrFbAMIhfYCNyiZXBDuU/aiHlN84lp/xDzL2ubyFhLDobHIlU1X70XRrMDA== dependencies: color-name "^1.0.0" @@ -2282,7 +2316,7 @@ color-support@^1.1.3: color@^0.11.0: version "0.11.4" resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764" - integrity sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q= + integrity sha512-Ajpjd8asqZ6EdxQeqGzU5WBhhTfJ/0cA4Wlbre7e5vXfmDSmda7Ov6jeKoru+b0vHcb1CqvuroTHp5zIWzhVMA== dependencies: clone "^1.0.2" color-convert "^1.3.0" @@ -2294,9 +2328,9 @@ colord@^2.9.2: integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ== colorette@^2.0.14: - version "2.0.16" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" - integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== + version "2.0.17" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.17.tgz#5dd4c0d15e2984b7433cb4a9f2ead45063b80c47" + integrity sha512-hJo+3Bkn0NCHybn9Tu35fIeoOKGOk5OCC32y4Hz2It+qlCO2Q3DeQ1hRn/tDDMQKRYUEzqsl7jbF6dYKjlE60g== commander@^2.20.0, commander@^2.20.3: version "2.20.3" @@ -2316,7 +2350,7 @@ commander@^8.3.0: commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== component-emitter@^1.2.1: version "1.3.0" @@ -2336,7 +2370,7 @@ compress-commons@^4.1.0: concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== connected-react-router@6.9.1: version "6.9.1" @@ -2352,7 +2386,7 @@ connected-react-router@6.9.1: continuable-cache@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" - integrity sha1-vXJ6f67XfnH/OYWskzUakSczrQ8= + integrity sha512-TF30kpKhTH8AGCG3dut0rdd/19B7Z+qCnrMoBLpyQu/2drZdNrrpcjPEoJeSVsQM+8KmWG5O56oPDjSSUsuTyA== convert-source-map@^1.7.0: version "1.8.0" @@ -2364,20 +2398,20 @@ convert-source-map@^1.7.0: copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== -core-js-compat@^3.20.2, core-js-compat@^3.21.0: - version "3.21.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.21.1.tgz#cac369f67c8d134ff8f9bd1623e3bc2c42068c82" - integrity sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g== +core-js-compat@^3.21.0, core-js-compat@^3.22.1: + version "3.22.8" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.22.8.tgz#46fa34ce1ddf742acd7f95f575f66bbb21e05d62" + integrity sha512-pQnwg4xtuvc2Bs/5zYQPaEYYSuTxsF7LBWF0SvnVhthZo/Qe+rJpcEekrdNK5DWwDJ0gv0oI9NNX5Mppdy0ctg== dependencies: - browserslist "^4.19.1" + browserslist "^4.20.3" semver "7.0.0" -core-js@3.21.1: - version "3.21.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.21.1.tgz#f2e0ddc1fc43da6f904706e8e955bc19d06a0d94" - integrity sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig== +core-js@3.22.8: + version "3.22.8" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.22.8.tgz#23f860b1fe60797cc4f704d76c93fea8a2f60631" + integrity sha512-UoGQ/cfzGYIuiq6Z7vWL1HfkE9U9IZ4Ub+0XSiJTCzvbZzgPA69oDF2f+lgJ6dFFLEdjW5O6svvoKzXX23xFkA== core-js@^2.4.0: version "2.6.12" @@ -2426,12 +2460,9 @@ cpy@^8.1.2: p-map "^3.0.0" crc-32@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.1.tgz#436d2bcaad27bcb6bd073a2587139d3024a16460" - integrity sha512-Dn/xm/1vFFgs3nfrpEVScHoIslO9NZRITWGz/1E/St6u4xw99vfZzVkW0OSnzx2h9egej9xwMCEut6sqwokM/w== - dependencies: - exit-on-epipe "~1.0.1" - printj "~1.3.1" + version "1.2.2" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== crc32-stream@^4.0.2: version "4.0.2" @@ -2461,7 +2492,7 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: css-color-function@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/css-color-function/-/css-color-function-1.3.3.tgz#8ed24c2c0205073339fafa004bc8c141fccb282e" - integrity sha1-jtJMLAIFBzM5+voAS8jBQfzLKC4= + integrity sha512-YD/WhiRZIYgadwFJ48X5QmlOQ/w8Me4yQI6/eSUoiE8spIFp+S/rGpsAH48iyq/0ZWkCDWqVQKUlQmUzn7BQ9w== dependencies: balanced-match "0.1.0" color "^0.11.0" @@ -2469,9 +2500,9 @@ css-color-function@~1.3.3: rgb "~0.1.0" css-functions-list@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.0.1.tgz#1460df7fb584d1692c30b105151dbb988c8094f9" - integrity sha512-PriDuifDt4u4rkDgnqRCLnjfMatufLmWNfQnGCq34xZwpY3oabwhB9SqRBmuvWUgndbemCFlKqg+nO7C2q0SBw== + version "3.1.0" + resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.1.0.tgz#cf5b09f835ad91a00e5959bcfc627cd498e1321b" + integrity sha512-/9lCvYZaUbBGvYUgYGFJ4dcYiyqdhSjG7IPVluoV8A1ILjkF7ilmhp1OGUz8n+nmBcu0RNrQAzgD8B6FJbrt2w== css-loader@6.7.1: version "6.7.1" @@ -2488,20 +2519,20 @@ css-loader@6.7.1: semver "^7.3.5" css-select@^4.1.3: - version "4.2.1" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.2.1.tgz#9e665d6ae4c7f9d65dbe69d0316e3221fb274cdd" - integrity sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ== + version "4.3.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b" + integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== dependencies: boolbase "^1.0.0" - css-what "^5.1.0" - domhandler "^4.3.0" + css-what "^6.0.1" + domhandler "^4.3.1" domutils "^2.8.0" nth-check "^2.0.1" -css-what@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" - integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw== +css-what@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" + integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== cssesc@^3.0.0: version "3.0.0" @@ -2509,14 +2540,14 @@ cssesc@^3.0.0: integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== csstype@^3.0.2: - version "3.0.11" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33" - integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw== + version "3.1.0" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2" + integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA== cuint@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b" - integrity sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs= + integrity sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw== debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: version "2.6.9" @@ -2532,7 +2563,7 @@ debug@^3.1.0, debug@^3.1.1, debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3: +debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -2542,7 +2573,7 @@ debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3: decamelize-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" - integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= + integrity sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg== dependencies: decamelize "^1.1.0" map-obj "^1.0.0" @@ -2550,12 +2581,12 @@ decamelize-keys@^1.1.0: decamelize@^1.1.0, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og== deep-equal@^1.1.1: version "1.1.1" @@ -2574,24 +2605,25 @@ deep-is@^0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== +define-properties@^1.1.3, define-properties@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" + integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== dependencies: - object-keys "^1.0.12" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + integrity sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA== dependencies: is-descriptor "^0.1.0" define-property@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA== dependencies: is-descriptor "^1.0.0" @@ -2604,9 +2636,9 @@ define-property@^2.0.2: isobject "^3.0.1" del@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/del/-/del-6.0.0.tgz#0b40d0332cea743f1614f818be4feb717714c952" - integrity sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ== + version "6.1.1" + resolved "https://registry.yarnpkg.com/del/-/del-6.1.1.tgz#3b70314f1ec0aa325c6b14eb36b95786671edb7a" + integrity sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg== dependencies: globby "^11.0.1" graceful-fs "^4.2.4" @@ -2684,7 +2716,7 @@ dom-converter@^0.2.0: dom-css@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/dom-css/-/dom-css-2.1.0.tgz#fdbc2d5a015d0a3e1872e11472bbd0e7b9e6a202" - integrity sha1-/bwtWgFdCj4YcuEUcrvQ57nmogI= + integrity sha512-w9kU7FAbaSh3QKijL6n59ofAhkkmMJ31GclJIz/vyQdjogfyxcB6Zf8CZyibOERI5o0Hxz30VmJS7+7r5fEj2Q== dependencies: add-px-to-style "1.0.0" prefix-style "2.0.1" @@ -2698,20 +2730,20 @@ dom-css@^2.0.0: "@babel/runtime" "^7.1.2" dom-serializer@^1.0.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" - integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== + version "1.4.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30" + integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== dependencies: domelementtype "^2.0.1" domhandler "^4.2.0" entities "^2.0.0" domelementtype@^2.0.1, domelementtype@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" - integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== -domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.0: +domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== @@ -2735,15 +2767,15 @@ dot-case@^3.0.4: no-case "^3.0.4" tslib "^2.0.3" -electron-to-chromium@^1.4.84: - version "1.4.92" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.92.tgz#88996e9aceb3a500710fd439abfa89b6cc1ac56c" - integrity sha512-YAVbvQIcDE/IJ/vzDMjD484/hsRbFPW2qXJPaYTfOhtligmfYEYOep+5QojpaEU9kq6bMvNeC2aG7arYvTHYsA== +electron-to-chromium@^1.4.118: + version "1.4.146" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.146.tgz#fd20970c3def2f9e6b32ac13a2e7a6b64e1b0c48" + integrity sha512-4eWebzDLd+hYLm4csbyMU2EbBnqhwl8Oe9eF/7CBDPWcRxFmqzx4izxvHH+lofQxzieg8UbB8ZuzNTxeukzfTg== element-class@0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/element-class/-/element-class-0.2.2.tgz#9d3bbd0767f9013ef8e1c8ebe722c1402a60050e" - integrity sha1-nTu9B2f5AT744cjr5yLBQCpgBQ4= + integrity sha512-e4tkRAFtQkGiZB8fzxAFdjEbx5zajMb1GpiRwKs3lhOLxQcvdOIG7XlERT1sTX3/ulIUGZrgL02YZ0cRNC5OLQ== emoji-regex@^8.0.0: version "8.0.0" @@ -2762,10 +2794,10 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -enhanced-resolve@^5.9.2: - version "5.9.2" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz#0224dcd6a43389ebfb2d55efee517e5466772dd9" - integrity sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA== +enhanced-resolve@^5.9.3: + version "5.9.3" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz#44a342c012cbc473254af5cc6ae20ebd0aae5d88" + integrity sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -2794,37 +2826,47 @@ error@^7.0.0: dependencies: string-template "~0.2.1" -es-abstract@^1.19.0, es-abstract@^1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" - integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== +es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5: + version "1.20.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814" + integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA== dependencies: call-bind "^1.0.2" es-to-primitive "^1.2.1" function-bind "^1.1.1" + function.prototype.name "^1.1.5" get-intrinsic "^1.1.1" get-symbol-description "^1.0.0" has "^1.0.3" - has-symbols "^1.0.2" + has-property-descriptors "^1.0.0" + has-symbols "^1.0.3" internal-slot "^1.0.3" is-callable "^1.2.4" - is-negative-zero "^2.0.1" + is-negative-zero "^2.0.2" is-regex "^1.1.4" - is-shared-array-buffer "^1.0.1" + is-shared-array-buffer "^1.0.2" is-string "^1.0.7" - is-weakref "^1.0.1" - object-inspect "^1.11.0" + is-weakref "^1.0.2" + object-inspect "^1.12.0" object-keys "^1.1.1" object.assign "^4.1.2" - string.prototype.trimend "^1.0.4" - string.prototype.trimstart "^1.0.4" - unbox-primitive "^1.0.1" + regexp.prototype.flags "^1.4.3" + string.prototype.trimend "^1.0.5" + string.prototype.trimstart "^1.0.5" + unbox-primitive "^1.0.2" es-module-lexer@^0.9.0: version "0.9.3" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== +es-shim-unscopables@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" + integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + dependencies: + has "^1.0.3" + es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -2842,7 +2884,7 @@ es6-promise@^4.0.3, es6-promise@^4.2.8: es6-promisify@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== dependencies: es6-promise "^4.0.3" @@ -2854,7 +2896,7 @@ escalade@^3.1.1: escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== escape-string-regexp@^4.0.0: version "4.0.0" @@ -2869,7 +2911,7 @@ eslint-import-resolver-node@^0.3.6: debug "^3.2.7" resolve "^1.20.0" -eslint-module-utils@^2.7.2: +eslint-module-utils@^2.7.3: version "2.7.3" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== @@ -2887,44 +2929,44 @@ eslint-plugin-filenames@1.3.2: lodash.snakecase "4.1.1" lodash.upperfirst "4.3.1" -eslint-plugin-import@2.25.4: - version "2.25.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1" - integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA== +eslint-plugin-import@2.26.0: + version "2.26.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b" + integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA== dependencies: array-includes "^3.1.4" array.prototype.flat "^1.2.5" debug "^2.6.9" doctrine "^2.1.0" eslint-import-resolver-node "^0.3.6" - eslint-module-utils "^2.7.2" + eslint-module-utils "^2.7.3" has "^1.0.3" - is-core-module "^2.8.0" + is-core-module "^2.8.1" is-glob "^4.0.3" - minimatch "^3.0.4" + minimatch "^3.1.2" object.values "^1.1.5" - resolve "^1.20.0" - tsconfig-paths "^3.12.0" + resolve "^1.22.0" + tsconfig-paths "^3.14.1" -eslint-plugin-react@7.29.4: - version "7.29.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.29.4.tgz#4717de5227f55f3801a5fd51a16a4fa22b5914d2" - integrity sha512-CVCXajliVh509PcZYRFyu/BoUEz452+jtQJq2b3Bae4v3xBUWPLCmtmBM+ZinG4MzwmxJgJ2M5rMqhqLVn7MtQ== +eslint-plugin-react@7.30.0: + version "7.30.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.30.0.tgz#8e7b1b2934b8426ac067a0febade1b13bd7064e3" + integrity sha512-RgwH7hjW48BleKsYyHK5vUAvxtE9SMPDKmcPRQgtRCYaZA0XQPt5FSkrU3nhz5ifzMZcA8opwmRJ2cmOO8tr5A== dependencies: - array-includes "^3.1.4" - array.prototype.flatmap "^1.2.5" + array-includes "^3.1.5" + array.prototype.flatmap "^1.3.0" doctrine "^2.1.0" estraverse "^5.3.0" jsx-ast-utils "^2.4.1 || ^3.0.0" minimatch "^3.1.2" object.entries "^1.1.5" object.fromentries "^2.0.5" - object.hasown "^1.1.0" + object.hasown "^1.1.1" object.values "^1.1.5" prop-types "^15.8.1" resolve "^2.0.0-next.3" semver "^6.3.0" - string.prototype.matchall "^4.0.6" + string.prototype.matchall "^4.0.7" eslint-plugin-simple-import-sort@7.0.0: version "7.0.0" @@ -2964,12 +3006,12 @@ eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@8.11.0: - version "8.11.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.11.0.tgz#88b91cfba1356fc10bb9eb592958457dfe09fb37" - integrity sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA== +eslint@8.17.0: + version "8.17.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.17.0.tgz#1cfc4b6b6912f77d24b874ca1506b0fe09328c21" + integrity sha512-gq0m0BTJfci60Fz4nczYxNAlED+sMcihltndR8t9t1evnU/azx53x3t2UHXC/uRjcbvRw/XctpaNygSTcQD+Iw== dependencies: - "@eslint/eslintrc" "^1.2.1" + "@eslint/eslintrc" "^1.3.0" "@humanwhocodes/config-array" "^0.9.2" ajv "^6.10.0" chalk "^4.0.0" @@ -2980,14 +3022,14 @@ eslint@8.11.0: eslint-scope "^7.1.1" eslint-utils "^3.0.0" eslint-visitor-keys "^3.3.0" - espree "^9.3.1" + espree "^9.3.2" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" functional-red-black-tree "^1.0.1" glob-parent "^6.0.1" - globals "^13.6.0" + globals "^13.15.0" ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" @@ -2996,7 +3038,7 @@ eslint@8.11.0: json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" - minimatch "^3.0.4" + minimatch "^3.1.2" natural-compare "^1.4.0" optionator "^0.9.1" regexpp "^3.2.0" @@ -3005,19 +3047,19 @@ eslint@8.11.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^9.3.1: - version "9.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd" - integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ== +espree@^9.3.2: + version "9.3.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596" + integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA== dependencies: - acorn "^8.7.0" - acorn-jsx "^5.3.1" + acorn "^8.7.1" + acorn-jsx "^5.3.2" eslint-visitor-keys "^3.3.0" -esprint@3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/esprint/-/esprint-3.3.0.tgz#ed0e31f536ac647fc10171cca9575c08b922bcc2" - integrity sha512-JcfyfU5SfsofQKj6D9rET99IX3SuthuL21Ltc8yIiqHK4XNEGBM1d2XSlZqht4LGAr/ilgNjDf+yLZJ4OKFOvA== +esprint@3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/esprint/-/esprint-3.6.0.tgz#8d9404166047c2e86632af8ab4ba1e14519bcc53" + integrity sha512-BWj0GXqpwd0k2GJurS3P7W7uQ3oRofDH+qilptsjqMVwzOOQ54DzHAMT7fUJBNG7EXZd7znuTQShSx/CiGMs7Q== dependencies: fb-watchman "^2.0.1" glob "^7.2.0" @@ -3066,9 +3108,9 @@ events@^3.2.0: integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== eventsource@^1.0.7: - version "1.1.0" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.0.tgz#00e8ca7c92109e94b0ddf32dac677d841028cfaf" - integrity sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg== + version "1.1.1" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.1.tgz#4544a35a57d7120fba4fa4c86cb4023b2c09df2f" + integrity sha512-qV5ZC0h7jYIAOhArFJgSfdyz6rALJyb270714o7ZtNnw2WSJ+eexhKtE0O8LYPRsHZHf2osHKZBxGPvm3kPkCA== dependencies: original "^1.0.0" @@ -3114,15 +3156,10 @@ execall@^2.0.0: dependencies: clone-regexp "^2.1.0" -exit-on-epipe@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" - integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw== - expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + integrity sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA== dependencies: debug "^2.3.3" define-property "^0.2.5" @@ -3135,21 +3172,21 @@ expand-brackets@^2.1.4: extend-shallow@^1.1.2: version "1.1.4" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-1.1.4.tgz#19d6bf94dfc09d76ba711f39b872d21ff4dd9071" - integrity sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE= + integrity sha512-L7AGmkO6jhDkEBBGWlLtftA80Xq8DipnrRPr0pyi7GQLXkaq9JYA4xF4z6qnadIC6euiTDKco0cGSU9muw+WTw== dependencies: kind-of "^1.1.0" extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug== dependencies: is-extendable "^0.1.0" extend-shallow@^3.0.0, extend-shallow@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== dependencies: assign-symbols "^1.0.0" is-extendable "^1.0.1" @@ -3171,7 +3208,7 @@ extglob@^2.0.4: eyes@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" - integrity sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A= + integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== fancy-log@^1.3.2: version "1.3.3" @@ -3219,7 +3256,7 @@ fast-json-stable-stringify@^2.0.0: fast-levenshtein@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fastest-levenshtein@^1.0.12: version "1.0.12" @@ -3236,7 +3273,7 @@ fastq@^1.6.0: faye-websocket@~0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" - integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= + integrity sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ== dependencies: websocket-driver ">=0.5.1" @@ -3290,7 +3327,7 @@ filesize@6.3.0: fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + integrity sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ== dependencies: extend-shallow "^2.0.1" is-number "^3.0.0" @@ -3316,7 +3353,7 @@ find-cache-dir@^3.3.1: find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== dependencies: locate-path "^2.0.0" @@ -3351,7 +3388,7 @@ focus-lock@^0.8.1: for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== fraction.js@^4.2.0: version "4.2.0" @@ -3361,7 +3398,7 @@ fraction.js@^4.2.0: fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + integrity sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA== dependencies: map-cache "^0.2.2" @@ -3371,9 +3408,9 @@ fs-constants@^1.0.0: integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== fs-extra@^10.0.0: - version "10.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.1.tgz#27de43b4320e833f6867cc044bfce29fdf0ef3b8" - integrity sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag== + version "10.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" + integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== dependencies: graceful-fs "^4.2.0" jsonfile "^6.0.1" @@ -3382,17 +3419,32 @@ fs-extra@^10.0.0: fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +functions-have-names@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== gensync@^1.0.0-beta.2: version "1.0.0-beta.2" @@ -3446,12 +3498,12 @@ get-symbol-description@^1.0.0: get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + integrity sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA== dependencies: is-glob "^3.1.0" path-dirname "^1.0.0" @@ -3473,7 +3525,7 @@ glob-parent@^6.0.1: glob-to-regexp@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" - integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= + integrity sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig== glob-to-regexp@^0.4.1: version "0.4.1" @@ -3481,14 +3533,14 @@ glob-to-regexp@^0.4.1: integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== glob@^7.1.3, glob@^7.1.4, glob@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.4" + minimatch "^3.1.1" once "^1.3.0" path-is-absolute "^1.0.0" @@ -3513,10 +3565,10 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.6.0, globals@^13.9.0: - version "13.13.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.13.0.tgz#ac32261060d8070e2719dd6998406e27d2b5727b" - integrity sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A== +globals@^13.15.0: + version "13.15.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.15.0.tgz#38113218c907d2f7e98658af246cef8b77e90bac" + integrity sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog== dependencies: type-fest "^0.20.2" @@ -3549,19 +3601,19 @@ globby@^9.2.0: globjoin@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" - integrity sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM= + integrity sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg== good-listener@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" - integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA= + integrity sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw== dependencies: delegate "^3.1.2" graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: - version "4.2.9" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" - integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== gud@^1.0.0: version "1.0.0" @@ -3576,19 +3628,19 @@ hard-rejection@^2.1.0: has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg== dependencies: ansi-regex "^2.0.0" -has-bigints@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: version "4.0.0" @@ -3598,10 +3650,17 @@ has-flag@^4.0.0: has-glob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-glob/-/has-glob-1.0.0.tgz#9aaa9eedbffb1ba3990a7b0010fb678ee0081207" - integrity sha1-mqqe7b/7G6OZCnsAEPtnjuAIEgc= + integrity sha512-D+8A457fBShSEI3tFCj65PAbT++5sKiFtdCdOam0gnfBgw9D277OERk+HM9qYJXmdVLZ/znez10SqHN0BBQ50g== dependencies: is-glob "^3.0.0" +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" @@ -3617,7 +3676,7 @@ has-tostringtag@^1.0.0: has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + integrity sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q== dependencies: get-value "^2.0.3" has-values "^0.1.4" @@ -3626,7 +3685,7 @@ has-value@^0.3.1: has-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + integrity sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw== dependencies: get-value "^2.0.6" has-values "^1.0.0" @@ -3635,12 +3694,12 @@ has-value@^1.0.0: has-values@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + integrity sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ== has-values@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + integrity sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ== dependencies: is-number "^3.0.0" kind-of "^4.0.0" @@ -3701,10 +3760,10 @@ html-minifier-terser@^6.0.2: relateurl "^0.2.7" terser "^5.10.0" -html-tags@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" - integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg== +html-tags@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.2.0.tgz#dbb3518d20b726524e4dd43de397eb0a95726961" + integrity sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg== html-webpack-plugin@5.5.0: version "5.5.0" @@ -3735,7 +3794,7 @@ http-parser-js@>=0.5.1: https-browserify@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + integrity sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg== human-signals@^1.1.1: version "1.1.1" @@ -3770,12 +3829,12 @@ ignore@^5.2.0: immediate@~3.0.5: version "3.0.6" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" - integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== "immutable@^3.8.1 || ^4.0.0-rc.1": - version "4.0.0" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23" - integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw== + version "4.1.0" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.1.0.tgz#f795787f0db780183307b9eb2091fcac1f6fafef" + integrity sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ== import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" @@ -3801,7 +3860,7 @@ import-local@^3.0.2: imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== indent-string@^4.0.0: version "4.0.0" @@ -3811,7 +3870,7 @@ indent-string@^4.0.0: inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" @@ -3850,7 +3909,7 @@ invariant@^2.2.4: is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + integrity sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A== dependencies: kind-of "^3.0.2" @@ -3872,7 +3931,7 @@ is-arguments@^1.0.4: is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== is-bigint@^1.0.1: version "1.0.4" @@ -3899,17 +3958,17 @@ is-callable@^1.1.4, is-callable@^1.2.4: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== -is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.8.0, is-core-module@^2.8.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" - integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== +is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.8.1: + version "2.9.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" + integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== dependencies: has "^1.0.3" is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + integrity sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg== dependencies: kind-of "^3.0.2" @@ -3948,7 +4007,7 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw== is-extendable@^1.0.1: version "1.0.1" @@ -3960,7 +4019,7 @@ is-extendable@^1.0.1: is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-fullwidth-code-point@^3.0.0: version "3.0.0" @@ -3970,7 +4029,7 @@ is-fullwidth-code-point@^3.0.0: is-glob@^3.0.0, is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + integrity sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw== dependencies: is-extglob "^2.1.0" @@ -3981,22 +4040,22 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: dependencies: is-extglob "^2.1.1" -is-negative-zero@^2.0.1: +is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== is-number-object@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" - integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== dependencies: has-tostringtag "^1.0.0" is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg== dependencies: kind-of "^3.0.2" @@ -4018,7 +4077,7 @@ is-path-inside@^3.0.2: is-plain-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" @@ -4045,10 +4104,12 @@ is-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-2.1.0.tgz#cd734a56864e23b956bf4e7c66c396a4c0b22c2d" integrity sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA== -is-shared-array-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" - integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" is-stream@^2.0.0: version "2.0.1" @@ -4069,7 +4130,7 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-weakref@^1.0.1: +is-weakref@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== @@ -4084,29 +4145,29 @@ is-windows@^1.0.2: isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA== dependencies: isarray "1.0.0" isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== isomorphic-ws@^4.0.1: version "4.0.1" @@ -4116,7 +4177,7 @@ isomorphic-ws@^4.0.1: isstream@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== jayson@^3.6.6: version "3.6.6" @@ -4142,7 +4203,7 @@ jayson@^3.6.6: jdu@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/jdu/-/jdu-1.0.0.tgz#28f1e388501785ae0a1d93e93ed0b14dd41e51ce" - integrity sha1-KPHjiFAXha4KHZPpPtCxTdQeUc4= + integrity sha512-fa6WTUpCOM7/hpLBudes2zck0fyP5bR4xUkNbywS6b54Is2BxjF56nGpISr8fFCLNDdItxvZn4Qqd19Ej2wNwA== jest-worker@^27.4.5, jest-worker@^27.4.6: version "27.5.1" @@ -4178,14 +4239,9 @@ jsesc@^2.5.1: jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== -json-parse-better-errors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-parse-even-better-errors@^2.3.0: +json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== @@ -4203,12 +4259,12 @@ json-schema-traverse@^1.0.0: json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== json-stringify-safe@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== json5@^1.0.1: version "1.0.1" @@ -4217,7 +4273,7 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" -json5@^2.1.2: +json5@^2.1.2, json5@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== @@ -4234,14 +4290,14 @@ jsonfile@^6.0.1: jsonparse@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= + integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== "jsx-ast-utils@^2.4.1 || ^3.0.0": - version "3.2.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b" - integrity sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA== + version "3.3.0" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.0.tgz#e624f259143b9062c92b6413ff92a164c80d3ccb" + integrity sha512-XzO9luP6L0xkxwhIJMTJQpZo/eeN60K08jHdexfD569AGxeNug6UketeHXEhROoM8aR7EcUoOQmIhcJQjcuq8Q== dependencies: - array-includes "^3.1.3" + array-includes "^3.1.4" object.assign "^4.1.2" junk@^3.1.0: @@ -4257,19 +4313,19 @@ just-curry-it@^3.1.0: kind-of@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44" - integrity sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ= + integrity sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g== kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw== dependencies: is-buffer "^1.1.5" @@ -4288,10 +4344,10 @@ klona@^2.0.5: resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== -known-css-properties@^0.24.0: - version "0.24.0" - resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.24.0.tgz#19aefd85003ae5698a5560d2b55135bf5432155c" - integrity sha512-RTSoaUAfLvpR357vWzAz/50Q/BmHfmE6ETSWfutT0AJiw10e6CmcdYRQJlLRd95B53D0Y2aD1jSxD3V3ySF+PA== +known-css-properties@^0.25.0: + version "0.25.0" + resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.25.0.tgz#6ebc4d4b412f602e5cfbeb4086bd544e34c0a776" + integrity sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA== lazystream@^1.0.0: version "1.0.1" @@ -4311,14 +4367,14 @@ levn@^0.4.1: lie@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" - integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4= + integrity sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw== dependencies: immediate "~3.0.5" linear-layout-vector@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/linear-layout-vector/-/linear-layout-vector-0.0.1.tgz#398114d7303b6ecc7fd6b273af7b8401d8ba9c70" - integrity sha1-OYEU1zA7bsx/1rJzr3uEAdi6nHA= + integrity sha512-w+nr1ZOVFGyMhwr8JKo0YzqDc8C2Z7pc9UbTuJA4VG/ezlSFEx+7kNrfCYvq7JQ/jHKR+FWy6reNrkVVzm0hSA== lines-and-columns@^1.1.6: version "1.2.4" @@ -4331,9 +4387,9 @@ livereload-js@^2.3.0: integrity sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw== loader-runner@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" - integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== loader-utils@^2.0.0: version "2.0.2" @@ -4359,7 +4415,7 @@ localforage@^1.8.1: locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== dependencies: p-locate "^2.0.0" path-exists "^3.0.0" @@ -4374,42 +4430,42 @@ locate-path@^5.0.0: lodash.camelcase@4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== lodash.defaults@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" - integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== lodash.difference@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" - integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw= + integrity sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA== lodash.flatten@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" - integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== lodash.isequalwith@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.isequalwith/-/lodash.isequalwith-4.4.0.tgz#266726ddd528f854f21f4ea98a065606e0fbc6b0" - integrity sha1-Jmcm3dUo+FTyH06pigZWBuD7xrA= + integrity sha512-dcZON0IalGBpRmJBmMkaoV7d3I80R2O+FrzsZyHdNSFrANq/cgDqKQNmAHE8UEj4+QYWwwhkQOVdLHiAopzlsQ== lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== lodash.kebabcase@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" - integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY= + integrity sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g== lodash.merge@^4.6.2: version "4.6.2" @@ -4419,22 +4475,22 @@ lodash.merge@^4.6.2: lodash.snakecase@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d" - integrity sha1-OdcUo1NXFHg3rv1ktdy7Fr7Nj40= + integrity sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw== lodash.truncate@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" - integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== lodash.union@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" - integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= + integrity sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw== lodash.upperfirst@4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" - integrity sha1-E2Xt9DFIBIHvDRxolXpe2Z1J984= + integrity sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg== lodash@4.17.21, lodash@^4.17.14, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" @@ -4479,12 +4535,12 @@ makeerror@1.0.12: map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== map-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= + integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== map-obj@^4.0.0: version "4.3.0" @@ -4494,7 +4550,7 @@ map-obj@^4.0.0: map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + integrity sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w== dependencies: object-visit "^1.0.0" @@ -4550,7 +4606,7 @@ micromatch@^3.1.10: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.2, micromatch@^4.0.4: +micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== @@ -4600,7 +4656,7 @@ mini-css-extract-plugin@2.6.0: dependencies: schema-utils "^4.0.0" -minimatch@^3.0.4, minimatch@^3.1.2: +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -4661,7 +4717,7 @@ mousetrap@1.6.5: ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== ms@2.1.2: version "2.1.2" @@ -4673,10 +4729,10 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nanoid@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" - integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== +nanoid@^3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== nanomatch@^1.2.9: version "1.2.13" @@ -4698,7 +4754,7 @@ nanomatch@^1.2.9: natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== neo-async@^2.6.2: version "2.6.2" @@ -4706,9 +4762,9 @@ neo-async@^2.6.2: integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" - integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== + version "2.1.1" + resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz#26c8a3cee6cc05fbcf1e333cd2fc3e003326c0b5" + integrity sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw== no-case@^3.0.4: version "3.0.4" @@ -4728,12 +4784,12 @@ node-fetch@^2.6.1: node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-releases@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" - integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg== +node-releases@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666" + integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q== normalize-package-data@^2.5.0: version "2.5.0" @@ -4763,12 +4819,7 @@ normalize-path@^3.0.0: normalize-range@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" - integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= - -normalize-selector@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/normalize-selector/-/normalize-selector-0.2.0.tgz#d0b145eb691189c63a78d201dc4fdb1293ef0c03" - integrity sha1-0LFF62kRicY6eNIB3E/bEpPvDAM= + integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== normalize.css@8.0.1: version "8.0.1" @@ -4783,35 +4834,35 @@ npm-run-path@^4.0.0, npm-run-path@^4.0.1: path-key "^3.0.0" nth-check@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" - integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== + version "2.1.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== dependencies: boolbase "^1.0.0" object-assign@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" - integrity sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I= + integrity sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ== object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + integrity sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ== dependencies: copy-descriptor "^0.1.0" define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.11.0, object-inspect@^1.9.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" - integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== +object-inspect@^1.12.0, object-inspect@^1.9.0: + version "1.12.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" + integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== object-is@^1.0.1: version "1.1.5" @@ -4821,7 +4872,7 @@ object-is@^1.0.1: call-bind "^1.0.2" define-properties "^1.1.3" -object-keys@^1.0.12, object-keys@^1.1.1: +object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== @@ -4829,7 +4880,7 @@ object-keys@^1.0.12, object-keys@^1.1.1: object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + integrity sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA== dependencies: isobject "^3.0.0" @@ -4861,18 +4912,18 @@ object.fromentries@^2.0.5: define-properties "^1.1.3" es-abstract "^1.19.1" -object.hasown@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5" - integrity sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg== +object.hasown@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.1.tgz#ad1eecc60d03f49460600430d97f23882cf592a3" + integrity sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A== dependencies: - define-properties "^1.1.3" - es-abstract "^1.19.1" + define-properties "^1.1.4" + es-abstract "^1.19.5" object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + integrity sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ== dependencies: isobject "^3.0.1" @@ -4888,7 +4939,7 @@ object.values@^1.1.5: once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" @@ -4942,7 +4993,7 @@ p-filter@^2.1.0: p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== p-limit@^1.1.0: version "1.3.0" @@ -4961,7 +5012,7 @@ p-limit@^2.2.0: p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + integrity sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg== dependencies: p-limit "^1.1.0" @@ -5001,7 +5052,7 @@ p-timeout@^3.1.0: p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== p-try@^2.0.0: version "2.2.0" @@ -5049,17 +5100,17 @@ pascal-case@^3.1.2: pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + integrity sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q== path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== path-exists@^4.0.0: version "4.0.0" @@ -5069,7 +5120,7 @@ path-exists@^4.0.0: path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" @@ -5103,7 +5154,7 @@ path-type@^4.0.0: performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== picocolors@^1.0.0: version "1.0.0" @@ -5118,7 +5169,7 @@ picomatch@^2.0.4, picomatch@^2.3.1: pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== pify@^4.0.1: version "4.0.1" @@ -5135,7 +5186,7 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: plugin-error@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" - integrity sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4= + integrity sha512-WzZHcm4+GO34sjFMxQMqZbsz3xiNEgonCskQ9v+IroMmYgk/tas8dG+Hr2D6IbRPybZ12oWpzE/w3cGJ6FJzOw== dependencies: ansi-cyan "^0.1.1" ansi-red "^0.1.1" @@ -5160,7 +5211,7 @@ portfinder@^1.0.17: posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== postcss-color-function@4.1.0: version "4.1.0" @@ -5191,12 +5242,12 @@ postcss-loader@6.2.1: postcss-media-query-parser@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" - integrity sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ= + integrity sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig== postcss-message-helpers@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" - integrity sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4= + integrity sha512-tPLZzVAiIJp46TBbpXtrUAKqedXSyW5xDEo1sikrfEfnTs+49SBZR/xDdqCiJvSSbtr615xDsaMF3RrxS2jZlA== postcss-mixins@9.0.2: version "9.0.2" @@ -5246,17 +5297,17 @@ postcss-nested@5.0.6: postcss-resolve-nested-selector@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz#29ccbc7c37dedfac304e9fff0bf1596b3f6a0e4e" - integrity sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4= + integrity sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw== postcss-safe-parser@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz#bb4c29894171a94bc5c996b9a30317ef402adaa1" integrity sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ== -postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.6, postcss-selector-parser@^6.0.9: - version "6.0.9" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz#ee71c3b9ff63d9cd130838876c13a2ec1a992b2f" - integrity sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ== +postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.6: + version "6.0.10" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d" + integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== dependencies: cssesc "^3.0.0" util-deprecate "^1.0.2" @@ -5291,12 +5342,12 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@8.4.12, postcss@^8.3.11, postcss@^8.4.12, postcss@^8.4.7: - version "8.4.12" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905" - integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg== +postcss@8.4.14, postcss@^8.3.11, postcss@^8.4.14, postcss@^8.4.7: + version "8.4.14" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf" + integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig== dependencies: - nanoid "^3.3.1" + nanoid "^3.3.4" picocolors "^1.0.0" source-map-js "^1.0.2" @@ -5312,7 +5363,7 @@ postcss@^6.0.23: prefix-style@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/prefix-style/-/prefix-style-2.0.1.tgz#66bba9a870cfda308a5dc20e85e9120932c95a06" - integrity sha1-ZrupqHDP2jCKXcIOhekSCTLJWgY= + integrity sha512-gdr1MBNVT0drzTq95CbSNdsrBDoHGlb2aDJP/FoY+1e+jSDPOb1Cv554gH2MGiSr2WTcXi/zu+NaFzfcHQkfBQ== prelude-ls@^1.2.1: version "1.2.1" @@ -5327,11 +5378,6 @@ pretty-error@^4.0.0: lodash "^4.17.20" renderkid "^3.0.0" -printj@~1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/printj/-/printj-1.3.1.tgz#9af6b1d55647a1587ac44f4c1654a4b95b8e12cb" - integrity sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg== - process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -5403,7 +5449,7 @@ randombytes@^2.1.0: raw-body@~1.1.0: version "1.1.7" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" - integrity sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU= + integrity sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg== dependencies: bytes "1" string_decoder "0.10" @@ -5435,9 +5481,9 @@ react-autosuggest@10.1.0: shallow-equal "^1.2.1" react-clientside-effect@^1.2.2: - version "1.2.5" - resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.5.tgz#e2c4dc3c9ee109f642fac4f5b6e9bf5bcd2219a3" - integrity sha512-2bL8qFW1TGBHozGGbVeyvnggRpMjibeZM2536AKNENLECutp2yfs44IL8Hmpn8qjFQ2K7A9PnYf3vc7aQq/cPA== + version "1.2.6" + resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz#29f9b14e944a376b03fb650eed2a754dd128ea3a" + integrity sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg== dependencies: "@babel/runtime" "^7.12.13" @@ -5744,9 +5790,9 @@ redux@4.1.0: "@babel/runtime" "^7.9.2" redux@^4.0.0, redux@^4.1.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.2.tgz#140f35426d99bb4729af760afcf79eaaac407104" - integrity sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw== + version "4.2.0" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.0.tgz#46f10d6e29b6666df758780437651eeb2b969f13" + integrity sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA== dependencies: "@babel/runtime" "^7.9.2" @@ -5772,10 +5818,10 @@ regenerator-runtime@^0.13.4: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== -regenerator-transform@^0.14.2: - version "0.14.5" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" - integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== +regenerator-transform@^0.15.0: + version "0.15.0" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537" + integrity sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg== dependencies: "@babel/runtime" "^7.8.4" @@ -5787,13 +5833,14 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz#b3f4c0059af9e47eca9f3f660e51d81307e72307" - integrity sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ== +regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" + integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" + functions-have-names "^1.2.2" regexpp@^3.2.0: version "3.2.0" @@ -5907,7 +5954,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.9.0: +resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.9.0: version "1.22.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== @@ -6071,9 +6118,9 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== semver@^7.3.4, semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== dependencies: lru-cache "^6.0.0" @@ -6215,7 +6262,7 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== -source-map@^0.5.0, source-map@^0.5.6: +source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -6225,11 +6272,6 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@~0.7.2: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - spdx-correct@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" @@ -6298,7 +6340,7 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string.prototype.matchall@^4.0.6: +string.prototype.matchall@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d" integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg== @@ -6312,21 +6354,23 @@ string.prototype.matchall@^4.0.6: regexp.prototype.flags "^1.4.1" side-channel "^1.0.4" -string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== +string.prototype.trimend@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0" + integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" + define-properties "^1.1.4" + es-abstract "^1.19.5" -string.prototype.trimstart@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" - integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== +string.prototype.trimstart@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef" + integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" + define-properties "^1.1.4" + es-abstract "^1.19.5" string_decoder@0.10: version "0.10.31" @@ -6401,16 +6445,16 @@ stylelint-order@5.0.0: postcss "^8.3.11" postcss-sorting "^7.0.1" -stylelint@14.6.0: - version "14.6.0" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.6.0.tgz#bf577103c8a1d47cd8818469e27db77b83ab3cc1" - integrity sha512-Xk2sqXYPi9nXgq70nBiZkbQm/QOOKd83NBTaBE1fXEWAEeRlgHnKC/E7kJFlT6K0SaNDOK5yIvR7GFPGsNLuOg== +stylelint@14.8.5: + version "14.8.5" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.8.5.tgz#0fcbf5b6821283b5a249dde36d70f1158da0a2a3" + integrity sha512-e3t4H/hlWlspkcNUrkhf44RU3OpPTA7uBOoREGBzSwdEF+2g/+gbZq7WEpMP7BpopcSe/uLaTvDuL+URL7cdnQ== dependencies: balanced-match "^2.0.0" colord "^2.9.2" cosmiconfig "^7.0.1" css-functions-list "^3.0.1" - debug "^4.3.3" + debug "^4.3.4" execall "^2.0.0" fast-glob "^3.2.11" fastest-levenshtein "^1.0.12" @@ -6419,23 +6463,22 @@ stylelint@14.6.0: global-modules "^2.0.0" globby "^11.1.0" globjoin "^0.1.4" - html-tags "^3.1.0" + html-tags "^3.2.0" ignore "^5.2.0" import-lazy "^4.0.0" imurmurhash "^0.1.4" is-plain-object "^5.0.0" - known-css-properties "^0.24.0" + known-css-properties "^0.25.0" mathml-tag-names "^2.1.3" meow "^9.0.0" - micromatch "^4.0.4" + micromatch "^4.0.5" normalize-path "^3.0.0" - normalize-selector "^0.2.0" picocolors "^1.0.0" - postcss "^8.4.12" + postcss "^8.4.14" postcss-media-query-parser "^0.2.3" postcss-resolve-nested-selector "^0.1.1" postcss-safe-parser "^6.0.0" - postcss-selector-parser "^6.0.9" + postcss-selector-parser "^6.0.10" postcss-value-parser "^4.2.0" resolve-from "^5.0.0" specificity "^0.4.1" @@ -6525,24 +6568,24 @@ tar-stream@^2.2.0: readable-stream "^3.1.1" terser-webpack-plugin@^5.1.3: - version "5.3.1" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz#0320dcc270ad5372c1e8993fabbd927929773e54" - integrity sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g== + version "5.3.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz#8033db876dd5875487213e87c627bca323e5ed90" + integrity sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ== dependencies: + "@jridgewell/trace-mapping" "^0.3.7" jest-worker "^27.4.5" schema-utils "^3.1.1" serialize-javascript "^6.0.0" - source-map "^0.6.1" terser "^5.7.2" terser@^5.10.0, terser@^5.7.2: - version "5.12.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.12.1.tgz#4cf2ebed1f5bceef5c83b9f60104ac4a78b49e9c" - integrity sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ== + version "5.14.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.0.tgz#eefeec9af5153f55798180ee2617f390bdd285e2" + integrity sha512-JC6qfIEkPBd9j1SMO3Pfn+A6w2kQV54tv+ABQLgZr7dA3k/DL/OBoYSWxzVpZev3J+bUHXfr55L8Mox7AaNo6g== dependencies: + "@jridgewell/source-map" "^0.3.2" acorn "^8.5.0" commander "^2.20.0" - source-map "~0.7.2" source-map-support "~0.5.20" text-table@^0.2.0: @@ -6667,7 +6710,7 @@ trim-newlines@^3.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== -tsconfig-paths@^3.12.0: +tsconfig-paths@^3.14.1: version "3.14.1" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== @@ -6682,10 +6725,10 @@ tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.3: - version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== +tslib@^2.0.0, tslib@^2.0.3: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" @@ -6719,14 +6762,14 @@ typed-styles@^0.0.7: resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9" integrity sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q== -unbox-primitive@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" - integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== dependencies: - function-bind "^1.1.1" - has-bigints "^1.0.1" - has-symbols "^1.0.2" + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" unicode-canonical-property-names-ecmascript@^2.0.0: @@ -6810,17 +6853,19 @@ url-parse@^1.4.3: requires-port "^1.0.0" use-callback-ref@^1.2.1: - version "1.2.5" - resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.2.5.tgz#6115ed242cfbaed5915499c0a9842ca2912f38a5" - integrity sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg== + version "1.3.0" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.0.tgz#772199899b9c9a50526fedc4993fc7fa1f7e32d5" + integrity sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w== + dependencies: + tslib "^2.0.0" use-sidecar@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.0.5.tgz#ffff2a17c1df42e348624b699ba6e5c220527f2b" - integrity sha512-k9jnrjYNwN6xYLj1iaGhonDghfvmeTmYjAiGvOr7clwKfPjMXJf4/HOr7oT5tJwYafgp2tG2l3eZEOfoELiMcA== + version "1.1.2" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2" + integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw== dependencies: detect-node-es "^1.1.0" - tslib "^1.9.3" + tslib "^2.0.0" use@^3.1.0: version "3.1.1" @@ -6875,9 +6920,9 @@ warning@^4.0.2, warning@^4.0.3: loose-envify "^1.0.0" watchpack@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.1.tgz#4200d9447b401156eeca7767ee610f8809bc9d25" - integrity sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA== + version "2.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== dependencies: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" @@ -6928,10 +6973,10 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@5.70.0: - version "5.70.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.70.0.tgz#3461e6287a72b5e6e2f4872700bc8de0d7500e6d" - integrity sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw== +webpack@5.73.0: + version "5.73.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.73.0.tgz#bbd17738f8a53ee5760ea2f59dce7f3431d35d38" + integrity sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^0.0.51" @@ -6942,13 +6987,13 @@ webpack@5.70.0: acorn-import-assertions "^1.7.6" browserslist "^4.14.5" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.9.2" + enhanced-resolve "^5.9.3" es-module-lexer "^0.9.0" eslint-scope "5.1.1" events "^3.2.0" glob-to-regexp "^0.4.1" graceful-fs "^4.2.9" - json-parse-better-errors "^1.0.2" + json-parse-even-better-errors "^2.3.1" loader-runner "^4.2.0" mime-types "^2.1.27" neo-async "^2.6.2" @@ -7038,9 +7083,9 @@ write-file-atomic@^4.0.1: signal-exit "^3.0.7" ws@^7.4.5: - version "7.5.7" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" - integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== + version "7.5.8" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.8.tgz#ac2729881ab9e7cbaf8787fe3469a48c5c7f636a" + integrity sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw== xxhashjs@~0.2.2: version "0.2.2" @@ -7075,9 +7120,9 @@ yargs-parser@^21.0.0: integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== yargs@^17.3.1: - version "17.4.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.4.0.tgz#9fc9efc96bd3aa2c1240446af28499f0e7593d00" - integrity sha512-WJudfrk81yWFSOkZYpAZx4Nt7V4xp7S/uJkX0CnxovMCt1wCE8LNftPpNuF9X/u9gN5nsD7ycYtRcDf2pL3UiA== + version "17.5.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" + integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== dependencies: cliui "^7.0.2" escalade "^3.1.1" From f0abfae9785cdb9ecb694c5c9c725027721fc519 Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Tue, 31 May 2022 04:39:31 +0000 Subject: [PATCH 0486/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 80 +++++++++++++++++--------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index 690134c0b..5e1297928 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -4210,44 +4210,6 @@ } }, "/api/v1/config/ui/{id}": { - "get": { - "tags": [ - "UiConfig" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UiConfigResource" - } - } - } - } - } - }, "put": { "tags": [ "UiConfig" @@ -4293,6 +4255,44 @@ } } } + }, + "get": { + "tags": [ + "UiConfig" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UiConfigResource" + } + } + } + } + } } }, "/api/v1/config/ui": { @@ -6316,6 +6316,10 @@ "uiLanguage": { "type": "integer", "format": "int32" + }, + "theme": { + "type": "string", + "nullable": true } }, "additionalProperties": false From 59e990227d02dd8eff5a56911f61827cb2759439 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 11 Aug 2021 20:57:51 -0500 Subject: [PATCH 0487/2320] Fixed: Better Cleansing of Tracker Announce Keys Fixed: Cleanse Notifiarr secret from URL in logs (cherry picked from commit e6210aede6f7ead197e82572976bc0267d910d46) (cherry picked from commit ec866082d44d299096112a6c7c232384b1f74505) --- .../InstrumentationTests/CleanseLogMessageFixture.cs | 8 ++++++-- src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs index d26e4e0d9..77d518916 100644 --- a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs +++ b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs @@ -77,20 +77,24 @@ namespace NzbDrone.Common.Test.InstrumentationTests // Download Station [TestCase(@"webapi/entry.cgi?api=(removed)&version=2&method=login&account=01233210&passwd=mySecret&format=sid&session=DownloadStation")] + // Tracker Responses + [TestCase(@"tracker"":""http://xxx.yyy/announce.php?passkey=9pr04sg601233210imaveql2tyu8xyui"",""info"":""http://xxx.yyy/info?a=b""")] + // BroadcastheNet [TestCase(@"method: ""getTorrents"", ""params"": [ ""mySecret"",")] [TestCase(@"getTorrents(""mySecret"", [asdfasdf], 100, 0)")] [TestCase(@"""DownloadURL"":""https:\/\/broadcasthe.net\/torrents.php?action=download&id=123&authkey=mySecret&torrent_pass=mySecret""")] - // Notifiarr + // Webhooks - Notifiarr + [TestCase(@"https://xxx.yyy/api/v1/notification/prowlarr/9pr04sg6-0123-3210-imav-eql2tyu8xyui")] [TestCase("https://notifiarr.com/notifier.php: api=1234530f-422f-4aac-b6b3-01233210aaaa&radarr_health_issue_message=Download")] - [TestCase("/readarr/signalr/messages/negotiate?access_token=1234530f422f4aacb6b301233210aaaa&negotiateVersion=1")] // RSS [TestCase(@"<atom:link href = ""https://api.nzb.su/api?t=search&extended=1&cat=3030&apikey=mySecret&q=Diggers"" rel=""self"" type=""application/rss+xml"" />")] // Internal [TestCase(@"[Info] MigrationController: *** Migrating Database=prowlarr-main;Host=postgres14;Username=mySecret;Password=mySecret;Port=5432;Enlist=False ***")] + [TestCase("/readarr/signalr/messages/negotiate?access_token=1234530f422f4aacb6b301233210aaaa&negotiateVersion=1")] public void should_clean_message(string message) { diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index e9d726537..d2ffe1636 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -11,7 +11,7 @@ namespace NzbDrone.Common.Instrumentation private static readonly Regex[] CleansingRules = new[] { // Url - new Regex(@"(?<=[?&: ;])(apikey|(?:(?:access|api)[-_]?)?token|pass(?:key|wd)?|auth|authkey|user|u?id|api|[a-z_]*apikey|account|pwd)=(?<secret>[^&=]+?)(?= |&|$|<)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"(?<=[?&: ;])(apikey|(?:(?:access|api)[-_]?)?token|pass(?:key|wd)?|auth|authkey|user|u?id|api|[a-z_]*apikey|account|pwd)=(?<secret>[^&=""]+?)(?=[ ""&=]|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"(?<=[?& ;])[^=]*?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"rss\.torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"rss\.torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), @@ -28,6 +28,9 @@ namespace NzbDrone.Common.Instrumentation new Regex(@"""C:\\Users\\(?<secret>[^\""]+?)(\\|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"""/home/(?<secret>[^/""]+?)(/|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + // Trackers Announce Keys; Designed for Qbit Json; should work for all in theory + new Regex(@"announce(\.php)?(/|%2f|%3fpasskey%3d)(?<secret>[a-z0-9]{16,})|(?<secret>[a-z0-9]{16,})(/|%2f)announce"), + // NzbGet new Regex(@"""Name""\s*:\s*""[^""]*(username|password)""\s*,\s*""Value""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase), From fbfb70a1bb1e06eed371132d99a1445760407303 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 11 Jun 2022 14:22:09 -0500 Subject: [PATCH 0488/2320] Fixed: (Cardigann) Searching with nab Parent should also use Child categories Fixes #1031 --- .../Definitions/Cardigann/CardigannBase.cs | 78 +------------------ .../Definitions/Cardigann/CardigannParser.cs | 4 +- .../Cardigann/CardigannRequestGenerator.cs | 2 +- 3 files changed, 6 insertions(+), 78 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index 8c1a63019..387f45a58 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -25,7 +25,7 @@ namespace NzbDrone.Core.Indexers.Cardigann protected virtual string SiteLink { get; private set; } - protected readonly List<CategoryMapping> _categoryMapping = new List<CategoryMapping>(); + protected readonly IndexerCapabilitiesCategories _categories = new IndexerCapabilitiesCategories(); protected readonly List<string> _defaultCategories = new List<string>(); protected readonly string[] OptionalFields = new string[] { "imdb", "imdbid", "rageid", "tmdbid", "tvdbid", "poster", "banner", "description" }; @@ -75,7 +75,7 @@ namespace NzbDrone.Core.Indexers.Cardigann continue; } - AddCategoryMapping(category.Key, cat); + _categories.AddCategoryMapping(category.Key, cat); } } @@ -95,7 +95,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } } - AddCategoryMapping(categorymapping.id, torznabCat, categorymapping.desc); + _categories.AddCategoryMapping(categorymapping.id, torznabCat, categorymapping.desc); if (categorymapping.Default) { @@ -105,30 +105,6 @@ namespace NzbDrone.Core.Indexers.Cardigann } } - public void AddCategoryMapping(string trackerCategory, IndexerCategory torznabCategory, string trackerCategoryDesc = null) - { - _categoryMapping.Add(new CategoryMapping(trackerCategory, trackerCategoryDesc, torznabCategory.Id)); - - if (trackerCategoryDesc == null) - { - return; - } - - // create custom cats (1:1 categories) if trackerCategoryDesc is defined - // - if trackerCategory is "integer" we use that number to generate custom category id - // - if trackerCategory is "string" we compute a hash to generate fixed integer id for the custom category - // the hash is not perfect but it should work in most cases. we can't use sequential numbers because - // categories are updated frequently and the id must be fixed to work in 3rd party apps - if (!int.TryParse(trackerCategory, out var trackerCategoryInt)) - { - var hashed = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(trackerCategory)); - trackerCategoryInt = BitConverter.ToUInt16(hashed, 0); // id between 0 and 65535 < 100000 - } - - var customCat = new IndexerCategory(trackerCategoryInt + 100000, trackerCategoryDesc); - _categoryMapping.Add(new CategoryMapping(trackerCategory, trackerCategoryDesc, customCat.Id)); - } - protected IElement QuerySelector(IElement element, string selector) { // AngleSharp doesn't support the :root pseudo selector, so we check for it manually @@ -362,54 +338,6 @@ namespace NzbDrone.Core.Indexers.Cardigann return variables; } - protected ICollection<IndexerCategory> MapTrackerCatToNewznab(string input) - { - if (string.IsNullOrWhiteSpace(input)) - { - return new List<IndexerCategory>(); - } - - var cats = _categoryMapping - .Where(m => - !string.IsNullOrWhiteSpace(m.TrackerCategory) && - string.Equals(m.TrackerCategory, input, StringComparison.InvariantCultureIgnoreCase)) - .Select(c => NewznabStandardCategory.AllCats.FirstOrDefault(n => n.Id == c.NewzNabCategory) ?? new IndexerCategory { Id = c.NewzNabCategory }) - .ToList(); - return cats; - } - - public List<string> MapTorznabCapsToTrackers(int[] searchCategories, bool mapChildrenCatsToParent = false) - { - if (searchCategories == null) - { - return new List<string>(); - } - - var results = new List<string>(); - - results.AddRange(_categoryMapping - .Where(c => searchCategories.Contains(c.NewzNabCategory)) - .Select(mapping => mapping.TrackerCategory).Distinct().ToList()); - - return results; - } - - public ICollection<IndexerCategory> MapTrackerCatDescToNewznab(string trackerCategoryDesc) - { - if (string.IsNullOrWhiteSpace(trackerCategoryDesc)) - { - return new List<IndexerCategory>(); - } - - var cats = _categoryMapping - .Where(m => - !string.IsNullOrWhiteSpace(m.TrackerCategoryDesc) && - string.Equals(m.TrackerCategoryDesc, trackerCategoryDesc, StringComparison.InvariantCultureIgnoreCase)) - .Select(c => NewznabStandardCategory.AllCats.FirstOrDefault(n => n.Id == c.NewzNabCategory) ?? new IndexerCategory { Id = c.NewzNabCategory }) - .ToList(); - return cats; - } - protected delegate string TemplateTextModifier(string str); protected string ApplyGoTemplateText(string template, Dictionary<string, object> variables = null, TemplateTextModifier modifier = null) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index 1916a01ed..930d5b45f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -451,7 +451,7 @@ namespace NzbDrone.Core.Indexers.Cardigann value = release.Description; break; case "category": - var cats = MapTrackerCatToNewznab(value); + var cats = _categories.MapTrackerCatToNewznab(value); if (cats.Any()) { if (release.Categories == null || fieldModifiers.Contains("noappend")) @@ -467,7 +467,7 @@ namespace NzbDrone.Core.Indexers.Cardigann value = release.Categories.ToString(); break; case "categorydesc": - var catsDesc = MapTrackerCatDescToNewznab(value); + var catsDesc = _categories.MapTrackerCatDescToNewznab(value); if (catsDesc.Any()) { if (release.Categories == null || fieldModifiers.Contains("noappend")) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 30ccb3ad0..11004a606 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -975,7 +975,7 @@ namespace NzbDrone.Core.Indexers.Cardigann { var search = _definition.Search; - var mappedCategories = MapTorznabCapsToTrackers((int[])variables[".Query.Categories"]); + var mappedCategories = _categories.MapTorznabCapsToTrackers((int[])variables[".Query.Categories"]); if (mappedCategories.Count == 0) { mappedCategories = _defaultCategories; From 4334e7eef16acc7137cc8840c001394856f64f64 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 11 Jun 2022 15:04:35 -0500 Subject: [PATCH 0489/2320] New: (PassThePopcorn) Freeleech only option Fixes #1014 --- .../IndexerTests/PTPTests/PTPFixture.cs | 2 +- .../PassThePopcorn/PassThePopcornInfo.cs | 11 ----------- .../PassThePopcorn/PassThePopcornParser.cs | 5 +---- .../PassThePopcornRequestGenerator.cs | 16 +++++++++++++++- .../PassThePopcorn/PassThePopcornSettings.cs | 5 ++++- 5 files changed, 21 insertions(+), 18 deletions(-) delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornInfo.cs diff --git a/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs index 2f606c420..c27972e0f 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/PTPTests/PTPFixture.cs @@ -48,7 +48,7 @@ namespace NzbDrone.Core.Test.IndexerTests.PTPTests var torrents = (await Subject.Fetch(new MovieSearchCriteria())).Releases; torrents.Should().HaveCount(293); - torrents.First().Should().BeOfType<PassThePopcornInfo>(); + torrents.First().Should().BeOfType<TorrentInfo>(); var first = torrents.First() as TorrentInfo; diff --git a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornInfo.cs b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornInfo.cs deleted file mode 100644 index b117d77c3..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -using NzbDrone.Core.Parser.Model; - -namespace NzbDrone.Core.Indexers.PassThePopcorn -{ - public class PassThePopcornInfo : TorrentInfo - { - public bool? Golden { get; set; } - public bool? Scene { get; set; } - public bool? Approved { get; set; } - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornParser.cs b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornParser.cs index 46273b077..d7ce9c862 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornParser.cs @@ -94,7 +94,7 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn // Only add approved torrents try { - torrentInfos.Add(new PassThePopcornInfo() + torrentInfos.Add(new TorrentInfo() { Guid = string.Format("PassThePopcorn-{0}", id), Title = title, @@ -104,9 +104,6 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn Seeders = int.Parse(torrent.Seeders), Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders), PublishDate = torrent.UploadTime.ToUniversalTime(), - Golden = torrent.GoldenPopcorn, - Scene = torrent.Scene, - Approved = torrent.Checked, ImdbId = result.ImdbId.IsNotNullOrWhiteSpace() ? int.Parse(result.ImdbId) : 0, IndexerFlags = flags, MinimumRatio = 1, diff --git a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornRequestGenerator.cs index 40c1fd867..3bb7a3ff2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornRequestGenerator.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Parser; namespace NzbDrone.Core.Indexers.PassThePopcorn { @@ -37,9 +39,21 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn private IEnumerable<IndexerRequest> GetRequest(string searchParameters) { + var queryParams = new NameValueCollection + { + { "action", "advanced" }, + { "json", "noredirect" }, + { "searchstr", searchParameters } + }; + + if (Settings.FreeleechOnly) + { + queryParams.Add("freetorrent", "1"); + } + var request = new IndexerRequest( - $"{Settings.BaseUrl.Trim().TrimEnd('/')}/torrents.php?action=advanced&json=noredirect&searchstr={searchParameters}", + $"{Settings.BaseUrl.Trim().TrimEnd('/')}/torrents.php?{queryParams.GetQueryString()}", HttpAccept.Json); request.HttpRequest.Headers["ApiUser"] = Settings.APIUser; diff --git a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornSettings.cs index cf0ea42e5..8e7eabafc 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornSettings.cs @@ -22,12 +22,15 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn { } - [FieldDefinition(2, Label = "APIUser", HelpText = "These settings are found in your PassThePopcorn security settings (Edit Profile > Security).", Privacy = PrivacyLevel.UserName)] + [FieldDefinition(2, Label = "API User", HelpText = "These settings are found in your PassThePopcorn security settings (Edit Profile > Security).", Privacy = PrivacyLevel.UserName)] public string APIUser { get; set; } [FieldDefinition(3, Label = "API Key", HelpText = "Site API Key", Privacy = PrivacyLevel.ApiKey)] public string APIKey { get; set; } + [FieldDefinition(4, Label = "Freeleech Only", HelpText = "Return only freeleech torrents", Type = FieldType.Checkbox)] + public bool FreeleechOnly { get; set; } + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); From 0db804b6473af178b480f490d52a13cac73ae2a6 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 20 Jun 2022 21:39:20 -0500 Subject: [PATCH 0490/2320] Fixed: (Exoticaz) Category parsing kills search/feed Fixes #938 --- .../Files/Indexers/Exoticaz/recentfeed.json | 5684 +++++++++++++++++ .../AvistazTests/ExoticazFixture.cs | 63 + .../Definitions/Avistaz/AvistazApi.cs | 2 +- .../Indexers/Definitions/ExoticaZ.cs | 2 +- 4 files changed, 5749 insertions(+), 2 deletions(-) create mode 100644 src/NzbDrone.Core.Test/Files/Indexers/Exoticaz/recentfeed.json create mode 100644 src/NzbDrone.Core.Test/IndexerTests/AvistazTests/ExoticazFixture.cs diff --git a/src/NzbDrone.Core.Test/Files/Indexers/Exoticaz/recentfeed.json b/src/NzbDrone.Core.Test/Files/Indexers/Exoticaz/recentfeed.json new file mode 100644 index 000000000..7375e1e16 --- /dev/null +++ b/src/NzbDrone.Core.Test/Files/Indexers/Exoticaz/recentfeed.json @@ -0,0 +1,5684 @@ +{ + "current_page": 1, + "data": [ + { + "id": 64040, + "url": "https://exoticaz.to/torrent/64040-ssis-419-my-first-experience-is-yua-mikami-from-the-day-i-lost-my-virginity-i-was-devoted-to-sex", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "asdjfiasdf54asd7f4a2sdf544asdf", + "file_name": "[SSIS-419] My first experience is Yua Mikami. From the day I lost my virginity, I was devoted to sex.", + "file_size": 7085405541, + "file_count": 1, + "seed": 33, + "leech": 0, + "completed": 55, + "downloaded": 63, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "43": "solo", + "140": "cherry.boy", + "144": "documentary" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/6/f/8/h575yci3htvz.jpg", + "images/torrent/7/b/0/jg4blxyctslq.jpg", + "images/torrent/9/6/7/k8cgjcycayko.jpg", + "images/torrent/2/4/e/pjesasbfcs94.jpg", + "images/torrent/7/6/0/4w1jqpp6ay4p.jpg", + "images/torrent/c/0/3/ju3oryahz3x9.jpg", + "images/torrent/d/2/a/z3aqnfphlmwz.jpg", + "images/torrent/e/0/0/ufkqmbedbx9o.jpg", + "images/torrent/1/4/0/mxgwdlpk4pt2.jpg" + ], + "description": "<p>[SSIS-419] My first experience is Yua Mikami. From the day I lost my virginity, I was devoted to sex.</p>\n<p>Actress: Yua Mikami</p>\n<p>Studio: S1 NO.1 STYLE</p>\n<p>Runtime: 2:41:00</p>\n<p>Movies Genres: Minimal Mosaic,Cherry Boy,Documentary,Featured Actress,Idol & Celebrity</p>", + "created_at": "2022-06-11 11:04:50" + }, + { + "id": 61953, + "url": "https://exoticaz.to/torrent/61953-ssis-338-ultimate-lover-swamp-ideal-sex-only-relationship-that-is-not-disturbed-by-work-or-family-with-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSIS-338] Ultimate Lover Swamp. Ideal Sex-Only Relationship That Is Not Disturbed By Work Or Family With Yua Mikami", + "file_size": 25545844745, + "file_count": 1, + "seed": 16, + "leech": 0, + "completed": 35, + "downloaded": 45, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "6": "2160p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "35": "prostitute", + "153": "cheating", + "802": "story" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/1/7/7/53lsgh50a3j6.jpg", + "images/torrent/c/8/a/5vn0qzyarggi.jpg", + "images/torrent/1/a/3/ct0betxweekr.jpg", + "images/torrent/c/8/7/9cc7oppsrfvt.jpg", + "images/torrent/0/5/2/ksglz4vocodc.jpg", + "images/torrent/9/9/1/zmfpijczinkv.jpg", + "images/torrent/f/2/b/jtwvffw5oxvx.jpg", + "images/torrent/2/d/d/vuudmjrbccfn.jpg", + "images/torrent/c/8/a/u5dgqwhfse7u.jpg", + "images/torrent/1/c/4/shtm7dyjq3jk.jpg", + "images/torrent/f/1/9/bqnfhim3ajpv.jpg", + "images/torrent/3/3/c/lftughbb3gge.jpg", + "images/torrent/1/6/5/pctsv9eoiyqs.jpg", + "images/torrent/0/4/0/gsuctius9zw2.jpg" + ], + "description": "<p>https://www.r18.com/videos/vod/movies/detail/-/id=ssis00338/</p>\n<p>SSIS-338</p>\n<p>Ultimate Lover Swamp. Ideal Sex-Only Relationship That Is Not Disturbed By Work Or Family With Yua Mikami</p>", + "created_at": "2022-05-23 23:41:25" + }, + { + "id": 61947, + "url": "https://exoticaz.to/torrent/61947-ssis-313-yua-mikamis-ecstasy-lotion-special-offering-the-best-ever-slick-servicing-to-work-cum-loads-out", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSIS-313] Yua Mikami's Ecstasy Lotion Special. Offering The Best-ever Slick Servicing To Work Cum Loads Out.", + "file_size": 25756020462, + "file_count": 1, + "seed": 9, + "leech": 0, + "completed": 26, + "downloaded": 39, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "6": "2160p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "41": "big.tits", + "83": "oil.or.lotion", + "102": "idol", + "566": "boob.job" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/f/4/1/hznvqp2hvylv.jpg", + "images/torrent/c/8/6/5nhm3amvrejd.jpg", + "images/torrent/2/e/c/b1o7wwjmmlj7.jpg", + "images/torrent/4/5/e/dxay66t39d8n.jpg", + "images/torrent/e/2/8/gicjrs1fqzcs.jpg", + "images/torrent/9/3/f/eqzc9ibhik8f.jpg", + "images/torrent/5/1/8/flfaualr5g4y.jpg", + "images/torrent/5/1/e/zp5gkc002lip.jpg", + "images/torrent/d/6/e/hdhnwguegx56.jpg", + "images/torrent/e/3/d/xwrptcvja4zh.jpg", + "images/torrent/f/a/9/00xqbfynwztu.jpg", + "images/torrent/0/0/e/g6tquwvlmfdx.jpg" + ], + "description": "<p>https://www.r18.com/videos/vod/movies/detail/-/id=ssis00313/</p>\n<p>SSIS-313</p>\n<p>Yua Mikami's Ecstasy Lotion Special. Offering The Best-ever Slick Servicing To Work Cum Loads Out.</p>", + "created_at": "2022-05-23 08:34:34" + }, + { + "id": 61630, + "url": "https://exoticaz.to/torrent/61630-ssis-287-drool-the-effects-of-a-few-sips-her-face-during-sex-and-peeing-released-all-at-once-yua-mikami-flies-indecently", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSIS-287] Drool, The Effects Of A Few Sips, Her Face During Sex, And Peeing Released All At Once. Yua Mikami Flies Indecently.", + "file_size": 26231683997, + "file_count": 1, + "seed": 11, + "leech": 0, + "completed": 28, + "downloaded": 40, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "6": "2160p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "41": "big.tits", + "102": "idol", + "143": "nympho", + "187": "squirting" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/4/6/8/1y53gyyxtuih.jpg", + "images/torrent/d/7/3/8na713cczcr1.jpg", + "images/torrent/3/e/5/uisihqqtwjqf.jpg", + "images/torrent/c/3/d/tyrwg8xxf1cj.jpg", + "images/torrent/a/1/c/3kvqfiwahsjo.jpg", + "images/torrent/9/0/2/unamlwrlyogd.jpg", + "images/torrent/7/0/c/ddixls4ybads.jpg", + "images/torrent/9/1/d/ac336go2hrtt.jpg", + "images/torrent/f/4/6/rqpblzbhhp0i.jpg", + "images/torrent/b/b/e/kgegqvb0awyb.jpg", + "images/torrent/c/9/9/yunvdx0h2ycy.jpg", + "images/torrent/2/8/2/5xbxcf4mt5ge.jpg", + "images/torrent/c/b/3/irduhyox5vhx.jpg", + "images/torrent/e/8/a/0duhy1otblnq.jpg", + "images/torrent/f/0/a/no82eccbjkna.jpg", + "images/torrent/a/7/9/nwupqewhqlsm.jpg", + "images/torrent/6/b/0/rxiebxjiooet.jpg", + "images/torrent/e/4/c/rumst0y5vcpr.jpg", + "images/torrent/f/2/5/kdihq6gibacb.jpg" + ], + "description": "<p>https://www.r18.com/videos/vod/movies/detail/-/id=ssis00287/</p>\n<p>SSIS-287</p>\n<p>Drool, The Effects Of A Few Sips, Her Face During Sex, And Peeing Released All At Once. Yua Mikami Flies Indecently.</p>", + "created_at": "2022-05-21 10:25:32" + }, + { + "id": 61514, + "url": "https://exoticaz.to/torrent/61514-ssis-241-forbidden-teacher-love-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSIS-241] Forbidden Teacher Love. Yua Mikami", + "file_size": 20750441566, + "file_count": 1, + "seed": 11, + "leech": 0, + "completed": 30, + "downloaded": 42, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "6": "2160p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "41": "big.tits", + "102": "idol", + "109": "teacher" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/d/f/2/18zsu5rebm4x.jpg", + "images/torrent/5/3/c/1olglatua5hl.jpg", + "images/torrent/1/d/7/pve7fwcxkvhz.jpg", + "images/torrent/f/e/9/xuur246m2nzl.jpg", + "images/torrent/5/5/a/fzs20dpirvry.jpg", + "images/torrent/9/3/b/mejcprimizz2.jpg", + "images/torrent/9/9/2/zgwlijvmabkd.jpg", + "images/torrent/d/0/0/pml3micdox3n.jpg", + "images/torrent/3/1/d/q9kvedzbr9h8.jpg", + "images/torrent/e/2/a/ujrvmtgjakko.jpg" + ], + "description": "<p>https://www.r18.com/videos/vod/movies/detail/-/id=ssis00241/</p>\n<p>SSIS-241</p>\n<p>Forbidden Teacher Love. Yua Mikami</p>", + "created_at": "2022-05-20 09:17:10" + }, + { + "id": 59929, + "url": "https://exoticaz.to/torrent/59929-ssis-392-lets-do-it-at-a-mens-massage-parlor-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSIS-392] Let's Do It At A Men's Massage Parlor. Yua Mikami", + "file_size": 5189209526, + "file_count": 1, + "seed": 35, + "leech": 0, + "completed": 96, + "downloaded": 106, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "83": "oil.or.lotion", + "167": "massage", + "629": "salon" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/3/b/9/qquasgwre4tb.jpg", + "images/torrent/2/6/0/gldb2b3ehlr8.jpg", + "images/torrent/1/4/9/knl6ubdnjhjc.jpg", + "images/torrent/d/a/0/cfqmjn2lawhr.jpg", + "images/torrent/a/7/4/bmiv2yflo9bp.jpg", + "images/torrent/2/f/6/fnb9ii5dshru.jpg", + "images/torrent/5/4/b/mfnt1u6zvs4d.jpg", + "images/torrent/c/4/a/hycbduxlw3ei.jpg" + ], + "description": "<p><strong>[SSIS-392] Let's Do It At A Men's Massage Parlor. Yua Mikami</strong></p>\n<p><strong>+++ [FHD] SSIS-392 メンエスでしようよ 三上悠亜</strong></p>\n<p><strong>ID:</strong> SSIS-392<br><strong>Release Date:</strong> May 6, 2022<br><strong>Runtime:</strong> 1 hour 58 minutes 59 seconds [01:59:00]<br><strong>Studio:</strong> S1 NO.1 STYLE<br><strong>Label:</strong> S1 NO.1 STYLE<br><strong>Director:</strong> TAKE-D<br><strong>Series:</strong> A Super Gorgeous Men's Massage Parlor<br><strong>Actresses:</strong> Yua Mikami<br><strong>Categories:</strong> Featured Actress, Idol & Celebrity, Massage Parlor, Lotion, Minimal Mosaic, Hi-Def, 4K<br><br></p>\n<p><strong>Website:</strong> https://s1s1s1.com/works/detail/SSIS392/ <br><strong>R18:</strong> https://www.r18.com/videos/vod/movies/detail/-/id=ssis00392/ <br><strong>DMM:</strong> https://www.dmm.co.jp/digital/videoa/-/detail/=/cid=ssis00392/</p>\n<p>Uploaded by a Bot</p>", + "created_at": "2022-05-06 03:48:23" + }, + { + "id": 58235, + "url": "https://exoticaz.to/torrent/58235-ssis-365-what-were-gonna-fuck-here-sticking-close-to-yua-mikami-for-a-whole-month-taking-advantage-any-time-theres-a-chance-for-a-quick-fuck-unprecedented-hidden-camera-av-primetime-challenge", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSIS-365] \"What!? We're Gonna Fuck Here?\" Sticking Close To Yua Mikami For A Whole Month, Taking Advantage Any Time There's A Chance For A Quick Fuck! Unprecedented Hidden Camera AV Primetime Challenge.", + "file_size": 5688524831, + "file_count": 1, + "seed": 21, + "leech": 0, + "completed": 101, + "downloaded": 115, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "41": "big.tits", + "922": "quickie" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/d/b/0/fqfa4na7kcgu.jpg", + "images/torrent/6/7/6/1zcrbafgogfs.jpg", + "images/torrent/2/7/3/arjaynlhkdnx.jpg", + "images/torrent/f/5/2/aql5ycrgxot9.jpg", + "images/torrent/e/6/3/tklisetis3vp.jpg", + "images/torrent/b/4/a/3lrarw6xf0ad.jpg", + "images/torrent/a/e/a/fk8rbwmbfixo.jpg", + "images/torrent/3/6/1/6fuhfb5kcbpz.jpg" + ], + "description": "<p><strong>[SSIS-365] \"What!? We're Gonna Fuck Here?\" Sticking Close To Yua Mikami For A Whole Month, Taking Advantage Any Time There's A Chance For A Quick Fuck! Unprecedented Hidden Camera AV Primetime Challenge.</strong></p>\n <p><strong>+++ [HD] SSIS-365 「えっ!ここでヤルの?」三上悠亜に一ヶ月密着して隙あらばいきなり即ズボッ! 前代未聞ドッキリAV大作戦</strong></p>\n <p><strong>ID:</strong> SSIS-365<br>\n <strong>Release Date:</strong> Apr 8, 2022<br>\n <strong>Runtime:</strong> 2 hours 5 minutes 59 seconds\n [02:06:00]<br>\n <strong>Studio:</strong> S1 NO.1 STYLE<br>\n <strong>Label:</strong> S1 NO.1 STYLE<br>\n <strong>Director:</strong> Kyosei<br>\n <strong>Series:</strong> -<br>\n <strong>Actresses:</strong> Yua Mikami<br>\n <strong>Categories:</strong> Big Tits, Quickie, Featured Actress, Blowjob, Minimal Mosaic, Hi-Def<br><br>\n </p><p><strong>Website:</strong> https://s1s1s1.com/works/detail/SSIS365/</p>\n<p><strong>R18:</strong> https://www.r18.com/videos/vod/movies/detail/-/id=ssis00365/</p><p>Uploaded by a Bot</p>", + "created_at": "2022-04-08 06:31:27" + }, + { + "id": 57416, + "url": "https://exoticaz.to/torrent/57416-yua-mikami-collection-june-2015-march-2022", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "4": "Pornstar Pack" + }, + "info_hash": "(removed)", + "file_name": "Yua Mikami collection June 2015 ~ March 2022", + "file_size": 838526969892, + "file_count": 119, + "seed": 30, + "leech": 13, + "completed": 91, + "downloaded": 215, + "upload_multiply": 1, + "download_multiply": 0, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p", + "6": "2160p", + "8": "VR 180°" + }, + "studios": { + "10": "S1 No.1 Style", + "38": "MUTEKI" + }, + "tags": { + "41": "big.tits", + "100": "creampie", + "104": "dirty.talk", + "109": "teacher", + "165": "facial", + "462": "virtual.reality", + "574": "affair", + "578": "bathing.suit", + "802": "story", + "1968": "cunnilingus", + "2065": "yearly.pack" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/8/b/7/9mxg59pcyiue.jpg", + "images/torrent/4/7/4/cxemylviqkzh.jpg", + "images/torrent/4/e/8/01mlqgkbuhzi.jpg", + "images/torrent/8/5/d/ldymkrn3kyft.jpg", + "images/torrent/4/0/1/fsxvb9doww0k.jpg", + "images/torrent/3/5/7/e1bdumpl3aid.jpg", + "images/torrent/7/b/a/i4yxizmuzpat.jpg", + "images/torrent/6/3/c/qfese0fj7tgg.jpg", + "images/torrent/5/a/c/u5x5p382k6mx.jpg", + "images/torrent/f/8/0/cau3cpihqbab.jpg", + "images/torrent/3/8/6/fzmkxvebb1fx.jpg", + "images/torrent/0/7/b/h9id92epz1dc.jpg", + "images/torrent/a/4/c/buhvv6xajoms.jpg", + "images/torrent/6/1/5/uoh4tlvbwa2t.jpg", + "images/torrent/c/4/d/stm4af4utbfy.jpg", + "images/torrent/e/1/2/zx5saiuasdn1.jpg", + "images/torrent/b/9/c/jznyowsomjdz.jpg", + "images/torrent/3/7/7/guotleycrnqd.jpg", + "images/torrent/6/6/4/gdjpqxdcg0le.jpg", + "images/torrent/b/f/5/ugflvqz1npc6.jpg", + "images/torrent/f/c/c/bixq8bk3c1ij.jpg", + "images/torrent/9/a/9/bb2biqfjee6x.jpg", + "images/torrent/6/7/9/oijpdpqswtch.jpg", + "images/torrent/b/4/1/zjzdqcripacu.jpg", + "images/torrent/d/6/6/46lqz0sv0vdd.jpg", + "images/torrent/2/8/d/puyiwfm9eypy.jpg", + "images/torrent/2/0/f/ysfiv31o790s.jpg", + "images/torrent/5/6/b/omfyf7fgqa0u.jpg", + "images/torrent/c/2/2/ur8q5uv5tv6h.jpg", + "images/torrent/0/5/8/kav57rdaibzj.jpg", + "images/torrent/8/7/f/j0qbisvkjg64.jpg", + "images/torrent/7/9/0/pi1ve5bp2zrl.jpg", + "images/torrent/d/d/5/hklbfmy0kni7.jpg", + "images/torrent/5/f/3/zixgvuvu7kmk.jpg", + "images/torrent/a/b/1/pszluy81rmir.jpg", + "images/torrent/6/c/f/sqgpcxcsvvlg.jpg", + "images/torrent/c/9/0/wt9hlkju9dpl.jpg", + "images/torrent/d/e/9/czh512ocn0qx.jpg", + "images/torrent/6/8/d/nunvab4bsd1h.jpg", + "images/torrent/d/0/d/2mwcbnb9y9yw.jpg", + "images/torrent/9/a/6/mogl57itapm5.jpg", + "images/torrent/5/6/8/cwohdjy4x0ql.jpg", + "images/torrent/4/b/d/3utog1no5qu6.jpg", + "images/torrent/9/1/d/6ka4vcsymkbw.jpg", + "images/torrent/e/d/3/ntxsk9wbggbq.jpg", + "images/torrent/5/6/7/zvuc87ez3fzf.jpg", + "images/torrent/2/8/0/mvsyyx7ayjzl.jpg", + "images/torrent/a/e/6/eyrtkp8jgaba.jpg", + "images/torrent/0/4/7/uaaojlm9hzvn.jpg", + "images/torrent/4/f/9/pnqvzhlg0kwj.jpg", + "images/torrent/a/e/9/6wqst9p0jy4y.jpg", + "images/torrent/5/6/6/kd4xrqhwmrim.jpg", + "images/torrent/2/8/c/wqdsd9elfywy.jpg", + "images/torrent/0/b/7/ivdhuodkurws.jpg", + "images/torrent/f/b/b/okzymk1y0lgy.jpg", + "images/torrent/3/5/4/lhxyfu1x9oba.jpg", + "images/torrent/0/8/e/ljy7k4bwovhg.jpg", + "images/torrent/4/e/b/eixpv7opuosz.jpg", + "images/torrent/a/3/2/hdhkabqarjoh.jpg", + "images/torrent/f/2/2/g09iisao2ldt.jpg", + "images/torrent/4/6/c/qcmvpdnlju5f.jpg", + "images/torrent/f/9/5/yjmlqjde4utu.jpg", + "images/torrent/2/a/3/m0lywpkggcpf.jpg", + "images/torrent/7/e/9/zdlemg4pgoer.jpg", + "images/torrent/2/b/f/ka3cq8dniowe.jpg", + "images/torrent/8/a/9/ale0fyervlgx.jpg", + "images/torrent/d/0/b/tolrt23ghr3o.jpg", + "images/torrent/8/f/e/l08pxpb8q7o2.jpg", + "images/torrent/7/9/4/vczpqesgd4ky.jpg", + "images/torrent/4/4/4/7d0zrg1jghpe.jpg", + "images/torrent/d/8/9/6tjmmyrpmilt.jpg", + "images/torrent/4/a/6/cjbvrabhg2pp.jpg", + "images/torrent/2/8/3/7curnjw9k35u.jpg", + "images/torrent/6/d/2/juo3vn9c5xri.jpg", + "images/torrent/e/6/8/xhlyighcojdf.jpg", + "images/torrent/5/f/6/bpyfki0vjwof.jpg", + "images/torrent/f/6/2/km4kcqilyyjz.jpg", + "images/torrent/c/e/f/sxfvygcvzgos.jpg", + "images/torrent/9/5/d/svv00iksbted.jpg", + "images/torrent/e/8/5/wwhsxwji0dod.jpg", + "images/torrent/4/b/6/pdhc6lbsznjy.jpg", + "images/torrent/9/8/a/ryloa9s6b3al.jpg", + "images/torrent/c/4/5/6gsdtn0qw0bk.jpg", + "images/torrent/a/d/0/svx5wxj02duw.jpg", + "images/torrent/f/3/5/hdwsrxecoctx.jpg", + "images/torrent/e/8/9/gsaklaafqtce.jpg", + "images/torrent/1/7/8/c3fkvtd0xlgf.jpg", + "images/torrent/8/d/3/ip91re9gehs3.jpg", + "images/torrent/2/8/2/kqycky8etgys.jpg", + "images/torrent/c/6/5/lokzdr1km94i.jpg", + "images/torrent/6/e/e/v1pdbqpaq6du.jpg", + "images/torrent/f/8/a/sxpmxgjv4mmd.jpg", + "images/torrent/6/6/b/kqgvz3b8z0kl.jpg", + "images/torrent/f/0/2/uxfc5hmcwnlf.jpg", + "images/torrent/2/2/b/uu4tbtcqtppu.jpg", + "images/torrent/a/4/5/0gdqaq3bk3hj.jpg", + "images/torrent/3/d/e/hevgqw0ejd8p.jpg", + "images/torrent/0/9/3/rrr8xzoobrzf.jpg", + "images/torrent/1/a/f/kxs0afa4dkuz.jpg", + "images/torrent/5/b/7/gqmubjyvlrpq.jpg", + "images/torrent/2/b/b/v6xrnu0pxx2l.jpg", + "images/torrent/2/6/3/remao5gz4beh.jpg", + "images/torrent/4/6/0/4cw9xxfnqf1o.jpg", + "images/torrent/2/b/f/ojw8mlrtvqcq.jpg", + "images/torrent/c/a/3/9f4zagmoc8qo.jpg", + "images/torrent/d/8/8/fg6otfj2vnh5.jpg", + "images/torrent/b/5/3/pphvlvjae6rw.jpg", + "images/torrent/5/6/2/lzhh4vsyktgx.jpg", + "images/torrent/7/8/2/zak71iumpxxo.jpg", + "images/torrent/0/3/0/7fpc2v8jvyaj.jpg", + "images/torrent/1/5/7/zjkxdkbdminf.jpg", + "images/torrent/d/a/7/zitz5vyfr8wh.jpg", + "images/torrent/4/0/2/nmt3j6jobzig.jpg", + "images/torrent/3/7/f/0zykbgirivlb.jpg", + "images/torrent/7/9/6/t2umlxq92fr0.jpg", + "images/torrent/9/1/6/tr26x7defr0j.jpg", + "images/torrent/e/8/1/m3qdoggx0sje.jpg", + "images/torrent/d/a/7/77bfmmlb9rze.jpg", + "images/torrent/0/8/d/s2fwywmziojy.jpg", + "images/torrent/4/b/c/wmq3qoxnt0wv.jpg", + "images/torrent/6/a/8/2iz1yl1doq6j.jpg", + "images/torrent/8/f/b/lizaaqqtaxqs.jpg", + "images/torrent/5/f/2/fzhdu3s2j9vr.jpg", + "images/torrent/c/1/9/xqqetsuhep6f.jpg", + "images/torrent/b/5/9/1tkt156w3ki2.jpg", + "images/torrent/4/6/6/evc2imhomzjj.jpg", + "images/torrent/8/a/2/r4rzucuedssd.jpg", + "images/torrent/7/2/f/qlfxdhblwchz.jpg", + "images/torrent/f/f/a/ngdzplijermo.jpg", + "images/torrent/5/1/9/43fyxktztsqk.jpg", + "images/torrent/8/a/4/aktsjxwfeye5.jpg", + "images/torrent/7/0/4/msgfeq9bjuik.jpg", + "images/torrent/3/3/3/lwhnud4shdra.jpg", + "images/torrent/4/1/b/dg5cmqbupfas.jpg", + "images/torrent/7/3/9/9z1stdxhai5o.jpg", + "images/torrent/1/8/7/fowrhuuzg9le.jpg", + "images/torrent/4/4/0/e3zccstusrrn.jpg", + "images/torrent/b/5/f/7r4d3wxrfwim.jpg", + "images/torrent/5/a/b/dnpuwukrwlg9.jpg", + "images/torrent/6/5/5/godksjash5mf.jpg", + "images/torrent/3/e/a/vgtuterqyteq.jpg", + "images/torrent/1/a/0/87gz3l7dy2st.jpg", + "images/torrent/7/8/f/ajripgwyhaqa.jpg", + "images/torrent/2/b/8/kuegvu8s4iod.jpg", + "images/torrent/d/6/b/v6i88i7lelne.jpg", + "images/torrent/b/7/0/ruktjdz6nt7o.jpg", + "images/torrent/c/b/c/iunijgaj2jyy.jpg", + "images/torrent/c/e/d/pdz7jfbawzhh.jpg", + "images/torrent/5/1/5/qtsvpslcdvc2.jpg", + "images/torrent/c/7/d/qtjvts7hapu1.jpg", + "images/torrent/4/1/0/qcdwxxaabxt6.jpg", + "images/torrent/b/8/9/jt51ab0v856r.jpg", + "images/torrent/e/9/6/wtelmvhkoxbm.jpg", + "images/torrent/f/d/9/r7uayadwwda9.jpg", + "images/torrent/e/7/7/xi8e3kbmy1pj.jpg", + "images/torrent/d/a/9/g6svyqqwd5iq.jpg", + "images/torrent/5/c/b/2wh3zotufuhr.jpg", + "images/torrent/7/f/8/hxp4og0zrxmm.jpg", + "images/torrent/0/d/1/6e6msgn99e2k.jpg", + "images/torrent/d/4/0/hwf9ozrmkezt.jpg", + "images/torrent/d/5/c/eu7emwfh5yij.jpg", + "images/torrent/2/b/6/kaxndtmzkuaa.jpg", + "images/torrent/c/2/1/nj2chdheiq1g.jpg", + "images/torrent/1/f/5/on2q7whomqzt.jpg", + "images/torrent/3/2/1/mnpu9lpbdpor.jpg", + "images/torrent/8/e/8/4ftfoffjylip.jpg", + "images/torrent/2/9/2/gld1mtgpjbfq.jpg", + "images/torrent/6/a/3/8qumepxsxcge.jpg", + "images/torrent/5/3/0/erclqimkhmyf.jpg", + "images/torrent/c/7/6/6tmfvbqmjpv8.jpg", + "images/torrent/0/d/f/fmp79njihjor.jpg", + "images/torrent/6/2/2/2spexk0uovwh.jpg", + "images/torrent/6/a/7/dja0lmbwk1zb.jpg", + "images/torrent/f/0/2/cnenzfsu1j98.jpg", + "images/torrent/e/7/5/7mk3btujs6io.jpg", + "images/torrent/d/1/2/ymk5klfx3hye.jpg", + "images/torrent/7/d/d/grybcca8lvyi.jpg", + "images/torrent/a/7/d/1lyb3dkshiop.jpg", + "images/torrent/8/4/a/gurlsuo4zj40.jpg", + "images/torrent/6/9/9/tdtzckfffp7w.jpg", + "images/torrent/8/f/b/qgmyjstl9kf4.jpg", + "images/torrent/4/d/b/vumazzxxdrzh.jpg", + "images/torrent/c/3/7/cqwkglj8ovwy.jpg", + "images/torrent/6/5/8/adphhvihbvew.jpg", + "images/torrent/c/5/1/uo9vqcqw7qaa.jpg", + "images/torrent/3/3/f/ixxcuhopstph.jpg", + "images/torrent/e/5/8/moqbrfwncygz.jpg", + "images/torrent/9/a/4/ojttslgrjfyp.jpg", + "images/torrent/5/6/c/tryhideukegk.jpg", + "images/torrent/3/8/6/t8exucqdhyah.jpg", + "images/torrent/b/5/9/snpj5sxq4hby.jpg", + "images/torrent/a/4/5/lexdb8ueufbk.jpg", + "images/torrent/f/9/c/n5xxdswnzqp7.jpg", + "images/torrent/0/3/0/s7moglsdat82.jpg", + "images/torrent/4/b/8/kajm5w5bormz.jpg", + "images/torrent/0/f/a/dhayxfrkppxo.jpg", + "images/torrent/a/4/3/ti5y6mtrvsis.jpg", + "images/torrent/7/9/5/qqialgqekrga.jpg", + "images/torrent/3/e/6/0eh4df6vbx7g.jpg", + "images/torrent/e/8/d/22zmtxijbkyo.jpg", + "images/torrent/a/3/d/zqoz4ywi3xc3.jpg", + "images/torrent/4/c/8/0vfkaamwvzoa.jpg", + "images/torrent/8/a/4/03hmklkagiwr.jpg", + "images/torrent/b/a/0/zkglan8ogh8g.jpg", + "images/torrent/f/e/6/we2jcrqey4kw.jpg", + "images/torrent/d/3/f/lt1dyd2laqra.jpg", + "images/torrent/0/4/d/ujadbdrvuzct.jpg", + "images/torrent/4/6/d/wrc9ufigztc1.jpg", + "images/torrent/9/2/1/rq9yr0xwc52l.jpg", + "images/torrent/8/d/b/2wgnxopajxxe.jpg", + "images/torrent/8/a/8/173wziofthtv.jpg", + "images/torrent/7/0/2/wvxgfnnoo85j.jpg", + "images/torrent/2/1/5/aicqqlh7y2bb.jpg", + "images/torrent/3/8/f/hxzly7alqt9f.jpg" + ], + "description": null, + "created_at": "2022-03-29 20:58:49" + }, + { + "id": 56332, + "url": "https://exoticaz.to/torrent/56332-ofje-304-gorgeous-big-tits-bouncing-all-over-the-place-yua-mikami-decensored-by-ai", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[OFJE-304] Gorgeous Big Tits Bouncing All Over The Place! [Yua Mikami - Decensored by AI]", + "file_size": 3514186774, + "file_count": 1, + "seed": 146, + "leech": 1, + "completed": 517, + "downloaded": 641, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "165": "facial", + "187": "squirting", + "383": "hairy.pussy", + "620": "big.areola", + "1390": "decensored", + "2059": "ai.decensored" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/4/8/9/fh1ew9iegmwx.jpg", + "images/torrent/e/4/8/mpnlbhsxsaol.jpg", + "images/torrent/c/a/8/0kp5sr2b4ryu.jpg", + "images/torrent/a/c/5/qhigtwk2qgtd.jpg", + "images/torrent/2/9/6/bw4kyn1ckz5u.jpg" + ], + "description": "<p>De-censored with AI algorithm. </p>\n<p>Originated from [OFJE-304] Gorgeous Big Tits Bouncing All Over The Place! All G-Cup And Bigger Actresses Ride Dick Until They Cum 50 Rounds</p>\n<p>+++ [HD] OFJE-304 縦横無尽に神乳が揺れまくりっ!オールGcup超えS1女優のおっぱい激揺れ激イキ激ピスSEX50本番</p>\n<p>https://www.r18.com/videos/vod/movies/detail/-/id=ofje00304/</p>", + "created_at": "2022-03-10 09:06:27" + }, + { + "id": 56108, + "url": "https://exoticaz.to/torrent/56108-ssis-338-ultimate-lover-swamp-ideal-sex-only-relationship-that-is-not-disturbed-by-work-or-family-with-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSIS-338] Ultimate Lover Swamp. Ideal Sex-Only Relationship That Is Not Disturbed By Work Or Family With Yua Mikami", + "file_size": 7958148356, + "file_count": 1, + "seed": 37, + "leech": 0, + "completed": 150, + "downloaded": 176, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "153": "cheating", + "802": "story" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/0/8/8/vfdvlgil0h5r.jpg", + "images/torrent/2/3/2/wcucy9v6erbg.jpg", + "images/torrent/7/5/1/fab5wasruonv.jpg", + "images/torrent/3/e/2/qa1hbvipajty.jpg", + "images/torrent/8/e/1/f7nicyjvi53g.jpg", + "images/torrent/2/7/0/ouqci7ot71ku.jpg", + "images/torrent/e/7/8/0dmhig6hzjbo.jpg", + "images/torrent/0/0/0/kqggybnirddd.jpg", + "images/torrent/1/2/3/rieqetllmh3o.jpg", + "images/torrent/4/7/5/c37ccemtm6tt.jpg", + "images/torrent/d/6/b/gexzyognkxeb.jpg" + ], + "description": "<p><strong>[SSIS-338] Ultimate Lover Swamp. Ideal Sex-Only Relationship That Is Not Disturbed By Work Or Family With Yua Mikami</strong></p>\n <p><strong>+++ [HD] SSIS-338 最高の愛人沼 仕事にも家庭にも干渉してこない、セックスだけの理想関係を三上悠亜と…。</strong></p>\n <p><strong>ID:</strong> SSIS-338<br>\n <strong>Release Date:</strong> Mar 4, 2022<br>\n <strong>Runtime:</strong> 2 hours 25 minutes 59 seconds\n [02:26:00]<br>\n <strong>Studio:</strong> S1 NO.1 STYLE<br>\n <strong>Label:</strong> S1 NO.1 STYLE<br>\n <strong>Director:</strong> Amazing Meat<br>\n <strong>Series:</strong> -<br>\n <strong>Actresses:</strong> Yua Mikami<br>\n <strong>Categories:</strong> Adultery, Featured Actress, Cheating Wife, Drama, Minimal Mosaic, Hi-Def, 4K<br><br>\n </p><p><strong>Website:</strong> https://s1s1s1.com/works/detail/SSIS338/</p>\n<p><strong>R18:</strong> https://www.r18.com/videos/vod/movies/detail/-/id=ssis00338/</p><p>Uploaded by a Bot</p>", + "created_at": "2022-03-04 05:28:49" + }, + { + "id": 54324, + "url": "https://exoticaz.to/torrent/54324-ssis-313-yua-mikamis-ecstasy-lotion-special-offering-the-best-ever-slick-servicing-to-work-cum-loads-out", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSIS-313] Yua Mikami's Ecstasy Lotion Special. Offering The Best-ever Slick Servicing To Work Cum Loads Out.", + "file_size": 8026427033, + "file_count": 1, + "seed": 19, + "leech": 0, + "completed": 103, + "downloaded": 127, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "41": "big.tits", + "83": "oil.or.lotion", + "102": "idol", + "566": "boob.job", + "578": "bathing.suit" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/7/a/4/wrhknrhpsmwr.jpg", + "images/torrent/c/0/b/j5z5jo76mnkd.jpg", + "images/torrent/0/e/1/hjinvnujerts.jpg", + "images/torrent/c/e/e/a7acsezc2eis.jpg", + "images/torrent/1/4/8/fw4vab38or60.jpg", + "images/torrent/d/0/d/gewklv2fzqcv.jpg", + "images/torrent/1/4/b/71ha6x3ll7ms.jpg", + "images/torrent/3/0/1/bi7snqfsepzy.jpg", + "images/torrent/d/1/f/3an8mkns0mlo.jpg", + "images/torrent/a/2/8/rfl3po84hdlb.jpg", + "images/torrent/9/7/d/ujzu5he0deum.jpg" + ], + "description": "<p><strong>[SSIS-313] Yua Mikami's Ecstasy Lotion Special. Offering The Best-ever Slick Servicing To Work Cum Loads Out.</strong></p>\n<p><strong>SSIS-313 三上悠亜の有頂天ローションSP 人生最高ヌルヌルご奉仕で射精させてあげる</strong></p>\n<p><strong>ID:</strong> SSIS-313<br><strong>Release Date:</strong> Feb 4, 2022<br><strong>Runtime:</strong> 2 hours 27 minutes 59 seconds [02:28:00]<br><strong>Studio:</strong> S1 NO.1 STYLE<br><strong>Label:</strong> S1 NO.1 STYLE<br><strong>Director:</strong> TAKE-D<br><strong>Series:</strong> Ecstatic Lotion SP<br><strong>Actresses:</strong> Yua Mikami<br><strong>Categories:</strong> Big Tits, Featured Actress, Idol & Celebrity, Titty Fuck, Lotion, Minimal Mosaic, Hi-Def, 4K<br><br></p>\n<p><strong>Website:</strong> https://s1s1s1.com/works/detail/SSIS313/</p>\n<p><strong>R18:</strong> https://www.r18.com/videos/vod/movies/detail/-/id=ssis00313/</p>", + "created_at": "2022-02-04 07:02:14" + }, + { + "id": 53526, + "url": "https://exoticaz.to/torrent/53526-ofje-281-yua-mikami-x-shame-special-this-national-grade-idol-is-getting-continuously-fucked-8-hours", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[OFJE-281] Yua Mikami x Shame Special This National-Grade Idol Is Getting Continuously Fucked 8 Hours", + "file_size": 21301383406, + "file_count": 4, + "seed": 6, + "leech": 0, + "completed": 57, + "downloaded": 75, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "132": "compilation", + "143": "nympho" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/f/3/5/zwm35c6ihmx6.jpg", + "images/torrent/5/4/6/dm6kfqcjclb9.jpg", + "images/torrent/a/5/d/xvypkvsvmglf.jpg", + "images/torrent/a/7/a/54ck4qhiel6c.jpg", + "images/torrent/1/1/0/occfmiy6uv9b.jpg", + "images/torrent/0/b/5/pxkuuvj4h5zj.jpg", + "images/torrent/1/c/7/haq3z6fauih8.jpg", + "images/torrent/3/5/3/4gjdrlwcydyp.jpg", + "images/torrent/a/8/e/tmfsxnqqdypt.jpg", + "images/torrent/7/d/b/7hm3hwtxgvra.jpg", + "images/torrent/7/f/c/bip402y3m0pa.jpg", + "images/torrent/b/2/b/qahxflwq6ngb.jpg", + "images/torrent/6/8/7/kyccmn3wdgda.jpg", + "images/torrent/7/8/1/54rsa9o1nomp.jpg", + "images/torrent/3/6/7/ajzbgsr21jxd.jpg", + "images/torrent/4/9/0/krxjcqd92xp4.jpg", + "images/torrent/f/e/6/yrnjbemtsqvf.jpg", + "images/torrent/d/6/d/bm7ps6clh7yf.jpg", + "images/torrent/4/8/e/jowfezkiw5rg.jpg", + "images/torrent/7/8/c/lnlkz4fluy2a.jpg", + "images/torrent/a/f/e/wscpcjwtcida.jpg", + "images/torrent/5/0/6/dqbll9040h7p.jpg", + "images/torrent/1/5/9/onn2b25f3js8.jpg", + "images/torrent/3/6/e/e93yudodgbdk.jpg", + "images/torrent/4/d/e/zjoma2mgyyn6.jpg", + "images/torrent/7/d/0/w4lraenuqmos.jpg" + ], + "description": "<p><strong>[OFJE-281] Yua Mikami x Shame Special This National-Grade Idol Is Getting Continuously Fucked 8 Hours</strong></p>\n <p><strong>+++ [HD] OFJE-281 三上悠亜×レ●プSpecial 国民的アイドルをひたすら犯し続ける8時間</strong></p>\n <p><strong>ID:</strong> OFJE-281<br>\n <strong>Release Date:</strong> Nov 6, 2020<br>\n <strong>Runtime:</strong> 7 hours 56 minutes 59 seconds\n [07:57:00]<br>\n <strong>Studio:</strong> S1 NO.1 STYLE<br>\n <strong>Label:</strong> S1 NO.1 STYLE<br>\n <strong>Director:</strong> <br>\n <strong>Series:</strong> S1 GIRLS COLLECTION<br>\n <strong>Actresses:</strong> Yua Mikami<br>\n <strong>Categories:</strong> Beautiful Girl, Featured Actress, Nymphomaniac, Idol & Celebrity, Over 4 Hours, Hi-Def, Actress Best Compilation<br><br>\n </p><p><strong>Website:</strong> https://s1s1s1.com/works/detail/OFJE281/</p>\n<p><strong>R18:</strong> https://www.r18.com/videos/vod/movies/detail/-/id=ofje00281/</p><p>Uploaded by a Bot</p>", + "created_at": "2022-01-26 12:46:09" + }, + { + "id": 52648, + "url": "https://exoticaz.to/torrent/52648-ssis-287-drool-the-effects-of-a-few-sips-her-face-during-sex-and-peeing-released-all-at-once-yua-mikami-flies-indecently", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSIS-287] Drool, The Effects Of A Few Sips, Her Face During Sex, And Peeing Released All At Once. Yua Mikami Flies Indecently.", + "file_size": 8168923326, + "file_count": 1, + "seed": 7, + "leech": 1, + "completed": 70, + "downloaded": 120, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "102": "idol", + "143": "nympho", + "187": "squirting" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/8/e/0/gtjuct7l6shn.jpg", + "images/torrent/c/a/6/rtlotapxd118.jpg", + "images/torrent/5/2/b/9zi0llylqxgv.jpg", + "images/torrent/7/9/4/q7cfygj1unpr.jpg", + "images/torrent/1/7/b/5hnkkmv4onmx.jpg", + "images/torrent/e/9/5/dnh42ovodstr.jpg", + "images/torrent/a/a/f/yprejldwmttb.jpg", + "images/torrent/5/0/e/tnrn9dock5mp.jpg", + "images/torrent/8/7/2/92ph60ekxpkx.jpg" + ], + "description": "<p>Actresses: Yua Mikami<br>Categories<br>Big TitsFeatured ActressNymphomaniacIdol & CelebritySquirtingMinimal MosaicHi-Def4K<br>Studio: S1 NO.1 STYLE <br>Series: Release All At Once And Fly Vulgarly<br> Release date: Jan 7, 2022<br>Runtime: 150min<br>Director: Mon C<br>Label: S1 NO.1 STYLE<br>Content ID: ssis00287<br>DVD ID: SSIS-287<br>Languages: Japanese<br><br></p>", + "created_at": "2022-01-07 13:01:13" + }, + { + "id": 52438, + "url": "https://exoticaz.to/torrent/52438-ssis-270-yua-mikami-earnestly-small-devil-chikubiti-all-round-200-minutes-nipple-licking-blame-rolling-4k-knickerz", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSIS-270] Yua Mikami - Earnestly Small Devil Chikubiti All-round 200 Minutes Nipple Licking Blame Rolling (4K) ~ KnickerZ", + "file_size": 34260760954, + "file_count": 1, + "seed": 7, + "leech": 0, + "completed": 51, + "downloaded": 70, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "6": "2160p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "165": "facial", + "1969": "handjob" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/e/2/f/g5l2v6bcrv1h.jpg", + "images/torrent/2/5/6/cnzzdunqojnt.jpg", + "images/torrent/d/c/c/tyihoxrdy6zb.jpg", + "images/torrent/a/8/1/3zkboujnsmmj.jpg", + "images/torrent/5/d/4/cxgw7dwkrue2.jpg", + "images/torrent/4/3/8/xow7wto0lhck.jpg", + "images/torrent/f/e/f/bfyfh3dahmup.jpg", + "images/torrent/9/d/5/nnrwmevoeh6y.jpg", + "images/torrent/2/6/8/ocs67uzvx7ps.jpg", + "images/torrent/b/c/8/3rlqlrfdjtdm.jpg", + "images/torrent/5/2/9/ysj3lq3t58h4.jpg", + "images/torrent/8/2/5/kkx5cthz2eca.jpg", + "images/torrent/3/2/3/n0auyywcc4vl.gif", + "images/torrent/8/a/4/2ysjt3zr9c3r.jpg", + "images/torrent/5/4/8/4lzuulkhfuyq.jpg", + "images/torrent/0/9/2/yhdsjr2jrf2k.gif" + ], + "description": "<p><a href=\"https://exoticaz.to/torrents?in=1&search=KnickerZ&uploader=&verifier=\"><img src=\"https://i.exoticaz.to/images/torrent/e/3/9/i7bfled2kuss.jpg\" width=\"824\" height=\"300\" alt=\"i7bfled2kuss.jpg\"></a></p>\n<p>[SSIS-270] Yua Mikami - Earnestly Small Devil Chikubiti All-round 200 Minutes Nipple Licking Blame Rolling (4K)</p>\n<p>Scene 1: Yua plays with a toy boob<br>Scene 2: Yua seduces teacher, missionary and cums on tits<br>Various Sex Acts Included : Oral, Doggy, One on One sex, MF sex, Facials, Cumshots, Missionary Sex, Handjob, Blowjobs, Blowbangs, Handjobs, Cowgirl & Reverse-Cowgirl, Deep-throat, Solo tease, Solo Masturbation, Toy/Dildo play, Kissing, etc</p>\n\n<p>                                        <img src=\"https://i.exoticaz.to/images/torrent/0/9/2/yhdsjr2jrf2k.gif\" alt=\"yhdsjr2jrf2k.gif\"></p>", + "created_at": "2022-01-03 12:59:46" + }, + { + "id": 52436, + "url": "https://exoticaz.to/torrent/52436-ssis-211-yua-mikami-youre-at-a-whore-house-and-one-of-japans-top-pornstars-appears-right-in-front-of-you-do-you-fuck-her-or-fuck-off-4k-knickerz", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSIS-211] Yua Mikami - You're At A Whore House, And One Of Japan's Top Pornstars Appears Right In Front Of You! Do You Fuck Her Or Fuck Off? (4K) ~KnickerZ", + "file_size": 30607593774, + "file_count": 1, + "seed": 7, + "leech": 0, + "completed": 44, + "downloaded": 64, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "6": "2160p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "165": "facial", + "401": "forced", + "1968": "cunnilingus" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/2/d/d/ks480u5zoulo.jpg", + "images/torrent/b/4/6/xtcxujqe5vlz.jpg", + "images/torrent/1/7/8/k4n88xlimend.jpg", + "images/torrent/b/e/9/p7edblwbukhr.jpg", + "images/torrent/4/9/b/hrq0ahg6hvhz.jpg", + "images/torrent/8/5/d/pznpyo3wppty.jpg", + "images/torrent/9/0/a/bzffgvkh7mqk.jpg", + "images/torrent/2/7/6/czuknrmmydg4.jpg", + "images/torrent/1/0/9/rj8pemdpmdce.gif" + ], + "description": "<p><a href=\"https://exoticaz.to/torrents?in=1&search=KnickerZ&uploader=&verifier=\"><img src=\"https://i.exoticaz.to/images/torrent/e/3/9/i7bfled2kuss.jpg\" width=\"824\" height=\"300\" alt=\"i7bfled2kuss.jpg\"></a></p>\n<p>[SSIS-211] Yua Mikami - You're At A Whore House, And One Of Japan's Top Pornstars Appears Right In Front Of You! Do You Fuck Her Or Fuck Off? (4K)</p>\n<p>Scene 1: Yua gives a handjob<br>Scene 2: Blowjob & doggy<br>Various Sex Acts Included : Oral, Doggy, One on One sex, MF sex, Facials, Cumshots, Missionary Sex, Handjob, Blowjobs, Blowbangs, Handjobs, Cowgirl & Reverse-Cowgirl, Deep-throat, Solo tease, Solo Masturbation, Toy/Dildo play, Kissing, etc</p>\n\n<p>                                                     <img src=\"https://i.exoticaz.to/images/torrent/1/0/9/rj8pemdpmdce.gif\" alt=\"rj8pemdpmdce.gif\"></p>", + "created_at": "2022-01-03 12:55:28" + }, + { + "id": 52434, + "url": "https://exoticaz.to/torrent/52434-ssis-181-yua-mikami-getting-a-lick-down-from-step-dad-3-full-days-indecency-while-the-husband-is-away-4k-knickerz", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSIS-181] Yua Mikami - Getting A Lick Down From Step-dad. 3 Full Days Indecency While The Husband Is Away (4K) ~ KnickerZ", + "file_size": 26431869854, + "file_count": 1, + "seed": 8, + "leech": 0, + "completed": 55, + "downloaded": 79, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "6": "2160p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "153": "cheating", + "165": "facial", + "1968": "cunnilingus" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/a/0/1/zbblwkcdx987.jpg", + "images/torrent/6/d/7/qw31z7i78cue.jpg", + "images/torrent/8/8/c/6rntkok21tt1.jpg", + "images/torrent/d/e/9/ellxh5a9vvg4.jpg", + "images/torrent/a/7/c/ckkdvwnw2osr.jpg", + "images/torrent/8/1/6/xjwdpnnugglf.jpg", + "images/torrent/8/d/c/bjmsonnscwgs.jpg", + "images/torrent/6/6/d/nuqzytsy4bin.jpg", + "images/torrent/9/0/6/jpoyeqdohhft.gif" + ], + "description": "<p><a href=\"https://exoticaz.to/torrents?in=1&search=KnickerZ&uploader=&verifier=\"><img src=\"https://i.exoticaz.to/images/torrent/e/3/9/i7bfled2kuss.jpg\" width=\"824\" height=\"300\" alt=\"i7bfled2kuss.jpg\"></a></p>\n<p>[SSIS-181] Yua Mikami - Getting A Lick Down From Step-dad. 3 Full Days Indecency While The Husband Is Away (4K)</p>\n<p>Scene 1: Yua while asleep gets tits sucked, missionary<br>Scene 2: Yua plays with toothbrush<br>Scene 3: Blowjob<br>Various Sex Acts Included : Oral, Doggy, One on One sex, MF sex, Facials, Cumshots, Missionary Sex, Handjob, Blowjobs, Blowbangs, Handjobs, Cowgirl & Reverse-Cowgirl, Deep-throat, Solo tease, Solo Masturbation, Toy/Dildo play, Kissing, etc</p>\n\n<p>                                            <img src=\"https://i.exoticaz.to/images/torrent/9/0/6/jpoyeqdohhft.gif\" alt=\"jpoyeqdohhft.gif\"></p>", + "created_at": "2022-01-03 12:49:49" + }, + { + "id": 51414, + "url": "https://exoticaz.to/torrent/51414-ssis-270-yua-mikamis-devilish-200-minutes-of-all-round-nipple-licking-teasing-and-kneading", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSIS-270] Yua Mikami's Devilish 200 Minutes of All Round Nipple Licking, Teasing and Kneading", + "file_size": 9142368868, + "file_count": 1, + "seed": 10, + "leech": 0, + "completed": 99, + "downloaded": 126, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "102": "idol" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/8/1/6/05eycdxiuk9e.jpg", + "images/torrent/4/f/8/6y7u6j37paoz.jpg", + "images/torrent/5/e/7/cd6hyfzyyc7k.jpg", + "images/torrent/3/a/2/yxdxbqvnujyy.jpg", + "images/torrent/7/c/0/mz8iaummru9q.jpg", + "images/torrent/8/c/9/zpjxhsylyic0.jpg", + "images/torrent/1/b/4/cpbvokvulqtz.jpg", + "images/torrent/0/0/d/0zmqxhc0jso2.jpg", + "images/torrent/6/6/c/lyslrs0lvx05.jpg", + "images/torrent/4/4/e/tb3l6bafyo9s.jpg", + "images/torrent/7/a/2/v4bbhqrhfaic.jpg" + ], + "description": "<p>Yua Mikami's Devilish 200 Minutes of All Round Nipple Licking, Teasing and Kneading</p>\n<p>Actresses: Yua Mikami<br>Studio: S1 NO.1 STYLE<br>Series: Just A Little Devil Chick.<br>Release date: Dec 10, 2021<br>Runtime: 197min<br>Director: ZAMPA<br>Label: S1 NO.1 STYLE<br>Content ID: ssis00270<br>DVD ID: SSIS-270<br>Languages: Japanese</p>", + "created_at": "2021-12-10 16:59:45" + }, + { + "id": 50935, + "url": "https://exoticaz.to/torrent/50935-ssis-241-english-subbed-forbidden-teacher-love-yua-mikami-1080p", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSIS-241] (English subbed) Forbidden Teacher Love. Yua Mikami (1080p)", + "file_size": 5492948045, + "file_count": 1, + "seed": 76, + "leech": 0, + "completed": 411, + "downloaded": 503, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "102": "idol", + "109": "teacher" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/a/3/f/uiurw1mrxerj.jpg", + "images/torrent/5/e/5/zhjrjkav6pnk.jpg", + "images/torrent/9/f/1/evdpyf1j3grk.png", + "images/torrent/e/e/f/rlgkmyfzxfk8.png", + "images/torrent/5/4/8/qenfolmm94xd.png", + "images/torrent/8/6/1/svusdz2ctkbs.png", + "images/torrent/9/8/3/d3jiz9a7lstp.png", + "images/torrent/9/8/b/es5vpyasitev.png", + "images/torrent/a/4/f/frcx5mhk53dg.png", + "images/torrent/7/b/2/jxavrbmbypl0.png", + "images/torrent/2/f/7/aow9cx6tenbr.png", + "images/torrent/4/d/2/8ppl4ibq95se.png" + ], + "description": null, + "created_at": "2021-11-27 21:51:25" + }, + { + "id": 50154, + "url": "https://exoticaz.to/torrent/50154-ofje-139-bd-raw-yua-mikami-first-best-the-12-newest-titles-complete-best", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[OFJE-139] [BD-Raw] Yua Mikami First Best The 12 newest Titles Complete Best", + "file_size": 82196594688, + "file_count": 2, + "seed": 11, + "leech": 0, + "completed": 49, + "downloaded": 86, + "upload_multiply": 1, + "download_multiply": 0, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "102": "idol", + "132": "compilation", + "165": "facial", + "717": "celeb" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/0/f/3/7kmvpxta7l5o.jpg", + "images/torrent/4/d/1/kg2ahfvyk7vr.jpg", + "images/torrent/f/a/5/imajknv5ciyi.jpg", + "images/torrent/5/8/8/ooluv4nfauvk.jpg", + "images/torrent/8/9/1/jveotivzpnaf.jpg", + "images/torrent/7/b/3/ny7kb7jt5bfe.jpg", + "images/torrent/1/0/b/acaswxrodrbw.jpg", + "images/torrent/f/e/2/qjzhummerpst.jpg", + "images/torrent/1/3/1/1jlkhi5t0sjg.jpg", + "images/torrent/1/5/b/k36tt90f1k5v.jpg", + "images/torrent/c/0/6/xwzc1ydtsf4q.jpg", + "images/torrent/8/d/2/pnnwpjwbf8bp.jpg", + "images/torrent/5/7/e/g2lhvvmtmafx.jpg", + "images/torrent/c/3/1/pk6t6xd8mofk.jpg", + "images/torrent/6/f/5/tt8fsefz2otb.jpg", + "images/torrent/1/4/8/f8avpwtvuf2i.jpg", + "images/torrent/f/7/b/qxwquyfhzwoo.jpg", + "images/torrent/9/d/7/9icrjyl3huad.jpg", + "images/torrent/4/1/b/cpao4dsb1ycz.jpg", + "images/torrent/6/b/1/6mrbo5h5oucu.jpg", + "images/torrent/c/1/7/cr9otlemktbu.jpg", + "images/torrent/4/a/e/cv7lxyhmpohw.jpg", + "images/torrent/a/7/7/t90zggbrwwf5.jpg" + ], + "description": null, + "created_at": "2021-11-12 10:26:20" + }, + { + "id": 49718, + "url": "https://exoticaz.to/torrent/49718-tek-076-iso-high-class-5-star-soapland-brothel-where-a-pop-star-will-service-you-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[TEK-076] [ISO] High-Class 5-Star Soapland Brothel Where A Pop Star Will Service You Yua Mikami", + "file_size": 40935686144, + "file_count": 2, + "seed": 1, + "leech": 0, + "completed": 25, + "downloaded": 63, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "38": "MUTEKI" + }, + "tags": { + "35": "prostitute", + "41": "big.tits", + "102": "idol", + "536": "spa.resort.or.inn", + "717": "celeb", + "718": "hostess", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/8/6/0/gjbqy73alraw.jpg", + "images/torrent/7/d/d/j6wmv7qacnih.png", + "images/torrent/f/2/6/fwbp8jppblrx.png", + "images/torrent/e/3/0/vhryqo38atp6.png", + "images/torrent/4/8/5/bzej0mfa9d3p.png", + "images/torrent/b/9/0/jewxuj0rai2e.png", + "images/torrent/e/7/c/pkasxqtfxqfi.png", + "images/torrent/a/5/9/lyzqyjwizllx.png", + "images/torrent/b/6/8/ycbnh5mjokbn.png", + "images/torrent/5/9/4/lb2nmfiugsvn.png", + "images/torrent/4/3/f/gghk4q3wv4xm.png", + "images/torrent/2/f/2/wtyhlm89snok.jpg", + "images/torrent/1/2/6/m5nvyoceh2gk.png", + "images/torrent/5/a/1/poxcmt9au9el.png", + "images/torrent/b/a/6/pdoepy3rzfhb.png", + "images/torrent/5/c/e/yrdz9wnygdmi.png", + "images/torrent/8/8/2/jocgld4jhe1y.png", + "images/torrent/d/2/c/e62xbnaavz13.png", + "images/torrent/0/f/6/ir4grb0on4fs.png", + "images/torrent/b/2/c/wqsjkxz4coql.png", + "images/torrent/b/2/2/tkwssbja82zd.png", + "images/torrent/1/c/f/nb7udoijfwfp.png", + "images/torrent/5/9/9/7uo17medy6ib.jpg" + ], + "description": null, + "created_at": "2021-11-02 11:39:32" + }, + { + "id": 49717, + "url": "https://exoticaz.to/torrent/49717-tek-080-iso-saliva-slick-tongues-intertwined-sex-with-hot-smothering-kisses-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[TEK-080] [ISO] Saliva-Slick Tongues Intertwined: Sex With Hot, Smothering Kisses Yua Mikami", + "file_size": 23807852544, + "file_count": 1, + "seed": 2, + "leech": 0, + "completed": 26, + "downloaded": 55, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "38": "MUTEKI" + }, + "tags": { + "41": "big.tits", + "102": "idol", + "370": "kissing", + "717": "celeb", + "1635": "saliva", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/1/a/0/rdhthuopzv7j.jpg", + "images/torrent/e/6/8/qipmmjkc3b7w.png", + "images/torrent/6/8/a/l7zgowwctjoz.png", + "images/torrent/7/a/6/guhv0jt8ssvu.png", + "images/torrent/4/2/f/qloujsapjged.png", + "images/torrent/b/2/2/ouyfbpwlk8uk.png", + "images/torrent/c/a/2/xkiew2gx2azp.png", + "images/torrent/1/e/9/7jdio9eyfuz7.png", + "images/torrent/2/f/0/aibbhaiv9qd8.png", + "images/torrent/9/f/0/4ubh4p0xqwwq.png", + "images/torrent/5/f/1/wvjlfsn05cq4.png", + "images/torrent/2/4/0/f99j7rtxwlni.jpg" + ], + "description": null, + "created_at": "2021-11-02 11:25:47" + }, + { + "id": 49715, + "url": "https://exoticaz.to/torrent/49715-tek-079-iso-lets-fuck-a-sl-idol-after-school-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[TEK-079] [ISO] Let's Fuck A S********l Idol After School Yua Mikami", + "file_size": 23796449280, + "file_count": 1, + "seed": 3, + "leech": 0, + "completed": 26, + "downloaded": 61, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "38": "MUTEKI" + }, + "tags": { + "41": "big.tits", + "86": "schoolgirl", + "102": "idol", + "717": "celeb", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/f/c/f/tztk8ncck7ok.jpg", + "images/torrent/b/d/0/zbiv4udydctb.png", + "images/torrent/4/e/1/o0zcqhdesjfm.png", + "images/torrent/6/9/a/ylnvifnkoeog.png", + "images/torrent/6/4/c/bdox8chkm72l.png", + "images/torrent/4/c/6/ukunzxdfpsff.png", + "images/torrent/a/5/d/ya7hgc7kpmol.png", + "images/torrent/c/5/b/x0r6mcamxsi0.png", + "images/torrent/9/e/a/jyvvlgzonein.png", + "images/torrent/8/2/2/0jpnl4khjwit.png", + "images/torrent/e/3/d/scetu8pqwwqx.png", + "images/torrent/7/3/5/6e8mmocet7pq.jpg" + ], + "description": null, + "created_at": "2021-11-02 11:16:12" + }, + { + "id": 49714, + "url": "https://exoticaz.to/torrent/49714-tek-071-iso-pleasant-feeling-starring-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[TEK-071] [ISO] Pleasant Feeling Starring Yua Mikami", + "file_size": 24220008448, + "file_count": 1, + "seed": 2, + "leech": 1, + "completed": 19, + "downloaded": 51, + "upload_multiply": 2, + "download_multiply": 0, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "38": "MUTEKI" + }, + "tags": { + "41": "big.tits", + "102": "idol", + "717": "celeb", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/0/9/3/0sybzmwx02vb.jpg", + "images/torrent/d/9/b/xodiytrmhceg.png", + "images/torrent/8/e/7/31xidgf8kacu.png", + "images/torrent/f/6/9/bikd6ppbnnks.png", + "images/torrent/e/1/8/nrtmv4kgjzeo.png", + "images/torrent/4/6/5/solru7hypwmb.png", + "images/torrent/f/0/b/o3tdsrkgagcj.png", + "images/torrent/9/2/d/jqkem6xgrzgq.png", + "images/torrent/9/1/c/zqp6bbafrwcr.png", + "images/torrent/6/1/6/ttqjcz2nbq7z.png", + "images/torrent/9/4/5/euv6uu6ywikf.png", + "images/torrent/5/a/b/bchwfgrs4jm4.jpg" + ], + "description": null, + "created_at": "2021-11-02 11:06:08" + }, + { + "id": 49712, + "url": "https://exoticaz.to/torrent/49712-ssni-279-iso-lusty-kissing-sluts-spit-swap-sloppy-licking-fuck-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-279] [ISO] Lusty Kissing Slut's Spit Swap Sloppy Licking Fuck Yua Mikami", + "file_size": 20684275712, + "file_count": 1, + "seed": 3, + "leech": 0, + "completed": 28, + "downloaded": 53, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "102": "idol", + "370": "kissing", + "717": "celeb", + "1068": "sloppy", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/2/3/4/fwjsvihmzb2t.jpg", + "images/torrent/d/3/2/iwzovvwbd4st.png", + "images/torrent/f/8/7/xskzbufsz0iz.png", + "images/torrent/3/b/b/tlmdlu5jmyfq.png", + "images/torrent/1/e/4/oeu6f3ei39wx.png", + "images/torrent/0/c/4/dk96lxwjmhls.png", + "images/torrent/c/0/1/snunamedxiei.png", + "images/torrent/0/0/9/xtcthjmfnvjp.png", + "images/torrent/9/4/f/mnnkkmgac8yn.png", + "images/torrent/8/d/2/uu1kahtqtwft.png", + "images/torrent/5/e/c/qjkgiblf7shf.png", + "images/torrent/d/8/0/n8wlosqiuz92.jpg" + ], + "description": null, + "created_at": "2021-11-02 10:46:18" + }, + { + "id": 49647, + "url": "https://exoticaz.to/torrent/49647-ssni-254-iso-jiggling-and-wiggling-voluptuous-titties-in-hard-piston-thrusting-sex-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-254] [ISO] Jiggling And Wiggling Voluptuous Titties In Hard Piston Thrusting Sex Yua Mikami", + "file_size": 22127706112, + "file_count": 1, + "seed": 3, + "leech": 0, + "completed": 25, + "downloaded": 45, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "83": "oil.or.lotion", + "102": "idol", + "566": "boob.job", + "717": "celeb", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/7/e/7/hbvu5zsrbfxg.jpg", + "images/torrent/8/f/f/vaef7esgo63a.png", + "images/torrent/8/6/0/ypjauqndorvo.png", + "images/torrent/5/3/5/clv5mcc7usvl.png", + "images/torrent/2/c/5/f4mp3fgvnjyw.png", + "images/torrent/b/5/e/jicpisvnx9ql.png", + "images/torrent/c/3/4/ytyh53l2qmxl.png", + "images/torrent/b/c/1/sxmwikvwmrce.png", + "images/torrent/4/c/4/jnjpwokxjd2g.png", + "images/torrent/d/5/a/dz4exwmi1pov.png", + "images/torrent/3/3/c/4gmutc8qhgax.png", + "images/torrent/c/5/f/nc1q6ejlvyqu.jpg" + ], + "description": null, + "created_at": "2021-11-02 10:29:43" + }, + { + "id": 49646, + "url": "https://exoticaz.to/torrent/49646-ssni-229-iso-silent-obedience-on-the-mter-train-a-big-tits-college-girl-is-taught-a-lesson-in-orgasmic-ecstasy-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-229] [ISO] Silent Obedience On The M****ter Train A Big Tits College Girl Is Taught A Lesson In Orgasmic Ecstasy Yua Mikami", + "file_size": 30172643328, + "file_count": 1, + "seed": 4, + "leech": 0, + "completed": 30, + "downloaded": 63, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "102": "idol", + "115": "college.girl", + "717": "celeb", + "780": "public.transport", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/e/a/d/bjutnxf7i7kf.jpg", + "images/torrent/1/0/3/otlzqlwkhsvu.png", + "images/torrent/a/2/7/e21wztnhndio.png", + "images/torrent/8/9/a/xpwfuoxf46cx.png", + "images/torrent/a/d/4/cg85cjefy1sj.png", + "images/torrent/1/9/6/iq9gugg21p5a.png", + "images/torrent/1/e/8/nlvo6o2tuago.png", + "images/torrent/c/5/8/c1wfncbm1eve.jpg" + ], + "description": null, + "created_at": "2021-10-31 14:28:38" + }, + { + "id": 49645, + "url": "https://exoticaz.to/torrent/49645-ssni-205-iso-sticky-and-teasing-trembling-pleasure-the-twitching-and-throbbing-sensuality-awakening-oil-massage-parlor-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-205] [ISO] Sticky And Teasing Trembling Pleasure The Twitching And Throbbing Sensuality-Awakening Oil Massage Parlor Yua Mikami", + "file_size": 33929363456, + "file_count": 1, + "seed": 3, + "leech": 0, + "completed": 30, + "downloaded": 63, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "83": "oil.or.lotion", + "102": "idol", + "167": "massage", + "629": "salon", + "717": "celeb", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/5/1/b/aedqrmo0omqb.jpg", + "images/torrent/d/2/8/tvto1wg3nc9c.png", + "images/torrent/4/4/8/pbgupy8uzs2n.png", + "images/torrent/6/f/4/thfyahcgjwm2.png", + "images/torrent/e/0/b/xaoljxumubpa.png", + "images/torrent/3/5/4/fgcgy3fv4fd6.png", + "images/torrent/3/f/7/uus7tezigvpe.png", + "images/torrent/1/e/0/q2tyy4shl8ua.png", + "images/torrent/3/9/0/4bloqzj1qc7c.png", + "images/torrent/0/3/0/i9jbeanertrt.png", + "images/torrent/d/e/5/oft8fgqh1c3j.png", + "images/torrent/8/4/e/wc4toojco9dx.jpg" + ], + "description": null, + "created_at": "2021-10-31 14:17:13" + }, + { + "id": 49644, + "url": "https://exoticaz.to/torrent/49644-ssni-178-iso-you-vs-yua-mikami-5-basic-instinct-baring-lust-exposing-mind-blowing-one-on-one-upper-limit-fucks", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-178] [ISO] You Vs Yua Mikami 5 Basic Instinct Baring Lust Exposing Mind Blowing One On One Upper Limit Fucks", + "file_size": 41374318592, + "file_count": 1, + "seed": 2, + "leech": 0, + "completed": 17, + "downloaded": 33, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "102": "idol", + "187": "squirting", + "370": "kissing", + "717": "celeb", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/0/9/5/dqu1oo0prf8l.jpg", + "images/torrent/e/f/6/gyklt0wrm9vr.png", + "images/torrent/c/9/6/lyl53mprocj0.png", + "images/torrent/d/e/2/osc6phrzb8qk.png", + "images/torrent/c/a/9/uwcmvwu7f7td.png", + "images/torrent/4/e/b/wxvxnrwg2j9v.png", + "images/torrent/7/9/b/rzwchi1gl6b7.png", + "images/torrent/3/e/4/iyuza1ppdoqq.png", + "images/torrent/9/0/7/l8bvb2tmtgno.png", + "images/torrent/0/b/7/ivhp7pngwi6b.png", + "images/torrent/c/8/3/kgu5h4jbhmze.png", + "images/torrent/7/7/c/4qp3mqsokrnw.jpg" + ], + "description": null, + "created_at": "2021-10-31 14:02:50" + }, + { + "id": 49643, + "url": "https://exoticaz.to/torrent/49643-ssni-152-iso-the-re-of-a-big-tits-female-teacher-a-massive-gg-re-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-152] [ISO] The R**e Of A Big Tits Female Teacher A Massive G*******g R**e Yua Mikami", + "file_size": 29614800896, + "file_count": 1, + "seed": 3, + "leech": 0, + "completed": 30, + "downloaded": 45, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "102": "idol", + "109": "teacher", + "717": "celeb", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/4/9/3/laq5w3e1hjc9.jpg", + "images/torrent/9/2/d/bw7auqfwrhyu.png", + "images/torrent/5/2/4/xwctd52hgjyw.png", + "images/torrent/d/2/2/qhheo3x7tuna.png", + "images/torrent/7/0/a/0hmoyhrx8q1z.png", + "images/torrent/9/c/a/jx2sow6os0wo.png", + "images/torrent/8/4/6/wyfno9g219hg.png", + "images/torrent/1/1/f/t7n518qzxbhy.png", + "images/torrent/0/9/f/fgwbfeqmzftr.jpg" + ], + "description": null, + "created_at": "2021-10-31 13:50:27" + }, + { + "id": 49079, + "url": "https://exoticaz.to/torrent/49079-ssni-802-english-subbed-poor-teacher-trapped-at-school-during-a-storm-she-fucks-her-male-students-until-the-weather-clears-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-802] (English subbed) Poor Teacher – Trapped At School During A Storm, She Fucks Her Male Students Until The Weather Clears… – Yua Mikami", + "file_size": 5400244950, + "file_count": 1, + "seed": 21, + "leech": 0, + "completed": 154, + "downloaded": 205, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "109": "teacher", + "153": "cheating", + "792": "subtitle.english" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/b/5/2/h4zkhcmvpoqj.jpg", + "images/torrent/1/5/d/wy3r0q3gjgxz.jpg", + "images/torrent/5/0/c/0lqzp597ji44.png", + "images/torrent/7/8/c/mktfijuwyi4o.png", + "images/torrent/2/0/b/kgxq2lzegbmo.png", + "images/torrent/d/1/e/njv9fhxnrzf8.png", + "images/torrent/f/8/1/2p2xg897xw4l.png", + "images/torrent/9/3/b/gicj0orwwzym.png", + "images/torrent/5/9/d/8awaef4atbcs.png", + "images/torrent/d/3/3/km2uyuvbrcou.png", + "images/torrent/5/0/4/bj8hrepmrm1e.png", + "images/torrent/7/d/d/xe1gcbp5acwx.png" + ], + "description": null, + "created_at": "2021-10-16 16:50:12" + }, + { + "id": 49056, + "url": "https://exoticaz.to/torrent/49056-ssni-780-iso-shes-unwittingly-luring-men-to-temptation-with-her-clothed-big-tits-a-super-lucky-horny-daydream-fantasy-situation-special-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-780] [ISO] She's Unwittingly Luring Men To Temptation With Her Clothed Big Tits A Super Lucky Horny Daydream Fantasy Situation Special Yua Mikami", + "file_size": 33023655936, + "file_count": 1, + "seed": 2, + "leech": 0, + "completed": 32, + "downloaded": 63, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "4": "720p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "102": "idol", + "717": "celeb", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/9/3/a/uetsh2h0ulsa.jpg", + "images/torrent/4/a/9/mrewveoxoj0x.png", + "images/torrent/f/7/1/txxl27gmkkfw.png", + "images/torrent/d/d/a/hg7lk4zrnbic.png", + "images/torrent/6/c/8/hudyhghvfjpo.png", + "images/torrent/9/9/3/lazldpp5wpi5.png", + "images/torrent/5/d/9/tbhgbdep8irm.png", + "images/torrent/7/4/f/xcr6f29j7y9o.png", + "images/torrent/1/c/d/qean6y2czuvx.png", + "images/torrent/8/5/c/iawomcmv2wce.png", + "images/torrent/4/a/2/dy1ennwzfmyt.png", + "images/torrent/e/1/1/yv3ablrdkgfv.jpg" + ], + "description": null, + "created_at": "2021-10-16 07:10:29" + }, + { + "id": 49050, + "url": "https://exoticaz.to/torrent/49050-ssni-127-iso-finally-its-out-in-the-open-a-nationally-loved-idol-in-a-scandalous-love-video-we-were-embedded-with-yua-mikami-for-32-days-with-raw-kissing-blowjob-action-and-sex-a-totally-private-video-from-start-to-finish", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-127] [ISO] Finally It's Out In The Open! A Nationally Loved Idol In A Scandalous Love Video We Were Embedded With Yua Mikami For 32 Days, With Raw Kissing, Blowjob Action, And Sex... A Totally Private Video, From Start To Finish", + "file_size": 23860871168, + "file_count": 1, + "seed": 3, + "leech": 0, + "completed": 24, + "downloaded": 59, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "102": "idol", + "144": "documentary", + "370": "kissing", + "456": "voyeur", + "717": "celeb", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/d/a/8/cnmmej5angiv.jpg", + "images/torrent/5/0/6/d2c2xzxst0h1.png", + "images/torrent/5/1/a/ociunwhu8cxk.png", + "images/torrent/3/8/8/wd63dy7lt79m.png", + "images/torrent/0/a/d/nmm9vszvg0qr.png", + "images/torrent/3/3/1/uorz1hpm1hld.jpg" + ], + "description": null, + "created_at": "2021-10-16 02:11:54" + }, + { + "id": 49049, + "url": "https://exoticaz.to/torrent/49049-ssni-077-iso-a-super-high-class-idol-at-an-ultra-high-temptation-mens-massage-parlor-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-077] [ISO] A Super High Class Idol At An Ultra High Temptation Mens Massage Parlor Yua Mikami", + "file_size": 23800971264, + "file_count": 1, + "seed": 3, + "leech": 0, + "completed": 27, + "downloaded": 61, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "102": "idol", + "167": "massage", + "629": "salon", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/5/9/4/ptzfay34ithk.jpg", + "images/torrent/3/9/1/lwuxynivfeqv.png", + "images/torrent/d/a/2/mdmzjqmpttpu.png", + "images/torrent/5/0/2/gzorssau03bx.png", + "images/torrent/c/8/2/6xfgqr2aqwnd.png", + "images/torrent/b/1/0/flknxwhcvlxh.png", + "images/torrent/6/1/9/0mykczznsjj4.png", + "images/torrent/6/7/e/w0gmib1jpepj.png", + "images/torrent/2/a/f/knjbiwimocaw.png", + "images/torrent/e/e/c/nezvesz8cmy1.png", + "images/torrent/d/9/a/chvn1d7vzddc.png", + "images/torrent/9/6/e/bahbhr2gaqeq.jpg" + ], + "description": null, + "created_at": "2021-10-16 00:06:39" + }, + { + "id": 49048, + "url": "https://exoticaz.to/torrent/49048-ssni-054-iso-a-cock-sucking-ball-slurping-gland-rubbing-dick-swallowing-special-and-it-cums-with-an-amazing-cleanup-blowjob-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-054] [ISO] A Cock Sucking Ball Slurping Gland Rubbing Dick Swallowing Special And It Cums With An Amazing Cleanup Blowjob Yua Mikami", + "file_size": 22929408000, + "file_count": 1, + "seed": 2, + "leech": 0, + "completed": 26, + "downloaded": 58, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "70": "fetish", + "102": "idol", + "717": "celeb", + "1025": "rubbing", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/3/1/1/ldfzo2thhrul.jpg", + "images/torrent/e/1/4/jzgamzd4n04e.png", + "images/torrent/d/d/e/2gcsnmp1jfm1.png", + "images/torrent/3/0/e/3oggjvhvawgq.png", + "images/torrent/0/6/f/xa1gdfax1fa0.png", + "images/torrent/b/c/d/3d23njqmgoie.png", + "images/torrent/b/c/a/riabfbpcusgk.png", + "images/torrent/1/d/0/esb8jiltf8dx.png", + "images/torrent/7/3/8/zibvhtfffrvg.png", + "images/torrent/0/1/2/qeqpgnbh7ztq.png", + "images/torrent/a/9/1/5es1kn230aza.png", + "images/torrent/7/8/b/eq1jkrz8icoi.jpg" + ], + "description": null, + "created_at": "2021-10-16 00:01:42" + }, + { + "id": 49038, + "url": "https://exoticaz.to/torrent/49038-ssni-030-iso-yua-mikami-fan-thanksgiving-day-a-national-idol-x-20-regular-fans-sex-with-the-fans-unleashed-a-fuck-fest-special", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-030] [ISO] Yua Mikami Fan Thanksgiving Day A National Idol x 20 Regular Fans Sex With The Fans, Unleashed A Fuck Fest Special", + "file_size": 23836164096, + "file_count": 1, + "seed": 5, + "leech": 0, + "completed": 24, + "downloaded": 55, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "82": "bukkake", + "102": "idol", + "126": "fan.appreciation", + "717": "celeb", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/4/f/c/wwm56nuyvduv.jpg", + "images/torrent/d/f/1/jlr04qqzt8er.png", + "images/torrent/a/f/c/ec4n6rn1vjde.png", + "images/torrent/5/6/9/vj5sdxn4v7ci.png", + "images/torrent/a/6/8/y5i6ofgzkzqz.png", + "images/torrent/2/6/a/dr8z9jz7htf9.png", + "images/torrent/e/e/3/ep87kzrm0zak.png", + "images/torrent/4/e/8/9lkhrnvybwu9.png", + "images/torrent/c/f/9/whgga9n695oh.png", + "images/torrent/5/9/a/31k2sza1sebu.png", + "images/torrent/1/c/3/jl4rhrn43ln9.png", + "images/torrent/0/1/7/c2hcjiknuv26.jpg" + ], + "description": null, + "created_at": "2021-10-15 14:15:16" + }, + { + "id": 49037, + "url": "https://exoticaz.to/torrent/49037-snis-986-iso-a-national-idol-an-adrenaline-explosion-forbidden-to-fuck-for-1-month-shes-a-lustful-beast-ready-for-a-trance-global-fuck-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SNIS-986] [ISO] A National Idol An Adrenaline Explosion! Forbidden To Fuck For 1 Month, She's A Lustful Beast Ready For A Trance Global Fuck Yua Mikami", + "file_size": 23830855680, + "file_count": 1, + "seed": 3, + "leech": 0, + "completed": 24, + "downloaded": 48, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "102": "idol", + "187": "squirting", + "238": "sweating", + "717": "celeb", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/9/7/1/rmm4ocqgrxwj.jpg", + "images/torrent/7/6/f/v8pqbwdlmmh3.png", + "images/torrent/8/b/0/bqx4o0ydyh6k.png", + "images/torrent/c/3/8/tnmqpfx2ywkk.png", + "images/torrent/f/2/7/3emzfzveug5y.png", + "images/torrent/d/5/e/yednvqybgyrs.png", + "images/torrent/7/4/8/tuxoq9s8k1nk.png", + "images/torrent/a/8/7/kpkgwh1qiaxr.png", + "images/torrent/0/4/c/o8web1jove3t.png", + "images/torrent/e/7/b/vio9cg7rixlv.png", + "images/torrent/0/c/3/8xblnsxuagrh.png", + "images/torrent/f/c/c/sir7gae1bnjv.jpg" + ], + "description": null, + "created_at": "2021-10-15 13:58:51" + }, + { + "id": 48883, + "url": "https://exoticaz.to/torrent/48883-snis-786-exclusive-no1-style-yua-mikamis-s1-debut-her-shocking-transfer-to-a-new-label-x-4-full-fuck-special", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SNIS-786] Exclusive NO.1 STYLE - Yua Mikami's S1 Debut - Her Shocking Transfer To A New Label x 4-Full Fuck Special", + "file_size": 7689662034, + "file_count": 1, + "seed": 7, + "leech": 0, + "completed": 40, + "downloaded": 51, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "102": "idol", + "717": "celeb", + "803": "av.debut" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/0/4/c/xf7hkgwd2alq.jpg", + "images/torrent/2/1/d/2zaicbzunkrm.jpg", + "images/torrent/6/e/b/h7zrk9mxsucp.jpg", + "images/torrent/b/2/e/6f3vhi5txega.jpg", + "images/torrent/9/c/0/qauw85krewha.jpg", + "images/torrent/5/3/3/qmfu4ggsddyk.jpg", + "images/torrent/1/5/7/myv4v8tpa6d6.jpg" + ], + "description": "<p>ISO: https://exoticaz.to/torrent/48124</p>", + "created_at": "2021-10-12 07:11:18" + }, + { + "id": 48364, + "url": "https://exoticaz.to/torrent/48364-ssni-030-yua-mikami-fan-thanksgiving-day-a-national-idol", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-030] Yua Mikami Fan Thanksgiving Day A National Idol", + "file_size": 8084277073, + "file_count": 1, + "seed": 7, + "leech": 0, + "completed": 53, + "downloaded": 68, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "102": "idol", + "126": "fan.appreciation" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/d/3/5/4ihijylfcfh7.jpg", + "images/torrent/f/b/f/lw6fcsf6fz9z.jpg" + ], + "description": "<p>Somebody requested this separately from pack that is already on here.</p>", + "created_at": "2021-09-29 03:12:14" + }, + { + "id": 48189, + "url": "https://exoticaz.to/torrent/48189-snis-940-iso-the-national-idol-is-my-private-slick-lotion-se-maid-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SNIS-940] [ISO] The National Idol Is My Private Slick Lotion S***e Maid (Yua Mikami)", + "file_size": 23828430848, + "file_count": 1, + "seed": 5, + "leech": 0, + "completed": 33, + "downloaded": 59, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "83": "oil.or.lotion", + "87": "maid", + "102": "idol", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/2/2/2/1vcfozbv2njj.jpg", + "images/torrent/5/7/c/of6l8nt2rjuc.png", + "images/torrent/1/8/1/ajura2pj3yvf.png", + "images/torrent/b/9/e/5yc11t4mrxya.png", + "images/torrent/f/9/c/qy5blsrbnzdk.png", + "images/torrent/f/c/a/pcuombs3dqsg.png", + "images/torrent/1/f/e/dbi7tpbtaemv.png", + "images/torrent/d/4/f/rwszx7kqgyen.png", + "images/torrent/9/f/c/0dd0ndf5cr51.png", + "images/torrent/5/0/7/40ihy9qrq7er.png", + "images/torrent/6/a/6/dcx3ha6ajqks.png", + "images/torrent/6/3/2/5yvhovuhybyd.jpg" + ], + "description": null, + "created_at": "2021-09-24 14:32:49" + }, + { + "id": 48186, + "url": "https://exoticaz.to/torrent/48186-snis-919-iso-welcome-to-the-sex-club-apartment-featuring-the-highest-class-idols-yua-mikami-and-her-up-close-and-personal-sex-technique-150-minute-full-course", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SNIS-919] [ISO] Welcome To The Sex Club Apartment Featuring The Highest Class Idols Yua Mikami And Her Up Close And Personal Sex Technique 150 Minute Full Course", + "file_size": 23812636672, + "file_count": 1, + "seed": 1, + "leech": 0, + "completed": 30, + "downloaded": 51, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "83": "oil.or.lotion", + "102": "idol", + "717": "celeb", + "718": "hostess", + "814": "venue", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/3/d/8/pqtzjvkczzid.jpg", + "images/torrent/9/4/4/hfxgzujttw6s.png", + "images/torrent/d/7/5/4pzokjyuxbtw.png", + "images/torrent/2/d/6/syec1vmyg7ge.png", + "images/torrent/4/1/2/msrp5slsvbdi.png", + "images/torrent/f/d/e/iilr1qyftyjv.png", + "images/torrent/c/8/f/vnnj2qmk8y5z.png", + "images/torrent/1/a/2/gbt5n6gngnua.png", + "images/torrent/3/8/7/ngtxbjj83mvs.png", + "images/torrent/6/c/e/5kivguzxtugv.png", + "images/torrent/c/b/9/rlhyyichkh1v.png", + "images/torrent/6/0/8/e6jahgfjtvkf.jpg" + ], + "description": null, + "created_at": "2021-09-24 14:17:46" + }, + { + "id": 48184, + "url": "https://exoticaz.to/torrent/48184-snis-896-iso-a-nationally-loved-idol-is-having-quickie-sex-in-4-candid-camera-fuck-scenes-always-fucking-always-cumming-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SNIS-896] [ISO] A Nationally Loved Idol Is Having Quickie Sex In 4 Candid Camera Fuck Scenes Always Fucking, Always Cumming Yua Mikami", + "file_size": 21468151808, + "file_count": 1, + "seed": 1, + "leech": 0, + "completed": 32, + "downloaded": 57, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "102": "idol", + "144": "documentary", + "456": "voyeur", + "717": "celeb", + "922": "quickie", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/5/5/3/zz9dxawocbzk.jpg", + "images/torrent/2/7/e/rycylhtpnt9x.png", + "images/torrent/2/7/3/olultjtmqt1z.png", + "images/torrent/3/7/6/trtlbehq59th.png", + "images/torrent/d/8/6/hz5swh42sebn.png", + "images/torrent/f/0/d/nwuzm5ueyvr7.png", + "images/torrent/a/b/1/u2t625swrjox.png", + "images/torrent/d/5/8/hbot7hwdygjt.png", + "images/torrent/e/c/9/jtpkdcosvh9m.png", + "images/torrent/1/6/3/bbfuwpszczh1.png", + "images/torrent/c/6/1/q9refoi7ppeo.png", + "images/torrent/9/a/b/msjcjdcarxj2.jpg" + ], + "description": null, + "created_at": "2021-09-24 13:59:44" + }, + { + "id": 48181, + "url": "https://exoticaz.to/torrent/48181-snis-872-iso-92-furious-orgasms-3600-cumtastic-spasms-2300cc-of-squirting-a-nationally-loved-idol-is-awakening-to-her-erotic-nature-her-first-massive-spasmic-special-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SNIS-872] [ISO] 92 Furious Orgasms! 3600 Cumtastic Spasms! 2300cc Of Squirting! A Nationally Loved Idol Is Awakening To Her Erotic Nature Her First Massive Spasmic Special Yua Mikami", + "file_size": 21433024512, + "file_count": 1, + "seed": 4, + "leech": 0, + "completed": 29, + "downloaded": 50, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "96": "shame", + "102": "idol", + "187": "squirting", + "717": "celeb", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/4/1/2/g4odivfvu6tm.jpg", + "images/torrent/a/d/b/zeorcuossozt.png", + "images/torrent/b/4/d/0yebydpznwhj.png", + "images/torrent/f/d/8/8jqw5bedvwzc.png", + "images/torrent/7/a/7/kidodeaxozit.png", + "images/torrent/f/d/a/aznpmeuoiiew.png", + "images/torrent/9/6/0/eqmtl8yxxmw5.png", + "images/torrent/d/9/0/ydigqijl4jsl.png", + "images/torrent/d/4/4/razywfvqimw3.png", + "images/torrent/9/a/7/g4cqaidkqel0.png", + "images/torrent/b/8/d/2xcaoaa08jww.png", + "images/torrent/f/c/c/hkmy2iaaessw.jpg" + ], + "description": null, + "created_at": "2021-09-24 13:46:50" + }, + { + "id": 48179, + "url": "https://exoticaz.to/torrent/48179-snis-850-iso-a-national-idol-yua-mikami-in-31-cosplays-get-your-kicks-every-day-with-yua-in-cosplay-action-4-hours31-outfits", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SNIS-850] [ISO] A National Idol Yua Mikami In 31 Cosplays! Get Your Kicks Every Day With Yua In Cosplay Action 4 Hours/31 Outfits", + "file_size": 23862050816, + "file_count": 1, + "seed": 2, + "leech": 0, + "completed": 26, + "downloaded": 45, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "71": "cosplay", + "102": "idol", + "717": "celeb", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/a/d/6/gcidfckjkr1u.jpg", + "images/torrent/3/3/6/kgwhlhdihixr.png", + "images/torrent/d/f/6/vpm8lnr1y7fk.png", + "images/torrent/e/5/a/sojyouxwaizc.png", + "images/torrent/2/f/c/34ewh6p9ff02.png", + "images/torrent/a/f/c/xdodg4xw33kc.png", + "images/torrent/b/3/9/ezwqg3jvxlct.png", + "images/torrent/b/1/4/epic1l2ewrxh.png", + "images/torrent/8/4/f/r5rertc1qbek.png", + "images/torrent/d/1/4/xjotgdclk54m.png", + "images/torrent/f/7/b/hbyscaon4441.png", + "images/torrent/9/8/3/fw84szdvrmk4.jpg" + ], + "description": null, + "created_at": "2021-09-24 13:34:17" + }, + { + "id": 48178, + "url": "https://exoticaz.to/torrent/48178-snis-825-iso-a-massive-dream-cum-face-shot-on-a-nationally-beloved-idol-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SNIS-825] [ISO] A Massive Dream Cum Face Shot On A Nationally Beloved Idol Yua Mikami", + "file_size": 21526151168, + "file_count": 1, + "seed": 2, + "leech": 0, + "completed": 25, + "downloaded": 44, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "82": "bukkake", + "102": "idol", + "165": "facial", + "717": "celeb", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/4/7/4/j7c9qkmfspy1.jpg", + "images/torrent/c/1/e/r6nz4zyzljgu.png", + "images/torrent/c/1/4/krt33fub1upa.png", + "images/torrent/8/2/2/s6jk44qwo5fv.png", + "images/torrent/2/e/4/9p4uennw99xi.png", + "images/torrent/1/2/b/pfjikknal4zn.png", + "images/torrent/4/f/6/7sc6oi18qh6u.png", + "images/torrent/7/a/7/55jcco34z6dk.png", + "images/torrent/a/e/b/5jjqrywzrtgc.png", + "images/torrent/4/3/b/e8gwoz1psj0o.png", + "images/torrent/c/1/6/vdrxgduk8xce.png", + "images/torrent/5/c/5/y7fjqvupby01.jpg" + ], + "description": null, + "created_at": "2021-09-24 13:22:30" + }, + { + "id": 48125, + "url": "https://exoticaz.to/torrent/48125-snis-800-iso-mixed-body-fluids-deep-sex-complete-no-cut-special-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SNIS-800] [ISO] Mixed Body Fluids, Deep Sex: Complete No-Cut Special (Yua Mikami)", + "file_size": 23812898816, + "file_count": 1, + "seed": 2, + "leech": 0, + "completed": 31, + "downloaded": 59, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "102": "idol", + "370": "kissing", + "717": "celeb", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/5/9/f/wmy5c9rotx4c.jpg", + "images/torrent/d/8/a/skwycyyamrzp.png", + "images/torrent/a/7/3/skwdv7yuab9f.png", + "images/torrent/9/f/d/xel9i1esuriq.png", + "images/torrent/2/c/0/eteynu8yfq5l.png", + "images/torrent/3/3/6/8qxrd11kc17d.png", + "images/torrent/c/7/5/spyfous1iofd.png", + "images/torrent/f/b/0/mg6be07md8sw.png", + "images/torrent/9/6/3/asoo8hrckfsq.png", + "images/torrent/a/c/6/vu9ytisejs2e.png", + "images/torrent/4/9/4/gspvdkau9mkr.png", + "images/torrent/f/2/1/wj8axuerttva.jpg" + ], + "description": null, + "created_at": "2021-09-23 06:34:55" + }, + { + "id": 48124, + "url": "https://exoticaz.to/torrent/48124-snis-786-iso-exclusive-no1-style-yua-mikamis-s1-debut-her-shocking-transfer-to-a-new-label-x-4-full-fuck-special", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SNIS-786] [ISO] Exclusive NO.1 STYLE - Yua Mikami's S1 Debut - Her Shocking Transfer To A New Label x 4-Full Fuck Special", + "file_size": 23828824064, + "file_count": 1, + "seed": 3, + "leech": 0, + "completed": 34, + "downloaded": 55, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "102": "idol", + "717": "celeb", + "803": "av.debut", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/9/3/6/8yt17rpac4nh.jpg", + "images/torrent/6/3/0/o0ng2gcsjc8b.png", + "images/torrent/e/6/1/syati5hz0zoy.png", + "images/torrent/d/f/f/l63uoweeei7o.png", + "images/torrent/1/b/2/nqkxrxuuptdt.png", + "images/torrent/b/c/8/rr50zezwusqb.png", + "images/torrent/4/a/f/fnzutcd53qti.png", + "images/torrent/a/9/a/ksanomp5ym7g.png", + "images/torrent/4/f/d/krqoy6ilaj37.png", + "images/torrent/2/6/f/blotz8wguugh.png", + "images/torrent/3/5/6/w38enxetgc1j.png", + "images/torrent/b/6/8/qa5nfh9blige.jpg" + ], + "description": null, + "created_at": "2021-09-23 05:38:43" + }, + { + "id": 46870, + "url": "https://exoticaz.to/torrent/46870-snis-850-a-national-idol-yua-mikami-in-31-cosplays", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SNIS-850] A National Idol Yua Mikami In 31 Cosplays", + "file_size": 13044632087, + "file_count": 1, + "seed": 8, + "leech": 0, + "completed": 78, + "downloaded": 101, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "71": "cosplay", + "102": "idol", + "1390": "decensored" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/1/f/2/wzpsx01zgmek.jpg", + "images/torrent/9/7/d/3pkspsvu110a.jpg", + "images/torrent/e/b/e/if01jf87y4ds.jpg", + "images/torrent/f/8/3/vzuqd2whk0xe.jpg", + "images/torrent/4/b/2/om3axtgniixt.jpg", + "images/torrent/4/e/8/pitoatxc5g8p.jpg", + "images/torrent/b/c/a/3fcjohndfb4g.jpg", + "images/torrent/d/4/1/rpn5ywrgch3m.jpg" + ], + "description": null, + "created_at": "2021-09-01 13:28:55" + }, + { + "id": 46193, + "url": "https://exoticaz.to/torrent/46193-ssni-756-iso-providing-deep-and-rich-entertainmen-for-perverted-middle-aged-men-a-members-only-sugar-daddy-date-club-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-756] [ISO] Providing Deep And Rich Entertainmen For Perverted Middle-Aged Men A Members-Only Sugar Daddy Date Club Yua Mikami", + "file_size": 28133230593, + "file_count": 1, + "seed": 3, + "leech": 0, + "completed": 33, + "downloaded": 58, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "147": "dating", + "370": "kissing", + "814": "venue", + "1533": "spanking", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/c/6/2/iqffett3r986.jpg", + "images/torrent/9/4/4/kvasnbns6oly.png", + "images/torrent/d/8/9/rdkuxqylxvme.png", + "images/torrent/b/7/5/xj47vmuuid1u.png", + "images/torrent/9/e/a/oo8t3pkdxfkg.png", + "images/torrent/2/3/c/v9pbp5vklyqv.png", + "images/torrent/1/5/d/lqwoit0a4t7g.png", + "images/torrent/f/4/6/gb2xqkxyt9dq.png", + "images/torrent/d/2/6/ywq78yuvrj6p.png", + "images/torrent/8/e/1/fjf1uulxixvt.png", + "images/torrent/4/2/b/vxdqrav06pub.png", + "images/torrent/7/6/8/o87ujrsbmehp.jpg" + ], + "description": null, + "created_at": "2021-08-19 09:44:36" + }, + { + "id": 45171, + "url": "https://exoticaz.to/torrent/45171-ssni-756-providing-deep-and-rich-entertainmen-for-perverted-middle-aged-men-a-members-only-sugar-daddy-date-club-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-756] Providing Deep And Rich Entertainmen For Perverted Middle-Aged Men A Members-Only Sugar Daddy Date Club Yua Mikami", + "file_size": 3297505813, + "file_count": 1, + "seed": 13, + "leech": 0, + "completed": 112, + "downloaded": 135, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "370": "kissing", + "383": "hairy.pussy", + "566": "boob.job" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/8/7/8/syvkydnu7mnk.jpg", + "images/torrent/7/6/1/3qbhezw2kksf.jpg", + "images/torrent/7/3/1/a0qgy3c5m1sp.jpg", + "images/torrent/c/0/f/dvgntzmelwnf.jpg", + "images/torrent/0/2/7/igkozijinphv.jpg", + "images/torrent/6/d/b/wm8ikfbzpecs.jpg" + ], + "description": "<p>I don't know why the source was 25 fps</p>", + "created_at": "2021-07-30 14:34:43" + }, + { + "id": 43663, + "url": "https://exoticaz.to/torrent/43663-ofje-300-yua-mikami-4th-anniversary-memorial-best-her-12-latest-titles-in-full-72-scenes-480-minutes-special", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[OFJE-300] Yua Mikami 4th Anniversary Memorial Best - Her 12 Latest Titles In Full, 72 Scenes, 480 Minutes Special", + "file_size": 5667727982, + "file_count": 1, + "seed": 14, + "leech": 0, + "completed": 146, + "downloaded": 186, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "4": "720p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "132": "compilation", + "153": "cheating", + "802": "story" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/9/8/5/pwdxailrxmbz.jpg", + "images/torrent/c/1/3/fjxn4x7lqxyt.jpg", + "images/torrent/9/1/1/5ldr2ztikybe.jpg", + "images/torrent/d/0/b/zooqezj1a3oa.jpg", + "images/torrent/8/f/0/lsulcfpje9nq.jpg", + "images/torrent/a/c/1/rcrkbzl21inz.jpg", + "images/torrent/5/2/b/tu9fnq29hmii.jpg", + "images/torrent/b/7/d/qswq8vdshnyb.jpg" + ], + "description": "<p>Yua Mikami 4th Anniversary Memorial Best - Her 12 Latest Titles In Full, 72 Scenes, 480 Minutes Special</p>\n<p>Release Date: Mar. 06, 2021<br>Runtime: 477min. (HD: 477min.)<br>Director: ----<br>Studio: S1 NO.1 STYLE<br>Label: S1 NO.1 STYLE</p>\n<p>Channel: ----<br>Content ID: ofje00300<br>DVD ID: OFJE-300<br>Series: S1 GIRLS COLLECTION<br>Languages: Japanese</p>\n<p>Actress(es): Yua Mikami</p>", + "created_at": "2021-07-04 16:17:44" + }, + { + "id": 39515, + "url": "https://exoticaz.to/torrent/39515-ssis-013-yua-mikami-will-stimulate-your-five-senses-in-a-soothing-stroking-masturbatory-luxury-support-role-6-erection-situations-of-fully-satisfying-eros-excitement-to-blow-your-mind", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSIS-013] Yua Mikami Will Stimulate Your Five Senses In A Soothing, Stroking, Masturbatory Luxury Support Role 6 Erection Situations Of Fully Satisfying Eros Excitement To Blow Your Mind", + "file_size": 7415130206, + "file_count": 1, + "seed": 18, + "leech": 0, + "completed": 227, + "downloaded": 280, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "41": "big.tits", + "102": "idol", + "141": "masturbation", + "165": "facial", + "229": "lingerie", + "566": "boob.job" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/9/1/4/loienoye9sir.jpg", + "images/torrent/8/c/c/sxnklyltdpqt.jpg", + "images/torrent/b/9/3/ecypylnms5mk.png", + "images/torrent/6/d/b/8ufqerw4brjn.png", + "images/torrent/7/8/8/dtdpzektwflo.png", + "images/torrent/5/f/a/sdb7e44wgjbh.png", + "images/torrent/1/1/1/u1rp5yapmk49.png", + "images/torrent/1/e/a/h9mnixhgzr5c.png", + "images/torrent/0/7/6/skiqqrojoywg.png", + "images/torrent/9/c/8/9vxlzy2pw6vg.png", + "images/torrent/4/2/5/ozqnjr1vsa3k.png", + "images/torrent/d/1/3/boe7inegqz3q.png", + "images/torrent/7/f/d/yocrs2wkd8ci.png", + "images/torrent/7/a/b/wktntni6gswq.png", + "images/torrent/b/6/1/qixo3zexs9xd.png", + "images/torrent/a/4/c/eod0v9luvutt.png", + "images/torrent/4/4/e/xbgvxrclpkwo.png", + "images/torrent/3/1/e/ydk5unqhc1od.png", + "images/torrent/5/5/b/mbg5xwcsvwyj.png", + "images/torrent/5/2/8/cmu3ju1xkt72.png", + "images/torrent/3/7/c/ozj1cczqfbll.png", + "images/torrent/6/9/d/pqr3nwib4tgg.png", + "images/torrent/e/d/2/wzdya1htunhr.png", + "images/torrent/3/c/a/y6ma3missydh.png", + "images/torrent/8/f/6/xhxphk3b0u93.png", + "images/torrent/1/e/9/4lqy5zyww49i.png", + "images/torrent/1/1/c/z9gekink6ona.png", + "images/torrent/5/e/2/n9fbu5pbiacq.png", + "images/torrent/b/a/b/lqrjcdr1cbya.png", + "images/torrent/4/4/9/7jfkejpjmiym.png", + "images/torrent/3/e/b/emwqtkixmkbk.png", + "images/torrent/7/c/4/cjfjjrfpxc0c.png", + "images/torrent/a/0/c/5dgyfrjx6x7p.png" + ], + "description": "<pre>+++ [HD] SSIS-013 アナタの五感を刺激する三上悠亜のシコシコサポートラグジュアリー 脳をエロスで満たす6つの癒され勃起シチュエーション</pre>\n<p><strong>Full title:</strong> <em>Yua Mikami Will Stimulate Your Five Senses In A Soothing, Stroking, Masturbatory Luxury Support Role 6 Soothing Erection Situations Of Fully Satisfying Eros Company Excitement To Blow Your Mind</em></p>\n<p><strong>Release Date:</strong> Mar. 18, 2021</p>\n<p><strong>R18:</strong> https://www.r18.com/videos/vod/movies/detail/-/id=ssis00013/</p>\n<p><strong>Studio:</strong> https://www.s1s1s1.com/works/detail/ssis013/</p>", + "created_at": "2021-03-22 14:40:56" + }, + { + "id": 39245, + "url": "https://exoticaz.to/torrent/39245-ssni-388-yua-mikami-in-a-16-consecutive-cum-shot-slut-assault-shes-tied-up-men-for-some", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-388] Yua Mikami In A 16-Consecutive Cum Shot Slut Assault She’s Tied Up Men For Some", + "file_size": 4518636516, + "file_count": 1, + "seed": 17, + "leech": 0, + "completed": 133, + "downloaded": 179, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "83": "oil.or.lotion", + "229": "lingerie", + "425": "femdom", + "1938": "bondage" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/e/e/5/lc9i2zxau3zp.jpg", + "images/torrent/d/2/b/vlaiorvqoq7q.jpg", + "images/torrent/c/5/0/ifludkvenfzz.jpg", + "images/torrent/3/b/3/rvj0rewk9wvf.jpg", + "images/torrent/e/a/0/fdyvs5shxnjf.jpg", + "images/torrent/f/5/1/nqjy8fpqskdj.jpg" + ], + "description": "<p>BDISO: https://exoticaz.to/torrent/34023</p>", + "created_at": "2021-03-17 01:27:10" + }, + { + "id": 38628, + "url": "https://exoticaz.to/torrent/38628-ssni-344-yua-mikami-ever-since-that-day-when-my-father-in-law-raped-me", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-344] Yua Mikami - Ever Since That Day When My Father-In-Law Raped Me…", + "file_size": 4026734664, + "file_count": 1, + "seed": 36, + "leech": 0, + "completed": 346, + "downloaded": 452, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "188": "fingering", + "221": "cum.in.mouth", + "264": "69", + "314": "father.in.law", + "1938": "bondage" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/5/4/8/xsy82pxdr3fg.jpg", + "images/torrent/e/0/4/ltmcv1vjonh0.jpg", + "images/torrent/d/a/a/lm2ayvkwezm2.jpg", + "images/torrent/f/d/9/l0choedqagqh.jpg", + "images/torrent/8/6/2/6ibzlv7s9mlc.jpg", + "images/torrent/6/f/e/juc07vprbndp.jpg" + ], + "description": null, + "created_at": "2021-02-28 08:42:42" + }, + { + "id": 38281, + "url": "https://exoticaz.to/torrent/38281-ssni-989-during-her-business-trip-to-her-surprise-she-was-booked-into-the-same-hotel-room-with-her-asshole-boss-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-989] During Her Business Trip, To Her Surprise, She Was Booked Into The Same Hotel Room With Her Asshole Boss - Yua Mikami", + "file_size": 8001904519, + "file_count": 1, + "seed": 50, + "leech": 0, + "completed": 482, + "downloaded": 618, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "41": "big.tits", + "102": "idol", + "153": "cheating", + "251": "wife", + "370": "kissing", + "383": "hairy.pussy", + "431": "cum.on.tits", + "536": "spa.resort.or.inn", + "561": "blind.fold", + "566": "boob.job", + "842": "traditional.dress" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/8/0/1/cjdpkiqlm6sx.jpg", + "images/torrent/6/0/8/ghgwjtp3hpxf.jpg", + "images/torrent/4/e/3/sfqqq2yhm2pc.jpg", + "images/torrent/0/b/9/q9k73coj5d3s.jpg", + "images/torrent/0/0/a/tld906ldqmb7.jpg", + "images/torrent/0/a/a/ujpjijkuvqhh.jpg", + "images/torrent/f/c/0/vejb1cei6ojp.jpg", + "images/torrent/c/8/4/ymiqgbefa0uk.jpg", + "images/torrent/2/a/a/r4zwm5ieiqui.jpg", + "images/torrent/a/b/3/dyefvpvcjhpz.jpg", + "images/torrent/8/6/8/vazvb4ycnmb8.jpg" + ], + "description": "<p><strong>During Her Business Trip, To Her Surprise, She Was Booked Into The Same Hotel Room With Her Asshole Boss (Whom She Hates With A Passion) ... So He Banged Her With Excessive Lust And Relentless Piston-Pounding Thrusts And Kept This Big Tits Office Lady Cumming All Night Long Yua Mikami</strong></p>\n<p><strong>Website:</strong> https://www.s1s1s1.com/works/detail/ssni989/</p>\n<p><strong>R18:</strong> https://www.r18.com/videos/vod/movies/detail/-/id=ssni00989/</p>\n<p>+++ [HD] SSNI-989 出張先の旅館で大嫌いなセクハラ上司とまさかの相部屋に…絶倫過ぎる粘着ピストンで一晩中イカされ続けた巨乳OL 三上悠亜</p>", + "created_at": "2021-02-17 22:42:58" + }, + { + "id": 37072, + "url": "https://exoticaz.to/torrent/37072-ssni-963-the-top-sex-cosplayer-in-japan-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-963] The Top Sex Cosplayer In Japan - Yua Mikami", + "file_size": 6739705744, + "file_count": 1, + "seed": 20, + "leech": 0, + "completed": 171, + "downloaded": 216, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "41": "big.tits", + "71": "cosplay", + "102": "idol", + "377": "dildo", + "380": "mmf.threesome", + "566": "boob.job" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/a/7/a/n55o79exw2de.jpg", + "images/torrent/1/3/b/ndl3d7mekhgs.jpg", + "images/torrent/b/7/a/at998tmitmuv.jpg", + "images/torrent/f/f/f/ziejx48hvjan.jpg", + "images/torrent/c/6/d/einu9d3kqp6d.jpg", + "images/torrent/e/a/4/zqcsxzyz7pub.jpg", + "images/torrent/8/1/e/syl9ip0w7nlx.jpg", + "images/torrent/b/0/1/5io4sddiww2e.jpg", + "images/torrent/3/a/e/cgle6syx9txs.jpg", + "images/torrent/9/8/e/talwwtckcsei.jpg", + "images/torrent/6/6/9/1ms8yiiif82h.jpg" + ], + "description": "<p><strong>Website:</strong> https://www.s1s1s1.com/works/detail/ssni963/</p>\n<p><strong>R18:</strong> https://www.r18.com/videos/vod/movies/detail/-/id=ssni00963/</p>\n<p>+++ [HD] SSNI-963 日本一のSEXコスプレイヤー 三上悠亜</p>", + "created_at": "2021-01-16 02:52:11" + }, + { + "id": 36791, + "url": "https://exoticaz.to/torrent/36791-sivr-003-vr-vr-x-s1-national-idol-yua-mikami-straddles-and-has-sex-with-you-in-a-virtual-real-space", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SIVR-003] [VR] VR X S1 National Idol Yua Mikami Straddles And Has SEX With You In A Virtual Real Space", + "file_size": 2985740897, + "file_count": 1, + "seed": 17, + "leech": 0, + "completed": 138, + "downloaded": 188, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "6": "2160p", + "8": "VR 180°" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "43": "solo", + "462": "virtual.reality", + "1528": "subjectivity" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/4/d/4/qfmryjmtqumn.jpg", + "images/torrent/7/2/4/z8m75f3rfkvs.jpg", + "images/torrent/8/d/1/5ahodjvkkvim.jpg", + "images/torrent/f/c/2/ohva4frbmkgy.jpg", + "images/torrent/f/d/e/8nhu6ldkuhxa.jpg", + "images/torrent/b/3/e/q8yf2pgia59g.jpg", + "images/torrent/9/1/2/cxwbripa83ci.jpg", + "images/torrent/3/4/a/cksljosjwhlw.jpg", + "images/torrent/d/f/7/ehfhogpyfne8.jpg", + "images/torrent/0/9/7/bbbexxyexm8q.jpg", + "images/torrent/b/b/4/pampaacdzpoa.jpg" + ], + "description": "<p>credits to perfectcanary</p>", + "created_at": "2021-01-09 03:44:31" + }, + { + "id": 36790, + "url": "https://exoticaz.to/torrent/36790-sivr-002-vr-vr-x-s1-national-idol-yua-mikami-has-the-best-handjob-just-for-you-in-a-virtual-real-room", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SIVR-002] [VR] VR X S1 National Idol Yua Mikami Has The Best Handjob Just For You In A Virtual Real Room", + "file_size": 1858238654, + "file_count": 1, + "seed": 13, + "leech": 0, + "completed": 96, + "downloaded": 132, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "6": "2160p", + "8": "VR 180°" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "43": "solo", + "462": "virtual.reality", + "1528": "subjectivity" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/5/e/e/eur6g7gh4tkz.jpg", + "images/torrent/f/b/2/qgdrhxxvadcj.jpg", + "images/torrent/1/b/0/kxlgjlclgv6g.jpg", + "images/torrent/3/d/6/79swii8xpr7r.jpg", + "images/torrent/1/4/b/ewvxgj8njnzz.jpg", + "images/torrent/d/c/a/eilsovnz0zi6.jpg", + "images/torrent/4/a/9/zwf2mxbt8zat.jpg", + "images/torrent/e/f/9/neqgkp0m3mpi.jpg", + "images/torrent/4/a/0/t7ysvrmqhuk8.jpg", + "images/torrent/8/b/d/fgttaluuvma1.jpg", + "images/torrent/1/3/4/y47zrjs3etf7.jpg", + "images/torrent/a/a/c/hyaed34gxuic.jpg" + ], + "description": "<p>credits to perfectcanary</p>", + "created_at": "2021-01-09 03:44:02" + }, + { + "id": 36789, + "url": "https://exoticaz.to/torrent/36789-sivr-001-vr-vr-x-s1-national-idol-yua-mikami-gives-a-blowjob-in-a-virtual-real-space-just-for-you", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SIVR-001] [VR] VR X S1 National Idol Yua Mikami Gives A Blowjob In A Virtual Real Space Just For You", + "file_size": 1859418599, + "file_count": 1, + "seed": 13, + "leech": 0, + "completed": 96, + "downloaded": 125, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "6": "2160p", + "8": "VR 180°" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "43": "solo", + "462": "virtual.reality", + "1528": "subjectivity" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/b/0/2/hhlqlwrre6mx.jpg", + "images/torrent/0/8/3/tmsmh0txpxvu.jpg", + "images/torrent/e/c/b/ta2wvbfhjye3.jpg", + "images/torrent/a/a/1/dk9hcpkoipdo.jpg", + "images/torrent/5/9/a/ijsdz5mgktpo.jpg", + "images/torrent/6/8/d/ssqpx3q4phin.jpg", + "images/torrent/6/a/b/0thciatyyanx.jpg", + "images/torrent/9/0/e/7aeisoeaza1f.jpg", + "images/torrent/7/e/8/nk8wbosgceen.jpg", + "images/torrent/c/5/6/gzkd8vyuj90h.jpg", + "images/torrent/9/9/8/lff4uuevidgp.jpg", + "images/torrent/7/8/6/3uotc2hw7s6l.jpg" + ], + "description": "<p>credits to perfectcanary</p>", + "created_at": "2021-01-09 03:42:52" + }, + { + "id": 36465, + "url": "https://exoticaz.to/torrent/36465-sivr-067-a-complete-monopoly-on-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SIVR-067] A Complete Monopoly On Yua Mikami!", + "file_size": 20001174871, + "file_count": 3, + "seed": 30, + "leech": 0, + "completed": 172, + "downloaded": 231, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "6": "2160p", + "8": "VR 180°" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "105": "pov" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/8/a/9/tsxc5nmxhi6q.jpg", + "images/torrent/b/5/9/kj4kzceqwcqe.jpg", + "images/torrent/2/6/c/wehsij26mp3e.jpg", + "images/torrent/6/b/4/vzbu0rnpe1j6.jpg", + "images/torrent/8/5/e/nbggox8jt5iv.jpg", + "images/torrent/7/6/6/a1li6gqrwfjr.jpg", + "images/torrent/6/3/2/neub518zozre.jpg", + "images/torrent/8/7/7/ymkbsu7hr6tr.jpg", + "images/torrent/4/4/a/vgecldmea9sm.jpg", + "images/torrent/3/4/e/r7jihkje6ipc.jpg", + "images/torrent/c/f/2/pufqnudlbosl.jpg", + "images/torrent/1/1/3/3jp9bzibijwl.jpg", + "images/torrent/8/d/8/nubrpo4674nv.jpg", + "images/torrent/3/b/f/qfzwsiqg8f5b.jpg", + "images/torrent/7/5/b/b1veealqoysq.jpg", + "images/torrent/1/1/a/x6yztt33psfz.jpg" + ], + "description": "<p>配信開始日: 2020/02/07<br>商品発売日: 2020/02/07<br>収録時間: 87分 (HQ版:87分)<br>出演者: 三上悠亜<br>監督: ZAMPA<br>シリーズ: S1 VR<br>メーカー: エスワン ナンバーワンスタイル<br>レーベル: S1 VR<br>コンテンツタイプ: 3D<br>ジャンル: ハイクオリティVR 独占配信 単体作品 VR専用 騎乗位 巨乳 アイドル・芸能人 主観<br>品番: sivr00067</p>\n<p>待望のHQ超なめらか高画質VRで三上悠亜とボクのエッチで可愛すぎる神同棲生活!「僕の彼女はトップAVアイドルの、あの三上悠亜.・」超多忙なトップAVアイドルでありながら、実はこっそりボクと付き合っている夢のような展開!愛されて、心配されて、嫉妬されて、普段は見れない等身大のアイドルの素顔を完全独占!最高の距離感で四六時中SEXに明け暮れる究極同棲VR</p>", + "created_at": "2020-12-30 13:29:53" + }, + { + "id": 36096, + "url": "https://exoticaz.to/torrent/36096-ssni-939-teased-to-your-limit-edging-and-aphrodisiac-orgasms-the-ultimate-pleasure-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-939] Teased To Your Limit - Edging And Aphrodisiac Orgasms - The Ultimate Pleasure Yua Mikami", + "file_size": 25531591874, + "file_count": 1, + "seed": 17, + "leech": 0, + "completed": 145, + "downloaded": 204, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "6": "2160p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "41": "big.tits", + "44": "toys", + "102": "idol", + "141": "masturbation", + "187": "squirting" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/0/0/b/idkwbzd348wh.jpg", + "images/torrent/5/4/4/hjbe4o7efccw.jpg", + "images/torrent/9/8/6/a1spvam3hqxg.jpg", + "images/torrent/a/7/7/toaagqiqmvdz.jpg", + "images/torrent/6/3/f/larx7lakew5j.jpg", + "images/torrent/8/7/a/mcpaf5gbxl49.jpg", + "images/torrent/8/6/f/yn7cwvirhxsh.jpg", + "images/torrent/3/9/3/kmne2etpj3mu.jpg", + "images/torrent/e/0/b/nqpynhwabitg.jpg", + "images/torrent/b/1/9/mlqi04pbnxbi.jpg", + "images/torrent/1/9/e/dtxkxrwdpf3m.jpg" + ], + "description": "<p><strong>Website:</strong> https://www.s1s1s1.com/works/detail/ssni939/</p>\n<p><strong>R18:</strong> https://www.r18.com/videos/vod/movies/detail/-/id=ssni00939/</p>\n<p><strong>1080p</strong> : https://exoticaz.to/torrent/35862</p>", + "created_at": "2020-12-22 00:57:11" + }, + { + "id": 35862, + "url": "https://exoticaz.to/torrent/35862-ssni-939-teased-to-your-limit-edging-and-aphrodisiac-orgasms-the-ultimate-pleasure-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-939] Teased To Your Limit - Edging And Aphrodisiac Orgasms - The Ultimate Pleasure Yua Mikami", + "file_size": 7133201320, + "file_count": 1, + "seed": 18, + "leech": 0, + "completed": 195, + "downloaded": 228, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "41": "big.tits", + "44": "toys", + "102": "idol", + "141": "masturbation", + "187": "squirting" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/8/a/b/qapjbsbyqhda.jpg", + "images/torrent/5/2/4/gstqj72sx2kv.jpg", + "images/torrent/7/9/4/vgwtaaakdh6u.jpg", + "images/torrent/6/1/6/mqwqvlugfwje.jpg", + "images/torrent/3/a/3/4tzbe4zqijzf.jpg", + "images/torrent/6/b/1/csbpoamvtvcp.jpg", + "images/torrent/d/3/5/4osxim7lpyja.jpg", + "images/torrent/c/0/c/28l2b8c78rak.jpg", + "images/torrent/3/f/c/am0tvy1bvvhm.jpg", + "images/torrent/b/4/2/63yizaow815k.jpg", + "images/torrent/a/9/4/ksgywpxmjg9h.jpg" + ], + "description": "<p><strong>Website:</strong> https://www.s1s1s1.com/works/detail/ssni939/</p>\n<p><strong>R18:</strong> https://www.r18.com/videos/vod/movies/detail/-/id=ssni00939/</p>\n<p>+++ [HD] SSNI-939 執拗な焦らしと寸止めで極限まで感度を高めた恍惚キメセク大絶頂FUCK 三上悠亜</p>", + "created_at": "2020-12-17 03:16:29" + }, + { + "id": 34686, + "url": "https://exoticaz.to/torrent/34686-ssni-916-big-tits-bursting-out-of-her-school-swimsuit-former-bikini-model-teacher-gets-drenched-gets-horny-gets-drilled-yua-mikami-big-tits-bursting-out-of-her-school-swimsuit", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-916] Big Tits Bursting Out Of Her School Swimsuit - Former Bikini Model Teacher Gets Drenched, Gets Horny, Gets Drilled Yua Mikami Big Tits Bursting Out Of Her School Swimsuit", + "file_size": 6775799968, + "file_count": 1, + "seed": 50, + "leech": 0, + "completed": 513, + "downloaded": 627, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "102": "idol", + "109": "teacher", + "566": "boob.job", + "578": "bathing.suit" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/b/c/e/pjjjy2b7qfxm.jpg", + "images/torrent/8/8/4/eyimiyosenku.jpg", + "images/torrent/e/a/7/zsimdjtt4jgc.jpg", + "images/torrent/b/f/e/slvfuqmqtzko.jpg", + "images/torrent/a/b/7/9urruytq6tmx.jpg", + "images/torrent/8/d/9/8rhpgsctlxbl.jpg", + "images/torrent/5/a/7/edwi6nzpqkhh.jpg", + "images/torrent/1/6/9/lm9vsr8wykk4.jpg", + "images/torrent/a/1/9/ediknyrpjcm8.jpg", + "images/torrent/3/9/b/zonnqckhdvpy.jpg", + "images/torrent/f/a/7/ksuy5dhkffa5.jpg", + "images/torrent/d/9/1/bwlnfr7basnd.jpg", + "images/torrent/4/a/b/tausgrghwsai.jpg", + "images/torrent/9/9/6/zywu0gx19aev.jpg", + "images/torrent/0/e/3/x3gbvpggq4r6.jpg", + "images/torrent/8/e/8/8xeryczqzl9g.jpg", + "images/torrent/9/f/8/h1crylyzbuql.jpg", + "images/torrent/9/9/c/pt9hjlaxohrp.jpg", + "images/torrent/3/0/4/dtb70p4cfkhi.jpg" + ], + "description": "<p><strong>Website:</strong> https://www.s1s1s1.com/works/detail/ssni916/</p>\n<p><strong>R18:</strong> https://www.r18.com/videos/vod/movies/detail/-/id=ssni00916/</p>\n<p>+++ [HD] SSNI-916 スク水巨乳の水泳部顧問は元グラビアアイドル…濡れ透ける先生の巨乳に我慢できなくて、じっとり汗だくひたすら密着交尾 三上悠亜</p>\n<p>Play with the water in the classroom or in the pool.... Wet nipples, spilling god milk, high leg that eats into the crotch. Meat feeling Sk water dynamite to nail the students! Healthy BODY and Rodro Special SEX Bathed In The Shining Midsummer Sun! Unstoppable sexual desire of the unending men flocking to the squiring big that attach perfectly with dripping sweat! The Swimsuit Big That Shake Violently Is While Wearing It! All boys love their teachers.</p>\n<p>Release Date:<br>Nov. 19, 2020</p>\n<p>Runtime:<br>145min.  (HD: 145min.)</p>\n<p>Director:<br>ZAMPA</p>\n<p>Studio:<br>S1 NO.1 STYLE</p>\n<p>Label:<br>S1 NO.1 STYLE</p>\n<p>Channel:<br>----</p>\n<p>Content ID:<br>ssni00916</p>\n<p>DVD ID:<br>SSNI-916</p>\n<p>Series:<br>----</p>\n<p>Languages:<br>Japanese</p>", + "created_at": "2020-11-18 23:55:07" + }, + { + "id": 34051, + "url": "https://exoticaz.to/torrent/34051-ssni-344-ever-since-that-day-when-my-father-in-law-raped-me-yua-mikami-bluray", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-344] Ever Since That Day When My Father-In-Law Raped Me… Yua Mikami -Bluray", + "file_size": 26941194240, + "file_count": 1, + "seed": 5, + "leech": 1, + "completed": 75, + "downloaded": 128, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "188": "fingering", + "221": "cum.in.mouth", + "264": "69", + "314": "father.in.law", + "1924": "disc.image", + "1938": "bondage" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/1/2/1/gojcr8ofgl4y.jpg", + "images/torrent/5/c/e/hirwoeoabu95.jpg", + "images/torrent/a/c/2/0z7dkaw0imgu.jpg", + "images/torrent/2/a/0/w2inau5ij5fg.jpg", + "images/torrent/9/a/9/cavrfaesekap.jpg", + "images/torrent/4/e/0/dvghr5k4x6g6.jpg", + "images/torrent/9/e/9/0ocpe6n3lsc6.jpg" + ], + "description": "<p>Title: Ever Since That Day When My Father-In-Law Raped Me… Yua Mikami</p>\n<p>Date: October 22, 2019  </p>\n<p>Time: 02:29:00<br><br>Pornstars: Yua Mikami</p>\n<p>Studio: S1 NO.1 Style</p>", + "created_at": "2020-11-03 06:16:30" + }, + { + "id": 34049, + "url": "https://exoticaz.to/torrent/34049-tek-072-climax-x-4-hardcore-scenes-yua-mikami-bluray", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[TEK-072] Climax x 4 Hardcore Scenes Yua Mikami - Bluray", + "file_size": 31840927744, + "file_count": 1, + "seed": 2, + "leech": 0, + "completed": 59, + "downloaded": 98, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "38": "MUTEKI" + }, + "tags": { + "2": "japanese", + "41": "big.tits", + "142": "threesome", + "165": "facial", + "188": "fingering", + "229": "lingerie", + "575": "body.licking", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/c/3/d/obuyianqids4.jpg", + "images/torrent/f/f/d/kqlmtqvjv8li.jpg", + "images/torrent/4/2/1/3kdpwd1pkytw.jpg", + "images/torrent/8/7/a/oyr7kh71oqao.jpg", + "images/torrent/a/f/c/klqbx5beqj37.jpg", + "images/torrent/c/9/b/wscmqe1ndq8x.jpg", + "images/torrent/9/0/4/5yho2mvumies.jpg" + ], + "description": "<p>Title: TEK-072 Climax x 4 Hardcore Scenes Yua Mikami</p>\n<p>Date: August 1, 2020</p>\n<p>Time: 02:55:00</p>\n<p>Pornstars: Yua Mikami</p>\n<p>Studio: MUTEKI</p>\n<p>https://www.javlibrary.com/en/?v=javlild2tm</p>", + "created_at": "2020-11-03 06:06:51" + }, + { + "id": 34024, + "url": "https://exoticaz.to/torrent/34024-ssni-301-yua-mikami-is-completely-tied-down-and-unable-to-move-unlimited-piston-pounding-fucks-that", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-301] Yua Mikami Is Completely Tied Down And Unable To Move Unlimited Piston Pounding Fucks That", + "file_size": 28846587904, + "file_count": 1, + "seed": 7, + "leech": 0, + "completed": 60, + "downloaded": 98, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "165": "facial", + "188": "fingering", + "276": "restraint", + "380": "mmf.threesome", + "583": "leash", + "1924": "disc.image", + "1938": "bondage" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/3/0/2/mk1j5n9jftj8.jpg", + "images/torrent/a/4/6/wt7nr57zelsx.jpg", + "images/torrent/0/f/d/lcxd9zo8x0xc.jpg", + "images/torrent/1/8/5/mxt2ah99lqk6.jpg", + "images/torrent/5/4/7/qqqehdehpugk.jpg", + "images/torrent/d/3/2/qeylkbizibzy.jpg" + ], + "description": "<p>Titile: Yua Mikami Is Completely Tied Down And Unable To Move Unlimited Piston Pounding Fucks That</p>\n<p>Date: October 22, 2019  </p>\n<p>Time: 02:34:00</p>\n<p>Pornstars: Yua Mikami</p>\n<p>Studio: S1 NO.1 Style</p>", + "created_at": "2020-11-02 05:13:10" + }, + { + "id": 34023, + "url": "https://exoticaz.to/torrent/34023-ssni-388-yua-mikami-in-a-16-consecutive-cum-shot-slut-assault-shes-tied-up-men-for-some", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-388] Yua Mikami In A 16-Consecutive Cum Shot Slut Assault She’s Tied Up Men For Some", + "file_size": 22152347648, + "file_count": 1, + "seed": 6, + "leech": 0, + "completed": 53, + "downloaded": 89, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "83": "oil.or.lotion", + "229": "lingerie", + "425": "femdom", + "1924": "disc.image", + "1938": "bondage" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/f/5/b/dotftnd1wsxd.jpg", + "images/torrent/1/c/e/jizybiagahbz.jpg", + "images/torrent/a/0/1/dbkvpcmp6pjx.jpg", + "images/torrent/c/9/d/y5apj9jkd4gu.jpg", + "images/torrent/c/0/2/pvoql1zscpdl.jpg" + ], + "description": "<p>Title: SSNI-388 Yua Mikami In A 16-Consecutive Cum Shot Slut Assault She’s Tied Up Men For Some</p>\n<p>Date: October 22, 2019</p>\n<p>Pornstars: Yua Mikami</p>\n<p>Studio: S1 NO.1 Style</p>\n<p>Time: 02:04:00</p>", + "created_at": "2020-11-02 04:57:51" + }, + { + "id": 33466, + "url": "https://exoticaz.to/torrent/33466-ssni-888-cant-stop-climaxing-these-orgasms-will-last-you-for-life-48-hours-of-extreme-ecstasy-with-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-888] Can't Stop Climaxing - These Orgasms Will Last You For Life - 48 Hours Of Extreme Ecstasy With Yua Mikami", + "file_size": 7416760344, + "file_count": 1, + "seed": 23, + "leech": 0, + "completed": 263, + "downloaded": 310, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "41": "big.tits", + "83": "oil.or.lotion", + "102": "idol", + "144": "documentary", + "187": "squirting", + "188": "fingering", + "370": "kissing" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/1/3/a/3yhyl5u1ajua.jpg", + "images/torrent/9/8/9/wobim6ohzmfw.jpg", + "images/torrent/1/a/e/z3qy5zc46rzf.jpg", + "images/torrent/c/1/e/zzexoipq42cs.jpg", + "images/torrent/2/c/e/udqrn7rxgebh.jpg", + "images/torrent/4/b/2/g8kza2u6ewky.jpg", + "images/torrent/0/d/8/jzinquguy7ur.jpg", + "images/torrent/0/5/4/t9l79vggbimx.jpg", + "images/torrent/9/f/5/j87pkr21v6xu.jpg", + "images/torrent/6/e/4/fctknioo95eh.jpg", + "images/torrent/1/6/0/bwivpujoltwr.jpg" + ], + "description": "<p><strong>Website:</strong> https://www.s1s1s1.com/works/detail/ssni888/</p>\n<p><strong>R18:</strong> https://www.r18.com/videos/vod/movies/detail/-/id=ssni00888/</p>\n<p>+++ [HD] SSNI-888 絶頂の向こう側でイッてイッてイキまくる確変オーガズム状態のまま48時間耐久で一生分ハメまくった三上悠亜のヤバい性交</p>", + "created_at": "2020-10-17 01:29:36" + }, + { + "id": 32469, + "url": "https://exoticaz.to/torrent/32469-ssni-865-big-tits-office-lady-and-cherry-boy-boss-weekly-escalations-into-weekend-sexy-overtime-work-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-865] Big Tits Office Lady And Cherry Boy Boss' Weekly Escalations Into Weekend Sexy Overtime Work. Yua Mikami", + "file_size": 7520516682, + "file_count": 1, + "seed": 21, + "leech": 0, + "completed": 302, + "downloaded": 368, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "41": "big.tits", + "133": "pantyhose", + "140": "cherry.boy", + "188": "fingering", + "217": "office.lady" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/a/f/4/nf2kb4ek4jl0.jpg", + "images/torrent/9/2/6/fachcvmybmxf.jpg", + "images/torrent/6/9/8/dlgq3knm9v8f.jpg", + "images/torrent/8/4/4/ihzkcvgdumk6.jpg", + "images/torrent/c/8/f/5pdukhdlv8nx.jpg", + "images/torrent/e/1/9/q5vsxel5wess.jpg", + "images/torrent/6/6/6/egdxb2kgwv3j.jpg", + "images/torrent/2/b/4/l5dkvxtxq9yv.jpg", + "images/torrent/c/6/0/rovfejpd7rtb.jpg", + "images/torrent/5/a/f/bt9irmjmbbry.jpg", + "images/torrent/7/f/4/qn6q2w8bgjzg.jpg" + ], + "description": "<p><strong>Website:</strong> https://www.s1s1s1.com/works/detail/ssni865/</p>\n<p><strong>R18:</strong> https://www.r18.com/videos/vod/movies/detail/-/id=ssni00865/</p>\n<p>+++ [HD] SSNI-865 巨乳OLと絶倫童貞上司の毎週エスカレートする週末のセックス残業 三上悠亜</p>", + "created_at": "2020-09-17 03:27:12" + }, + { + "id": 31490, + "url": "https://exoticaz.to/torrent/31490-yua-mikami-megapack-2020", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "4": "Pornstar Pack" + }, + "info_hash": "(removed)", + "file_name": "Yua Mikami Megapack 2020", + "file_size": 275556040351, + "file_count": 51, + "seed": 30, + "leech": 4, + "completed": 289, + "downloaded": 508, + "upload_multiply": 1, + "download_multiply": 0, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "4": "720p", + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style", + "11": "Moodyz", + "81": "Air Control" + }, + "tags": null, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/a/0/c/bqwczwafkej6.jpg", + "images/torrent/9/a/c/7aav55slsvmi.jpg", + "images/torrent/b/b/7/emhygm89qjnl.jpg", + "images/torrent/7/9/a/f6d0smw7bsms.jpg", + "images/torrent/a/c/8/6rwl8vdo1rfs.jpg", + "images/torrent/c/a/c/ifhzlk5onpl7.jpg", + "images/torrent/3/9/a/2pbhpr7mrig1.jpg", + "images/torrent/f/4/f/wcv5iagcdabl.jpg", + "images/torrent/9/d/3/juf6ey2rbevl.jpg", + "images/torrent/2/6/a/xbcxlsowbml6.jpg", + "images/torrent/5/f/9/pgr13wjtywvr.jpg", + "images/torrent/c/4/3/gretk8cxe2s6.jpg", + "images/torrent/d/e/b/ou4ekewxfhl0.jpg", + "images/torrent/a/7/8/5ajxcgbpf6rd.jpg", + "images/torrent/f/f/e/flboeb5fhu3u.jpg", + "images/torrent/5/1/a/ulagzlr89ba7.jpg", + "images/torrent/5/4/d/xqbtgdnbdrxh.jpg", + "images/torrent/0/7/d/mhswpaknof8k.jpg", + "images/torrent/f/5/0/g2cy54kpiiov.jpg", + "images/torrent/5/2/9/tsjo7cykewmn.jpg", + "images/torrent/1/0/8/loubf0z1igtr.jpg", + "images/torrent/e/4/3/jgk9cgoywfmd.jpg", + "images/torrent/7/f/b/u1nytcpjsxrk.jpg", + "images/torrent/8/b/7/6sx9wem4qwm3.jpg", + "images/torrent/c/3/3/2ljzjdhmsqcm.jpg", + "images/torrent/b/8/b/fdj6eteztjyq.jpg", + "images/torrent/1/f/7/rxnnfjosu5jx.jpg", + "images/torrent/b/b/3/cij7zbibatii.jpg", + "images/torrent/2/3/3/mjsvf9gayqrs.jpg", + "images/torrent/c/6/7/4ffewwvqcui3.jpg", + "images/torrent/d/4/1/icbiossus4xt.jpg", + "images/torrent/4/5/5/nia2ymu4jzv7.jpg", + "images/torrent/f/9/1/mgfl2vbm3a1n.jpg", + "images/torrent/f/e/4/ktbihndgaecd.jpg", + "images/torrent/4/8/e/kpdadu6ifxp8.jpg", + "images/torrent/5/3/6/xknibpdjqjkq.jpg", + "images/torrent/4/b/1/xhc7hhyv1sn5.jpg", + "images/torrent/c/a/a/8ie9csjrflos.jpg", + "images/torrent/4/b/4/mmsqtfwbmfvl.jpg", + "images/torrent/5/1/b/wvzuscujqxmr.jpg", + "images/torrent/4/0/1/mx0nsryeqrsl.jpg", + "images/torrent/9/e/8/9ip1e9vztmvy.jpg", + "images/torrent/f/4/a/mavkuqj8lspd.jpg", + "images/torrent/3/8/5/b2arm5zmaiun.jpg", + "images/torrent/9/9/d/ltjpjqgqptvx.jpg", + "images/torrent/5/d/4/mnpa9d853ftt.jpg", + "images/torrent/f/7/4/p7ienc1chxct.jpg", + "images/torrent/5/e/c/ulmwjdu8nt01.jpg", + "images/torrent/e/0/0/4jylp8a3ltuv.jpg", + "images/torrent/7/1/7/a8gspbxnlfsy.jpg", + "images/torrent/0/a/7/s9ecxadoaumn.jpg", + "images/torrent/9/b/b/p1qz8a1yfwtj.jpg", + "images/torrent/e/4/3/ek2bew9ask1c.jpg", + "images/torrent/3/0/2/fktd0n8qg0dj.jpg", + "images/torrent/d/0/1/ic0tqlwkhaxa.jpg", + "images/torrent/2/9/0/v78cex0q2hrq.jpg", + "images/torrent/9/1/3/fcyckakveagi.jpg", + "images/torrent/7/0/0/y6rw8f1n0vet.jpg", + "images/torrent/e/c/9/ymb2hcglzuxi.jpg", + "images/torrent/6/1/c/bncxy6t3co1v.jpg", + "images/torrent/5/c/d/djyautfqxmq9.jpg", + "images/torrent/d/8/7/kxarysuzqlte.jpg", + "images/torrent/8/1/c/ierxwmc8cn8r.jpg", + "images/torrent/c/3/3/bn9jmis3pbmt.jpg", + "images/torrent/8/2/d/kfxylkkay3ij.jpg", + "images/torrent/3/e/9/voxxhpgth5cg.jpg", + "images/torrent/4/d/6/lkcxjyc8ncfm.jpg", + "images/torrent/c/5/7/w45r7zmsciau.jpg", + "images/torrent/1/f/0/6lsnmhxsj7hi.jpg", + "images/torrent/3/e/d/auoizkmekvoh.jpg", + "images/torrent/4/9/1/qnixwr1nma4w.jpg", + "images/torrent/c/4/a/mwj72amzyyzf.jpg", + "images/torrent/f/6/2/g0aqeu8znpkb.jpg", + "images/torrent/1/b/d/0rdo0rgvbsn7.jpg", + "images/torrent/d/8/8/nddx4lmsto34.jpg", + "images/torrent/f/d/5/ukrpkexzmphm.jpg", + "images/torrent/1/1/3/lbz721dpfiby.jpg", + "images/torrent/4/6/c/enf8al6yebfj.jpg", + "images/torrent/1/f/d/t9dumvd4xkk7.jpg", + "images/torrent/b/5/5/iarrm0vw42ck.jpg", + "images/torrent/4/6/8/dq9up062in7d.jpg", + "images/torrent/0/4/5/44rpjkuzu6ej.jpg", + "images/torrent/a/a/9/uobfmnh44ytn.jpg", + "images/torrent/8/6/7/lwoquy5b1plv.jpg", + "images/torrent/e/5/c/xu2a9vxxlnej.jpg", + "images/torrent/5/2/e/msaxk4qrpbjd.jpg", + "images/torrent/d/f/3/tco02iq8swvl.jpg", + "images/torrent/b/2/8/ukjivoy8f2jx.jpg", + "images/torrent/8/e/2/ftxbjgzknhta.jpg", + "images/torrent/4/0/0/9w5fbohx7kwe.jpg", + "images/torrent/8/1/6/aaoqcgu19wlz.jpg", + "images/torrent/5/7/6/mhhovjofjypp.jpg", + "images/torrent/e/0/3/54kjnz75finw.jpg", + "images/torrent/6/a/7/ww88yqsccxok.jpg", + "images/torrent/5/f/5/gibp2izdl6ql.jpg", + "images/torrent/f/a/f/ek8w0wwxqy1w.jpg", + "images/torrent/4/a/0/nrkow2ql5rpe.jpg", + "images/torrent/e/b/8/wbdtnegblcwn.jpg", + "images/torrent/3/4/a/kgimr5tzdvqu.jpg", + "images/torrent/5/b/7/68efiotj1vcx.jpg", + "images/torrent/3/8/7/e6xsq2x0xv8f.jpg", + "images/torrent/3/f/e/dsfwaamsxmpu.jpg", + "images/torrent/f/1/1/hluuii48dpm8.jpg", + "images/torrent/2/6/e/yxn0wbpcmzrj.jpg", + "images/torrent/3/3/7/4jgrkwnpmwa5.jpg", + "images/torrent/7/7/7/hsk890w3vc4e.jpg", + "images/torrent/3/7/9/x8viw2xhxtx6.jpg", + "images/torrent/5/7/0/icei97wfuhjm.jpg", + "images/torrent/a/b/4/iaautm9wxc8y.jpg", + "images/torrent/5/f/0/cqd91hfbt1lb.jpg", + "images/torrent/7/8/8/e4im1uj1unpe.jpg", + "images/torrent/0/2/7/i3npdqchrlbi.jpg", + "images/torrent/1/8/8/q4ox3lyttxyo.jpg", + "images/torrent/5/9/f/3ik05eycgp8i.jpg", + "images/torrent/2/0/e/vnluxb8amlt9.jpg", + "images/torrent/4/3/a/dtercbmhmkdi.jpg", + "images/torrent/2/f/c/kmlbu9ookhuu.jpg", + "images/torrent/6/b/7/r03o6pysqnde.jpg", + "images/torrent/9/a/9/ngmiema9ucly.jpg", + "images/torrent/c/a/9/frjf20lbaiyp.jpg", + "images/torrent/8/5/a/xznmkfydxsnb.jpg", + "images/torrent/e/f/6/8z6plgk1eosy.jpg", + "images/torrent/9/c/e/muiyandtfvhj.jpg", + "images/torrent/f/e/1/rr5ntjvirrlm.jpg", + "images/torrent/c/e/a/qkzlzntru6o3.jpg", + "images/torrent/9/f/1/qckqlz0vkkp5.jpg", + "images/torrent/3/1/c/vls4caonuenn.jpg", + "images/torrent/b/5/3/yt9qwso4qhqo.jpg", + "images/torrent/4/7/8/yxjboxnb0s6j.jpg", + "images/torrent/a/a/d/wweaqu92qrld.jpg", + "images/torrent/9/1/0/f3kqjy9u9j2g.jpg", + "images/torrent/9/3/1/lco7fbndoosj.jpg", + "images/torrent/c/b/1/watszleifh68.jpg", + "images/torrent/a/f/b/kljsxsgfpoow.jpg", + "images/torrent/a/6/1/ptesuuqnd2sg.jpg", + "images/torrent/f/2/1/gnc8qzzigkfc.jpg", + "images/torrent/0/e/d/kjg8pvoqhwol.jpg", + "images/torrent/8/0/d/5g0xr7qpclso.jpg", + "images/torrent/d/1/e/xitvozy0wlkd.jpg", + "images/torrent/7/1/c/bul0mhlzrk1w.jpg", + "images/torrent/2/4/d/lfhcjpnhgilo.jpg", + "images/torrent/a/7/a/w0pp6zgkgzge.jpg", + "images/torrent/9/d/7/hodj00hrnljh.jpg", + "images/torrent/7/7/1/65laanl1pmyh.jpg", + "images/torrent/1/4/3/bvfq607bcyjq.jpg", + "images/torrent/3/e/0/gaguzrcwhewq.jpg", + "images/torrent/5/1/b/mqei1njuzlyv.jpg", + "images/torrent/e/7/c/1gippxxkue7k.jpg", + "images/torrent/2/3/c/e5il8pnbzwhn.jpg", + "images/torrent/f/4/c/xtitfwrtrscw.jpg", + "images/torrent/3/1/c/owhueywggbrl.jpg", + "images/torrent/b/1/2/p3dnykmohsbf.jpg", + "images/torrent/1/0/d/9wmpejovzbg7.jpg" + ], + "description": "<p>A quarter terabyte of Yua Mikami videos. Pretty close to a complete solo discography as of this date. Mostly 1080p, a few 720p. No super loud Chinese language ads at the beginnings of any videos, mostly unobtrusive watermarks. A few of the Muteki vids are decensored with the sorta annoying JAVPlayer watermark.</p>", + "created_at": "2020-08-20 00:49:29" + }, + { + "id": 31465, + "url": "https://exoticaz.to/torrent/31465-ssni-802-poor-teacher-trapped-at-school-during-a-storm-she-fucks-her-male-students-until-the-weather-clears-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-802] Poor Teacher - Trapped At School During A Storm, She Fucks Her Male Students Until The Weather Clears - Yua Mikami", + "file_size": 5398367415, + "file_count": 1, + "seed": 15, + "leech": 0, + "completed": 176, + "downloaded": 217, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "41": "big.tits", + "109": "teacher", + "153": "cheating", + "188": "fingering", + "370": "kissing", + "393": "cuckold", + "566": "boob.job" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/3/e/c/fo4pngwvgsht.jpg", + "images/torrent/d/e/5/3wdnrwna7srk.jpg", + "images/torrent/9/9/d/9b9xhxfe8xmq.jpg", + "images/torrent/2/d/e/erefrjrjmcn9.jpg", + "images/torrent/5/0/c/fx6lbhsb0wxx.jpg", + "images/torrent/8/9/1/1dvvbqmn25ba.jpg", + "images/torrent/a/a/4/vyhtka7467lb.jpg", + "images/torrent/6/e/e/6fm6kpst2a02.jpg", + "images/torrent/0/0/e/pa3i7jixn7qg.jpg", + "images/torrent/9/1/8/kl6xnz10l7rc.jpg", + "images/torrent/7/4/f/npjdewgqw8bj.jpg" + ], + "description": "<p><strong>Website:</strong> https://www.s1s1s1.com/works/detail/ssni802/</p>\n<p><strong>R18:</strong> https://www.r18.com/videos/vod/movies/detail/-/id=ssni00802/</p>\n<p>+++ [HD] SSNI-802 『教師失格』帰宅困難になったあの日、嵐が過ぎるまでひたすら男子生徒とハメまくりました…。 三上悠亜</p>\n<p>Release Date: June 14, 2020<br>Runtime: 117min.  (HD: 117min.)<br>Director: Amazing Meat<br>Studio: S1 NO.1 STYLE<br>Label: S1 NO.1 STYLE</p>\n<p>I'm a slut priest... On that day when a large typhoon hit directly, the two broke their line... On the night when it was difficult to return home, the unstoppable desire of a female teacher who shakes her big tits until the morning and gets turbulent like a storm. \"Much more... messed up... Ah... No... Iku...!!!\" \"Before I am a teacher, I am a woman...\"</p>", + "created_at": "2020-08-19 12:04:41" + }, + { + "id": 30383, + "url": "https://exoticaz.to/torrent/30383-ssni-826-yua-mikami-platinum-soap", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-826] Yua Mikami PLATINUM SOAP", + "file_size": 2080431595, + "file_count": 1, + "seed": 5, + "leech": 0, + "completed": 116, + "downloaded": 148, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "4": "720p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "44": "toys", + "431": "cum.on.tits", + "566": "boob.job", + "649": "soap" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/0/e/b/llk7oab85mmz.jpg", + "images/torrent/9/9/9/i3ciw7xmwson.jpg" + ], + "description": "<p>[SSNI-826] Yua Mikami 三上悠亜のPLATINUM SOAP 三上悠亞</p>\n<p>The finest customs to serve with the best body and best service! No matter how many times I ejaculate, the full erection doesn’t stop… I just ejaculated, but I’m jealous of any number of shots! Unlimited firing within the time. “Please give out as many shots as you want today.” Yua’s awesome technique will fulfill all your desires. For a while, Onakura, men’s esthetic, pin salo, SM club, finest soap. Platinum BODY and the finest service a total of 15 shots will ejaculate a special sex custom!</p>", + "created_at": "2020-07-27 10:51:58" + }, + { + "id": 29815, + "url": "https://exoticaz.to/torrent/29815-sivr-033vr-s1-15th-anniversary-special-extravagant-harem-and-reverse-threesome-yua-mikami-and-arina-hashimoto", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SIVR-033][VR] S1 15th Anniversary Special. Extravagant Harem And Reverse Threesome: Yua Mikami and Arina Hashimoto", + "file_size": 10648889543, + "file_count": 6, + "seed": 21, + "leech": 0, + "completed": 128, + "downloaded": 182, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "6": "2160p", + "8": "VR 180°" + }, + "studios": null, + "tags": { + "2": "japanese", + "99": "harem", + "142": "threesome", + "462": "virtual.reality" + }, + "performers": { + "16": "Yua MIKAMI", + "555": "Arina HASHIMOTO" + }, + "images": [ + "images/torrent/b/2/6/mkosypciv5ao.jpg", + "images/torrent/5/8/7/kqllkq1k2tf8.jpg", + "images/torrent/c/a/a/enpzytwamdxf.jpg", + "images/torrent/c/0/3/gstipfproits.jpg", + "images/torrent/d/f/4/fl1i1scjssss.jpg", + "images/torrent/a/6/a/7dfeunadac3w.jpg", + "images/torrent/b/9/3/wvu3uhkwmxbz.jpg" + ], + "description": "<p>【VR】エスワン15周年スペシャル共演 日本一のAV女優2人と超豪華ハーレム逆3P体験</p>\n<p>【VR】 15th Anniversary Of Esuan Special Co-starring 2 Best AV Actresses In Japan And A Super Luxury Harem Reverse 3P Experience</p>", + "created_at": "2020-07-14 07:28:09" + }, + { + "id": 29356, + "url": "https://exoticaz.to/torrent/29356-tek-067-princess-peach-yua-mikami-bluray", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[TEK-067] Princess Peach Yua Mikami - Bluray", + "file_size": 25025314816, + "file_count": 1, + "seed": 5, + "leech": 0, + "completed": 42, + "downloaded": 66, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "38": "MUTEKI" + }, + "tags": { + "142": "threesome", + "252": "princess", + "370": "kissing", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/5/0/8/zfejtem3ozpr.jpg", + "images/torrent/5/b/2/cijzvu5spoan.jpg", + "images/torrent/f/4/3/itbpaheajnk4.jpg", + "images/torrent/5/6/4/kdkmgw9mxjiy.jpg" + ], + "description": "<p>Title: TEK-067 Princess Peach Mikami YuA</p>\n<p>ID: TEK-067<br>Release Date: 2015-06-01<br>Length: 180 min(s)<br>Director: ----<br>Maker: Muteki  <br>Label: Muteki </p>\n<p>Ps: It was claimed to be the first real porn that Yua Mikami participated.</p>", + "created_at": "2020-07-08 01:32:21" + }, + { + "id": 29261, + "url": "https://exoticaz.to/torrent/29261-ssni-322-piston-pumping-ultra-large-orgies-special-yua-mikami-blueray", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-322] Piston Pumping Ultra Large Orgies Special Yua Mikami - BlueRay", + "file_size": 20293812224, + "file_count": 1, + "seed": 6, + "leech": 0, + "completed": 61, + "downloaded": 88, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "44": "toys", + "83": "oil.or.lotion", + "98": "orgy", + "165": "facial", + "187": "squirting", + "188": "fingering", + "377": "dildo", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/3/d/b/c2pehksxrsyq.jpg", + "images/torrent/0/3/6/mja8nehpzilg.jpg", + "images/torrent/0/b/4/golay2vdfoom.jpg", + "images/torrent/9/a/c/hocvufnx1xxg.jpg" + ], + "description": "<p><span style=\"font-size:20px;\"><strong>Full Title</strong></span>:  <span style=\"font-size:20px;\"><strong>Massive Cocks x Follow-Up Fucks x Large Orgies These 24 Massive Cocks Will Relentlessly Pump These Twitching And Cumming Pussies In A Furious Follow-Up Piston Pumping Ultra Large Orgies Special Yua Mikami<br></strong><br><span style=\"font-size:18px;\">Release Date: Oct. 18, 2018</span><br><span style=\"font-size:18px;\">Runtime: 117min.  (HD: 117min.)</span><br><span style=\"font-size:18px;\">Director: ZAMPA</span><br><span style=\"font-size:18px;\">Studio: S1 NO.1 STYLE</span><br><span style=\"font-size:18px;\">Label: S1 NO.1 STYLE<br>Channel: S1 NO.1 STYLE, PRIME<br>Content ID: ssni00322<br>DVD ID: SSNI-322<br><br><a href=\"https://awscc3001.r18.com/litevideo/freepv/s/ssn/ssni00322/ssni00322_dmb_w.mp4\">Trailer</a></span></span></p>", + "created_at": "2020-07-06 02:25:40" + }, + { + "id": 27208, + "url": "https://exoticaz.to/torrent/27208-snis-786-exclusive-no1-style-yua-mikamis-s1-debut-her-shocking-transfer-to-a-new-label-x-4-full-fuck-special", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SNIS-786] Exclusive NO.1 STYLE – Yua Mikami’s S1 Debut – Her Shocking Transfer To A New Label x 4-Full Fuck Special", + "file_size": 1846756046, + "file_count": 1, + "seed": 4, + "leech": 0, + "completed": 95, + "downloaded": 123, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "3": "480p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "41": "big.tits", + "43": "solo", + "803": "av.debut" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/4/c/1/efj88le0mjci.png", + "images/torrent/5/9/b/mo2v3qnws9lb.png", + "images/torrent/a/a/4/xun4sgqjg5su.png", + "images/torrent/5/4/d/mazhybews0es.png", + "images/torrent/d/7/6/c0tok2qmdvj6.png", + "images/torrent/7/e/a/d9zdbe0vo4up.png", + "images/torrent/4/2/3/4hbln5nagxul.png", + "images/torrent/d/3/d/ixs6pe8dbzgf.png", + "images/torrent/e/4/9/ns4b3ue3zad9.png", + "images/torrent/d/d/e/uglduxqjgbkq.png", + "images/torrent/b/a/3/imx3ym1ldtly.png", + "images/torrent/8/6/3/br1smc0lvdfy.png" + ], + "description": null, + "created_at": "2020-05-31 03:07:27" + }, + { + "id": 26018, + "url": "https://exoticaz.to/torrent/26018-tek-076-decensored-high-class-5-star-soapland-brothel-where-a-pop-star-will-service-you-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[TEK-076] [DECENSORED] High-Class 5-Star Soapland Brothel Where A Pop Star Will Service You Yua Mikami", + "file_size": 6773653262, + "file_count": 1, + "seed": 16, + "leech": 0, + "completed": 542, + "downloaded": 652, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "38": "MUTEKI" + }, + "tags": { + "2": "japanese", + "78": "slender", + "536": "spa.resort.or.inn", + "539": "soapy.massage", + "1390": "decensored" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/8/4/9/tekd6lp60cpx.jpg", + "images/torrent/c/e/d/fjzmigqdm3qt.jpg" + ], + "description": "<p><strong>Yua Mikami in awesome POV scene working as a 5star soapland popstar girI</strong></p>\n<p><strong>Infiltrate the soapland where the strongest national idol you have ever dreamed of works! ! Immediate scale blowjob & immediate etch of greeting unwashed cock! Full body lip to anal & toes! Vacuum periscope Blow while bathing in the bath! Adhesive slimy mat that will serve hard! Full charter feeling full course 180 minutes unlimited firing! \"Please go and enjoy today!\"</strong></p>\n<p><a href=\"https://www.r18.com/videos/vod/movies/detail/-/id=tek00076/?i3_ref=search&i3_ord=1\">https://www.r18.com/videos/vod/movies/detail/-/id=tek00076/?i3_ref=search&i3_ord=1</a></p>", + "created_at": "2020-03-16 20:11:31" + }, + { + "id": 26005, + "url": "https://exoticaz.to/torrent/26005-tek-079-decensored-lets-fuck-a-schoolgirl-idol-after-school-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[TEK-079] [DECENSORED] Let's Fuck A Schoolgirl Idol After School Yua Mikami", + "file_size": 6495815986, + "file_count": 1, + "seed": 18, + "leech": 0, + "completed": 408, + "downloaded": 490, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "38": "MUTEKI" + }, + "tags": { + "2": "japanese", + "44": "toys", + "86": "schoolgirl", + "102": "idol", + "240": "gym.clothes", + "1390": "decensored" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/2/8/a/4x0ah7uma6lt.jpg", + "images/torrent/6/5/4/lhkdfbqlsqlu.jpg" + ], + "description": "<p>One day before summer vacation, I had a crazy sex in the classroom at sunset when no one was there. Push down to the bed in the nurse's room, fill the face in the skirt, and rub the young and tender big tits and peach ass. Titty fuck and fellatio into school swimsuit. The best girl in school, take off the uniform of a national idol school girl who is too angelic and roll up after school! Youth school sex! \"It's a secret to everyone.\"</p>\n<p><a href=\"https://www.r18.com/videos/vod/movies/detail/-/id=tek00079/\">https://www.r18.com/videos/vod/movies/detail/-/id=tek00079/</a></p>", + "created_at": "2020-03-16 05:22:31" + }, + { + "id": 26004, + "url": "https://exoticaz.to/torrent/26004-tek-080-decensored-saliva-slick-tongues-intertwined-sex-with-hot-smothering-kisses-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[TEK-080] [DECENSORED] Saliva-Slick Tongues Intertwined: Sex With Hot, Smothering Kisses Yua Mikami", + "file_size": 7095501465, + "file_count": 1, + "seed": 14, + "leech": 0, + "completed": 333, + "downloaded": 412, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "38": "MUTEKI" + }, + "tags": { + "2": "japanese", + "142": "threesome", + "1390": "decensored" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/a/7/a/f7nasmwukv0y.jpg", + "images/torrent/c/5/d/n5ciceiboq1l.jpg" + ], + "description": "<p>\"More ... more kiss ...\" The obscene and hot sexy Kiss that the national idol Yua Mikami shows for the first time and the passion SEX that burns up! Temptation hot Licking Handjob & Footjob With A Lot Of drips. Saliva and pussy juice are intertwined and the pussy gets wet so shamefully! The climax FUCK of an odious kiss that licks the whole body of the idol! The most erotic idol of the strongest idol who pulls a string in love popularity sweaty kissing sex! !</p>\n<p><a href=\"https://www.r18.com/videos/vod/movies/detail/-/id=tek00080/\">https://www.r18.com/videos/vod/movies/detail/-/id=tek00080/</a></p>", + "created_at": "2020-03-16 05:15:51" + }, + { + "id": 25958, + "url": "https://exoticaz.to/torrent/25958-tek-073-decensored-my-girlfriend-is-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[TEK-073] [DECENSORED] My Girlfriend Is Yua Mikami", + "file_size": 6691380721, + "file_count": 1, + "seed": 12, + "leech": 0, + "completed": 424, + "downloaded": 525, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "38": "MUTEKI" + }, + "tags": { + "2": "japanese", + "41": "big.tits", + "188": "fingering", + "581": "bathroom", + "1390": "decensored" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/9/5/7/pu8ljkshbdvk.jpg", + "images/torrent/e/5/b/dtmfbfmqsekh.jpg" + ], + "description": "<p>Yua Mikami is my one of my favourite JAV Actress, she is so pretty and have killer body. In this video she acts as your girlfriend.<br>she waits you at home, wash your dick and handjob it. she likes to kiss. in the bedroom she HJ you and you fingering her then she rides you cow girl style, missionary and doggy style. she likes travelling with you and give you nice service in the bathroom during vacation and fucks around in the bathtub then continue fucking in the bedroom hotels.</p>", + "created_at": "2020-03-10 04:08:49" + }, + { + "id": 25204, + "url": "https://exoticaz.to/torrent/25204-ssni-589-yua-mikami-is-cumming-with-all-her-might-bluray-iso", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "6": "BluRay" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-589] Yua Mikami Is Cumming With All Her Might [ BluRay ISO ]", + "file_size": 27124105216, + "file_count": 1, + "seed": 3, + "leech": 0, + "completed": 87, + "downloaded": 140, + "upload_multiply": 1, + "download_multiply": 0.5, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "105": "pov", + "142": "threesome", + "229": "lingerie", + "1924": "disc.image" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/7/3/7/9tp0sygf2xvj.jpg", + "images/torrent/8/8/a/hzdbk7alileu.jpg", + "images/torrent/9/d/c/nzbycz15u9ou.jpg", + "images/torrent/5/e/1/oadu5qvnaenn.jpg", + "images/torrent/f/c/a/5rsj5fnyw7sy.jpg" + ], + "description": "<p>Release Date: Oct. 12, 2019<br>Runtime: 149min.  (HD: 149min.)<br>Director: Mon C<br>Studio: S1 NO.1 STYLE<br>Label: S1 NO.1 STYLE<br>Content ID: ssni00589<br>DVD ID: SSNI-589<br>Series: Full-Power Cumming Cowgirl<br>Languages: Japanese</p>\n<p>三上悠亜の全力イクイク騎乗位マニアックス 三上悠亜</p>\n<p>「ほら、おま●こに挿ってるの丸見えだよ…」国民的アイドルの大胆!騎乗位マニアックス!前後左右360°尻肉揺れまくり徹底アングル!クビレ腰と肉弾ヒップを一心不乱に振りまくる!男根を咥え込む騎乗位の乱舞!イッてもイッても止めない高速グラインド!!イキまくるクビレ、尻肉大迫力神アングル!絶頂汁を撒き散らしそれでも振り続けるアグレッシブFUCK!! ※こちらはBlu-ray Disc専用ソフトです。対応プレイヤー以外では再生できませんのでご注意ください。 ★アダルトブック「三上悠亜写真集」の商品ご購入はこちらから★ 「コンビニ受取」対象商品です。詳しくはこちらをご覧ください。</p>", + "created_at": "2019-12-13 00:30:33" + }, + { + "id": 24777, + "url": "https://exoticaz.to/torrent/24777-ssni-589-yua-mikami-is-cumming-with-all-her-might", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-589] - Yua Mikami Is Cumming With All Her Might", + "file_size": 4677574830, + "file_count": 1, + "seed": 8, + "leech": 0, + "completed": 221, + "downloaded": 344, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "43": "solo", + "44": "toys", + "81": "gang.bang", + "165": "facial", + "773": "stripping" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/f/b/e/qifgdreqaf5b.jpg", + "images/torrent/b/7/2/xoozbaeetghq.jpg", + "images/torrent/d/2/6/xq3jzygq8bre.jpg", + "images/torrent/1/5/a/mdod0u9vglzp.jpg", + "images/torrent/3/0/4/v1m4mpfyblcy.jpg", + "images/torrent/c/e/2/g8dffnux1nts.jpg", + "images/torrent/9/c/2/kxk9xw2a6xej.jpg", + "images/torrent/1/0/1/kubs7pvuz0aa.jpg", + "images/torrent/6/4/5/8lhfqthtzxcs.jpg", + "images/torrent/2/3/5/8lmpqf9n36lq.jpg", + "images/torrent/7/2/f/xygk0jdd4hkc.jpg", + "images/torrent/c/f/2/m2itm5kmlfut.jpg", + "images/torrent/7/1/3/zgcpyxt8xaqo.jpg", + "images/torrent/a/f/a/qwlrz0il8zel.jpg", + "images/torrent/a/e/8/yis2cqnxlabo.jpg", + "images/torrent/4/2/0/qqtfa6axbcwv.jpg", + "images/torrent/9/c/f/dqvsizqqy3vn.jpg", + "images/torrent/f/7/5/odwv1y7jjkxi.jpg", + "images/torrent/5/9/a/akmogdcz8z38.jpg", + "images/torrent/0/a/4/igw0bxhxbf4g.jpg", + "images/torrent/1/2/f/0q0ixlg7avab.jpg", + "images/torrent/7/d/1/h3taivgykifz.jpg", + "images/torrent/a/1/4/nzbouoip0fqi.jpg", + "images/torrent/a/3/d/cv9cngpv8v50.jpg", + "images/torrent/c/4/3/pxr4lnm9lxv2.jpg", + "images/torrent/2/1/8/fbxldk3q9y9c.jpg", + "images/torrent/6/3/c/dmievonhdzuy.jpg", + "images/torrent/2/5/8/4zlaj4fq2jsr.jpg", + "images/torrent/e/7/0/u6u9ha5zlqwu.jpg", + "images/torrent/c/c/4/gvpvpha40x4w.jpg", + "images/torrent/1/e/7/y16fd1hx66ke.jpg", + "images/torrent/4/5/5/ioay6m7flgri.jpg", + "images/torrent/4/6/e/iosp8ta1nk5y.jpg", + "images/torrent/a/9/c/7mrg4nqeik2l.jpg", + "images/torrent/8/d/1/pyxdggscdmbz.jpg", + "images/torrent/5/c/a/cvodwnveloyi.jpg", + "images/torrent/4/c/e/hq681lsvp84q.jpg", + "images/torrent/4/0/3/wj4elb2qf55b.jpg", + "images/torrent/e/a/d/zlk5empv2tsr.jpg", + "images/torrent/4/0/1/qiq9l0g9b4lb.jpg" + ], + "description": null, + "created_at": "2019-10-12 07:37:42" + }, + { + "id": 24714, + "url": "https://exoticaz.to/torrent/24714-ssni-542-ntr-alumni-association-my-wife-and-my-worst-ex-boyfriend-cheating-video-that-seems-to-be-crazy-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "SSNI-542 NTR Alumni Association My Wife And My Worst Ex-boyfriend Cheating Video That Seems To Be Crazy. Yua Mikami", + "file_size": 4738954073, + "file_count": 1, + "seed": 15, + "leech": 0, + "completed": 400, + "downloaded": 547, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "153": "cheating", + "251": "wife" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/4/e/5/1a9g513v03lq.jpg", + "images/torrent/e/4/a/vjo94gprzomz.jpg", + "images/torrent/2/3/b/aiu9oymlnapp.jpg", + "images/torrent/a/8/e/ck4b8lvvbfl3.jpg", + "images/torrent/b/a/4/ss5fjzjrglzx.jpg", + "images/torrent/e/0/1/sim4xsfbyw7n.jpg", + "images/torrent/5/b/8/usvrynixarox.jpg", + "images/torrent/b/3/4/t1zifwtbowrg.jpg", + "images/torrent/b/a/1/9tmre5ropcht.jpg", + "images/torrent/6/8/4/kqnujxrhblie.jpg", + "images/torrent/0/3/8/3ijjmwygi5ct.jpg", + "images/torrent/5/3/a/stogfck7riem.jpg", + "images/torrent/1/d/a/bptfmrqsoulr.jpg", + "images/torrent/e/f/3/hlu4exb7esux.jpg", + "images/torrent/3/3/f/4lqgtrcxxymw.jpg", + "images/torrent/6/7/2/gqh13frlu1vh.jpg", + "images/torrent/a/4/a/zp9xtg1wpnav.jpg", + "images/torrent/e/9/c/grbz5llpnbwi.jpg", + "images/torrent/f/a/7/ok10gpplrpre.jpg", + "images/torrent/d/6/9/zrhkx4iauslq.jpg", + "images/torrent/b/3/c/h9v2zcumkug7.jpg", + "images/torrent/e/c/d/xcqo9utm7p8z.jpg", + "images/torrent/3/d/6/mj34l4kwyfcs.jpg", + "images/torrent/0/0/c/pz6a1om1zcj6.jpg" + ], + "description": null, + "created_at": "2019-10-03 07:22:22" + }, + { + "id": 24432, + "url": "https://exoticaz.to/torrent/24432-fc2ppv-1123075-yua-mikami-mosaic-removed", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "FC2PPV-1123075 yua mikami (mosaic removed)", + "file_size": 51622148, + "file_count": 1, + "seed": 82, + "leech": 0, + "completed": 774, + "downloaded": 939, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": false, + "gay": false, + "transexual": false, + "resolutions": { + "2": "360p" + }, + "studios": null, + "tags": { + "2": "japanese" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/e/0/b/pluwx8ebvjrw.png", + "images/torrent/c/3/e/ivi2v3xvuxvf.png" + ], + "description": "<p>Yua mikami (mosaic removed) not exactly more like digitally altered person seems to have done a good job albeit the quality is not the greatest.</p>", + "created_at": "2019-08-06 05:01:10" + }, + { + "id": 22633, + "url": "https://exoticaz.to/torrent/22633-ssni-077-super-idiot-temptation-mens-aesthetic-salon-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-077] Super Idiot Temptation Men's Aesthetic Salon Yua Mikami", + "file_size": 6349992217, + "file_count": 1, + "seed": 8, + "leech": 0, + "completed": 164, + "downloaded": 222, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "629": "salon" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/9/0/9/8a9eecdzbos6.png", + "images/torrent/5/b/f/etco5vfiapr3.png", + "images/torrent/c/b/e/ijtvmadwf41j.png", + "images/torrent/d/3/4/qttu8kiwcaaf.png", + "images/torrent/1/0/1/jwfxloxiz88w.png", + "images/torrent/b/3/3/0dfcozcjhzaf.png", + "images/torrent/c/1/0/tallav2tsrwk.png", + "images/torrent/8/e/1/pjqw8ai4pubu.png", + "images/torrent/d/1/d/siepkvzdjdjm.png" + ], + "description": null, + "created_at": "2019-02-16 01:52:32" + }, + { + "id": 22606, + "url": "https://exoticaz.to/torrent/22606-ssni-054-a-cock-sucking-ball-slurping-gland-rubbing-dick-swallowing-special-and-it-cums-with-an-amazing-cleanup-blowjob-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-054] A Cock Sucking Ball Slurping Gland Rubbing Dick Swallowing Special And It Cums With An Amazing Cleanup Blowjob Yua Mikami", + "file_size": 4533534633, + "file_count": 1, + "seed": 5, + "leech": 0, + "completed": 137, + "downloaded": 188, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "102": "idol" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/2/7/8/zfrzvqi9meu2.png", + "images/torrent/9/1/9/n9dwka8a1ybx.png", + "images/torrent/8/9/f/xaftxpq488of.png", + "images/torrent/1/e/c/9sgcuj4vznq9.png", + "images/torrent/f/e/d/nlvdxpufmjm6.png", + "images/torrent/f/9/9/scjrral5midb.png" + ], + "description": null, + "created_at": "2019-02-14 09:58:29" + }, + { + "id": 21647, + "url": "https://exoticaz.to/torrent/21647-oae-165-yua-mikami-cries", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[OAE-165] Yua Mikami Cries", + "file_size": 5318957871, + "file_count": 1, + "seed": 24, + "leech": 0, + "completed": 565, + "downloaded": 753, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": true, + "censored": false, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "81": "Air Control" + }, + "tags": { + "43": "solo", + "875": "portrait.mode" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/8/5/7/8gjmnjdtxqyf.jpg", + "images/torrent/f/7/4/ywoxzplr4te0.png", + "images/torrent/f/9/3/q1qpkrrhxt9r.png", + "images/torrent/9/a/b/1cya91dpi4ym.png", + "images/torrent/1/e/0/wttr4vaxusov.png", + "images/torrent/7/8/5/sgzn0mejgo1d.png", + "images/torrent/a/6/9/ytwkx154gggv.png", + "images/torrent/b/a/0/fnwlho48hxxy.png", + "images/torrent/1/e/9/zb4gphrposw0.gif" + ], + "description": "<p>no sexual activity in the show.</p>\n<p>for details : http://www.r18.com/videos/vod/movies/detail/-/id=oae00165/?i3_ref=search&i3_ord=1</p>", + "created_at": "2018-12-16 20:31:03" + }, + { + "id": 21564, + "url": "https://exoticaz.to/torrent/21564-tek-097-shoko-takahashi-yua-mikami-these-two-are-muteki", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[TEK-097] Shoko Takahashi, Yua Mikami - These Two Are MUTEKI", + "file_size": 7560496643, + "file_count": 1, + "seed": 10, + "leech": 0, + "completed": 309, + "downloaded": 406, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "38": "MUTEKI" + }, + "tags": { + "41": "big.tits", + "102": "idol", + "142": "threesome", + "235": "foursome", + "717": "celeb" + }, + "performers": { + "16": "Yua MIKAMI", + "175": "Shoko TAKAHASHI" + }, + "images": [ + "images/torrent/8/5/b/qnxklss7sinb.jpg", + "images/torrent/b/5/f/r0ml2pj3xrvq.jpg" + ], + "description": "<p>MUTEKI 10th Anniversary Special Project.</p>", + "created_at": "2018-12-06 02:16:35" + }, + { + "id": 21561, + "url": "https://exoticaz.to/torrent/21561-mide-599-yua-mikami-premature-orgasm-cum-sensitive-4-sex-s1s-exclusive-moodyzs-popular-series", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[MIDE-599] Yua Mikami - Premature Orgasm Cum Sensitive 4 Sex [S1's Exclusive × Moodyz's Popular Series]", + "file_size": 7541382461, + "file_count": 1, + "seed": 9, + "leech": 0, + "completed": 247, + "downloaded": 322, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "11": "Moodyz" + }, + "tags": { + "41": "big.tits", + "56": "orgasm", + "102": "idol", + "187": "squirting" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/2/7/5/tk4vvpvqiele.jpg", + "images/torrent/8/6/d/jitug0zre7mf.jpg", + "images/torrent/e/d/4/ikkdvi8ylkia.jpg", + "images/torrent/d/5/5/nntnvnkncfex.jpg", + "images/torrent/6/0/f/nimr1m6nhevo.jpg", + "images/torrent/7/5/0/7vvvklhbkdci.jpg", + "images/torrent/3/1/2/hhted7hdeapq.jpg", + "images/torrent/2/a/8/ntoxmktfrg3k.jpg", + "images/torrent/e/6/0/rjwqddkgyjde.jpg", + "images/torrent/b/9/2/ewoattyoqfct.jpg", + "images/torrent/1/a/1/16kjv5ryijr3.jpg", + "images/torrent/7/c/3/kvjyuskn3mkf.jpg" + ], + "description": null, + "created_at": "2018-12-05 19:43:15" + }, + { + "id": 20515, + "url": "https://exoticaz.to/torrent/20515-yua-mikami-megapack", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "4": "Pornstar Pack" + }, + "info_hash": "(removed)", + "file_name": "Yua Mikami MegaPack", + "file_size": 159149593237, + "file_count": 26, + "seed": 56, + "leech": 5, + "completed": 871, + "downloaded": 1658, + "upload_multiply": 1, + "download_multiply": 0, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style", + "38": "MUTEKI", + "81": "Air Control" + }, + "tags": { + "2": "japanese", + "71": "cosplay", + "81": "gang.bang", + "83": "oil.or.lotion", + "86": "schoolgirl", + "87": "maid", + "105": "pov", + "110": "nurse", + "141": "masturbation", + "142": "threesome", + "165": "facial", + "188": "fingering", + "215": "medium.tits", + "377": "dildo", + "566": "boob.job", + "578": "bathing.suit", + "1938": "bondage" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/6/b/d/caaasridewaa.jpg", + "images/torrent/9/2/3/8yclm2b3eqnj.jpg", + "images/torrent/6/7/4/3ygtoaxybrgm.jpg", + "images/torrent/7/b/c/47qmpqiznx9o.jpg", + "images/torrent/5/5/c/plzn4v8vrcqw.jpg", + "images/torrent/b/f/9/yiiwlvpy96ph.jpg", + "images/torrent/6/0/8/ajhsa47uulil.jpg", + "images/torrent/f/6/b/mtwuxcnkfnxd.jpg", + "images/torrent/8/6/9/ep2ppfml3prg.jpg", + "images/torrent/3/3/e/mfvvplf65fnq.jpg", + "images/torrent/8/5/5/fjscdqrlmn18.jpg", + "images/torrent/d/2/a/merafg6jwl98.jpg", + "images/torrent/5/8/6/7zobje67lds6.jpg", + "images/torrent/d/a/d/dpp201bvawne.jpg", + "images/torrent/8/d/c/8tgl3sqc0uqb.jpg", + "images/torrent/c/a/7/cbzfwtsi7lvm.jpg", + "images/torrent/e/3/5/yufwoqdkw5qi.jpg", + "images/torrent/b/8/e/x2sjjjxzt68r.jpg", + "images/torrent/2/e/e/cqmszgh6h29g.jpg", + "images/torrent/d/d/2/x5gzkvcoo4z7.jpg", + "images/torrent/c/7/5/e7gwu09kibmv.jpg", + "images/torrent/b/3/8/q7v9hufpbr0c.jpg", + "images/torrent/b/d/4/v1krpm9anerk.jpg", + "images/torrent/9/4/6/igc0a6vckc9f.jpg", + "images/torrent/a/c/b/ysparrlgkk41.jpg", + "images/torrent/7/e/5/pfydx5d3eorg.jpg", + "images/torrent/7/3/4/sdloqiiuicmt.jpg", + "images/torrent/d/e/e/ljm4fexekgm9.jpg", + "images/torrent/3/b/c/v9rq6hcp6ql9.jpg", + "images/torrent/8/0/2/jlnjh1yuwq6r.jpg", + "images/torrent/e/a/0/m4zlczh6urcr.jpg", + "images/torrent/e/3/1/a9k8m7dvbmhy.jpg", + "images/torrent/a/c/6/eimbr66y55ad.jpg", + "images/torrent/d/e/6/asphrldoipnf.jpg", + "images/torrent/4/c/0/8xz8ujeiyvq9.jpg", + "images/torrent/b/b/0/sp4htha3mrv9.jpg", + "images/torrent/6/a/3/ru3eajn0gxni.jpg", + "images/torrent/2/a/e/t5zjq3lytjwq.jpg", + "images/torrent/a/f/e/8hsa2jnava7p.jpg", + "images/torrent/d/8/9/0kikizmqogsq.jpg", + "images/torrent/1/7/c/hm9egdjzx56z.jpg", + "images/torrent/2/4/a/x2whvzzfhnls.jpg", + "images/torrent/0/d/d/cygy0mvsx6yx.jpg", + "images/torrent/8/2/2/uns7jrne2j9c.jpg", + "images/torrent/a/d/3/4kcc5spz192f.jpg", + "images/torrent/7/0/5/0zb0dssitulw.jpg", + "images/torrent/3/f/a/v0xb9ywq5d6a.jpg", + "images/torrent/d/f/8/kvnw6sssgggp.jpg", + "images/torrent/8/0/b/ka6lao3hovk3.jpg", + "images/torrent/6/c/3/zhaae0yrn3nr.jpg", + "images/torrent/c/3/8/1jw9pepmnzeo.jpg", + "images/torrent/1/8/a/tfgyusq6amep.jpg", + "images/torrent/a/a/b/yondejxaddfm.jpg", + "images/torrent/b/5/a/28itaanb16lg.jpg", + "images/torrent/9/8/4/hqnd1kdq7ly2.jpg", + "images/torrent/2/2/9/yum7h5wl87gn.jpg", + "images/torrent/f/8/d/pax3dubtieuv.jpg", + "images/torrent/4/0/1/xyds5k66uhs2.jpg", + "images/torrent/d/8/f/snp8rft0uv4z.jpg", + "images/torrent/c/c/f/cpzr8kidtvnc.jpg", + "images/torrent/1/2/0/23cikzmnwq4m.jpg", + "images/torrent/9/7/f/pczl0plw88zb.jpg", + "images/torrent/b/5/a/hgeil8elgdxp.jpg", + "images/torrent/c/9/3/mfyqo1qidz16.jpg", + "images/torrent/0/b/1/jvmjmv2tbxgq.jpg", + "images/torrent/6/d/6/r7hvzrp1qbug.jpg", + "images/torrent/1/a/3/ifsr5h5odcqg.jpg", + "images/torrent/a/1/9/5ngcygiazvrv.jpg" + ], + "description": null, + "created_at": "2018-09-07 07:56:21" + }, + { + "id": 15261, + "url": "https://exoticaz.to/torrent/15261-ssni-205-mikami-yuka-necinacious-impatient-and-crispy-feeling-bikkun-bikin-sexual-development-development-oil-massage-salon-mikami-yua", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-205] Mikami Yuka - Necinacious Impatient And Crispy Feeling Bikkun Bikin Sexual Development Development Oil Massage Salon Mikami Yua", + "file_size": 5601218639, + "file_count": 3, + "seed": 9, + "leech": 0, + "completed": 154, + "downloaded": 180, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "3": "480p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "167": "massage" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/2/b/a/zozwfgmbhxth.jpg", + "images/torrent/e/f/6/ubgilv5db5mo.jpg" + ], + "description": null, + "created_at": "2018-06-02 17:44:49" + }, + { + "id": 4333, + "url": "https://exoticaz.to/torrent/4333-tek-081-pleasure-splashthe-first-time-of-pleasant-too-squirting-mikami-yua", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[TEK-081] Pleasure Splash!The First Time Of Pleasant Too Squirting ~ Mikami Yua", + "file_size": 1595554659, + "file_count": 1, + "seed": 5, + "leech": 0, + "completed": 106, + "downloaded": 111, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "3": "480p" + }, + "studios": { + "38": "MUTEKI" + }, + "tags": { + "2": "japanese" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/d/e/c/a8hitjfi2skr.jpg", + "images/torrent/c/9/c/3qxdyhvuefwu.jpg" + ], + "description": "<pre><br>General<br>Complete name : Tek081.mp4<br>Format : MPEG-4<br>Format profile : Base Media / Version 2<br>Codec ID : mp42 (isom/iso2/mp41)<br>File size : 1.49 GiB<br>Duration : 2 h 51 min<br>Overall bit rate mode : Variable<br>Overall bit rate : 1 243 kb/s<br>Encoded date : UTC 2017-02-12 20:24:00<br>Tagged date : UTC 2017-02-12 20:24:00<br>Writing application : HandBrake 1.0.2 2017012200<br><br>Video<br>ID : 1<br>Format : HEVC<br>Format/Info : High Efficiency Video Coding<br>Format profile : Main@L3.1@Main<br>Codec ID : hev1<br>Codec ID/Info : High Efficiency Video Coding<br>Duration : 2 h 51 min<br>Bit rate : 1 139 kb/s<br>Width : 1 280 pixels<br>Height : 720 pixels<br>Display aspect ratio : 16:9<br>Frame rate mode : Variable<br>Frame rate : 28.707 FPS<br>Minimum frame rate : 11.446 FPS<br>Maximum frame rate : 195.652 FPS<br>Color space : YUV<br>Chroma subsampling : 4:2:0<br>Bit depth : 8 bits<br>Bits/(Pixel*Frame) : 0.043<br>Stream size : 1.36 GiB (92%)<br>Writing library : x265 2.1:[Windows][GCC 5.4.0][64 bit] 8bit<br>Encoding settings : wpp / ctu=64 / min-cu-size=8 / max-tu-size=32 / tu-intra-depth=1 / tu-inter-depth=1 / me=1 / subme=2 / merange=57 / no-rect / no-amp / max-merge=2 / temporal-mvp / no-early-skip / rskip / rdpenalty=0 / no-tskip / no-tskip-fast / strong-intra-smoothing / no-lossless / no-cu-lossless / no-constrained-intra / no-fast-intra / open-gop / no-temporal-layers / interlace=0 / keyint=290 / min-keyint=29 / scenecut=40 / rc-lookahead=20 / lookahead-slices=4 / bframes=4 / bframe-bias=0 / b-adapt=2 / ref=3 / limit-refs=3 / no-limit-modes / weightp / no-weightb / aq-mode=1 / qg-size=32 / aq-strength=1.00 / cbqpoffs=0 / crqpoffs=0 / rd=3 / psy-rd=2.00 / rdoq-level=0 / psy-rdoq=0.00 / log2-max-poc-lsb=8 / no-rd-refine / signhide / deblock=0:0 / sao / no-sao-non-deblock / b-pyramid / cutree / no-intra-refresh / rc=crf / crf=22.0 / qcomp=0.60 / qpmin=0 / qpmax=69 / qpstep=4 / ipratio=1.40 / pbratio=1.30<br>Encoded date : UTC 2017-02-12 20:24:00<br>Tagged date : UTC 2017-02-12 20:24:00<br>Color range : Limited<br>Color primaries : BT.709<br>Transfer characteristics : BT.709<br>Matrix coefficients : BT.709<br><br>Audio<br>ID : 2<br>Format : AAC<br>Format/Info : Advanced Audio Codec<br>Format profile : LC<br>Codec ID : mp4a-40-2<br>Duration : 2 h 51 min<br>Bit rate mode : Variable<br>Bit rate : 96.0 kb/s<br>Channel(s) : 2 channels<br>Channel positions : Front: L R<br>Sampling rate : 48.0 kHz<br>Frame rate : 46.875 FPS (1024 SPF)<br>Compression mode : Lossy<br>Stream size : 118 MiB (8%)<br>Title : Stereo / Stereo<br>Language : English<br>Default : Yes<br>Alternate group : 1<br>Encoded date : UTC 2017-02-12 20:24:00<br>Tagged date : UTC 2017-02-12 20:24:00<br><br></pre>", + "created_at": "2018-03-19 06:01:40" + }, + { + "id": 4241, + "url": "https://exoticaz.to/torrent/4241-tek-080-caramel-saliva-thick-kiss-sex-mikami-yua", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[TEK-080] Caramel Saliva Thick Kiss Sex ~ Mikami Yua", + "file_size": 1787053002, + "file_count": 1, + "seed": 5, + "leech": 0, + "completed": 79, + "downloaded": 87, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "3": "480p" + }, + "studios": { + "38": "MUTEKI" + }, + "tags": { + "2": "japanese" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/b/9/3/virufojfn4pi.jpg", + "images/torrent/c/4/4/o8jsphfh7rr9.jpg" + ], + "description": null, + "created_at": "2018-02-20 02:46:45" + }, + { + "id": 4191, + "url": "https://exoticaz.to/torrent/4191-snis825-ultra-mass-blow-to-national-idle-dream-facials-mikami-yua", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SNIS825] Ultra Mass Blow To National Idle Dream Facials ~ Mikami Yua", + "file_size": 1177131759, + "file_count": 1, + "seed": 4, + "leech": 0, + "completed": 80, + "downloaded": 87, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "3": "480p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/0/3/d/8parwx5ndrst.jpg", + "images/torrent/9/6/1/c1szrkxbf6fn.jpg" + ], + "description": null, + "created_at": "2018-02-05 05:39:41" + }, + { + "id": 4101, + "url": "https://exoticaz.to/torrent/4101-snis896-snis-896-national-idol-suddenly-immediate-saddle-shot-4-production-at-any-time-immediately-coalesce-anywhere-immediately-climax-mikami-yua", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SNIS896] SNIS-896 National Idol Suddenly Immediate Saddle Shot 4 Production At Any Time Immediately Coalesce, Anywhere Immediately Climax ~ Mikami Yua", + "file_size": 1505202606, + "file_count": 1, + "seed": 5, + "leech": 0, + "completed": 106, + "downloaded": 97, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "3": "480p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/2/7/b/t8juhyfd7qlb.jpg", + "images/torrent/7/4/6/9r3ars6pa9cn.jpg" + ], + "description": "<pre><br><br>General<br>Complete name : snis896.mp4<br>Format : MPEG-4<br>Format profile : Base Media / Version 2<br>Codec ID : mp42 (isom/iso2/mp41)<br>File size : 1.40 GiB<br>Duration : 1 h 58 min<br>Overall bit rate mode : Variable<br>Overall bit rate : 1 691 kb/s<br>Encoded date : UTC 2017-05-31 19:30:00<br>Tagged date : UTC 2017-05-31 19:30:00<br>Writing application : HandBrake 1.0.7 2017040900<br><br>Video<br>ID : 1<br>Format : HEVC<br>Format/Info : High Efficiency Video Coding<br>Format profile : Main@L3.1@Main<br>Codec ID : hev1<br>Codec ID/Info : High Efficiency Video Coding<br>Duration : 1 h 58 min<br>Bit rate : 1 588 kb/s<br>Width : 1 280 pixels<br>Height : 720 pixels<br>Display aspect ratio : 16:9<br>Frame rate mode : Constant<br>Frame rate : 30.000 FPS<br>Color space : YUV<br>Chroma subsampling : 4:2:0<br>Bit depth : 8 bits<br>Bits/(Pixel*Frame) : 0.057<br>Stream size : 1.32 GiB (94%)<br>Writing library : x265 2.1:[Windows][GCC 5.3.1][64 bit] 8bit<br>Encoding settings : wpp / ctu=64 / min-cu-size=8 / max-tu-size=32 / tu-intra-depth=1 / tu-inter-depth=1 / me=1 / subme=2 / merange=57 / no-rect / no-amp / max-merge=2 / temporal-mvp / no-early-skip / rskip / rdpenalty=0 / no-tskip / no-tskip-fast / strong-intra-smoothing / no-lossless / no-cu-lossless / no-constrained-intra / no-fast-intra / open-gop / no-temporal-layers / interlace=0 / keyint=300 / min-keyint=30 / scenecut=40 / rc-lookahead=20 / lookahead-slices=4 / bframes=4 / bframe-bias=0 / b-adapt=2 / ref=3 / limit-refs=3 / no-limit-modes / weightp / no-weightb / aq-mode=1 / qg-size=32 / aq-strength=1.00 / cbqpoffs=0 / crqpoffs=0 / rd=3 / psy-rd=2.00 / rdoq-level=0 / psy-rdoq=0.00 / log2-max-poc-lsb=8 / no-rd-refine / signhide / deblock=0:0 / sao / no-sao-non-deblock / b-pyramid / cutree / no-intra-refresh / rc=crf / crf=20.0 / qcomp=0.60 / qpmin=0 / qpmax=69 / qpstep=4 / ipratio=1.40 / pbratio=1.30<br>Encoded date : UTC 2017-05-31 19:30:00<br>Tagged date : UTC 2017-05-31 19:30:00<br>Color range : Limited<br>Color primaries : BT.709<br>Transfer characteristics : BT.709<br>Matrix coefficients : BT.709<br><br>Audio<br>ID : 2<br>Format : AAC<br>Format/Info : Advanced Audio Codec<br>Format profile : LC<br>Codec ID : 40<br>Duration : 1 h 58 min<br>Bit rate mode : Variable<br>Bit rate : 96.0 kb/s<br>Channel(s) : 2 channels<br>Channel positions : Front: L R<br>Sampling rate : 48.0 kHz<br>Frame rate : 46.875 FPS (1024 spf)<br>Compression mode : Lossy<br>Stream size : 81.6 MiB (6%)<br>Title : Stereo / Stereo<br>Default : Yes<br>Alternate group : 1<br>Encoded date : UTC 2017-05-31 19:30:00<br>Tagged date : UTC 2017-05-31 19:30:00<br><br></pre>", + "created_at": "2017-12-24 02:51:02" + }, + { + "id": 4002, + "url": "https://exoticaz.to/torrent/4002-tek-071-pleasure-mikami-yua-mkv", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[TEK-071] Pleasure ~ Mikami Yua [mkv]", + "file_size": 5340855460, + "file_count": 1, + "seed": 6, + "leech": 0, + "completed": 80, + "downloaded": 97, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "38": "MUTEKI" + }, + "tags": { + "2": "japanese" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/1/a/a/9eeclc5deq1q.jpg", + "images/torrent/7/d/3/wj64npz8aizr.jpg" + ], + "description": "<p>三上悠亜<br>TEK-071 快感(MUTEKI-2016年1月1日)</p>", + "created_at": "2017-11-16 03:02:55" + }, + { + "id": 3951, + "url": "https://exoticaz.to/torrent/3951-tek-067-princess-peach-mikami-yua-mkv", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[TEK-067] Princess Peach ~ Mikami Yua [mkv]", + "file_size": 5258879180, + "file_count": 1, + "seed": 4, + "leech": 0, + "completed": 101, + "downloaded": 113, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "38": "MUTEKI" + }, + "tags": { + "2": "japanese" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/5/2/7/qtrginnz0qzt.jpg", + "images/torrent/c/1/7/herqbzuq6jj4.jpg" + ], + "description": "<p>三上悠亜<br>TEK-067 Princess Peach(MUTEKI-2015年6月1日)</p>", + "created_at": "2017-11-12 14:47:18" + }, + { + "id": 16896, + "url": "https://exoticaz.to/torrent/16896-ssni-030-mikami-yua-fan-thanksgiving-national-idol", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-030] Mikami Yua Fan Thanksgiving National Idol", + "file_size": 1807560913, + "file_count": 3, + "seed": 9, + "leech": 0, + "completed": 128, + "downloaded": 148, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "3": "480p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "102": "idol", + "126": "fan.appreciation" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/8/5/a/9mulsu7hvt4o.jpg", + "images/torrent/4/b/a/n4wsdkzea7y6.jpg", + "images/torrent/d/7/5/bnrhqtpopzcv.jpg", + "images/torrent/e/6/7/edlha36jpvhj.jpg", + "images/torrent/2/0/d/vwnmnsncpyvw.jpg", + "images/torrent/e/3/9/zbntxdwj2dly.jpg", + "images/torrent/8/a/a/ena0fdra1rif.jpg" + ], + "description": "<p>[SSNI-030] Mikami Yua Fan Thanksgiving National Idol x General Users 20 People 'Guttyfan and SEX Economy' Hime Meakuri Special<br><br></p>\n<pre><br><br></pre>", + "created_at": "2017-10-15 06:46:48" + }, + { + "id": 15273, + "url": "https://exoticaz.to/torrent/15273-ssni-009-national-idol-life-first-first-freakbig-caps-23-endless-unlimited-sex-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-009] National Idol Life First First Freak!Big Caps 23 Endless Unlimited Sex - Yua Mikami", + "file_size": 5485007833, + "file_count": 4, + "seed": 3, + "leech": 0, + "completed": 75, + "downloaded": 92, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "5": "1080p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese", + "102": "idol" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/0/6/f/h4fkgftj6faf.jpg", + "images/torrent/f/6/5/srlry3vu9kas.jpg" + ], + "description": "<p>SSNI-009 National Idol Life First First Freak!Big Caps 23 Endless Unlimited Sex - Yua Mikami<br><br></p>", + "created_at": "2017-10-11 02:33:59" + }, + { + "id": 17757, + "url": "https://exoticaz.to/torrent/17757-ssni-009-23-big-cocks-endless-unlimited-sex-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SSNI-009] 23 Big Cocks Endless Unlimited Sex ~ Yua Mikami", + "file_size": 1409697647, + "file_count": 3, + "seed": 8, + "leech": 0, + "completed": 60, + "downloaded": 82, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "3": "480p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/8/a/2/ij2yfrzewqzd.jpg", + "images/torrent/c/4/4/hgfstyyer4ve.jpg", + "images/torrent/9/0/e/hf46gtdvwdao.jpg", + "images/torrent/1/1/b/orkckrdepnqt.jpg", + "images/torrent/c/5/0/w9ku6z9m5bd9.jpg", + "images/torrent/9/f/c/hwwhz7rgreac.jpg", + "images/torrent/3/1/6/21sudpyouj3f.jpg" + ], + "description": "SSNI-009 Our National Idol First Gangbang! Three raw scenes. 23 big cocks endless unlimited sex ~ Yua Mikami<br><br><pre><br><br></pre>", + "created_at": "2017-09-14 01:19:43" + }, + { + "id": 17364, + "url": "https://exoticaz.to/torrent/17364-snis-964-dripping-wet-sex-with-yua-mikami", + "download": "https://exoticaz.to/rss/download/(removed)/(removed).torrent", + "category": { + "1": "Video Clip" + }, + "info_hash": "(removed)", + "file_name": "[SNIS-964] Dripping Wet Sex With ~ YuA Mikami", + "file_size": 1547028897, + "file_count": 3, + "seed": 6, + "leech": 0, + "completed": 67, + "downloaded": 69, + "upload_multiply": 1, + "download_multiply": 1, + "asian": true, + "softcore": false, + "censored": true, + "gay": false, + "transexual": false, + "resolutions": { + "3": "480p" + }, + "studios": { + "10": "S1 No.1 Style" + }, + "tags": { + "2": "japanese" + }, + "performers": { + "16": "Yua MIKAMI" + }, + "images": [ + "images/torrent/8/8/f/ae3bwugtex3n.jpg", + "images/torrent/6/9/1/qtwyijojnxi0.jpg", + "images/torrent/c/4/9/r86h4u8wcqqr.jpg", + "images/torrent/2/a/2/bcqmrigbbryf.jpg", + "images/torrent/2/9/4/mk41d4xcloui.jpg", + "images/torrent/f/a/b/tvqctziuy8k2.jpg" + ], + "description": "SNIS-964 Covered In Sweat, ?**, And Saliva: Dripping Wet Sex With A National Pop Star ~ YuA Mikami<br><br><pre><br><br></pre>", + "created_at": "2017-09-01 22:56:53" + } + ], + "first_page_url": "https://exoticaz.to/api/v1/jackett/torrents?search=yua%20mikami&page=1", + "from": 1, + "last_page": 2, + "last_page_url": "https://exoticaz.to/api/v1/jackett/torrents?search=yua%20mikami&page=2", + "next_page_url": "https://exoticaz.to/api/v1/jackett/torrents?search=yua%20mikami&page=2", + "path": "https://exoticaz.to/api/v1/jackett/torrents", + "per_page": 100, + "prev_page_url": null, + "to": 100, + "total": 105 +} \ No newline at end of file diff --git a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/ExoticazFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/ExoticazFixture.cs new file mode 100644 index 000000000..ea4b7f98c --- /dev/null +++ b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/ExoticazFixture.cs @@ -0,0 +1,63 @@ +using System; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Common.Http; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Indexers.Definitions; +using NzbDrone.Core.Indexers.Definitions.Avistaz; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.IndexerTests.AvistazTests +{ + [TestFixture] + public class ExoticazFixture : CoreTest<ExoticaZ> + { + [SetUp] + public void Setup() + { + Subject.Definition = new IndexerDefinition() + { + Name = "ExoticaZ", + Settings = new AvistazSettings() { Username = "someuser", Password = "somepass", Pid = "somepid" } + }; + } + + [Test] + public async Task should_parse_recent_feed_from_ExoticaZ() + { + var recentFeed = ReadAllText(@"Files/Indexers/Exoticaz/recentfeed.json"); + + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader { { "Content-Type", "application/json" } }, new CookieCollection(), recentFeed))); + + var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases; + + releases.Should().HaveCount(100); + releases.First().Should().BeOfType<TorrentInfo>(); + + var torrentInfo = releases.First() as TorrentInfo; + + torrentInfo.Title.Should().Be("[SSIS-419] My first experience is Yua Mikami. From the day I lost my virginity, I was devoted to sex."); + torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent); + torrentInfo.DownloadUrl.Should().Be("https://exoticaz.to/rss/download/(removed)/(removed).torrent"); + torrentInfo.InfoUrl.Should().Be("https://exoticaz.to/torrent/64040-ssis-419-my-first-experience-is-yua-mikami-from-the-day-i-lost-my-virginity-i-was-devoted-to-sex"); + torrentInfo.CommentUrl.Should().BeNullOrEmpty(); + torrentInfo.Indexer.Should().Be(Subject.Definition.Name); + torrentInfo.PublishDate.Should().Be(DateTime.Parse("2022-06-11 11:04:50")); + torrentInfo.Size.Should().Be(7085405541); + torrentInfo.InfoHash.Should().Be("asdjfiasdf54asd7f4a2sdf544asdf"); + torrentInfo.MagnetUrl.Should().Be(null); + torrentInfo.Peers.Should().Be(33); + torrentInfo.Seeders.Should().Be(33); + torrentInfo.Categories.First().Id.Should().Be(6040); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs index b8dc82575..fd2b2b892 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz { public string Url { get; set; } public string Download { get; set; } - public string Category { get; set; } + public Dictionary<string, string> Category { get; set; } [JsonProperty(PropertyName = "movie_tv")] public AvistazIdInfo MovieTvinfo { get; set; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/ExoticaZ.cs b/src/NzbDrone.Core/Indexers/Definitions/ExoticaZ.cs index 6c1f85777..608edf2a2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/ExoticaZ.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/ExoticaZ.cs @@ -65,7 +65,7 @@ namespace NzbDrone.Core.Indexers.Definitions { var cat = row.Category; - return _categories.MapTrackerCatToNewznab(cat).ToList(); + return cat.SelectMany(c => _categories.MapTrackerCatToNewznab(c.Key)).ToList(); } } } From d3ffb7b49024956de3b6ad515d1af8fe39ab4726 Mon Sep 17 00:00:00 2001 From: Davo1624 <85573606+Davo1624@users.noreply.github.com> Date: Tue, 21 Jun 2022 10:14:02 -0400 Subject: [PATCH 0491/2320] (Filelist) Update help text for pass key (#1039) --- .../Indexers/Definitions/FileList/FileListSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListSettings.cs index a64fc257a..82320a91d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListSettings.cs @@ -26,7 +26,7 @@ namespace NzbDrone.Core.Indexers.FileList [FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)] public string Username { get; set; } - [FieldDefinition(3, Label = "Passkey", HelpText = "Site Passkey", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] + [FieldDefinition(3, Label = "Passkey", HelpText = "Site Passkey (This is the alphanumeric string in the tracker url shown in your download client)", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] public string Passkey { get; set; } public override NzbDroneValidationResult Validate() From 761e15a4760bf962d44b46d27163fa6d1d884085 Mon Sep 17 00:00:00 2001 From: olly <dark.olly@gmail.com> Date: Sun, 12 Jun 2022 16:06:59 +0800 Subject: [PATCH 0492/2320] New: Send description element in nab response --- src/NzbDrone.Core/IndexerSearch/NewznabResults.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs index d74bb2d78..134bfe4d9 100644 --- a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs +++ b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs @@ -75,6 +75,7 @@ namespace NzbDrone.Core.IndexerSearch let t = (r as TorrentInfo) ?? new TorrentInfo() select new XElement("item", new XElement("title", RemoveInvalidXMLChars(r.Title)), + new XElement("description", RemoveInvalidXMLChars(r.Description)), new XElement("guid", r.Guid), // GUID and (Link or Magnet) are mandatory new XElement("prowlarrindexer", new XAttribute("id", r.IndexerId), r.Indexer), r.InfoUrl == null ? null : new XElement("comments", r.InfoUrl), From 479e29dde7b5fe5346653e0e625d76de26ede9e8 Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Tue, 21 Jun 2022 21:29:24 +0100 Subject: [PATCH 0493/2320] Use DryIoc for Automoqer, drop Unity dependency (cherry picked from commit e3468daba04b52fbf41ce3004934a26b0220ec4f) --- src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs | 141 +++++++----------- .../Unity/AutoMockingBuilderStrategy.cs | 80 ---------- .../Unity/AutoMockingContainerExtension.cs | 35 ----- .../Prowlarr.Test.Common.csproj | 1 - 4 files changed, 57 insertions(+), 200 deletions(-) delete mode 100644 src/NzbDrone.Test.Common/AutoMoq/Unity/AutoMockingBuilderStrategy.cs delete mode 100644 src/NzbDrone.Test.Common/AutoMoq/Unity/AutoMockingContainerExtension.cs diff --git a/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs b/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs index a34e7cb33..c32a06f2a 100644 --- a/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs +++ b/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs @@ -3,17 +3,11 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using System.Linq.Expressions; using System.Reflection; -using System.Runtime.CompilerServices; +using DryIoc; using Moq; -using Moq.Language.Flow; using NzbDrone.Common.Composition; using NzbDrone.Common.EnvironmentInfo; -using NzbDrone.Test.Common.AutoMoq.Unity; -using Unity; - -[assembly: InternalsVisibleTo("AutoMoq.Tests")] namespace NzbDrone.Test.Common.AutoMoq { @@ -21,32 +15,18 @@ namespace NzbDrone.Test.Common.AutoMoq public class AutoMoqer { public readonly MockBehavior DefaultBehavior = MockBehavior.Default; - public Type ResolveType; - private IUnityContainer _container; + private IContainer _container; private IDictionary<Type, object> _registeredMocks; public AutoMoqer() { - SetupAutoMoqer(new UnityContainer()); - } - - public AutoMoqer(MockBehavior defaultBehavior) - { - DefaultBehavior = defaultBehavior; - SetupAutoMoqer(new UnityContainer()); - } - - public AutoMoqer(IUnityContainer container) - { - SetupAutoMoqer(container); + SetupAutoMoqer(CreateTestContainer(new Container())); } public virtual T Resolve<T>() { - ResolveType = typeof(T); var result = _container.Resolve<T>(); SetConstant(result); - ResolveType = null; return result; } @@ -59,7 +39,6 @@ namespace NzbDrone.Test.Common.AutoMoq public virtual Mock<T> GetMock<T>(MockBehavior behavior) where T : class { - ResolveType = null; var type = GetTheMockType<T>(); if (GetMockHasNotBeenCalledForThisType(type)) { @@ -78,87 +57,81 @@ namespace NzbDrone.Test.Common.AutoMoq public virtual void SetMock(Type type, Mock mock) { - if (_registeredMocks.ContainsKey(type) == false) + if (GetMockHasNotBeenCalledForThisType(type)) { _registeredMocks.Add(type, mock); } if (mock != null) { - _container.RegisterInstance(type, mock.Object); + _container.RegisterInstance(type, mock.Object, ifAlreadyRegistered: IfAlreadyRegistered.Replace); } } public virtual void SetConstant<T>(T instance) { - _container.RegisterInstance(instance); + _container.RegisterInstance(instance, ifAlreadyRegistered: IfAlreadyRegistered.Replace); SetMock(instance.GetType(), null); } - public ISetup<T> Setup<T>(Expression<Action<T>> expression) - where T : class + private IContainer CreateTestContainer(IContainer container) { - return GetMock<T>().Setup(expression); + var c = container.CreateChild(IfAlreadyRegistered.Replace, + container.Rules + .WithDynamicRegistration((serviceType, serviceKey) => + { + // ignore services with non-default key + if (serviceKey != null) + { + return null; + } + + if (serviceType == typeof(object)) + { + return null; + } + + if (serviceType.IsGenericType && serviceType.IsOpenGeneric()) + { + return null; + } + + // get the Mock object for the abstract class or interface + if (serviceType.IsInterface || serviceType.IsAbstract) + { + var mockType = typeof(Mock<>).MakeGenericType(serviceType); + var mockFactory = new DelegateFactory(r => + { + var mock = (Mock)r.Resolve(mockType); + SetMock(serviceType, mock); + return mock.Object; + }, Reuse.Singleton); + + return new[] { new DynamicRegistration(mockFactory, IfAlreadyRegistered.Keep) }; + } + + // concrete types + var concreteTypeFactory = serviceType.ToFactory(Reuse.Singleton, FactoryMethod.ConstructorWithResolvableArgumentsIncludingNonPublic); + + return new[] { new DynamicRegistration(concreteTypeFactory) }; + }, + DynamicRegistrationFlags.Service | DynamicRegistrationFlags.AsFallback)); + + c.Register(typeof(Mock<>), Reuse.Singleton, FactoryMethod.DefaultConstructor()); + + return c; } - public ISetup<T, TResult> Setup<T, TResult>(Expression<Func<T, TResult>> expression) - where T : class - { - return GetMock<T>().Setup(expression); - } - - public void Verify<T>(Expression<Action<T>> expression) - where T : class - { - GetMock<T>().Verify(expression); - } - - public void Verify<T>(Expression<Action<T>> expression, string failMessage) - where T : class - { - GetMock<T>().Verify(expression, failMessage); - } - - public void Verify<T>(Expression<Action<T>> expression, Times times) - where T : class - { - GetMock<T>().Verify(expression, times); - } - - public void Verify<T>(Expression<Action<T>> expression, Times times, string failMessage) - where T : class - { - GetMock<T>().Verify(expression, times, failMessage); - } - - public void VerifyAllMocks() - { - foreach (var registeredMock in _registeredMocks) - { - var mock = registeredMock.Value as Mock; - if (mock != null) - { - mock.VerifyAll(); - } - } - } - - private void SetupAutoMoqer(IUnityContainer container) + private void SetupAutoMoqer(IContainer container) { _container = container; container.RegisterInstance(this); - RegisterPlatformLibrary(container); - _registeredMocks = new Dictionary<Type, object>(); - AddTheAutoMockingContainerExtensionToTheContainer(container); - AssemblyLoader.RegisterSQLiteResolver(); - } - private static void AddTheAutoMockingContainerExtensionToTheContainer(IUnityContainer container) - { - container.AddNewExtension<AutoMockingContainerExtension>(); - return; + LoadPlatformLibrary(); + + AssemblyLoader.RegisterSQLiteResolver(); } private Mock<T> TheRegisteredMockForThisType<T>(Type type) @@ -177,7 +150,7 @@ namespace NzbDrone.Test.Common.AutoMoq private bool GetMockHasNotBeenCalledForThisType(Type type) { - return _registeredMocks.ContainsKey(type) == false; + return !_registeredMocks.ContainsKey(type); } private static Type GetTheMockType<T>() @@ -186,7 +159,7 @@ namespace NzbDrone.Test.Common.AutoMoq return typeof(T); } - private void RegisterPlatformLibrary(IUnityContainer container) + private void LoadPlatformLibrary() { var assemblyName = "Prowlarr.Windows"; diff --git a/src/NzbDrone.Test.Common/AutoMoq/Unity/AutoMockingBuilderStrategy.cs b/src/NzbDrone.Test.Common/AutoMoq/Unity/AutoMockingBuilderStrategy.cs deleted file mode 100644 index c841dc7d7..000000000 --- a/src/NzbDrone.Test.Common/AutoMoq/Unity/AutoMockingBuilderStrategy.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Moq; -using Unity; -using Unity.Builder; -using Unity.Strategies; - -namespace NzbDrone.Test.Common.AutoMoq.Unity -{ - public class AutoMockingBuilderStrategy : BuilderStrategy - { - private readonly IUnityContainer _container; - private readonly MockRepository _mockFactory; - private readonly IEnumerable<Type> _registeredTypes; - - public AutoMockingBuilderStrategy(IEnumerable<Type> registeredTypes, IUnityContainer container) - { - var autoMoqer = container.Resolve<AutoMoqer>(); - _mockFactory = new MockRepository(autoMoqer.DefaultBehavior); - _registeredTypes = registeredTypes; - _container = container; - } - - public override void PreBuildUp(ref BuilderContext context) - { - var autoMoqer = _container.Resolve<AutoMoqer>(); - - var type = GetTheTypeFromTheBuilderContext(context); - if (AMockObjectShouldBeCreatedForThisType(type)) - { - var mock = CreateAMockObject(type); - context.Existing = mock.Object; - autoMoqer.SetMock(type, mock); - } - } - - private bool AMockObjectShouldBeCreatedForThisType(Type type) - { - var mocker = _container.Resolve<AutoMoqer>(); - return TypeIsNotRegistered(type) && (mocker.ResolveType == null || mocker.ResolveType != type); - } - - private static Type GetTheTypeFromTheBuilderContext(BuilderContext context) - { - // return (context.OriginalBuildKey).Type; - return context.Type; - } - - private bool TypeIsNotRegistered(Type type) - { - return _registeredTypes.Any(x => x.Equals(type)) == false; - } - - private Mock CreateAMockObject(Type type) - { - var createMethod = GenerateAnInterfaceMockCreationMethod(type); - - return InvokeTheMockCreationMethod(createMethod); - } - - private Mock InvokeTheMockCreationMethod(MethodInfo createMethod) - { - return (Mock)createMethod.Invoke(_mockFactory, new object[] { new List<object>().ToArray() }); - } - - private MethodInfo GenerateAnInterfaceMockCreationMethod(Type type) - { - var createMethodWithNoParameters = _mockFactory.GetType().GetMethod("Create", EmptyArgumentList()); - - return createMethodWithNoParameters.MakeGenericMethod(new[] { type }); - } - - private static Type[] EmptyArgumentList() - { - return new[] { typeof(object[]) }; - } - } -} diff --git a/src/NzbDrone.Test.Common/AutoMoq/Unity/AutoMockingContainerExtension.cs b/src/NzbDrone.Test.Common/AutoMoq/Unity/AutoMockingContainerExtension.cs deleted file mode 100644 index 71838c545..000000000 --- a/src/NzbDrone.Test.Common/AutoMoq/Unity/AutoMockingContainerExtension.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Generic; -using Unity.Builder; -using Unity.Extension; - -namespace NzbDrone.Test.Common.AutoMoq.Unity -{ - public class AutoMockingContainerExtension : UnityContainerExtension - { - private readonly IList<Type> _registeredTypes = new List<Type>(); - - protected override void Initialize() - { - SetEventsOnContainerToTrackAllRegisteredTypes(); - SetBuildingStrategyForBuildingUnregisteredTypes(); - } - - private void SetEventsOnContainerToTrackAllRegisteredTypes() - { - Context.Registering += (sender, e) => RegisterType(e.TypeFrom); - Context.RegisteringInstance += (sender, e) => RegisterType(e.RegisteredType); - } - - private void RegisterType(Type typeToRegister) - { - _registeredTypes.Add(typeToRegister); - } - - private void SetBuildingStrategyForBuildingUnregisteredTypes() - { - var strategy = new AutoMockingBuilderStrategy(_registeredTypes, Container); - Context.Strategies.Add(strategy, UnityBuildStage.PreCreation); - } - } -} diff --git a/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj b/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj index 753dc63cb..249797e07 100644 --- a/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj +++ b/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj @@ -10,7 +10,6 @@ <PackageReference Include="NUnit" Version="3.13.3" /> <PackageReference Include="RestSharp" Version="106.15.0" /> <PackageReference Include="RestSharp.Serializers.SystemTextJson" Version="106.15.0" /> - <PackageReference Include="Unity" Version="5.11.10" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Common\Prowlarr.Common.csproj" /> From 86f5768461e24e37b2be9fca5da22accda95b81d Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 23 Jun 2022 20:36:13 -0500 Subject: [PATCH 0494/2320] Fixed: VIP Healthcheck not triggered for expired indexers --- .../HealthCheck/Checks/IndexerVIPCheck.cs | 19 +----- .../Checks/IndexerVIPExpiredCheck.cs | 64 +++++++++++++++++++ 2 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPExpiredCheck.cs diff --git a/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPCheck.cs index 7c12348b7..eff84cc67 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPCheck.cs @@ -23,11 +23,10 @@ namespace NzbDrone.Core.HealthCheck.Checks public override HealthCheck Check() { - var enabled = _indexerFactory.Enabled(false); + var indexers = _indexerFactory.AllProviders(false); var expiringProviders = new List<IIndexer>(); - var expiredProviders = new List<IIndexer>(); - foreach (var provider in enabled) + foreach (var provider in indexers) { var settingsType = provider.Definition.Settings.GetType(); var vipProp = settingsType.GetProperty("VipExpiration"); @@ -44,11 +43,6 @@ namespace NzbDrone.Core.HealthCheck.Checks continue; } - if (DateTime.Parse(expiration).Before(DateTime.Now)) - { - expiredProviders.Add(provider); - } - if (DateTime.Parse(expiration).Between(DateTime.Now, DateTime.Now.AddDays(7))) { expiringProviders.Add(provider); @@ -64,15 +58,6 @@ namespace NzbDrone.Core.HealthCheck.Checks "#indexer-vip-expiring"); } - if (!expiredProviders.Empty()) - { - return new HealthCheck(GetType(), - HealthCheckResult.Warning, - string.Format(_localizationService.GetLocalizedString("IndexerVipCheckExpiredClientMessage"), - string.Join(", ", expiredProviders.Select(v => v.Definition.Name))), - "#indexer-vip-expired"); - } - return new HealthCheck(GetType()); } } diff --git a/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPExpiredCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPExpiredCheck.cs new file mode 100644 index 000000000..5170897c4 --- /dev/null +++ b/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPExpiredCheck.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Localization; +using NzbDrone.Core.ThingiProvider.Events; + +namespace NzbDrone.Core.HealthCheck.Checks +{ + [CheckOn(typeof(ProviderAddedEvent<IIndexer>))] + [CheckOn(typeof(ProviderUpdatedEvent<IIndexer>))] + [CheckOn(typeof(ProviderDeletedEvent<IIndexer>))] + public class IndexerVIPExpiredCheck : HealthCheckBase + { + private readonly IIndexerFactory _indexerFactory; + + public IndexerVIPExpiredCheck(IIndexerFactory indexerFactory, ILocalizationService localizationService) + : base(localizationService) + { + _indexerFactory = indexerFactory; + } + + public override HealthCheck Check() + { + var indexers = _indexerFactory.AllProviders(false); + var expiredProviders = new List<IIndexer>(); + + foreach (var provider in indexers) + { + var settingsType = provider.Definition.Settings.GetType(); + var vipProp = settingsType.GetProperty("VipExpiration"); + + if (vipProp == null) + { + continue; + } + + var expiration = (string)vipProp.GetValue(provider.Definition.Settings); + + if (expiration.IsNullOrWhiteSpace()) + { + continue; + } + + if (DateTime.Parse(expiration).Before(DateTime.Now)) + { + expiredProviders.Add(provider); + } + } + + if (!expiredProviders.Empty()) + { + return new HealthCheck(GetType(), + HealthCheckResult.Error, + string.Format(_localizationService.GetLocalizedString("IndexerVipCheckExpiredClientMessage"), + string.Join(", ", expiredProviders.Select(v => v.Definition.Name))), + "#indexer-vip-expired"); + } + + return new HealthCheck(GetType()); + } + } +} From 7cf9fc6a4ff48b87dd242a6047db9ec4a18c2b41 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 23 Jun 2022 20:56:07 -0500 Subject: [PATCH 0495/2320] New: (BeyondHD) Better status messages for failures Closes #1028 --- src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs b/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs index 66c8feab9..2021ba987 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs @@ -201,6 +201,11 @@ namespace NzbDrone.Core.Indexers.Definitions var jsonResponse = new HttpResponse<BeyondHDResponse>(indexerHttpResponse); + if (jsonResponse.Resource.StatusCode == 0) + { + throw new IndexerException(indexerResponse, $"Indexer Error: {jsonResponse.Resource.StatusMessage}"); + } + foreach (var row in jsonResponse.Resource.Results) { var details = row.InfoUrl; @@ -272,6 +277,11 @@ namespace NzbDrone.Core.Indexers.Definitions public class BeyondHDResponse { + [JsonProperty(PropertyName = "status_code")] + public int StatusCode { get; set; } + + [JsonProperty(PropertyName = "status_message")] + public string StatusMessage { get; set; } public List<BeyondHDTorrent> Results { get; set; } } From a0b650e7a56cb958f0165ec99197a4c042446225 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 23 Jun 2022 22:22:30 -0500 Subject: [PATCH 0496/2320] Fixed: (Cardigann) Use variables in keywordsfilters block Fixes #1035 Fixes v5 TorrentLand --- .../Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 11004a606..079313e3d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -1000,7 +1000,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } variables[".Query.Keywords"] = string.Join(" ", keywordTokens); - variables[".Keywords"] = ApplyFilters((string)variables[".Query.Keywords"], search.Keywordsfilters); + variables[".Keywords"] = ApplyFilters((string)variables[".Query.Keywords"], search.Keywordsfilters, variables); // TODO: prepare queries first and then send them parallel var searchPaths = search.Paths; From e76a255229302054d78bc0933e421d4ecbdc5379 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Thu, 23 Jun 2022 14:08:57 -0500 Subject: [PATCH 0497/2320] Fixed: (AnimeBytes) Cleanse Passkey from response Fixes #1041 --- .../InstrumentationTests/CleanseLogMessageFixture.cs | 3 +++ src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs | 1 + 2 files changed, 4 insertions(+) diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs index 77d518916..eba324bf1 100644 --- a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs +++ b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs @@ -31,6 +31,9 @@ namespace NzbDrone.Common.Test.InstrumentationTests [TestCase(@"""download"":""https:\/\/avistaz.to\/rss\/download\/2b51db35e1910123321025a12b9933d2\/tb51db35e1910123321025a12b9933d2.torrent"",")] [TestCase(@",""info_hash"":""2b51db35e1910123321025a12b9933d2"",")] + // animebytes response + [TestCase(@"""Link"":""https:\/\/animebytes.tv\/torrent\/994064\/download\/tb51db35e1910123321025a12b9933d2"",")] + // danish bytes response [TestCase(@",""rsskey"":""2b51db35e1910123321025a12b9933d2"",")] [TestCase(@",""passkey"":""2b51db35e1910123321025a12b9933d2"",")] diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index d2ffe1636..7cc749b3a 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -55,6 +55,7 @@ namespace NzbDrone.Common.Instrumentation // Indexer Responses new Regex(@"(?:avistaz|exoticaz|cinemaz|privatehd)\.[a-z]{2,3}\\\/rss\\\/download\\\/(?<secret>[^&=]+?)\\\/(?<secret>[^&=]+?)\.torrent", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"(?:animebytes)\.[a-z]{2,3}\\\/torrent\\\/[0-9]+\\\/download\\\/(?<secret>[^&=]+?)[""]", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@",""info_hash"":""(?<secret>[^&=]+?)"",", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@",""pass[- _]?key"":""(?<secret>[^&=]+?)"",", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@",""rss[- _]?key"":""(?<secret>[^&=]+?)"",", RegexOptions.Compiled | RegexOptions.IgnoreCase), From dfed229a1df8a829cabf1f86226b4c6c5fcf8c8a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 24 Jun 2022 18:46:19 -0500 Subject: [PATCH 0498/2320] Fix Tooltips in Dark Theme --- frontend/src/Components/Tooltip/Tooltip.css | 2 +- frontend/src/Styles/Themes/dark.js | 7 ++++--- frontend/src/Styles/Themes/light.js | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/src/Components/Tooltip/Tooltip.css b/frontend/src/Components/Tooltip/Tooltip.css index 82c80752a..3921a4de2 100644 --- a/frontend/src/Components/Tooltip/Tooltip.css +++ b/frontend/src/Components/Tooltip/Tooltip.css @@ -7,7 +7,7 @@ position: relative; &.default { - background-color: var(--white); + background-color: var(--popoverBodyBackgroundColor); box-shadow: 0 5px 10px var(--popoverShadowColor); } diff --git a/frontend/src/Styles/Themes/dark.js b/frontend/src/Styles/Themes/dark.js index 0bbb9e3ca..cc013da48 100644 --- a/frontend/src/Styles/Themes/dark.js +++ b/frontend/src/Styles/Themes/dark.js @@ -168,10 +168,11 @@ module.exports = { // // Popover - popoverTitleBackgroundColor: '#f7f7f7', - popoverTitleBorderColor: '#ebebeb', + popoverTitleBackgroundColor: '#424242', + popoverTitleBorderColor: '#2a2a2a', + popoverBodyBackgroundColor: '#2a2a2a', popoverShadowColor: 'rgba(0, 0, 0, 0.2)', - popoverArrowBorderColor: '#fff', + popoverArrowBorderColor: '#2a2a2a', popoverTitleBackgroundInverseColor: '#595959', popoverTitleBorderInverseColor: '#707070', diff --git a/frontend/src/Styles/Themes/light.js b/frontend/src/Styles/Themes/light.js index e48bcd40c..e3c5a753f 100644 --- a/frontend/src/Styles/Themes/light.js +++ b/frontend/src/Styles/Themes/light.js @@ -170,6 +170,7 @@ module.exports = { popoverTitleBackgroundColor: '#f7f7f7', popoverTitleBorderColor: '#ebebeb', + popoverBodyBackgroundColor: '#e9e9e9', popoverShadowColor: 'rgba(0, 0, 0, 0.2)', popoverArrowBorderColor: '#fff', From 580fc528e5b89580a92e0e80223dc9dd76c5b545 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 24 Jun 2022 18:49:08 -0500 Subject: [PATCH 0499/2320] Fix Donation Links --- frontend/src/Components/Page/Header/PageHeader.js | 2 +- frontend/src/System/Status/Donations/Donations.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/Components/Page/Header/PageHeader.js b/frontend/src/Components/Page/Header/PageHeader.js index 22e71ca4c..d9e2c1189 100644 --- a/frontend/src/Components/Page/Header/PageHeader.js +++ b/frontend/src/Components/Page/Header/PageHeader.js @@ -74,7 +74,7 @@ class PageHeader extends Component { <IconButton className={styles.donate} name={icons.HEART} - to="https://opencollective.com/prowlarr" + to="https://prowlarr.com/donate" size={14} /> <IconButton diff --git a/frontend/src/System/Status/Donations/Donations.js b/frontend/src/System/Status/Donations/Donations.js index fcce39e57..a89e0dea8 100644 --- a/frontend/src/System/Status/Donations/Donations.js +++ b/frontend/src/System/Status/Donations/Donations.js @@ -13,7 +13,7 @@ class Donations extends Component { return ( <FieldSet legend={translate('Donations')}> <div className={styles.logoContainer} title="Radarr"> - <Link to="https://opencollective.com/radarr"> + <Link to="https://radarr.video/donate"> <img className={styles.logo} src={`${window.Prowlarr.urlBase}/Content/Images/Icons/logo-radarr.png`} @@ -21,7 +21,7 @@ class Donations extends Component { </Link> </div> <div className={styles.logoContainer} title="Lidarr"> - <Link to="https://opencollective.com/lidarr"> + <Link to="https://lidarr.audio/donate"> <img className={styles.logo} src={`${window.Prowlarr.urlBase}/Content/Images/Icons/logo-lidarr.png`} @@ -29,7 +29,7 @@ class Donations extends Component { </Link> </div> <div className={styles.logoContainer} title="Readarr"> - <Link to="https://opencollective.com/readarr"> + <Link to="https://readarr.com/donate"> <img className={styles.logo} src={`${window.Prowlarr.urlBase}/Content/Images/Icons/logo-readarr.png`} @@ -37,7 +37,7 @@ class Donations extends Component { </Link> </div> <div className={styles.logoContainer} title="Prowlarr"> - <Link to="https://opencollective.com/prowlarr"> + <Link to="https://prowlarr.com/donate"> <img className={styles.logo} src={`${window.Prowlarr.urlBase}/Content/Images/Icons/logo-prowlarr.png`} From cdb1f163f8317e784f2ee5880a75e23574b59c66 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 25 Jun 2022 13:05:54 -0500 Subject: [PATCH 0500/2320] Bump version to 0.4.1 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 51c5f6ad2..230d511f8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: testsFolder: './_tests' yarnCacheFolder: $(Pipeline.Workspace)/.yarn nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages - majorVersion: '0.4.0' + majorVersion: '0.4.1' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From d1949d24e0622675e86f81e6668444c1ce4153c5 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 25 Jun 2022 16:12:50 -0500 Subject: [PATCH 0501/2320] Fix NullRef in analytics service --- src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs index f4840ffcc..67822cb82 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs @@ -1,5 +1,7 @@ +using System.Collections.Generic; using System.Linq; using System.Net.Http; +using NLog; using NzbDrone.Common.Cloud; using NzbDrone.Common.Http; using NzbDrone.Common.Serializer; @@ -14,6 +16,7 @@ namespace NzbDrone.Core.IndexerSearch private readonly IHttpClient _httpClient; private readonly IHttpRequestBuilderFactory _requestBuilder; private readonly IAnalyticsService _analyticsService; + private readonly Logger _logger; public ReleaseAnalyticsService(IHttpClient httpClient, IProwlarrCloudRequestBuilder requestBuilder, IAnalyticsService analyticsService) { @@ -24,7 +27,7 @@ namespace NzbDrone.Core.IndexerSearch public void HandleAsync(IndexerQueryEvent message) { - if (_analyticsService.IsEnabled) + if (_analyticsService.IsEnabled && message.QueryResult?.Releases != null) { var request = _requestBuilder.Create().Resource("release/push").Build(); request.Method = HttpMethod.Post; @@ -34,7 +37,7 @@ namespace NzbDrone.Core.IndexerSearch var body = message.QueryResult.Releases.Select(x => new { Title = x.Title, - Categories = x.Categories.Where(c => c.Id < 10000).Select(c => c.Id), + Categories = x.Categories?.Where(c => c.Id < 10000).Select(c => c.Id) ?? new List<int>(), Protocol = x.DownloadProtocol.ToString(), Size = x.Size, PublishDate = x.PublishDate From 0e2d15cb739afde5f066013945d4c52aa8b08324 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 25 Jun 2022 16:19:55 -0500 Subject: [PATCH 0502/2320] Swallow HTTP issues on analytics call --- .../IndexerSearch/ReleaseAnalyticsService.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs index 67822cb82..a195e1125 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs @@ -18,11 +18,12 @@ namespace NzbDrone.Core.IndexerSearch private readonly IAnalyticsService _analyticsService; private readonly Logger _logger; - public ReleaseAnalyticsService(IHttpClient httpClient, IProwlarrCloudRequestBuilder requestBuilder, IAnalyticsService analyticsService) + public ReleaseAnalyticsService(IHttpClient httpClient, IProwlarrCloudRequestBuilder requestBuilder, IAnalyticsService analyticsService, Logger logger) { _analyticsService = analyticsService; _requestBuilder = requestBuilder.Releases; _httpClient = httpClient; + _logger = logger; } public void HandleAsync(IndexerQueryEvent message) @@ -43,8 +44,15 @@ namespace NzbDrone.Core.IndexerSearch PublishDate = x.PublishDate }); - request.SetContent(body.ToJson()); - _httpClient.Post(request); + try + { + request.SetContent(body.ToJson()); + _httpClient.Post(request); + } + catch + { + _logger.Trace("Analytics push failed"); + } } } } From a311d138057ff99ae2f401d6975d60e402688c39 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 25 Jun 2022 18:06:40 -0500 Subject: [PATCH 0503/2320] Remove ShowRSS C# Implementation --- .../Migration/018_minimum_seeders.cs | 2 +- .../Datastore/Migration/019_remove_showrss.cs | 15 ++ .../Indexers/Definitions/ShowRSS.cs | 183 ------------------ 3 files changed, 16 insertions(+), 184 deletions(-) create mode 100644 src/NzbDrone.Core/Datastore/Migration/019_remove_showrss.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs diff --git a/src/NzbDrone.Core/Datastore/Migration/018_minimum_seeders.cs b/src/NzbDrone.Core/Datastore/Migration/018_minimum_seeders.cs index 9569db660..9fda4423d 100644 --- a/src/NzbDrone.Core/Datastore/Migration/018_minimum_seeders.cs +++ b/src/NzbDrone.Core/Datastore/Migration/018_minimum_seeders.cs @@ -3,7 +3,7 @@ using NzbDrone.Core.Datastore.Migration.Framework; namespace NzbDrone.Core.Datastore.Migration { - [Migration(18)] + [Migration(018)] public class minimum_seeders : NzbDroneMigrationBase { protected override void MainDbUpgrade() diff --git a/src/NzbDrone.Core/Datastore/Migration/019_remove_showrss.cs b/src/NzbDrone.Core/Datastore/Migration/019_remove_showrss.cs new file mode 100644 index 000000000..f58eb6ccc --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/019_remove_showrss.cs @@ -0,0 +1,15 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(019)] + public class remove_showrss : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + // Remove, YML version exists + Delete.FromTable("Indexers").Row(new { Implementation = "ShowRSS" }); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs b/src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs deleted file mode 100644 index 5c4508665..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs +++ /dev/null @@ -1,183 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Text; -using System.Xml; -using FluentValidation; -using NLog; -using NzbDrone.Common.Http; -using NzbDrone.Core.Annotations; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Indexers.Settings; -using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.ThingiProvider; -using NzbDrone.Core.Validation; - -namespace NzbDrone.Core.Indexers.Definitions -{ - public class ShowRSS : TorrentIndexerBase<NoAuthTorrentBaseSettings> - { - public override string Name => "ShowRSS"; - public override string[] IndexerUrls => new string[] { "https://showrss.info/" }; - public override string Language => "en-US"; - public override string Description => "showRSS is a service that allows you to keep track of your favorite TV shows"; - public override Encoding Encoding => Encoding.UTF8; - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerPrivacy Privacy => IndexerPrivacy.Public; - public override IndexerCapabilities Capabilities => SetCapabilities(); - - public ShowRSS(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) - { - } - - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new ShowRSSRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; - } - - public override IParseIndexerResponse GetParser() - { - return new ShowRSSParser(Settings); - } - - private IndexerCapabilities SetCapabilities() - { - var caps = new IndexerCapabilities - { - TvSearchParams = new List<TvSearchParam> - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep - } - }; - - caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.TV); - caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVSD); - caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.TVHD); - - return caps; - } - } - - public class ShowRSSRequestGenerator : IIndexerRequestGenerator - { - public NoAuthTorrentBaseSettings Settings { get; set; } - public IndexerCapabilities Capabilities { get; set; } - - public ShowRSSRequestGenerator() - { - } - - private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories) - { - var searchUrl = string.Format("{0}/other/all.rss", Settings.BaseUrl.TrimEnd('/')); - - var request = new IndexerRequest(searchUrl, HttpAccept.Html); - - yield return request; - } - - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories)); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - return pageableRequests; - } - - public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); - - return pageableRequests; - } - - public Func<IDictionary<string, string>> GetCookies { get; set; } - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } - - public class ShowRSSParser : IParseIndexerResponse - { - private readonly NoAuthTorrentBaseSettings _settings; - private string BrowseUrl => _settings.BaseUrl + "browse/"; - - public ShowRSSParser(NoAuthTorrentBaseSettings settings) - { - _settings = settings; - } - - public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) - { - var torrentInfos = new List<ReleaseInfo>(); - - var xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(indexerResponse.Content); - foreach (XmlNode node in xmlDoc.GetElementsByTagName("item")) - { - var title = node.SelectSingleNode(".//*[local-name()='raw_title']").InnerText; - - // TODO: Make sure we don't return all sorts of trash - //if (!query.MatchQueryStringAND(title)) - //{ - // continue; - //} - var category = title.Contains("720p") || title.Contains("1080p") ? - NewznabStandardCategory.TVHD : - NewznabStandardCategory.TVSD; - - var magnetUri = node.SelectSingleNode("link")?.InnerText; - var publishDate = DateTime.Parse(node.SelectSingleNode("pubDate").InnerText, CultureInfo.InvariantCulture); - var infoHash = node.SelectSingleNode(".//*[local-name()='info_hash']").InnerText; - var details = BrowseUrl + node.SelectSingleNode(".//*[local-name()='show_id']").InnerText; - - var release = new TorrentInfo - { - Title = title, - InfoUrl = details, - Categories = new List<IndexerCategory> { category }, - Guid = magnetUri, - PublishDate = publishDate, - InfoHash = infoHash, - MagnetUrl = magnetUri, - Size = 512, - Seeders = 1, - Peers = 2, - DownloadVolumeFactor = 0, - UploadVolumeFactor = 1 - }; - - torrentInfos.Add(release); - } - - return torrentInfos.ToArray(); - } - - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - } -} From 2ffe88bf6a34f43de7724cc16911c5d0fc7a5598 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 25 Jun 2022 18:22:28 -0500 Subject: [PATCH 0504/2320] Update AngleSharp to 0.17.0 --- src/NzbDrone.Core/Prowlarr.Core.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index 17c69bd06..596cd9e51 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -3,7 +3,7 @@ <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> - <PackageReference Include="AngleSharp.Xml" Version="0.16.0" /> + <PackageReference Include="AngleSharp.Xml" Version="0.17.0" /> <PackageReference Include="Dapper" Version="2.0.123" /> <PackageReference Include="FluentMigrator.Runner" Version="3.3.2" /> <PackageReference Include="MailKit" Version="3.1.1" /> @@ -23,7 +23,7 @@ <PackageReference Include="System.Text.Json" Version="6.0.2" /> <PackageReference Include="MonoTorrent" Version="2.0.5" /> <PackageReference Include="YamlDotNet" Version="11.2.1" /> - <PackageReference Include="AngleSharp" Version="0.16.1" /> + <PackageReference Include="AngleSharp" Version="0.17.1" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Common\Prowlarr.Common.csproj" /> From 313a0b459a133f375c7a26b98f28a65bcdd2098e Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 25 Jun 2022 18:24:44 -0500 Subject: [PATCH 0505/2320] Bump dotnet to 6.0.6 --- azure-pipelines.yml | 2 +- package.json | 2 +- src/Directory.Build.props | 2 +- src/NzbDrone.Core/Prowlarr.Core.csproj | 4 ++-- .../Prowlarr.Integration.Test.csproj | 2 +- yarn.lock | 12 ++++++------ 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 230d511f8..011d9a3d9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,7 +15,7 @@ variables: buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' sentryOrg: 'servarr' sentryUrl: 'https://sentry.servarr.com' - dotnetVersion: '6.0.201' + dotnetVersion: '6.0.301' innoVersion: '6.2.0' nodeVersion: '16.x' windowsImage: 'windows-2022' diff --git a/package.json b/package.json index 1d4c831c3..0d351012b 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "@fortawesome/free-regular-svg-icons": "6.1.1", "@fortawesome/free-solid-svg-icons": "6.1.1", "@fortawesome/react-fontawesome": "0.1.18", - "@microsoft/signalr": "6.0.3", + "@microsoft/signalr": "6.0.6", "@sentry/browser": "6.19.2", "@sentry/integrations": "6.19.2", "chart.js": "3.7.1", diff --git a/src/Directory.Build.props b/src/Directory.Build.props index c675f8dc2..c226ec800 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -94,7 +94,7 @@ <!-- Standard testing packages --> <ItemGroup Condition="'$(TestProject)'=='true'"> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> <PackageReference Include="NUnit" Version="3.13.3" /> <PackageReference Include="NUnit3TestAdapter" Version="4.2.1" /> <PackageReference Include="NunitXml.TestLogger" Version="3.0.117" /> diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index 596cd9e51..d43d7135a 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -10,7 +10,7 @@ <PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" /> <PackageReference Include="NLog.Targets.Syslog" Version="6.0.3" /> <PackageReference Include="Npgsql" Version="5.0.11" /> - <PackageReference Include="System.Memory" Version="4.5.4" /> + <PackageReference Include="System.Memory" Version="4.5.5" /> <PackageReference Include="System.ServiceModel.Syndication" Version="6.0.0" /> <PackageReference Include="FluentMigrator.Runner.SQLite" Version="3.3.2" /> <PackageReference Include="FluentMigrator.Runner.Postgres" Version="3.3.2" /> @@ -20,7 +20,7 @@ <PackageReference Include="TinyTwitter" Version="1.1.2" /> <PackageReference Include="Kveer.XmlRPC" Version="1.1.1" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> - <PackageReference Include="System.Text.Json" Version="6.0.2" /> + <PackageReference Include="System.Text.Json" Version="6.0.5" /> <PackageReference Include="MonoTorrent" Version="2.0.5" /> <PackageReference Include="YamlDotNet" Version="11.2.1" /> <PackageReference Include="AngleSharp" Version="0.17.1" /> diff --git a/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj b/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj index 06267ddc9..47586e916 100644 --- a/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj +++ b/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj @@ -4,7 +4,7 @@ <OutputType>Library</OutputType> </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.3" /> + <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.6" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" /> diff --git a/yarn.lock b/yarn.lock index 10cca6a46..de6dc72ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1150,15 +1150,15 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@microsoft/signalr@6.0.3": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-6.0.3.tgz#9904efd48cd488e3c1c80930ff9fbb3c9f55895d" - integrity sha512-wWGVC2xi8OxNjyir8iQWuyxWHy3Dkakk2Q3VreCE7pDzFAgZ4pId6abJlRPMVIQxkUvUGc8knMW5l3sv2bJ/yw== +"@microsoft/signalr@6.0.6": + version "6.0.6" + resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-6.0.6.tgz#6ba53623a64df64a80126694db4e37146647d3fe" + integrity sha512-3dTLtgwEXUeE9R/3NZQslh1B2WbppeHVXdnpvSZc7Yz+tP5Yiw3KCVUHwKUVnYmd9/2v3DaI/pvCdihrss49zA== dependencies: abort-controller "^3.0.0" eventsource "^1.0.7" fetch-cookie "^0.11.0" - node-fetch "^2.6.1" + node-fetch "^2.6.7" ws "^7.4.5" "@mrmlnc/readdir-enhanced@^2.2.1": @@ -4774,7 +4774,7 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" -node-fetch@^2.6.1: +node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== From 326a7b5e16249cbdf55d7125229d5dcd73a10677 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 25 Jun 2022 18:26:07 -0500 Subject: [PATCH 0506/2320] Update Swashbuckle to 6.3.1 --- src/NzbDrone.Host/Prowlarr.Host.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Host/Prowlarr.Host.csproj b/src/NzbDrone.Host/Prowlarr.Host.csproj index 331a241d0..06fb50e0b 100644 --- a/src/NzbDrone.Host/Prowlarr.Host.csproj +++ b/src/NzbDrone.Host/Prowlarr.Host.csproj @@ -7,7 +7,7 @@ <PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> - <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.3.0" /> + <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.3.1" /> <PackageReference Include="DryIoc.dll" Version="4.8.8" /> <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="5.1.0" /> </ItemGroup> From d52516b700fa1c1ef2f00d24b5f0b8a6ed15ff79 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 25 Jun 2022 18:26:37 -0500 Subject: [PATCH 0507/2320] Update Sentry to 3.18.0 --- src/NzbDrone.Common/Prowlarr.Common.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index 0bd5a78ff..52da94711 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -10,7 +10,7 @@ <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="NLog" Version="4.7.14" /> - <PackageReference Include="Sentry" Version="3.15.0" /> + <PackageReference Include="Sentry" Version="3.18.0" /> <PackageReference Include="SharpZipLib" Version="1.3.3" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> From 67ae7e32df00fb2da86a2076d83dcef011d52883 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 26 Jun 2022 10:50:01 -0500 Subject: [PATCH 0508/2320] Bump version to 0.4.2 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 011d9a3d9..5d4cff6ae 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: testsFolder: './_tests' yarnCacheFolder: $(Pipeline.Workspace)/.yarn nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages - majorVersion: '0.4.1' + majorVersion: '0.4.2' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From 654d2dbad3c5339686525aa8f5fa346446c06b81 Mon Sep 17 00:00:00 2001 From: Mark McDowall <mark@mcdowall.ca> Date: Mon, 23 May 2022 13:59:15 -0700 Subject: [PATCH 0509/2320] Sliding expiration for auth cookie and a little clean up --- .../Authentication/AuthenticationBuilderExtensions.cs | 1 + src/Prowlarr.Http/Authentication/AuthenticationService.cs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Prowlarr.Http/Authentication/AuthenticationBuilderExtensions.cs b/src/Prowlarr.Http/Authentication/AuthenticationBuilderExtensions.cs index 0d0d0918f..e672a87e5 100644 --- a/src/Prowlarr.Http/Authentication/AuthenticationBuilderExtensions.cs +++ b/src/Prowlarr.Http/Authentication/AuthenticationBuilderExtensions.cs @@ -33,6 +33,7 @@ namespace Prowlarr.Http.Authentication options.AccessDeniedPath = "/login?loginFailed=true"; options.LoginPath = "/login"; options.ExpireTimeSpan = TimeSpan.FromDays(7); + options.SlidingExpiration = true; }) .AddApiKey("API", options => { diff --git a/src/Prowlarr.Http/Authentication/AuthenticationService.cs b/src/Prowlarr.Http/Authentication/AuthenticationService.cs index 04990632a..b9fe86559 100644 --- a/src/Prowlarr.Http/Authentication/AuthenticationService.cs +++ b/src/Prowlarr.Http/Authentication/AuthenticationService.cs @@ -1,5 +1,8 @@ +using System; +using System.Net; using Microsoft.AspNetCore.Http; using NLog; +using NzbDrone.Common.Extensions; using NzbDrone.Core.Authentication; using NzbDrone.Core.Configuration; using Prowlarr.Http.Extensions; @@ -15,17 +18,14 @@ namespace Prowlarr.Http.Authentication public class AuthenticationService : IAuthenticationService { - private const string AnonymousUser = "Anonymous"; private static readonly Logger _authLogger = LogManager.GetLogger("Auth"); private readonly IUserService _userService; - private static string API_KEY; private static AuthenticationType AUTH_METHOD; public AuthenticationService(IConfigFileProvider configFileProvider, IUserService userService) { _userService = userService; - API_KEY = configFileProvider.ApiKey; AUTH_METHOD = configFileProvider.AuthenticationMethod; } From 5ee95e3cc29d1307192320eb82b5a8f1287f00d6 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 27 Jun 2022 20:39:15 -0500 Subject: [PATCH 0510/2320] V6 Cardigann Changes (#1045) * V6 Cardigann Changes * fixup! * !fixup range * !fixup more cardigann tests --- frontend/src/Search/QueryParameterModal.js | 1 + .../ApplyGoTemplateTextFixture.cs | 91 +++++++++++++++++++ src/NzbDrone.Core/History/HistoryService.cs | 1 + .../IndexerSearch/NewznabResults.cs | 1 + .../IndexerDefinitionUpdateService.cs | 2 +- .../Indexers/Definitions/Anthelion.cs | 4 - .../Definitions/Cardigann/CardigannBase.cs | 29 ++++-- .../Definitions/Cardigann/CardigannParser.cs | 11 ++- .../Cardigann/CardigannRequestGenerator.cs | 1 + .../Indexers/Definitions/Newznab/Newznab.cs | 2 +- .../Newznab/NewznabRequestGenerator.cs | 5 + .../Definitions/Newznab/NewznabRssParser.cs | 2 +- src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs | 1 + 13 files changed, 135 insertions(+), 16 deletions(-) create mode 100644 src/NzbDrone.Core.Test/IndexerTests/CardigannTests/ApplyGoTemplateTextFixture.cs diff --git a/frontend/src/Search/QueryParameterModal.js b/frontend/src/Search/QueryParameterModal.js index d684d32d8..df06648a2 100644 --- a/frontend/src/Search/QueryParameterModal.js +++ b/frontend/src/Search/QueryParameterModal.js @@ -24,6 +24,7 @@ const searchOptions = [ const seriesTokens = [ { token: '{ImdbId:tt1234567}', example: 'tt12345' }, { token: '{TvdbId:12345}', example: '12345' }, + { token: '{TmdbId:12345}', example: '12345' }, { token: '{TvMazeId:12345}', example: '54321' }, { token: '{Season:00}', example: '01' }, { token: '{Episode:00}', example: '01' } diff --git a/src/NzbDrone.Core.Test/IndexerTests/CardigannTests/ApplyGoTemplateTextFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/CardigannTests/ApplyGoTemplateTextFixture.cs new file mode 100644 index 000000000..0f585abc9 --- /dev/null +++ b/src/NzbDrone.Core.Test/IndexerTests/CardigannTests/ApplyGoTemplateTextFixture.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Indexers.Cardigann; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.IndexerTests.CardigannTests +{ + public class ApplyGoTemplateTextFixture : CoreTest<CardigannBase> + { + private Dictionary<string, object> _variables; + private CardigannDefinition _definition; + + [SetUp] + public void SetUp() + { + _variables = new Dictionary<string, object> + { + [".Config.sitelink"] = "https://somesite.com/", + [".True"] = "True", + [".False"] = null, + [".Today.Year"] = DateTime.Today.Year.ToString(), + [".Categories"] = new string[] { "tv", "movies" } + }; + + _definition = Builder<CardigannDefinition>.CreateNew() + .With(x => x.Encoding = "UTF-8") + .With(x => x.Links = new List<string> + { + "https://somesite.com/" + }) + .With(x => x.Caps = new CapabilitiesBlock + { + Modes = new Dictionary<string, List<string>> + { + { "search", new List<string> { "q" } } + } + }) + .Build(); + + Mocker.SetConstant<CardigannDefinition>(_definition); + } + + [TestCase("{{ range .Categories}}&categories[]={{.}}{{end}}", "&categories[]=tv&categories[]=movies")] + [TestCase("{{ range $i, $e := .Categories}}&categories[{{$i}}]={{.}}{{end}}", "&categories[0]=tv&categories[1]=movies")] + [TestCase("{{ range $index, $element := .Categories}}&categories[{{$index}}]={{.}}+postIndex[{{$index}}]{{end}}", "&categories[0]=tv+postIndex[0]&categories[1]=movies+postIndex[1]")] + public void should_handle_range_statements(string template, string expected) + { + var result = Subject.ApplyGoTemplateText(template, _variables); + + result.Should().Be(expected); + } + + [TestCase("{{ re_replace .Query.Keywords \"[^a-zA-Z0-9]+\" \"%\" }}", "abc%def")] + public void should_handle_re_replace_statements(string template, string expected) + { + _variables[".Query.Keywords"] = string.Join(" ", new List<string> { "abc", "def" }); + + var result = Subject.ApplyGoTemplateText(template, _variables); + + result.Should().Be(expected); + } + + [TestCase("{{ join .Categories \", \" }}", "tv, movies")] + public void should_handle_join_statements(string template, string expected) + { + var result = Subject.ApplyGoTemplateText(template, _variables); + + result.Should().Be(expected); + } + + [TestCase("{{ .Today.Year }}", "2022")] + public void should_handle_variables_statements(string template, string expected) + { + var result = Subject.ApplyGoTemplateText(template, _variables); + + result.Should().Be(expected); + } + + [TestCase("{{if .False }}0{{else}}1{{end}}", "1")] + [TestCase("{{if .True }}0{{else}}1{{end}}", "0")] + public void should_handle_if_statements(string template, string expected) + { + var result = Subject.ApplyGoTemplateText(template, _variables); + + result.Should().Be(expected); + } + } +} diff --git a/src/NzbDrone.Core/History/HistoryService.cs b/src/NzbDrone.Core/History/HistoryService.cs index 685a36882..a06636d42 100644 --- a/src/NzbDrone.Core/History/HistoryService.cs +++ b/src/NzbDrone.Core/History/HistoryService.cs @@ -136,6 +136,7 @@ namespace NzbDrone.Core.History { history.Data.Add("ImdbId", ((TvSearchCriteria)message.Query).FullImdbId ?? string.Empty); history.Data.Add("TvdbId", ((TvSearchCriteria)message.Query).TvdbId?.ToString() ?? string.Empty); + history.Data.Add("TmdbId", ((TvSearchCriteria)message.Query).TmdbId?.ToString() ?? string.Empty); history.Data.Add("TraktId", ((TvSearchCriteria)message.Query).TraktId?.ToString() ?? string.Empty); history.Data.Add("RId", ((TvSearchCriteria)message.Query).RId?.ToString() ?? string.Empty); history.Data.Add("TvMazeId", ((TvSearchCriteria)message.Query).TvMazeId?.ToString() ?? string.Empty); diff --git a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs index 134bfe4d9..85af5b5f4 100644 --- a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs +++ b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs @@ -98,6 +98,7 @@ namespace NzbDrone.Core.IndexerSearch GetNabElement("imdb", r.ImdbId.ToString("D7"), protocol), GetNabElement("tmdbid", r.TmdbId, protocol), GetNabElement("traktid", r.TraktId, protocol), + GetNabElement("doubanid", r.DoubanId, protocol), GetNabElement("seeders", t.Seeders, protocol), GetNabElement("files", r.Files, protocol), GetNabElement("grabs", r.Grabs, protocol), diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index 2bc83aae7..b48b790b2 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.IndexerVersions /* Update Service will fall back if version # does not exist for an indexer per Ta */ private const string DEFINITION_BRANCH = "master"; - private const int DEFINITION_VERSION = 5; + private const int DEFINITION_VERSION = 6; //Used when moving yml to C# private readonly List<string> _defintionBlocklist = new List<string>() diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs b/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs index cb1cdde92..f1464f07a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs @@ -6,11 +6,9 @@ using System.Net.Http; using System.Text; using System.Threading.Tasks; using AngleSharp.Html.Parser; -using FluentValidation; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; -using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Settings; @@ -18,8 +16,6 @@ using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.ThingiProvider; -using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index 387f45a58..3c725792f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.Indexers.Cardigann protected readonly IndexerCapabilitiesCategories _categories = new IndexerCapabilitiesCategories(); protected readonly List<string> _defaultCategories = new List<string>(); - protected readonly string[] OptionalFields = new string[] { "imdb", "imdbid", "rageid", "tmdbid", "tvdbid", "poster", "banner", "description" }; + protected readonly string[] OptionalFields = new string[] { "imdb", "imdbid", "rageid", "tmdbid", "tvdbid", "poster", "banner", "description", "doubanid" }; protected static readonly string[] _SupportedLogicFunctions = { @@ -338,9 +338,9 @@ namespace NzbDrone.Core.Indexers.Cardigann return variables; } - protected delegate string TemplateTextModifier(string str); + public delegate string TemplateTextModifier(string str); - protected string ApplyGoTemplateText(string template, Dictionary<string, object> variables = null, TemplateTextModifier modifier = null) + public string ApplyGoTemplateText(string template, Dictionary<string, object> variables = null, TemplateTextModifier modifier = null) { if (variables == null) { @@ -520,7 +520,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } // handle range expression - var rangeRegex = new Regex(@"{{\s*range\s*(.+?)\s*}}(.*?){{\.}}(.*?){{end}}"); + var rangeRegex = new Regex(@"{{\s*range\s*(((?<index>\$.+?),)((\s*(?<element>.+?)\s*(:=)\s*)))?(?<variable>.+?)\s*}}(?<prefix>.*?){{\.}}(?<postfix>.*?){{end}}"); var rangeRegexMatches = rangeRegex.Match(template); while (rangeRegexMatches.Success) @@ -528,9 +528,13 @@ namespace NzbDrone.Core.Indexers.Cardigann var expanded = string.Empty; var all = rangeRegexMatches.Groups[0].Value; - var variable = rangeRegexMatches.Groups[1].Value; - var prefix = rangeRegexMatches.Groups[2].Value; - var postfix = rangeRegexMatches.Groups[3].Value; + var index = rangeRegexMatches.Groups["index"].Value; + var variable = rangeRegexMatches.Groups["variable"].Value; + var prefix = rangeRegexMatches.Groups["prefix"].Value; + var postfix = rangeRegexMatches.Groups["postfix"].Value; + + var arrayIndex = 0; + var indexReplace = "{{" + index + "}}"; foreach (var value in (ICollection<string>)variables[variable]) { @@ -540,7 +544,16 @@ namespace NzbDrone.Core.Indexers.Cardigann newvalue = modifier(newvalue); } - expanded += prefix + newvalue + postfix; + var indexValue = arrayIndex++; + + if (index.IsNotNullOrWhiteSpace()) + { + expanded += prefix.Replace(indexReplace, indexValue.ToString()) + newvalue + postfix.Replace(indexReplace, indexValue.ToString()); + } + else + { + expanded += prefix + newvalue + postfix; + } } template = template.Replace(all, expanded); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index 930d5b45f..414ca8e53 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -60,7 +60,9 @@ namespace NzbDrone.Core.Indexers.Cardigann if (request.SearchPath.Response != null && request.SearchPath.Response.Type.Equals("json")) { - if (request.SearchPath.Response != null && request.SearchPath.Response.NoResultsMessage != null && (request.SearchPath.Response.NoResultsMessage.Equals(results) || (request.SearchPath.Response.NoResultsMessage == string.Empty && results == string.Empty))) + if (request.SearchPath.Response != null && + request.SearchPath.Response.NoResultsMessage != null && + ((request.SearchPath.Response.NoResultsMessage != string.Empty && results.Contains(request.SearchPath.Response.NoResultsMessage)) || (request.SearchPath.Response.NoResultsMessage == string.Empty && results == string.Empty))) { return releases; } @@ -575,6 +577,13 @@ namespace NzbDrone.Core.Indexers.Cardigann release.TvdbId = (int)ParseUtil.CoerceLong(tvdbId); value = release.TvdbId.ToString(); break; + case "doubanid": + var doubanIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); + var doubanIDMatch = doubanIDRegEx.Match(value); + var doubanID = doubanIDMatch.Groups[1].Value; + release.DoubanId = (int)ParseUtil.CoerceLong(doubanID); + value = release.DoubanId.ToString(); + break; case "poster": if (!string.IsNullOrWhiteSpace(value)) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 079313e3d..dce7816d7 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -91,6 +91,7 @@ namespace NzbDrone.Core.Indexers.Cardigann variables[".Query.IMDBID"] = searchCriteria.FullImdbId; variables[".Query.IMDBIDShort"] = searchCriteria.ImdbId; variables[".Query.TVDBID"] = searchCriteria.TvdbId?.ToString() ?? null; + variables[".Query.TMDBID"] = searchCriteria.TmdbId?.ToString() ?? null; variables[".Query.TVRageID"] = searchCriteria.RId?.ToString() ?? null; variables[".Query.TVMazeID"] = searchCriteria.TvMazeId?.ToString() ?? null; variables[".Query.TraktID"] = searchCriteria.TraktId?.ToString() ?? null; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs index 367076cf1..9660c9391 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs @@ -187,7 +187,7 @@ namespace NzbDrone.Core.Indexers.Newznab } if (capabilities.TvSearchParams != null && - new[] { TvSearchParam.Q, TvSearchParam.TvdbId, TvSearchParam.RId }.Any(v => capabilities.TvSearchParams.Contains(v)) && + new[] { TvSearchParam.Q, TvSearchParam.TvdbId, TvSearchParam.TmdbId, TvSearchParam.RId }.Any(v => capabilities.TvSearchParams.Contains(v)) && new[] { TvSearchParam.Season, TvSearchParam.Ep }.All(v => capabilities.TvSearchParams.Contains(v))) { return null; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs index f8835e82a..08a05debb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs @@ -125,6 +125,11 @@ namespace NzbDrone.Core.Indexers.Newznab parameters.Add("tvdbid", searchCriteria.TvdbId.Value.ToString()); } + if (searchCriteria.TmdbId.HasValue && capabilities.TvSearchTvdbAvailable) + { + parameters.Add("tmdbid", searchCriteria.TvdbId.Value.ToString()); + } + if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace() && capabilities.TvSearchImdbAvailable) { parameters.Add("imdbid", searchCriteria.ImdbId); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs index b3792a47b..851951356 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs @@ -96,7 +96,7 @@ namespace NzbDrone.Core.Indexers.Newznab releaseInfo = base.ProcessItem(item, releaseInfo); releaseInfo.ImdbId = GetIntAttribute(item, "imdb"); - releaseInfo.TmdbId = GetIntAttribute(item, "tmdb"); + releaseInfo.TmdbId = GetIntAttribute(item, "tmdbid"); releaseInfo.TvdbId = GetIntAttribute(item, "tvdbid"); releaseInfo.TvRageId = GetIntAttribute(item, "rageid"); releaseInfo.Grabs = GetIntAttribute(item, "grabs"); diff --git a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs index b8e77e328..0505c9e0d 100644 --- a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs +++ b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs @@ -33,6 +33,7 @@ namespace NzbDrone.Core.Parser.Model public int ImdbId { get; set; } public int TmdbId { get; set; } public int TraktId { get; set; } + public int DoubanId { get; set; } public int Year { get; set; } public string Author { get; set; } public string BookTitle { get; set; } From a6b499e4a5df1104273148dc56e85a193c6835eb Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 28 Jun 2022 18:31:13 -0500 Subject: [PATCH 0511/2320] Fixed: Correctly remove TorrentParadiseMl Fixes #1046 --- .../Datastore/Migration/017_indexer_cleanup.cs | 1 - .../Migration/020_remove_torrentparadiseml.cs | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 src/NzbDrone.Core/Datastore/Migration/020_remove_torrentparadiseml.cs diff --git a/src/NzbDrone.Core/Datastore/Migration/017_indexer_cleanup.cs b/src/NzbDrone.Core/Datastore/Migration/017_indexer_cleanup.cs index fefc24aeb..defd8eb5f 100644 --- a/src/NzbDrone.Core/Datastore/Migration/017_indexer_cleanup.cs +++ b/src/NzbDrone.Core/Datastore/Migration/017_indexer_cleanup.cs @@ -24,7 +24,6 @@ namespace NzbDrone.Core.Datastore.Migration Delete.FromTable("Indexers").Row(new { Implementation = "ThePirateBay" }); Delete.FromTable("Indexers").Row(new { Implementation = "TorrentLeech" }); Delete.FromTable("Indexers").Row(new { Implementation = "TorrentSeeds" }); - Delete.FromTable("Indexers").Row(new { Implementation = "TorrentParadiseMI" }); Delete.FromTable("Indexers").Row(new { Implementation = "YTS" }); //Change settings to shared classes diff --git a/src/NzbDrone.Core/Datastore/Migration/020_remove_torrentparadiseml.cs b/src/NzbDrone.Core/Datastore/Migration/020_remove_torrentparadiseml.cs new file mode 100644 index 000000000..662e7ecef --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/020_remove_torrentparadiseml.cs @@ -0,0 +1,15 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(020)] + public class remove_torrentparadiseml : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + // Remove, 017 incorrectly removes this using "TorrentParadiseMI" + Delete.FromTable("Indexers").Row(new { Implementation = "TorrentParadiseMl" }); + } + } +} From 76285a8ccd5183430e235d49cc1591b477bf8c21 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 28 Jun 2022 19:45:16 -0500 Subject: [PATCH 0512/2320] Add additional link logging to DownloadService --- src/NzbDrone.Core/Download/DownloadService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NzbDrone.Core/Download/DownloadService.cs b/src/NzbDrone.Core/Download/DownloadService.cs index 34a18e029..6c6f67f0a 100644 --- a/src/NzbDrone.Core/Download/DownloadService.cs +++ b/src/NzbDrone.Core/Download/DownloadService.cs @@ -114,6 +114,7 @@ namespace NzbDrone.Core.Download public async Task<byte[]> DownloadReport(string link, int indexerId, string source, string host, string title) { + _logger.Trace("Attempting download of {0}", link); var url = new Uri(link); // Limit grabs to 2 per second. From 9b1f9abfacbb72eba6a5aa14609cc8c1ec4e4628 Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Sat, 2 Jul 2022 16:26:59 +0100 Subject: [PATCH 0513/2320] Updated NLog Version (#7365) --- .../Extensions/SentryLoggerExtensions.cs | 31 ++++++++++--------- .../Instrumentation/NzbDroneFileTarget.cs | 9 ++++-- .../Instrumentation/NzbDroneLogger.cs | 13 ++++++++ src/NzbDrone.Common/Prowlarr.Common.csproj | 4 ++- .../Definitions/FileList/FileListSettings.cs | 24 -------------- .../Instrumentation/ReconfigureLogging.cs | 3 +- src/NzbDrone.Core/Prowlarr.Core.csproj | 4 +-- src/NzbDrone.Host/Prowlarr.Host.csproj | 2 +- .../Prowlarr.Test.Common.csproj | 2 +- src/NzbDrone.Update/Prowlarr.Update.csproj | 2 +- src/NzbDrone.Windows/Prowlarr.Windows.csproj | 2 +- src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj | 2 +- src/Prowlarr.Http/Prowlarr.Http.csproj | 4 +-- 13 files changed, 48 insertions(+), 54 deletions(-) diff --git a/src/NzbDrone.Common/Instrumentation/Extensions/SentryLoggerExtensions.cs b/src/NzbDrone.Common/Instrumentation/Extensions/SentryLoggerExtensions.cs index 2e17aad44..437288d69 100644 --- a/src/NzbDrone.Common/Instrumentation/Extensions/SentryLoggerExtensions.cs +++ b/src/NzbDrone.Common/Instrumentation/Extensions/SentryLoggerExtensions.cs @@ -1,4 +1,6 @@ -using System.Linq; +using System; +using System.Collections.Generic; +using System.Linq; using NLog; using NLog.Fluent; @@ -8,47 +10,46 @@ namespace NzbDrone.Common.Instrumentation.Extensions { public static readonly Logger SentryLogger = LogManager.GetLogger("Sentry"); - public static LogBuilder SentryFingerprint(this LogBuilder logBuilder, params string[] fingerprint) + public static LogEventBuilder SentryFingerprint(this LogEventBuilder logBuilder, params string[] fingerprint) { return logBuilder.Property("Sentry", fingerprint); } - public static LogBuilder WriteSentryDebug(this LogBuilder logBuilder, params string[] fingerprint) + public static LogEventBuilder WriteSentryDebug(this LogEventBuilder logBuilder, params string[] fingerprint) { return LogSentryMessage(logBuilder, LogLevel.Debug, fingerprint); } - public static LogBuilder WriteSentryInfo(this LogBuilder logBuilder, params string[] fingerprint) + public static LogEventBuilder WriteSentryInfo(this LogEventBuilder logBuilder, params string[] fingerprint) { return LogSentryMessage(logBuilder, LogLevel.Info, fingerprint); } - public static LogBuilder WriteSentryWarn(this LogBuilder logBuilder, params string[] fingerprint) + public static LogEventBuilder WriteSentryWarn(this LogEventBuilder logBuilder, params string[] fingerprint) { return LogSentryMessage(logBuilder, LogLevel.Warn, fingerprint); } - public static LogBuilder WriteSentryError(this LogBuilder logBuilder, params string[] fingerprint) + public static LogEventBuilder WriteSentryError(this LogEventBuilder logBuilder, params string[] fingerprint) { return LogSentryMessage(logBuilder, LogLevel.Error, fingerprint); } - private static LogBuilder LogSentryMessage(LogBuilder logBuilder, LogLevel level, string[] fingerprint) + private static LogEventBuilder LogSentryMessage(LogEventBuilder logBuilder, LogLevel level, string[] fingerprint) { - SentryLogger.Log(level) - .CopyLogEvent(logBuilder.LogEventInfo) + SentryLogger.ForLogEvent(level) + .CopyLogEvent(logBuilder.LogEvent) .SentryFingerprint(fingerprint) - .Write(); + .Log(); - return logBuilder.Property("Sentry", null); + return logBuilder.Property<string>("Sentry", null); } - private static LogBuilder CopyLogEvent(this LogBuilder logBuilder, LogEventInfo logEvent) + private static LogEventBuilder CopyLogEvent(this LogEventBuilder logBuilder, LogEventInfo logEvent) { - return logBuilder.LoggerName(logEvent.LoggerName) - .TimeStamp(logEvent.TimeStamp) + return logBuilder.TimeStamp(logEvent.TimeStamp) .Message(logEvent.Message, logEvent.Parameters) - .Properties(logEvent.Properties.ToDictionary(v => v.Key, v => v.Value)) + .Properties(logEvent.Properties.Select(p => new KeyValuePair<string, object>(p.Key.ToString(), p.Value))) .Exception(logEvent.Exception); } } diff --git a/src/NzbDrone.Common/Instrumentation/NzbDroneFileTarget.cs b/src/NzbDrone.Common/Instrumentation/NzbDroneFileTarget.cs index 62e41b0e0..e2c38f95c 100644 --- a/src/NzbDrone.Common/Instrumentation/NzbDroneFileTarget.cs +++ b/src/NzbDrone.Common/Instrumentation/NzbDroneFileTarget.cs @@ -1,13 +1,16 @@ -using NLog; +using System; +using System.Text; +using NLog; using NLog.Targets; namespace NzbDrone.Common.Instrumentation { public class NzbDroneFileTarget : FileTarget { - protected override string GetFormattedMessage(LogEventInfo logEvent) + protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target) { - return CleanseLogMessage.Cleanse(Layout.Render(logEvent)); + var result = CleanseLogMessage.Cleanse(Layout.Render(logEvent)); + target.Append(result); } } } diff --git a/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs b/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs index 5a98d35d0..7d8cfaf83 100644 --- a/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs +++ b/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs @@ -34,6 +34,8 @@ namespace NzbDrone.Common.Instrumentation var appFolderInfo = new AppFolderInfo(startupContext); + RegisterGlobalFilters(); + if (Debugger.IsAttached) { RegisterDebugger(); @@ -97,10 +99,21 @@ namespace NzbDrone.Common.Instrumentation target.Layout = "[${level}] [${threadid}] ${logger}: ${message} ${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}"; var loggingRule = new LoggingRule("*", LogLevel.Trace, target); + LogManager.Configuration.AddTarget("debugger", target); LogManager.Configuration.LoggingRules.Add(loggingRule); } + private static void RegisterGlobalFilters() + { + LogManager.Setup().LoadConfiguration(c => + { + c.ForLogger("Microsoft.Hosting.Lifetime*").WriteToNil(LogLevel.Info); + c.ForLogger("System*").WriteToNil(LogLevel.Warn); + c.ForLogger("Microsoft*").WriteToNil(LogLevel.Warn); + }); + } + private static void RegisterConsole() { var level = LogLevel.Trace; diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index 52da94711..298c3825d 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -9,8 +9,10 @@ <PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> - <PackageReference Include="NLog" Version="4.7.14" /> + <PackageReference Include="NLog" Version="5.0.1" /> + <PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" /> <PackageReference Include="Sentry" Version="3.18.0" /> + <PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" /> <PackageReference Include="SharpZipLib" Version="1.3.3" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> diff --git a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListSettings.cs index 82320a91d..ec8e9c4bd 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListSettings.cs @@ -34,28 +34,4 @@ namespace NzbDrone.Core.Indexers.FileList return new NzbDroneValidationResult(Validator.Validate(this)); } } - - public enum FileListCategories - { - [FieldOption] - Movie_SD = 1, - [FieldOption] - Movie_DVD = 2, - [FieldOption] - Movie_DVDRO = 3, - [FieldOption] - Movie_HD = 4, - [FieldOption] - Movie_HDRO = 19, - [FieldOption] - Movie_BluRay = 20, - [FieldOption] - Movie_BluRay4K = 26, - [FieldOption] - Movie_3D = 25, - [FieldOption] - Movie_4K = 6, - [FieldOption] - Xxx = 7 - } } diff --git a/src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs b/src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs index b2f80d8d1..38b695ccc 100644 --- a/src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs +++ b/src/NzbDrone.Core/Instrumentation/ReconfigureLogging.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using NLog; using NLog.Config; @@ -117,7 +117,6 @@ namespace NzbDrone.Core.Instrumentation syslogTarget.MessageSend.Protocol = ProtocolType.Udp; syslogTarget.MessageSend.Udp.Port = syslogPort; syslogTarget.MessageSend.Udp.Server = syslogServer; - syslogTarget.MessageSend.Udp.ReconnectInterval = 500; syslogTarget.MessageCreation.Rfc = RfcNumber.Rfc5424; syslogTarget.MessageCreation.Rfc5424.AppName = _configFileProvider.InstanceName; diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index d43d7135a..cf38f7cae 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -8,7 +8,7 @@ <PackageReference Include="FluentMigrator.Runner" Version="3.3.2" /> <PackageReference Include="MailKit" Version="3.1.1" /> <PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" /> - <PackageReference Include="NLog.Targets.Syslog" Version="6.0.3" /> + <PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" /> <PackageReference Include="Npgsql" Version="5.0.11" /> <PackageReference Include="System.Memory" Version="4.5.5" /> <PackageReference Include="System.ServiceModel.Syndication" Version="6.0.0" /> @@ -16,7 +16,7 @@ <PackageReference Include="FluentMigrator.Runner.Postgres" Version="3.3.2" /> <PackageReference Include="FluentValidation" Version="8.6.2" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> - <PackageReference Include="NLog" Version="4.7.14" /> + <PackageReference Include="NLog" Version="5.0.1" /> <PackageReference Include="TinyTwitter" Version="1.1.2" /> <PackageReference Include="Kveer.XmlRPC" Version="1.1.1" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> diff --git a/src/NzbDrone.Host/Prowlarr.Host.csproj b/src/NzbDrone.Host/Prowlarr.Host.csproj index 06fb50e0b..2d46ee94d 100644 --- a/src/NzbDrone.Host/Prowlarr.Host.csproj +++ b/src/NzbDrone.Host/Prowlarr.Host.csproj @@ -4,7 +4,7 @@ <OutputType>Library</OutputType> </PropertyGroup> <ItemGroup> - <PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" /> + <PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.3.1" /> diff --git a/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj b/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj index 249797e07..1ca89ee02 100644 --- a/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj +++ b/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj @@ -6,7 +6,7 @@ <PackageReference Include="FluentAssertions" Version="5.10.3" /> <PackageReference Include="FluentValidation" Version="8.6.2" /> <PackageReference Include="Moq" Version="4.17.2" /> - <PackageReference Include="NLog" Version="4.7.14" /> + <PackageReference Include="NLog" Version="5.0.1" /> <PackageReference Include="NUnit" Version="3.13.3" /> <PackageReference Include="RestSharp" Version="106.15.0" /> <PackageReference Include="RestSharp.Serializers.SystemTextJson" Version="106.15.0" /> diff --git a/src/NzbDrone.Update/Prowlarr.Update.csproj b/src/NzbDrone.Update/Prowlarr.Update.csproj index a75badc8e..ba6785fc3 100644 --- a/src/NzbDrone.Update/Prowlarr.Update.csproj +++ b/src/NzbDrone.Update/Prowlarr.Update.csproj @@ -6,7 +6,7 @@ <ItemGroup> <PackageReference Include="DryIoc.dll" Version="4.8.8" /> <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="5.1.0" /> - <PackageReference Include="NLog" Version="4.7.14" /> + <PackageReference Include="NLog" Version="5.0.1" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Common\Prowlarr.Common.csproj" /> diff --git a/src/NzbDrone.Windows/Prowlarr.Windows.csproj b/src/NzbDrone.Windows/Prowlarr.Windows.csproj index 2b5a5c955..1661cd01f 100644 --- a/src/NzbDrone.Windows/Prowlarr.Windows.csproj +++ b/src/NzbDrone.Windows/Prowlarr.Windows.csproj @@ -4,7 +4,7 @@ <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> </PropertyGroup> <ItemGroup> - <PackageReference Include="NLog" Version="4.7.14" /> + <PackageReference Include="NLog" Version="5.0.1" /> <PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" /> </ItemGroup> <ItemGroup> diff --git a/src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj b/src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj index c1c33aa86..5fa5c9af6 100644 --- a/src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj +++ b/src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj @@ -4,7 +4,7 @@ </PropertyGroup> <ItemGroup> <PackageReference Include="FluentValidation" Version="8.6.2" /> - <PackageReference Include="NLog" Version="4.7.14" /> + <PackageReference Include="NLog" Version="5.0.1" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Core\Prowlarr.Core.csproj" /> diff --git a/src/Prowlarr.Http/Prowlarr.Http.csproj b/src/Prowlarr.Http/Prowlarr.Http.csproj index d5d25faea..75751a276 100644 --- a/src/Prowlarr.Http/Prowlarr.Http.csproj +++ b/src/Prowlarr.Http/Prowlarr.Http.csproj @@ -4,8 +4,8 @@ </PropertyGroup> <ItemGroup> <PackageReference Include="FluentValidation" Version="8.6.2" /> - <PackageReference Include="ImpromptuInterface" Version="7.0.1" /> - <PackageReference Include="NLog" Version="4.7.14" /> + <PackageReference Include="ImpromptuInterface" Version="7.0.1" /> + <PackageReference Include="NLog" Version="5.0.1" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Core\Prowlarr.Core.csproj" /> From cac27292305a50792c192bd0e906e384e6241647 Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Sat, 2 Jul 2022 23:48:10 +0100 Subject: [PATCH 0514/2320] Running Integration Tests against Postgres Database (#838) * Allow configuring postgres with environment variables (cherry picked from commit 8439df78fea25656a9a1275d2a2fe3f0df0528c7) * Fix process provider when environment variables alread exist [common] (cherry picked from commit 66e5b4025974e081c1406f01a860b1ac52949c22) * First bash at running integration tests on postgres (cherry picked from commit f950e80c7e4f9b088ec6a149386160eab83b61c3) * Postgres integration tests running as part of the build pipeline (cherry picked from commit 9ca8616f5098778e9b5e6ce09d2aa11224018fab) * Fixed: Register PostgresOptions when running in utility mode * fixup! * fixup! * fixup! * fixup! * fixup! Co-authored-by: ta264 <ta264@users.noreply.github.com> Co-authored-by: Qstick <qstick@gmail.com> --- azure-pipelines.yml | 113 ++++++++++++++++++ .../AutomationTest.cs | 2 +- .../ProcessProviderFixture.cs | 2 +- .../ServiceFactoryFixture.cs | 5 +- .../Processes/ProcessProvider.cs | 13 +- .../Datastore/DatabaseFixture.cs | 2 +- src/NzbDrone.Core.Test/Framework/DbTest.cs | 53 ++++++-- .../Framework/DbTestCleanup.cs | 6 +- .../Framework/TestDatabase.cs | 3 + .../FixFutureRunScheduledTasksFixture.cs | 3 +- .../Configuration/ConfigFileProvider.cs | 19 +-- .../Datastore/BasicRepository.cs | 8 +- .../Datastore/PostgresOptions.cs | 26 ++++ .../Datastore/WhereBuilderPostgres.cs | 21 +++- src/NzbDrone.Host.Test/ContainerFixture.cs | 10 ++ src/NzbDrone.Host/Bootstrap.cs | 33 ++++- .../IntegrationTest.cs | 33 ++++- .../SymlinkResolverFixture.cs | 7 +- .../Datastore/PostgresDatabase.cs | 69 +++++++++++ .../Datastore/SqliteDatabase.cs | 14 +++ src/NzbDrone.Test.Common/NzbDroneRunner.cs | 23 +++- src/NzbDrone.Test.Common/TestBase.cs | 8 -- src/postgres.runsettings | 11 ++ 23 files changed, 428 insertions(+), 56 deletions(-) create mode 100644 src/NzbDrone.Core/Datastore/PostgresOptions.cs create mode 100644 src/NzbDrone.Test.Common/Datastore/PostgresDatabase.cs create mode 100644 src/NzbDrone.Test.Common/Datastore/SqliteDatabase.cs create mode 100644 src/postgres.runsettings diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5d4cff6ae..89e9d33df 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -506,6 +506,58 @@ stages: testResultsFiles: '**/TestResult.xml' testRunTitle: '$(testName) Unit Tests' failTaskOnFailedTests: true + + - job: Unit_LinuxCore_Postgres + displayName: Unit Native LinuxCore with Postgres Database + dependsOn: Prepare + condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0')) + variables: + pattern: 'Prowlarr.*.linux-core-x64.tar.gz' + artifactName: LinuxCoreTests + Prowlarr__Postgres__Host: 'localhost' + Prowlarr__Postgres__Port: '5432' + Prowlarr__Postgres__User: 'prowlarr' + Prowlarr__Postgres__Password: 'prowlarr' + + pool: + vmImage: 'ubuntu-18.04' + + timeoutInMinutes: 10 + + steps: + - task: UseDotNet@2 + displayName: 'Install .net core' + inputs: + version: $(dotnetVersion) + - checkout: none + - task: DownloadPipelineArtifact@2 + displayName: Download Test Artifact + inputs: + buildType: 'current' + artifactName: $(artifactName) + targetPath: $(testsFolder) + - bash: find ${TESTSFOLDER} -name "Prowlarr.Test.Dummy" -exec chmod a+x {} \; + displayName: Make Test Dummy Executable + condition: and(succeeded(), ne(variables['osName'], 'Windows')) + - bash: | + docker run -d --name=postgres14 \ + -e POSTGRES_PASSWORD=prowlarr \ + -e POSTGRES_USER=prowlarr \ + -p 5432:5432/tcp \ + postgres:14 + displayName: Start postgres + - bash: | + chmod a+x ${TESTSFOLDER}/test.sh + ls -lR ${TESTSFOLDER} + ${TESTSFOLDER}/test.sh Linux Unit Test + displayName: Run Tests + - task: PublishTestResults@2 + displayName: Publish Test Results + inputs: + testResultsFormat: 'NUnit' + testResultsFiles: '**/TestResult.xml' + testRunTitle: 'LinuxCore Postgres Unit Tests' + failTaskOnFailedTests: true - stage: Integration displayName: Integration @@ -590,6 +642,67 @@ stages: failTaskOnFailedTests: true displayName: Publish Test Results + - job: Integration_LinuxCore_Postgres + displayName: Integration Native LinuxCore with Postgres Database + dependsOn: Prepare + condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0')) + variables: + pattern: 'Prowlarr.*.linux-core-x64.tar.gz' + Prowlarr__Postgres__Host: 'localhost' + Prowlarr__Postgres__Port: '5432' + Prowlarr__Postgres__User: 'prowlarr' + Prowlarr__Postgres__Password: 'prowlarr' + + pool: + vmImage: 'ubuntu-18.04' + + steps: + - task: UseDotNet@2 + displayName: 'Install .net core' + inputs: + version: $(dotnetVersion) + - checkout: none + - task: DownloadPipelineArtifact@2 + displayName: Download Test Artifact + inputs: + buildType: 'current' + artifactName: 'LinuxCoreTests' + targetPath: $(testsFolder) + - task: DownloadPipelineArtifact@2 + displayName: Download Build Artifact + inputs: + buildType: 'current' + artifactName: Packages + itemPattern: '**/$(pattern)' + targetPath: $(Build.ArtifactStagingDirectory) + - task: ExtractFiles@1 + inputs: + archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)' + destinationFolder: '$(Build.ArtifactStagingDirectory)/bin' + displayName: Extract Package + - bash: | + mkdir -p ./bin/ + cp -r -v ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin/Prowlarr/. ./bin/ + displayName: Move Package Contents + - bash: | + docker run -d --name=postgres14 \ + -e POSTGRES_PASSWORD=prowlarr \ + -e POSTGRES_USER=prowlarr \ + -p 5432:5432/tcp \ + postgres:14 + displayName: Start postgres + - bash: | + chmod a+x ${TESTSFOLDER}/test.sh + ${TESTSFOLDER}/test.sh Linux Integration Test + displayName: Run Integration Tests + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'NUnit' + testResultsFiles: '**/TestResult.xml' + testRunTitle: 'Integration LinuxCore Postgres Database Integration Tests' + failTaskOnFailedTests: true + displayName: Publish Test Results + - job: Integration_FreeBSD displayName: Integration Native FreeBSD dependsOn: Prepare diff --git a/src/NzbDrone.Automation.Test/AutomationTest.cs b/src/NzbDrone.Automation.Test/AutomationTest.cs index 638b1aaf5..840346de8 100644 --- a/src/NzbDrone.Automation.Test/AutomationTest.cs +++ b/src/NzbDrone.Automation.Test/AutomationTest.cs @@ -44,7 +44,7 @@ namespace NzbDrone.Automation.Test driver.Manage().Window.Size = new System.Drawing.Size(1920, 1080); - _runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger()); + _runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), null); _runner.KillAll(); _runner.Start(); diff --git a/src/NzbDrone.Common.Test/ProcessProviderFixture.cs b/src/NzbDrone.Common.Test/ProcessProviderFixture.cs index b81bbfa19..106c25fa0 100644 --- a/src/NzbDrone.Common.Test/ProcessProviderFixture.cs +++ b/src/NzbDrone.Common.Test/ProcessProviderFixture.cs @@ -170,7 +170,7 @@ namespace NzbDrone.Common.Test var processStarted = new ManualResetEventSlim(); string suffix; - if (OsInfo.IsWindows || PlatformInfo.IsMono) + if (OsInfo.IsWindows) { suffix = ".exe"; } diff --git a/src/NzbDrone.Common.Test/ServiceFactoryFixture.cs b/src/NzbDrone.Common.Test/ServiceFactoryFixture.cs index 560bf39ea..9c348316f 100644 --- a/src/NzbDrone.Common.Test/ServiceFactoryFixture.cs +++ b/src/NzbDrone.Common.Test/ServiceFactoryFixture.cs @@ -4,11 +4,13 @@ using DryIoc.Microsoft.DependencyInjection; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using NzbDrone.Common.Composition.Extensions; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Instrumentation.Extensions; +using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore.Extensions; using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Messaging.Events; @@ -29,7 +31,8 @@ namespace NzbDrone.Common.Test .AddDummyDatabase() .AddStartupContext(new StartupContext("first", "second")); - container.RegisterInstance<IHostLifetime>(new Mock<IHostLifetime>().Object); + container.RegisterInstance(new Mock<IHostLifetime>().Object); + container.RegisterInstance(new Mock<IOptions<PostgresOptions>>().Object); var serviceProvider = container.GetServiceProvider(); diff --git a/src/NzbDrone.Common/Processes/ProcessProvider.cs b/src/NzbDrone.Common/Processes/ProcessProvider.cs index 953450aaa..796f4f6e8 100644 --- a/src/NzbDrone.Common/Processes/ProcessProvider.cs +++ b/src/NzbDrone.Common/Processes/ProcessProvider.cs @@ -127,7 +127,18 @@ namespace NzbDrone.Common.Processes try { _logger.Trace("Setting environment variable '{0}' to '{1}'", environmentVariable.Key, environmentVariable.Value); - startInfo.EnvironmentVariables.Add(environmentVariable.Key.ToString(), environmentVariable.Value.ToString()); + + var key = environmentVariable.Key.ToString(); + var value = environmentVariable.Value?.ToString(); + + if (startInfo.EnvironmentVariables.ContainsKey(key)) + { + startInfo.EnvironmentVariables[key] = value; + } + else + { + startInfo.EnvironmentVariables.Add(key, value); + } } catch (Exception e) { diff --git a/src/NzbDrone.Core.Test/Datastore/DatabaseFixture.cs b/src/NzbDrone.Core.Test/Datastore/DatabaseFixture.cs index 1bc182395..985fbb7d5 100644 --- a/src/NzbDrone.Core.Test/Datastore/DatabaseFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/DatabaseFixture.cs @@ -15,7 +15,7 @@ namespace NzbDrone.Core.Test.Datastore public void SingleOrDefault_should_return_null_on_empty_db() { Mocker.Resolve<IDatabase>() - .OpenConnection().Query<IndexerDefinition>("SELECT * FROM Indexers") + .OpenConnection().Query<IndexerDefinition>("SELECT * FROM \"Indexers\"") .SingleOrDefault() .Should() .BeNull(); diff --git a/src/NzbDrone.Core.Test/Framework/DbTest.cs b/src/NzbDrone.Core.Test/Framework/DbTest.cs index e38336375..05cfd5bfd 100644 --- a/src/NzbDrone.Core.Test/Framework/DbTest.cs +++ b/src/NzbDrone.Core.Test/Framework/DbTest.cs @@ -5,10 +5,14 @@ using System.IO; using System.Linq; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using Npgsql; using NUnit.Framework; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Configuration; using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore.Migration.Framework; +using NzbDrone.Test.Common.Datastore; namespace NzbDrone.Core.Test.Framework { @@ -49,6 +53,7 @@ namespace NzbDrone.Core.Test.Framework public abstract class DbTest : CoreTest { private ITestDatabase _db; + private DatabaseType _databaseType; protected virtual MigrationType MigrationType => MigrationType.Main; @@ -101,17 +106,39 @@ namespace NzbDrone.Core.Test.Framework private IDatabase CreateDatabase(MigrationContext migrationContext) { + if (_databaseType == DatabaseType.PostgreSQL) + { + CreatePostgresDb(); + } + var factory = Mocker.Resolve<DbFactory>(); // If a special migration test or log migration then create new - if (migrationContext.BeforeMigration != null) + if (migrationContext.BeforeMigration != null || _databaseType == DatabaseType.PostgreSQL) { return factory.Create(migrationContext); } + return CreateSqliteDatabase(factory, migrationContext); + } + + private void CreatePostgresDb() + { + var options = Mocker.Resolve<IOptions<PostgresOptions>>().Value; + PostgresDatabase.Create(options, MigrationType); + } + + private void DropPostgresDb() + { + var options = Mocker.Resolve<IOptions<PostgresOptions>>().Value; + PostgresDatabase.Drop(options, MigrationType); + } + + private IDatabase CreateSqliteDatabase(IDbFactory factory, MigrationContext migrationContext) + { // Otherwise try to use a cached migrated db - var cachedDb = GetCachedDatabase(migrationContext.MigrationType); - var testDb = GetTestDb(migrationContext.MigrationType); + var cachedDb = SqliteDatabase.GetCachedDb(migrationContext.MigrationType); + var testDb = GetTestSqliteDb(migrationContext.MigrationType); if (File.Exists(cachedDb)) { TestLogger.Info($"Using cached initial database {cachedDb}"); @@ -131,12 +158,7 @@ namespace NzbDrone.Core.Test.Framework } } - private string GetCachedDatabase(MigrationType type) - { - return Path.Combine(TestContext.CurrentContext.TestDirectory, $"cached_{type}.db"); - } - - private string GetTestDb(MigrationType type) + private string GetTestSqliteDb(MigrationType type) { return type == MigrationType.Main ? TestFolderInfo.GetDatabase() : TestFolderInfo.GetLogDatabase(); } @@ -151,6 +173,13 @@ namespace NzbDrone.Core.Test.Framework WithTempAsAppPath(); SetupLogging(); + // populate the possible postgres options + var postgresOptions = PostgresDatabase.GetTestOptions(); + _databaseType = postgresOptions.Host.IsNotNullOrWhiteSpace() ? DatabaseType.PostgreSQL : DatabaseType.SQLite; + + // Set up remaining container services + Mocker.SetConstant(Options.Create(postgresOptions)); + Mocker.SetConstant<IConfigFileProvider>(Mocker.Resolve<ConfigFileProvider>()); Mocker.SetConstant<IConnectionStringFactory>(Mocker.Resolve<ConnectionStringFactory>()); Mocker.SetConstant<IMigrationController>(Mocker.Resolve<MigrationController>()); @@ -171,11 +200,17 @@ namespace NzbDrone.Core.Test.Framework GC.Collect(); GC.WaitForPendingFinalizers(); SQLiteConnection.ClearAllPools(); + NpgsqlConnection.ClearAllPools(); if (TestFolderInfo != null) { DeleteTempFolder(TestFolderInfo.AppDataFolder); } + + if (_databaseType == DatabaseType.PostgreSQL) + { + DropPostgresDb(); + } } } } diff --git a/src/NzbDrone.Core.Test/Framework/DbTestCleanup.cs b/src/NzbDrone.Core.Test/Framework/DbTestCleanup.cs index 587043e95..ae6b102a7 100644 --- a/src/NzbDrone.Core.Test/Framework/DbTestCleanup.cs +++ b/src/NzbDrone.Core.Test/Framework/DbTestCleanup.cs @@ -1,5 +1,7 @@ using System.IO; using NUnit.Framework; +using NzbDrone.Core.Datastore.Migration.Framework; +using NzbDrone.Test.Common.Datastore; namespace NzbDrone.Core.Test { @@ -10,13 +12,13 @@ namespace NzbDrone.Core.Test [OneTimeTearDown] public void ClearCachedDatabase() { - var mainCache = Path.Combine(TestContext.CurrentContext.TestDirectory, $"cached_Main.db"); + var mainCache = SqliteDatabase.GetCachedDb(MigrationType.Main); if (File.Exists(mainCache)) { File.Delete(mainCache); } - var logCache = Path.Combine(TestContext.CurrentContext.TestDirectory, $"cached_Log.db"); + var logCache = SqliteDatabase.GetCachedDb(MigrationType.Log); if (File.Exists(logCache)) { File.Delete(logCache); diff --git a/src/NzbDrone.Core.Test/Framework/TestDatabase.cs b/src/NzbDrone.Core.Test/Framework/TestDatabase.cs index 3fbfdf028..5391cfb1f 100644 --- a/src/NzbDrone.Core.Test/Framework/TestDatabase.cs +++ b/src/NzbDrone.Core.Test/Framework/TestDatabase.cs @@ -23,6 +23,7 @@ namespace NzbDrone.Core.Test.Framework where T : ModelBase, new(); IDirectDataMapper GetDirectDataMapper(); IDbConnection OpenConnection(); + DatabaseType DatabaseType { get; } } public class TestDatabase : ITestDatabase @@ -30,6 +31,8 @@ namespace NzbDrone.Core.Test.Framework private readonly IDatabase _dbConnection; private readonly IEventAggregator _eventAggregator; + public DatabaseType DatabaseType => _dbConnection.DatabaseType; + public TestDatabase(IDatabase dbConnection) { _eventAggregator = new Mock<IEventAggregator>().Object; diff --git a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/FixFutureRunScheduledTasksFixture.cs b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/FixFutureRunScheduledTasksFixture.cs index 68e4c87e6..39e193368 100644 --- a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/FixFutureRunScheduledTasksFixture.cs +++ b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/FixFutureRunScheduledTasksFixture.cs @@ -41,7 +41,8 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers Subject.Clean(); - AllStoredModels.ToList().ForEach(t => t.LastExecution.Should().Be(expectedTime)); + // BeCloseTo handles Postgres rounding times + AllStoredModels.ToList().ForEach(t => t.LastExecution.Should().BeCloseTo(expectedTime)); } } } diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index 796d475c9..6b55b6ece 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -5,12 +5,14 @@ using System.Linq; using System.Text.RegularExpressions; using System.Xml; using System.Xml.Linq; +using Microsoft.Extensions.Options; using NzbDrone.Common.Cache; using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; using NzbDrone.Core.Authentication; using NzbDrone.Core.Configuration.Events; +using NzbDrone.Core.Datastore; using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Events; @@ -67,6 +69,7 @@ namespace NzbDrone.Core.Configuration private readonly IEventAggregator _eventAggregator; private readonly IDiskProvider _diskProvider; private readonly ICached<string> _cache; + private readonly PostgresOptions _postgresOptions; private readonly string _configFile; private static readonly Regex HiddenCharacterRegex = new Regex("[^a-z0-9]", RegexOptions.Compiled | RegexOptions.IgnoreCase); @@ -76,12 +79,14 @@ namespace NzbDrone.Core.Configuration public ConfigFileProvider(IAppFolderInfo appFolderInfo, ICacheManager cacheManager, IEventAggregator eventAggregator, - IDiskProvider diskProvider) + IDiskProvider diskProvider, + IOptions<PostgresOptions> postgresOptions) { _cache = cacheManager.GetCache<string>(GetType()); _eventAggregator = eventAggregator; _diskProvider = diskProvider; _configFile = appFolderInfo.GetConfigPath(); + _postgresOptions = postgresOptions.Value; } public Dictionary<string, object> GetConfigDictionary() @@ -195,13 +200,13 @@ namespace NzbDrone.Core.Configuration public string LogLevel => GetValue("LogLevel", "info").ToLowerInvariant(); public string ConsoleLogLevel => GetValue("ConsoleLogLevel", string.Empty, persist: false); - public string PostgresHost => GetValue("PostgresHost", string.Empty, persist: false); - public string PostgresUser => GetValue("PostgresUser", string.Empty, persist: false); - public string PostgresPassword => GetValue("PostgresPassword", string.Empty, persist: false); - public string PostgresMainDb => GetValue("PostgresMainDb", "prowlarr-main", persist: false); - public string PostgresLogDb => GetValue("PostgresLogDb", "prowlarr-log", persist: false); + public string PostgresHost => _postgresOptions?.Host ?? GetValue("PostgresHost", string.Empty, persist: false); + public string PostgresUser => _postgresOptions?.User ?? GetValue("PostgresUser", string.Empty, persist: false); + public string PostgresPassword => _postgresOptions?.Password ?? GetValue("PostgresPassword", string.Empty, persist: false); + public string PostgresMainDb => _postgresOptions?.MainDb ?? GetValue("PostgresMainDb", "prowlarr-main", persist: false); + public string PostgresLogDb => _postgresOptions?.LogDb ?? GetValue("PostgresLogDb", "prowlarr-log", persist: false); + public int PostgresPort => (_postgresOptions?.Port ?? 0) != 0 ? _postgresOptions.Port : GetValueInt("PostgresPort", 5432, persist: false); public string Theme => GetValue("Theme", "light", persist: false); - public int PostgresPort => GetValueInt("PostgresPort", 5432, persist: false); public bool LogSql => GetValueBoolean("LogSql", false, persist: false); public int LogRotate => GetValueInt("LogRotate", 50, persist: false); public bool FilterSentryEvents => GetValueBoolean("FilterSentryEvents", true, persist: false); diff --git a/src/NzbDrone.Core/Datastore/BasicRepository.cs b/src/NzbDrone.Core/Datastore/BasicRepository.cs index 33253efa9..b34b530b2 100644 --- a/src/NzbDrone.Core/Datastore/BasicRepository.cs +++ b/src/NzbDrone.Core/Datastore/BasicRepository.cs @@ -167,14 +167,12 @@ namespace NzbDrone.Core.Datastore } } - if (_database.DatabaseType == DatabaseType.SQLite) - { - return $"INSERT INTO {_table} ({sbColumnList.ToString()}) VALUES ({sbParameterList.ToString()}); SELECT last_insert_rowid() id"; - } - else + if (_database.DatabaseType == DatabaseType.PostgreSQL) { return $"INSERT INTO \"{_table}\" ({sbColumnList.ToString()}) VALUES ({sbParameterList.ToString()}) RETURNING \"Id\""; } + + return $"INSERT INTO {_table} ({sbColumnList.ToString()}) VALUES ({sbParameterList.ToString()}); SELECT last_insert_rowid() id"; } private TModel Insert(IDbConnection connection, IDbTransaction transaction, TModel model) diff --git a/src/NzbDrone.Core/Datastore/PostgresOptions.cs b/src/NzbDrone.Core/Datastore/PostgresOptions.cs new file mode 100644 index 000000000..b67ec66ea --- /dev/null +++ b/src/NzbDrone.Core/Datastore/PostgresOptions.cs @@ -0,0 +1,26 @@ +using Microsoft.Extensions.Configuration; + +namespace NzbDrone.Core.Datastore +{ + public class PostgresOptions + { + public string Host { get; set; } + public int Port { get; set; } + public string User { get; set; } + public string Password { get; set; } + public string MainDb { get; set; } + public string LogDb { get; set; } + + public static PostgresOptions GetOptions() + { + var config = new ConfigurationBuilder() + .AddEnvironmentVariables() + .Build(); + + var postgresOptions = new PostgresOptions(); + config.GetSection("Prowlarr:Postgres").Bind(postgresOptions); + + return postgresOptions; + } + } +} diff --git a/src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs b/src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs index bc4c39490..f3e31e179 100644 --- a/src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs +++ b/src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs @@ -313,7 +313,20 @@ namespace NzbDrone.Core.Datastore _sb.Append(" = ANY ("); - Visit(list); + // hardcode the integer list if it exists to bypass parameter limit + if (item.Type == typeof(int) && TryGetRightValue(list, out var value)) + { + var items = (IEnumerable<int>)value; + _sb.Append("('{"); + _sb.Append(string.Join(", ", items)); + _sb.Append("}')"); + + _gotConcreteValue = true; + } + else + { + Visit(list); + } _sb.Append("))"); } @@ -324,7 +337,7 @@ namespace NzbDrone.Core.Datastore Visit(body.Object); - _sb.Append(" LIKE '%' || "); + _sb.Append(" ILIKE '%' || "); Visit(body.Arguments[0]); @@ -337,7 +350,7 @@ namespace NzbDrone.Core.Datastore Visit(body.Object); - _sb.Append(" LIKE "); + _sb.Append(" ILIKE "); Visit(body.Arguments[0]); @@ -350,7 +363,7 @@ namespace NzbDrone.Core.Datastore Visit(body.Object); - _sb.Append(" LIKE '%' || "); + _sb.Append(" ILIKE '%' || "); Visit(body.Arguments[0]); diff --git a/src/NzbDrone.Host.Test/ContainerFixture.cs b/src/NzbDrone.Host.Test/ContainerFixture.cs index 30774afbd..4f61aa877 100644 --- a/src/NzbDrone.Host.Test/ContainerFixture.cs +++ b/src/NzbDrone.Host.Test/ContainerFixture.cs @@ -5,13 +5,16 @@ using DryIoc.Microsoft.DependencyInjection; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using NzbDrone.Common; using NzbDrone.Common.Composition.Extensions; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Instrumentation.Extensions; +using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore.Extensions; +using NzbDrone.Core.Download; using NzbDrone.Core.Indexers; using NzbDrone.Core.Jobs; using NzbDrone.Core.Lifecycle; @@ -43,6 +46,7 @@ namespace NzbDrone.App.Test // dummy lifetime and broadcaster so tests resolve container.RegisterInstance<IHostLifetime>(new Mock<IHostLifetime>().Object); container.RegisterInstance<IBroadcastSignalRMessage>(new Mock<IBroadcastSignalRMessage>().Object); + container.RegisterInstance<IOptions<PostgresOptions>>(new Mock<IOptions<PostgresOptions>>().Object); _container = container.GetServiceProvider(); } @@ -53,6 +57,12 @@ namespace NzbDrone.App.Test _container.GetRequiredService<IEnumerable<IIndexer>>().Should().NotBeEmpty(); } + [Test] + public void should_be_able_to_resolve_downloadclients() + { + _container.GetRequiredService<IEnumerable<IDownloadClient>>().Should().NotBeEmpty(); + } + [Test] public void container_should_inject_itself() { diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index 42b434cef..d4ab88f39 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -9,8 +9,11 @@ using System.Security.Cryptography.X509Certificates; using System.Text; using DryIoc; using DryIoc.Microsoft.DependencyInjection; +using FluentMigrator.Runner.Processors.Postgres; +using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting.WindowsServices; using NLog; @@ -23,6 +26,8 @@ using NzbDrone.Common.Instrumentation; using NzbDrone.Common.Instrumentation.Extensions; using NzbDrone.Core.Configuration; using NzbDrone.Core.Datastore.Extensions; +using NzbDrone.Host; +using PostgresOptions = NzbDrone.Core.Datastore.PostgresOptions; namespace NzbDrone.Host { @@ -52,6 +57,7 @@ namespace NzbDrone.Host Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); var appMode = GetApplicationMode(startupContext); + var config = GetConfiguration(startupContext); switch (appMode) { @@ -80,12 +86,22 @@ namespace NzbDrone.Host // Utility mode default: { - new Container(rules => rules.WithNzbDroneRules()) - .AutoAddServices(ASSEMBLIES) - .AddNzbDroneLogger() - .AddStartupContext(startupContext) - .Resolve<UtilityModeRouter>() - .Route(appMode); + new HostBuilder() + .UseServiceProviderFactory(new DryIocServiceProviderFactory(new Container(rules => rules.WithNzbDroneRules()))) + .ConfigureContainer<IContainer>(c => + { + c.AutoAddServices(Bootstrap.ASSEMBLIES) + .AddNzbDroneLogger() + .AddDatabase() + .AddStartupContext(startupContext) + .Resolve<UtilityModeRouter>() + .Route(appMode); + }) + .ConfigureServices(services => + { + services.Configure<PostgresOptions>(config.GetSection("Prowlarr:Postgres")); + }).Build(); + break; } } @@ -135,6 +151,10 @@ namespace NzbDrone.Host .AddDatabase() .AddStartupContext(context); }) + .ConfigureServices(services => + { + services.Configure<PostgresOptions>(config.GetSection("Prowlarr:Postgres")); + }) .ConfigureWebHost(builder => { builder.UseConfiguration(config); @@ -205,6 +225,7 @@ namespace NzbDrone.Host return new ConfigurationBuilder() .AddXmlFile(appFolder.GetConfigPath(), optional: true, reloadOnChange: false) .AddInMemoryCollection(new List<KeyValuePair<string, string>> { new ("dataProtectionFolder", appFolder.GetDataProtectionPath()) }) + .AddEnvironmentVariables() .Build(); } diff --git a/src/NzbDrone.Integration.Test/IntegrationTest.cs b/src/NzbDrone.Integration.Test/IntegrationTest.cs index 3b64124b8..609117a19 100644 --- a/src/NzbDrone.Integration.Test/IntegrationTest.cs +++ b/src/NzbDrone.Integration.Test/IntegrationTest.cs @@ -1,9 +1,15 @@ +using System.Collections.Generic; using System.Threading; +using Microsoft.Extensions.Configuration; using NLog; +using Npgsql; using NUnit.Framework; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Datastore; +using NzbDrone.Core.Datastore.Migration.Framework; using NzbDrone.Core.Indexers.FileList; using NzbDrone.Test.Common; +using NzbDrone.Test.Common.Datastore; using Prowlarr.Http.ClientSchema; namespace NzbDrone.Integration.Test @@ -19,6 +25,8 @@ namespace NzbDrone.Integration.Test protected int Port { get; private set; } + protected PostgresOptions PostgresOptions { get; set; } = new (); + protected override string RootUrl => $"http://localhost:{Port}/"; protected override string ApiKey => _runner.ApiKey; @@ -27,7 +35,14 @@ namespace NzbDrone.Integration.Test { Port = Interlocked.Increment(ref StaticPort); - _runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), Port); + PostgresOptions = PostgresDatabase.GetTestOptions(); + + if (PostgresOptions?.Host != null) + { + CreatePostgresDb(PostgresOptions); + } + + _runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), PostgresOptions, Port); _runner.Kill(); _runner.Start(); @@ -56,6 +71,22 @@ namespace NzbDrone.Integration.Test protected override void StopTestTarget() { _runner.Kill(); + if (PostgresOptions?.Host != null) + { + DropPostgresDb(PostgresOptions); + } + } + + private static void CreatePostgresDb(PostgresOptions options) + { + PostgresDatabase.Create(options, MigrationType.Main); + PostgresDatabase.Create(options, MigrationType.Log); + } + + private static void DropPostgresDb(PostgresOptions options) + { + PostgresDatabase.Drop(options, MigrationType.Main); + PostgresDatabase.Drop(options, MigrationType.Log); } } } diff --git a/src/NzbDrone.Mono.Test/DiskProviderTests/SymlinkResolverFixture.cs b/src/NzbDrone.Mono.Test/DiskProviderTests/SymlinkResolverFixture.cs index ac7fadd60..8b4bf2aee 100644 --- a/src/NzbDrone.Mono.Test/DiskProviderTests/SymlinkResolverFixture.cs +++ b/src/NzbDrone.Mono.Test/DiskProviderTests/SymlinkResolverFixture.cs @@ -8,14 +8,9 @@ using NzbDrone.Test.Common; namespace NzbDrone.Mono.Test.DiskProviderTests { [TestFixture] - [Platform("Mono")] + [Platform(Exclude = "Win")] public class SymbolicLinkResolverFixture : TestBase<SymbolicLinkResolver> { - public SymbolicLinkResolverFixture() - { - MonoOnly(); - } - [Test] public void should_follow_nested_symlinks() { diff --git a/src/NzbDrone.Test.Common/Datastore/PostgresDatabase.cs b/src/NzbDrone.Test.Common/Datastore/PostgresDatabase.cs new file mode 100644 index 000000000..940334ca2 --- /dev/null +++ b/src/NzbDrone.Test.Common/Datastore/PostgresDatabase.cs @@ -0,0 +1,69 @@ +using System; +using Npgsql; +using NzbDrone.Core.Datastore; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Test.Common.Datastore +{ + public static class PostgresDatabase + { + public static PostgresOptions GetTestOptions() + { + var options = PostgresOptions.GetOptions(); + + var uid = TestBase.GetUID(); + options.MainDb = uid + "_main"; + options.LogDb = uid + "_log"; + + return options; + } + + public static void Create(PostgresOptions options, MigrationType migrationType) + { + var db = GetDatabaseName(options, migrationType); + var connectionString = GetConnectionString(options); + using var conn = new NpgsqlConnection(connectionString); + conn.Open(); + + using var cmd = conn.CreateCommand(); + cmd.CommandText = $"CREATE DATABASE \"{db}\" WITH OWNER = {options.User} ENCODING = 'UTF8' CONNECTION LIMIT = -1;"; + cmd.ExecuteNonQuery(); + } + + public static void Drop(PostgresOptions options, MigrationType migrationType) + { + var db = GetDatabaseName(options, migrationType); + var connectionString = GetConnectionString(options); + using var conn = new NpgsqlConnection(connectionString); + conn.Open(); + + using var cmd = conn.CreateCommand(); + cmd.CommandText = $"DROP DATABASE \"{db}\" WITH (FORCE);"; + cmd.ExecuteNonQuery(); + } + + private static string GetConnectionString(PostgresOptions options) + { + var builder = new NpgsqlConnectionStringBuilder() + { + Host = options.Host, + Port = options.Port, + Username = options.User, + Password = options.Password, + Enlist = false + }; + + return builder.ConnectionString; + } + + private static string GetDatabaseName(PostgresOptions options, MigrationType migrationType) + { + return migrationType switch + { + MigrationType.Main => options.MainDb, + MigrationType.Log => options.LogDb, + _ => throw new NotImplementedException("Unknown migration type") + }; + } + } +} diff --git a/src/NzbDrone.Test.Common/Datastore/SqliteDatabase.cs b/src/NzbDrone.Test.Common/Datastore/SqliteDatabase.cs new file mode 100644 index 000000000..151e245fc --- /dev/null +++ b/src/NzbDrone.Test.Common/Datastore/SqliteDatabase.cs @@ -0,0 +1,14 @@ +using System.IO; +using NUnit.Framework; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Test.Common.Datastore +{ + public static class SqliteDatabase + { + public static string GetCachedDb(MigrationType type) + { + return Path.Combine(TestContext.CurrentContext.TestDirectory, $"cached_{type}.db"); + } + } +} diff --git a/src/NzbDrone.Test.Common/NzbDroneRunner.cs b/src/NzbDrone.Test.Common/NzbDroneRunner.cs index 8ea3dd5ce..b4c97847c 100644 --- a/src/NzbDrone.Test.Common/NzbDroneRunner.cs +++ b/src/NzbDrone.Test.Common/NzbDroneRunner.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Specialized; using System.Diagnostics; using System.IO; using System.Linq; @@ -9,7 +10,9 @@ using NUnit.Framework; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; using NzbDrone.Common.Processes; +using NzbDrone.Common.Serializer; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Datastore; using RestSharp; namespace NzbDrone.Test.Common @@ -22,13 +25,15 @@ namespace NzbDrone.Test.Common public string AppData { get; private set; } public string ApiKey { get; private set; } + public PostgresOptions PostgresOptions { get; private set; } public int Port { get; private set; } - public NzbDroneRunner(Logger logger, int port = 9696) + public NzbDroneRunner(Logger logger, PostgresOptions postgresOptions, int port = 9696) { _processProvider = new ProcessProvider(logger); _restClient = new RestClient($"http://localhost:{port}/api/v1"); + PostgresOptions = postgresOptions; Port = port; } @@ -133,9 +138,23 @@ namespace NzbDrone.Test.Common private void Start(string outputProwlarrConsoleExe) { + StringDictionary envVars = new (); + if (PostgresOptions?.Host != null) + { + envVars.Add("Prowlarr__Postgres__Host", PostgresOptions.Host); + envVars.Add("Prowlarr__Postgres__Port", PostgresOptions.Port.ToString()); + envVars.Add("Prowlarr__Postgres__User", PostgresOptions.User); + envVars.Add("Prowlarr__Postgres__Password", PostgresOptions.Password); + envVars.Add("Prowlarr__Postgres__MainDb", PostgresOptions.MainDb); + envVars.Add("Prowlarr__Postgres__LogDb", PostgresOptions.LogDb); + + TestContext.Progress.WriteLine("Using env vars:\n{0}", envVars.ToJson()); + } + TestContext.Progress.WriteLine("Starting instance from {0} on port {1}", outputProwlarrConsoleExe, Port); + var args = "-nobrowser -nosingleinstancecheck -data=\"" + AppData + "\""; - _nzbDroneProcess = _processProvider.Start(outputProwlarrConsoleExe, args, null, OnOutputDataReceived, OnOutputDataReceived); + _nzbDroneProcess = _processProvider.Start(outputProwlarrConsoleExe, args, envVars, OnOutputDataReceived, OnOutputDataReceived); } private void OnOutputDataReceived(string data) diff --git a/src/NzbDrone.Test.Common/TestBase.cs b/src/NzbDrone.Test.Common/TestBase.cs index fa25c039f..4ca32b7c7 100644 --- a/src/NzbDrone.Test.Common/TestBase.cs +++ b/src/NzbDrone.Test.Common/TestBase.cs @@ -166,14 +166,6 @@ namespace NzbDrone.Test.Common } } - protected void MonoOnly() - { - if (!PlatformInfo.IsMono) - { - throw new IgnoreException("mono specific test"); - } - } - protected void NotBsd() { if (OsInfo.Os == Os.Bsd) diff --git a/src/postgres.runsettings b/src/postgres.runsettings new file mode 100644 index 000000000..fa0a59c96 --- /dev/null +++ b/src/postgres.runsettings @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<RunSettings> + <RunConfiguration> + <EnvironmentVariables> + <Prowlarr__Postgres__Host>192.168.100.5</Prowlarr__Postgres__Host> + <Prowlarr__Postgres__Port>5432</Prowlarr__Postgres__Port> + <Prowlarr__Postgres__User>abc</Prowlarr__Postgres__User> + <Prowlarr__Postgres__Password>abc</Prowlarr__Postgres__Password> + </EnvironmentVariables> + </RunConfiguration> +</RunSettings> From 473405ceebd4763a0eff84615120bc25a6aa86e6 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 2 Jul 2022 18:40:00 -0500 Subject: [PATCH 0515/2320] Update file and folder handling methods from Radarr (#1051) * Update file/folder handling methods from Radarr * fixup! --- .../DiskTests/DiskProviderFixtureBase.cs | 10 + .../DiskTests/DiskTransferServiceFixture.cs | 91 +++++++++ .../DiskTests/FreeSpaceFixtureBase.cs | 37 ---- src/NzbDrone.Common/Disk/DiskProviderBase.cs | 29 ++- .../Disk/DiskTransferService.cs | 63 +++++- src/NzbDrone.Common/Disk/IDiskProvider.cs | 5 +- src/NzbDrone.Common/Disk/LongPathSupport.cs | 64 ++++++ .../UpdateTests/UpdateServiceFixture.cs | 21 +- .../Update/InstallUpdateService.cs | 31 +-- ...odValidator.cs => FolderChmodValidator.cs} | 6 +- .../DiskProviderTests/DiskProviderFixture.cs | 183 ++++++++++++++---- .../DiskProviderTests/FreeSpaceFixture.cs | 17 +- src/NzbDrone.Mono/Disk/DiskProvider.cs | 93 ++++----- src/NzbDrone.Mono/Disk/FindDriveType.cs | 1 + .../UpdateEngine/InstallUpdateService.cs | 10 +- .../DiskProviderTests/FreeSpaceFixture.cs | 29 ++- src/NzbDrone.Windows/Disk/DiskProvider.cs | 6 +- 17 files changed, 534 insertions(+), 162 deletions(-) rename src/NzbDrone.Core/Validation/{FileChmodValidator.cs => FolderChmodValidator.cs} (69%) diff --git a/src/NzbDrone.Common.Test/DiskTests/DiskProviderFixtureBase.cs b/src/NzbDrone.Common.Test/DiskTests/DiskProviderFixtureBase.cs index 8b9e72b4f..63c991a29 100644 --- a/src/NzbDrone.Common.Test/DiskTests/DiskProviderFixtureBase.cs +++ b/src/NzbDrone.Common.Test/DiskTests/DiskProviderFixtureBase.cs @@ -10,6 +10,16 @@ namespace NzbDrone.Common.Test.DiskTests public abstract class DiskProviderFixtureBase<TSubject> : TestBase<TSubject> where TSubject : class, IDiskProvider { + [Test] + public void writealltext_should_truncate_existing() + { + var file = GetTempFilePath(); + + Subject.WriteAllText(file, "A pretty long string"); + Subject.WriteAllText(file, "A short string"); + Subject.ReadAllText(file).Should().Be("A short string"); + } + [Test] [Retry(5)] public void directory_exist_should_be_able_to_find_existing_folder() diff --git a/src/NzbDrone.Common.Test/DiskTests/DiskTransferServiceFixture.cs b/src/NzbDrone.Common.Test/DiskTests/DiskTransferServiceFixture.cs index 1672fe0d4..9e6799d43 100644 --- a/src/NzbDrone.Common.Test/DiskTests/DiskTransferServiceFixture.cs +++ b/src/NzbDrone.Common.Test/DiskTests/DiskTransferServiceFixture.cs @@ -402,6 +402,40 @@ namespace NzbDrone.Common.Test.DiskTests VerifyCopyFolder(source.FullName, destination.FullName); } + [Test] + public void CopyFolder_should_detect_caseinsensitive_parents() + { + WindowsOnly(); + + WithRealDiskProvider(); + + var original = GetFilledTempFolder(); + var root = new DirectoryInfo(GetTempFilePath()); + var source = new DirectoryInfo(root.FullName + "A/series"); + var destination = new DirectoryInfo(root.FullName + "a/series"); + + Subject.TransferFolder(original.FullName, source.FullName, TransferMode.Copy); + + Assert.Throws<IOException>(() => Subject.TransferFolder(source.FullName, destination.FullName, TransferMode.Copy)); + } + + [Test] + public void CopyFolder_should_detect_caseinsensitive_folder() + { + WindowsOnly(); + + WithRealDiskProvider(); + + var original = GetFilledTempFolder(); + var root = new DirectoryInfo(GetTempFilePath()); + var source = new DirectoryInfo(root.FullName + "A/series"); + var destination = new DirectoryInfo(root.FullName + "A/Series"); + + Subject.TransferFolder(original.FullName, source.FullName, TransferMode.Copy); + + Assert.Throws<IOException>(() => Subject.TransferFolder(source.FullName, destination.FullName, TransferMode.Copy)); + } + [Test] public void CopyFolder_should_ignore_nfs_temp_file() { @@ -451,6 +485,42 @@ namespace NzbDrone.Common.Test.DiskTests VerifyMoveFolder(original.FullName, source.FullName, destination.FullName); } + [Test] + public void MoveFolder_should_detect_caseinsensitive_parents() + { + WindowsOnly(); + + WithRealDiskProvider(); + + var original = GetFilledTempFolder(); + var root = new DirectoryInfo(GetTempFilePath()); + var source = new DirectoryInfo(root.FullName + "A/series"); + var destination = new DirectoryInfo(root.FullName + "a/series"); + + Subject.TransferFolder(original.FullName, source.FullName, TransferMode.Copy); + + Assert.Throws<IOException>(() => Subject.TransferFolder(source.FullName, destination.FullName, TransferMode.Move)); + } + + [Test] + public void MoveFolder_should_rename_caseinsensitive_folder() + { + WindowsOnly(); + + WithRealDiskProvider(); + + var original = GetFilledTempFolder(); + var root = new DirectoryInfo(GetTempFilePath()); + var source = new DirectoryInfo(root.FullName + "A/series"); + var destination = new DirectoryInfo(root.FullName + "A/Series"); + + Subject.TransferFolder(original.FullName, source.FullName, TransferMode.Copy); + + Subject.TransferFolder(source.FullName, destination.FullName, TransferMode.Move); + + source.FullName.GetActualCasing().Should().Be(destination.FullName); + } + [Test] public void should_throw_if_destination_is_readonly() { @@ -553,6 +623,23 @@ namespace NzbDrone.Common.Test.DiskTests VerifyCopyFolder(original.FullName, destination.FullName); } + [Test] + public void MirrorFolder_should_handle_trailing_slash() + { + WithRealDiskProvider(); + + var original = GetFilledTempFolder(); + var source = new DirectoryInfo(GetTempFilePath()); + var destination = new DirectoryInfo(GetTempFilePath()); + + Subject.TransferFolder(original.FullName, source.FullName, TransferMode.Copy); + + var count = Subject.MirrorFolder(source.FullName + Path.DirectorySeparatorChar, destination.FullName); + + count.Should().Equals(3); + VerifyCopyFolder(original.FullName, destination.FullName); + } + [Test] public void TransferFolder_should_use_movefolder_if_on_same_mount() { @@ -752,6 +839,10 @@ namespace NzbDrone.Common.Test.DiskTests .Setup(v => v.CreateFolder(It.IsAny<string>())) .Callback<string>(v => Directory.CreateDirectory(v)); + Mocker.GetMock<IDiskProvider>() + .Setup(v => v.MoveFolder(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>())) + .Callback<string, string, bool>((v, r, b) => Directory.Move(v, r)); + Mocker.GetMock<IDiskProvider>() .Setup(v => v.DeleteFolder(It.IsAny<string>(), It.IsAny<bool>())) .Callback<string, bool>((v, r) => Directory.Delete(v, r)); diff --git a/src/NzbDrone.Common.Test/DiskTests/FreeSpaceFixtureBase.cs b/src/NzbDrone.Common.Test/DiskTests/FreeSpaceFixtureBase.cs index 63d973946..220f4734d 100644 --- a/src/NzbDrone.Common.Test/DiskTests/FreeSpaceFixtureBase.cs +++ b/src/NzbDrone.Common.Test/DiskTests/FreeSpaceFixtureBase.cs @@ -28,14 +28,6 @@ namespace NzbDrone.Common.Test.DiskTests Subject.GetAvailableSpace(Path.Combine(path, "invalidFolder")).Should().NotBe(0); } - [Ignore("Docker")] - [Test] - public void should_be_able_to_check_space_on_ramdrive() - { - PosixOnly(); - Subject.GetAvailableSpace("/run/").Should().NotBe(0); - } - [Ignore("Docker")] [Test] public void should_return_free_disk_space() @@ -44,35 +36,6 @@ namespace NzbDrone.Common.Test.DiskTests result.Should().BeGreaterThan(0); } - [Test] - public void should_be_able_to_get_space_on_unc() - { - WindowsOnly(); - - var result = Subject.GetAvailableSpace(@"\\localhost\c$\Windows"); - result.Should().BeGreaterThan(0); - } - - [Test] - public void should_throw_if_drive_doesnt_exist() - { - WindowsOnly(); - - // Find a drive that doesn't exist. - for (char driveletter = 'Z'; driveletter > 'D'; driveletter--) - { - if (new DriveInfo(driveletter.ToString()).IsReady) - { - continue; - } - - Assert.Throws<DirectoryNotFoundException>(() => Subject.GetAvailableSpace(driveletter + @":\NOT_A_REAL_PATH\DOES_NOT_EXIST".AsOsAgnostic())); - return; - } - - Assert.Inconclusive("No drive available for testing."); - } - [Ignore("Docker")] [Test] public void should_be_able_to_get_space_on_folder_that_doesnt_exist() diff --git a/src/NzbDrone.Common/Disk/DiskProviderBase.cs b/src/NzbDrone.Common/Disk/DiskProviderBase.cs index 084e515c2..9aa5ebdec 100644 --- a/src/NzbDrone.Common/Disk/DiskProviderBase.cs +++ b/src/NzbDrone.Common/Disk/DiskProviderBase.cs @@ -30,7 +30,8 @@ namespace NzbDrone.Common.Disk public abstract long? GetAvailableSpace(string path); public abstract void InheritFolderPermissions(string filename); public abstract void SetEveryonePermissions(string filename); - public abstract void SetPermissions(string path, string mask); + public abstract void SetFilePermissions(string path, string mask, string group); + public abstract void SetPermissions(string path, string mask, string group); public abstract void CopyPermissions(string sourcePath, string targetPath); public abstract long? GetTotalSize(string path); @@ -130,7 +131,7 @@ namespace NzbDrone.Common.Disk { var testPath = Path.Combine(path, "prowlarr_write_test.txt"); var testContent = string.Format("This file was created to verify if '{0}' is writable. It should've been automatically deleted. Feel free to delete it.", path); - File.WriteAllText(testPath, testContent); + WriteAllText(testPath, testContent); File.Delete(testPath); return true; } @@ -258,17 +259,6 @@ namespace NzbDrone.Common.Disk Ensure.That(source, () => source).IsValidPath(); Ensure.That(destination, () => destination).IsValidPath(); - if (source.PathEquals(destination)) - { - throw new IOException(string.Format("Source and destination can't be the same {0}", source)); - } - - if (FolderExists(destination) && overwrite) - { - DeleteFolder(destination, true); - } - - RemoveReadOnlyFolder(source); Directory.Move(source, destination); } @@ -310,7 +300,16 @@ namespace NzbDrone.Common.Disk { Ensure.That(filename, () => filename).IsValidPath(); RemoveReadOnly(filename); - File.WriteAllText(filename, contents); + + // File.WriteAllText is broken on net core when writing to some CIFS mounts + // This workaround from https://github.com/dotnet/runtime/issues/42790#issuecomment-700362617 + using (var fs = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None)) + { + using (var writer = new StreamWriter(fs)) + { + writer.Write(contents); + } + } } public void FolderSetLastWriteTime(string path, DateTime dateTime) @@ -550,7 +549,7 @@ namespace NzbDrone.Common.Disk } } - public virtual bool IsValidFilePermissionMask(string mask) + public virtual bool IsValidFolderPermissionMask(string mask) { throw new NotSupportedException(); } diff --git a/src/NzbDrone.Common/Disk/DiskTransferService.cs b/src/NzbDrone.Common/Disk/DiskTransferService.cs index 5d7e7d23a..44d28a9df 100644 --- a/src/NzbDrone.Common/Disk/DiskTransferService.cs +++ b/src/NzbDrone.Common/Disk/DiskTransferService.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Threading; using NLog; using NzbDrone.Common.EnsureThat; -using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; namespace NzbDrone.Common.Disk @@ -27,11 +26,56 @@ namespace NzbDrone.Common.Disk _logger = logger; } + private string ResolveRealParentPath(string path) + { + var parentPath = path.GetParentPath(); + if (!_diskProvider.FolderExists(parentPath)) + { + return path; + } + + var realParentPath = parentPath.GetActualCasing(); + + var partialChildPath = path.Substring(parentPath.Length); + + return realParentPath + partialChildPath; + } + public TransferMode TransferFolder(string sourcePath, string targetPath, TransferMode mode) { Ensure.That(sourcePath, () => sourcePath).IsValidPath(); Ensure.That(targetPath, () => targetPath).IsValidPath(); + sourcePath = ResolveRealParentPath(sourcePath); + targetPath = ResolveRealParentPath(targetPath); + + _logger.Debug("{0} Directory [{1}] > [{2}]", mode, sourcePath, targetPath); + + if (sourcePath == targetPath) + { + throw new IOException(string.Format("Source and destination can't be the same {0}", sourcePath)); + } + + if (mode == TransferMode.Move && sourcePath.PathEquals(targetPath, StringComparison.InvariantCultureIgnoreCase) && _diskProvider.FolderExists(targetPath)) + { + // Move folder out of the way to allow case-insensitive renames + var tempPath = sourcePath + ".backup~"; + _logger.Trace("Rename Intermediate Directory [{0}] > [{1}]", sourcePath, tempPath); + _diskProvider.MoveFolder(sourcePath, tempPath); + + if (!_diskProvider.FolderExists(targetPath)) + { + _logger.Trace("Rename Intermediate Directory [{0}] > [{1}]", tempPath, targetPath); + _logger.Debug("Rename Directory [{0}] > [{1}]", sourcePath, targetPath); + _diskProvider.MoveFolder(tempPath, targetPath); + return mode; + } + + // There were two separate folders, revert the intermediate rename and let the recursion deal with it + _logger.Trace("Rename Intermediate Directory [{0}] > [{1}]", tempPath, sourcePath); + _diskProvider.MoveFolder(tempPath, sourcePath); + } + if (mode == TransferMode.Move && !_diskProvider.FolderExists(targetPath)) { var sourceMount = _diskProvider.GetMount(sourcePath); @@ -40,7 +84,7 @@ namespace NzbDrone.Common.Disk // If we're on the same mount, do a simple folder move. if (sourceMount != null && targetMount != null && sourceMount.RootDirectory == targetMount.RootDirectory) { - _logger.Debug("Move Directory [{0}] > [{1}]", sourcePath, targetPath); + _logger.Debug("Rename Directory [{0}] > [{1}]", sourcePath, targetPath); _diskProvider.MoveFolder(sourcePath, targetPath); return mode; } @@ -79,6 +123,13 @@ namespace NzbDrone.Common.Disk if (mode.HasFlag(TransferMode.Move)) { + var totalSize = _diskProvider.GetFileInfos(sourcePath).Sum(v => v.Length); + + if (totalSize > (100 * 1024L * 1024L)) + { + throw new IOException($"Large files still exist in {sourcePath} after folder move, not deleting source folder"); + } + _diskProvider.DeleteFolder(sourcePath, true); } @@ -92,7 +143,10 @@ namespace NzbDrone.Common.Disk Ensure.That(sourcePath, () => sourcePath).IsValidPath(); Ensure.That(targetPath, () => targetPath).IsValidPath(); - _logger.Debug("Mirror [{0}] > [{1}]", sourcePath, targetPath); + sourcePath = ResolveRealParentPath(sourcePath); + targetPath = ResolveRealParentPath(targetPath); + + _logger.Debug("Mirror Folder [{0}] > [{1}]", sourcePath, targetPath); if (!_diskProvider.FolderExists(targetPath)) { @@ -204,6 +258,9 @@ namespace NzbDrone.Common.Disk Ensure.That(sourcePath, () => sourcePath).IsValidPath(); Ensure.That(targetPath, () => targetPath).IsValidPath(); + sourcePath = ResolveRealParentPath(sourcePath); + targetPath = ResolveRealParentPath(targetPath); + _logger.Debug("{0} [{1}] > [{2}]", mode, sourcePath, targetPath); var originalSize = _diskProvider.GetFileSize(sourcePath); diff --git a/src/NzbDrone.Common/Disk/IDiskProvider.cs b/src/NzbDrone.Common/Disk/IDiskProvider.cs index cb262504a..4f1cad811 100644 --- a/src/NzbDrone.Common/Disk/IDiskProvider.cs +++ b/src/NzbDrone.Common/Disk/IDiskProvider.cs @@ -11,7 +11,8 @@ namespace NzbDrone.Common.Disk long? GetAvailableSpace(string path); void InheritFolderPermissions(string filename); void SetEveryonePermissions(string filename); - void SetPermissions(string path, string mask); + void SetFilePermissions(string path, string mask, string group); + void SetPermissions(string path, string mask, string group); void CopyPermissions(string sourcePath, string targetPath); long? GetTotalSize(string path); DateTime FolderGetCreationTime(string path); @@ -56,6 +57,6 @@ namespace NzbDrone.Common.Disk List<FileInfo> GetFileInfos(string path, SearchOption searchOption = SearchOption.TopDirectoryOnly); void RemoveEmptySubfolders(string path); void SaveStream(Stream stream, string path); - bool IsValidFilePermissionMask(string mask); + bool IsValidFolderPermissionMask(string mask); } } diff --git a/src/NzbDrone.Common/Disk/LongPathSupport.cs b/src/NzbDrone.Common/Disk/LongPathSupport.cs index ef4bd3f7c..8d10f78d6 100644 --- a/src/NzbDrone.Common/Disk/LongPathSupport.cs +++ b/src/NzbDrone.Common/Disk/LongPathSupport.cs @@ -1,15 +1,79 @@ using System; +using System.IO; +using NzbDrone.Common.EnvironmentInfo; namespace NzbDrone.Common.Disk { public static class LongPathSupport { + private static int MAX_PATH; + private static int MAX_NAME; + public static void Enable() { // Mono has an issue with enabling long path support via app.config. // This works for both mono and .net on Windows. AppContext.SetSwitch("Switch.System.IO.UseLegacyPathHandling", false); AppContext.SetSwitch("Switch.System.IO.BlockLongPaths", false); + + DetectLongPathLimits(); + } + + private static void DetectLongPathLimits() + { + if (!int.TryParse(Environment.GetEnvironmentVariable("MAX_PATH"), out MAX_PATH)) + { + if (OsInfo.IsLinux) + { + MAX_PATH = 4096; + } + else + { + try + { + // Windows paths can be up to 32,767 characters long, but each component of the path must be less than 255. + // If the OS does not have Long Path enabled, then the following will throw an exception + // ref: https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation + Path.GetDirectoryName($@"C:\{new string('a', 254)}\{new string('a', 254)}"); + MAX_PATH = 4096; + } + catch + { + MAX_PATH = 260 - 1; + } + } + } + + if (!int.TryParse(Environment.GetEnvironmentVariable("MAX_NAME"), out MAX_NAME)) + { + MAX_NAME = 255; + } + } + + public static int MaxFilePathLength + { + get + { + if (MAX_PATH == 0) + { + DetectLongPathLimits(); + } + + return MAX_PATH; + } + } + + public static int MaxFileNameLength + { + get + { + if (MAX_NAME == 0) + { + DetectLongPathLimits(); + } + + return MAX_NAME; + } } } } diff --git a/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs b/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs index 56b78ade5..70fd2fbca 100644 --- a/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs +++ b/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs @@ -68,6 +68,10 @@ namespace NzbDrone.Core.Test.UpdateTests .Setup(c => c.FolderWritable(It.IsAny<string>())) .Returns(true); + Mocker.GetMock<IDiskProvider>() + .Setup(v => v.FileExists(It.Is<string>(s => s.EndsWith("Prowlarr.Update.exe")))) + .Returns(true); + _sandboxFolder = Mocker.GetMock<IAppFolderInfo>().Object.GetUpdateSandboxFolder(); } @@ -149,7 +153,7 @@ namespace NzbDrone.Core.Test.UpdateTests } [Test] - public void should_start_update_client() + public void should_start_update_client_if_updater_exists() { Subject.Execute(new ApplicationUpdateCommand()); @@ -157,6 +161,21 @@ namespace NzbDrone.Core.Test.UpdateTests .Verify(c => c.Start(It.IsAny<string>(), It.Is<string>(s => s.StartsWith("12")), null, null, null), Times.Once()); } + [Test] + public void should_return_with_warning_if_updater_doesnt_exists() + { + Mocker.GetMock<IDiskProvider>() + .Setup(v => v.FileExists(It.Is<string>(s => s.EndsWith("Prowlarr.Update.exe")))) + .Returns(false); + + Subject.Execute(new ApplicationUpdateCommand()); + + Mocker.GetMock<IProcessProvider>() + .Verify(c => c.Start(It.IsAny<string>(), It.IsAny<string>(), null, null, null), Times.Never()); + + ExceptionVerification.ExpectedWarns(1); + } + [Test] public void should_return_without_error_or_warnings_when_no_updates_are_available() { diff --git a/src/NzbDrone.Core/Update/InstallUpdateService.cs b/src/NzbDrone.Core/Update/InstallUpdateService.cs index 1c0489798..c7b358861 100644 --- a/src/NzbDrone.Core/Update/InstallUpdateService.cs +++ b/src/NzbDrone.Core/Update/InstallUpdateService.cs @@ -146,16 +146,24 @@ namespace NzbDrone.Core.Update _logger.Info("Preparing client"); _diskTransferService.TransferFolder(_appFolderInfo.GetUpdateClientFolder(), updateSandboxFolder, TransferMode.Move); + var updateClientExePath = _appFolderInfo.GetUpdateClientExePath(updatePackage.Runtime); + + if (!_diskProvider.FileExists(updateClientExePath)) + { + _logger.Warn("Update client {0} does not exist, aborting update.", updateClientExePath); + return false; + } + // Set executable flag on update app if (OsInfo.IsOsx || (OsInfo.IsLinux && PlatformInfo.IsNetCore)) { - _diskProvider.SetPermissions(_appFolderInfo.GetUpdateClientExePath(updatePackage.Runtime), "0755"); + _diskProvider.SetFilePermissions(updateClientExePath, "755", null); } - _logger.Info("Starting update client {0}", _appFolderInfo.GetUpdateClientExePath(updatePackage.Runtime)); + _logger.Info("Starting update client {0}", updateClientExePath); _logger.ProgressInfo("Prowlarr will restart shortly."); - _processProvider.Start(_appFolderInfo.GetUpdateClientExePath(updatePackage.Runtime), GetUpdaterArgs(updateSandboxFolder)); + _processProvider.Start(updateClientExePath, GetUpdaterArgs(updateSandboxFolder)); return true; } @@ -298,14 +306,6 @@ namespace NzbDrone.Core.Update // Check if we have to do an application update on startup try { - // Don't do a prestartup update check unless BuiltIn update is enabled - if (_configFileProvider.UpdateAutomatically || - _configFileProvider.UpdateMechanism != UpdateMechanism.BuiltIn || - _deploymentInfoProvider.IsExternalUpdateMechanism) - { - return; - } - var updateMarker = Path.Combine(_appFolderInfo.AppDataFolder, "update_required"); if (!_diskProvider.FileExists(updateMarker)) { @@ -314,6 +314,15 @@ namespace NzbDrone.Core.Update _logger.Debug("Post-install update check requested"); + // Don't do a prestartup update check unless BuiltIn update is enabled + if (!_configFileProvider.UpdateAutomatically || + _configFileProvider.UpdateMechanism != UpdateMechanism.BuiltIn || + _deploymentInfoProvider.IsExternalUpdateMechanism) + { + _logger.Debug("Built-in updater disabled, skipping post-install update check"); + return; + } + var latestAvailable = _checkUpdateService.AvailableUpdate(); if (latestAvailable == null) { diff --git a/src/NzbDrone.Core/Validation/FileChmodValidator.cs b/src/NzbDrone.Core/Validation/FolderChmodValidator.cs similarity index 69% rename from src/NzbDrone.Core/Validation/FileChmodValidator.cs rename to src/NzbDrone.Core/Validation/FolderChmodValidator.cs index c9f0881a7..3e90bf9fa 100644 --- a/src/NzbDrone.Core/Validation/FileChmodValidator.cs +++ b/src/NzbDrone.Core/Validation/FolderChmodValidator.cs @@ -3,11 +3,11 @@ using NzbDrone.Common.Disk; namespace NzbDrone.Core.Validation { - public class FileChmodValidator : PropertyValidator + public class FolderChmodValidator : PropertyValidator { private readonly IDiskProvider _diskProvider; - public FileChmodValidator(IDiskProvider diskProvider) + public FolderChmodValidator(IDiskProvider diskProvider) : base("Must contain a valid Unix permissions octal") { _diskProvider = diskProvider; @@ -20,7 +20,7 @@ namespace NzbDrone.Core.Validation return false; } - return _diskProvider.IsValidFilePermissionMask(context.PropertyValue.ToString()); + return _diskProvider.IsValidFolderPermissionMask(context.PropertyValue.ToString()); } } } diff --git a/src/NzbDrone.Mono.Test/DiskProviderTests/DiskProviderFixture.cs b/src/NzbDrone.Mono.Test/DiskProviderTests/DiskProviderFixture.cs index 5ca5e831e..cb804ecf4 100644 --- a/src/NzbDrone.Mono.Test/DiskProviderTests/DiskProviderFixture.cs +++ b/src/NzbDrone.Mono.Test/DiskProviderTests/DiskProviderFixture.cs @@ -18,11 +18,32 @@ namespace NzbDrone.Mono.Test.DiskProviderTests [Platform(Exclude = "Win")] public class DiskProviderFixture : DiskProviderFixtureBase<DiskProvider> { + private string _tempPath; + public DiskProviderFixture() { PosixOnly(); } + [TearDown] + public void MonoDiskProviderFixtureTearDown() + { + // Give ourselves back write permissions so we can delete it + if (_tempPath != null) + { + if (Directory.Exists(_tempPath)) + { + Syscall.chmod(_tempPath, FilePermissions.S_IRWXU); + } + else if (File.Exists(_tempPath)) + { + Syscall.chmod(_tempPath, FilePermissions.S_IRUSR | FilePermissions.S_IWUSR); + } + + _tempPath = null; + } + } + protected override void SetWritePermissions(string path, bool writable) { if (Environment.UserName == "root") @@ -30,16 +51,41 @@ namespace NzbDrone.Mono.Test.DiskProviderTests Assert.Inconclusive("Need non-root user to test write permissions."); } + SetWritePermissionsInternal(path, writable, false); + } + + protected void SetWritePermissionsInternal(string path, bool writable, bool setgid) + { // Remove Write permissions, we're still owner so we can clean it up, but we'll have to do that explicitly. - var entry = UnixFileSystemInfo.GetFileSystemEntry(path); + Stat stat; + Syscall.stat(path, out stat); + FilePermissions mode = stat.st_mode; if (writable) { - entry.FileAccessPermissions |= FileAccessPermissions.UserWrite | FileAccessPermissions.GroupWrite | FileAccessPermissions.OtherWrite; + mode |= FilePermissions.S_IWUSR | FilePermissions.S_IWGRP | FilePermissions.S_IWOTH; } else { - entry.FileAccessPermissions &= ~(FileAccessPermissions.UserWrite | FileAccessPermissions.GroupWrite | FileAccessPermissions.OtherWrite); + mode &= ~(FilePermissions.S_IWUSR | FilePermissions.S_IWGRP | FilePermissions.S_IWOTH); + } + + if (setgid) + { + mode |= FilePermissions.S_ISGID; + } + else + { + mode &= ~FilePermissions.S_ISGID; + } + + if (stat.st_mode != mode) + { + if (Syscall.chmod(path, mode) < 0) + { + var error = Stdlib.GetLastError(); + throw new LinuxPermissionsException("Error setting group: " + error); + } } } @@ -165,24 +211,25 @@ namespace NzbDrone.Mono.Test.DiskProviderTests var tempFile = GetTempFilePath(); File.WriteAllText(tempFile, "File1"); - SetWritePermissions(tempFile, false); + SetWritePermissionsInternal(tempFile, false, false); + _tempPath = tempFile; // Verify test setup Syscall.stat(tempFile, out var fileStat); NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("0444"); - Subject.SetPermissions(tempFile, "644"); + Subject.SetPermissions(tempFile, "755", null); Syscall.stat(tempFile, out fileStat); NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("0644"); - Subject.SetPermissions(tempFile, "0644"); + Subject.SetPermissions(tempFile, "0755", null); Syscall.stat(tempFile, out fileStat); NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("0644"); if (OsInfo.Os != Os.Bsd) { // This is not allowed on BSD - Subject.SetPermissions(tempFile, "1664"); + Subject.SetPermissions(tempFile, "1775", null); Syscall.stat(tempFile, out fileStat); NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("1664"); } @@ -194,62 +241,118 @@ namespace NzbDrone.Mono.Test.DiskProviderTests var tempPath = GetTempFilePath(); Directory.CreateDirectory(tempPath); - SetWritePermissions(tempPath, false); + SetWritePermissionsInternal(tempPath, false, false); + _tempPath = tempPath; // Verify test setup Syscall.stat(tempPath, out var fileStat); NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("0555"); - Subject.SetPermissions(tempPath, "644"); + Subject.SetPermissions(tempPath, "755", null); Syscall.stat(tempPath, out fileStat); NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("0755"); - Subject.SetPermissions(tempPath, "0644"); - Syscall.stat(tempPath, out fileStat); - NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("0755"); - - Subject.SetPermissions(tempPath, "1664"); - Syscall.stat(tempPath, out fileStat); - NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("1775"); - - Subject.SetPermissions(tempPath, "775"); + Subject.SetPermissions(tempPath, "775", null); Syscall.stat(tempPath, out fileStat); NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("0775"); - Subject.SetPermissions(tempPath, "640"); + Subject.SetPermissions(tempPath, "750", null); Syscall.stat(tempPath, out fileStat); NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("0750"); - Subject.SetPermissions(tempPath, "0041"); + Subject.SetPermissions(tempPath, "051", null); Syscall.stat(tempPath, out fileStat); NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("0051"); - - // reinstate sane permissions so fokder can be cleaned up - Subject.SetPermissions(tempPath, "775"); - Syscall.stat(tempPath, out fileStat); - NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("0775"); } [Test] - public void IsValidFilePermissionMask_should_return_correct() + public void should_preserve_setgid_on_set_folder_permissions() { - // Files may not be executable - Subject.IsValidFilePermissionMask("0777").Should().BeFalse(); - Subject.IsValidFilePermissionMask("0544").Should().BeFalse(); - Subject.IsValidFilePermissionMask("0454").Should().BeFalse(); - Subject.IsValidFilePermissionMask("0445").Should().BeFalse(); + var tempPath = GetTempFilePath(); + Directory.CreateDirectory(tempPath); + SetWritePermissionsInternal(tempPath, false, true); + _tempPath = tempPath; + + // Verify test setup + Syscall.stat(tempPath, out var fileStat); + NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("2555"); + + Subject.SetPermissions(tempPath, "755", null); + Syscall.stat(tempPath, out fileStat); + NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("2755"); + + Subject.SetPermissions(tempPath, "775", null); + Syscall.stat(tempPath, out fileStat); + NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("2775"); + + Subject.SetPermissions(tempPath, "750", null); + Syscall.stat(tempPath, out fileStat); + NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("2750"); + + Subject.SetPermissions(tempPath, "051", null); + Syscall.stat(tempPath, out fileStat); + NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("2051"); + } + + [Test] + public void should_clear_setgid_on_set_folder_permissions() + { + var tempPath = GetTempFilePath(); + + Directory.CreateDirectory(tempPath); + SetWritePermissionsInternal(tempPath, false, true); + _tempPath = tempPath; + + // Verify test setup + Syscall.stat(tempPath, out var fileStat); + NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("2555"); + + Subject.SetPermissions(tempPath, "0755", null); + Syscall.stat(tempPath, out fileStat); + NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("0755"); + + Subject.SetPermissions(tempPath, "0775", null); + Syscall.stat(tempPath, out fileStat); + NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("0775"); + + Subject.SetPermissions(tempPath, "0750", null); + Syscall.stat(tempPath, out fileStat); + NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("0750"); + + Subject.SetPermissions(tempPath, "0051", null); + Syscall.stat(tempPath, out fileStat); + NativeConvert.ToOctalPermissionString(fileStat.st_mode).Should().Be("0051"); + } + + [Test] + public void IsValidFolderPermissionMask_should_return_correct() + { // No special bits should be set - Subject.IsValidFilePermissionMask("1644").Should().BeFalse(); - Subject.IsValidFilePermissionMask("2644").Should().BeFalse(); - Subject.IsValidFilePermissionMask("4644").Should().BeFalse(); - Subject.IsValidFilePermissionMask("7644").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("1755").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("2755").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("4755").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("7755").Should().BeFalse(); - // Files should be readable and writeable by owner - Subject.IsValidFilePermissionMask("0400").Should().BeFalse(); - Subject.IsValidFilePermissionMask("0000").Should().BeFalse(); - Subject.IsValidFilePermissionMask("0200").Should().BeFalse(); - Subject.IsValidFilePermissionMask("0600").Should().BeTrue(); + // Folder should be readable and writeable by owner + Subject.IsValidFolderPermissionMask("000").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("100").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("200").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("300").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("400").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("500").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("600").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("700").Should().BeTrue(); + + // Folder should be readable and writeable by owner + Subject.IsValidFolderPermissionMask("0000").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("0100").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("0200").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("0300").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("0400").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("0500").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("0600").Should().BeFalse(); + Subject.IsValidFolderPermissionMask("0700").Should().BeTrue(); } } } diff --git a/src/NzbDrone.Mono.Test/DiskProviderTests/FreeSpaceFixture.cs b/src/NzbDrone.Mono.Test/DiskProviderTests/FreeSpaceFixture.cs index 619194cdd..b1c518c90 100644 --- a/src/NzbDrone.Mono.Test/DiskProviderTests/FreeSpaceFixture.cs +++ b/src/NzbDrone.Mono.Test/DiskProviderTests/FreeSpaceFixture.cs @@ -1,3 +1,5 @@ +using FluentAssertions; +using Moq; using NUnit.Framework; using NzbDrone.Common.Test.DiskTests; using NzbDrone.Mono.Disk; @@ -8,9 +10,20 @@ namespace NzbDrone.Mono.Test.DiskProviderTests [Platform(Exclude = "Win")] public class FreeSpaceFixture : FreeSpaceFixtureBase<DiskProvider> { - public FreeSpaceFixture() + [SetUp] + public void Setup() { - PosixOnly(); + Mocker.SetConstant<IProcMountProvider>(new ProcMountProvider(TestLogger)); + Mocker.GetMock<ISymbolicLinkResolver>() + .Setup(v => v.GetCompleteRealPath(It.IsAny<string>())) + .Returns<string>(s => s); + } + + [Ignore("Docker")] + [Test] + public void should_be_able_to_check_space_on_ramdrive() + { + Subject.GetAvailableSpace("/run/").Should().NotBe(0); } } } diff --git a/src/NzbDrone.Mono/Disk/DiskProvider.cs b/src/NzbDrone.Mono/Disk/DiskProvider.cs index 6ea2549dd..e18332124 100644 --- a/src/NzbDrone.Mono/Disk/DiskProvider.cs +++ b/src/NzbDrone.Mono/Disk/DiskProvider.cs @@ -61,15 +61,41 @@ namespace NzbDrone.Mono.Disk { } - public override void SetPermissions(string path, string mask) + public override void SetFilePermissions(string path, string mask, string group) + { + var permissions = NativeConvert.FromOctalPermissionString(mask); + + SetPermissions(path, mask, group, permissions); + } + + public override void SetPermissions(string path, string mask, string group) + { + var permissions = NativeConvert.FromOctalPermissionString(mask); + + if (File.Exists(path)) + { + permissions = GetFilePermissions(permissions); + } + + SetPermissions(path, mask, group, permissions); + } + + protected void SetPermissions(string path, string mask, string group, FilePermissions permissions) { _logger.Debug("Setting permissions: {0} on {1}", mask, path); - var permissions = NativeConvert.FromOctalPermissionString(mask); - - if (Directory.Exists(path)) + // Preserve non-access permissions + if (Syscall.stat(path, out var curStat) < 0) { - permissions = GetFolderPermissions(permissions); + var error = Stdlib.GetLastError(); + + throw new LinuxPermissionsException("Error getting current permissions: " + error); + } + + // Preserve existing non-access permissions unless mask is 4 digits + if (mask.Length < 4) + { + permissions |= curStat.st_mode & ~FilePermissions.ACCESSPERMS; } if (Syscall.chmod(path, permissions) < 0) @@ -78,33 +104,39 @@ namespace NzbDrone.Mono.Disk throw new LinuxPermissionsException("Error setting permissions: " + error); } + + var groupId = GetGroupId(group); + + if (Syscall.chown(path, unchecked((uint)-1), groupId) < 0) + { + var error = Stdlib.GetLastError(); + + throw new LinuxPermissionsException("Error setting group: " + error); + } } - private static FilePermissions GetFolderPermissions(FilePermissions permissions) + private static FilePermissions GetFilePermissions(FilePermissions permissions) { - permissions |= (FilePermissions)((int)(permissions & (FilePermissions.S_IRUSR | FilePermissions.S_IRGRP | FilePermissions.S_IROTH)) >> 2); + permissions &= ~(FilePermissions.S_IXUSR | FilePermissions.S_IXGRP | FilePermissions.S_IXOTH); return permissions; } - public override bool IsValidFilePermissionMask(string mask) + public override bool IsValidFolderPermissionMask(string mask) { try { var permissions = NativeConvert.FromOctalPermissionString(mask); - if ((permissions & (FilePermissions.S_ISUID | FilePermissions.S_ISGID | FilePermissions.S_ISVTX)) != 0) + if ((permissions & ~FilePermissions.ACCESSPERMS) != 0) { + // Only allow access permissions return false; } - if ((permissions & (FilePermissions.S_IXUSR | FilePermissions.S_IXGRP | FilePermissions.S_IXOTH)) != 0) - { - return false; - } - - if ((permissions & (FilePermissions.S_IRUSR | FilePermissions.S_IWUSR)) != (FilePermissions.S_IRUSR | FilePermissions.S_IWUSR)) + if ((permissions & FilePermissions.S_IRWXU) != FilePermissions.S_IRWXU) { + // We expect at least full owner permissions (700) return false; } @@ -281,9 +313,7 @@ namespace NzbDrone.Mono.Disk // Catch the exception and attempt to handle these edgecases // Mono 6.x till 6.10 doesn't properly try use rename first. - if (move && - ((PlatformInfo.Platform == PlatformType.Mono && PlatformInfo.GetVersion() < new Version(6, 10)) || - (PlatformInfo.Platform == PlatformType.NetCore))) + if (move && (PlatformInfo.Platform == PlatformType.NetCore)) { if (Syscall.lstat(source, out var sourcestat) == 0 && Syscall.lstat(destination, out var deststat) != 0 && @@ -311,32 +341,7 @@ namespace NzbDrone.Mono.Disk var dstInfo = new FileInfo(destination); var exists = dstInfo.Exists && srcInfo.Exists; - if (PlatformInfo.Platform == PlatformType.Mono && PlatformInfo.GetVersion() >= new Version(6, 6) && - exists && dstInfo.Length == 0 && srcInfo.Length != 0) - { - // mono >=6.6 bug: zero length file since chmod happens at the start - _logger.Debug("{3} failed to {2} file likely due to known {3} bug, attempting to {2} directly. '{0}' -> '{1}'", source, destination, move ? "move" : "copy", PlatformInfo.PlatformName); - - try - { - _logger.Trace("Copying content from {0} to {1} ({2} bytes)", source, destination, srcInfo.Length); - using (var srcStream = new FileStream(source, FileMode.Open, FileAccess.Read)) - using (var dstStream = new FileStream(destination, FileMode.Create, FileAccess.Write)) - { - srcStream.CopyTo(dstStream); - } - } - catch - { - // If it fails again then bail - throw; - } - } - else if (((PlatformInfo.Platform == PlatformType.Mono && - PlatformInfo.GetVersion() >= new Version(6, 0) && - PlatformInfo.GetVersion() < new Version(6, 6)) || - PlatformInfo.Platform == PlatformType.NetCore) && - exists && dstInfo.Length == srcInfo.Length) + if (PlatformInfo.Platform == PlatformType.NetCore && exists && dstInfo.Length == srcInfo.Length) { // mono 6.0, mono 6.4 and netcore 3.1 bug: full length file since utime and chmod happens at the end _logger.Debug("{3} failed to {2} file likely due to known {3} bug, attempting to {2} directly. '{0}' -> '{1}'", source, destination, move ? "move" : "copy", PlatformInfo.PlatformName); diff --git a/src/NzbDrone.Mono/Disk/FindDriveType.cs b/src/NzbDrone.Mono/Disk/FindDriveType.cs index a01c6c41f..d0481c3d4 100644 --- a/src/NzbDrone.Mono/Disk/FindDriveType.cs +++ b/src/NzbDrone.Mono/Disk/FindDriveType.cs @@ -12,6 +12,7 @@ namespace NzbDrone.Mono.Disk { "apfs", DriveType.Fixed }, { "fuse.mergerfs", DriveType.Fixed }, { "fuse.glusterfs", DriveType.Network }, + { "nullfs", DriveType.Fixed }, { "zfs", DriveType.Fixed } }; diff --git a/src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs b/src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs index c44820c50..4ae927c4a 100644 --- a/src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs +++ b/src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs @@ -90,6 +90,12 @@ namespace NzbDrone.Update.UpdateEngine Verify(installationFolder, processId); + if (installationFolder.EndsWith(@"\bin\Prowlarr") || installationFolder.EndsWith(@"/bin/Prowlarr")) + { + installationFolder = installationFolder.GetParentPath(); + _logger.Info("Fixed Installation Folder: {0}", installationFolder); + } + var appType = _detectApplicationType.GetAppType(); _processProvider.FindProcessByName(ProcessProvider.PROWLARR_CONSOLE_PROCESS_NAME); @@ -125,7 +131,7 @@ namespace NzbDrone.Update.UpdateEngine // Set executable flag on app if (OsInfo.IsOsx || (OsInfo.IsLinux && PlatformInfo.IsNetCore)) { - _diskProvider.SetPermissions(Path.Combine(installationFolder, "Prowlarr"), "0755"); + _diskProvider.SetPermissions(Path.Combine(installationFolder, "Prowlarr"), "0755", null); } } catch (Exception e) @@ -146,7 +152,7 @@ namespace NzbDrone.Update.UpdateEngine _terminateNzbDrone.Terminate(processId); _logger.Info("Waiting for external auto-restart."); - for (int i = 0; i < 5; i++) + for (int i = 0; i < 10; i++) { System.Threading.Thread.Sleep(1000); diff --git a/src/NzbDrone.Windows.Test/DiskProviderTests/FreeSpaceFixture.cs b/src/NzbDrone.Windows.Test/DiskProviderTests/FreeSpaceFixture.cs index c68de2451..fdb0b0988 100644 --- a/src/NzbDrone.Windows.Test/DiskProviderTests/FreeSpaceFixture.cs +++ b/src/NzbDrone.Windows.Test/DiskProviderTests/FreeSpaceFixture.cs @@ -1,4 +1,6 @@ -using NUnit.Framework; +using System.IO; +using FluentAssertions; +using NUnit.Framework; using NzbDrone.Common.Test.DiskTests; using NzbDrone.Windows.Disk; @@ -12,5 +14,30 @@ namespace NzbDrone.Windows.Test.DiskProviderTests { WindowsOnly(); } + + [Test] + public void should_throw_if_drive_doesnt_exist() + { + // Find a drive that doesn't exist. + for (char driveletter = 'Z'; driveletter > 'D'; driveletter--) + { + if (new DriveInfo(driveletter.ToString()).IsReady) + { + continue; + } + + Assert.Throws<DirectoryNotFoundException>(() => Subject.GetAvailableSpace(driveletter + @":\NOT_A_REAL_PATH\DOES_NOT_EXIST")); + return; + } + + Assert.Inconclusive("No drive available for testing."); + } + + [Test] + public void should_be_able_to_get_space_on_unc() + { + var result = Subject.GetAvailableSpace(@"\\localhost\c$\Windows"); + result.Should().BeGreaterThan(0); + } } } diff --git a/src/NzbDrone.Windows/Disk/DiskProvider.cs b/src/NzbDrone.Windows/Disk/DiskProvider.cs index 943058a6e..d8b9dc448 100644 --- a/src/NzbDrone.Windows/Disk/DiskProvider.cs +++ b/src/NzbDrone.Windows/Disk/DiskProvider.cs @@ -91,7 +91,11 @@ namespace NzbDrone.Windows.Disk } } - public override void SetPermissions(string path, string mask) + public override void SetFilePermissions(string path, string mask, string group) + { + } + + public override void SetPermissions(string path, string mask, string group) { } From 86fe19a5ddb58713dd80ee9f5b05e09e172662af Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 3 Jul 2022 12:26:02 -0500 Subject: [PATCH 0516/2320] Fixed: Don't call for server notifications on event driven check [common] --- .../HealthCheck/HealthCheckService.cs | 13 ++++---- .../ServerSideNotificationService.cs | 30 ++++++++++++++----- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs b/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs index 26442f9e7..f134bfeea 100644 --- a/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs +++ b/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs @@ -77,12 +77,15 @@ namespace NzbDrone.Core.HealthCheck .ToDictionary(g => g.Key, g => g.ToArray()); } - private void PerformHealthCheck(IProvideHealthCheck[] healthChecks) + private void PerformHealthCheck(IProvideHealthCheck[] healthChecks, bool performServerChecks = false) { var results = healthChecks.Select(c => c.Check()) .ToList(); - results.AddRange(_serverSideNotificationService.GetServerChecks()); + if (performServerChecks) + { + results.AddRange(_serverSideNotificationService.GetServerChecks()); + } foreach (var result in results) { @@ -108,17 +111,17 @@ namespace NzbDrone.Core.HealthCheck { if (message.Trigger == CommandTrigger.Manual) { - PerformHealthCheck(_healthChecks); + PerformHealthCheck(_healthChecks, true); } else { - PerformHealthCheck(_scheduledHealthChecks); + PerformHealthCheck(_scheduledHealthChecks, true); } } public void HandleAsync(ApplicationStartedEvent message) { - PerformHealthCheck(_startupHealthChecks); + PerformHealthCheck(_startupHealthChecks, true); } public void HandleAsync(IEvent message) diff --git a/src/NzbDrone.Core/HealthCheck/ServerSideNotificationService.cs b/src/NzbDrone.Core/HealthCheck/ServerSideNotificationService.cs index e5fc51dd7..14f4d3e8a 100644 --- a/src/NzbDrone.Core/HealthCheck/ServerSideNotificationService.cs +++ b/src/NzbDrone.Core/HealthCheck/ServerSideNotificationService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using NLog; +using NzbDrone.Common.Cache; using NzbDrone.Common.Cloud; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Http; @@ -23,24 +24,37 @@ namespace NzbDrone.Core.HealthCheck private readonly IHttpRequestBuilderFactory _cloudRequestBuilder; private readonly Logger _logger; - public ServerSideNotificationService(IHttpClient client, IConfigFileProvider configFileProvider, IProwlarrCloudRequestBuilder cloudRequestBuilder, Logger logger) + private readonly ICached<List<HealthCheck>> _cache; + + public ServerSideNotificationService(IHttpClient client, + IConfigFileProvider configFileProvider, + IProwlarrCloudRequestBuilder cloudRequestBuilder, + ICacheManager cacheManager, + Logger logger) { _client = client; _configFileProvider = configFileProvider; _cloudRequestBuilder = cloudRequestBuilder.Services; _logger = logger; + + _cache = cacheManager.GetCache<List<HealthCheck>>(GetType()); } public List<HealthCheck> GetServerChecks() + { + return _cache.Get("ServerChecks", () => RetrieveServerChecks(), TimeSpan.FromHours(2)); + } + + private List<HealthCheck> RetrieveServerChecks() { var request = _cloudRequestBuilder.Create() - .Resource("/notification") - .AddQueryParam("version", BuildInfo.Version) - .AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant()) - .AddQueryParam("arch", RuntimeInformation.OSArchitecture) - .AddQueryParam("runtime", PlatformInfo.Platform.ToString().ToLowerInvariant()) - .AddQueryParam("branch", _configFileProvider.Branch) - .Build(); + .Resource("/notification") + .AddQueryParam("version", BuildInfo.Version) + .AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant()) + .AddQueryParam("arch", RuntimeInformation.OSArchitecture) + .AddQueryParam("runtime", PlatformInfo.Platform.ToString().ToLowerInvariant()) + .AddQueryParam("branch", _configFileProvider.Branch) + .Build(); try { _logger.Trace("Getting server side health notifications"); From 5436d4f8009a0e823adbe97bc634019470baedee Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 3 Jul 2022 12:32:41 -0500 Subject: [PATCH 0517/2320] Fixed: Set update executable permissions correctly --- src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs b/src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs index 4ae927c4a..f656c8775 100644 --- a/src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs +++ b/src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs @@ -131,7 +131,7 @@ namespace NzbDrone.Update.UpdateEngine // Set executable flag on app if (OsInfo.IsOsx || (OsInfo.IsLinux && PlatformInfo.IsNetCore)) { - _diskProvider.SetPermissions(Path.Combine(installationFolder, "Prowlarr"), "0755", null); + _diskProvider.SetFilePermissions(Path.Combine(installationFolder, "Prowlarr"), "755", null); } } catch (Exception e) From d2c1ffa7619d515ab24f2da5933917585710c5a0 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 3 Jul 2022 10:13:40 -0500 Subject: [PATCH 0518/2320] Fixed: Log Cleanse Indexer Response Logic and Test Cases --- .../InstrumentationTests/CleanseLogMessageFixture.cs | 6 +++--- src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs index eba324bf1..d78034b2f 100644 --- a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs +++ b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs @@ -28,11 +28,11 @@ namespace NzbDrone.Common.Test.InstrumentationTests // Indexer and Download Client Responses // avistaz response - [TestCase(@"""download"":""https:\/\/avistaz.to\/rss\/download\/2b51db35e1910123321025a12b9933d2\/tb51db35e1910123321025a12b9933d2.torrent"",")] + [TestCase(@"""download"":""https://avistaz.to/rss/download/2b51db35e1910123321025a12b9933d2/tb51db35e1910123321025a12b9933d2.torrent"",")] [TestCase(@",""info_hash"":""2b51db35e1910123321025a12b9933d2"",")] // animebytes response - [TestCase(@"""Link"":""https:\/\/animebytes.tv\/torrent\/994064\/download\/tb51db35e1910123321025a12b9933d2"",")] + [TestCase(@"""Link"":""https://animebytes.tv/torrent/994064/download/tb51db35e1910123321025a12b9933d2"",")] // danish bytes response [TestCase(@",""rsskey"":""2b51db35e1910123321025a12b9933d2"",")] @@ -86,7 +86,7 @@ namespace NzbDrone.Common.Test.InstrumentationTests // BroadcastheNet [TestCase(@"method: ""getTorrents"", ""params"": [ ""mySecret"",")] [TestCase(@"getTorrents(""mySecret"", [asdfasdf], 100, 0)")] - [TestCase(@"""DownloadURL"":""https:\/\/broadcasthe.net\/torrents.php?action=download&id=123&authkey=mySecret&torrent_pass=mySecret""")] + [TestCase(@"""DownloadURL"":""https://broadcasthe.net/torrents.php?action=download&id=123&authkey=mySecret&torrent_pass=mySecret""")] // Webhooks - Notifiarr [TestCase(@"https://xxx.yyy/api/v1/notification/prowlarr/9pr04sg6-0123-3210-imav-eql2tyu8xyui")] diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index 7cc749b3a..9a501d607 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -54,8 +54,8 @@ namespace NzbDrone.Common.Instrumentation new Regex(@"(?<=\?|&)(X-Plex-Client-Identifier|X-Plex-Token)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), // Indexer Responses - new Regex(@"(?:avistaz|exoticaz|cinemaz|privatehd)\.[a-z]{2,3}\\\/rss\\\/download\\\/(?<secret>[^&=]+?)\\\/(?<secret>[^&=]+?)\.torrent", RegexOptions.Compiled | RegexOptions.IgnoreCase), - new Regex(@"(?:animebytes)\.[a-z]{2,3}\\\/torrent\\\/[0-9]+\\\/download\\\/(?<secret>[^&=]+?)[""]", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"(?:avistaz|exoticaz|cinemaz|privatehd)\.[a-z]{2,3}/rss/download/(?<secret>[^&=]+?)/(?<secret>[^&=]+?)\.torrent", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"(?:animebytes)\.[a-z]{2,3}/torrent/[0-9]+/download/(?<secret>[^&=]+?)[""]", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@",""info_hash"":""(?<secret>[^&=]+?)"",", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@",""pass[- _]?key"":""(?<secret>[^&=]+?)"",", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@",""rss[- _]?key"":""(?<secret>[^&=]+?)"",", RegexOptions.Compiled | RegexOptions.IgnoreCase), From 59b74358201e8c17941879c0d352a3de87292d80 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 3 Jul 2022 17:23:47 -0500 Subject: [PATCH 0519/2320] Fixed: (IPTorrents) Allow UA override for CF Fixes #842 Fixes #809 --- .../Indexers/Definitions/IPTorrents.cs | 21 +++++++++++++++++++ .../Settings/CookieTorrentBaseSettings.cs | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs index 43c95e5cf..c0f238284 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs @@ -200,6 +200,8 @@ namespace NzbDrone.Core.Indexers.Definitions var request = new IndexerRequest(searchUrl, HttpAccept.Html); + request.HttpRequest.Headers.UserAgent = Settings.UserAgent; + yield return request; } @@ -349,13 +351,32 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } + public class IPTorrentsSettingsValidator : AbstractValidator<IPTorrentsSettings> + { + public IPTorrentsSettingsValidator() + { + RuleFor(c => c.UserAgent).NotEmpty(); + RuleFor(c => c.Cookie).NotEmpty(); + } + } + public class IPTorrentsSettings : CookieTorrentBaseSettings { public IPTorrentsSettings() { } + private static readonly IPTorrentsSettingsValidator Validator = new IPTorrentsSettingsValidator(); + + [FieldDefinition(2, Label = "Cookie User-Agent", Type = FieldType.Textbox, HelpText = "User-Agent associated with cookie used from Browser")] + public string UserAgent { get; set; } + [FieldDefinition(3, Label = "FreeLeech Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Search Freeleech torrents only")] public bool FreeLeechOnly { get; set; } + + public override NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } } } diff --git a/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs index 653127007..1ea233525 100644 --- a/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Indexers.Settings [FieldDefinition(4)] public IndexerTorrentBaseSettings TorrentBaseSettings { get; set; } = new IndexerTorrentBaseSettings(); - public NzbDroneValidationResult Validate() + public virtual NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } From 83344fb6f45262ff24d2a977bdeea81f93057252 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 4 Jul 2022 11:21:14 -0500 Subject: [PATCH 0520/2320] Double MultipartBodyLengthLimit for Backup Restore to 256MB --- src/NzbDrone.Host/Bootstrap.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index d4ab88f39..9e18e262f 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -12,6 +12,7 @@ using DryIoc.Microsoft.DependencyInjection; using FluentMigrator.Runner.Processors.Postgres; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -154,6 +155,11 @@ namespace NzbDrone.Host .ConfigureServices(services => { services.Configure<PostgresOptions>(config.GetSection("Prowlarr:Postgres")); + services.Configure<FormOptions>(x => + { + //Double the default multipart body length from 128 MB to 256 MB + x.MultipartBodyLengthLimit = 268435456; + }); }) .ConfigureWebHost(builder => { From f9c731627ff30b410521ae288384dd7997878e23 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 4 Jul 2022 12:58:50 -0500 Subject: [PATCH 0521/2320] Fixed: Lidarr null ref when building indexer for sync Fixes PROWLARR-856 --- src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs b/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs index 63023d2f9..f242fa0c1 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs @@ -40,8 +40,8 @@ namespace NzbDrone.Core.Applications.Lidarr var otherSeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value); var seedTimeCompare = seedTime == otherSeedTime; - var discographySeedTime = Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seasonPackSeedTime").Value); - var otherDiscographySeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seasonPackSeedTime").Value); + var discographySeedTime = Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime").Value); + var otherDiscographySeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime").Value); var discographySeedTimeCompare = discographySeedTime == otherDiscographySeedTime; var seedRatio = Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); From 832080cb36b3289dbb991c8c56a3ace75e6623f9 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 4 Jul 2022 12:59:58 -0500 Subject: [PATCH 0522/2320] Fixed: Lidarr null ref when building indexer for sync Fixes PROWLARR-B5Y --- src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs b/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs index d41073717..097bcaa04 100644 --- a/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs @@ -40,8 +40,8 @@ namespace NzbDrone.Core.Applications.Readarr var otherSeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value); var seedTimeCompare = seedTime == otherSeedTime; - var discographySeedTime = Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seasonPackSeedTime").Value); - var otherDiscographySeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seasonPackSeedTime").Value); + var discographySeedTime = Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime").Value); + var otherDiscographySeedTime = other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime").Value); var discographySeedTimeCompare = discographySeedTime == otherDiscographySeedTime; var seedRatio = Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio")?.Value == null ? null : (double?)Convert.ToDouble(Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value); From 91eb65bd6c874757295684a5194b8561de3bf207 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 4 Jul 2022 13:02:25 -0500 Subject: [PATCH 0523/2320] ProtectionService Test Fixture --- .../SecurityTests/ProtectionServiceFixture.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/NzbDrone.Core.Test/SecurityTests/ProtectionServiceFixture.cs diff --git a/src/NzbDrone.Core.Test/SecurityTests/ProtectionServiceFixture.cs b/src/NzbDrone.Core.Test/SecurityTests/ProtectionServiceFixture.cs new file mode 100644 index 000000000..1030ecaba --- /dev/null +++ b/src/NzbDrone.Core.Test/SecurityTests/ProtectionServiceFixture.cs @@ -0,0 +1,36 @@ +using System; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Security; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.SecurityTests +{ + [TestFixture] + public class ProtectionServiceFixture : CoreTest<ProtectionService> + { + private string _protectionKey; + + [SetUp] + public void Setup() + { + _protectionKey = Guid.NewGuid().ToString().Replace("-", ""); + + Mocker.GetMock<IConfigService>() + .SetupGet(s => s.DownloadProtectionKey) + .Returns(_protectionKey); + } + + [Test] + public void should_encrypt_and_decrypt_string() + { + const string plainText = "https://prowlarr.com"; + + var encrypted = Subject.Protect(plainText); + var decrypted = Subject.UnProtect(encrypted); + + decrypted.Should().Be(plainText); + } + } +} From 06f3c8e151027391cdff18e1a1d211eb90038273 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 4 Jul 2022 14:24:32 -0500 Subject: [PATCH 0524/2320] Fixed: (Applications) ApiPath can be null from -arr in some cases --- src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs | 7 +++++-- src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs | 7 +++++-- src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs | 7 +++++-- src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs | 7 +++++-- src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs | 7 +++++-- 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs b/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs index f242fa0c1..b2be57c33 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs @@ -28,10 +28,13 @@ namespace NzbDrone.Core.Applications.Lidarr } var baseUrl = (string)Fields.FirstOrDefault(x => x.Name == "baseUrl").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value; - var apiPath = (string)Fields.FirstOrDefault(x => x.Name == "apiPath").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey").Value; var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value); + var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value; + var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; + var apiPathCompare = apiPath == otherApiPath; + var minimumSeeders = Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); var otherMinimumSeeders = other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); var minimumSeedersCompare = minimumSeeders == otherMinimumSeeders; @@ -55,7 +58,7 @@ namespace NzbDrone.Core.Applications.Lidarr other.Implementation == Implementation && other.Priority == Priority && other.Id == Id && - apiKey && apiPath && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && discographySeedTimeCompare; + apiKey && apiPathCompare && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && discographySeedTimeCompare; } } } diff --git a/src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs b/src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs index c9b649913..52065160e 100644 --- a/src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs @@ -28,10 +28,13 @@ namespace NzbDrone.Core.Applications.Radarr } var baseUrl = (string)Fields.FirstOrDefault(x => x.Name == "baseUrl").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value; - var apiPath = (string)Fields.FirstOrDefault(x => x.Name == "apiPath").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey").Value; var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value); + var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value; + var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; + var apiPathCompare = apiPath == otherApiPath; + var minimumSeeders = Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); var otherMinimumSeeders = other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); var minimumSeedersCompare = minimumSeeders == otherMinimumSeeders; @@ -51,7 +54,7 @@ namespace NzbDrone.Core.Applications.Radarr other.Implementation == Implementation && other.Priority == Priority && other.Id == Id && - apiKey && apiPath && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare; + apiKey && apiPathCompare && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare; } } } diff --git a/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs b/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs index 097bcaa04..ef108cba5 100644 --- a/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs @@ -28,10 +28,13 @@ namespace NzbDrone.Core.Applications.Readarr } var baseUrl = (string)Fields.FirstOrDefault(x => x.Name == "baseUrl").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value; - var apiPath = (string)Fields.FirstOrDefault(x => x.Name == "apiPath").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey").Value; var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value); + var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value; + var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; + var apiPathCompare = apiPath == otherApiPath; + var minimumSeeders = Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); var otherMinimumSeeders = other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); var minimumSeedersCompare = minimumSeeders == otherMinimumSeeders; @@ -55,7 +58,7 @@ namespace NzbDrone.Core.Applications.Readarr other.Implementation == Implementation && other.Priority == Priority && other.Id == Id && - apiKey && apiPath && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && discographySeedTimeCompare; + apiKey && apiPathCompare && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && discographySeedTimeCompare; } } } diff --git a/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs b/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs index dc1282112..15adc891d 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs @@ -28,11 +28,14 @@ namespace NzbDrone.Core.Applications.Sonarr } var baseUrl = (string)Fields.FirstOrDefault(x => x.Name == "baseUrl").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value; - var apiPath = (string)Fields.FirstOrDefault(x => x.Name == "apiPath").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey").Value; var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value); var animeCats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "animeCategories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "animeCategories").Value); + var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value; + var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; + var apiPathCompare = apiPath == otherApiPath; + var minimumSeeders = Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); var otherMinimumSeeders = other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); var minimumSeedersCompare = minimumSeeders == otherMinimumSeeders; @@ -56,7 +59,7 @@ namespace NzbDrone.Core.Applications.Sonarr other.Implementation == Implementation && other.Priority == Priority && other.Id == Id && - apiKey && apiPath && baseUrl && cats && animeCats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && seasonSeedTimeCompare; + apiKey && apiPathCompare && baseUrl && cats && animeCats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && seasonSeedTimeCompare; } } } diff --git a/src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs b/src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs index 5898b1c96..fc4d33f9a 100644 --- a/src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs @@ -28,10 +28,13 @@ namespace NzbDrone.Core.Applications.Whisparr } var baseUrl = (string)Fields.FirstOrDefault(x => x.Name == "baseUrl").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value; - var apiPath = (string)Fields.FirstOrDefault(x => x.Name == "apiPath").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey").Value; var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value); + var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value; + var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; + var apiPathCompare = apiPath == otherApiPath; + var minimumSeeders = Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); var otherMinimumSeeders = other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); var minimumSeedersCompare = minimumSeeders == otherMinimumSeeders; @@ -51,7 +54,7 @@ namespace NzbDrone.Core.Applications.Whisparr other.Implementation == Implementation && other.Priority == Priority && other.Id == Id && - apiKey && apiPath && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare; + apiKey && apiPathCompare && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare; } } } From cec304a0be3c5ca8d61c3afa5b76d7c896dc49b1 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 4 Jul 2022 18:13:18 -0500 Subject: [PATCH 0525/2320] Don't require user agent for IPTorrents --- .../Indexers/Definitions/IPTorrents.cs | 23 ++++--------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs b/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs index c0f238284..d64ee7560 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/IPTorrents.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using AngleSharp.Html.Parser; -using FluentValidation; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; @@ -14,7 +13,6 @@ using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { @@ -200,7 +198,10 @@ namespace NzbDrone.Core.Indexers.Definitions var request = new IndexerRequest(searchUrl, HttpAccept.Html); - request.HttpRequest.Headers.UserAgent = Settings.UserAgent; + if (Settings.UserAgent.IsNotNullOrWhiteSpace()) + { + request.HttpRequest.Headers.UserAgent = Settings.UserAgent; + } yield return request; } @@ -351,32 +352,16 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - public class IPTorrentsSettingsValidator : AbstractValidator<IPTorrentsSettings> - { - public IPTorrentsSettingsValidator() - { - RuleFor(c => c.UserAgent).NotEmpty(); - RuleFor(c => c.Cookie).NotEmpty(); - } - } - public class IPTorrentsSettings : CookieTorrentBaseSettings { public IPTorrentsSettings() { } - private static readonly IPTorrentsSettingsValidator Validator = new IPTorrentsSettingsValidator(); - [FieldDefinition(2, Label = "Cookie User-Agent", Type = FieldType.Textbox, HelpText = "User-Agent associated with cookie used from Browser")] public string UserAgent { get; set; } [FieldDefinition(3, Label = "FreeLeech Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Search Freeleech torrents only")] public bool FreeLeechOnly { get; set; } - - public override NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } } } From 593a649045ada3bb28cac9f178c6ee1bfec4d7d5 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 4 Jul 2022 18:36:57 -0500 Subject: [PATCH 0526/2320] Bump version to 0.4.3 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 89e9d33df..1be407772 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: testsFolder: './_tests' yarnCacheFolder: $(Pipeline.Workspace)/.yarn nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages - majorVersion: '0.4.2' + majorVersion: '0.4.3' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From b7b5a6e7e1150e2a34aac37deff84f02840111cf Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 4 Jul 2022 18:37:31 -0500 Subject: [PATCH 0527/2320] Modern HTTP Client (#685) --- .../Http/HttpClientFixture.cs | 135 ++++++- .../Extensions/StringExtensions.cs | 21 + .../Http/BasicNetworkCredential.cs | 12 + src/NzbDrone.Common/Http/CookieUtil.cs | 3 +- .../ICertificateValidationService.cs | 11 + .../Http/Dispatchers/IHttpDispatcher.cs | 1 - .../Http/Dispatchers/ManagedHttpDispatcher.cs | 358 +++++++++++------- src/NzbDrone.Common/Http/GZipWebClient.cs | 15 - src/NzbDrone.Common/Http/HttpClient.cs | 154 ++++++-- src/NzbDrone.Common/Http/HttpHeader.cs | 21 + src/NzbDrone.Common/Http/HttpRequest.cs | 14 +- .../Http/HttpRequestBuilder.cs | 13 +- src/NzbDrone.Common/Http/HttpResponse.cs | 9 +- .../Http/XmlRpcRequestBuilder.cs | 103 +++++ src/NzbDrone.Core.Test/Framework/CoreTest.cs | 4 +- .../Download/Clients/Aria2/Aria2Containers.cs | 220 ++++++----- .../Download/Clients/Aria2/Aria2Proxy.cs | 228 +++++------ .../Clients/rTorrent/RTorrentFault.cs | 28 ++ .../Clients/rTorrent/RTorrentProxy.cs | 253 +++++-------- .../Clients/rTorrent/RTorrentTorrent.cs | 31 +- .../Download/Extensions/XmlExtensions.cs | 54 +++ .../Definitions/Headphones/Headphones.cs | 2 +- .../Headphones/HeadphonesRequestGenerator.cs | 2 +- .../Notifications/Email/Email.cs | 7 +- .../PushBullet/PushBulletProxy.cs | 4 +- .../Notifications/Twitter/TwitterProxy.cs | 110 ++++++ .../Notifications/Twitter/TwitterService.cs | 46 +-- .../Notifications/Webhook/WebhookProxy.cs | 2 +- .../X509CertificateValidationService.cs | 38 +- src/NzbDrone.Core/TinyTwitter.cs | 235 ------------ 30 files changed, 1260 insertions(+), 874 deletions(-) create mode 100644 src/NzbDrone.Common/Http/BasicNetworkCredential.cs create mode 100644 src/NzbDrone.Common/Http/Dispatchers/ICertificateValidationService.cs delete mode 100644 src/NzbDrone.Common/Http/GZipWebClient.cs create mode 100644 src/NzbDrone.Common/Http/XmlRpcRequestBuilder.cs create mode 100644 src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentFault.cs create mode 100644 src/NzbDrone.Core/Download/Extensions/XmlExtensions.cs create mode 100644 src/NzbDrone.Core/Notifications/Twitter/TwitterProxy.cs delete mode 100644 src/NzbDrone.Core/TinyTwitter.cs diff --git a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs index 23f08adbe..8979c2a19 100644 --- a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs +++ b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading; using FluentAssertions; using Moq; @@ -15,8 +16,11 @@ using NzbDrone.Common.Http; using NzbDrone.Common.Http.Dispatchers; using NzbDrone.Common.Http.Proxy; using NzbDrone.Common.TPL; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Security; using NzbDrone.Test.Common; using NzbDrone.Test.Common.Categories; +using HttpClient = NzbDrone.Common.Http.HttpClient; namespace NzbDrone.Common.Test.Http { @@ -31,6 +35,8 @@ namespace NzbDrone.Common.Test.Http private string _httpBinHost; private string _httpBinHost2; + private System.Net.Http.HttpClient _httpClient = new (); + [OneTimeSetUp] public void FixtureSetUp() { @@ -38,7 +44,7 @@ namespace NzbDrone.Common.Test.Http var mainHost = "httpbin.servarr.com"; // Use mirrors for tests that use two hosts - var candidates = new[] { "eu.httpbin.org", /* "httpbin.org", */ "www.httpbin.org" }; + var candidates = new[] { "httpbin1.servarr.com" }; // httpbin.org is broken right now, occassionally redirecting to https if it's unavailable. _httpBinHost = mainHost; @@ -46,29 +52,20 @@ namespace NzbDrone.Common.Test.Http TestLogger.Info($"{candidates.Length} TestSites available."); - _httpBinSleep = _httpBinHosts.Length < 2 ? 100 : 10; + _httpBinSleep = 10; } private bool IsTestSiteAvailable(string site) { try { - var req = WebRequest.Create($"https://{site}/get") as HttpWebRequest; - var res = req.GetResponse() as HttpWebResponse; + var res = _httpClient.GetAsync($"https://{site}/get").GetAwaiter().GetResult(); if (res.StatusCode != HttpStatusCode.OK) { return false; } - try - { - req = WebRequest.Create($"https://{site}/status/429") as HttpWebRequest; - res = req.GetResponse() as HttpWebResponse; - } - catch (WebException ex) - { - res = ex.Response as HttpWebResponse; - } + res = _httpClient.GetAsync($"https://{site}/status/429").GetAwaiter().GetResult(); if (res == null || res.StatusCode != (HttpStatusCode)429) { @@ -95,10 +92,13 @@ namespace NzbDrone.Common.Test.Http Mocker.GetMock<IOsInfo>().Setup(c => c.Name).Returns("TestOS"); Mocker.GetMock<IOsInfo>().Setup(c => c.Version).Returns("9.0.0"); + Mocker.GetMock<IConfigService>().SetupGet(x => x.CertificateValidation).Returns(CertificateValidationType.Enabled); + Mocker.SetConstant<IUserAgentBuilder>(Mocker.Resolve<UserAgentBuilder>()); Mocker.SetConstant<ICacheManager>(Mocker.Resolve<CacheManager>()); Mocker.SetConstant<ICreateManagedWebProxy>(Mocker.Resolve<ManagedWebProxyFactory>()); + Mocker.SetConstant<ICertificateValidationService>(new X509CertificateValidationService(Mocker.GetMock<IConfigService>().Object, TestLogger)); Mocker.SetConstant<IRateLimitService>(Mocker.Resolve<RateLimitService>()); Mocker.SetConstant<IEnumerable<IHttpRequestInterceptor>>(Array.Empty<IHttpRequestInterceptor>()); Mocker.SetConstant<IHttpDispatcher>(Mocker.Resolve<TDispatcher>()); @@ -138,6 +138,28 @@ namespace NzbDrone.Common.Test.Http response.Content.Should().NotBeNullOrWhiteSpace(); } + [TestCase(CertificateValidationType.Enabled)] + [TestCase(CertificateValidationType.DisabledForLocalAddresses)] + public void bad_ssl_should_fail_when_remote_validation_enabled(CertificateValidationType validationType) + { + Mocker.GetMock<IConfigService>().SetupGet(x => x.CertificateValidation).Returns(validationType); + var request = new HttpRequest($"https://expired.badssl.com"); + + Assert.Throws<HttpRequestException>(() => Subject.Execute(request)); + ExceptionVerification.ExpectedErrors(1); + } + + [Test] + public void bad_ssl_should_pass_if_remote_validation_disabled() + { + Mocker.GetMock<IConfigService>().SetupGet(x => x.CertificateValidation).Returns(CertificateValidationType.Disabled); + + var request = new HttpRequest($"https://expired.badssl.com"); + + Subject.Execute(request); + ExceptionVerification.ExpectedErrors(0); + } + [Test] public void should_execute_typed_get() { @@ -162,15 +184,44 @@ namespace NzbDrone.Common.Test.Http response.Resource.Data.Should().Be(message); } - [TestCase("gzip")] - public void should_execute_get_using_gzip(string compression) + [Test] + public void should_execute_post_with_content_type() { - var request = new HttpRequest($"https://{_httpBinHost}/{compression}"); + var message = "{ my: 1 }"; + + var request = new HttpRequest($"https://{_httpBinHost}/post"); + request.SetContent(message); + request.Headers.ContentType = "application/json"; + + var response = Subject.Post<HttpBinResource>(request); + + response.Resource.Data.Should().Be(message); + } + + [Test] + public void should_execute_get_using_gzip() + { + var request = new HttpRequest($"https://{_httpBinHost}/gzip"); var response = Subject.Get<HttpBinResource>(request); - response.Resource.Headers["Accept-Encoding"].ToString().Should().Be(compression); + response.Resource.Headers["Accept-Encoding"].ToString().Should().Contain("gzip"); + response.Resource.Gzipped.Should().BeTrue(); + response.Resource.Brotli.Should().BeFalse(); + } + + [Test] + public void should_execute_get_using_brotli() + { + var request = new HttpRequest($"https://{_httpBinHost}/brotli"); + + var response = Subject.Get<HttpBinResource>(request); + + response.Resource.Headers["Accept-Encoding"].ToString().Should().Contain("br"); + + response.Resource.Gzipped.Should().BeFalse(); + response.Resource.Brotli.Should().BeTrue(); } [TestCase(HttpStatusCode.Unauthorized)] @@ -190,6 +241,28 @@ namespace NzbDrone.Common.Test.Http ExceptionVerification.IgnoreWarns(); } + [Test] + public void should_not_throw_on_suppressed_status_codes() + { + var request = new HttpRequest($"https://{_httpBinHost}/status/{HttpStatusCode.NotFound}"); + request.SuppressHttpErrorStatusCodes = new[] { HttpStatusCode.NotFound }; + + Assert.Throws<HttpException>(() => Subject.Get<HttpBinResource>(request)); + + ExceptionVerification.IgnoreWarns(); + } + + [Test] + public void should_not_log_unsuccessful_status_codes() + { + var request = new HttpRequest($"https://{_httpBinHost}/status/{HttpStatusCode.NotFound}"); + request.LogHttpError = false; + + Assert.Throws<HttpException>(() => Subject.Get<HttpBinResource>(request)); + + ExceptionVerification.ExpectedWarns(0); + } + [Test] public void should_not_follow_redirects_when_not_in_production() { @@ -315,13 +388,38 @@ namespace NzbDrone.Common.Test.Http { var file = GetTempFilePath(); - Assert.Throws<WebException>(() => Subject.DownloadFile("https://download.sonarr.tv/wrongpath", file)); + Assert.Throws<HttpException>(() => Subject.DownloadFile("https://download.sonarr.tv/wrongpath", file)); File.Exists(file).Should().BeFalse(); ExceptionVerification.ExpectedWarns(1); } + [Test] + public void should_not_write_redirect_content_to_stream() + { + var file = GetTempFilePath(); + + using (var fileStream = new FileStream(file, FileMode.Create)) + { + var request = new HttpRequest($"http://{_httpBinHost}/redirect/1"); + request.AllowAutoRedirect = false; + request.ResponseStream = fileStream; + + var response = Subject.Get(request); + + response.StatusCode.Should().Be(HttpStatusCode.Moved); + } + + ExceptionVerification.ExpectedErrors(1); + + File.Exists(file).Should().BeTrue(); + + var fileInfo = new FileInfo(file); + + fileInfo.Length.Should().Be(0); + } + [Test] public void should_send_cookie() { @@ -753,6 +851,7 @@ namespace NzbDrone.Common.Test.Http public string Url { get; set; } public string Data { get; set; } public bool Gzipped { get; set; } + public bool Brotli { get; set; } } public class HttpCookieResource diff --git a/src/NzbDrone.Common/Extensions/StringExtensions.cs b/src/NzbDrone.Common/Extensions/StringExtensions.cs index 744309caf..28725f269 100644 --- a/src/NzbDrone.Common/Extensions/StringExtensions.cs +++ b/src/NzbDrone.Common/Extensions/StringExtensions.cs @@ -210,5 +210,26 @@ namespace NzbDrone.Common.Extensions return result.TrimStart(' ', '.').TrimEnd(' '); } + + public static string EncodeRFC3986(this string value) + { + // From Twitterizer http://www.twitterizer.net/ + if (string.IsNullOrEmpty(value)) + { + return string.Empty; + } + + var encoded = Uri.EscapeDataString(value); + + return Regex + .Replace(encoded, "(%[0-9a-f][0-9a-f])", c => c.Value.ToUpper()) + .Replace("(", "%28") + .Replace(")", "%29") + .Replace("$", "%24") + .Replace("!", "%21") + .Replace("*", "%2A") + .Replace("'", "%27") + .Replace("%7E", "~"); + } } } diff --git a/src/NzbDrone.Common/Http/BasicNetworkCredential.cs b/src/NzbDrone.Common/Http/BasicNetworkCredential.cs new file mode 100644 index 000000000..26710f766 --- /dev/null +++ b/src/NzbDrone.Common/Http/BasicNetworkCredential.cs @@ -0,0 +1,12 @@ +using System.Net; + +namespace NzbDrone.Common.Http +{ + public class BasicNetworkCredential : NetworkCredential + { + public BasicNetworkCredential(string user, string pass) + : base(user, pass) + { + } + } +} diff --git a/src/NzbDrone.Common/Http/CookieUtil.cs b/src/NzbDrone.Common/Http/CookieUtil.cs index 5b57c06a1..38c3c756b 100644 --- a/src/NzbDrone.Common/Http/CookieUtil.cs +++ b/src/NzbDrone.Common/Http/CookieUtil.cs @@ -10,6 +10,7 @@ namespace NzbDrone.Common.Http // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie // NOTE: we are not checking non-ascii characters and we should private static readonly Regex _CookieRegex = new Regex(@"([^\(\)<>@,;:\\""/\[\]\?=\{\}\s]+)=([^,;\\""\s]+)"); + private static readonly string[] FilterProps = { "COMMENT", "COMMENTURL", "DISCORD", "DOMAIN", "EXPIRES", "MAX-AGE", "PATH", "PORT", "SECURE", "VERSION", "HTTPONLY", "SAMESITE" }; private static readonly char[] InvalidKeyChars = { '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t', '\n' }; private static readonly char[] InvalidValueChars = { '"', ',', ';', '\\', ' ', '\t', '\n' }; @@ -24,7 +25,7 @@ namespace NzbDrone.Common.Http var matches = _CookieRegex.Match(cookieHeader); while (matches.Success) { - if (matches.Groups.Count > 2) + if (matches.Groups.Count > 2 && !FilterProps.Contains(matches.Groups[1].Value.ToUpperInvariant())) { cookieDictionary[matches.Groups[1].Value] = matches.Groups[2].Value; } diff --git a/src/NzbDrone.Common/Http/Dispatchers/ICertificateValidationService.cs b/src/NzbDrone.Common/Http/Dispatchers/ICertificateValidationService.cs new file mode 100644 index 000000000..187c1fd43 --- /dev/null +++ b/src/NzbDrone.Common/Http/Dispatchers/ICertificateValidationService.cs @@ -0,0 +1,11 @@ +using System.Net.Http; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; + +namespace NzbDrone.Common.Http.Dispatchers +{ + public interface ICertificateValidationService + { + bool ShouldByPassValidationError(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors); + } +} diff --git a/src/NzbDrone.Common/Http/Dispatchers/IHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/IHttpDispatcher.cs index 9afd1f5ad..a5565f26b 100644 --- a/src/NzbDrone.Common/Http/Dispatchers/IHttpDispatcher.cs +++ b/src/NzbDrone.Common/Http/Dispatchers/IHttpDispatcher.cs @@ -6,6 +6,5 @@ namespace NzbDrone.Common.Http.Dispatchers public interface IHttpDispatcher { Task<HttpResponse> GetResponseAsync(HttpRequest request, CookieContainer cookies); - Task DownloadFileAsync(string url, string fileName); } } diff --git a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs index 1be10eb56..20b407a69 100644 --- a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs +++ b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs @@ -1,13 +1,16 @@ using System; using System.Diagnostics; using System.IO; -using System.IO.Compression; +using System.Linq; using System.Net; -using System.Reflection; +using System.Net.Http; +using System.Net.Security; +using System.Net.Sockets; +using System.Text; +using System.Threading; using System.Threading.Tasks; using NLog; -using NLog.Fluent; -using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http.Proxy; @@ -15,221 +18,223 @@ namespace NzbDrone.Common.Http.Dispatchers { public class ManagedHttpDispatcher : IHttpDispatcher { + private const string NO_PROXY_KEY = "no-proxy"; + + private const int connection_establish_timeout = 2000; + private static bool useIPv6 = Socket.OSSupportsIPv6; + private static bool hasResolvedIPv6Availability; + private readonly IHttpProxySettingsProvider _proxySettingsProvider; private readonly ICreateManagedWebProxy _createManagedWebProxy; + private readonly ICertificateValidationService _certificateValidationService; private readonly IUserAgentBuilder _userAgentBuilder; - private readonly IPlatformInfo _platformInfo; - private readonly Logger _logger; + private readonly ICached<System.Net.Http.HttpClient> _httpClientCache; + private readonly ICached<CredentialCache> _credentialCache; - public ManagedHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, ICreateManagedWebProxy createManagedWebProxy, IUserAgentBuilder userAgentBuilder, IPlatformInfo platformInfo, Logger logger) + public ManagedHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, + ICreateManagedWebProxy createManagedWebProxy, + ICertificateValidationService certificateValidationService, + IUserAgentBuilder userAgentBuilder, + ICacheManager cacheManager) { _proxySettingsProvider = proxySettingsProvider; _createManagedWebProxy = createManagedWebProxy; + _certificateValidationService = certificateValidationService; _userAgentBuilder = userAgentBuilder; - _platformInfo = platformInfo; - _logger = logger; + + _httpClientCache = cacheManager.GetCache<System.Net.Http.HttpClient>(typeof(ManagedHttpDispatcher)); + _credentialCache = cacheManager.GetCache<CredentialCache>(typeof(ManagedHttpDispatcher), "credentialcache"); } public async Task<HttpResponse> GetResponseAsync(HttpRequest request, CookieContainer cookies) { - var webRequest = (HttpWebRequest)WebRequest.Create((Uri)request.Url); + var requestMessage = new HttpRequestMessage(request.Method, (Uri)request.Url); + requestMessage.Headers.UserAgent.ParseAdd(_userAgentBuilder.GetUserAgent(request.UseSimplifiedUserAgent)); + requestMessage.Headers.ConnectionClose = !request.ConnectionKeepAlive; - // Deflate is not a standard and could break depending on implementation. - // we should just stick with the more compatible Gzip - //http://stackoverflow.com/questions/8490718/how-to-decompress-stream-deflated-with-java-util-zip-deflater-in-net - webRequest.AutomaticDecompression = DecompressionMethods.GZip; - - webRequest.Method = request.Method.ToString(); - webRequest.UserAgent = _userAgentBuilder.GetUserAgent(request.UseSimplifiedUserAgent); - webRequest.KeepAlive = request.ConnectionKeepAlive; - webRequest.AllowAutoRedirect = false; - webRequest.CookieContainer = cookies; - - if (request.RequestTimeout != TimeSpan.Zero) + var cookieHeader = cookies.GetCookieHeader((Uri)request.Url); + if (cookieHeader.IsNotNullOrWhiteSpace()) { - webRequest.Timeout = (int)Math.Ceiling(request.RequestTimeout.TotalMilliseconds); + requestMessage.Headers.Add("Cookie", cookieHeader); } - webRequest.Proxy = request.Proxy ?? GetProxy(request.Url); + using var cts = new CancellationTokenSource(); + if (request.RequestTimeout != TimeSpan.Zero) + { + cts.CancelAfter(request.RequestTimeout); + } + else + { + // The default for System.Net.Http.HttpClient + cts.CancelAfter(TimeSpan.FromSeconds(100)); + } + + if (request.Credentials != null) + { + if (request.Credentials is BasicNetworkCredential bc) + { + // Manually set header to avoid initial challenge response + var authInfo = bc.UserName + ":" + bc.Password; + authInfo = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(authInfo)); + requestMessage.Headers.Add("Authorization", "Basic " + authInfo); + } + else if (request.Credentials is NetworkCredential nc) + { + var creds = GetCredentialCache(); + foreach (var authtype in new[] { "Basic", "Digest" }) + { + creds.Remove((Uri)request.Url, authtype); + creds.Add((Uri)request.Url, authtype, nc); + } + } + } + + if (request.ContentData != null) + { + requestMessage.Content = new ByteArrayContent(request.ContentData); + } if (request.Headers != null) { - AddRequestHeaders(webRequest, request.Headers); + AddRequestHeaders(requestMessage, request.Headers); } - HttpWebResponse httpWebResponse; + var httpClient = GetClient(request.Url); var sw = new Stopwatch(); sw.Start(); - try + using var responseMessage = await httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, cts.Token); { - if (request.ContentData != null) - { - webRequest.ContentLength = request.ContentData.Length; - using (var writeStream = webRequest.GetRequestStream()) - { - writeStream.Write(request.ContentData, 0, request.ContentData.Length); - } - } + byte[] data = null; - httpWebResponse = (HttpWebResponse)await webRequest.GetResponseAsync(); - } - catch (WebException e) - { - httpWebResponse = (HttpWebResponse)e.Response; - - if (httpWebResponse == null) + try { - // The default messages for WebException on mono are pretty horrible. - if (e.Status == WebExceptionStatus.NameResolutionFailure) + if (request.ResponseStream != null && responseMessage.StatusCode == HttpStatusCode.OK) { - throw new WebException($"DNS Name Resolution Failure: '{webRequest.RequestUri.Host}'", e.Status); - } - else if (e.ToString().Contains("TLS Support not")) - { - throw new TlsFailureException(webRequest, e); - } - else if (e.ToString().Contains("The authentication or decryption has failed.")) - { - throw new TlsFailureException(webRequest, e); - } - else if (OsInfo.IsNotWindows) - { - throw new WebException($"{e.Message}: '{webRequest.RequestUri}'", e, e.Status, e.Response); + responseMessage.Content.CopyTo(request.ResponseStream, null, cts.Token); } else { - throw; + data = responseMessage.Content.ReadAsByteArrayAsync(cts.Token).GetAwaiter().GetResult(); } } - } - - byte[] data = null; - - using (var responseStream = httpWebResponse.GetResponseStream()) - { - if (responseStream != null && responseStream != Stream.Null) + catch (Exception ex) { - try + throw new WebException("Failed to read complete http response", ex, WebExceptionStatus.ReceiveFailure, null); + } + + var headers = responseMessage.Headers.ToNameValueCollection(); + + headers.Add(responseMessage.Content.Headers.ToNameValueCollection()); + + CookieContainer responseCookies = new CookieContainer(); + + if (responseMessage.Headers.TryGetValues("Set-Cookie", out var cookieHeaders)) + { + foreach (var responseCookieHeader in cookieHeaders) { - data = await responseStream.ToBytes(); - } - catch (Exception ex) - { - throw new WebException("Failed to read complete http response", ex, WebExceptionStatus.ReceiveFailure, httpWebResponse); + try + { + cookies.SetCookies(responseMessage.RequestMessage.RequestUri, responseCookieHeader); + } + catch + { + // Ignore invalid cookies + } } } - } - sw.Stop(); + var cookieCollection = cookies.GetCookies(responseMessage.RequestMessage.RequestUri); - return new HttpResponse(request, new HttpHeader(httpWebResponse.Headers), httpWebResponse.Cookies, data, sw.ElapsedMilliseconds, httpWebResponse.StatusCode); - } + sw.Stop(); - public async Task DownloadFileAsync(string url, string fileName) - { - try - { - var fileInfo = new FileInfo(fileName); - if (fileInfo.Directory != null && !fileInfo.Directory.Exists) - { - fileInfo.Directory.Create(); - } - - _logger.Debug("Downloading [{0}] to [{1}]", url, fileName); - - var stopWatch = Stopwatch.StartNew(); - var uri = new HttpUri(url); - - using (var webClient = new GZipWebClient()) - { - webClient.Headers.Add(HttpRequestHeader.UserAgent, _userAgentBuilder.GetUserAgent()); - webClient.Proxy = GetProxy(uri); - await webClient.DownloadFileTaskAsync(url, fileName); - stopWatch.Stop(); - _logger.Debug("Downloading Completed. took {0:0}s", stopWatch.Elapsed.Seconds); - } - } - catch (WebException e) - { - _logger.Warn("Failed to get response from: {0} {1}", url, e.Message); - - if (File.Exists(fileName)) - { - File.Delete(fileName); - } - - throw; - } - catch (Exception e) - { - _logger.Warn(e, "Failed to get response from: " + url); - - if (File.Exists(fileName)) - { - File.Delete(fileName); - } - - throw; + return new HttpResponse(request, new HttpHeader(headers), cookieCollection, data, sw.ElapsedMilliseconds, responseMessage.StatusCode); } } - protected virtual IWebProxy GetProxy(HttpUri uri) + protected virtual System.Net.Http.HttpClient GetClient(HttpUri uri) { - IWebProxy proxy = null; - var proxySettings = _proxySettingsProvider.GetProxySettings(uri); + var key = proxySettings?.Key ?? NO_PROXY_KEY; + + return _httpClientCache.Get(key, () => CreateHttpClient(proxySettings)); + } + + protected virtual System.Net.Http.HttpClient CreateHttpClient(HttpProxySettings proxySettings) + { + var handler = new SocketsHttpHandler() + { + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Brotli, + UseCookies = false, // sic - we don't want to use a shared cookie container + AllowAutoRedirect = false, + Credentials = GetCredentialCache(), + PreAuthenticate = true, + MaxConnectionsPerServer = 12, + ConnectCallback = onConnect, + SslOptions = new SslClientAuthenticationOptions + { + RemoteCertificateValidationCallback = _certificateValidationService.ShouldByPassValidationError + } + }; + if (proxySettings != null) { - proxy = _createManagedWebProxy.GetWebProxy(proxySettings); + handler.Proxy = _createManagedWebProxy.GetWebProxy(proxySettings); } - return proxy; + var client = new System.Net.Http.HttpClient(handler) + { + Timeout = Timeout.InfiniteTimeSpan + }; + + return client; } - protected virtual void AddRequestHeaders(HttpWebRequest webRequest, HttpHeader headers) + protected virtual void AddRequestHeaders(HttpRequestMessage webRequest, HttpHeader headers) { foreach (var header in headers) { switch (header.Key) { case "Accept": - webRequest.Accept = header.Value; + webRequest.Headers.Accept.ParseAdd(header.Value); break; case "Connection": - webRequest.Connection = header.Value; + webRequest.Headers.Connection.Clear(); + webRequest.Headers.Connection.Add(header.Value); break; case "Content-Length": - webRequest.ContentLength = Convert.ToInt64(header.Value); + AddContentHeader(webRequest, "Content-Length", header.Value); break; case "Content-Type": - webRequest.ContentType = header.Value; + AddContentHeader(webRequest, "Content-Type", header.Value); break; case "Date": - webRequest.Date = HttpHeader.ParseDateTime(header.Value); + webRequest.Headers.Remove("Date"); + webRequest.Headers.Date = HttpHeader.ParseDateTime(header.Value); break; case "Expect": - webRequest.Expect = header.Value; + webRequest.Headers.Expect.ParseAdd(header.Value); break; case "Host": - webRequest.Host = header.Value; + webRequest.Headers.Host = header.Value; break; case "If-Modified-Since": - webRequest.IfModifiedSince = HttpHeader.ParseDateTime(header.Value); + webRequest.Headers.IfModifiedSince = HttpHeader.ParseDateTime(header.Value); break; case "Range": throw new NotImplementedException(); case "Referer": - webRequest.Referer = header.Value; + webRequest.Headers.Add("Referer", header.Value); break; case "Transfer-Encoding": - webRequest.TransferEncoding = header.Value; + webRequest.Headers.TransferEncoding.ParseAdd(header.Value); break; case "User-Agent": - webRequest.UserAgent = header.Value; + webRequest.Headers.UserAgent.ParseAdd(header.Value); break; case "Proxy-Connection": throw new NotImplementedException(); @@ -239,5 +244,84 @@ namespace NzbDrone.Common.Http.Dispatchers } } } + + private void AddContentHeader(HttpRequestMessage request, string header, string value) + { + var headers = request.Content?.Headers; + if (headers == null) + { + return; + } + + headers.Remove(header); + headers.Add(header, value); + } + + private CredentialCache GetCredentialCache() + { + return _credentialCache.Get("credentialCache", () => new CredentialCache()); + } + + private static async ValueTask<Stream> onConnect(SocketsHttpConnectionContext context, CancellationToken cancellationToken) + { + // Until .NET supports an implementation of Happy Eyeballs (https://tools.ietf.org/html/rfc8305#section-2), let's make IPv4 fallback work in a simple way. + // This issue is being tracked at https://github.com/dotnet/runtime/issues/26177 and expected to be fixed in .NET 6. + if (useIPv6) + { + try + { + var localToken = cancellationToken; + + if (!hasResolvedIPv6Availability) + { + // to make things move fast, use a very low timeout for the initial ipv6 attempt. + var quickFailCts = new CancellationTokenSource(connection_establish_timeout); + var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, quickFailCts.Token); + + localToken = linkedTokenSource.Token; + } + + return await attemptConnection(AddressFamily.InterNetworkV6, context, localToken); + } + catch + { + // very naively fallback to ipv4 permanently for this execution based on the response of the first connection attempt. + // note that this may cause users to eventually get switched to ipv4 (on a random failure when they are switching networks, for instance) + // but in the interest of keeping this implementation simple, this is acceptable. + useIPv6 = false; + } + finally + { + hasResolvedIPv6Availability = true; + } + } + + // fallback to IPv4. + return await attemptConnection(AddressFamily.InterNetwork, context, cancellationToken); + } + + private static async ValueTask<Stream> attemptConnection(AddressFamily addressFamily, SocketsHttpConnectionContext context, CancellationToken cancellationToken) + { + // The following socket constructor will create a dual-mode socket on systems where IPV6 is available. + var socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp) + { + // Turn off Nagle's algorithm since it degrades performance in most HttpClient scenarios. + NoDelay = true + }; + + try + { + await socket.ConnectAsync(context.DnsEndPoint, cancellationToken).ConfigureAwait(false); + + // The stream should take the ownership of the underlying socket, + // closing it when it's disposed. + return new NetworkStream(socket, ownsSocket: true); + } + catch + { + socket.Dispose(); + throw; + } + } } } diff --git a/src/NzbDrone.Common/Http/GZipWebClient.cs b/src/NzbDrone.Common/Http/GZipWebClient.cs deleted file mode 100644 index 191bfb10b..000000000 --- a/src/NzbDrone.Common/Http/GZipWebClient.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Net; - -namespace NzbDrone.Common.Http -{ - public class GZipWebClient : WebClient - { - protected override WebRequest GetWebRequest(Uri address) - { - var request = (HttpWebRequest)base.GetWebRequest(address); - request.AutomaticDecompression = DecompressionMethods.GZip; - return request; - } - } -} diff --git a/src/NzbDrone.Common/Http/HttpClient.cs b/src/NzbDrone.Common/Http/HttpClient.cs index 7be59b663..6fb27fbb3 100644 --- a/src/NzbDrone.Common/Http/HttpClient.cs +++ b/src/NzbDrone.Common/Http/HttpClient.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; using System.Net; using System.Net.Http; @@ -86,13 +87,21 @@ namespace NzbDrone.Common.Http } // 302 or 303 should default to GET on redirect even if POST on original - if (response.StatusCode == HttpStatusCode.Redirect || response.StatusCode == HttpStatusCode.RedirectMethod) + if (RequestRequiresForceGet(response.StatusCode, response.Request.Method)) { request.Method = HttpMethod.Get; request.ContentData = null; } - response = await ExecuteRequestAsync(request, cookieContainer); + // Save to add to final response + var responseCookies = response.Cookies; + + // Update cookiecontainer for next request with any cookies recieved on last request + var responseContainer = HandleRedirectCookies(request, response); + + response = await ExecuteRequestAsync(request, responseContainer); + + response.Cookies.Add(responseCookies); } while (response.HasHttpRedirect); } @@ -102,9 +111,12 @@ namespace NzbDrone.Common.Http _logger.Error("Server requested a redirect to [{0}] while in developer mode. Update the request URL to avoid this redirect.", response.Headers["Location"]); } - if (!request.SuppressHttpError && response.HasHttpError) + if (!request.SuppressHttpError && response.HasHttpError && (request.SuppressHttpErrorStatusCodes == null || !request.SuppressHttpErrorStatusCodes.Contains(response.StatusCode))) { - _logger.Warn("HTTP Error - {0}", response); + if (request.LogHttpError) + { + _logger.Warn("HTTP Error - {0}", response); + } if ((int)response.StatusCode == 429) { @@ -124,6 +136,21 @@ namespace NzbDrone.Common.Http return ExecuteAsync(request).GetAwaiter().GetResult(); } + private static bool RequestRequiresForceGet(HttpStatusCode statusCode, HttpMethod requestMethod) + { + switch (statusCode) + { + case HttpStatusCode.Moved: + case HttpStatusCode.Found: + case HttpStatusCode.MultipleChoices: + return requestMethod == HttpMethod.Post; + case HttpStatusCode.SeeOther: + return requestMethod != HttpMethod.Get && requestMethod != HttpMethod.Head; + default: + return false; + } + } + private async Task<HttpResponse> ExecuteRequestAsync(HttpRequest request, CookieContainer cookieContainer) { foreach (var interceptor in _requestInterceptors) @@ -140,8 +167,6 @@ namespace NzbDrone.Common.Http var stopWatch = Stopwatch.StartNew(); - PrepareRequestCookies(request, cookieContainer); - var response = await _httpDispatcher.GetResponseAsync(request, cookieContainer); HandleResponseCookies(response, cookieContainer); @@ -208,52 +233,125 @@ namespace NzbDrone.Common.Http } } - private void PrepareRequestCookies(HttpRequest request, CookieContainer cookieContainer) + private CookieContainer HandleRedirectCookies(HttpRequest request, HttpResponse response) { - // Don't collect persistnet cookies for intermediate/redirected urls. - /*lock (_cookieContainerCache) + var sourceContainer = new CookieContainer(); + var responseCookies = response.GetCookies(); + if (responseCookies.Count != 0) { - var presistentContainer = _cookieContainerCache.Get("container", () => new CookieContainer()); - var persistentCookies = presistentContainer.GetCookies((Uri)request.Url); - var existingCookies = cookieContainer.GetCookies((Uri)request.Url); + foreach (var pair in responseCookies) + { + Cookie cookie; + if (pair.Value == null) + { + cookie = new Cookie(pair.Key, "", "/") + { + Expires = DateTime.Now.AddDays(-1) + }; + } + else + { + cookie = new Cookie(pair.Key, pair.Value, "/") + { + // Use Now rather than UtcNow to work around Mono cookie expiry bug. + // See https://gist.github.com/ta264/7822b1424f72e5b4c961 + Expires = DateTime.Now.AddHours(1) + }; + } - cookieContainer.Add(persistentCookies); - cookieContainer.Add(existingCookies); - }*/ + sourceContainer.Add((Uri)request.Url, cookie); + } + } + + return sourceContainer; } - private void HandleResponseCookies(HttpResponse response, CookieContainer cookieContainer) + private void HandleResponseCookies(HttpResponse response, CookieContainer container) { + foreach (Cookie cookie in container.GetAllCookies()) + { + cookie.Expired = true; + } + var cookieHeaders = response.GetCookieHeaders(); if (cookieHeaders.Empty()) { return; } + AddCookiesToContainer(response.Request.Url, cookieHeaders, container); + if (response.Request.StoreResponseCookie) { lock (_cookieContainerCache) { var persistentCookieContainer = _cookieContainerCache.Get("container", () => new CookieContainer()); - foreach (var cookieHeader in cookieHeaders) - { - try - { - persistentCookieContainer.SetCookies((Uri)response.Request.Url, cookieHeader); - } - catch (Exception ex) - { - _logger.Debug(ex, "Invalid cookie in {0}", response.Request.Url); - } - } + AddCookiesToContainer(response.Request.Url, cookieHeaders, persistentCookieContainer); + } + } + } + + private void AddCookiesToContainer(HttpUri url, string[] cookieHeaders, CookieContainer container) + { + foreach (var cookieHeader in cookieHeaders) + { + try + { + container.SetCookies((Uri)url, cookieHeader); + } + catch (Exception ex) + { + _logger.Debug(ex, "Invalid cookie in {0}", url); } } } public async Task DownloadFileAsync(string url, string fileName) { - await _httpDispatcher.DownloadFileAsync(url, fileName); + var fileNamePart = fileName + ".part"; + + try + { + var fileInfo = new FileInfo(fileName); + if (fileInfo.Directory != null && !fileInfo.Directory.Exists) + { + fileInfo.Directory.Create(); + } + + _logger.Debug("Downloading [{0}] to [{1}]", url, fileName); + + var stopWatch = Stopwatch.StartNew(); + using (var fileStream = new FileStream(fileNamePart, FileMode.Create, FileAccess.ReadWrite)) + { + var request = new HttpRequest(url); + request.AllowAutoRedirect = true; + request.ResponseStream = fileStream; + var response = await GetAsync(request); + + if (response.Headers.ContentType != null && response.Headers.ContentType.Contains("text/html")) + { + throw new HttpException(request, response, "Site responded with html content."); + } + } + + stopWatch.Stop(); + + if (File.Exists(fileName)) + { + File.Delete(fileName); + } + + File.Move(fileNamePart, fileName); + _logger.Debug("Downloading Completed. took {0:0}s", stopWatch.Elapsed.Seconds); + } + finally + { + if (File.Exists(fileNamePart)) + { + File.Delete(fileNamePart); + } + } } public void DownloadFile(string url, string fileName) diff --git a/src/NzbDrone.Common/Http/HttpHeader.cs b/src/NzbDrone.Common/Http/HttpHeader.cs index b78e27460..a5047f4b6 100644 --- a/src/NzbDrone.Common/Http/HttpHeader.cs +++ b/src/NzbDrone.Common/Http/HttpHeader.cs @@ -4,11 +4,27 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Globalization; using System.Linq; +using System.Net; +using System.Net.Http.Headers; using System.Text; using NzbDrone.Common.Extensions; namespace NzbDrone.Common.Http { + public static class WebHeaderCollectionExtensions + { + public static NameValueCollection ToNameValueCollection(this HttpHeaders headers) + { + var result = new NameValueCollection(); + foreach (var header in headers) + { + result.Add(header.Key, header.Value.ConcatToString(";")); + } + + return result; + } + } + public class HttpHeader : NameValueCollection, IEnumerable<KeyValuePair<string, string>>, IEnumerable { public HttpHeader(NameValueCollection headers) @@ -16,6 +32,11 @@ namespace NzbDrone.Common.Http { } + public HttpHeader(HttpHeaders headers) + : base(headers.ToNameValueCollection()) + { + } + public HttpHeader() { } diff --git a/src/NzbDrone.Common/Http/HttpRequest.cs b/src/NzbDrone.Common/Http/HttpRequest.cs index 4a0b7a85a..5092207bc 100644 --- a/src/NzbDrone.Common/Http/HttpRequest.cs +++ b/src/NzbDrone.Common/Http/HttpRequest.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Net; using System.Net.Http; using System.Text; @@ -12,11 +13,13 @@ namespace NzbDrone.Common.Http { public HttpRequest(string url, HttpAccept httpAccept = null) { + Method = HttpMethod.Get; Url = new HttpUri(url); Headers = new HttpHeader(); Method = HttpMethod.Get; ConnectionKeepAlive = true; AllowAutoRedirect = true; + LogHttpError = true; Cookies = new Dictionary<string, string>(); if (!RuntimeInfo.IsProduction) @@ -37,16 +40,20 @@ namespace NzbDrone.Common.Http public IWebProxy Proxy { get; set; } public byte[] ContentData { get; set; } public string ContentSummary { get; set; } + public ICredentials Credentials { get; set; } public bool SuppressHttpError { get; set; } + public IEnumerable<HttpStatusCode> SuppressHttpErrorStatusCodes { get; set; } public bool UseSimplifiedUserAgent { get; set; } public bool AllowAutoRedirect { get; set; } public bool ConnectionKeepAlive { get; set; } public bool LogResponseContent { get; set; } + public bool LogHttpError { get; set; } public Dictionary<string, string> Cookies { get; private set; } public bool StoreRequestCookie { get; set; } public bool StoreResponseCookie { get; set; } public TimeSpan RequestTimeout { get; set; } public TimeSpan RateLimit { get; set; } + public Stream ResponseStream { get; set; } public override string ToString() { @@ -103,12 +110,5 @@ namespace NzbDrone.Common.Http return encoding.GetString(ContentData); } } - - public void AddBasicAuthentication(string username, string password) - { - var authInfo = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes($"{username}:{password}")); - - Headers.Set("Authorization", "Basic " + authInfo); - } } } diff --git a/src/NzbDrone.Common/Http/HttpRequestBuilder.cs b/src/NzbDrone.Common/Http/HttpRequestBuilder.cs index 86b40b319..7d75291b3 100644 --- a/src/NzbDrone.Common/Http/HttpRequestBuilder.cs +++ b/src/NzbDrone.Common/Http/HttpRequestBuilder.cs @@ -21,12 +21,13 @@ namespace NzbDrone.Common.Http public Dictionary<string, string> Segments { get; private set; } public HttpHeader Headers { get; private set; } public bool SuppressHttpError { get; set; } + public bool LogHttpError { get; set; } public bool UseSimplifiedUserAgent { get; set; } public bool AllowAutoRedirect { get; set; } public bool ConnectionKeepAlive { get; set; } public TimeSpan RateLimit { get; set; } public bool LogResponseContent { get; set; } - public NetworkCredential NetworkCredential { get; set; } + public ICredentials NetworkCredential { get; set; } public Dictionary<string, string> Cookies { get; private set; } public bool StoreRequestCookie { get; set; } public bool StoreResponseCookie { get; set; } @@ -46,6 +47,7 @@ namespace NzbDrone.Common.Http Headers = new HttpHeader(); Cookies = new Dictionary<string, string>(); FormData = new List<HttpFormData>(); + LogHttpError = true; } public HttpRequestBuilder(bool useHttps, string host, int port, string urlBase = null) @@ -106,6 +108,7 @@ namespace NzbDrone.Common.Http request.Method = Method; request.Encoding = Encoding; request.SuppressHttpError = SuppressHttpError; + request.LogHttpError = LogHttpError; request.UseSimplifiedUserAgent = UseSimplifiedUserAgent; request.AllowAutoRedirect = AllowAutoRedirect; request.StoreRequestCookie = StoreRequestCookie; @@ -113,13 +116,7 @@ namespace NzbDrone.Common.Http request.ConnectionKeepAlive = ConnectionKeepAlive; request.RateLimit = RateLimit; request.LogResponseContent = LogResponseContent; - - if (NetworkCredential != null) - { - var authInfo = NetworkCredential.UserName + ":" + NetworkCredential.Password; - authInfo = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(authInfo)); - request.Headers.Set("Authorization", "Basic " + authInfo); - } + request.Credentials = NetworkCredential; foreach (var header in Headers) { diff --git a/src/NzbDrone.Common/Http/HttpResponse.cs b/src/NzbDrone.Common/Http/HttpResponse.cs index 819b3b805..c92444d76 100644 --- a/src/NzbDrone.Common/Http/HttpResponse.cs +++ b/src/NzbDrone.Common/Http/HttpResponse.cs @@ -64,10 +64,11 @@ namespace NzbDrone.Common.Http public bool HasHttpError => (int)StatusCode >= 400; public bool HasHttpRedirect => StatusCode == HttpStatusCode.Moved || - StatusCode == HttpStatusCode.MovedPermanently || - StatusCode == HttpStatusCode.RedirectMethod || - StatusCode == HttpStatusCode.TemporaryRedirect || StatusCode == HttpStatusCode.Found || + StatusCode == HttpStatusCode.SeeOther || + StatusCode == HttpStatusCode.TemporaryRedirect || + StatusCode == HttpStatusCode.MultipleChoices || + StatusCode == HttpStatusCode.PermanentRedirect || Headers.ContainsKey("Refresh"); public string RedirectUrl @@ -117,7 +118,7 @@ namespace NzbDrone.Common.Http public override string ToString() { - var result = string.Format("Res: [{0}] {1}: {2}.{3}", Request.Method, Request.Url, (int)StatusCode, StatusCode); + var result = string.Format("Res: [{0}] {1}: {2}.{3} ({4} bytes)", Request.Method, Request.Url, (int)StatusCode, StatusCode, ResponseData?.Length ?? 0); if (HasHttpError && Headers.ContentType.IsNotNullOrWhiteSpace() && !Headers.ContentType.Equals("text/html", StringComparison.InvariantCultureIgnoreCase)) { diff --git a/src/NzbDrone.Common/Http/XmlRpcRequestBuilder.cs b/src/NzbDrone.Common/Http/XmlRpcRequestBuilder.cs new file mode 100644 index 000000000..e03161702 --- /dev/null +++ b/src/NzbDrone.Common/Http/XmlRpcRequestBuilder.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Xml.Linq; +using NLog; +using NzbDrone.Common.Instrumentation; + +namespace NzbDrone.Common.Http +{ + public class XmlRpcRequestBuilder : HttpRequestBuilder + { + public static string XmlRpcContentType = "text/xml"; + + private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(XmlRpcRequestBuilder)); + + public string XmlMethod { get; private set; } + public List<object> XmlParameters { get; private set; } + + public XmlRpcRequestBuilder(string baseUrl) + : base(baseUrl) + { + Method = HttpMethod.Post; + XmlParameters = new List<object>(); + } + + public XmlRpcRequestBuilder(bool useHttps, string host, int port, string urlBase = null) + : this(BuildBaseUrl(useHttps, host, port, urlBase)) + { + } + + public override HttpRequestBuilder Clone() + { + var clone = base.Clone() as XmlRpcRequestBuilder; + clone.XmlParameters = new List<object>(XmlParameters); + return clone; + } + + public XmlRpcRequestBuilder Call(string method, params object[] parameters) + { + var clone = Clone() as XmlRpcRequestBuilder; + clone.XmlMethod = method; + clone.XmlParameters = parameters.ToList(); + return clone; + } + + protected override void Apply(HttpRequest request) + { + base.Apply(request); + + request.Headers.ContentType = XmlRpcContentType; + + var methodCallElements = new List<XElement> { new XElement("methodName", XmlMethod) }; + + if (XmlParameters.Any()) + { + var argElements = XmlParameters.Select(x => new XElement("param", ConvertParameter(x))).ToList(); + var paramsElement = new XElement("params", argElements); + methodCallElements.Add(paramsElement); + } + + var message = new XDocument( + new XDeclaration("1.0", "utf-8", "yes"), + new XElement("methodCall", methodCallElements)); + + var body = message.ToString(); + + Logger.Debug($"Executing remote method: {XmlMethod}"); + + Logger.Trace($"methodCall {XmlMethod} body:\n{body}"); + + request.SetContent(body); + } + + private static XElement ConvertParameter(object value) + { + XElement data; + + if (value is string s) + { + data = new XElement("string", s); + } + else if (value is List<string> l) + { + data = new XElement("array", new XElement("data", l.Select(x => new XElement("value", new XElement("string", x))))); + } + else if (value is int i) + { + data = new XElement("int", i); + } + else if (value is byte[] bytes) + { + data = new XElement("base64", Convert.ToBase64String(bytes)); + } + else + { + throw new InvalidOperationException($"Unhandled argument type {value.GetType().Name}"); + } + + return new XElement("value", data); + } + } +} diff --git a/src/NzbDrone.Core.Test/Framework/CoreTest.cs b/src/NzbDrone.Core.Test/Framework/CoreTest.cs index 9da38329f..ef5202734 100644 --- a/src/NzbDrone.Core.Test/Framework/CoreTest.cs +++ b/src/NzbDrone.Core.Test/Framework/CoreTest.cs @@ -11,6 +11,7 @@ using NzbDrone.Common.TPL; using NzbDrone.Core.Configuration; using NzbDrone.Core.Http; using NzbDrone.Core.Parser; +using NzbDrone.Core.Security; using NzbDrone.Test.Common; namespace NzbDrone.Core.Test.Framework @@ -25,7 +26,8 @@ namespace NzbDrone.Core.Test.Framework Mocker.SetConstant<IHttpProxySettingsProvider>(new HttpProxySettingsProvider(Mocker.Resolve<ConfigService>())); Mocker.SetConstant<ICreateManagedWebProxy>(new ManagedWebProxyFactory(Mocker.Resolve<CacheManager>())); - Mocker.SetConstant<IHttpDispatcher>(new ManagedHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<ICreateManagedWebProxy>(), Mocker.Resolve<UserAgentBuilder>(), Mocker.Resolve<IPlatformInfo>(), TestLogger)); + Mocker.SetConstant<ICertificateValidationService>(new X509CertificateValidationService(Mocker.Resolve<ConfigService>(), TestLogger)); + Mocker.SetConstant<IHttpDispatcher>(new ManagedHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<ICreateManagedWebProxy>(), Mocker.Resolve<ICertificateValidationService>(), Mocker.Resolve<UserAgentBuilder>(), Mocker.Resolve<CacheManager>())); Mocker.SetConstant<IHttpClient>(new HttpClient(Array.Empty<IHttpRequestInterceptor>(), Mocker.Resolve<CacheManager>(), Mocker.Resolve<RateLimitService>(), Mocker.Resolve<IHttpDispatcher>(), TestLogger)); Mocker.SetConstant<IProwlarrCloudRequestBuilder>(new ProwlarrCloudRequestBuilder()); } diff --git a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Containers.cs b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Containers.cs index d4ab5a49c..24122b65c 100644 --- a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Containers.cs +++ b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Containers.cs @@ -1,111 +1,161 @@ -using CookComputing.XmlRpc; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using System.Xml.XPath; +using NzbDrone.Core.Download.Extensions; namespace NzbDrone.Core.Download.Clients.Aria2 { - public class Aria2Version + public class Aria2Fault { - [XmlRpcMember("version")] - public string Version; + public Aria2Fault(XElement element) + { + foreach (var e in element.XPathSelectElements("./value/struct/member")) + { + var name = e.ElementAsString("name"); + if (name == "faultCode") + { + FaultCode = e.Element("value").ElementAsInt("int"); + } + else if (name == "faultString") + { + FaultString = e.Element("value").GetStringValue(); + } + } + } - [XmlRpcMember("enabledFeatures")] - public string[] EnabledFeatures; + public int FaultCode { get; set; } + public string FaultString { get; set; } } - public class Aria2Uri + public class Aria2Version { - [XmlRpcMember("status")] - public string Status; + public Aria2Version(XElement element) + { + foreach (var e in element.XPathSelectElements("./struct/member")) + { + if (e.ElementAsString("name") == "version") + { + Version = e.Element("value").GetStringValue(); + } + } + } - [XmlRpcMember("uri")] - public string Uri; + public string Version { get; set; } } public class Aria2File { - [XmlRpcMember("index")] - public string Index; + public Aria2File(XElement element) + { + foreach (var e in element.XPathSelectElements("./struct/member")) + { + var name = e.ElementAsString("name"); - [XmlRpcMember("length")] - public string Length; + if (name == "path") + { + Path = e.Element("value").GetStringValue(); + } + } + } - [XmlRpcMember("completedLength")] - public string CompletedLength; + public string Path { get; set; } + } - [XmlRpcMember("path")] - public string Path; + public class Aria2Dict + { + public Aria2Dict(XElement element) + { + Dict = new Dictionary<string, string>(); - [XmlRpcMember("selected")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public string Selected; + foreach (var e in element.XPathSelectElements("./struct/member")) + { + Dict.Add(e.ElementAsString("name"), e.Element("value").GetStringValue()); + } + } - [XmlRpcMember("uris")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public Aria2Uri[] Uris; + public Dictionary<string, string> Dict { get; set; } + } + + public class Aria2Bittorrent + { + public Aria2Bittorrent(XElement element) + { + foreach (var e in element.Descendants("member")) + { + if (e.ElementAsString("name") == "name") + { + Name = e.Element("value").GetStringValue(); + } + } + } + + public string Name; } public class Aria2Status { - [XmlRpcMember("bittorrent")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public XmlRpcStruct Bittorrent; + public Aria2Status(XElement element) + { + foreach (var e in element.XPathSelectElements("./struct/member")) + { + var name = e.ElementAsString("name"); - [XmlRpcMember("bitfield")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public string Bitfield; + if (name == "bittorrent") + { + Bittorrent = new Aria2Bittorrent(e.Element("value")); + } + else if (name == "infoHash") + { + InfoHash = e.Element("value").GetStringValue(); + } + else if (name == "completedLength") + { + CompletedLength = e.Element("value").GetStringValue(); + } + else if (name == "downloadSpeed") + { + DownloadSpeed = e.Element("value").GetStringValue(); + } + else if (name == "files") + { + Files = e.XPathSelectElement("./value/array/data") + .Elements() + .Select(x => new Aria2File(x)) + .ToArray(); + } + else if (name == "gid") + { + Gid = e.Element("value").GetStringValue(); + } + else if (name == "status") + { + Status = e.Element("value").GetStringValue(); + } + else if (name == "totalLength") + { + TotalLength = e.Element("value").GetStringValue(); + } + else if (name == "uploadLength") + { + UploadLength = e.Element("value").GetStringValue(); + } + else if (name == "errorMessage") + { + ErrorMessage = e.Element("value").GetStringValue(); + } + } + } - [XmlRpcMember("infoHash")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public string InfoHash; - - [XmlRpcMember("completedLength")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public string CompletedLength; - - [XmlRpcMember("connections")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public string Connections; - - [XmlRpcMember("dir")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public string Dir; - - [XmlRpcMember("downloadSpeed")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public string DownloadSpeed; - - [XmlRpcMember("files")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public Aria2File[] Files; - - [XmlRpcMember("gid")] - public string Gid; - - [XmlRpcMember("numPieces")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public string NumPieces; - - [XmlRpcMember("pieceLength")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public string PieceLength; - - [XmlRpcMember("status")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public string Status; - - [XmlRpcMember("totalLength")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public string TotalLength; - - [XmlRpcMember("uploadLength")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public string UploadLength; - - [XmlRpcMember("uploadSpeed")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public string UploadSpeed; - - [XmlRpcMember("errorMessage")] - [XmlRpcMissingMapping(MappingAction.Ignore)] - public string ErrorMessage; + public Aria2Bittorrent Bittorrent { get; set; } + public string InfoHash { get; set; } + public string CompletedLength { get; set; } + public string DownloadSpeed { get; set; } + public Aria2File[] Files { get; set; } + public string Gid { get; set; } + public string Status { get; set; } + public string TotalLength { get; set; } + public string UploadLength { get; set; } + public string ErrorMessage { get; set; } } } diff --git a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Proxy.cs b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Proxy.cs index 855d300ba..9cc2d9793 100644 --- a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Proxy.cs +++ b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2Proxy.cs @@ -1,9 +1,9 @@ -using System; -using System.Collections; using System.Collections.Generic; -using System.Net; -using CookComputing.XmlRpc; -using NLog; +using System.Linq; +using System.Xml.Linq; +using System.Xml.XPath; +using NzbDrone.Common.Http; +using NzbDrone.Core.Download.Extensions; namespace NzbDrone.Core.Download.Clients.Aria2 { @@ -12,46 +12,103 @@ namespace NzbDrone.Core.Download.Clients.Aria2 string GetVersion(Aria2Settings settings); string AddUri(Aria2Settings settings, string magnet); string AddTorrent(Aria2Settings settings, byte[] torrent); + Dictionary<string, string> GetGlobals(Aria2Settings settings); + List<Aria2Status> GetTorrents(Aria2Settings settings); Aria2Status GetFromGID(Aria2Settings settings, string gid); } - public interface IAria2 : IXmlRpcProxy - { - [XmlRpcMethod("aria2.getVersion")] - Aria2Version GetVersion(string token); - - [XmlRpcMethod("aria2.addUri")] - string AddUri(string token, string[] uri); - - [XmlRpcMethod("aria2.addTorrent")] - string AddTorrent(string token, byte[] torrent); - - [XmlRpcMethod("aria2.forceRemove")] - string Remove(string token, string gid); - - [XmlRpcMethod("aria2.tellStatus")] - Aria2Status GetFromGid(string token, string gid); - - [XmlRpcMethod("aria2.getGlobalOption")] - XmlRpcStruct GetGlobalOption(string token); - - [XmlRpcMethod("aria2.tellActive")] - Aria2Status[] GetActives(string token); - - [XmlRpcMethod("aria2.tellWaiting")] - Aria2Status[] GetWaitings(string token, int offset, int num); - - [XmlRpcMethod("aria2.tellStopped")] - Aria2Status[] GetStoppeds(string token, int offset, int num); - } - public class Aria2Proxy : IAria2Proxy { - private readonly Logger _logger; + private readonly IHttpClient _httpClient; - public Aria2Proxy(Logger logger) + public Aria2Proxy(IHttpClient httpClient) { - _logger = logger; + _httpClient = httpClient; + } + + public string GetVersion(Aria2Settings settings) + { + var response = ExecuteRequest(settings, "aria2.getVersion", GetToken(settings)); + + var element = response.XPathSelectElement("./methodResponse/params/param/value"); + + var version = new Aria2Version(element); + + return version.Version; + } + + public Aria2Status GetFromGID(Aria2Settings settings, string gid) + { + var response = ExecuteRequest(settings, "aria2.tellStatus", GetToken(settings), gid); + + var element = response.XPathSelectElement("./methodResponse/params/param/value"); + + return new Aria2Status(element); + } + + private List<Aria2Status> GetTorrentsMethod(Aria2Settings settings, string method, params object[] args) + { + var allArgs = new List<object> { GetToken(settings) }; + if (args.Any()) + { + allArgs.AddRange(args); + } + + var response = ExecuteRequest(settings, method, allArgs.ToArray()); + + var element = response.XPathSelectElement("./methodResponse/params/param/value/array/data"); + + var torrents = element?.Elements() + .Select(x => new Aria2Status(x)) + .ToList() + ?? new List<Aria2Status>(); + return torrents; + } + + public List<Aria2Status> GetTorrents(Aria2Settings settings) + { + var active = GetTorrentsMethod(settings, "aria2.tellActive"); + + var waiting = GetTorrentsMethod(settings, "aria2.tellWaiting", 0, 10 * 1024); + + var stopped = GetTorrentsMethod(settings, "aria2.tellStopped", 0, 10 * 1024); + + var items = new List<Aria2Status>(); + + items.AddRange(active); + items.AddRange(waiting); + items.AddRange(stopped); + + return items; + } + + public Dictionary<string, string> GetGlobals(Aria2Settings settings) + { + var response = ExecuteRequest(settings, "aria2.getGlobalOption", GetToken(settings)); + + var element = response.XPathSelectElement("./methodResponse/params/param/value"); + + var result = new Aria2Dict(element); + + return result.Dict; + } + + public string AddUri(Aria2Settings settings, string magnet) + { + var response = ExecuteRequest(settings, "aria2.addUri", GetToken(settings), new List<string> { magnet }); + + var gid = response.GetStringResponse(); + + return gid; + } + + public string AddTorrent(Aria2Settings settings, byte[] torrent) + { + var response = ExecuteRequest(settings, "aria2.addTorrent", GetToken(settings), torrent); + + var gid = response.GetStringResponse(); + + return gid; } private string GetToken(Aria2Settings settings) @@ -59,86 +116,29 @@ namespace NzbDrone.Core.Download.Clients.Aria2 return $"token:{settings?.SecretToken}"; } - private string GetURL(Aria2Settings settings) + private XDocument ExecuteRequest(Aria2Settings settings, string methodName, params object[] args) { - return $"http{(settings.UseSsl ? "s" : "")}://{settings.Host}:{settings.Port}{settings.RpcPath}"; - } - - public string GetVersion(Aria2Settings settings) - { - _logger.Debug("> aria2.getVersion"); - - var client = BuildClient(settings); - var version = ExecuteRequest(() => client.GetVersion(GetToken(settings))); - - _logger.Debug("< aria2.getVersion"); - - return version.Version; - } - - public Aria2Status GetFromGID(Aria2Settings settings, string gid) - { - _logger.Debug("> aria2.tellStatus"); - - var client = BuildClient(settings); - var found = ExecuteRequest(() => client.GetFromGid(GetToken(settings), gid)); - - _logger.Debug("< aria2.tellStatus"); - - return found; - } - - public string AddUri(Aria2Settings settings, string magnet) - { - _logger.Debug("> aria2.addUri"); - - var client = BuildClient(settings); - var gid = ExecuteRequest(() => client.AddUri(GetToken(settings), new[] { magnet })); - - _logger.Debug("< aria2.addUri"); - - return gid; - } - - public string AddTorrent(Aria2Settings settings, byte[] torrent) - { - _logger.Debug("> aria2.addTorrent"); - - var client = BuildClient(settings); - var gid = ExecuteRequest(() => client.AddTorrent(GetToken(settings), torrent)); - - _logger.Debug("< aria2.addTorrent"); - - return gid; - } - - private IAria2 BuildClient(Aria2Settings settings) - { - var client = XmlRpcProxyGen.Create<IAria2>(); - client.Url = GetURL(settings); - - return client; - } - - private T ExecuteRequest<T>(Func<T> task) - { - try + var requestBuilder = new XmlRpcRequestBuilder(settings.UseSsl, settings.Host, settings.Port, settings.RpcPath) { - return task(); - } - catch (XmlRpcServerException ex) - { - throw new DownloadClientException("Unable to connect to aria2, please check your settings", ex); - } - catch (WebException ex) - { - if (ex.Status == WebExceptionStatus.TrustFailure) - { - throw new DownloadClientUnavailableException("Unable to connect to aria2, certificate validation failed.", ex); - } + LogResponseContent = true, + }; - throw new DownloadClientUnavailableException("Unable to connect to aria2, please check your settings", ex); + var request = requestBuilder.Call(methodName, args).Build(); + + var response = _httpClient.Execute(request); + + var doc = XDocument.Parse(response.Content); + + var faultElement = doc.XPathSelectElement("./methodResponse/fault"); + + if (faultElement != null) + { + var fault = new Aria2Fault(faultElement); + + throw new DownloadClientException($"Aria2 returned error code {fault.FaultCode}: {fault.FaultString}"); } + + return doc; } } } diff --git a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentFault.cs b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentFault.cs new file mode 100644 index 000000000..ba1a23962 --- /dev/null +++ b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentFault.cs @@ -0,0 +1,28 @@ +using System.Xml.Linq; +using System.Xml.XPath; +using NzbDrone.Core.Download.Extensions; + +namespace NzbDrone.Core.Download.Clients.RTorrent +{ + public class RTorrentFault + { + public RTorrentFault(XElement element) + { + foreach (var e in element.XPathSelectElements("./value/struct/member")) + { + var name = e.ElementAsString("name"); + if (name == "faultCode") + { + FaultCode = e.Element("value").GetIntValue(); + } + else if (name == "faultString") + { + FaultString = e.Element("value").GetStringValue(); + } + } + } + + public int FaultCode { get; set; } + public string FaultString { get; set; } + } +} diff --git a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentProxy.cs b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentProxy.cs index c7f72952f..fb32c0598 100644 --- a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentProxy.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Net; -using CookComputing.XmlRpc; -using NLog; +using System.Xml.Linq; +using System.Xml.XPath; using NzbDrone.Common.Extensions; -using NzbDrone.Common.Serializer; +using NzbDrone.Common.Http; +using NzbDrone.Core.Download.Extensions; namespace NzbDrone.Core.Download.Clients.RTorrent { @@ -18,122 +20,70 @@ namespace NzbDrone.Core.Download.Clients.RTorrent void RemoveTorrent(string hash, RTorrentSettings settings); void SetTorrentLabel(string hash, string label, RTorrentSettings settings); bool HasHashTorrent(string hash, RTorrentSettings settings); - } - - public interface IRTorrent : IXmlRpcProxy - { - [XmlRpcMethod("d.multicall2")] - object[] TorrentMulticall(params string[] parameters); - - [XmlRpcMethod("load.normal")] - int LoadNormal(string target, string data, params string[] commands); - - [XmlRpcMethod("load.start")] - int LoadStart(string target, string data, params string[] commands); - - [XmlRpcMethod("load.raw")] - int LoadRaw(string target, byte[] data, params string[] commands); - - [XmlRpcMethod("load.raw_start")] - int LoadRawStart(string target, byte[] data, params string[] commands); - - [XmlRpcMethod("d.erase")] - int Remove(string hash); - - [XmlRpcMethod("d.name")] - string GetName(string hash); - - [XmlRpcMethod("d.custom1.set")] - string SetLabel(string hash, string label); - - [XmlRpcMethod("system.client_version")] - string GetVersion(); + void PushTorrentUniqueView(string hash, string view, RTorrentSettings settings); } public class RTorrentProxy : IRTorrentProxy { - private readonly Logger _logger; + private readonly IHttpClient _httpClient; - public RTorrentProxy(Logger logger) + public RTorrentProxy(IHttpClient httpClient) { - _logger = logger; + _httpClient = httpClient; } public string GetVersion(RTorrentSettings settings) { - _logger.Debug("Executing remote method: system.client_version"); + var document = ExecuteRequest(settings, "system.client_version"); - var client = BuildClient(settings); - var version = ExecuteRequest(() => client.GetVersion()); - - return version; + return document.Descendants("string").FirstOrDefault()?.Value ?? "0.0.0"; } public List<RTorrentTorrent> GetTorrents(RTorrentSettings settings) { - _logger.Debug("Executing remote method: d.multicall2"); + var document = ExecuteRequest(settings, + "d.multicall2", + "", + "", + "d.name=", // string + "d.hash=", // string + "d.base_path=", // string + "d.custom1=", // string (label) + "d.size_bytes=", // long + "d.left_bytes=", // long + "d.down.rate=", // long (in bytes / s) + "d.ratio=", // long + "d.is_open=", // long + "d.is_active=", // long + "d.complete=", //long + "d.timestamp.finished="); // long (unix timestamp) - var client = BuildClient(settings); - var ret = ExecuteRequest(() => client.TorrentMulticall( - "", - "", - "d.name=", // string - "d.hash=", // string - "d.base_path=", // string - "d.custom1=", // string (label) - "d.size_bytes=", // long - "d.left_bytes=", // long - "d.down.rate=", // long (in bytes / s) - "d.ratio=", // long - "d.is_open=", // long - "d.is_active=", // long - "d.complete=")); //long + var torrents = document.XPathSelectElement("./methodResponse/params/param/value/array/data") + ?.Elements() + .Select(x => new RTorrentTorrent(x)) + .ToList() + ?? new List<RTorrentTorrent>(); - _logger.Trace(ret.ToJson()); - - var items = new List<RTorrentTorrent>(); - - foreach (object[] torrent in ret) - { - var labelDecoded = System.Web.HttpUtility.UrlDecode((string)torrent[3]); - - var item = new RTorrentTorrent(); - item.Name = (string)torrent[0]; - item.Hash = (string)torrent[1]; - item.Path = (string)torrent[2]; - item.Category = labelDecoded; - item.TotalSize = (long)torrent[4]; - item.RemainingSize = (long)torrent[5]; - item.DownRate = (long)torrent[6]; - item.Ratio = (long)torrent[7]; - item.IsOpen = Convert.ToBoolean((long)torrent[8]); - item.IsActive = Convert.ToBoolean((long)torrent[9]); - item.IsFinished = Convert.ToBoolean((long)torrent[10]); - - items.Add(item); - } - - return items; + return torrents; } public void AddTorrentFromUrl(string torrentUrl, string label, RTorrentPriority priority, string directory, RTorrentSettings settings) { - var client = BuildClient(settings); - var response = ExecuteRequest(() => - { - if (settings.AddStopped) - { - _logger.Debug("Executing remote method: load.normal"); - return client.LoadNormal("", torrentUrl, GetCommands(label, priority, directory)); - } - else - { - _logger.Debug("Executing remote method: load.start"); - return client.LoadStart("", torrentUrl, GetCommands(label, priority, directory)); - } - }); + var args = new List<object> { "", torrentUrl }; + args.AddRange(GetCommands(label, priority, directory)); - if (response != 0) + XDocument response; + + if (settings.AddStopped) + { + response = ExecuteRequest(settings, "load.normal", args.ToArray()); + } + else + { + response = ExecuteRequest(settings, "load.start", args.ToArray()); + } + + if (response.GetIntResponse() != 0) { throw new DownloadClientException("Could not add torrent: {0}.", torrentUrl); } @@ -141,22 +91,21 @@ namespace NzbDrone.Core.Download.Clients.RTorrent public void AddTorrentFromFile(string fileName, byte[] fileContent, string label, RTorrentPriority priority, string directory, RTorrentSettings settings) { - var client = BuildClient(settings); - var response = ExecuteRequest(() => - { - if (settings.AddStopped) - { - _logger.Debug("Executing remote method: load.raw"); - return client.LoadRaw("", fileContent, GetCommands(label, priority, directory)); - } - else - { - _logger.Debug("Executing remote method: load.raw_start"); - return client.LoadRawStart("", fileContent, GetCommands(label, priority, directory)); - } - }); + var args = new List<object> { "", fileContent }; + args.AddRange(GetCommands(label, priority, directory)); - if (response != 0) + XDocument response; + + if (settings.AddStopped) + { + response = ExecuteRequest(settings, "load.raw", args.ToArray()); + } + else + { + response = ExecuteRequest(settings, "load.raw_start", args.ToArray()); + } + + if (response.GetIntResponse() != 0) { throw new DownloadClientException("Could not add torrent: {0}.", fileName); } @@ -164,25 +113,29 @@ namespace NzbDrone.Core.Download.Clients.RTorrent public void SetTorrentLabel(string hash, string label, RTorrentSettings settings) { - _logger.Debug("Executing remote method: d.custom1.set"); + var response = ExecuteRequest(settings, "d.custom1.set", hash, label); - var client = BuildClient(settings); - var response = ExecuteRequest(() => client.SetLabel(hash, label)); - - if (response != label) + if (response.GetStringResponse() != label) { throw new DownloadClientException("Could not set label to {1} for torrent: {0}.", hash, label); } } + public void PushTorrentUniqueView(string hash, string view, RTorrentSettings settings) + { + var response = ExecuteRequest(settings, "d.views.push_back_unique", hash, view); + + if (response.GetIntResponse() != 0) + { + throw new DownloadClientException("Could not push unique view {0} for torrent: {1}.", view, hash); + } + } + public void RemoveTorrent(string hash, RTorrentSettings settings) { - _logger.Debug("Executing remote method: d.erase"); + var response = ExecuteRequest(settings, "d.erase", hash); - var client = BuildClient(settings); - var response = ExecuteRequest(() => client.Remove(hash)); - - if (response != 0) + if (response.GetIntResponse() != 0) { throw new DownloadClientException("Could not remove torrent: {0}.", hash); } @@ -190,13 +143,10 @@ namespace NzbDrone.Core.Download.Clients.RTorrent public bool HasHashTorrent(string hash, RTorrentSettings settings) { - _logger.Debug("Executing remote method: d.name"); - - var client = BuildClient(settings); - try { - var name = ExecuteRequest(() => client.GetName(hash)); + var response = ExecuteRequest(settings, "d.name", hash); + var name = response.GetStringResponse(); if (name.IsNullOrWhiteSpace()) { @@ -235,45 +185,34 @@ namespace NzbDrone.Core.Download.Clients.RTorrent return result.ToArray(); } - private IRTorrent BuildClient(RTorrentSettings settings) + private XDocument ExecuteRequest(RTorrentSettings settings, string methodName, params object[] args) { - var client = XmlRpcProxyGen.Create<IRTorrent>(); - - client.Url = string.Format(@"{0}://{1}:{2}/{3}", - settings.UseSsl ? "https" : "http", - settings.Host, - settings.Port, - settings.UrlBase); - - client.EnableCompression = true; + var requestBuilder = new XmlRpcRequestBuilder(settings.UseSsl, settings.Host, settings.Port, settings.UrlBase) + { + LogResponseContent = true, + }; if (!settings.Username.IsNullOrWhiteSpace()) { - client.Credentials = new NetworkCredential(settings.Username, settings.Password); + requestBuilder.NetworkCredential = new NetworkCredential(settings.Username, settings.Password); } - return client; - } + var request = requestBuilder.Call(methodName, args).Build(); - private T ExecuteRequest<T>(Func<T> task) - { - try - { - return task(); - } - catch (XmlRpcServerException ex) - { - throw new DownloadClientException("Unable to connect to rTorrent, please check your settings", ex); - } - catch (WebException ex) - { - if (ex.Status == WebExceptionStatus.TrustFailure) - { - throw new DownloadClientUnavailableException("Unable to connect to rTorrent, certificate validation failed.", ex); - } + var response = _httpClient.Execute(request); - throw new DownloadClientUnavailableException("Unable to connect to rTorrent, please check your settings", ex); + var doc = XDocument.Parse(response.Content); + + var faultElement = doc.XPathSelectElement("./methodResponse/fault"); + + if (faultElement != null) + { + var fault = new RTorrentFault(faultElement); + + throw new DownloadClientException($"rTorrent returned error code {fault.FaultCode}: {fault.FaultString}"); } + + return doc; } } } diff --git a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentTorrent.cs b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentTorrent.cs index d00df188f..0dc1165d0 100644 --- a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentTorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentTorrent.cs @@ -1,7 +1,35 @@ -namespace NzbDrone.Core.Download.Clients.RTorrent +using System; +using System.Linq; +using System.Web; +using System.Xml.Linq; +using NzbDrone.Core.Download.Extensions; + +namespace NzbDrone.Core.Download.Clients.RTorrent { public class RTorrentTorrent { + public RTorrentTorrent() + { + } + + public RTorrentTorrent(XElement element) + { + var data = element.Descendants("value").ToList(); + + Name = data[0].GetStringValue(); + Hash = data[1].GetStringValue(); + Path = data[2].GetStringValue(); + Category = HttpUtility.UrlDecode(data[3].GetStringValue()); + TotalSize = data[4].GetLongValue(); + RemainingSize = data[5].GetLongValue(); + DownRate = data[6].GetLongValue(); + Ratio = data[7].GetLongValue(); + IsOpen = Convert.ToBoolean(data[8].GetLongValue()); + IsActive = Convert.ToBoolean(data[9].GetLongValue()); + IsFinished = Convert.ToBoolean(data[10].GetLongValue()); + FinishedTime = data[11].GetLongValue(); + } + public string Name { get; set; } public string Hash { get; set; } public string Path { get; set; } @@ -10,6 +38,7 @@ public long RemainingSize { get; set; } public long DownRate { get; set; } public long Ratio { get; set; } + public long FinishedTime { get; set; } public bool IsFinished { get; set; } public bool IsOpen { get; set; } public bool IsActive { get; set; } diff --git a/src/NzbDrone.Core/Download/Extensions/XmlExtensions.cs b/src/NzbDrone.Core/Download/Extensions/XmlExtensions.cs new file mode 100644 index 000000000..bce66c8bc --- /dev/null +++ b/src/NzbDrone.Core/Download/Extensions/XmlExtensions.cs @@ -0,0 +1,54 @@ +using System.Xml.Linq; +using System.Xml.XPath; + +namespace NzbDrone.Core.Download.Extensions +{ + internal static class XmlExtensions + { + public static string GetStringValue(this XElement element) + { + return element.ElementAsString("string"); + } + + public static long GetLongValue(this XElement element) + { + return element.ElementAsLong("i8"); + } + + public static int GetIntValue(this XElement element) + { + return element.ElementAsInt("i4"); + } + + public static string ElementAsString(this XElement element, XName name, bool trim = false) + { + var el = element.Element(name); + + return string.IsNullOrWhiteSpace(el?.Value) + ? null + : (trim ? el.Value.Trim() : el.Value); + } + + public static long ElementAsLong(this XElement element, XName name) + { + var el = element.Element(name); + return long.TryParse(el?.Value, out long value) ? value : default; + } + + public static int ElementAsInt(this XElement element, XName name) + { + var el = element.Element(name); + return int.TryParse(el?.Value, out int value) ? value : default(int); + } + + public static int GetIntResponse(this XDocument document) + { + return document.XPathSelectElement("./methodResponse/params/param/value").GetIntValue(); + } + + public static string GetStringResponse(this XDocument document) + { + return document.XPathSelectElement("./methodResponse/params/param/value").GetStringValue(); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs b/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs index 264aed562..65a0734af 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Headphones/Headphones.cs @@ -59,7 +59,7 @@ namespace NzbDrone.Core.Indexers.Headphones var request = requestBuilder.Build(); - request.AddBasicAuthentication(Settings.Username, Settings.Password); + request.Credentials = new BasicNetworkCredential(Settings.Username, Settings.Password); try { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Headphones/HeadphonesRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Headphones/HeadphonesRequestGenerator.cs index 22eca7982..c2169d9cb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Headphones/HeadphonesRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Headphones/HeadphonesRequestGenerator.cs @@ -131,7 +131,7 @@ namespace NzbDrone.Core.Indexers.Headphones } var request = new IndexerRequest(string.Format("{0}&{1}", baseUrl, parameters.GetQueryString()), HttpAccept.Rss); - request.HttpRequest.AddBasicAuthentication(Settings.Username, Settings.Password); + request.HttpRequest.Credentials = new BasicNetworkCredential(Settings.Username, Settings.Password); yield return request; } diff --git a/src/NzbDrone.Core/Notifications/Email/Email.cs b/src/NzbDrone.Core/Notifications/Email/Email.cs index f40c20da6..6844f132f 100644 --- a/src/NzbDrone.Core/Notifications/Email/Email.cs +++ b/src/NzbDrone.Core/Notifications/Email/Email.cs @@ -7,17 +7,20 @@ using MailKit.Security; using MimeKit; using NLog; using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http.Dispatchers; namespace NzbDrone.Core.Notifications.Email { public class Email : NotificationBase<EmailSettings> { + private readonly ICertificateValidationService _certificateValidationService; private readonly Logger _logger; public override string Name => "Email"; - public Email(Logger logger) + public Email(ICertificateValidationService certificateValidationService, Logger logger) { + _certificateValidationService = certificateValidationService; _logger = logger; } @@ -113,6 +116,8 @@ namespace NzbDrone.Core.Notifications.Email } } + client.ServerCertificateValidationCallback = _certificateValidationService.ShouldByPassValidationError; + _logger.Debug("Connecting to mail server"); client.Connect(settings.Server, settings.Port, serverOption); diff --git a/src/NzbDrone.Core/Notifications/PushBullet/PushBulletProxy.cs b/src/NzbDrone.Core/Notifications/PushBullet/PushBulletProxy.cs index f39382ae8..da36b9970 100644 --- a/src/NzbDrone.Core/Notifications/PushBullet/PushBulletProxy.cs +++ b/src/NzbDrone.Core/Notifications/PushBullet/PushBulletProxy.cs @@ -102,7 +102,7 @@ namespace NzbDrone.Core.Notifications.PushBullet var request = requestBuilder.Build(); request.Method = HttpMethod.Get; - request.AddBasicAuthentication(settings.ApiKey, string.Empty); + request.Credentials = new BasicNetworkCredential(settings.ApiKey, string.Empty); var response = _httpClient.Execute(request); @@ -198,7 +198,7 @@ namespace NzbDrone.Core.Notifications.PushBullet var request = requestBuilder.Build(); - request.AddBasicAuthentication(settings.ApiKey, string.Empty); + request.Credentials = new BasicNetworkCredential(settings.ApiKey, string.Empty); _httpClient.Execute(request); } diff --git a/src/NzbDrone.Core/Notifications/Twitter/TwitterProxy.cs b/src/NzbDrone.Core/Notifications/Twitter/TwitterProxy.cs new file mode 100644 index 000000000..3330e4a07 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Twitter/TwitterProxy.cs @@ -0,0 +1,110 @@ +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Web; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Common.OAuth; + +namespace NzbDrone.Core.Notifications.Twitter +{ + public interface ITwitterProxy + { + NameValueCollection GetOAuthToken(string consumerKey, string consumerSecret, string oauthToken, string oauthVerifier); + string GetOAuthRedirect(string consumerKey, string consumerSecret, string callbackUrl); + void UpdateStatus(string message, TwitterSettings settings); + void DirectMessage(string message, TwitterSettings settings); + } + + public class TwitterProxy : ITwitterProxy + { + private readonly IHttpClient _httpClient; + + public TwitterProxy(IHttpClient httpClient) + { + _httpClient = httpClient; + } + + public string GetOAuthRedirect(string consumerKey, string consumerSecret, string callbackUrl) + { + // Creating a new instance with a helper method + var oAuthRequest = OAuthRequest.ForRequestToken(consumerKey, consumerSecret, callbackUrl); + oAuthRequest.RequestUrl = "https://api.twitter.com/oauth/request_token"; + var qscoll = HttpUtility.ParseQueryString(ExecuteRequest(GetRequest(oAuthRequest, new Dictionary<string, string>())).Content); + + return string.Format("https://api.twitter.com/oauth/authorize?oauth_token={0}", qscoll["oauth_token"]); + } + + public NameValueCollection GetOAuthToken(string consumerKey, string consumerSecret, string oauthToken, string oauthVerifier) + { + // Creating a new instance with a helper method + var oAuthRequest = OAuthRequest.ForAccessToken(consumerKey, consumerSecret, oauthToken, "", oauthVerifier); + oAuthRequest.RequestUrl = "https://api.twitter.com/oauth/access_token"; + + return HttpUtility.ParseQueryString(ExecuteRequest(GetRequest(oAuthRequest, new Dictionary<string, string>())).Content); + } + + public void UpdateStatus(string message, TwitterSettings settings) + { + var oAuthRequest = OAuthRequest.ForProtectedResource("POST", settings.ConsumerKey, settings.ConsumerSecret, settings.AccessToken, settings.AccessTokenSecret); + + oAuthRequest.RequestUrl = "https://api.twitter.com/1.1/statuses/update.json"; + + var customParams = new Dictionary<string, string> + { + { "status", message.EncodeRFC3986() } + }; + + var request = GetRequest(oAuthRequest, customParams); + + request.Headers.ContentType = "application/x-www-form-urlencoded"; + request.SetContent(Encoding.ASCII.GetBytes(GetCustomParametersString(customParams))); + + ExecuteRequest(request); + } + + public void DirectMessage(string message, TwitterSettings settings) + { + var oAuthRequest = OAuthRequest.ForProtectedResource("POST", settings.ConsumerKey, settings.ConsumerSecret, settings.AccessToken, settings.AccessTokenSecret); + + oAuthRequest.RequestUrl = "https://api.twitter.com/1.1/direct_messages/new.json"; + + var customParams = new Dictionary<string, string> + { + { "text", message.EncodeRFC3986() }, + { "screenname", settings.Mention.EncodeRFC3986() } + }; + + var request = GetRequest(oAuthRequest, customParams); + + request.Headers.ContentType = "application/x-www-form-urlencoded"; + request.SetContent(Encoding.ASCII.GetBytes(GetCustomParametersString(customParams))); + + ExecuteRequest(request); + } + + private string GetCustomParametersString(Dictionary<string, string> customParams) + { + return customParams.Select(x => string.Format("{0}={1}", x.Key, x.Value)).Join("&"); + } + + private HttpRequest GetRequest(OAuthRequest oAuthRequest, Dictionary<string, string> customParams) + { + var auth = oAuthRequest.GetAuthorizationHeader(customParams); + var request = new HttpRequest(oAuthRequest.RequestUrl); + + request.Headers.Add("Authorization", auth); + + request.Method = oAuthRequest.Method == "POST" ? HttpMethod.Post : HttpMethod.Get; + + return request; + } + + private HttpResponse ExecuteRequest(HttpRequest request) + { + return _httpClient.Execute(request); + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Twitter/TwitterService.cs b/src/NzbDrone.Core/Notifications/Twitter/TwitterService.cs index 85a9646e7..bce42d483 100644 --- a/src/NzbDrone.Core/Notifications/Twitter/TwitterService.cs +++ b/src/NzbDrone.Core/Notifications/Twitter/TwitterService.cs @@ -1,13 +1,9 @@ using System; -using System.Collections.Specialized; using System.IO; using System.Net; -using System.Web; using FluentValidation.Results; using NLog; using NzbDrone.Common.Extensions; -using NzbDrone.Common.Http; -using NzbDrone.Common.OAuth; namespace NzbDrone.Core.Notifications.Twitter { @@ -21,31 +17,18 @@ namespace NzbDrone.Core.Notifications.Twitter public class TwitterService : ITwitterService { - private readonly IHttpClient _httpClient; + private readonly ITwitterProxy _twitterProxy; private readonly Logger _logger; - public TwitterService(IHttpClient httpClient, Logger logger) + public TwitterService(ITwitterProxy twitterProxy, Logger logger) { - _httpClient = httpClient; + _twitterProxy = twitterProxy; _logger = logger; } - private NameValueCollection OAuthQuery(OAuthRequest oAuthRequest) - { - var auth = oAuthRequest.GetAuthorizationHeader(); - var request = new Common.Http.HttpRequest(oAuthRequest.RequestUrl); - request.Headers.Add("Authorization", auth); - var response = _httpClient.Get(request); - - return HttpUtility.ParseQueryString(response.Content); - } - public OAuthToken GetOAuthToken(string consumerKey, string consumerSecret, string oauthToken, string oauthVerifier) { - // Creating a new instance with a helper method - var oAuthRequest = OAuthRequest.ForAccessToken(consumerKey, consumerSecret, oauthToken, "", oauthVerifier); - oAuthRequest.RequestUrl = "https://api.twitter.com/oauth/access_token"; - var qscoll = OAuthQuery(oAuthRequest); + var qscoll = _twitterProxy.GetOAuthToken(consumerKey, consumerSecret, oauthToken, oauthVerifier); return new OAuthToken { @@ -56,31 +39,16 @@ namespace NzbDrone.Core.Notifications.Twitter public string GetOAuthRedirect(string consumerKey, string consumerSecret, string callbackUrl) { - // Creating a new instance with a helper method - var oAuthRequest = OAuthRequest.ForRequestToken(consumerKey, consumerSecret, callbackUrl); - oAuthRequest.RequestUrl = "https://api.twitter.com/oauth/request_token"; - var qscoll = OAuthQuery(oAuthRequest); - - return string.Format("https://api.twitter.com/oauth/authorize?oauth_token={0}", qscoll["oauth_token"]); + return _twitterProxy.GetOAuthRedirect(consumerKey, consumerSecret, callbackUrl); } public void SendNotification(string message, TwitterSettings settings) { try { - var oAuth = new TinyTwitter.OAuthInfo - { - ConsumerKey = settings.ConsumerKey, - ConsumerSecret = settings.ConsumerSecret, - AccessToken = settings.AccessToken, - AccessSecret = settings.AccessTokenSecret - }; - - var twitter = new TinyTwitter.TinyTwitter(oAuth); - if (settings.DirectMessage) { - twitter.DirectMessage(message, settings.Mention); + _twitterProxy.DirectMessage(message, settings); } else { @@ -89,7 +57,7 @@ namespace NzbDrone.Core.Notifications.Twitter message += string.Format(" @{0}", settings.Mention); } - twitter.UpdateStatus(message); + _twitterProxy.UpdateStatus(message, settings); } } catch (WebException ex) diff --git a/src/NzbDrone.Core/Notifications/Webhook/WebhookProxy.cs b/src/NzbDrone.Core/Notifications/Webhook/WebhookProxy.cs index d196b5579..23a7fbdc8 100755 --- a/src/NzbDrone.Core/Notifications/Webhook/WebhookProxy.cs +++ b/src/NzbDrone.Core/Notifications/Webhook/WebhookProxy.cs @@ -40,7 +40,7 @@ namespace NzbDrone.Core.Notifications.Webhook if (settings.Username.IsNotNullOrWhiteSpace() || settings.Password.IsNotNullOrWhiteSpace()) { - request.AddBasicAuthentication(settings.Username, settings.Password); + request.Credentials = new BasicNetworkCredential(settings.Username, settings.Password); } _httpClient.Execute(request); diff --git a/src/NzbDrone.Core/Security/X509CertificateValidationService.cs b/src/NzbDrone.Core/Security/X509CertificateValidationService.cs index 6d505ca0a..7efc877ad 100644 --- a/src/NzbDrone.Core/Security/X509CertificateValidationService.cs +++ b/src/NzbDrone.Core/Security/X509CertificateValidationService.cs @@ -4,13 +4,12 @@ using System.Net.Security; using System.Security.Cryptography.X509Certificates; using NLog; using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http.Dispatchers; using NzbDrone.Core.Configuration; -using NzbDrone.Core.Lifecycle; -using NzbDrone.Core.Messaging.Events; namespace NzbDrone.Core.Security { - public class X509CertificateValidationService : IHandle<ApplicationStartedEvent> + public class X509CertificateValidationService : ICertificateValidationService { private readonly IConfigService _configService; private readonly Logger _logger; @@ -21,19 +20,29 @@ namespace NzbDrone.Core.Security _logger = logger; } - private bool ShouldByPassValidationError(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + public bool ShouldByPassValidationError(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { - var request = sender as HttpWebRequest; + var targetHostName = string.Empty; - if (request == null) + if (sender is not SslStream && sender is not string) { return true; } - var cert2 = certificate as X509Certificate2; - if (cert2 != null && request != null && cert2.SignatureAlgorithm.FriendlyName == "md5RSA") + if (sender is SslStream request) { - _logger.Error("https://{0} uses the obsolete md5 hash in it's https certificate, if that is your certificate, please (re)create certificate with better algorithm as soon as possible.", request.RequestUri.Authority); + targetHostName = request.TargetHostName; + } + + // Mailkit passes host in sender as string + if (sender is string stringHost) + { + targetHostName = stringHost; + } + + if (certificate is X509Certificate2 cert2 && cert2.SignatureAlgorithm.FriendlyName == "md5RSA") + { + _logger.Error("https://{0} uses the obsolete md5 hash in it's https certificate, if that is your certificate, please (re)create certificate with better algorithm as soon as possible.", targetHostName); } if (sslPolicyErrors == SslPolicyErrors.None) @@ -41,12 +50,12 @@ namespace NzbDrone.Core.Security return true; } - if (request.RequestUri.Host == "localhost" || request.RequestUri.Host == "127.0.0.1") + if (targetHostName == "localhost" || targetHostName == "127.0.0.1") { return true; } - var ipAddresses = GetIPAddresses(request.RequestUri.Host); + var ipAddresses = GetIPAddresses(targetHostName); var certificateValidation = _configService.CertificateValidation; if (certificateValidation == CertificateValidationType.Disabled) @@ -60,7 +69,7 @@ namespace NzbDrone.Core.Security return true; } - _logger.Error("Certificate validation for {0} failed. {1}", request.Address, sslPolicyErrors); + _logger.Error("Certificate validation for {0} failed. {1}", targetHostName, sslPolicyErrors); return false; } @@ -74,10 +83,5 @@ namespace NzbDrone.Core.Security return Dns.GetHostEntry(host).AddressList; } - - public void Handle(ApplicationStartedEvent message) - { - ServicePointManager.ServerCertificateValidationCallback = ShouldByPassValidationError; - } } } diff --git a/src/NzbDrone.Core/TinyTwitter.cs b/src/NzbDrone.Core/TinyTwitter.cs deleted file mode 100644 index 9f772095d..000000000 --- a/src/NzbDrone.Core/TinyTwitter.cs +++ /dev/null @@ -1,235 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; - -namespace TinyTwitter -{ - public class OAuthInfo - { - public string ConsumerKey { get; set; } - public string ConsumerSecret { get; set; } - public string AccessToken { get; set; } - public string AccessSecret { get; set; } - } - - public class Tweet - { - public long Id { get; set; } - public DateTime CreatedAt { get; set; } - public string UserName { get; set; } - public string ScreenName { get; set; } - public string Text { get; set; } - } - - public class TinyTwitter - { - private readonly OAuthInfo _oauth; - - public TinyTwitter(OAuthInfo oauth) - { - _oauth = oauth; - } - - public void UpdateStatus(string message) - { - new RequestBuilder(_oauth, "POST", "https://api.twitter.com/1.1/statuses/update.json") - .AddParameter("status", message) - .Execute(); - } - - /** - * - * As of June 26th 2015 Direct Messaging is not part of TinyTwitter. - * I have added it to Sonarr's copy to make our implementation easier - * and added this banner so it's not blindly updated. - * - **/ - public void DirectMessage(string message, string screenName) - { - new RequestBuilder(_oauth, "POST", "https://api.twitter.com/1.1/direct_messages/new.json") - .AddParameter("text", message) - .AddParameter("screen_name", screenName) - .Execute(); - } - - public class RequestBuilder - { - private const string VERSION = "1.0"; - private const string SIGNATURE_METHOD = "HMAC-SHA1"; - - private readonly OAuthInfo _oauth; - private readonly string _method; - private readonly IDictionary<string, string> _customParameters; - private readonly string _url; - - public RequestBuilder(OAuthInfo oauth, string method, string url) - { - _oauth = oauth; - _method = method; - _url = url; - _customParameters = new Dictionary<string, string>(); - } - - public RequestBuilder AddParameter(string name, string value) - { - _customParameters.Add(name, value.EncodeRFC3986()); - return this; - } - - public string Execute() - { - var timespan = GetTimestamp(); - var nonce = CreateNonce(); - - var parameters = new Dictionary<string, string>(_customParameters); - AddOAuthParameters(parameters, timespan, nonce); - - var signature = GenerateSignature(parameters); - var headerValue = GenerateAuthorizationHeaderValue(parameters, signature); - - var request = (HttpWebRequest)WebRequest.Create(GetRequestUrl()); - request.Method = _method; - request.ContentType = "application/x-www-form-urlencoded"; - - request.Headers.Add("Authorization", headerValue); - - WriteRequestBody(request); - - // It looks like a bug in HttpWebRequest. It throws random TimeoutExceptions - // after some requests. Abort the request seems to work. More info: - // http://stackoverflow.com/questions/2252762/getrequeststream-throws-timeout-exception-randomly - var response = request.GetResponse(); - - string content; - - using (var stream = response.GetResponseStream()) - { - using (var reader = new StreamReader(stream)) - { - content = reader.ReadToEnd(); - } - } - - request.Abort(); - - return content; - } - - private void WriteRequestBody(HttpWebRequest request) - { - if (_method == "GET") - { - return; - } - - var requestBody = Encoding.ASCII.GetBytes(GetCustomParametersString()); - using (var stream = request.GetRequestStream()) - { - stream.Write(requestBody, 0, requestBody.Length); - } - } - - private string GetRequestUrl() - { - if (_method != "GET" || _customParameters.Count == 0) - { - return _url; - } - - return string.Format("{0}?{1}", _url, GetCustomParametersString()); - } - - private string GetCustomParametersString() - { - return _customParameters.Select(x => string.Format("{0}={1}", x.Key, x.Value)).Join("&"); - } - - private string GenerateAuthorizationHeaderValue(IEnumerable<KeyValuePair<string, string>> parameters, string signature) - { - return new StringBuilder("OAuth ") - .Append(parameters.Concat(new KeyValuePair<string, string>("oauth_signature", signature)) - .Where(x => x.Key.StartsWith("oauth_")) - .Select(x => string.Format("{0}=\"{1}\"", x.Key, x.Value.EncodeRFC3986())) - .Join(",")) - .ToString(); - } - - private string GenerateSignature(IEnumerable<KeyValuePair<string, string>> parameters) - { - var dataToSign = new StringBuilder() - .Append(_method).Append('&') - .Append(_url.EncodeRFC3986()).Append('&') - .Append(parameters - .OrderBy(x => x.Key) - .Select(x => string.Format("{0}={1}", x.Key, x.Value)) - .Join("&") - .EncodeRFC3986()); - - var signatureKey = string.Format("{0}&{1}", _oauth.ConsumerSecret.EncodeRFC3986(), _oauth.AccessSecret.EncodeRFC3986()); - var sha1 = new HMACSHA1(Encoding.ASCII.GetBytes(signatureKey)); - - var signatureBytes = sha1.ComputeHash(Encoding.ASCII.GetBytes(dataToSign.ToString())); - return Convert.ToBase64String(signatureBytes); - } - - private void AddOAuthParameters(IDictionary<string, string> parameters, string timestamp, string nonce) - { - parameters.Add("oauth_version", VERSION); - parameters.Add("oauth_consumer_key", _oauth.ConsumerKey); - parameters.Add("oauth_nonce", nonce); - parameters.Add("oauth_signature_method", SIGNATURE_METHOD); - parameters.Add("oauth_timestamp", timestamp); - parameters.Add("oauth_token", _oauth.AccessToken); - } - - private static string GetTimestamp() - { - return ((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds).ToString(); - } - - private static string CreateNonce() - { - return new Random().Next(0x0000000, 0x7fffffff).ToString("X8"); - } - } - } - - public static class TinyTwitterHelperExtensions - { - public static string Join<T>(this IEnumerable<T> items, string separator) - { - return string.Join(separator, items.ToArray()); - } - - public static IEnumerable<T> Concat<T>(this IEnumerable<T> items, T value) - { - return items.Concat(new[] { value }); - } - - public static string EncodeRFC3986(this string value) - { - // From Twitterizer http://www.twitterizer.net/ - if (string.IsNullOrEmpty(value)) - { - return string.Empty; - } - - var encoded = Uri.EscapeDataString(value); - - return Regex - .Replace(encoded, "(%[0-9a-f][0-9a-f])", c => c.Value.ToUpper()) - .Replace("(", "%28") - .Replace(")", "%29") - .Replace("$", "%24") - .Replace("!", "%21") - .Replace("*", "%2A") - .Replace("'", "%27") - .Replace("%7E", "~"); - } - } -} From ddcef3a99c0f77fc51736652ae2c2816d2b6ac0b Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 4 Jul 2022 18:51:52 -0500 Subject: [PATCH 0528/2320] Fixed: Delete CustomFilters not handled properly --- src/Prowlarr.Api.V1/CustomFilters/CustomFilterController.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Prowlarr.Api.V1/CustomFilters/CustomFilterController.cs b/src/Prowlarr.Api.V1/CustomFilters/CustomFilterController.cs index 018a3cc9f..e5aca3c85 100644 --- a/src/Prowlarr.Api.V1/CustomFilters/CustomFilterController.cs +++ b/src/Prowlarr.Api.V1/CustomFilters/CustomFilterController.cs @@ -47,9 +47,11 @@ namespace Prowlarr.Api.V1.CustomFilters } [RestDeleteById] - public void DeleteCustomResource(int id) + public object DeleteCustomResource(int id) { _customFilterService.Delete(id); + + return new { }; } } } From c53e0054ee3f075482f0457464924b9bbea7987d Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 4 Jul 2022 19:32:55 -0500 Subject: [PATCH 0529/2320] Fixed: (Cardigann) Use Session Cookie when making SimpleCaptchaCall Fixes #262 Fixes #136 Fixes #122 --- .../Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index dce7816d7..73d619f95 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -343,6 +343,8 @@ namespace NzbDrone.Core.Indexers.Cardigann Encoding = _encoding }; + requestBuilder.SetCookies(Cookies); + requestBuilder.Headers.Add("Referer", loginUrl); var simpleCaptchaResult = await HttpClient.ExecuteProxiedAsync(requestBuilder.Build(), Definition); From e4284d47b0c1665b9b36baf0893e004c7b56cbf9 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 4 Jul 2022 20:11:43 -0500 Subject: [PATCH 0530/2320] Fixed: (Cardigann) Use Indexer Encoding for Form Parameters Fixes #959 --- src/NzbDrone.Common/Http/HttpRequestBuilder.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Common/Http/HttpRequestBuilder.cs b/src/NzbDrone.Common/Http/HttpRequestBuilder.cs index 7d75291b3..87f8c9f45 100644 --- a/src/NzbDrone.Common/Http/HttpRequestBuilder.cs +++ b/src/NzbDrone.Common/Http/HttpRequestBuilder.cs @@ -209,7 +209,7 @@ namespace NzbDrone.Common.Http } else { - summary.AppendFormat("\r\n{0}={1}", formData.Name, Encoding.UTF8.GetString(formData.ContentData)); + summary.AppendFormat("\r\n{0}={1}", formData.Name, Encoding.GetString(formData.ContentData)); } } @@ -229,9 +229,9 @@ namespace NzbDrone.Common.Http } else { - var parameters = FormData.Select(v => string.Format("{0}={1}", v.Name, Uri.EscapeDataString(Encoding.UTF8.GetString(v.ContentData)))); + var parameters = FormData.Select(v => string.Format("{0}={1}", v.Name, Uri.EscapeDataString(Encoding.GetString(v.ContentData)))); var urlencoded = string.Join("&", parameters); - var body = Encoding.UTF8.GetBytes(urlencoded); + var body = Encoding.GetBytes(urlencoded); request.Headers.ContentType = "application/x-www-form-urlencoded"; request.SetContent(body); @@ -403,7 +403,7 @@ namespace NzbDrone.Common.Http FormData.Add(new HttpFormData { Name = key, - ContentData = Encoding.UTF8.GetBytes(Convert.ToString(value, System.Globalization.CultureInfo.InvariantCulture)) + ContentData = Encoding.GetBytes(Convert.ToString(value, System.Globalization.CultureInfo.InvariantCulture)) }); return this; From 812cf8135a1853175bea8ff0eb2fc599b091f4b5 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 4 Jul 2022 20:29:17 -0500 Subject: [PATCH 0531/2320] Remove unused XmlRPC dependency --- src/NzbDrone.Core/Prowlarr.Core.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index cf38f7cae..f94bdab8d 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -18,7 +18,6 @@ <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="NLog" Version="5.0.1" /> <PackageReference Include="TinyTwitter" Version="1.1.2" /> - <PackageReference Include="Kveer.XmlRPC" Version="1.1.1" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> <PackageReference Include="System.Text.Json" Version="6.0.5" /> <PackageReference Include="MonoTorrent" Version="2.0.5" /> From f2f6a82cf0aead1907beac1e417beafac983aeb4 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 4 Jul 2022 20:40:30 -0500 Subject: [PATCH 0532/2320] New: Add linux-x86 builds --- azure-pipelines.yml | 130 +++++++++++------- build.sh | 45 ++++-- .../Prowlarr.Mono.Test.csproj | 2 +- src/NzbDrone.Mono/Prowlarr.Mono.csproj | 2 +- 4 files changed, 116 insertions(+), 63 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1be407772..8fed1455f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -97,15 +97,14 @@ stages: - bash: | BUNDLEDVERSIONS=${AGENT_TOOLSDIRECTORY}/dotnet/sdk/${DOTNETVERSION}/Microsoft.NETCoreSdk.BundledVersions.props echo $BUNDLEDVERSIONS - grep osx-x64 $BUNDLEDVERSIONS if grep -q freebsd-x64 $BUNDLEDVERSIONS; then - echo "BSD already enabled" + echo "Extra platforms already enabled" else - echo "Enabling BSD support" - sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64/' $BUNDLEDVERSIONS + echo "Enabling extra platform support" + sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64;linux-x86/' $BUNDLEDVERSIONS fi - displayName: Enable FreeBSD Support - - bash: ./build.sh --backend --enable-bsd + displayName: Enable Extra Platform Support + - bash: ./build.sh --backend --enable-extra-platforms displayName: Build Prowlarr Backend - bash: | find ${OUTPUTFOLDER} -type f ! -path "*/publish/*" -exec rm -rf {} \; @@ -119,24 +118,28 @@ stages: displayName: Publish Backend condition: and(succeeded(), eq(variables['osName'], 'Windows')) - publish: '$(testsFolder)/net6.0/win-x64/publish' - artifact: WindowsCoreTests - displayName: Publish Windows Test Package + artifact: win-x64-tests + displayName: Publish win-x64 Test Package condition: and(succeeded(), eq(variables['osName'], 'Windows')) - publish: '$(testsFolder)/net6.0/linux-x64/publish' - artifact: LinuxCoreTests - displayName: Publish Linux Test Package + artifact: linux-x64-tests + displayName: Publish linux-x64 Test Package + condition: and(succeeded(), eq(variables['osName'], 'Windows')) + - publish: '$(testsFolder)/net6.0/linux-x86/publish' + artifact: linux-x86-tests + displayName: Publish linux-x86 Test Package condition: and(succeeded(), eq(variables['osName'], 'Windows')) - publish: '$(testsFolder)/net6.0/linux-musl-x64/publish' - artifact: LinuxMuslCoreTests - displayName: Publish Linux Musl Test Package + artifact: linux-musl-x64-tests + displayName: Publish linux-musl-x64 Test Package condition: and(succeeded(), eq(variables['osName'], 'Windows')) - publish: '$(testsFolder)/net6.0/freebsd-x64/publish' - artifact: FreebsdCoreTests - displayName: Publish FreeBSD Test Package + artifact: freebsd-x64-tests + displayName: Publish freebsd-x64 Test Package condition: and(succeeded(), eq(variables['osName'], 'Windows')) - publish: '$(testsFolder)/net6.0/osx-x64/publish' - artifact: MacCoreTests - displayName: Publish MacOS Test Package + artifact: osx-x64-tests + displayName: Publish osx-x64 Test Package condition: and(succeeded(), eq(variables['osName'], 'Windows')) - stage: Build_Frontend @@ -239,35 +242,35 @@ stages: artifactName: WindowsFrontend targetPath: _output displayName: Fetch Frontend - - bash: ./build.sh --packages --enable-bsd + - bash: ./build.sh --packages --enable-extra-platforms displayName: Create Packages - bash: | find . -name "Prowlarr" -exec chmod a+x {} \; find . -name "Prowlarr.Update" -exec chmod a+x {} \; displayName: Set executable bits - task: ArchiveFiles@2 - displayName: Create Windows Core zip + displayName: Create win-x64 zip inputs: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).windows-core-x64.zip' archiveType: 'zip' includeRootFolder: false rootFolderOrFile: $(artifactsFolder)/win-x64/net6.0 - task: ArchiveFiles@2 - displayName: Create Windows x86 Core zip + displayName: Create win-x86 zip inputs: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).windows-core-x86.zip' archiveType: 'zip' includeRootFolder: false rootFolderOrFile: $(artifactsFolder)/win-x86/net6.0 - task: ArchiveFiles@2 - displayName: Create MacOS x64 Core app + displayName: Create osx-x64 app inputs: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).osx-app-core-x64.zip' archiveType: 'zip' includeRootFolder: false rootFolderOrFile: $(artifactsFolder)/osx-x64-app/net6.0 - task: ArchiveFiles@2 - displayName: Create MacOS x64 Core tar + displayName: Create osx-x64 tar inputs: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).osx-core-x64.tar.gz' archiveType: 'tar' @@ -275,14 +278,14 @@ stages: includeRootFolder: false rootFolderOrFile: $(artifactsFolder)/osx-x64/net6.0 - task: ArchiveFiles@2 - displayName: Create MacOS arm64 Core app + displayName: Create osx-arm64 app inputs: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).osx-app-core-arm64.zip' archiveType: 'zip' includeRootFolder: false rootFolderOrFile: $(artifactsFolder)/osx-arm64-app/net6.0 - task: ArchiveFiles@2 - displayName: Create MacOS arm64 Core tar + displayName: Create osx-arm64 tar inputs: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).osx-core-arm64.tar.gz' archiveType: 'tar' @@ -290,7 +293,7 @@ stages: includeRootFolder: false rootFolderOrFile: $(artifactsFolder)/osx-arm64/net6.0 - task: ArchiveFiles@2 - displayName: Create Linux Core tar + displayName: Create linux-x64 tar inputs: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).linux-core-x64.tar.gz' archiveType: 'tar' @@ -298,7 +301,7 @@ stages: includeRootFolder: false rootFolderOrFile: $(artifactsFolder)/linux-x64/net6.0 - task: ArchiveFiles@2 - displayName: Create Linux Musl Core tar + displayName: Create linux-musl-x64 tar inputs: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).linux-musl-core-x64.tar.gz' archiveType: 'tar' @@ -306,7 +309,15 @@ stages: includeRootFolder: false rootFolderOrFile: $(artifactsFolder)/linux-musl-x64/net6.0 - task: ArchiveFiles@2 - displayName: Create ARM32 Linux Core tar + displayName: Create linux-x86 tar + inputs: + archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).linux-core-x86.tar.gz' + archiveType: 'tar' + tarCompression: 'gz' + includeRootFolder: false + rootFolderOrFile: $(artifactsFolder)/linux-x86/net6.0 + - task: ArchiveFiles@2 + displayName: Create linux-arm tar inputs: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).linux-core-arm.tar.gz' archiveType: 'tar' @@ -314,7 +325,7 @@ stages: includeRootFolder: false rootFolderOrFile: $(artifactsFolder)/linux-arm/net6.0 - task: ArchiveFiles@2 - displayName: Create ARM32 Linux Musl Core tar + displayName: Create linux-musl-arm tar inputs: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).linux-musl-core-arm.tar.gz' archiveType: 'tar' @@ -322,7 +333,7 @@ stages: includeRootFolder: false rootFolderOrFile: $(artifactsFolder)/linux-musl-arm/net6.0 - task: ArchiveFiles@2 - displayName: Create ARM64 Linux Core tar + displayName: Create linux-arm64 tar inputs: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).linux-core-arm64.tar.gz' archiveType: 'tar' @@ -330,7 +341,7 @@ stages: includeRootFolder: false rootFolderOrFile: $(artifactsFolder)/linux-arm64/net6.0 - task: ArchiveFiles@2 - displayName: Create ARM64 Linux Musl Core tar + displayName: Create linux-musl-arm64 tar inputs: archiveFile: '$(Build.ArtifactStagingDirectory)/Prowlarr.$(buildName).linux-musl-core-arm64.tar.gz' archiveType: 'tar' @@ -405,22 +416,22 @@ stages: matrix: MacCore: osName: 'Mac' - testName: 'MacCore' + testName: 'osx-x64' poolName: 'Azure Pipelines' imageName: ${{ variables.macImage }} WindowsCore: osName: 'Windows' - testName: 'WindowsCore' + testName: 'win-x64' poolName: 'Azure Pipelines' imageName: ${{ variables.windowsImage }} LinuxCore: osName: 'Linux' - testName: 'LinuxCore' + testName: 'linux-x64' poolName: 'Azure Pipelines' imageName: ${{ variables.linuxImage }} FreebsdCore: osName: 'Linux' - testName: 'FreebsdCore' + testName: 'freebsd-x64' poolName: 'FreeBSD' imageName: @@ -439,7 +450,7 @@ stages: displayName: Download Test Artifact inputs: buildType: 'current' - artifactName: '$(testName)Tests' + artifactName: '$(testName)-tests' targetPath: $(testsFolder) - powershell: Set-Service SCardSvr -StartupType Manual displayName: Enable Windows Test Service @@ -469,8 +480,12 @@ stages: matrix: alpine: testName: 'Musl Net Core' - artifactName: LinuxMuslCoreTests + artifactName: linux-musl-x64-tests containerImage: ghcr.io/servarr/testimages:alpine + linux-x86: + testName: 'linux-x86' + artifactName: linux-x86-tests + containerImage: ghcr.io/servarr/testimages:linux-x86 pool: vmImage: ${{ variables.linuxImage }} @@ -481,9 +496,15 @@ stages: steps: - task: UseDotNet@2 - displayName: 'Install .net core' + displayName: 'Install .NET' inputs: version: $(dotnetVersion) + condition: and(succeeded(), ne(variables['testName'], 'linux-x86')) + - bash: | + SDKURL=$(curl -s https://api.github.com/repos/Servarr/dotnet-linux-x86/releases | jq -rc '.[].assets[].browser_download_url' | grep sdk-${DOTNETVERSION}.*gz$) + curl -fsSL $SDKURL | tar xzf - -C /opt/dotnet + displayName: 'Install .NET' + condition: and(succeeded(), eq(variables['testName'], 'linux-x86')) - checkout: none - task: DownloadPipelineArtifact@2 displayName: Download Test Artifact @@ -513,7 +534,7 @@ stages: condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0')) variables: pattern: 'Prowlarr.*.linux-core-x64.tar.gz' - artifactName: LinuxCoreTests + artifactName: linux-x64-tests Prowlarr__Postgres__Host: 'localhost' Prowlarr__Postgres__Port: '5432' Prowlarr__Postgres__User: 'prowlarr' @@ -585,17 +606,17 @@ stages: matrix: MacCore: osName: 'Mac' - testName: 'MacCore' + testName: 'osx-x64' imageName: ${{ variables.macImage }} pattern: 'Prowlarr.*.osx-core-x64.tar.gz' WindowsCore: osName: 'Windows' - testName: 'WindowsCore' + testName: 'win-x64' imageName: ${{ variables.windowsImage }} pattern: 'Prowlarr.*.windows-core-x64.zip' LinuxCore: osName: 'Linux' - testName: 'LinuxCore' + testName: 'linux-x64' imageName: ${{ variables.linuxImage }} pattern: 'Prowlarr.*.linux-core-x64.tar.gz' @@ -612,7 +633,7 @@ stages: displayName: Download Test Artifact inputs: buildType: 'current' - artifactName: '$(testName)Tests' + artifactName: '$(testName)-tests' targetPath: $(testsFolder) - task: DownloadPipelineArtifact@2 displayName: Download Build Artifact @@ -666,7 +687,7 @@ stages: displayName: Download Test Artifact inputs: buildType: 'current' - artifactName: 'LinuxCoreTests' + artifactName: 'linux-x64-tests' targetPath: $(testsFolder) - task: DownloadPipelineArtifact@2 displayName: Download Build Artifact @@ -720,7 +741,7 @@ stages: displayName: Download Test Artifact inputs: buildType: 'current' - artifactName: 'FreebsdCoreTests' + artifactName: 'freebsd-x64-tests' targetPath: $(testsFolder) - task: DownloadPipelineArtifact@2 displayName: Download Build Artifact @@ -756,11 +777,15 @@ stages: strategy: matrix: alpine: - testName: 'Musl Net Core' - artifactName: LinuxMuslCoreTests + testName: 'linux-musl-x64' + artifactName: linux-musl-x64-tests containerImage: ghcr.io/servarr/testimages:alpine pattern: 'Prowlarr.*.linux-musl-core-x64.tar.gz' - + linux-x86: + testName: 'linux-x86' + artifactName: linux-x86-tests + containerImage: ghcr.io/servarr/testimages:linux-x86 + pattern: 'Prowlarr.*.linux-core-x86.tar.gz' pool: vmImage: ${{ variables.linuxImage }} @@ -770,9 +795,15 @@ stages: steps: - task: UseDotNet@2 - displayName: 'Install .net core' + displayName: 'Install .NET' inputs: version: $(dotnetVersion) + condition: and(succeeded(), ne(variables['testName'], 'linux-x86')) + - bash: | + SDKURL=$(curl -s https://api.github.com/repos/Servarr/dotnet-linux-x86/releases | jq -rc '.[].assets[].browser_download_url' | grep sdk-${DOTNETVERSION}.*gz$) + curl -fsSL $SDKURL | tar xzf - -C /opt/dotnet + displayName: 'Install .NET' + condition: and(succeeded(), eq(variables['testName'], 'linux-x86')) - checkout: none - task: DownloadPipelineArtifact@2 displayName: Download Test Artifact @@ -818,16 +849,19 @@ stages: matrix: Linux: osName: 'Linux' + artifactName: 'linux-x64' imageName: ${{ variables.linuxImage }} pattern: 'Prowlarr.*.linux-core-x64.tar.gz' failBuild: true Mac: osName: 'Mac' + artifactName: 'osx-x64' imageName: ${{ variables.macImage }} pattern: 'Prowlarr.*.osx-core-x64.tar.gz' failBuild: true Windows: osName: 'Windows' + artifactName: 'win-x64' imageName: ${{ variables.windowsImage }} pattern: 'Prowlarr.*.windows-core-x64.zip' failBuild: true @@ -845,7 +879,7 @@ stages: displayName: Download Test Artifact inputs: buildType: 'current' - artifactName: '$(osName)CoreTests' + artifactName: '$(artifactName)-tests' targetPath: $(testsFolder) - task: DownloadPipelineArtifact@2 displayName: Download Build Artifact diff --git a/build.sh b/build.sh index 93396ffdf..9ce85b634 100755 --- a/build.sh +++ b/build.sh @@ -25,15 +25,22 @@ UpdateVersionNumber() fi } -EnableBsdSupport() +EnableExtraPlatformsInSDK() { - #todo enable sdk with - #SDK_PATH=$(dotnet --list-sdks | grep -P '5\.\d\.\d+' | head -1 | sed 's/\(5\.[0-9]*\.[0-9]*\).*\[\(.*\)\]/\2\/\1/g') - # BUNDLED_VERSIONS="${SDK_PATH}/Microsoft.NETCoreSdk.BundledVersions.props" + SDK_PATH=$(dotnet --list-sdks | grep -P '6\.\d\.\d+' | head -1 | sed 's/\(6\.[0-9]*\.[0-9]*\).*\[\(.*\)\]/\2\/\1/g') + BUNDLEDVERSIONS="${SDK_PATH}/Microsoft.NETCoreSdk.BundledVersions.props" + if grep -q freebsd-x64 $BUNDLEDVERSIONS; then + echo "Extra platforms already enabled" + else + echo "Enabling extra platform support" + sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64;linux-x86/' $BUNDLEDVERSIONS + fi +} +EnableExtraPlatforms() +{ if grep -qv freebsd-x64 src/Directory.Build.props; then - sed -i'' -e "s^<RuntimeIdentifiers>\(.*\)</RuntimeIdentifiers>^<RuntimeIdentifiers>\1;freebsd-x64</RuntimeIdentifiers>^g" src/Directory.Build.props - sed -i'' -e "s^<ExcludedRuntimeFrameworkPairs>\(.*\)</ExcludedRuntimeFrameworkPairs>^<ExcludedRuntimeFrameworkPairs>\1;freebsd-x64:net472</ExcludedRuntimeFrameworkPairs>^g" src/Directory.Build.props + sed -i'' -e "s^<RuntimeIdentifiers>\(.*\)</RuntimeIdentifiers>^<RuntimeIdentifiers>\1;freebsd-x64;linux-x86</RuntimeIdentifiers>^g" src/Directory.Build.props fi } @@ -293,7 +300,8 @@ if [ $# -eq 0 ]; then PACKAGES=YES INSTALLER=NO LINT=YES - ENABLE_BSD=NO + ENABLE_EXTRA_PLATFORMS=NO + ENABLE_EXTRA_PLATFORMS_IN_SDK=NO fi while [[ $# -gt 0 ]] @@ -305,8 +313,12 @@ case $key in BACKEND=YES shift # past argument ;; - --enable-bsd) - ENABLE_BSD=YES + --enable-bsd|--enable-extra-platforms) + ENABLE_EXTRA_PLATFORMS=YES + shift # past argument + ;; + --enable-extra-platforms-in-sdk) + ENABLE_EXTRA_PLATFORMS_IN_SDK=YES shift # past argument ;; -r|--runtime) @@ -350,12 +362,17 @@ esac done set -- "${POSITIONAL[@]}" # restore positional parameters +if [ "$ENABLE_EXTRA_PLATFORMS_IN_SDK" = "YES" ]; +then + EnableExtraPlatformsInSDK +fi + if [ "$BACKEND" = "YES" ]; then UpdateVersionNumber - if [ "$ENABLE_BSD" = "YES" ]; + if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ]; then - EnableBsdSupport + EnableExtraPlatforms fi Build if [[ -z "$RID" || -z "$FRAMEWORK" ]]; @@ -365,9 +382,10 @@ then PackageTests "net6.0" "linux-x64" PackageTests "net6.0" "linux-musl-x64" PackageTests "net6.0" "osx-x64" - if [ "$ENABLE_BSD" = "YES" ]; + if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ]; then PackageTests "net6.0" "freebsd-x64" + PackageTests "net6.0" "linux-x86" fi else PackageTests "$FRAMEWORK" "$RID" @@ -406,9 +424,10 @@ then Package "net6.0" "linux-musl-arm" Package "net6.0" "osx-x64" Package "net6.0" "osx-arm64" - if [ "$ENABLE_BSD" = "YES" ]; + if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ]; then Package "net6.0" "freebsd-x64" + Package "net6.0" "linux-x86" fi else Package "$FRAMEWORK" "$RID" diff --git a/src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj b/src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj index a79b0aadc..6d2d1a18d 100644 --- a/src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj +++ b/src/NzbDrone.Mono.Test/Prowlarr.Mono.Test.csproj @@ -3,7 +3,7 @@ <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> - <PackageReference Include="Mono.Posix.NETStandard" Version="5.20.1.34-servarr18" /> + <PackageReference Include="Mono.Posix.NETStandard" Version="5.20.1.34-servarr20" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Common.Test\Prowlarr.Common.Test.csproj" /> diff --git a/src/NzbDrone.Mono/Prowlarr.Mono.csproj b/src/NzbDrone.Mono/Prowlarr.Mono.csproj index ede3bd762..46d7dabc8 100644 --- a/src/NzbDrone.Mono/Prowlarr.Mono.csproj +++ b/src/NzbDrone.Mono/Prowlarr.Mono.csproj @@ -4,7 +4,7 @@ <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> </PropertyGroup> <ItemGroup> - <PackageReference Include="Mono.Posix.NETStandard" Version="5.20.1.34-servarr18" /> + <PackageReference Include="Mono.Posix.NETStandard" Version="5.20.1.34-servarr20" /> <PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" /> </ItemGroup> <ItemGroup> From 37914fb90eb3efe95f991a45d24f862c48559468 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 4 Jul 2022 21:10:19 -0500 Subject: [PATCH 0533/2320] Bump Mailkit to 3.3.0 (#1054) * Bump Mailkit to 3.3.0 * Bump Sentry to 3.19.0 --- src/NzbDrone.Common/Prowlarr.Common.csproj | 2 +- src/NzbDrone.Core/Prowlarr.Core.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index 298c3825d..38d0fbc3e 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -11,7 +11,7 @@ <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="NLog" Version="5.0.1" /> <PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" /> - <PackageReference Include="Sentry" Version="3.18.0" /> + <PackageReference Include="Sentry" Version="3.19.0" /> <PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" /> <PackageReference Include="SharpZipLib" Version="1.3.3" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" /> diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index f94bdab8d..fae223961 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -6,7 +6,7 @@ <PackageReference Include="AngleSharp.Xml" Version="0.17.0" /> <PackageReference Include="Dapper" Version="2.0.123" /> <PackageReference Include="FluentMigrator.Runner" Version="3.3.2" /> - <PackageReference Include="MailKit" Version="3.1.1" /> + <PackageReference Include="MailKit" Version="3.3.0" /> <PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" /> <PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" /> <PackageReference Include="Npgsql" Version="5.0.11" /> From e85ccd5808eca02f8d21ab85bfea8c396c6d7c04 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 29 Mar 2022 19:19:22 -0500 Subject: [PATCH 0534/2320] New: (FlareSolverr) DDOS Guard Support (based on Flaresolverr b62c203f96222602964a291b845e4d16c1a0d43a) --- src/NzbDrone.Common/Http/HttpHeader.cs | 24 +++++++++++++++++++ .../FlareSolverr/FlareSolverr.cs | 23 +++++++++++++----- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Common/Http/HttpHeader.cs b/src/NzbDrone.Common/Http/HttpHeader.cs index a5047f4b6..020c04d93 100644 --- a/src/NzbDrone.Common/Http/HttpHeader.cs +++ b/src/NzbDrone.Common/Http/HttpHeader.cs @@ -128,6 +128,30 @@ namespace NzbDrone.Common.Http } } + public string ContentEncoding + { + get + { + return GetSingleValue("Content-Encoding"); + } + set + { + SetSingleValue("Content-Encoding", value); + } + } + + public string Vary + { + get + { + return GetSingleValue("Vary"); + } + set + { + SetSingleValue("Vary", value); + } + } + public string UserAgent { get diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index 23e682715..0275b7178 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -18,7 +18,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr { public class FlareSolverr : HttpIndexerProxyBase<FlareSolverrSettings> { - private static readonly HashSet<string> CloudflareServerNames = new HashSet<string> { "cloudflare", "cloudflare-nginx" }; + private static readonly HashSet<string> CloudflareServerNames = new HashSet<string> { "cloudflare", "cloudflare-nginx", "ddos-guard" }; private readonly ICached<string> _cache; public FlareSolverr(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger, ILocalizationService localizationService, ICacheManager cacheManager) @@ -70,7 +70,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr InjectCookies(newRequest, result); - //Request again with User-Agent and Cookies from Flaresolvrr + //Request again with User-Agent and Cookies from Flaresolverr var finalResponse = _httpClient.Execute(newRequest); return finalResponse; @@ -78,13 +78,24 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr private static bool IsCloudflareProtected(HttpResponse response) { - // check status code + if (!response.Headers.Any(i => i.Key != null && i.Key.ToLower() == "server" && CloudflareServerNames.Contains(i.Value.ToLower()))) + { + return false; + } + + // detect CloudFlare and DDoS-GUARD if (response.StatusCode.Equals(HttpStatusCode.ServiceUnavailable) || response.StatusCode.Equals(HttpStatusCode.Forbidden)) { - // check response headers - return response.Headers.Any(i => - i.Key != null && i.Key.ToLower() == "server" && CloudflareServerNames.Contains(i.Value.ToLower())); + return true; // Defected CloudFlare and DDoS-GUARD + } + + // detect Custom CloudFlare for EbookParadijs, Film-Paleis, MuziekFabriek and Puur-Hollands + if (response.Headers.Vary.ToString() == "Accept-Encoding,User-Agent" && + response.Headers.ContentEncoding.ToString() == "" && + response.Content.ToLower().Contains("ddos")) + { + return true; } return false; From 09ed132fe6dd4f59622024ad0504120c717cbe62 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 4 Jul 2022 22:17:39 -0500 Subject: [PATCH 0535/2320] Rework Cloudflare Protection Detection --- .../Http/HttpClientFixture.cs | 2 +- src/NzbDrone.Common/Http/HttpClient.cs | 2 +- .../CloudFlare/CloudFlareCaptchaException.cs | 21 -------- .../CloudFlare/CloudFlareCaptchaRequest.cs | 15 ------ .../CloudFlare/CloudFlareDetectionService.cs | 45 ++++++++++++++++ .../CloudFlare/CloudFlareHttpInterceptor.cs | 54 ------------------- .../CloudFlareProtectionException.cs | 16 ++++++ .../FlareSolverr/FlareSolverr.cs | 32 ++--------- .../Indexers/Definitions/Anidub.cs | 3 +- .../Indexers/Definitions/Animedia.cs | 3 +- .../Definitions/Cardigann/Cardigann.cs | 2 +- .../Indexers/Definitions/Rarbg/Rarbg.cs | 21 +------- .../Rarbg/RarbgRequestGenerator.cs | 6 --- .../Definitions/Rarbg/RarbgSettings.cs | 3 -- .../Definitions/Rarbg/RarbgTokenProvider.cs | 6 --- .../Indexers/Definitions/SpeedApp.cs | 2 +- src/NzbDrone.Core/Indexers/HttpIndexerBase.cs | 31 ++++------- .../Indexers/TorrentIndexerBase.cs | 2 +- .../Indexers/UsenetIndexerBase.cs | 2 +- 19 files changed, 87 insertions(+), 181 deletions(-) delete mode 100644 src/NzbDrone.Core/Http/CloudFlare/CloudFlareCaptchaException.cs delete mode 100644 src/NzbDrone.Core/Http/CloudFlare/CloudFlareCaptchaRequest.cs create mode 100644 src/NzbDrone.Core/Http/CloudFlare/CloudFlareDetectionService.cs delete mode 100644 src/NzbDrone.Core/Http/CloudFlare/CloudFlareHttpInterceptor.cs create mode 100644 src/NzbDrone.Core/Http/CloudFlare/CloudFlareProtectionException.cs diff --git a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs index 8979c2a19..026d0aae5 100644 --- a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs +++ b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs @@ -67,7 +67,7 @@ namespace NzbDrone.Common.Test.Http res = _httpClient.GetAsync($"https://{site}/status/429").GetAwaiter().GetResult(); - if (res == null || res.StatusCode != (HttpStatusCode)429) + if (res == null || res.StatusCode != HttpStatusCode.TooManyRequests) { return false; } diff --git a/src/NzbDrone.Common/Http/HttpClient.cs b/src/NzbDrone.Common/Http/HttpClient.cs index 6fb27fbb3..b0c3acb13 100644 --- a/src/NzbDrone.Common/Http/HttpClient.cs +++ b/src/NzbDrone.Common/Http/HttpClient.cs @@ -118,7 +118,7 @@ namespace NzbDrone.Common.Http _logger.Warn("HTTP Error - {0}", response); } - if ((int)response.StatusCode == 429) + if (response.StatusCode == HttpStatusCode.TooManyRequests) { throw new TooManyRequestsException(request, response); } diff --git a/src/NzbDrone.Core/Http/CloudFlare/CloudFlareCaptchaException.cs b/src/NzbDrone.Core/Http/CloudFlare/CloudFlareCaptchaException.cs deleted file mode 100644 index db88d5c7b..000000000 --- a/src/NzbDrone.Core/Http/CloudFlare/CloudFlareCaptchaException.cs +++ /dev/null @@ -1,21 +0,0 @@ -using NzbDrone.Common.Exceptions; -using NzbDrone.Common.Http; - -namespace NzbDrone.Core.Http.CloudFlare -{ - public class CloudFlareCaptchaException : NzbDroneException - { - public HttpResponse Response { get; set; } - - public CloudFlareCaptchaRequest CaptchaRequest { get; set; } - - public CloudFlareCaptchaException(HttpResponse response, CloudFlareCaptchaRequest captchaRequest) - : base("Unable to access {0}, blocked by CloudFlare CAPTCHA. Likely due to shared-IP VPN.", response.Request.Url.Host) - { - Response = response; - CaptchaRequest = captchaRequest; - } - - public bool IsExpired => Response.Request.Cookies.ContainsKey("cf_clearance"); - } -} diff --git a/src/NzbDrone.Core/Http/CloudFlare/CloudFlareCaptchaRequest.cs b/src/NzbDrone.Core/Http/CloudFlare/CloudFlareCaptchaRequest.cs deleted file mode 100644 index 332a01059..000000000 --- a/src/NzbDrone.Core/Http/CloudFlare/CloudFlareCaptchaRequest.cs +++ /dev/null @@ -1,15 +0,0 @@ -using NzbDrone.Common.Http; - -namespace NzbDrone.Core.Http.CloudFlare -{ - public class CloudFlareCaptchaRequest - { - public string Host { get; set; } - public string SiteKey { get; set; } - - public string Ray { get; set; } - public string SecretToken { get; set; } - - public HttpUri ResponseUrl { get; set; } - } -} diff --git a/src/NzbDrone.Core/Http/CloudFlare/CloudFlareDetectionService.cs b/src/NzbDrone.Core/Http/CloudFlare/CloudFlareDetectionService.cs new file mode 100644 index 000000000..e00838b67 --- /dev/null +++ b/src/NzbDrone.Core/Http/CloudFlare/CloudFlareDetectionService.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text.RegularExpressions; +using NLog; +using NzbDrone.Common.Http; + +namespace NzbDrone.Core.Http.CloudFlare +{ + public class CloudFlareDetectionService + { + private static readonly HashSet<string> CloudflareServerNames = new HashSet<string> { "cloudflare", "cloudflare-nginx", "ddos-guard" }; + private readonly Logger _logger; + + public CloudFlareDetectionService(Logger logger) + { + _logger = logger; + } + + public static bool IsCloudflareProtected(HttpResponse response) + { + if (!response.Headers.Any(i => i.Key != null && i.Key.ToLower() == "server" && CloudflareServerNames.Contains(i.Value.ToLower()))) + { + return false; + } + + // detect CloudFlare and DDoS-GUARD + if (response.StatusCode.Equals(HttpStatusCode.ServiceUnavailable) || + response.StatusCode.Equals(HttpStatusCode.Forbidden)) + { + return true; // Defected CloudFlare and DDoS-GUARD + } + + // detect Custom CloudFlare for EbookParadijs, Film-Paleis, MuziekFabriek and Puur-Hollands + if (response.Headers.Vary.ToString() == "Accept-Encoding,User-Agent" && + response.Headers.ContentEncoding.ToString() == "" && + response.Content.ToLower().Contains("ddos")) + { + return true; + } + + return false; + } + } +} diff --git a/src/NzbDrone.Core/Http/CloudFlare/CloudFlareHttpInterceptor.cs b/src/NzbDrone.Core/Http/CloudFlare/CloudFlareHttpInterceptor.cs deleted file mode 100644 index dca1d12c0..000000000 --- a/src/NzbDrone.Core/Http/CloudFlare/CloudFlareHttpInterceptor.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Net; -using System.Text.RegularExpressions; -using NLog; -using NzbDrone.Common.Http; - -namespace NzbDrone.Core.Http.CloudFlare -{ - public class CloudFlareHttpInterceptor : IHttpRequestInterceptor - { - private const string _cloudFlareChallengeScript = "cdn-cgi/scripts/cf.challenge.js"; - private readonly Logger _logger; - private static readonly Regex _cloudFlareRegex = new Regex(@"data-ray=""(?<Ray>[\w-_]+)"".*?data-sitekey=""(?<SiteKey>[\w-_]+)"".*?data-stoken=""(?<SecretToken>[\w-_]+)""", RegexOptions.Compiled); - - public CloudFlareHttpInterceptor(Logger logger) - { - _logger = logger; - } - - public HttpRequest PreRequest(HttpRequest request) - { - return request; - } - - public HttpResponse PostResponse(HttpResponse response) - { - if (response.StatusCode == HttpStatusCode.Forbidden && response.Content.Contains(_cloudFlareChallengeScript)) - { - _logger.Debug("CloudFlare CAPTCHA block on {0}", response.Request.Url); - throw new CloudFlareCaptchaException(response, CreateCaptchaRequest(response)); - } - - return response; - } - - private CloudFlareCaptchaRequest CreateCaptchaRequest(HttpResponse response) - { - var match = _cloudFlareRegex.Match(response.Content); - - if (!match.Success) - { - return null; - } - - return new CloudFlareCaptchaRequest - { - Host = response.Request.Url.Host, - SiteKey = match.Groups["SiteKey"].Value, - Ray = match.Groups["Ray"].Value, - SecretToken = match.Groups["SecretToken"].Value, - ResponseUrl = response.Request.Url + new HttpUri("/cdn-cgi/l/chk_captcha") - }; - } - } -} diff --git a/src/NzbDrone.Core/Http/CloudFlare/CloudFlareProtectionException.cs b/src/NzbDrone.Core/Http/CloudFlare/CloudFlareProtectionException.cs new file mode 100644 index 000000000..7ebcd4863 --- /dev/null +++ b/src/NzbDrone.Core/Http/CloudFlare/CloudFlareProtectionException.cs @@ -0,0 +1,16 @@ +using NzbDrone.Common.Exceptions; +using NzbDrone.Common.Http; + +namespace NzbDrone.Core.Http.CloudFlare +{ + public class CloudFlareProtectionException : NzbDroneException + { + public HttpResponse Response { get; set; } + + public CloudFlareProtectionException(HttpResponse response) + : base("Unable to access {0}, blocked by CloudFlare Protection.", response.Request.Url.Host) + { + Response = response; + } + } +} diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index 0275b7178..ff54e3fc9 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -11,6 +11,7 @@ using NzbDrone.Common.Cloud; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Common.Serializer; +using NzbDrone.Core.Http.CloudFlare; using NzbDrone.Core.Localization; using NzbDrone.Core.Validation; @@ -45,7 +46,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr public override HttpResponse PostResponse(HttpResponse response) { - if (!IsCloudflareProtected(response)) + if (!CloudFlareDetectionService.IsCloudflareProtected(response)) { _logger.Debug("CF Protection not detected, returning original response"); return response; @@ -53,14 +54,12 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr var flaresolverrResponse = _httpClient.Execute(GenerateFlareSolverrRequest(response.Request)); - FlareSolverrResponse result = null; - if (flaresolverrResponse.StatusCode != HttpStatusCode.OK && flaresolverrResponse.StatusCode != HttpStatusCode.InternalServerError) { throw new FlareSolverrException("HTTP StatusCode not 200 or 500. Status is :" + response.StatusCode); } - result = JsonConvert.DeserializeObject<FlareSolverrResponse>(flaresolverrResponse.Content); + var result = JsonConvert.DeserializeObject<FlareSolverrResponse>(flaresolverrResponse.Content); var newRequest = response.Request; @@ -76,31 +75,6 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr return finalResponse; } - private static bool IsCloudflareProtected(HttpResponse response) - { - if (!response.Headers.Any(i => i.Key != null && i.Key.ToLower() == "server" && CloudflareServerNames.Contains(i.Value.ToLower()))) - { - return false; - } - - // detect CloudFlare and DDoS-GUARD - if (response.StatusCode.Equals(HttpStatusCode.ServiceUnavailable) || - response.StatusCode.Equals(HttpStatusCode.Forbidden)) - { - return true; // Defected CloudFlare and DDoS-GUARD - } - - // detect Custom CloudFlare for EbookParadijs, Film-Paleis, MuziekFabriek and Puur-Hollands - if (response.Headers.Vary.ToString() == "Accept-Encoding,User-Agent" && - response.Headers.ContentEncoding.ToString() == "" && - response.Content.ToLower().Contains("ddos")) - { - return true; - } - - return false; - } - private void InjectCookies(HttpRequest request, FlareSolverrResponse flareSolverrResponse) { var rCookies = flareSolverrResponse.Solution.Cookies; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs b/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs index 323942b75..08b918aa1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anidub.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Globalization; using System.Linq; +using System.Net; using System.Net.Http; using System.Text; using System.Text.RegularExpressions; @@ -493,7 +494,7 @@ namespace NzbDrone.Core.Indexers.Definitions // Throw common http errors here before we try to parse if (releaseResponse.HttpResponse.HasHttpError) { - if ((int)releaseResponse.HttpResponse.StatusCode == 429) + if (releaseResponse.HttpResponse.StatusCode == HttpStatusCode.TooManyRequests) { throw new TooManyRequestsException(releaseRequest.HttpRequest, releaseResponse.HttpResponse); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs b/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs index 3b73777a8..0710550ba 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Animedia.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.Net; using System.Text; using System.Text.RegularExpressions; using AngleSharp.Html.Parser; @@ -307,7 +308,7 @@ namespace NzbDrone.Core.Indexers.Definitions // Throw common http errors here before we try to parse if (releaseResponse.HttpResponse.HasHttpError) { - if ((int)releaseResponse.HttpResponse.StatusCode == 429) + if (releaseResponse.HttpResponse.StatusCode == HttpStatusCode.TooManyRequests) { throw new TooManyRequestsException(releaseRequest.HttpRequest, releaseResponse.HttpResponse); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs index 23285b6c3..34d0f8a99 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs @@ -194,7 +194,7 @@ namespace NzbDrone.Core.Indexers.Cardigann throw new ReleaseUnavailableException("Downloading torrent failed", ex); } - if ((int)ex.Response.StatusCode == 429) + if (ex.Response.StatusCode == HttpStatusCode.TooManyRequests) { _logger.Error("API Grab Limit reached for {0}", request.Url.FullUri); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs index 4bb424ec9..4fc04fbf4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs @@ -101,29 +101,12 @@ namespace NzbDrone.Core.Indexers.Rarbg { Settings.Validate().Filter("BaseUrl").ThrowOnError(); - try - { - var request = new HttpRequestBuilder(Settings.BaseUrl.Trim('/')) + var request = new HttpRequestBuilder(Settings.BaseUrl.Trim('/')) .Resource($"/pubapi_v2.php?get_token=get_token&app_id={BuildInfo.AppName}") .Accept(HttpAccept.Json) .Build(); - _httpClient.Get(request); - } - catch (CloudFlareCaptchaException ex) - { - return new - { - captchaRequest = new - { - host = ex.CaptchaRequest.Host, - ray = ex.CaptchaRequest.Ray, - siteKey = ex.CaptchaRequest.SiteKey, - secretToken = ex.CaptchaRequest.SecretToken, - responseUrl = ex.CaptchaRequest.ResponseUrl.FullUri, - } - }; - } + _httpClient.Get(request); return new { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs index 29093f389..cef7b90f0 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs @@ -26,12 +26,6 @@ namespace NzbDrone.Core.Indexers.Rarbg .Resource("/pubapi_v2.php") .Accept(HttpAccept.Json); - if (Settings.CaptchaToken.IsNotNullOrWhiteSpace()) - { - requestBuilder.UseSimplifiedUserAgent = true; - requestBuilder.SetCookie("cf_clearance", Settings.CaptchaToken); - } - requestBuilder.AddQueryParam("mode", "search"); if (imdbId.IsNotNullOrWhiteSpace()) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgSettings.cs index 6eef9727a..45c091e6d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgSettings.cs @@ -14,8 +14,5 @@ namespace NzbDrone.Core.Indexers.Rarbg [FieldDefinition(2, Type = FieldType.Checkbox, Label = "Ranked Only", HelpText = "Only include ranked results.")] public bool RankedOnly { get; set; } - - [FieldDefinition(3, Type = FieldType.Captcha, Label = "CAPTCHA Token", HelpText = "CAPTCHA Clearance token used to handle CloudFlare Anti-DDOS measures on shared-ip VPNs.")] - public string CaptchaToken { get; set; } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs index 613aa1f39..60069d089 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs @@ -36,12 +36,6 @@ namespace NzbDrone.Core.Indexers.Rarbg .Resource($"/pubapi_v2.php?get_token=get_token&app_id={BuildInfo.AppName}") .Accept(HttpAccept.Json); - if (settings.CaptchaToken.IsNotNullOrWhiteSpace()) - { - requestBuilder.UseSimplifiedUserAgent = true; - requestBuilder.SetCookie("cf_clearance", settings.CaptchaToken); - } - var response = _httpClient.Get<JObject>(requestBuilder.Build()); return response.Resource["token"].ToString(); diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs index 2bd83027b..d4b696246 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs @@ -154,7 +154,7 @@ namespace NzbDrone.Core.Indexers.Definitions throw new ReleaseUnavailableException("Downloading torrent failed", ex); } - if ((int)ex.Response.StatusCode == 429) + if (ex.Response.StatusCode == HttpStatusCode.TooManyRequests) { _logger.Error("API Grab Limit reached for {0}", link.AbsoluteUri); } diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index 0e0d435fb..9adc525e2 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -232,7 +232,7 @@ namespace NzbDrone.Core.Indexers _indexerStatusService.RecordFailure(Definition.Id, TimeSpan.FromHours(1)); } - _logger.Warn("API Request Limit reached for {0}", this); + _logger.Warn("Request Limit reached for {0}", this); } catch (HttpException ex) { @@ -251,19 +251,12 @@ namespace NzbDrone.Core.Indexers _indexerStatusService.RecordFailure(Definition.Id); _logger.Warn("Invalid Credentials for {0} {1}", this, url); } - catch (CloudFlareCaptchaException ex) + catch (CloudFlareProtectionException ex) { result.Queries.Add(new IndexerQueryResult { Response = ex.Response }); _indexerStatusService.RecordFailure(Definition.Id); ex.WithData("FeedUrl", url); - if (ex.IsExpired) - { - _logger.Error(ex, "Expired CAPTCHA token for {0}, please refresh in indexer settings.", this); - } - else - { - _logger.Error(ex, "CAPTCHA token required for {0}, check indexer settings.", this); - } + _logger.Error(ex, "Cloudflare protection detected for {0}, Flaresolverr may be required.", this); } catch (IndexerException ex) { @@ -399,12 +392,17 @@ namespace NzbDrone.Core.Indexers { _logger.Warn("HTTP Error - {0}", response); - if ((int)response.StatusCode == 429) + if (response.StatusCode == HttpStatusCode.TooManyRequests) { throw new TooManyRequestsException(request.HttpRequest, response); } } + if (CloudFlareDetectionService.IsCloudflareProtected(response)) + { + throw new CloudFlareProtectionException(response); + } + UpdateCookies(Cookies, DateTime.Now + TimeSpan.FromDays(30)); return new IndexerResponse(request, response); @@ -471,16 +469,9 @@ namespace NzbDrone.Core.Indexers { _logger.Warn("Request limit reached: " + ex.Message); } - catch (CloudFlareCaptchaException ex) + catch (CloudFlareProtectionException ex) { - if (ex.IsExpired) - { - return new ValidationFailure("CaptchaToken", "CloudFlare CAPTCHA token expired, please Refresh."); - } - else - { - return new ValidationFailure("CaptchaToken", "Site protected by CloudFlare CAPTCHA. Valid CAPTCHA token required."); - } + return new ValidationFailure(string.Empty, ex.Message); } catch (UnsupportedFeedException ex) { diff --git a/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs b/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs index 451d001a7..b804c2903 100644 --- a/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs @@ -54,7 +54,7 @@ namespace NzbDrone.Core.Indexers throw new ReleaseUnavailableException("Downloading torrent failed", ex); } - if ((int)ex.Response.StatusCode == 429) + if (ex.Response.StatusCode == HttpStatusCode.TooManyRequests) { _logger.Error("API Grab Limit reached for {0}", link.AbsoluteUri); } diff --git a/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs b/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs index af3044c33..f8104a844 100644 --- a/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs @@ -52,7 +52,7 @@ namespace NzbDrone.Core.Indexers throw new ReleaseUnavailableException("Downloading nzb failed", ex); } - if ((int)ex.Response.StatusCode == 429) + if (ex.Response.StatusCode == HttpStatusCode.TooManyRequests) { _logger.Error("API Grab Limit reached for {0}", link.AbsoluteUri); } From 4dee1d65d1b4368237e8976f8e65dad031bf2746 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 4 Jul 2022 22:50:17 -0500 Subject: [PATCH 0536/2320] New: (AvistaZ) Parse Languages and Subs, pass in response #694 --- .../IndexerTests/AvistazTests/AvistazFixture.cs | 4 ++++ src/NzbDrone.Core/IndexerSearch/NewznabResults.cs | 4 ++-- .../Indexers/Definitions/Avistaz/AvistazApi.cs | 8 ++++++++ .../Indexers/Definitions/Avistaz/AvistazParser.cs | 2 ++ src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs | 6 ++++-- 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/AvistazFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/AvistazFixture.cs index 230512265..290944b46 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/AvistazFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/AvistazFixture.cs @@ -60,6 +60,10 @@ namespace NzbDrone.Core.Test.IndexerTests.AvistazTests torrentInfo.ImdbId.Should().Be(15569106); torrentInfo.TmdbId.Should().Be(135144); torrentInfo.TvdbId.Should().Be(410548); + torrentInfo.Languages.Should().HaveCount(1); + torrentInfo.Languages.First().Should().Be("Japanese"); + torrentInfo.Subs.Should().HaveCount(27); + torrentInfo.Subs.First().Should().Be("Arabic"); } } } diff --git a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs index 85af5b5f4..985822788 100644 --- a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs +++ b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs @@ -90,8 +90,8 @@ namespace NzbDrone.Core.IndexerSearch new XAttribute("type", protocol == DownloadProtocol.Torrent ? "application/x-bittorrent" : "application/x-nzb")), r.Categories == null ? null : from c in r.Categories select GetNabElement("category", c.Id, protocol), r.IndexerFlags == null ? null : from f in r.IndexerFlags select GetNabElement("tag", f.Name, protocol), - r.Languages == null ? null : from c in r.Languages select GetNabElement("language", c.Id, protocol), - r.Subs == null ? null : from c in r.Subs select GetNabElement("subs", c.Id, protocol), + r.Languages == null ? null : from c in r.Languages select GetNabElement("language", c, protocol), + r.Subs == null ? null : from c in r.Subs select GetNabElement("subs", c, protocol), r.Genres == null ? null : GetNabElement("genre", string.Join(", ", r.Genres), protocol), GetNabElement("rageid", r.TvRageId, protocol), GetNabElement("tvdbid", r.TvdbId, protocol), diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs index fd2b2b892..068be1881 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs @@ -40,6 +40,14 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz [JsonProperty(PropertyName = "video_quality")] public string VideoQuality { get; set; } public string Type { get; set; } + public List<AvistazLanguage> Audio { get; set; } + public List<AvistazLanguage> Subtitle { get; set; } + } + + public class AvistazLanguage + { + public int Id { get; set; } + public string Language { get; set; } } public class AvistazResponse diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs index 4029b45c0..c38fb9df4 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs @@ -66,6 +66,8 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz UploadVolumeFactor = row.UploadMultiply, MinimumRatio = 1, MinimumSeedTime = 172800, // 48 hours + Languages = row.Audio?.Select(x => x.Language).ToList() ?? new List<string>(), + Subs = row.Subtitle?.Select(x => x.Language).ToList() ?? new List<string>() }; if (row.MovieTvinfo != null) diff --git a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs index 0505c9e0d..f76e36747 100644 --- a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs +++ b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs @@ -13,6 +13,8 @@ namespace NzbDrone.Core.Parser.Model { IndexerFlags = new List<IndexerFlag>(); Categories = new List<IndexerCategory>(); + Languages = new List<string>(); + Subs = new List<string>(); } public string Guid { get; set; } @@ -49,8 +51,8 @@ namespace NzbDrone.Core.Parser.Model public string Codec { get; set; } public string Resolution { get; set; } public ICollection<string> Genres { get; set; } - public ICollection<Language> Languages { get; set; } - public ICollection<Language> Subs { get; set; } + public ICollection<string> Languages { get; set; } + public ICollection<string> Subs { get; set; } public ICollection<IndexerCategory> Categories { get; set; } public ICollection<IndexerFlag> IndexerFlags { get; set; } From 8b8d0b24ae5388722d59343571a6ae61f5d9391a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 5 Jul 2022 07:27:48 -0500 Subject: [PATCH 0537/2320] Fix NullRef in Cloudflare detection service --- .../Http/CloudFlare/CloudFlareDetectionService.cs | 4 ++-- src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Http/CloudFlare/CloudFlareDetectionService.cs b/src/NzbDrone.Core/Http/CloudFlare/CloudFlareDetectionService.cs index e00838b67..0ea144217 100644 --- a/src/NzbDrone.Core/Http/CloudFlare/CloudFlareDetectionService.cs +++ b/src/NzbDrone.Core/Http/CloudFlare/CloudFlareDetectionService.cs @@ -32,8 +32,8 @@ namespace NzbDrone.Core.Http.CloudFlare } // detect Custom CloudFlare for EbookParadijs, Film-Paleis, MuziekFabriek and Puur-Hollands - if (response.Headers.Vary.ToString() == "Accept-Encoding,User-Agent" && - response.Headers.ContentEncoding.ToString() == "" && + if (response.Headers.Vary == "Accept-Encoding,User-Agent" && + response.Headers.ContentEncoding == "" && response.Content.ToLower().Contains("ddos")) { return true; diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index ff54e3fc9..baa873222 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -19,7 +19,6 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr { public class FlareSolverr : HttpIndexerProxyBase<FlareSolverrSettings> { - private static readonly HashSet<string> CloudflareServerNames = new HashSet<string> { "cloudflare", "cloudflare-nginx", "ddos-guard" }; private readonly ICached<string> _cache; public FlareSolverr(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger, ILocalizationService localizationService, ICacheManager cacheManager) From f26b0474f573951088d6197cdb5ce5c4b512d8aa Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 5 Jul 2022 07:32:16 -0500 Subject: [PATCH 0538/2320] Fixed: BeyondHD using improperly cased Content-Type header --- src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs b/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs index 2021ba987..05acf60c9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BeyondHD.cs @@ -111,7 +111,7 @@ namespace NzbDrone.Core.Indexers.Definitions var request = new HttpRequest(searchUrl, HttpAccept.Json); - request.Headers.Add("Content-type", "application/json"); + request.Headers.ContentType = "application/json"; request.Method = HttpMethod.Post; request.SetContent(body.ToJson()); From cad4f3740bbdc49df21c768a043694ae388d74d0 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Wed, 6 Jul 2022 02:30:58 +0000 Subject: [PATCH 0539/2320] Added translation using Weblate (Lithuanian) Co-authored-by: Qstick <qstick@gmail.com> --- src/NzbDrone.Core/Localization/Core/lt.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/NzbDrone.Core/Localization/Core/lt.json diff --git a/src/NzbDrone.Core/Localization/Core/lt.json b/src/NzbDrone.Core/Localization/Core/lt.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/src/NzbDrone.Core/Localization/Core/lt.json @@ -0,0 +1 @@ +{} From 8c10f8b55cdb495ccd63b48b86f3f1052c81edd6 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 5 Jul 2022 21:22:54 -0500 Subject: [PATCH 0540/2320] Cleanup Language and Localization code --- frontend/src/Components/Page/PageConnector.js | 15 +- frontend/src/Settings/UI/UISettings.js | 4 +- .../src/Settings/UI/UISettingsConnector.js | 17 +- .../src/Store/Actions/Settings/languages.js | 48 ---- frontend/src/Store/Actions/index.js | 2 + .../src/Store/Actions/localizationActions.js | 39 +++ frontend/src/Store/Actions/settingsActions.js | 5 - .../Languages/LanguageFixture.cs | 85 ------ .../LocalizationServiceFixture.cs | 3 +- .../Configuration/ConfigService.cs | 5 +- .../Configuration/IConfigService.cs | 2 +- .../Converters/LanguageIntConverter.cs | 48 ---- .../021_localization_setting_to_string.cs | 82 ++++++ src/NzbDrone.Core/Datastore/TableMapping.cs | 3 - src/NzbDrone.Core/Languages/Language.cs | 193 ------------- .../Languages/LanguageExtensions.cs | 13 - .../Languages/LanguageFieldConverter.cs | 13 - .../Languages/LanguagesComparer.cs | 53 ---- .../Languages/RealLanguageFieldConverter.cs | 17 -- .../Localization/LocalizationOption.cs | 14 + .../Localization/LocalizationService.cs | 55 +++- src/NzbDrone.Core/Parser/IsoLanguage.cs | 22 -- src/NzbDrone.Core/Parser/IsoLanguages.cs | 85 ------ src/NzbDrone.Core/Parser/LanguageParser.cs | 272 ------------------ src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs | 1 - .../Config/UiConfigResource.cs | 2 +- .../Languages/LanguageController.cs | 37 --- .../Languages/LanguageResource.cs | 13 - .../Localization/LocalizationController.cs | 8 + 29 files changed, 204 insertions(+), 952 deletions(-) delete mode 100644 frontend/src/Store/Actions/Settings/languages.js create mode 100644 frontend/src/Store/Actions/localizationActions.js delete mode 100644 src/NzbDrone.Core.Test/Languages/LanguageFixture.cs delete mode 100644 src/NzbDrone.Core/Datastore/Converters/LanguageIntConverter.cs create mode 100644 src/NzbDrone.Core/Datastore/Migration/021_localization_setting_to_string.cs delete mode 100644 src/NzbDrone.Core/Languages/Language.cs delete mode 100644 src/NzbDrone.Core/Languages/LanguageExtensions.cs delete mode 100644 src/NzbDrone.Core/Languages/LanguageFieldConverter.cs delete mode 100644 src/NzbDrone.Core/Languages/LanguagesComparer.cs delete mode 100644 src/NzbDrone.Core/Languages/RealLanguageFieldConverter.cs create mode 100644 src/NzbDrone.Core/Localization/LocalizationOption.cs delete mode 100644 src/NzbDrone.Core/Parser/IsoLanguage.cs delete mode 100644 src/NzbDrone.Core/Parser/IsoLanguages.cs delete mode 100644 src/NzbDrone.Core/Parser/LanguageParser.cs delete mode 100644 src/Prowlarr.Api.V1/Languages/LanguageController.cs delete mode 100644 src/Prowlarr.Api.V1/Languages/LanguageResource.cs diff --git a/frontend/src/Components/Page/PageConnector.js b/frontend/src/Components/Page/PageConnector.js index 0f826fd68..647fdcf7b 100644 --- a/frontend/src/Components/Page/PageConnector.js +++ b/frontend/src/Components/Page/PageConnector.js @@ -7,7 +7,7 @@ import { saveDimensions, setIsSidebarVisible } from 'Store/Actions/appActions'; import { fetchCustomFilters } from 'Store/Actions/customFilterActions'; import { fetchIndexers } from 'Store/Actions/indexerActions'; import { fetchIndexerStatus } from 'Store/Actions/indexerStatusActions'; -import { fetchAppProfiles, fetchGeneralSettings, fetchIndexerCategories, fetchLanguages, fetchUISettings } from 'Store/Actions/settingsActions'; +import { fetchAppProfiles, fetchGeneralSettings, fetchIndexerCategories, fetchUISettings } from 'Store/Actions/settingsActions'; import { fetchStatus } from 'Store/Actions/systemActions'; import { fetchTags } from 'Store/Actions/tagActions'; import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector'; @@ -48,7 +48,6 @@ const selectIsPopulated = createSelector( (state) => state.tags.isPopulated, (state) => state.settings.ui.isPopulated, (state) => state.settings.general.isPopulated, - (state) => state.settings.languages.isPopulated, (state) => state.settings.appProfiles.isPopulated, (state) => state.indexers.isPopulated, (state) => state.indexerStatus.isPopulated, @@ -59,7 +58,6 @@ const selectIsPopulated = createSelector( tagsIsPopulated, uiSettingsIsPopulated, generalSettingsIsPopulated, - languagesIsPopulated, appProfilesIsPopulated, indexersIsPopulated, indexerStatusIsPopulated, @@ -71,7 +69,6 @@ const selectIsPopulated = createSelector( tagsIsPopulated && uiSettingsIsPopulated && generalSettingsIsPopulated && - languagesIsPopulated && appProfilesIsPopulated && indexersIsPopulated && indexerStatusIsPopulated && @@ -86,7 +83,6 @@ const selectErrors = createSelector( (state) => state.tags.error, (state) => state.settings.ui.error, (state) => state.settings.general.error, - (state) => state.settings.languages.error, (state) => state.settings.appProfiles.error, (state) => state.indexers.error, (state) => state.indexerStatus.error, @@ -97,7 +93,6 @@ const selectErrors = createSelector( tagsError, uiSettingsError, generalSettingsError, - languagesError, appProfilesError, indexersError, indexerStatusError, @@ -109,7 +104,6 @@ const selectErrors = createSelector( tagsError || uiSettingsError || generalSettingsError || - languagesError || appProfilesError || indexersError || indexerStatusError || @@ -123,7 +117,6 @@ const selectErrors = createSelector( tagsError, uiSettingsError, generalSettingsError, - languagesError, appProfilesError, indexersError, indexerStatusError, @@ -166,9 +159,6 @@ function createMapDispatchToProps(dispatch, props) { dispatchFetchTags() { dispatch(fetchTags()); }, - dispatchFetchLanguages() { - dispatch(fetchLanguages()); - }, dispatchFetchIndexers() { dispatch(fetchIndexers()); }, @@ -216,7 +206,6 @@ class PageConnector extends Component { if (!this.props.isPopulated) { this.props.dispatchFetchCustomFilters(); this.props.dispatchFetchTags(); - this.props.dispatchFetchLanguages(); this.props.dispatchFetchAppProfiles(); this.props.dispatchFetchIndexers(); this.props.dispatchFetchIndexerStatus(); @@ -242,7 +231,6 @@ class PageConnector extends Component { isPopulated, hasError, dispatchFetchTags, - dispatchFetchLanguages, dispatchFetchAppProfiles, dispatchFetchIndexers, dispatchFetchIndexerStatus, @@ -283,7 +271,6 @@ PageConnector.propTypes = { isSidebarVisible: PropTypes.bool.isRequired, dispatchFetchCustomFilters: PropTypes.func.isRequired, dispatchFetchTags: PropTypes.func.isRequired, - dispatchFetchLanguages: PropTypes.func.isRequired, dispatchFetchAppProfiles: PropTypes.func.isRequired, dispatchFetchIndexers: PropTypes.func.isRequired, dispatchFetchIndexerStatus: PropTypes.func.isRequired, diff --git a/frontend/src/Settings/UI/UISettings.js b/frontend/src/Settings/UI/UISettings.js index 7b395225b..83443cd72 100644 --- a/frontend/src/Settings/UI/UISettings.js +++ b/frontend/src/Settings/UI/UISettings.js @@ -62,8 +62,6 @@ class UISettings extends Component { ...otherProps } = this.props; - const uiLanguages = languages.filter((item) => item.value !== 'Original'); - const themeOptions = Object.keys(themes) .map((theme) => ({ key: theme, value: titleCase(theme) })); @@ -172,7 +170,7 @@ class UISettings extends Component { <FormInputGroup type={inputTypes.SELECT} name="uiLanguage" - values={uiLanguages} + values={languages} helpText={translate('UILanguageHelpText')} helpTextWarning={translate('UILanguageHelpTextWarning')} onChange={onInputChange} diff --git a/frontend/src/Settings/UI/UISettingsConnector.js b/frontend/src/Settings/UI/UISettingsConnector.js index ea9194f8c..98af9dfce 100644 --- a/frontend/src/Settings/UI/UISettingsConnector.js +++ b/frontend/src/Settings/UI/UISettingsConnector.js @@ -3,6 +3,7 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; import { clearPendingChanges } from 'Store/Actions/baseActions'; +import { fetchLocalizationOptions } from 'Store/Actions/localizationActions'; import { fetchUISettings, saveUISettings, setUISettingsValue } from 'Store/Actions/settingsActions'; import createSettingsSectionSelector from 'Store/Selectors/createSettingsSectionSelector'; import UISettings from './UISettings'; @@ -11,18 +12,19 @@ const SECTION = 'ui'; function createLanguagesSelector() { return createSelector( - (state) => state.settings.languages, - (languages) => { - const items = languages.items; - const filterItems = ['Any', 'Unknown']; + (state) => state.localization, + (localization) => { + console.log(localization); + + const items = localization.items; if (!items) { return []; } - const newItems = items.filter((lang) => !filterItems.includes(lang.name)).map((item) => { + const newItems = items.filter((lang) => !items.includes(lang.name)).map((item) => { return { - key: item.id, + key: item.value, value: item.name }; }); @@ -51,6 +53,7 @@ const mapDispatchToProps = { setUISettingsValue, saveUISettings, fetchUISettings, + fetchLocalizationOptions, clearPendingChanges }; @@ -61,6 +64,7 @@ class UISettingsConnector extends Component { componentDidMount() { this.props.fetchUISettings(); + this.props.fetchLocalizationOptions(); } componentWillUnmount() { @@ -96,6 +100,7 @@ UISettingsConnector.propTypes = { setUISettingsValue: PropTypes.func.isRequired, saveUISettings: PropTypes.func.isRequired, fetchUISettings: PropTypes.func.isRequired, + fetchLocalizationOptions: PropTypes.func.isRequired, clearPendingChanges: PropTypes.func.isRequired }; diff --git a/frontend/src/Store/Actions/Settings/languages.js b/frontend/src/Store/Actions/Settings/languages.js deleted file mode 100644 index a0b62fc49..000000000 --- a/frontend/src/Store/Actions/Settings/languages.js +++ /dev/null @@ -1,48 +0,0 @@ -import createFetchHandler from 'Store/Actions/Creators/createFetchHandler'; -import { createThunk } from 'Store/thunks'; - -// -// Variables - -const section = 'settings.languages'; - -// -// Actions Types - -export const FETCH_LANGUAGES = 'settings/languages/fetchLanguages'; - -// -// Action Creators - -export const fetchLanguages = createThunk(FETCH_LANGUAGES); - -// -// Details - -export default { - - // - // State - - defaultState: { - isFetching: false, - isPopulated: false, - error: null, - items: [] - }, - - // - // Action Handlers - - actionHandlers: { - [FETCH_LANGUAGES]: createFetchHandler(section, '/language') - }, - - // - // Reducers - - reducers: { - - } - -}; diff --git a/frontend/src/Store/Actions/index.js b/frontend/src/Store/Actions/index.js index 1f0eccd71..98db37faf 100644 --- a/frontend/src/Store/Actions/index.js +++ b/frontend/src/Store/Actions/index.js @@ -7,6 +7,7 @@ import * as indexers from './indexerActions'; import * as indexerIndex from './indexerIndexActions'; import * as indexerStats from './indexerStatsActions'; import * as indexerStatus from './indexerStatusActions'; +import * as localization from './localizationActions'; import * as oAuth from './oAuthActions'; import * as paths from './pathActions'; import * as providerOptions from './providerOptionActions'; @@ -25,6 +26,7 @@ export default [ paths, providerOptions, releases, + localization, indexers, indexerIndex, indexerStats, diff --git a/frontend/src/Store/Actions/localizationActions.js b/frontend/src/Store/Actions/localizationActions.js new file mode 100644 index 000000000..f7928fc63 --- /dev/null +++ b/frontend/src/Store/Actions/localizationActions.js @@ -0,0 +1,39 @@ +import createFetchHandler from 'Store/Actions/Creators/createFetchHandler'; +import { createThunk, handleThunks } from 'Store/thunks'; +import createHandleActions from './Creators/createHandleActions'; + +// +// Variables + +export const section = 'localization'; + +// +// State + +export const defaultState = { + isFetching: false, + isPopulated: false, + error: null, + items: [] +}; + +// +// Actions Types + +export const FETCH_LOCALIZATION_OPTIONS = 'localization/fetchLocalizationOptions'; + +// +// Action Creators + +export const fetchLocalizationOptions = createThunk(FETCH_LOCALIZATION_OPTIONS); + +// +// Action Handlers +export const actionHandlers = handleThunks({ + + [FETCH_LOCALIZATION_OPTIONS]: createFetchHandler(section, '/localization/options') +}); + +// +// Reducers +export const reducers = createHandleActions({}, defaultState, section); diff --git a/frontend/src/Store/Actions/settingsActions.js b/frontend/src/Store/Actions/settingsActions.js index e7fe7247a..6aa4ad6be 100644 --- a/frontend/src/Store/Actions/settingsActions.js +++ b/frontend/src/Store/Actions/settingsActions.js @@ -8,7 +8,6 @@ import downloadClients from './Settings/downloadClients'; import general from './Settings/general'; import indexerCategories from './Settings/indexerCategories'; import indexerProxies from './Settings/indexerProxies'; -import languages from './Settings/languages'; import notifications from './Settings/notifications'; import ui from './Settings/ui'; @@ -16,7 +15,6 @@ export * from './Settings/downloadClients'; export * from './Settings/general'; export * from './Settings/indexerCategories'; export * from './Settings/indexerProxies'; -export * from './Settings/languages'; export * from './Settings/notifications'; export * from './Settings/applications'; export * from './Settings/appProfiles'; @@ -38,7 +36,6 @@ export const defaultState = { general: general.defaultState, indexerCategories: indexerCategories.defaultState, indexerProxies: indexerProxies.defaultState, - languages: languages.defaultState, notifications: notifications.defaultState, applications: applications.defaultState, appProfiles: appProfiles.defaultState, @@ -68,7 +65,6 @@ export const actionHandlers = handleThunks({ ...general.actionHandlers, ...indexerCategories.actionHandlers, ...indexerProxies.actionHandlers, - ...languages.actionHandlers, ...notifications.actionHandlers, ...applications.actionHandlers, ...appProfiles.actionHandlers, @@ -89,7 +85,6 @@ export const reducers = createHandleActions({ ...general.reducers, ...indexerCategories.reducers, ...indexerProxies.reducers, - ...languages.reducers, ...notifications.reducers, ...applications.reducers, ...appProfiles.reducers, diff --git a/src/NzbDrone.Core.Test/Languages/LanguageFixture.cs b/src/NzbDrone.Core.Test/Languages/LanguageFixture.cs deleted file mode 100644 index 706c36541..000000000 --- a/src/NzbDrone.Core.Test/Languages/LanguageFixture.cs +++ /dev/null @@ -1,85 +0,0 @@ -using FluentAssertions; -using NUnit.Framework; -using NzbDrone.Core.Languages; -using NzbDrone.Core.Test.Framework; - -namespace NzbDrone.Core.Test.Languages -{ - [TestFixture] - public class LanguageFixture : CoreTest - { - public static object[] FromIntCases = - { - new object[] { 1, Language.English }, - new object[] { 2, Language.French }, - new object[] { 3, Language.Spanish }, - new object[] { 4, Language.German }, - new object[] { 5, Language.Italian }, - new object[] { 6, Language.Danish }, - new object[] { 7, Language.Dutch }, - new object[] { 8, Language.Japanese }, - new object[] { 9, Language.Icelandic }, - new object[] { 10, Language.Chinese }, - new object[] { 11, Language.Russian }, - new object[] { 12, Language.Polish }, - new object[] { 13, Language.Vietnamese }, - new object[] { 14, Language.Swedish }, - new object[] { 15, Language.Norwegian }, - new object[] { 16, Language.Finnish }, - new object[] { 17, Language.Turkish }, - new object[] { 18, Language.Portuguese }, - new object[] { 19, Language.Flemish }, - new object[] { 20, Language.Greek }, - new object[] { 21, Language.Korean }, - new object[] { 22, Language.Hungarian }, - new object[] { 23, Language.Hebrew }, - new object[] { 24, Language.Lithuanian }, - new object[] { 25, Language.Czech } - }; - - public static object[] ToIntCases = - { - new object[] { Language.English, 1 }, - new object[] { Language.French, 2 }, - new object[] { Language.Spanish, 3 }, - new object[] { Language.German, 4 }, - new object[] { Language.Italian, 5 }, - new object[] { Language.Danish, 6 }, - new object[] { Language.Dutch, 7 }, - new object[] { Language.Japanese, 8 }, - new object[] { Language.Icelandic, 9 }, - new object[] { Language.Chinese, 10 }, - new object[] { Language.Russian, 11 }, - new object[] { Language.Polish, 12 }, - new object[] { Language.Vietnamese, 13 }, - new object[] { Language.Swedish, 14 }, - new object[] { Language.Norwegian, 15 }, - new object[] { Language.Finnish, 16 }, - new object[] { Language.Turkish, 17 }, - new object[] { Language.Portuguese, 18 }, - new object[] { Language.Flemish, 19 }, - new object[] { Language.Greek, 20 }, - new object[] { Language.Korean, 21 }, - new object[] { Language.Hungarian, 22 }, - new object[] { Language.Hebrew, 23 }, - new object[] { Language.Lithuanian, 24 }, - new object[] { Language.Czech, 25 } - }; - - [Test] - [TestCaseSource("FromIntCases")] - public void should_be_able_to_convert_int_to_languageTypes(int source, Language expected) - { - var language = (Language)source; - language.Should().Be(expected); - } - - [Test] - [TestCaseSource("ToIntCases")] - public void should_be_able_to_convert_languageTypes_to_int(Language source, int expected) - { - var i = (int)source; - i.Should().Be(expected); - } - } -} diff --git a/src/NzbDrone.Core.Test/Localization/LocalizationServiceFixture.cs b/src/NzbDrone.Core.Test/Localization/LocalizationServiceFixture.cs index 9998bb8ee..e49b0592d 100644 --- a/src/NzbDrone.Core.Test/Localization/LocalizationServiceFixture.cs +++ b/src/NzbDrone.Core.Test/Localization/LocalizationServiceFixture.cs @@ -3,7 +3,6 @@ using FluentAssertions; using NUnit.Framework; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Core.Configuration; -using NzbDrone.Core.Languages; using NzbDrone.Core.Localization; using NzbDrone.Core.Test.Framework; using NzbDrone.Test.Common; @@ -16,7 +15,7 @@ namespace NzbDrone.Core.Test.Localization [SetUp] public void Setup() { - Mocker.GetMock<IConfigService>().Setup(m => m.UILanguage).Returns((int)Language.English); + Mocker.GetMock<IConfigService>().Setup(m => m.UILanguage).Returns("en"); Mocker.GetMock<IAppFolderInfo>().Setup(m => m.StartUpFolder).Returns(TestContext.CurrentContext.TestDirectory); } diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index 8cedd7b26..269847f33 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -6,7 +6,6 @@ using NLog; using NzbDrone.Common.EnsureThat; using NzbDrone.Common.Http.Proxy; using NzbDrone.Core.Configuration.Events; -using NzbDrone.Core.Languages; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Security; @@ -139,9 +138,9 @@ namespace NzbDrone.Core.Configuration set { SetValue("EnableColorImpairedMode", value); } } - public int UILanguage + public string UILanguage { - get { return GetValueInt("UILanguage", (int)Language.English); } + get { return GetValue("UILanguage", "en"); } set { SetValue("UILanguage", value); } } diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index 8da617821..4f37b8d51 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -22,7 +22,7 @@ namespace NzbDrone.Core.Configuration string TimeFormat { get; set; } bool ShowRelativeDates { get; set; } bool EnableColorImpairedMode { get; set; } - int UILanguage { get; set; } + string UILanguage { get; set; } //Internal string PlexClientIdentifier { get; } diff --git a/src/NzbDrone.Core/Datastore/Converters/LanguageIntConverter.cs b/src/NzbDrone.Core/Datastore/Converters/LanguageIntConverter.cs deleted file mode 100644 index b7981367f..000000000 --- a/src/NzbDrone.Core/Datastore/Converters/LanguageIntConverter.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Data; -using System.Text.Json; -using System.Text.Json.Serialization; -using Dapper; -using NzbDrone.Core.Languages; - -namespace NzbDrone.Core.Datastore.Converters -{ - public class DapperLanguageIntConverter : SqlMapper.TypeHandler<Language> - { - public override void SetValue(IDbDataParameter parameter, Language value) - { - if (value == null) - { - throw new InvalidOperationException("Attempted to save a language that isn't really a language"); - } - else - { - parameter.Value = (int)value; - } - } - - public override Language Parse(object value) - { - if (value == null || value is DBNull) - { - return Language.Unknown; - } - - return (Language)Convert.ToInt32(value); - } - } - - public class LanguageIntConverter : JsonConverter<Language> - { - public override Language Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - var item = reader.GetInt32(); - return (Language)item; - } - - public override void Write(Utf8JsonWriter writer, Language value, JsonSerializerOptions options) - { - writer.WriteNumberValue((int)value); - } - } -} diff --git a/src/NzbDrone.Core/Datastore/Migration/021_localization_setting_to_string.cs b/src/NzbDrone.Core/Datastore/Migration/021_localization_setting_to_string.cs new file mode 100644 index 000000000..3cd0cc4c6 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/021_localization_setting_to_string.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Data; +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(021)] + public class localization_setting_to_string : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Execute.WithConnection(FixLocalizationConfig); + } + + private void FixLocalizationConfig(IDbConnection conn, IDbTransaction tran) + { + string uiLanguage; + string uiCulture; + + using (var cmd = conn.CreateCommand()) + { + cmd.Transaction = tran; + cmd.CommandText = "SELECT \"Value\" FROM \"Config\" WHERE \"Key\" = 'uilanguage'"; + + uiLanguage = (string)cmd.ExecuteScalar(); + } + + if (uiLanguage != null && int.TryParse(uiLanguage, out var uiLanguageInt)) + { + uiCulture = _uiMapping.GetValueOrDefault(uiLanguageInt) ?? "en"; + + using (var insertCmd = conn.CreateCommand()) + { + insertCmd.Transaction = tran; + insertCmd.CommandText = string.Format("UPDATE \"Config\" SET \"Value\" = '{0}' WHERE \"Key\" = 'uilanguage'", uiCulture); + insertCmd.ExecuteNonQuery(); + } + } + } + + private readonly Dictionary<int, string> _uiMapping = new Dictionary<int, string>() + { + { 1, "en" }, + { 2, "fr" }, + { 3, "es" }, + { 4, "de" }, + { 5, "it" }, + { 6, "da" }, + { 7, "nl" }, + { 8, "ja" }, + { 9, "is" }, + { 10, "zh_CN" }, + { 11, "ru" }, + { 12, "pl" }, + { 13, "vi" }, + { 14, "sv" }, + { 15, "nb_NO" }, + { 16, "fi" }, + { 17, "tr" }, + { 18, "pt" }, + { 19, "en" }, + { 20, "el" }, + { 21, "ko" }, + { 22, "hu" }, + { 23, "he" }, + { 24, "lt" }, + { 25, "cs" }, + { 26, "hi" }, + { 27, "ro" }, + { 28, "th" }, + { 29, "bg" }, + { 30, "pt_BR" }, + { 31, "ar" }, + { 32, "uk" }, + { 33, "fa" }, + { 34, "be" }, + { 35, "zh_TW" }, + }; + } +} diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index 126c02740..566dba21e 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -14,7 +14,6 @@ using NzbDrone.Core.Indexers; using NzbDrone.Core.IndexerVersions; using NzbDrone.Core.Instrumentation; using NzbDrone.Core.Jobs; -using NzbDrone.Core.Languages; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Notifications; using NzbDrone.Core.Parser.Model; @@ -113,8 +112,6 @@ namespace NzbDrone.Core.Datastore SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<int>>()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<KeyValuePair<string, int>>>()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<KeyValuePair<string, int>>()); - SqlMapper.AddTypeHandler(new DapperLanguageIntConverter()); - SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<Language>>(new LanguageIntConverter())); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<string>>()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<ReleaseInfo>()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<HashSet<int>>()); diff --git a/src/NzbDrone.Core/Languages/Language.cs b/src/NzbDrone.Core/Languages/Language.cs deleted file mode 100644 index 0265858e0..000000000 --- a/src/NzbDrone.Core/Languages/Language.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using NzbDrone.Core.Datastore; - -namespace NzbDrone.Core.Languages -{ - public class Language : IEmbeddedDocument, IEquatable<Language> - { - public int Id { get; set; } - public string Name { get; set; } - - public Language() - { - } - - private Language(int id, string name) - { - Id = id; - Name = name; - } - - public override string ToString() - { - return Name; - } - - public override int GetHashCode() - { - return Id.GetHashCode(); - } - - public bool Equals(Language other) - { - if (ReferenceEquals(null, other)) - { - return false; - } - - if (ReferenceEquals(this, other)) - { - return true; - } - - return Id.Equals(other.Id); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) - { - return false; - } - - if (ReferenceEquals(this, obj)) - { - return true; - } - - return Equals(obj as Language); - } - - public static bool operator ==(Language left, Language right) - { - return Equals(left, right); - } - - public static bool operator !=(Language left, Language right) - { - return !Equals(left, right); - } - - public static Language Unknown => new Language(0, "Unknown"); - public static Language English => new Language(1, "English"); - public static Language French => new Language(2, "French"); - public static Language Spanish => new Language(3, "Spanish"); - public static Language German => new Language(4, "German"); - public static Language Italian => new Language(5, "Italian"); - public static Language Danish => new Language(6, "Danish"); - public static Language Dutch => new Language(7, "Dutch"); - public static Language Japanese => new Language(8, "Japanese"); - public static Language Icelandic => new Language(9, "Icelandic"); - public static Language Chinese => new Language(10, "Chinese (Simplified)"); - public static Language Russian => new Language(11, "Russian"); - public static Language Polish => new Language(12, "Polish"); - public static Language Vietnamese => new Language(13, "Vietnamese"); - public static Language Swedish => new Language(14, "Swedish"); - public static Language Norwegian => new Language(15, "Norwegian"); - public static Language Finnish => new Language(16, "Finnish"); - public static Language Turkish => new Language(17, "Turkish"); - public static Language Portuguese => new Language(18, "Portuguese"); - public static Language Flemish => new Language(19, "Flemish"); - public static Language Greek => new Language(20, "Greek"); - public static Language Korean => new Language(21, "Korean"); - public static Language Hungarian => new Language(22, "Hungarian"); - public static Language Hebrew => new Language(23, "Hebrew"); - public static Language Lithuanian => new Language(24, "Lithuanian"); - public static Language Czech => new Language(25, "Czech"); - public static Language Hindi => new Language(26, "Hindi"); - public static Language Romanian => new Language(27, "Romanian"); - public static Language Thai => new Language(28, "Thai"); - public static Language Bulgarian => new Language(29, "Bulgarian"); - public static Language PortugueseBR => new Language(30, "Portuguese (Brazil)"); - public static Language Arabic => new Language(31, "Arabic"); - public static Language Ukrainian => new Language(32, "Ukrainian"); - public static Language Persian => new Language(33, "Persian"); - public static Language Bengali => new Language(34, "Bengali"); - public static Language ChineseTW => new Language(35, "Chinese (Traditional)"); - public static Language Any => new Language(-1, "Any"); - public static Language Original => new Language(-2, "Original"); - - public static List<Language> All - { - get - { - return new List<Language> - { - Unknown, - English, - French, - Spanish, - German, - Italian, - Danish, - Dutch, - Japanese, - Icelandic, - Chinese, - Russian, - Polish, - Vietnamese, - Swedish, - Norwegian, - Finnish, - Turkish, - Portuguese, - Flemish, - Greek, - Korean, - Hungarian, - Hebrew, - Lithuanian, - Czech, - Romanian, - Hindi, - Thai, - Bulgarian, - Any, - Original - }; - } - } - - public static Language FindById(int id) - { - if (id == 0) - { - return Unknown; - } - - Language language = All.FirstOrDefault(v => v.Id == id); - - if (language == null) - { - throw new ArgumentException("ID does not match a known language", nameof(id)); - } - - return language; - } - - public static explicit operator Language(int id) - { - return FindById(id); - } - - public static explicit operator int(Language language) - { - return language.Id; - } - - public static explicit operator Language(string lang) - { - var language = All.FirstOrDefault(v => v.Name.Equals(lang, StringComparison.InvariantCultureIgnoreCase)); - - if (language == null) - { - throw new ArgumentException("Language does not match a known language", nameof(lang)); - } - - return language; - } - } -} diff --git a/src/NzbDrone.Core/Languages/LanguageExtensions.cs b/src/NzbDrone.Core/Languages/LanguageExtensions.cs deleted file mode 100644 index f9c42b078..000000000 --- a/src/NzbDrone.Core/Languages/LanguageExtensions.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace NzbDrone.Core.Languages -{ - public static class LanguageExtensions - { - public static string ToExtendedString(this IEnumerable<Language> languages) - { - return string.Join(", ", languages.Select(l => l.ToString())); - } - } -} diff --git a/src/NzbDrone.Core/Languages/LanguageFieldConverter.cs b/src/NzbDrone.Core/Languages/LanguageFieldConverter.cs deleted file mode 100644 index 801a251ac..000000000 --- a/src/NzbDrone.Core/Languages/LanguageFieldConverter.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; -using NzbDrone.Core.Annotations; - -namespace NzbDrone.Core.Languages -{ - public class LanguageFieldConverter : ISelectOptionsConverter - { - public List<SelectOption> GetSelectOptions() - { - return Language.All.ConvertAll(v => new SelectOption { Value = v.Id, Name = v.Name }); - } - } -} diff --git a/src/NzbDrone.Core/Languages/LanguagesComparer.cs b/src/NzbDrone.Core/Languages/LanguagesComparer.cs deleted file mode 100644 index 02a9dd3d6..000000000 --- a/src/NzbDrone.Core/Languages/LanguagesComparer.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace NzbDrone.Core.Languages -{ - public class LanguagesComparer : IComparer<List<Language>> - { - public int Compare(List<Language> x, List<Language> y) - { - if (!x.Any() && !y.Any()) - { - return 0; - } - - if (!x.Any() && y.Any()) - { - return 1; - } - - if (x.Any() && !y.Any()) - { - return -1; - } - - if (x.Count > 1 && y.Count > 1 && x.Count > y.Count) - { - return 1; - } - - if (x.Count > 1 && y.Count > 1 && x.Count < y.Count) - { - return -1; - } - - if (x.Count > 1 && y.Count == 1) - { - return 1; - } - - if (x.Count == 1 && y.Count > 1) - { - return -1; - } - - if (x.Count == 1 && y.Count == 1) - { - return x.First().Name.CompareTo(y.First().Name); - } - - return 0; - } - } -} diff --git a/src/NzbDrone.Core/Languages/RealLanguageFieldConverter.cs b/src/NzbDrone.Core/Languages/RealLanguageFieldConverter.cs deleted file mode 100644 index 12c5df289..000000000 --- a/src/NzbDrone.Core/Languages/RealLanguageFieldConverter.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using NzbDrone.Core.Annotations; - -namespace NzbDrone.Core.Languages -{ - public class RealLanguageFieldConverter : ISelectOptionsConverter - { - public List<SelectOption> GetSelectOptions() - { - return Language.All - .Where(l => l != Language.Unknown && l != Language.Any) - .ToList() - .ConvertAll(v => new SelectOption { Value = v.Id, Name = v.Name }); - } - } -} diff --git a/src/NzbDrone.Core/Localization/LocalizationOption.cs b/src/NzbDrone.Core/Localization/LocalizationOption.cs new file mode 100644 index 000000000..85426ef39 --- /dev/null +++ b/src/NzbDrone.Core/Localization/LocalizationOption.cs @@ -0,0 +1,14 @@ +namespace NzbDrone.Core.Localization +{ + public class LocalizationOption + { + public LocalizationOption(string name, string value) + { + Name = name; + Value = value; + } + + public string Name { get; set; } + public string Value { get; set; } + } +} diff --git a/src/NzbDrone.Core/Localization/LocalizationService.cs b/src/NzbDrone.Core/Localization/LocalizationService.cs index 66fda0b60..94e1a9924 100644 --- a/src/NzbDrone.Core/Localization/LocalizationService.cs +++ b/src/NzbDrone.Core/Localization/LocalizationService.cs @@ -9,7 +9,6 @@ using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration.Events; -using NzbDrone.Core.Languages; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -20,6 +19,7 @@ namespace NzbDrone.Core.Localization Dictionary<string, string> GetLocalizationDictionary(); string GetLocalizedString(string phrase); string GetLocalizedString(string phrase, string language); + IEnumerable<LocalizationOption> GetLocalizationOptions(); } public class LocalizationService : ILocalizationService, IHandleAsync<ConfigSavedEvent> @@ -45,14 +45,14 @@ namespace NzbDrone.Core.Localization public Dictionary<string, string> GetLocalizationDictionary() { - var language = GetSetLanguageFileName(); + var language = _configService.UILanguage; return GetLocalizationDictionary(language); } public string GetLocalizedString(string phrase) { - var language = GetSetLanguageFileName(); + var language = _configService.UILanguage; return GetLocalizedString(phrase, language); } @@ -66,7 +66,7 @@ namespace NzbDrone.Core.Localization if (language.IsNullOrWhiteSpace()) { - language = GetSetLanguageFileName(); + language = _configService.UILanguage; } if (language == null) @@ -84,17 +84,44 @@ namespace NzbDrone.Core.Localization return phrase; } - private string GetSetLanguageFileName() + public IEnumerable<LocalizationOption> GetLocalizationOptions() { - var isoLanguage = IsoLanguages.Get((Language)_configService.UILanguage); - var language = isoLanguage.TwoLetterCode; - - if (isoLanguage.CountryCode.IsNotNullOrWhiteSpace()) - { - language = string.Format("{0}_{1}", language, isoLanguage.CountryCode); - } - - return language; + yield return new LocalizationOption("العربية", "ar"); + yield return new LocalizationOption("Български", "bg"); + yield return new LocalizationOption("বাংলা (বাংলাদেশ)", "bn"); + yield return new LocalizationOption("Català", "ca"); + yield return new LocalizationOption("Čeština", "cs"); + yield return new LocalizationOption("Dansk", "da"); + yield return new LocalizationOption("Deutsch", "de"); + yield return new LocalizationOption("English", "en"); + yield return new LocalizationOption("Ελληνικά", "el"); + yield return new LocalizationOption("Español", "es"); + yield return new LocalizationOption("فارسی", "fa"); + yield return new LocalizationOption("Suomi", "fi"); + yield return new LocalizationOption("Français", "fr"); + yield return new LocalizationOption("עִבְרִית", "he"); + yield return new LocalizationOption("हिन्दी", "hi"); + yield return new LocalizationOption("Magyar", "hu"); + yield return new LocalizationOption("Íslenska", "is"); + yield return new LocalizationOption("Italiano", "it"); + yield return new LocalizationOption("日本語", "ja"); + yield return new LocalizationOption("한국어", "ko"); + yield return new LocalizationOption("Lietuvių", "lt"); + yield return new LocalizationOption("Norsk bokmål", "nb_NO"); + yield return new LocalizationOption("Nederlands", "nl"); + yield return new LocalizationOption("Polski", "pl"); + yield return new LocalizationOption("Português", "pt"); + yield return new LocalizationOption("Português (Brasil)", "pt_BR"); + yield return new LocalizationOption("Românește", "ro"); + yield return new LocalizationOption("Русский", "ru"); + yield return new LocalizationOption("Slovenčina", "sk"); + yield return new LocalizationOption("Svenska", "sv"); + yield return new LocalizationOption("ภาษาไทย", "th"); + yield return new LocalizationOption("Türkçe", "tr"); + yield return new LocalizationOption("Українська", "uk"); + yield return new LocalizationOption("Tiếng Việt", "vi"); + yield return new LocalizationOption("汉语 (简化字)", "zh_CN"); + yield return new LocalizationOption("漢語 (繁体字)", "zh_TW"); } private Dictionary<string, string> GetLocalizationDictionary(string language) diff --git a/src/NzbDrone.Core/Parser/IsoLanguage.cs b/src/NzbDrone.Core/Parser/IsoLanguage.cs deleted file mode 100644 index 6f919c572..000000000 --- a/src/NzbDrone.Core/Parser/IsoLanguage.cs +++ /dev/null @@ -1,22 +0,0 @@ -using NzbDrone.Core.Languages; - -namespace NzbDrone.Core.Parser -{ - public class IsoLanguage - { - public string TwoLetterCode { get; set; } - public string ThreeLetterCode { get; set; } - public string CountryCode { get; set; } - public string EnglishName { get; set; } - public Language Language { get; set; } - - public IsoLanguage(string twoLetterCode, string countryCode, string threeLetterCode, string englishName, Language language) - { - TwoLetterCode = twoLetterCode; - ThreeLetterCode = threeLetterCode; - CountryCode = countryCode; - EnglishName = englishName; - Language = language; - } - } -} diff --git a/src/NzbDrone.Core/Parser/IsoLanguages.cs b/src/NzbDrone.Core/Parser/IsoLanguages.cs deleted file mode 100644 index 141075c31..000000000 --- a/src/NzbDrone.Core/Parser/IsoLanguages.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using NzbDrone.Core.Languages; - -namespace NzbDrone.Core.Parser -{ - public static class IsoLanguages - { - private static readonly HashSet<IsoLanguage> All = new HashSet<IsoLanguage> - { - new IsoLanguage("en", "", "eng", "English", Language.English), - new IsoLanguage("fr", "fr", "fra", "French", Language.French), - new IsoLanguage("es", "", "spa", "Spanish", Language.Spanish), - new IsoLanguage("de", "", "deu", "German", Language.German), - new IsoLanguage("it", "", "ita", "Italian", Language.Italian), - new IsoLanguage("da", "", "dan", "Danish", Language.Danish), - new IsoLanguage("nl", "", "nld", "Dutch", Language.Dutch), - new IsoLanguage("ja", "", "jpn", "Japanese", Language.Japanese), - new IsoLanguage("is", "", "isl", "Icelandic", Language.Icelandic), - new IsoLanguage("zh", "cn", "zho", "Chinese (Simplified)", Language.Chinese), - new IsoLanguage("zh", "tw", "zho", "Chinese (Traditional)", Language.ChineseTW), - new IsoLanguage("ru", "", "rus", "Russian", Language.Russian), - new IsoLanguage("pl", "", "pol", "Polish", Language.Polish), - new IsoLanguage("vi", "", "vie", "Vietnamese", Language.Vietnamese), - new IsoLanguage("sv", "", "swe", "Swedish", Language.Swedish), - new IsoLanguage("no", "", "nor", "Norwegian", Language.Norwegian), - new IsoLanguage("nb", "", "nob", "Norwegian Bokmal", Language.Norwegian), - new IsoLanguage("fi", "", "fin", "Finnish", Language.Finnish), - new IsoLanguage("tr", "", "tur", "Turkish", Language.Turkish), - new IsoLanguage("pt", "pt", "por", "Portuguese", Language.Portuguese), - new IsoLanguage("el", "", "ell", "Greek", Language.Greek), - new IsoLanguage("ko", "", "kor", "Korean", Language.Korean), - new IsoLanguage("hu", "", "hun", "Hungarian", Language.Hungarian), - new IsoLanguage("he", "", "heb", "Hebrew", Language.Hebrew), - new IsoLanguage("cs", "", "ces", "Czech", Language.Czech), - new IsoLanguage("hi", "", "hin", "Hindi", Language.Hindi), - new IsoLanguage("th", "", "tha", "Thai", Language.Thai), - new IsoLanguage("bg", "", "bul", "Bulgarian", Language.Bulgarian), - new IsoLanguage("ro", "", "ron", "Romanian", Language.Romanian), - new IsoLanguage("pt", "br", "", "Portuguese (Brazil)", Language.PortugueseBR), - new IsoLanguage("ar", "", "ara", "Arabic", Language.Arabic), - new IsoLanguage("uk", "", "ukr", "Ukrainian", Language.Ukrainian), - new IsoLanguage("fa", "", "fas", "Persian", Language.Persian), - new IsoLanguage("be", "", "ben", "Bengali", Language.Bengali) - }; - - public static IsoLanguage Find(string isoCode) - { - var isoArray = isoCode.Split('-'); - - var langCode = isoArray[0].ToLower(); - - if (langCode.Length == 2) - { - //Lookup ISO639-1 code - var isoLanguages = All.Where(l => l.TwoLetterCode == langCode).ToList(); - - if (isoArray.Length > 1) - { - isoLanguages = isoLanguages.Any(l => l.CountryCode == isoArray[1].ToLower()) ? - isoLanguages.Where(l => l.CountryCode == isoArray[1].ToLower()).ToList() : isoLanguages.Where(l => string.IsNullOrEmpty(l.CountryCode)).ToList(); - } - - return isoLanguages.FirstOrDefault(); - } - else if (langCode.Length == 3) - { - //Lookup ISO639-2T code - return All.FirstOrDefault(l => l.ThreeLetterCode == langCode); - } - - return null; - } - - public static IsoLanguage FindByName(string name) - { - return All.FirstOrDefault(l => l.EnglishName == name.Trim()); - } - - public static IsoLanguage Get(Language language) - { - return All.FirstOrDefault(l => l.Language == language); - } - } -} diff --git a/src/NzbDrone.Core/Parser/LanguageParser.cs b/src/NzbDrone.Core/Parser/LanguageParser.cs deleted file mode 100644 index e7c262fc8..000000000 --- a/src/NzbDrone.Core/Parser/LanguageParser.cs +++ /dev/null @@ -1,272 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; -using NLog; -using NzbDrone.Common.Extensions; -using NzbDrone.Common.Instrumentation; -using NzbDrone.Core.Languages; - -namespace NzbDrone.Core.Parser -{ - public static class LanguageParser - { - private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(LanguageParser)); - - private static readonly Regex LanguageRegex = new Regex(@"(?:\W|_|^)(?<italian>\b(?:ita|italian)\b)|(?<german>\b(?:german|videomann|ger)\b)|(?<flemish>flemish)|(?<bulgarian>bgaudio)|(?<greek>greek)|(?<french>(?:\W|_)(?:FR|VO|VFF|VFQ|VFI|VF2|TRUEFRENCH)(?:\W|_))|(?<russian>\brus\b)|(?<english>\beng\b)|(?<hungarian>\b(?:HUNDUB|HUN)\b)|(?<hebrew>\bHebDub\b)|(?<chinese>\[(?:CH[ST]|BIG5|GB)\]|简|繁|字幕)", - RegexOptions.IgnoreCase | RegexOptions.Compiled); - - private static readonly Regex CaseSensitiveLanguageRegex = new Regex(@"(?<lithuanian>\bLT\b)|(?<czech>\bCZ\b)", - RegexOptions.Compiled); - - private static readonly Regex SubtitleLanguageRegex = new Regex(".+?[-_. ](?<iso_code>[a-z]{2,3})(?:[-_. ]forced)?$", RegexOptions.Compiled | RegexOptions.IgnoreCase); - - public static List<Language> ParseLanguages(string title) - { - var lowerTitle = title.ToLower(); - var languages = new List<Language>(); - - if (lowerTitle.Contains("english")) - { - languages.Add(Language.English); - } - - if (lowerTitle.Contains("french")) - { - languages.Add(Language.French); - } - - if (lowerTitle.Contains("spanish")) - { - languages.Add(Language.Spanish); - } - - if (lowerTitle.Contains("danish")) - { - languages.Add(Language.Danish); - } - - if (lowerTitle.Contains("dutch")) - { - languages.Add(Language.Dutch); - } - - if (lowerTitle.Contains("japanese")) - { - languages.Add(Language.Japanese); - } - - if (lowerTitle.Contains("icelandic")) - { - languages.Add(Language.Icelandic); - } - - if (lowerTitle.Contains("mandarin") || lowerTitle.Contains("cantonese") || lowerTitle.Contains("chinese")) - { - languages.Add(Language.Chinese); - } - - if (lowerTitle.Contains("korean")) - { - languages.Add(Language.Korean); - } - - if (lowerTitle.Contains("russian")) - { - languages.Add(Language.Russian); - } - - if (lowerTitle.Contains("romanian")) - { - languages.Add(Language.Romanian); - } - - if (lowerTitle.Contains("hindi")) - { - languages.Add(Language.Hindi); - } - - if (lowerTitle.Contains("thai")) - { - languages.Add(Language.Thai); - } - - if (lowerTitle.Contains("bulgarian")) - { - languages.Add(Language.Bulgarian); - } - - if (lowerTitle.Contains("polish")) - { - languages.Add(Language.Polish); - } - - if (lowerTitle.Contains("vietnamese")) - { - languages.Add(Language.Vietnamese); - } - - if (lowerTitle.Contains("swedish")) - { - languages.Add(Language.Swedish); - } - - if (lowerTitle.Contains("norwegian")) - { - languages.Add(Language.Norwegian); - } - - if (lowerTitle.Contains("finnish")) - { - languages.Add(Language.Finnish); - } - - if (lowerTitle.Contains("turkish")) - { - languages.Add(Language.Turkish); - } - - if (lowerTitle.Contains("portuguese")) - { - languages.Add(Language.Portuguese); - } - - if (lowerTitle.Contains("hungarian")) - { - languages.Add(Language.Hungarian); - } - - if (lowerTitle.Contains("hebrew")) - { - languages.Add(Language.Hebrew); - } - - // Case sensitive - var caseSensitiveMatch = CaseSensitiveLanguageRegex.Match(title); - - if (caseSensitiveMatch.Groups["lithuanian"].Captures.Cast<Capture>().Any()) - { - languages.Add(Language.Lithuanian); - } - - if (caseSensitiveMatch.Groups["czech"].Captures.Cast<Capture>().Any()) - { - languages.Add(Language.Czech); - } - - var matches = LanguageRegex.Matches(title); - - foreach (Match match in matches) - { - if (match.Groups["italian"].Captures.Cast<Capture>().Any()) - { - languages.Add(Language.Italian); - } - - if (match.Groups["german"].Captures.Cast<Capture>().Any()) - { - languages.Add(Language.German); - } - - if (match.Groups["flemish"].Captures.Cast<Capture>().Any()) - { - languages.Add(Language.Flemish); - } - - if (match.Groups["greek"].Captures.Cast<Capture>().Any()) - { - languages.Add(Language.Greek); - } - - if (match.Groups["french"].Success) - { - languages.Add(Language.French); - } - - if (match.Groups["russian"].Success) - { - languages.Add(Language.Russian); - } - - if (match.Groups["english"].Success) - { - languages.Add(Language.English); - } - - if (match.Groups["bulgarian"].Success) - { - languages.Add(Language.Bulgarian); - } - - if (match.Groups["dutch"].Success) - { - languages.Add(Language.Dutch); - } - - if (match.Groups["hungarian"].Success) - { - languages.Add(Language.Hungarian); - } - - if (match.Groups["hebrew"].Success) - { - languages.Add(Language.Hebrew); - } - - if (match.Groups["chinese"].Success) - { - languages.Add(Language.Chinese); - } - } - - if (title.ToLower().Contains("multi")) - { - //Let's add english language to multi release as a safe guard. - if (!languages.Contains(Language.English) && languages.Count < 2) - { - languages.Add(Language.English); - } - } - - if (!languages.Any()) - { - languages.Add(Language.Unknown); - } - - return languages.DistinctBy(l => (int)l).ToList(); - } - - public static Language ParseSubtitleLanguage(string fileName) - { - try - { -#if !LIBRARY - Logger.Debug("Parsing language from subtitle file: {0}", fileName); -#endif - - var simpleFilename = Path.GetFileNameWithoutExtension(fileName); - var languageMatch = SubtitleLanguageRegex.Match(simpleFilename); - - if (languageMatch.Success) - { - var isoCode = languageMatch.Groups["iso_code"].Value; - var isoLanguage = IsoLanguages.Find(isoCode); - - return isoLanguage?.Language ?? Language.Unknown; - } -#if !LIBRARY - Logger.Debug("Unable to parse langauge from subtitle file: {0}", fileName); -#endif - } - catch (Exception) - { -#if !LIBRARY - Logger.Debug("Failed parsing langauge from subtitle file: {0}", fileName); -#endif - } - - return Language.Unknown; - } - } -} diff --git a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs index f76e36747..fe1815483 100644 --- a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs +++ b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; using NzbDrone.Core.Indexers; -using NzbDrone.Core.Languages; namespace NzbDrone.Core.Parser.Model { diff --git a/src/Prowlarr.Api.V1/Config/UiConfigResource.cs b/src/Prowlarr.Api.V1/Config/UiConfigResource.cs index ae63a6d43..55f532f98 100644 --- a/src/Prowlarr.Api.V1/Config/UiConfigResource.cs +++ b/src/Prowlarr.Api.V1/Config/UiConfigResource.cs @@ -16,7 +16,7 @@ namespace Prowlarr.Api.V1.Config public bool ShowRelativeDates { get; set; } public bool EnableColorImpairedMode { get; set; } - public int UILanguage { get; set; } + public string UILanguage { get; set; } public string Theme { get; set; } } diff --git a/src/Prowlarr.Api.V1/Languages/LanguageController.cs b/src/Prowlarr.Api.V1/Languages/LanguageController.cs deleted file mode 100644 index de7a2c4e7..000000000 --- a/src/Prowlarr.Api.V1/Languages/LanguageController.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Mvc; -using NzbDrone.Core.Languages; -using Prowlarr.Http; -using Prowlarr.Http.REST; - -namespace Prowlarr.Api.V1.Languages -{ - [V1ApiController()] - public class LanguageController : RestController<LanguageResource> - { - public override LanguageResource GetResourceById(int id) - { - var language = (Language)id; - - return new LanguageResource - { - Id = (int)language, - Name = language.ToString() - }; - } - - [HttpGet] - [Produces("application/json")] - public List<LanguageResource> GetAll() - { - return Language.All.Select(l => new LanguageResource - { - Id = (int)l, - Name = l.ToString() - }) - .OrderBy(l => l.Name) - .ToList(); - } - } -} diff --git a/src/Prowlarr.Api.V1/Languages/LanguageResource.cs b/src/Prowlarr.Api.V1/Languages/LanguageResource.cs deleted file mode 100644 index 6bb325049..000000000 --- a/src/Prowlarr.Api.V1/Languages/LanguageResource.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Newtonsoft.Json; -using Prowlarr.Http.REST; - -namespace Prowlarr.Api.V1.Languages -{ - public class LanguageResource : RestResource - { - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Include)] - public new int Id { get; set; } - public string Name { get; set; } - public string NameLower => Name.ToLowerInvariant(); - } -} diff --git a/src/Prowlarr.Api.V1/Localization/LocalizationController.cs b/src/Prowlarr.Api.V1/Localization/LocalizationController.cs index 67d3f53b5..e544936b1 100644 --- a/src/Prowlarr.Api.V1/Localization/LocalizationController.cs +++ b/src/Prowlarr.Api.V1/Localization/LocalizationController.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Text.Json; using Microsoft.AspNetCore.Mvc; using NzbDrone.Common.Serializer; @@ -26,5 +27,12 @@ namespace Prowlarr.Api.V1.Localization { return Json(_localizationService.GetLocalizationDictionary().ToResource(), _serializerSettings); } + + [HttpGet("Options")] + [Produces("application/json")] + public ActionResult<IEnumerable<LocalizationOption>> GetLocalizationOptions() + { + return Ok(_localizationService.GetLocalizationOptions()); + } } } From 9959a1b5edf55a8e3e725f61fc233845f2b044d1 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 5 Jul 2022 22:00:07 -0500 Subject: [PATCH 0541/2320] Translation Improvements --- .../src/Components/Page/Sidebar/PageSidebar.js | 8 ++++---- frontend/src/Indexer/Index/IndexerIndexFooter.js | 8 ++++---- frontend/src/Store/Actions/historyActions.js | 14 +++++++------- frontend/src/Store/Actions/indexerIndexActions.js | 6 +++--- frontend/src/System/Tasks/Queued/QueuedTasks.js | 10 +++++----- .../src/System/Tasks/Scheduled/ScheduledTasks.js | 10 +++++----- src/NzbDrone.Core/Localization/Core/en.json | 11 +++++++++++ 7 files changed, 39 insertions(+), 28 deletions(-) diff --git a/frontend/src/Components/Page/Sidebar/PageSidebar.js b/frontend/src/Components/Page/Sidebar/PageSidebar.js index 16657f59e..045789075 100644 --- a/frontend/src/Components/Page/Sidebar/PageSidebar.js +++ b/frontend/src/Components/Page/Sidebar/PageSidebar.js @@ -20,9 +20,9 @@ const SIDEBAR_WIDTH = parseInt(dimensions.sidebarWidth); const links = [ { iconName: icons.MOVIE_CONTINUING, - title: 'Indexers', + title: translate('Indexers'), to: '/', - alias: '/movies', + alias: '/indexers', children: [ { title: translate('Stats'), @@ -33,13 +33,13 @@ const links = [ { iconName: icons.SEARCH, - title: 'Search', + title: translate('Search'), to: '/search' }, { iconName: icons.ACTIVITY, - title: 'History', + title: translate('History'), to: '/history' }, diff --git a/frontend/src/Indexer/Index/IndexerIndexFooter.js b/frontend/src/Indexer/Index/IndexerIndexFooter.js index 08bfebc48..6acd2f863 100644 --- a/frontend/src/Indexer/Index/IndexerIndexFooter.js +++ b/frontend/src/Indexer/Index/IndexerIndexFooter.js @@ -35,21 +35,21 @@ class IndexerIndexFooter extends PureComponent { <div className={styles.legendItem}> <div className={styles.enabled} /> <div> - Enabled + {translate('Enabled')} </div> </div> <div className={styles.legendItem}> <div className={styles.redirected} /> <div> - Enabled, Redirected + {translate('EnabledRedirected')} </div> </div> <div className={styles.legendItem}> <div className={styles.disabled} /> <div> - Disabled + {translate('Disabled')} </div> </div> @@ -60,7 +60,7 @@ class IndexerIndexFooter extends PureComponent { )} /> <div> - Error + {translate('Error')} </div> </div> </div> diff --git a/frontend/src/Store/Actions/historyActions.js b/frontend/src/Store/Actions/historyActions.js index a94ff8c3a..b03d8d26d 100644 --- a/frontend/src/Store/Actions/historyActions.js +++ b/frontend/src/Store/Actions/historyActions.js @@ -36,31 +36,31 @@ export const defaultState = { }, { name: 'indexer', - label: 'Indexer', + label: translate('Indexer'), isSortable: false, isVisible: true }, { name: 'query', - label: 'Query', + label: translate('Query'), isSortable: false, isVisible: true }, { name: 'parameters', - label: 'Parameters', + label: translate('Parameters'), isSortable: false, isVisible: false }, { name: 'grabTitle', - label: 'Grab Title', + label: translate('Grab Title'), isSortable: false, isVisible: false }, { name: 'categories', - label: 'Categories', + label: translate('Categories'), isSortable: false, isVisible: true }, @@ -72,13 +72,13 @@ export const defaultState = { }, { name: 'source', - label: 'Source', + label: translate('Source'), isSortable: false, isVisible: false }, { name: 'elapsedTime', - label: 'Elapsed Time', + label: translate('Elapsed Time'), isSortable: false, isVisible: true }, diff --git a/frontend/src/Store/Actions/indexerIndexActions.js b/frontend/src/Store/Actions/indexerIndexActions.js index 9a0c7679d..db6516972 100644 --- a/frontend/src/Store/Actions/indexerIndexActions.js +++ b/frontend/src/Store/Actions/indexerIndexActions.js @@ -36,7 +36,7 @@ export const defaultState = { columns: [ { name: 'select', - columnLabel: 'Select', + columnLabel: translate('Select'), isSortable: false, isVisible: true, isModifiable: false, @@ -51,7 +51,7 @@ export const defaultState = { }, { name: 'sortName', - label: 'Indexer Name', + label: translate('IndexerName'), isSortable: true, isVisible: true, isModifiable: false @@ -88,7 +88,7 @@ export const defaultState = { }, { name: 'capabilities', - label: 'Categories', + label: translate('Categories'), isSortable: false, isVisible: true }, diff --git a/frontend/src/System/Tasks/Queued/QueuedTasks.js b/frontend/src/System/Tasks/Queued/QueuedTasks.js index 13e566698..5dc901ae4 100644 --- a/frontend/src/System/Tasks/Queued/QueuedTasks.js +++ b/frontend/src/System/Tasks/Queued/QueuedTasks.js @@ -15,27 +15,27 @@ const columns = [ }, { name: 'commandName', - label: 'Name', + label: translate('Name'), isVisible: true }, { name: 'queued', - label: 'Queued', + label: translate('Queued'), isVisible: true }, { name: 'started', - label: 'Started', + label: translate('Started'), isVisible: true }, { name: 'ended', - label: 'Ended', + label: translate('Ended'), isVisible: true }, { name: 'duration', - label: 'Duration', + label: translate('Duration'), isVisible: true }, { diff --git a/frontend/src/System/Tasks/Scheduled/ScheduledTasks.js b/frontend/src/System/Tasks/Scheduled/ScheduledTasks.js index 8bde6f5f5..8dbe5c08b 100644 --- a/frontend/src/System/Tasks/Scheduled/ScheduledTasks.js +++ b/frontend/src/System/Tasks/Scheduled/ScheduledTasks.js @@ -10,27 +10,27 @@ import ScheduledTaskRowConnector from './ScheduledTaskRowConnector'; const columns = [ { name: 'name', - label: 'Name', + label: translate('Name'), isVisible: true }, { name: 'interval', - label: 'Interval', + label: translate('Interval'), isVisible: true }, { name: 'lastExecution', - label: 'Last Execution', + label: translate('LastExecution'), isVisible: true }, { name: 'lastDuration', - label: 'Last Duration', + label: translate('LastDuration'), isVisible: true }, { name: 'nextExecution', - label: 'Next Execution', + label: translate('NextExecution'), isVisible: true }, { diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index dc6dfb8ba..9ade26b92 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -116,13 +116,16 @@ "DownloadClientsSettingsSummary": "Download clients configuration for integration into Prowlarr UI search", "DownloadClientStatusCheckAllClientMessage": "All download clients are unavailable due to failures", "DownloadClientStatusCheckSingleClientMessage": "Download clients unavailable due to failures: {0}", + "Duration": "Duration", "Edit": "Edit", "EditIndexer": "Edit Indexer", "EditSyncProfile": "Edit Sync Profile", + "ElapsedTime": "Elapsed Time", "Enable": "Enable", "EnableAutomaticSearch": "Enable Automatic Search", "EnableAutomaticSearchHelpText": "Will be used when automatic searches are performed via the UI or by Prowlarr", "Enabled": "Enabled", + "EnabledRedirected": "Enabled, Redirected", "EnableIndexer": "Enable Indexer", "EnableInteractiveSearch": "Enable Interactive Search", "EnableInteractiveSearchHelpText": "Will be used when interactive search is used", @@ -131,6 +134,7 @@ "EnableSSL": "Enable SSL", "EnableSslHelpText": " Requires restart running as administrator to take effect", "Encoding": "Encoding", + "Ended": "Ended", "Error": "Error", "ErrorLoadingContents": "Error loading contents", "Events": "Events", @@ -155,6 +159,7 @@ "Grabbed": "Grabbed", "GrabReleases": "Grab Release(s)", "Grabs": "Grabs", + "GrabTitle": "Grab Title", "Health": "Health", "HealthNoIssues": "No issues with your configuration", "HiddenClickToShow": "Hidden, click to show", @@ -206,6 +211,8 @@ "Interval": "Interval", "KeyboardShortcuts": "Keyboard Shortcuts", "Language": "Language", + "LastDuration": "Last Duration", + "LastExecution": "Last Execution", "LastWriteTime": "Last Write Time", "LaunchBrowserHelpText": " Open a web browser and navigate to the Prowlarr homepage on app start.", "Level": "Level", @@ -234,6 +241,7 @@ "Name": "Name", "NetCore": ".NET", "New": "New", + "NextExecution": "Next Execution", "No": "No", "NoBackupsAreAvailable": "No backups are available", "NoChange": "No Change", @@ -262,6 +270,7 @@ "PackageVersion": "Package Version", "PageSize": "Page Size", "PageSizeHelpText": "Number of items to show on each page", + "Parameters": "Parameters", "Password": "Password", "Peers": "Peers", "PendingChangesDiscardChanges": "Discard changes and leave", @@ -293,6 +302,7 @@ "QueryOptions": "Query Options", "QueryResults": "Query Results", "Queue": "Queue", + "Queued": "Queued", "RawSearchSupported": "Raw Search Supported", "ReadTheWikiForMoreInformation": "Read the Wiki for more information", "Reddit": "Reddit", @@ -364,6 +374,7 @@ "SSLCertPath": "SSL Cert Path", "SSLCertPathHelpText": "Path to pfx file", "SSLPort": "SSL Port", + "Started": "Started", "StartTypingOrSelectAPathBelow": "Start typing or select a path below", "StartupDirectory": "Startup directory", "Stats": "Stats", From f607347bd70c69ffecbc30bffd5c5deb959107fc Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Fri, 8 Jul 2022 20:08:59 +0000 Subject: [PATCH 0542/2320] Translated using Weblate (Portuguese (Brazil)) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (462 of 462 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (462 of 462 strings) Translated using Weblate (Norwegian Bokmål) Currently translated at 24.6% (111 of 451 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 99.5% (449 of 451 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (451 of 451 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (451 of 451 strings) Translated using Weblate (Portuguese) Currently translated at 80.0% (361 of 451 strings) Translated using Weblate (Polish) Currently translated at 75.3% (340 of 451 strings) Translated using Weblate (Italian) Currently translated at 100.0% (451 of 451 strings) Translated using Weblate (Italian) Currently translated at 100.0% (451 of 451 strings) Translated using Weblate (Hungarian) Currently translated at 99.7% (450 of 451 strings) Translated using Weblate (Hebrew) Currently translated at 75.1% (339 of 451 strings) Translated using Weblate (Finnish) Currently translated at 99.7% (450 of 451 strings) Translated using Weblate (German) Currently translated at 96.2% (434 of 451 strings) Co-authored-by: Anonymous <noreply@weblate.org> Co-authored-by: Giorgio <sannagiorgio1997@gmail.com> Co-authored-by: Havok Dan <havokdan@yahoo.com.br> Co-authored-by: Oskari Lavinto <olavinto@protonmail.com> Co-authored-by: Weblate <noreply@weblate.org> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/he/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/it/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nb_NO/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pl/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/de.json | 4 +- src/NzbDrone.Core/Localization/Core/fi.json | 16 ++++- src/NzbDrone.Core/Localization/Core/he.json | 8 ++- src/NzbDrone.Core/Localization/Core/hu.json | 4 +- src/NzbDrone.Core/Localization/Core/it.json | 5 +- .../Localization/Core/nb_NO.json | 60 ++++++++++++++++++- src/NzbDrone.Core/Localization/Core/pl.json | 9 ++- src/NzbDrone.Core/Localization/Core/pt.json | 3 +- .../Localization/Core/pt_BR.json | 16 ++++- .../Localization/Core/zh_CN.json | 4 +- 10 files changed, 119 insertions(+), 10 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/de.json b/src/NzbDrone.Core/Localization/Core/de.json index df8b323ec..3c4312370 100644 --- a/src/NzbDrone.Core/Localization/Core/de.json +++ b/src/NzbDrone.Core/Localization/Core/de.json @@ -431,5 +431,7 @@ "SearchTypes": "Suchtyp", "TVSearchTypes": "Suchtyp", "UnableToLoadIndexers": "Indexer konnten nicht geladen werden", - "Yes": "Ja" + "Yes": "Ja", + "InstanceName": "Instanzname", + "InstanceNameHelpText": "Instanzname im Browser-Tab und für Syslog-Anwendungsname" } diff --git a/src/NzbDrone.Core/Localization/Core/fi.json b/src/NzbDrone.Core/Localization/Core/fi.json index fc6fa9a2f..c6059d672 100644 --- a/src/NzbDrone.Core/Localization/Core/fi.json +++ b/src/NzbDrone.Core/Localization/Core/fi.json @@ -446,5 +446,19 @@ "SyncProfile": "Synkronointiprofiili", "SyncProfiles": "Synkronointiprofiilit", "AddSyncProfile": "Lisää synkronointiprofiili", - "EditSyncProfile": "Muokkaa synkronointiprofiilia" + "EditSyncProfile": "Muokkaa synkronointiprofiilia", + "InstanceName": "Instanssin nimi", + "InstanceNameHelpText": "Instanssin nimi välilehdellä ja järjestelmälokissa", + "ThemeHelpText": "Vaihda Prowlarin käyttöliittymän teemaa, jota on inspiroinut {0}", + "Duration": "Kesto", + "ElapsedTime": "Kulunut aika", + "EnabledRedirected": "Kulunut, uudelleenohjattu", + "Ended": "Päättynyt", + "GrabTitle": "Sieppaa nimike", + "LastExecution": "Edellinen suoritus", + "LastDuration": "Edellinen kesto", + "NextExecution": "Seuraava suoritus", + "Parameters": "Parametrit", + "Queued": "Jonossa", + "Started": "Alkoi" } diff --git a/src/NzbDrone.Core/Localization/Core/he.json b/src/NzbDrone.Core/Localization/Core/he.json index d4531004a..b7cbaed95 100644 --- a/src/NzbDrone.Core/Localization/Core/he.json +++ b/src/NzbDrone.Core/Localization/Core/he.json @@ -331,5 +331,11 @@ "No": "לא", "UnableToLoadIndexers": "לא ניתן לטעון אינדקסים", "Yes": "כן", - "MappedDrivesRunningAsService": "כונני רשת ממופים אינם זמינים כאשר הם פועלים כשירות Windows. אנא עיין בשאלות הנפוצות למידע נוסף" + "MappedDrivesRunningAsService": "כונני רשת ממופים אינם זמינים כאשר הם פועלים כשירות Windows. אנא עיין בשאלות הנפוצות למידע נוסף", + "InstanceName": "שם מופע", + "InstanceNameHelpText": "שם מופע בטאב ובשביל שם אפליקציית סיסלוג", + "NotificationTriggersHelpText": "בחר איזה אירועים יפעילו את ההתראה הזאת", + "OnApplicationUpdate": "כשהאפליקציה מעדכנת גרסא", + "OnApplicationUpdateHelpText": "כשהאפליקציה מעדכנת גרסא", + "Database": "מסד נתונים" } diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index 4318311a5..c8986ca82 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -446,5 +446,7 @@ "SyncProfiles": "Szinkronizálási profilok", "AddSyncProfile": "Szinkronizálási profil hozzáadása", "EditSyncProfile": "Szinkronizálási profil szerkesztése", - "MinimumSeedersHelpText": "Az Alkalmazás által megkövetelt minimális Seeder az indexer számára" + "MinimumSeedersHelpText": "Az Alkalmazás által megkövetelt minimális Seeder az indexer számára", + "InstanceName": "Példány Neve", + "InstanceNameHelpText": "Példánynév a böngésző lapon és a syslog alkalmazás neve" } diff --git a/src/NzbDrone.Core/Localization/Core/it.json b/src/NzbDrone.Core/Localization/Core/it.json index e562a967b..4ff18e2b9 100644 --- a/src/NzbDrone.Core/Localization/Core/it.json +++ b/src/NzbDrone.Core/Localization/Core/it.json @@ -446,5 +446,8 @@ "SyncProfiles": "Profili Sincronizzazione", "AddSyncProfile": "Aggiungi Profilo di Sincronizzazione", "EditSyncProfile": "Modifica Profilo di Sincronizzazione", - "MinimumSeeders": "Seeder Minimi" + "MinimumSeeders": "Seeder Minimi", + "InstanceName": "Nome Istanza", + "InstanceNameHelpText": "Nome dell'istanza nella scheda e per il nome dell'applicazione Syslog", + "ThemeHelpText": "Cambia il tema dell'interfaccia di Prowlarr, ispirato da {0}" } diff --git a/src/NzbDrone.Core/Localization/Core/nb_NO.json b/src/NzbDrone.Core/Localization/Core/nb_NO.json index 7a013984d..45a645f61 100644 --- a/src/NzbDrone.Core/Localization/Core/nb_NO.json +++ b/src/NzbDrone.Core/Localization/Core/nb_NO.json @@ -51,5 +51,63 @@ "DeleteDownloadClientMessageText": "Er du sikker på at du vil slette formattaggen {0}?", "DeleteIndexerProxyMessageText": "Er du sikker på at du vil slette formattaggen {0}?", "DeleteNotificationMessageText": "Er du sikker på at du vil slette formattaggen {0}?", - "DeleteTagMessageText": "Er du sikker på at du vil slette formattaggen {0}?" + "DeleteTagMessageText": "Er du sikker på at du vil slette formattaggen {0}?", + "ClientPriority": "Klientprioritet", + "Close": "Lukk", + "Enabled": "Aktiver", + "Title": "Tittel", + "UI": "Grensesnitt", + "ConnectionLost": "Tilkobling mistet", + "New": "Ny", + "RSS": "RSS", + "Applications": "Applikasjoner", + "ConnectionLostMessage": "Radarr har mistet tilkoblingen til baksystemet og må lastes inn på nytt for å gjenopprette funksjonalitet.", + "Connections": "Tilkoblinger", + "Usenet": "Usenet", + "Username": "Brukernavn", + "Language": "språk", + "Notification": "Varslinger", + "Notifications": "Varslinger", + "Password": "Passord", + "Peers": "Likemenn", + "Port": "Port", + "Protocol": "Protokoll", + "Queue": "Kø", + "Refresh": "Oppdater", + "Scheduled": "Planlagt", + "Search": "Søk", + "Seeders": "Delere", + "Settings": "Innstillinger", + "Torrent": "Torrent", + "Torrents": "Torrents", + "CloneProfile": "Klon profil", + "Columns": "Kolonner", + "Component": "Komponent", + "Connect": "Varslinger", + "ConnectionLostAutomaticMessage": "Radarr vil forsøke å koble til automatisk, eller du kan klikke oppdater nedenfor.", + "ConnectSettings": "Tilkoblingsinnstillinger", + "CouldNotConnectSignalR": "Kunne ikke koble til SignalR, grensesnitt vil ikke oppdateres", + "Custom": "Tilpass", + "Delete": "Slett", + "Disabled": "deaktivert", + "DownloadClient": "Nedlastingsklient", + "DownloadClients": "Nedlastingsklient", + "Enable": "Aktiver", + "Encoding": "Koding", + "Events": "Hendelse", + "Files": "Fil", + "Filter": "Filter", + "Filters": "Filtre", + "Host": "Vert", + "Hostname": "Vertsnavn", + "Indexer": "Indekser", + "Indexers": "Indeksere", + "Grabs": "Hent", + "Application": "Applikasjoner", + "Reload": "Likemenn", + "UpdateMechanismHelpText": "Bruk Prowlarrs innebygde oppdaterer eller et skript", + "Updates": "Oppdater", + "URLBase": "URL Base", + "Details": "detaljer", + "Info": "Info" } diff --git a/src/NzbDrone.Core/Localization/Core/pl.json b/src/NzbDrone.Core/Localization/Core/pl.json index 16364bee5..47ce22d19 100644 --- a/src/NzbDrone.Core/Localization/Core/pl.json +++ b/src/NzbDrone.Core/Localization/Core/pl.json @@ -331,5 +331,12 @@ "UnableToLoadIndexers": "Nie można załadować indeksatorów", "Link": "Spinki do mankietów", "MappedDrivesRunningAsService": "Zmapowane dyski sieciowe nie są dostępne, gdy działają jako usługa systemu Windows. Więcej informacji można znaleźć w FAQ", - "Yes": "tak" + "Yes": "tak", + "InstanceName": "Nazwa instancji", + "InstanceNameHelpText": "Nazwa instancji w zakładce i dla nazwy aplikacji Syslog", + "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent podawany przez aplikację wywołującą API", + "OnApplicationUpdate": "Przy aktualizacji aplikacji", + "OnApplicationUpdateHelpText": "Przy aktualizacji aplikacji", + "Database": "Baza danych", + "NotificationTriggersHelpText": "Wybierz zdarzenia, które mają uruchamiać to powiadomienie" } diff --git a/src/NzbDrone.Core/Localization/Core/pt.json b/src/NzbDrone.Core/Localization/Core/pt.json index cc09232aa..ab5f36be1 100644 --- a/src/NzbDrone.Core/Localization/Core/pt.json +++ b/src/NzbDrone.Core/Localization/Core/pt.json @@ -400,5 +400,6 @@ "No": "Não", "UnableToLoadIndexers": "Não foi possível carregar os indexadores", "Yes": "Sim", - "GrabReleases": "Capturar versão" + "GrabReleases": "Capturar versão", + "InstanceName": "Nome da Instancia" } diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index 7f5370c0f..c17e54e68 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -446,5 +446,19 @@ "SyncProfiles": "Perfis de Sincronização", "AddSyncProfile": "Adicionar Perfil de Sincronização", "MinimumSeeders": "Mínimo de Seeders", - "MinimumSeedersHelpText": "Mínimo de seeders requeridos pelo Aplicativo para o indexador baixar" + "MinimumSeedersHelpText": "Mínimo de seeders requeridos pelo Aplicativo para o indexador baixar", + "ThemeHelpText": "Altere o tema da IU do Prowlarr, inspirado em {0}", + "InstanceName": "Nome da instância", + "InstanceNameHelpText": "Nome da instância na guia e para o nome do aplicativo Syslog", + "Duration": "Duração", + "ElapsedTime": "Tempo Decorrido", + "EnabledRedirected": "Habilitado, Redirecionado", + "Ended": "Terminado", + "LastExecution": "Última Execução", + "Parameters": "Parâmetros", + "Queued": "Enfileirado", + "GrabTitle": "Obter Título", + "LastDuration": "Última Duração", + "NextExecution": "Próxima Execução", + "Started": "Iniciado" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index 9a9a6f617..8cced4655 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -446,5 +446,7 @@ "EditSyncProfile": "编辑同步配置文件", "SyncProfile": "同步配置文件", "MinimumSeeders": "最少播种量", - "MinimumSeedersHelpText": "用于索引器抓取的应用程序所需的最小播种量" + "MinimumSeedersHelpText": "用于索引器抓取的应用程序所需的最小播种量", + "InstanceName": "中文", + "InstanceNameHelpText": "选项卡及日志应用名称" } From b8dd8b1880f0764907a0a119a58a89471bcf4f76 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 17 Jul 2022 14:52:21 -0500 Subject: [PATCH 0543/2320] Fixed: Set Download and Upload Factors from Generic Torznab --- .../Indexers/Definitions/Torznab/TorznabRssParser.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs index 58f493bbb..a7bc3c9af 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs @@ -61,6 +61,12 @@ namespace NzbDrone.Core.Indexers.Torznab torrentInfo.ImdbId = int.Parse(GetImdbId(item).Substring(2)); } + var downloadFactor = TryGetFloatTorznabAttribute(item, "downloadvolumefactor", 1); + var uploadFactor = TryGetFloatTorznabAttribute(item, "uploadvolumefactor", 1); + + torrentInfo.DownloadVolumeFactor = downloadFactor; + torrentInfo.UploadVolumeFactor = uploadFactor; + torrentInfo.IndexerFlags = GetFlags(item); torrentInfo.PosterUrl = GetPosterUrl(item); } From 970f80b15558b7acb5dba93ae087a5781906b67c Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 17 Jul 2022 19:40:40 -0500 Subject: [PATCH 0544/2320] Debounce analytics service --- .../IndexerSearch/ReleaseAnalyticsService.cs | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs index a195e1125..1bf364ffe 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs @@ -1,13 +1,17 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using NLog; using NzbDrone.Common.Cloud; +using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Common.Serializer; +using NzbDrone.Common.TPL; using NzbDrone.Core.Analytics; using NzbDrone.Core.Indexers.Events; using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.IndexerSearch { @@ -16,26 +20,48 @@ namespace NzbDrone.Core.IndexerSearch private readonly IHttpClient _httpClient; private readonly IHttpRequestBuilderFactory _requestBuilder; private readonly IAnalyticsService _analyticsService; + private readonly Debouncer _debouncer; private readonly Logger _logger; + private readonly List<ReleaseInfo> _pendingUpdates; public ReleaseAnalyticsService(IHttpClient httpClient, IProwlarrCloudRequestBuilder requestBuilder, IAnalyticsService analyticsService, Logger logger) { + _debouncer = new Debouncer(SendReleases, TimeSpan.FromMinutes(10)); _analyticsService = analyticsService; _requestBuilder = requestBuilder.Releases; _httpClient = httpClient; _logger = logger; + + _pendingUpdates = new List<ReleaseInfo>(); } public void HandleAsync(IndexerQueryEvent message) { - if (_analyticsService.IsEnabled && message.QueryResult?.Releases != null) + if (message.QueryResult?.Releases != null) { + lock (_pendingUpdates) + { + _pendingUpdates.AddRange(message.QueryResult.Releases.Where(r => r.Title.IsNotNullOrWhiteSpace())); + } + + _debouncer.Execute(); + } + } + + public void SendReleases() + { + lock (_pendingUpdates) + { + var pendingUpdates = _pendingUpdates.ToArray(); + _pendingUpdates.Clear(); + var request = _requestBuilder.Create().Resource("release/push").Build(); request.Method = HttpMethod.Post; request.Headers.ContentType = "application/json"; request.SuppressHttpError = true; + request.LogHttpError = false; - var body = message.QueryResult.Releases.Select(x => new + var body = pendingUpdates.DistinctBy(r => r.Title).Select(x => new { Title = x.Title, Categories = x.Categories?.Where(c => c.Id < 10000).Select(c => c.Id) ?? new List<int>(), From 8baf1b533bc992a35a902d358bda4083acaebf92 Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Mon, 18 Jul 2022 00:45:26 +0000 Subject: [PATCH 0545/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 67 ++++++-------------------------- 1 file changed, 11 insertions(+), 56 deletions(-) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index 5e1297928..1ac4758fb 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -2523,50 +2523,22 @@ } } }, - "/api/v1/language/{id}": { + "/api/v1/localization": { "get": { "tags": [ - "Language" - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } + "Localization" ], "responses": { "200": { - "description": "Success", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/LanguageResource" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/LanguageResource" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/LanguageResource" - } - } - } + "description": "Success" } } } }, - "/api/v1/language": { + "/api/v1/localization/options": { "get": { "tags": [ - "Language" + "Localization" ], "responses": { "200": { @@ -2576,7 +2548,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/LanguageResource" + "$ref": "#/components/schemas/LocalizationOption" } } } @@ -2585,18 +2557,6 @@ } } }, - "/api/v1/localization": { - "get": { - "tags": [ - "Localization" - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, "/api/v1/log": { "get": { "tags": [ @@ -5687,21 +5647,16 @@ }, "additionalProperties": false }, - "LanguageResource": { + "LocalizationOption": { "type": "object", "properties": { - "id": { - "type": "integer", - "format": "int32" - }, "name": { "type": "string", "nullable": true }, - "nameLower": { + "value": { "type": "string", - "nullable": true, - "readOnly": true + "nullable": true } }, "additionalProperties": false @@ -6314,8 +6269,8 @@ "type": "boolean" }, "uiLanguage": { - "type": "integer", - "format": "int32" + "type": "string", + "nullable": true }, "theme": { "type": "string", From 32ca2d172005da6112fceb2f6b7803eea7b93a71 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 17 Jul 2022 19:48:32 -0500 Subject: [PATCH 0546/2320] Update README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 7e1dd130d..e5759c632 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,7 @@ Prowlarr is an indexer manager/proxy built on the popular \*arr .net/reactjs bas ## Support -Note: Prowlarr is currently early in life, thus bugs should be expected - [![Wiki](https://img.shields.io/badge/servarr-wiki-181717.svg?maxAge=60)](https://wiki.servarr.com/prowlarr) - [![Discord](https://img.shields.io/badge/discord-chat-7289DA.svg?maxAge=60)](https://prowlarr.com/discord) [![Reddit](https://img.shields.io/badge/reddit-discussion-FF4500.svg?maxAge=60)](https://www.reddit.com/r/Prowlarr) From 215c87a099d11a5a7ebe849b33623681e57b9c7b Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Tue, 19 Jul 2022 08:09:02 +0000 Subject: [PATCH 0547/2320] Translated using Weblate (Chinese (Traditional) (zh_TW)) Currently translated at 2.8% (13 of 462 strings) Translated using Weblate (Catalan) Currently translated at 66.4% (307 of 462 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 100.0% (462 of 462 strings) Translated using Weblate (French) Currently translated at 95.4% (441 of 462 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (462 of 462 strings) Co-authored-by: Csaba <csab0825@gmail.com> Co-authored-by: Sytha <tharaud.sylvain@gmail.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: beefnoodle <acer.wang@protonmail.com> Co-authored-by: dtalens <databio@gmail.com> Co-authored-by: libsu <libsu@qq.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ca/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_TW/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/ca.json | 308 +++++++++++++++++- src/NzbDrone.Core/Localization/Core/fr.json | 2 +- src/NzbDrone.Core/Localization/Core/hu.json | 14 +- .../Localization/Core/zh_CN.json | 18 +- .../Localization/Core/zh_TW.json | 13 +- 5 files changed, 344 insertions(+), 11 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/ca.json b/src/NzbDrone.Core/Localization/Core/ca.json index 69ec76ef5..fe9a56c72 100644 --- a/src/NzbDrone.Core/Localization/Core/ca.json +++ b/src/NzbDrone.Core/Localization/Core/ca.json @@ -1,11 +1,309 @@ { - "Add": "Afegeix", + "Add": "Afegiu", "Actions": "Accions", - "AcceptConfirmationModal": "Accepta el mètode de confirmació", + "AcceptConfirmationModal": "Accepta el modal de confirmació", "About": "Quant a", "New": "Nou", - "Reload": "Recarregar", + "Reload": "Torna a carregar", "Queue": "Cua", - "Refresh": "Actualització", - "Password": "Contrassenya" + "Refresh": "Actualitza", + "Password": "Contrasenya", + "Logs": "Registres", + "MaintenanceRelease": "Versió de manteniment: correcció d'errors i altres millores. Consulteu l'historial de publicacions de Github per a més detalls", + "BackupIntervalHelpText": "Interval entre còpies de seguretat automàtiques", + "ProxyPasswordHelpText": "Només cal que introduïu un nom d'usuari i una contrasenya si cal. Deixeu-los en blanc en cas contrari.", + "ProxyType": "Tipus de servidor intermediari", + "DownloadClient": "Client de baixada", + "DownloadClients": "Descàrrega Clients", + "Scheduled": "Programat", + "ScriptPath": "Camí de l'script", + "Search": "Cerca", + "Files": "Fitxers", + "SettingsEnableColorImpairedModeHelpText": "Estil alternat per permetre als usuaris amb problemes de color distingir millor la informació codificada per colors", + "TagIsNotUsedAndCanBeDeleted": "L'etiqueta no està en ús i es pot suprimir", + "TagsSettingsSummary": "Consulta totes les etiquetes i com s'utilitzen. Les etiquetes no utilitzades es poden eliminar", + "Tasks": "Tasques", + "TestAllClients": "Prova tots els clients", + "Today": "Avui", + "PendingChangesMessage": "Teniu canvis no desats, esteu segur que voleu sortir d'aquesta pàgina?", + "PendingChangesStayReview": "Roman i revisa els canvis", + "Port": "Port^", + "PortNumber": "Número de port", + "ShowAdvanced": "Mostra característiques avançades", + "ShownClickToHide": "Es mostra, feu clic per amagar", + "AddDownloadClient": "Afegeix un client de descàrrega", + "Added": "Afegit", + "Age": "Edat", + "All": "Tots", + "Analytics": "Anàlisi", + "ApiKey": "Clau API", + "AppDataDirectory": "Directori AppData", + "AppDataLocationHealthCheckMessage": "No es podrà actualitzar per evitar que s'eliminin AppData a l'actualització", + "Authentication": "Autenticació", + "Torrents": "Torrents", + "Type": "Tipus", + "UILanguageHelpTextWarning": "Es requereix una recàrrega del navegador", + "UISettings": "Configuració de la interfície", + "UnableToLoadBackups": "No es poden carregar còpies de seguretat", + "UnableToLoadDownloadClients": "No es poden carregar els clients de baixada", + "UnableToLoadTags": "No es poden carregar les etiquetes", + "UnableToLoadUISettings": "No es pot carregar la configuració de la IU", + "UnselectAll": "Desseleccioneu-ho tot", + "UrlBaseHelpText": "Per al suport de servidor intermediari invers, el valor predeterminat és buit", + "DeleteBackup": "Suprimeix la còpia de seguretat", + "Warn": "Avís", + "DownloadClientSettings": "Baixeu la configuració del client", + "EnableSslHelpText": " Cal reiniciar l'execució com a administrador perquè tingui efecte", + "Filename": "Nom de fitxer", + "Fixed": "Corregit", + "Folder": "Carpeta", + "Health": "Salut", + "HiddenClickToShow": "Amagat, feu clic per mostrar", + "Host": "Amfitrió", + "Indexer": "Indexador", + "InteractiveSearch": "Cerca interactiva", + "LogLevel": "Nivell de registre", + "Name": "Nom", + "NetCore": ".NET", + "NoChange": "Cap canvi", + "LogLevelTraceHelpTextWarning": "El registre de traça només s'hauria d'habilitar temporalment", + "Message": "Missatge", + "MoreInfo": "Més informació", + "NoChanges": "Sense Canvis", + "RemovedFromTaskQueue": "S'ha eliminat de la cua de tasques", + "RestartNow": "Reinicia ara", + "Result": "Resultat", + "Retention": "Retenció", + "Title": "Títol", + "DeleteNotification": "Suprimeix la notificació", + "ProxyCheckBadRequestMessage": "No s'ha pogut provar el servidor intermediari. Codi d'estat: {0}", + "Reddit": "Reddit", + "System": "Sistema", + "Username": "Nom d'usuari", + "Duration": "durada", + "EditIndexer": "Edita l'indexador", + "EnableAutomaticSearch": "Activa la cerca automàtica", + "Enabled": "Habilitat", + "Error": "error", + "ErrorLoadingContents": "S'ha produït un error en carregar el contingut", + "Events": "Esdeveniments", + "ExistingTag": "Etiqueta existent", + "Failed": "S'ha produït un error", + "FeatureRequests": "Sol·licitud de noves característiques", + "Filter": "Filtre", + "NextExecution": "Propera execució", + "NoBackupsAreAvailable": "No hi ha còpies de seguretat disponibles", + "NoLeaveIt": "No, deixa-ho", + "NoLinks": "Sense enllaços", + "NoLogFiles": "No hi ha fitxers de registre", + "NoTagsHaveBeenAddedYet": "Encara no s'ha afegit cap etiqueta", + "NoUpdatesAreAvailable": "No hi ha actualitzacions disponibles", + "OAuthPopupMessage": "Les finestres emergents estan sent bloquejades pel vostre navegador", + "Ok": "D'acord", + "OnHealthIssue": "Al detectar incidència", + "OnHealthIssueHelpText": "Al detectar incidència", + "OpenBrowserOnStart": "Obriu el navegador a l'inici", + "OpenThisModal": "Obriu aquest modal", + "Options": "Opcions", + "PageSize": "Mida de la pàgina", + "PageSizeHelpText": "Nombre d'elements per mostrar a cada pàgina", + "Peers": "Parells", + "PendingChangesDiscardChanges": "Descarta els canvis i surt", + "Presets": "Predefinits", + "Protocol": "Protocol", + "Proxy": "Servidor intermediari", + "ProxyBypassFilterHelpText": "Utilitzeu ',' com a separador i '*.' com a comodí per als subdominis", + "RefreshMovie": "Actualitza pel·lícula", + "ReleaseStatus": "Estat de llançament", + "RemoveFilter": "Treu el filtre", + "RemovingTag": "S'està eliminant l'etiqueta", + "Reset": "Restableix", + "ResetAPIKey": "Restableix la clau de l'API", + "Restart": "Reinicia", + "Updates": "Actualitzacions", + "Version": "Versió", + "Apply": "Aplica", + "ApplyTags": "Aplica etiquetes", + "Close": "Tanca", + "EventType": "Tipus d'esdeveniment", + "Exception": "Excepció", + "Filters": "Filtres", + "FocusSearchBox": "Posa el focus a la caixa de cerca", + "Grabbed": "Capturat", + "IndexerStatusCheckAllClientMessage": "Tots els indexadors no estan disponibles a causa d'errors", + "IndexerStatusCheckSingleClientMessage": "Els indexadors no estan disponibles a causa d'errors: {0}", + "MovieIndexScrollTop": "Índex de pel·lícules: Desplaçament superior", + "NotificationTriggers": "Activadors de notificacions", + "NotificationTriggersHelpText": "Seleccioneu quins esdeveniments haurien d'activar aquesta notificació", + "Priority": "Prioritat", + "PriorityHelpText": "Prioritzeu diversos clients de baixada. S'utilitza round-robin per a clients amb la mateixa prioritat.", + "SendAnonymousUsageData": "Envia dades d'ús anònimes", + "SetTags": "Estableix etiquetes", + "SystemTimeCheckMessage": "L'hora del sistema està apagada durant més d'1 dia. És possible que les tasques programades no s'executin correctament fins que no es corregeixi l'hora", + "TableOptions": "Opcions de taula", + "TableOptionsColumnsMessage": "Trieu quines columnes són visibles i en quin ordre apareixen", + "ApplyTagsHelpTexts3": "Eliminar: elimina les etiquetes introduïdes", + "Columns": "Columnes", + "SettingsShortDateFormat": "Format de data curta", + "BindAddress": "Adreça d'enllaç", + "Database": "Base de dades", + "Ended": "S'ha acabat", + "SettingsTimeFormat": "Format horari", + "YesCancel": "Si, cancel·la", + "ApplyTagsHelpTexts4": "Substituïu: substituïu les etiquetes per les etiquetes introduïdes (no introduïu cap etiqueta per esborrar totes les etiquetes)", + "Automatic": "Automàtic", + "AutomaticSearch": "Cerca automàtica", + "Backup": "Còpia de seguretat", + "BackupNow": "Fes ara la còpia de seguretat", + "BackupRetentionHelpText": "Les còpies de seguretat automàtiques anteriors al període de retenció s'eliminaran automàticament", + "BeforeUpdate": "Abans de l'actualització", + "BranchUpdateMechanism": "Branca utilitzada pel mecanisme d'actualització extern", + "BypassProxyForLocalAddresses": "Ometre el servidor intermediari per a adreces locals", + "Cancel": "Cancel·la", + "CancelPendingTask": "Esteu segur que voleu cancel·lar aquesta tasca pendent?", + "ChangeHasNotBeenSavedYet": "El canvi encara no s'ha desat", + "Clear": "Esborra", + "ClientPriority": "Prioritat del client", + "CloneProfile": "Clona el perfil", + "CloseCurrentModal": "Tanca el modal actual", + "Component": "Component", + "ConnectionLost": "Connexió perduda", + "CouldNotConnectSignalR": "No s'ha pogut connectar a SignalR, la IU no s'actualitzarà", + "Custom": "Personalitzat", + "CustomFilters": "Filtres personalitzats", + "Date": "Data", + "Dates": "Dates", + "DBMigration": "Migració de BD", + "Delete": "Suprimeix", + "DeleteNotificationMessageText": "Esteu segur que voleu suprimir la notificació '{0}'?", + "DeleteTag": "Suprimeix l'etiqueta", + "DeleteTagMessageText": "Esteu segur que voleu suprimir l'etiqueta '{0}'?", + "Details": "Detalls", + "Disabled": "Desactivat", + "DownloadClientStatusCheckAllClientMessage": "Tots els clients de descàrrega no estan disponibles a causa d'errors", + "Edit": "Edita", + "EnableInteractiveSearchHelpText": "S'utilitzarà quan s'utilitzi la cerca interactiva", + "EnableInteractiveSearch": "Activa la cerca interactiva", + "EnableSSL": "Activa SSL", + "General": "General", + "GeneralSettings": "Configuració general", + "IllRestartLater": "Reinicia més tard", + "IncludeHealthWarningsHelpText": "Inclou advertències de salut", + "Indexers": "Indexadors", + "InstanceName": "Nom de la instància", + "InstanceNameHelpText": "Nom de la instància a la pestanya i per al nom de l'aplicació Syslog", + "Interval": "Interval", + "LastDuration": "Darrera durada", + "LastExecution": "Darrere execució", + "LastWriteTime": "La darrera hora d'escriptura", + "Manual": "Manual", + "Mode": "Mode", + "MovieIndexScrollBottom": "Índex de pel·lícules: Desplaçament inferior", + "OnApplicationUpdate": "A l'actualitzar de l'aplicació", + "OnApplicationUpdateHelpText": "A l'actualitzar de l'aplicació", + "OnGrab": "Al capturar", + "PackageVersion": "Versió del paquet", + "ProxyCheckFailedToTestMessage": "No s'ha pogut provar el servidor intermediari: {0}", + "ProxyCheckResolveIpMessage": "No s'ha pogut resoldre l'adreça IP de l'amfitrió intermediari configurat {0}", + "PtpOldSettingsCheckMessage": "Els següents indexadors de PassThePopcorn tenen configuracions obsoletes i s'han d'actualitzar: {0}", + "Queued": "En cua", + "ReadTheWikiForMoreInformation": "Llegiu el Wiki per a més informació", + "RestartRequiredHelpTextWarning": "Cal reiniciar perquè tingui efecte", + "Restore": "Restaura", + "RestoreBackup": "Restaura còpia de seguretat", + "RSS": "RSS", + "Save": "Desa", + "SaveChanges": "Desa els canvis", + "Security": "Seguretat", + "Settings": "Configuració", + "SettingsEnableColorImpairedMode": "Activa el mode amb alteracions del color", + "SettingsLongDateFormat": "Format de data llarga", + "SettingsShowRelativeDates": "Mostra les dates relatives", + "SettingsShowRelativeDatesHelpText": "Mostra dates relatives (avui/ahir/etc) o absolutes", + "ShowSearch": "Mostra la cerca", + "ShowSearchHelpText": "Mostra el botó de cerca al passar el cursor", + "Shutdown": "Tanca", + "Sort": "Ordena", + "Source": "Font", + "SSLCertPassword": "Contrasenya de certificat SSL", + "SSLCertPasswordHelpText": "Contrasenya per al fitxer pfx", + "SSLCertPath": "Camí del certificat SSL", + "SSLCertPathHelpText": "Camí al fitxer pfx", + "SSLPort": "Port SSL", + "Started": "Començat", + "StartTypingOrSelectAPathBelow": "Comenceu a escriure o seleccioneu un camí a continuació", + "StartupDirectory": "Directori d'inici", + "AddIndexer": "Afegeix un indexador", + "AddingTag": "Afegint etiqueta", + "CertificateValidation": "Validació del certificat", + "UI": "Interfície", + "UnableToLoadIndexers": "No es poden carregar els indexadors", + "Enable": "Activa", + "IndexerFlags": "Indicadors de l'indexador", + "UnableToLoadNotifications": "No es poden carregar les notificacions", + "IndexerLongTermStatusCheckAllClientMessage": "Tots els indexadors no estan disponibles a causa d'errors durant més de 6 hores", + "IndexerLongTermStatusCheckSingleClientMessage": "Els indexadors no estan disponibles a causa d'errors durant més de 6 hores: {0}", + "IndexerPriority": "Prioritat de l'indexador", + "UnsavedChanges": "Canvis no desats", + "UpdateAutomaticallyHelpText": "Baixeu i instal·leu les actualitzacions automàticament. Encara podreu instal·lar des de Sistema: Actualitzacions", + "UpdateCheckStartupTranslocationMessage": "No es pot instal·lar l'actualització perquè la carpeta d'inici \"{0}\" es troba en una carpeta de translocació d'aplicacions.", + "UpdateCheckUINotWritableMessage": "No es pot instal·lar l'actualització perquè l'usuari '{1}' no pot escriure la carpeta de la IU '{0}'.", + "UpdateScriptPathHelpText": "Camí a un script personalitzat que pren un paquet d'actualització i gestiona la resta del procés d'actualització", + "Uptime": "Temps de funcionament", + "Info": "Informació", + "KeyboardShortcuts": "Dreceres de teclat", + "Language": "Idioma", + "UseProxy": "Utilitzeu el servidor intermediari", + "Level": "Nivell", + "LogFiles": "Fitxers de registre", + "Logging": "Registre", + "MappedDrivesRunningAsService": "Les unitats de xarxa assignades no estan disponibles quan s'executen com a servei de Windows. Si us plau, consulteu les PMF per obtenir més informació", + "Mechanism": "Mecanisme", + "MIA": "MIA", + "Wiki": "Wiki", + "Tags": "Etiquetes", + "AreYouSureYouWantToResetYourAPIKey": "Esteu segur que voleu restablir la clau de l'API?", + "Backups": "Còpies de seguretat", + "Branch": "Branca", + "Connections": "Connexions", + "ConnectSettings": "Configuració de connexió", + "DeleteBackupMessageText": "Esteu segur que voleu suprimir la còpia de seguretat '{0}'?", + "DeleteDownloadClient": "Suprimeix el client de descàrrega", + "DeleteDownloadClientMessageText": "Esteu segur que voleu suprimir el client de baixada '{0}'?", + "Discord": "Discord", + "Docker": "Docker", + "Donations": "Donacions", + "DownloadClientStatusCheckSingleClientMessage": "Baixa els clients no disponibles a causa d'errors: {0}", + "HealthNoIssues": "No hi ha cap problema amb la configuració", + "HideAdvanced": "Amaga avançat", + "History": "Història", + "HomePage": "Pàgina d'inici", + "Hostname": "Nom d'amfitrió", + "IgnoredAddresses": "Adreces ignorades", + "ProxyUsernameHelpText": "Només cal que introduïu un nom d'usuari i una contrasenya si cal. Deixeu-los en blanc en cas contrari.", + "RSSIsNotSupportedWithThisIndexer": "RSS no és compatible amb aquest indexador", + "SaveSettings": "Desa la configuració", + "Seeders": "Llavors", + "SelectAll": "Selecciona-ho tot", + "Size": "Mida", + "Status": "Estat", + "Style": "Estil", + "SuggestTranslationChange": "Suggereix un canvi de traducció", + "TagCannotBeDeletedWhileInUse": "No es pot suprimir mentre està en ús", + "Test": "Prova", + "TestAll": "Prova-ho tot", + "TestAllIndexers": "Prova tots els indexadors", + "Time": "Temps", + "Tomorrow": "Demà", + "UILanguage": "Idioma de la interfície", + "UnableToAddANewDownloadClientPleaseTryAgain": "No es pot afegir un nou client de descàrrega, torneu-ho a provar.", + "UnableToAddANewIndexerPleaseTryAgain": "No es pot afegir un indexador nou, torneu-ho a provar.", + "UnableToAddANewNotificationPleaseTryAgain": "No es pot afegir una notificació nova, torneu-ho a provar.", + "UnableToLoadGeneralSettings": "No es pot carregar la configuració general", + "UnableToLoadHistory": "No es pot carregar l'historial", + "UpdateCheckStartupNotWritableMessage": "No es pot instal·lar l'actualització perquè l'usuari \"{1}\" no pot escriure la carpeta d'inici \"{0}\".", + "URLBase": "Base URL", + "Usenet": "Usenet", + "View": "Visualitza", + "Yesterday": "Ahir" } diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index 79fa29f3b..7057a5fe9 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -49,7 +49,7 @@ "SaveChanges": "Sauvegarder les modifications", "RestoreBackup": "Restaurer la sauvegarde", "ReleaseBranchCheckOfficialBranchMessage": "La branche {0} n'est pas une branche de version Prowlarr valide, vous ne recevrez pas de mises à jour", - "Refresh": "Rafraîchir", + "Refresh": "Actualiser", "Queue": "File d'attente", "PtpOldSettingsCheckMessage": "Les indexeurs PassThePopcorn suivants ont des paramètres obsolètes et doivent être mis à jour : {0}", "ProxyCheckResolveIpMessage": "Impossible de résoudre l'adresse IP de l'hôte proxy configuré {0}", diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index c8986ca82..782b43990 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -448,5 +448,17 @@ "EditSyncProfile": "Szinkronizálási profil szerkesztése", "MinimumSeedersHelpText": "Az Alkalmazás által megkövetelt minimális Seeder az indexer számára", "InstanceName": "Példány Neve", - "InstanceNameHelpText": "Példánynév a böngésző lapon és a syslog alkalmazás neve" + "InstanceNameHelpText": "Példánynév a böngésző lapon és a syslog alkalmazás neve", + "ThemeHelpText": "Prowlarr felhasználói felület témájának módosítása, ihlette {0}", + "Duration": "Időtartam", + "ElapsedTime": "Eltelt idő", + "EnabledRedirected": "Engedélyezve, átirányítva", + "Ended": "Vége lett", + "GrabTitle": "Cím megragadása", + "LastDuration": "Utolsó időtartam", + "LastExecution": "Utolsó végrehajtás", + "Parameters": "Paraméterek", + "Queued": "Sorba helyezve", + "Started": "Elkezdődött", + "NextExecution": "Következő végrehajtás" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index 8cced4655..f331b6085 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -335,7 +335,7 @@ "UILanguage": "UI界面语言", "UILanguageHelpText": "Radarr使用的UI界面语言", "UpdateCheckUINotWritableMessage": "无法安装升级,因为用户“{1}”不可写入界面文件夹“{0}”。", - "UpdateMechanismHelpText": "使用 Prowlarr 的内置程序或脚本进行程序升级", + "UpdateMechanismHelpText": "使用 Prowlarr 内置的更新器或者脚本", "Updates": "更新", "UpdateScriptPathHelpText": "自定义脚本的路径,该脚本处理获取的更新包并处理更新过程的其余部分", "Uptime": "运行时间", @@ -391,7 +391,7 @@ "SettingsIndexerLoggingHelpText": "记录额外的搜刮器数据,包括响应", "SettingsFilterSentryEventsHelpText": "过滤已知的用户错误事件,不让其作为分析报告发送", "RedirectHelpText": "重定向搜刮器的传入下载请求并直接传递抓取,而不是通过Prowlarr代理请求搜刮器", - "IndexerTagsHelpText": "‎使用标签‎‎指定‎‎索引器‎‎代理或仅用于你组织的‎‎索引器.", + "IndexerTagsHelpText": "使用标签指定索引器代理, 索引器同步到哪些应用程序,或者只是为了组织索引器。", "IndexerSettingsSummary": "配置全局索引器设置,包括代理。", "HistoryCleanupDaysHelpTextWarning": "回收站中的文件在超出选择的天数后会被自动清理", "UserAgentProvidedByTheAppThatCalledTheAPI": "由调用API的应用程序提供的User-Agent", @@ -448,5 +448,17 @@ "MinimumSeeders": "最少播种量", "MinimumSeedersHelpText": "用于索引器抓取的应用程序所需的最小播种量", "InstanceName": "中文", - "InstanceNameHelpText": "选项卡及日志应用名称" + "InstanceNameHelpText": "选项卡及日志应用名称", + "ThemeHelpText": "修改Prowlarr UI主题, 受{0}启发", + "Duration": "时长", + "ElapsedTime": "运行时间", + "EnabledRedirected": "启用, 修改", + "Ended": "已完结", + "GrabTitle": "抓取标题", + "LastExecution": "上一次执行", + "NextExecution": "接下来执行", + "Parameters": "参数", + "Queued": "队列中", + "Started": "已开始", + "LastDuration": "上一次用时" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_TW.json b/src/NzbDrone.Core/Localization/Core/zh_TW.json index 4ab65ccd6..85f52e977 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_TW.json +++ b/src/NzbDrone.Core/Localization/Core/zh_TW.json @@ -1,4 +1,15 @@ { "About": "關於", - "Add": "添加" + "Add": "新增", + "Added": "以新增", + "Actions": "執行", + "Age": "年齡", + "AddIndexer": "新增索引", + "AddNewIndexer": "新增新索引", + "AddDownloadClient": "新增下載器", + "Analytics": "分析", + "AddIndexerProxy": "新增索引器代理", + "AddingTag": "新增標籤", + "All": "全部", + "AddRemoveOnly": "僅限新增或移除" } From d5088cf4728e451ea628ec0fc7b7603bef5753c0 Mon Sep 17 00:00:00 2001 From: Ben Weidenhofer <benweidenhofer@live.com> Date: Fri, 22 Jul 2022 22:12:01 +0930 Subject: [PATCH 0548/2320] Fixed: UI Typos (#1072) Updated localization file to provide a few spelling and grammatical corrections. --- src/NzbDrone.Core/Localization/Core/en.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 9ade26b92..8411402df 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -78,7 +78,7 @@ "Connect": "Notifications", "ConnectionLost": "Connection Lost", "ConnectionLostAutomaticMessage": "Prowlarr will try to connect automatically, or you can click reload below.", - "ConnectionLostMessage": "Prowlarr has lost it's connection to the backend and will need to be reloaded to restore functionality.", + "ConnectionLostMessage": "Prowlarr has lost its connection to the backend and will need to be reloaded to restore functionality.", "Connections": "Connections", "ConnectSettings": "Connect Settings", "ConnectSettingsSummary": "Notifications and custom scripts", @@ -176,7 +176,7 @@ "IllRestartLater": "I'll restart later", "IncludeHealthWarningsHelpText": "Include Health Warnings", "Indexer": "Indexer", - "IndexerAlreadySetup": "At least one instace of indexer is already setup", + "IndexerAlreadySetup": "At least one instance of indexer is already setup", "IndexerAuth": "Indexer Auth", "IndexerDetails": "Indexer Details", "IndexerFlags": "Indexer Flags", @@ -230,7 +230,7 @@ "Message": "Message", "MIA": "MIA", "MinimumSeeders": "Minimum Seeders", - "MinimumSeedersHelpText": "Minimum seeders required by the Appliction for the indexer to grab", + "MinimumSeedersHelpText": "Minimum seeders required by the Application for the indexer to grab", "Mode": "Mode", "MoreInfo": "More Info", "MovieIndexScrollBottom": "Movie Index: Scroll Bottom", @@ -431,7 +431,7 @@ "UnableToLoadDownloadClients": "Unable to load download clients", "UnableToLoadGeneralSettings": "Unable to load General settings", "UnableToLoadHistory": "Unable to load history", - "UnableToLoadIndexerProxies": "Unable To Load Indexer Proxies", + "UnableToLoadIndexerProxies": "Unable to load Indexer Proxies", "UnableToLoadIndexers": "Unable to load Indexers", "UnableToLoadNotifications": "Unable to load Notifications", "UnableToLoadTags": "Unable to load Tags", From 60f87783059c47d816a2c98f9d611f9355510a25 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 24 Jul 2022 19:22:06 -0500 Subject: [PATCH 0549/2320] New: Search by DoubanId --- .../Definitions/MovieSearchCriteria.cs | 1 + .../Definitions/MusicSearchCriteria.cs | 1 + .../Definitions/TvSearchCriteria.cs | 1 + .../IndexerSearch/NewznabRequest.cs | 27 ++++++++++++++++--- .../IndexerSearch/NewznabResults.cs | 2 ++ .../IndexerSearch/ReleaseSearchService.cs | 3 +++ .../Indexers/IndexerCapabilities.cs | 27 ++++++++++++++++--- src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs | 2 ++ 8 files changed, 58 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/MovieSearchCriteria.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/MovieSearchCriteria.cs index e576d8eee..f69d88a3b 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/MovieSearchCriteria.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/MovieSearchCriteria.cs @@ -9,6 +9,7 @@ namespace NzbDrone.Core.IndexerSearch.Definitions public string ImdbId { get; set; } public int? TmdbId { get; set; } public int? TraktId { get; set; } + public int? DoubanId { get; set; } public int? Year { get; set; } public string Genre { get; set; } diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/MusicSearchCriteria.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/MusicSearchCriteria.cs index d75e3a0db..4026367cc 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/MusicSearchCriteria.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/MusicSearchCriteria.cs @@ -8,6 +8,7 @@ namespace NzbDrone.Core.IndexerSearch.Definitions public string Artist { get; set; } public string Label { get; set; } public string Genre { get; set; } + public string Track { get; set; } public int? Year { get; set; } public override bool RssSearch diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/TvSearchCriteria.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/TvSearchCriteria.cs index 4a1303d28..35ba12dd2 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/TvSearchCriteria.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/TvSearchCriteria.cs @@ -17,6 +17,7 @@ namespace NzbDrone.Core.IndexerSearch.Definitions public int? TvMazeId { get; set; } public int? TraktId { get; set; } public int? TmdbId { get; set; } + public int? DoubanId { get; set; } public string SanitizedTvSearchString => (SanitizedSearchTerm + " " + EpisodeSearchString).Trim(); public string EpisodeSearchString => GetEpisodeSearchString(); diff --git a/src/NzbDrone.Core/IndexerSearch/NewznabRequest.cs b/src/NzbDrone.Core/IndexerSearch/NewznabRequest.cs index 912c108fb..56dac00de 100644 --- a/src/NzbDrone.Core/IndexerSearch/NewznabRequest.cs +++ b/src/NzbDrone.Core/IndexerSearch/NewznabRequest.cs @@ -4,9 +4,9 @@ namespace NzbDrone.Core.IndexerSearch { public class NewznabRequest { - private static readonly Regex TvRegex = new Regex(@"\{((?:imdbid\:)(?<imdbid>[^{]+)|(?:tvdbid\:)(?<tvdbid>[^{]+)|(?:season\:)(?<season>[^{]+)|(?:episode\:)(?<episode>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); - private static readonly Regex MovieRegex = new Regex(@"\{((?:imdbid\:)(?<imdbid>[^{]+)|(?:tmdbid\:)(?<tmdbid>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); - private static readonly Regex MusicRegex = new Regex(@"\{((?:artist\:)(?<artist>[^{]+)|(?:album\:)(?<album>[^{]+)|(?:label\:)(?<label>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex TvRegex = new Regex(@"\{((?:imdbid\:)(?<imdbid>[^{]+)|(?:tvdbid\:)(?<tvdbid>[^{]+)|(?:tmdbid\:)(?<tmdbid>[^{]+)|(?:doubanid\:)(?<doubanid>[^{]+)|(?:season\:)(?<season>[^{]+)|(?:episode\:)(?<episode>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex MovieRegex = new Regex(@"\{((?:imdbid\:)(?<imdbid>[^{]+)|(?:doubanid\:)(?<doubanid>[^{]+)|(?:tmdbid\:)(?<tmdbid>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex MusicRegex = new Regex(@"\{((?:artist\:)(?<artist>[^{]+)|(?:album\:)(?<album>[^{]+)|(?:track\:)(?<track>[^{]+)|(?:label\:)(?<label>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex BookRegex = new Regex(@"\{((?:author\:)(?<author>[^{]+)|(?:title\:)(?<title>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); public string t { get; set; } @@ -21,6 +21,7 @@ namespace NzbDrone.Core.IndexerSearch public int? tvmazeid { get; set; } public int? traktid { get; set; } public int? tvdbid { get; set; } + public int? doubanid { get; set; } public int? season { get; set; } public string ep { get; set; } public string album { get; set; } @@ -49,6 +50,16 @@ namespace NzbDrone.Core.IndexerSearch tvdbid = int.TryParse(match.Groups["tvdbid"].Value, out var tvdb) ? tvdb : null; } + if (match.Groups["tmdbid"].Success) + { + tmdbid = int.TryParse(match.Groups["tmdbid"].Value, out var tmdb) ? tmdb : null; + } + + if (match.Groups["doubanid"].Success) + { + doubanid = int.TryParse(match.Groups["doubanid"].Value, out var tmdb) ? tmdb : null; + } + if (match.Groups["season"].Success) { season = int.TryParse(match.Groups["season"].Value, out var seasonParsed) ? seasonParsed : null; @@ -79,6 +90,11 @@ namespace NzbDrone.Core.IndexerSearch tmdbid = int.TryParse(match.Groups["tmdbid"].Value, out var tmdb) ? tmdb : null; } + if (match.Groups["doubanid"].Success) + { + doubanid = int.TryParse(match.Groups["doubanid"].Value, out var tmdb) ? tmdb : null; + } + if (match.Groups["imdbid"].Success) { imdbid = match.Groups["imdbid"].Value; @@ -104,6 +120,11 @@ namespace NzbDrone.Core.IndexerSearch album = match.Groups["album"].Value; } + if (match.Groups["track"].Success) + { + track = match.Groups["track"].Value; + } + if (match.Groups["label"].Success) { label = match.Groups["label"].Value; diff --git a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs index 985822788..f272559ae 100644 --- a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs +++ b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs @@ -107,6 +107,8 @@ namespace NzbDrone.Core.IndexerSearch GetNabElement("booktitle", RemoveInvalidXMLChars(r.BookTitle), protocol), GetNabElement("artist", RemoveInvalidXMLChars(r.Artist), protocol), GetNabElement("album", RemoveInvalidXMLChars(r.Album), protocol), + GetNabElement("label", RemoveInvalidXMLChars(r.Label), protocol), + GetNabElement("track", RemoveInvalidXMLChars(r.Track), protocol), GetNabElement("infohash", RemoveInvalidXMLChars(t.InfoHash), protocol), GetNabElement("minimumratio", t.MinimumRatio, protocol), GetNabElement("minimumseedtime", t.MinimumSeedTime, protocol), diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs index 75d87e73a..c4e40bd4e 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs @@ -59,6 +59,7 @@ namespace NzbDrone.Core.IndexerSearch searchSpec.ImdbId = request.imdbid; searchSpec.TmdbId = request.tmdbid; searchSpec.TraktId = request.traktid; + searchSpec.DoubanId = request.doubanid; searchSpec.Year = request.year; searchSpec.Genre = request.genre; @@ -73,6 +74,7 @@ namespace NzbDrone.Core.IndexerSearch searchSpec.Album = request.album; searchSpec.Label = request.label; searchSpec.Genre = request.genre; + searchSpec.Track = request.track; searchSpec.Year = request.year; return new NewznabResults { Releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) }; @@ -88,6 +90,7 @@ namespace NzbDrone.Core.IndexerSearch searchSpec.ImdbId = request.imdbid; searchSpec.TraktId = request.traktid; searchSpec.TmdbId = request.tmdbid; + searchSpec.DoubanId = request.doubanid; searchSpec.RId = request.rid; searchSpec.TvMazeId = request.tvmazeid; diff --git a/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs b/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs index e0e26593b..b20c0d17e 100644 --- a/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs +++ b/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs @@ -15,7 +15,8 @@ namespace NzbDrone.Core.Indexers RId, TvMazeId, TraktId, - TmdbId + TmdbId, + DoubanId } public enum MovieSearchParam @@ -26,7 +27,8 @@ namespace NzbDrone.Core.Indexers ImdbTitle, ImdbYear, TraktId, - Genre + Genre, + DoubanId } public enum MusicSearchParam @@ -36,7 +38,8 @@ namespace NzbDrone.Core.Indexers Artist, Label, Year, - Genre + Genre, + Track } public enum SearchParam @@ -71,6 +74,7 @@ namespace NzbDrone.Core.Indexers public bool TvSearchTvMazeAvailable => TvSearchParams.Contains(TvSearchParam.TvMazeId); public bool TvSearchTraktAvailable => TvSearchParams.Contains(TvSearchParam.TraktId); public bool TvSearchTmdbAvailable => TvSearchParams.Contains(TvSearchParam.TmdbId); + public bool TvSearchDoubanAvailable => TvSearchParams.Contains(TvSearchParam.DoubanId); public List<MovieSearchParam> MovieSearchParams; public bool MovieSearchAvailable => MovieSearchParams.Count > 0; @@ -78,12 +82,14 @@ namespace NzbDrone.Core.Indexers public bool MovieSearchTmdbAvailable => MovieSearchParams.Contains(MovieSearchParam.TmdbId); public bool MovieSearchTraktAvailable => MovieSearchParams.Contains(MovieSearchParam.TraktId); public bool MovieSearchGenreAvailable => MovieSearchParams.Contains(MovieSearchParam.Genre); + public bool MovieSearchDoubanAvailable => MovieSearchParams.Contains(MovieSearchParam.DoubanId); public List<MusicSearchParam> MusicSearchParams; public bool MusicSearchAvailable => MusicSearchParams.Count > 0; public bool MusicSearchAlbumAvailable => MusicSearchParams.Contains(MusicSearchParam.Album); public bool MusicSearchArtistAvailable => MusicSearchParams.Contains(MusicSearchParam.Artist); public bool MusicSearchLabelAvailable => MusicSearchParams.Contains(MusicSearchParam.Label); + public bool MusicSearchTrackAvailable => MusicSearchParams.Contains(MusicSearchParam.Track); public bool MusicSearchYearAvailable => MusicSearchParams.Contains(MusicSearchParam.Year); public bool MusicSearchGenreAvailable => MusicSearchParams.Contains(MusicSearchParam.Genre); @@ -302,6 +308,11 @@ namespace NzbDrone.Core.Indexers parameters.Add("tmdbid"); } + if (TvSearchDoubanAvailable) + { + parameters.Add("doubanid"); + } + return string.Join(",", parameters); } @@ -335,6 +346,11 @@ namespace NzbDrone.Core.Indexers parameters.Add("genre"); } + if (MovieSearchDoubanAvailable) + { + parameters.Add("doubanid"); + } + return string.Join(",", parameters); } @@ -356,6 +372,11 @@ namespace NzbDrone.Core.Indexers parameters.Add("label"); } + if (MusicSearchTrackAvailable) + { + parameters.Add("track"); + } + if (MusicSearchYearAvailable) { parameters.Add("year"); diff --git a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs index fe1815483..a3bb5169e 100644 --- a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs +++ b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs @@ -40,6 +40,8 @@ namespace NzbDrone.Core.Parser.Model public string BookTitle { get; set; } public string Artist { get; set; } public string Album { get; set; } + public string Label { get; set; } + public string Track { get; set; } public DateTime PublishDate { get; set; } public string PosterUrl { get; set; } From 60f48e3a94068315551b19d3c274dfd0368ea62c Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Mon, 25 Jul 2022 00:29:10 +0000 Subject: [PATCH 0550/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index 1ac4758fb..938b8153e 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -2753,6 +2753,14 @@ "format": "int32" } }, + { + "name": "doubanid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, { "name": "season", "in": "query", @@ -2967,6 +2975,14 @@ "format": "int32" } }, + { + "name": "doubanid", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, { "name": "season", "in": "query", @@ -5772,7 +5788,8 @@ "imdbTitle", "imdbYear", "traktId", - "genre" + "genre", + "doubanId" ], "type": "string" }, @@ -5783,7 +5800,8 @@ "artist", "label", "year", - "genre" + "genre", + "track" ], "type": "string" }, @@ -6231,7 +6249,8 @@ "rId", "tvMazeId", "traktId", - "tmdbId" + "tmdbId", + "doubanId" ], "type": "string" }, From 1d25a643f96c825e3e3c2fab6e544c2cc699400c Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Tue, 26 Jul 2022 05:09:04 +0000 Subject: [PATCH 0551/2320] Translated using Weblate (Hungarian) Currently translated at 100.0% (462 of 462 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (462 of 462 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (462 of 462 strings) Co-authored-by: Csaba <csab0825@gmail.com> Co-authored-by: Havok Dan <havokdan@yahoo.com.br> Co-authored-by: Oskari Lavinto <olavinto@protonmail.com> Co-authored-by: Weblate <noreply@weblate.org> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/fi.json | 4 ++-- src/NzbDrone.Core/Localization/Core/hu.json | 2 +- src/NzbDrone.Core/Localization/Core/pt_BR.json | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/fi.json b/src/NzbDrone.Core/Localization/Core/fi.json index c6059d672..e9887452b 100644 --- a/src/NzbDrone.Core/Localization/Core/fi.json +++ b/src/NzbDrone.Core/Localization/Core/fi.json @@ -351,7 +351,7 @@ "SyncLevelAddRemove": "Vain lisäys/poisto: Kun Prowlarrin tietolähteitä lisätään tai poistetaan, päivittyy myös etäsovellus.", "SyncAppIndexers": "Synkronoi tietolähteet", "TestAllApps": "Testaa kaikki sovellukset", - "UnableToLoadIndexerProxies": "Tietolähdevälityspalvelinten lataus epäonnistui", + "UnableToLoadIndexerProxies": "Tietolähdevälityspalvelimien lataus epäonnistui", "AddedToDownloadClient": "Julkaisu lisättiin lataustyökaluun", "AddNewIndexer": "Lisää uusi tietolähde", "AddToDownloadClient": "Lisää julkaisu lataustyökaluun", @@ -409,7 +409,7 @@ "Categories": "Kategoriat", "Database": "Tietokanta", "HistoryCleanup": "Historian siivous", - "IndexerAlreadySetup": "Tietolähteestä on määritetty jo ainakin yksi kopio", + "IndexerAlreadySetup": "Tietolähteestä on määritetty jo ainakin yksi instanssi", "IndexerInfo": "Tietolähteen tiedot", "MassEditor": "Massamuokkaus", "OnApplicationUpdate": "Sovelluksen päivittyessä", diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index 782b43990..0e82e860b 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -446,7 +446,7 @@ "SyncProfiles": "Szinkronizálási profilok", "AddSyncProfile": "Szinkronizálási profil hozzáadása", "EditSyncProfile": "Szinkronizálási profil szerkesztése", - "MinimumSeedersHelpText": "Az Alkalmazás által megkövetelt minimális Seeder az indexer számára", + "MinimumSeedersHelpText": "Az alkalmazás által megkövetelt minimális Seeder az indexer számára", "InstanceName": "Példány Neve", "InstanceNameHelpText": "Példánynév a böngésző lapon és a syslog alkalmazás neve", "ThemeHelpText": "Prowlarr felhasználói felület témájának módosítása, ihlette {0}", diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index c17e54e68..c4bd039e1 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -96,7 +96,7 @@ "Component": "Componente", "Connect": "Notificações", "ConnectionLost": "Conexão perdida", - "ConnectionLostMessage": "O Prowlarr perdeu a conexão com o backend e precisará ser recarregado para restaurar a funcionalidade.", + "ConnectionLostMessage": "O Prowlarr perdeu sua conexão com o backend e precisará ser recarregado para restaurar a funcionalidade.", "Connections": "Conexões", "ConnectSettings": "Configurações de conexão", "Date": "Data", @@ -387,7 +387,7 @@ "IndexerTagsHelpText": "Usar etiquetas para especificar proxies do indexador, com quais aplicativos o indexador é sincronizado ou apenas para organizar seus indexadores.", "Notifications": "Notificações", "UnableToAddANewIndexerProxyPleaseTryAgain": "Não foi possível adicionar um novo proxy indexador, tente novamente.", - "UnableToLoadIndexerProxies": "Incapaz de carregar proxies indexadores", + "UnableToLoadIndexerProxies": "Não foi possível carregar proxies do indexador", "IndexerVipCheckExpiredClientMessage": "Benefícios VIP do Indexador expiraram: {0}", "IndexerProxy": "Proxy do Indexador", "IndexerVipCheckExpiringClientMessage": "Os benefícios VIPS do Indexador expirarão em breve: {0}", @@ -409,7 +409,7 @@ "TestAllIndexers": "Testar todos os indexadores", "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent fornecido pelo aplicativo que chamou a API", "Categories": "Categorias", - "IndexerAlreadySetup": "Pelo menos uma instância do indexador já está configurado", + "IndexerAlreadySetup": "Pelo menos uma instância do indexador já está configurada", "IndexerInfo": "Info do Indexador", "MassEditor": "Editor em Massa", "Database": "Banco de dados", @@ -446,7 +446,7 @@ "SyncProfiles": "Perfis de Sincronização", "AddSyncProfile": "Adicionar Perfil de Sincronização", "MinimumSeeders": "Mínimo de Seeders", - "MinimumSeedersHelpText": "Mínimo de seeders requeridos pelo Aplicativo para o indexador baixar", + "MinimumSeedersHelpText": "Semeadores mínimos exigidos pelo aplicativo para o indexador baixar", "ThemeHelpText": "Altere o tema da IU do Prowlarr, inspirado em {0}", "InstanceName": "Nome da instância", "InstanceNameHelpText": "Nome da instância na guia e para o nome do aplicativo Syslog", From efffeebe7c2c09f48c9b400883b5ebc22cd0a9ed Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 24 Jul 2022 15:50:29 -0500 Subject: [PATCH 0552/2320] Fixed: (GazelleGames) Use API instead of scraping --- .../Indexers/GazelleGames/recentfeed.json | 51562 ++++++++++++++++ .../GazelleGamesTests/GazelleGamesFixture.cs | 68 + .../Indexers/Definitions/GazelleGames.cs | 393 +- 3 files changed, 51876 insertions(+), 147 deletions(-) create mode 100644 src/NzbDrone.Core.Test/Files/Indexers/GazelleGames/recentfeed.json create mode 100644 src/NzbDrone.Core.Test/IndexerTests/GazelleGamesTests/GazelleGamesFixture.cs diff --git a/src/NzbDrone.Core.Test/Files/Indexers/GazelleGames/recentfeed.json b/src/NzbDrone.Core.Test/Files/Indexers/GazelleGames/recentfeed.json new file mode 100644 index 000000000..aa1d66425 --- /dev/null +++ b/src/NzbDrone.Core.Test/Files/Indexers/GazelleGames/recentfeed.json @@ -0,0 +1,51562 @@ +{ + "status": "success", + "response": { + "84781": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "flight_simulation open_world | asobo_studio controller controller_support flight flying gamepad gamepad_support ggns_game_of_the_year_awards_2020 ggns_goty_2020 microsoft_flight_simulator microsoft_game_studios microsoft_studios microtransactions native_controller_support native_gamepad_support rock_paper_shotgun_top_100_pc_games_2021_edition windows_10_only xbox_game_studios", + "ID": "84781", + "Name": "Microsoft Flight Simulator", + "Rating": "1", + "TagList": "flight_simulation open_world", + "Torrents": { + "303216": { + "ID": "303216", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Microsoft_Flight_Simulator-HOODLUM", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "323", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "80077617780", + "Time": "2022-07-25 06:39:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 383, + "Leechers": 0, + "Snatched": 3033 + }, + "304154": { + "ID": "304154", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Microsoft Flight Simulator Monkey Repack [FitGirl Repack]", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "18", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "73486615129", + "Time": "2020-08-21 07:01:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 263, + "Leechers": 0, + "Snatched": 1790 + }, + "402359": { + "ID": "402359", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Microsoft Flight Simulator Update 22 v1.19.8.0", + "Miscellaneous": "Home Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "93824052353", + "Time": "2021-09-19 01:36:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 104, + "Leechers": 0, + "Snatched": 645 + }, + "442605": { + "ID": "442605", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Microsoft Flight Simulator 2020 v1.19.9.0", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "96072466657", + "Time": "2022-03-03 02:27:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 60, + "Leechers": 0, + "Snatched": 117 + }, + "349672": { + "ID": "349672", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Microsoft Flight Simulator - Premium Deluxe Aircraft v1.13.16", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4022549390", + "Time": "2021-02-19 08:53:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 154, + "Leechers": 0, + "Snatched": 584 + }, + "349671": { + "ID": "349671", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Microsoft Flight Simulator - Premium Deluxe Airports v1.13.16", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1668685573", + "Time": "2021-02-19 08:51:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 146, + "Leechers": 0, + "Snatched": 535 + }, + "479871": { + "ID": "479871", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "PMDG – Boeing 737–700 v3.0.29", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1641521031", + "Time": "2022-07-24 19:32:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 12 + }, + "479870": { + "ID": "479870", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Asobo Studio – Boeing B787–10 Dreamliner v0.1.96 (v1.27.5) (Patched)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "238530184", + "Time": "2022-07-24 19:32:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 7 + }, + "479778": { + "ID": "479778", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Hype Performance Group – Airbus H145 Action Pack v0.9.5 (Build 300)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1178921131", + "Time": "2022-07-24 07:19:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 14 + }, + "479777": { + "ID": "479777", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Hype Performance Group – Airbus H145 Base Pack v0.9.5 (Build 300)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1407601941", + "Time": "2022-07-24 07:19:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 13 + }, + "479574": { + "ID": "479574", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Aeroplane Heaven – Globe Swift GC–1A v1.0.6", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1493950977", + "Time": "2022-07-23 05:23:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 14 + }, + "479573": { + "ID": "479573", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "SC Designs – F–16 C, D & I Fighting Falcon v0.7.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "474425878", + "Time": "2022-07-23 05:23:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 10 + }, + "478551": { + "ID": "478551", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Nemeth Designs – Yakovlev Yak–18T v1.0.6", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "586025039", + "Time": "2022-07-19 01:05:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 13 + }, + "478550": { + "ID": "478550", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Nemeth Designs – Aero–Works Aerolite 103 v1.1.7", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "557489766", + "Time": "2022-07-19 01:05:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 12 + }, + "478549": { + "ID": "478549", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Nemeth Designs – SIAI\/Marchetti S.205 v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "388576554", + "Time": "2022-07-19 01:04:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 12 + }, + "478436": { + "ID": "478436", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Flysimware – Cessna 414AW Chancellor v2.7.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1806177379", + "Time": "2022-07-18 09:27:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 15 + }, + "478214": { + "ID": "478214", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "AzurPoly – Socata TB–30 Epsilon v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "657669999", + "Time": "2022-07-17 07:46:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 13 + }, + "477415": { + "ID": "477415", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Aerosoft – Twin Otter v1.0.6.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4127767932", + "Time": "2022-07-14 02:05:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 19 + }, + "477183": { + "ID": "477183", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Flysimware – Cessna 414AW Chancellor v2.6.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1806151185", + "Time": "2022-07-13 06:43:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 18 + }, + "476979": { + "ID": "476979", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Touching Cloud – Jetpack JW1 Skypirat v2.0.6", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "173487041", + "Time": "2022-07-11 23:32:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 11 + }, + "476900": { + "ID": "476900", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Aerosoft – KTNP Twentynine Palms Airport v1.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "761384248", + "Time": "2022-07-11 07:46:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 10 + }, + "476899": { + "ID": "476899", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Got Friends – Discus–2c Premium v2.0.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2796947726", + "Time": "2022-07-11 07:46:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 16 + }, + "476898": { + "ID": "476898", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Aerosoft – CRJ 550\/700\/900\/1000 Bundle v1.0.18.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1591622084", + "Time": "2022-07-11 07:45:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 19 + }, + "476897": { + "ID": "476897", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Roland Laborie – Canadair CL–415 v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1086720378", + "Time": "2022-07-11 07:45:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 15 + }, + "476891": { + "ID": "476891", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "PMDG – Boeing 737–700 v3.0.25", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1643986487", + "Time": "2022-07-11 07:42:01", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 23 + }, + "476058": { + "ID": "476058", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "LightSim – Stream v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "465522142", + "Time": "2022-07-07 00:50:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 11 + }, + "475890": { + "ID": "475890", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "IndiaFoxtEcho – Lockheed Martin F–35 Lightning II v1.0.9", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1569590663", + "Time": "2022-07-06 13:53:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 23 + }, + "475878": { + "ID": "475878", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "DC Designs – F–14 A\/B Tomcat v1.0.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "736508719", + "Time": "2022-07-06 13:48:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 19 + }, + "475877": { + "ID": "475877", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Aeroplane Heaven – de Havilland Canada DHC–1 Chipmunk v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2101624629", + "Time": "2022-07-06 13:47:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 16 + }, + "475339": { + "ID": "475339", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Just Flight – Piper PA–28–161 Warrior II v0.3.5", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "693082206", + "Time": "2022-07-03 19:35:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 13 + }, + "475338": { + "ID": "475338", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Just Flight – Piper PA–28R Turbo Arrow III\/IV v0.5.5", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1125755171", + "Time": "2022-07-03 19:34:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 16 + }, + "475337": { + "ID": "475337", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Just Flight – Piper PA–28R Arrow III v0.10.5", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "845366761", + "Time": "2022-07-03 19:34:03", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 13 + }, + "475336": { + "ID": "475336", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Embraer Phenom 100 v1.0.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "341422406", + "Time": "2022-07-03 19:33:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 14 + }, + "475335": { + "ID": "475335", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Just Flight – BAe Hawk T1\/A Advanced Trainer v0.1.7", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1045304132", + "Time": "2022-07-03 19:32:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 13 + }, + "475333": { + "ID": "475333", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Just Flight – BAe 146 Professional v0.1.7", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2977925861", + "Time": "2022-07-03 19:30:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 19 + }, + "474334": { + "ID": "474334", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Sim Skunk Works – Lockheed Martin TF–104G Starfighter v3.1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1137120968", + "Time": "2022-06-30 04:15:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 18 + }, + "474333": { + "ID": "474333", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Sim Skunk Works – Lockheed Martin FRF–104G Starfighter v1.2.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1179644156", + "Time": "2022-06-30 04:14:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 17 + }, + "474332": { + "ID": "474332", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Aeroplane Heaven – Electra 10A v1.33.7", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1731449151", + "Time": "2022-06-30 04:14:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 20 + }, + "474331": { + "ID": "474331", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Aeroplane Heaven – Supermarine Spitfire Mk1A v1.6.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "910954411", + "Time": "2022-06-30 04:13:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 12 + }, + "473805": { + "ID": "473805", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Parallel 42 – FreedomFox & Fox2 v2022.26.4.16", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3105876931", + "Time": "2022-06-28 02:38:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 15 + }, + "473794": { + "ID": "473794", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Roland Laborie – Vought Crusader F8–E v1.0.0 (Update 3)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1012846887", + "Time": "2022-06-28 02:31:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 12 + }, + "473793": { + "ID": "473793", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Big Radials – Grumman JRF–6B Goose v1.0.4d", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1569793737", + "Time": "2022-06-28 02:31:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 17 + }, + "473789": { + "ID": "473789", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Just Flight – Piper PA–28R Arrow III v0.10.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "845366236", + "Time": "2022-06-28 02:29:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 12 + }, + "472767": { + "ID": "472767", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Parallel 42 – FreedomFox & Fox2 v2022.25.4.18", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3330220923", + "Time": "2022-06-20 05:56:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 19 + }, + "472763": { + "ID": "472763", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Black Square – Velocity XL v0.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "137958552", + "Time": "2022-06-20 05:54:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 11 + }, + "472542": { + "ID": "472542", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Virtualcol FS Software – Embraer 190–195 Series v2.24.6", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "815176306", + "Time": "2022-06-18 08:53:22", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 16 + }, + "472541": { + "ID": "472541", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Virtualcol FS Software – Embraer 170–175 Series v2.66.6", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "566190453", + "Time": "2022-06-18 08:52:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 17 + }, + "472540": { + "ID": "472540", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Flysimware – Cessna 414AW Chancellor v2.3.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1636195730", + "Time": "2022-06-18 08:51:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 19 + }, + "472072": { + "ID": "472072", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Leonardo Software House – Fly the Maddog X v1.0.0b95", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "589592203", + "Time": "2022-06-16 08:29:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 21 + }, + "471959": { + "ID": "471959", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Captain Sim – Boeing 777–200ER with integrated FTSiM+ Sound Pack (GE) v1.0.1.2 (Fixed Files)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "724393745", + "Time": "2022-06-15 23:25:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 19 + }, + "471394": { + "ID": "471394", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "NextGen Simulations – Embraer EMB110 Bandeirante v1.5.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "523456498", + "Time": "2022-06-12 10:43:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 21 + }, + "471073": { + "ID": "471073", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Flight Replicas – L–4 Grasshopper v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "840791704", + "Time": "2022-06-11 01:42:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 19 + }, + "471072": { + "ID": "471072", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "FlyingIron Simulations – Spitfire L.F Mk IXc v1.2.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1093496032", + "Time": "2022-06-11 01:41:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 24 + }, + "470901": { + "ID": "470901", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Mario Noriega Designs – Caproni–Vizolla C–22J Ventura v1.3.9", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "154410156", + "Time": "2022-06-09 19:54:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 18 + }, + "470894": { + "ID": "470894", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "SimWorks Studios – Daher Kodiak 100 Wheels v1.2.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "641748249", + "Time": "2022-06-09 19:50:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 22 + }, + "470889": { + "ID": "470889", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "DC Designs – F–15 C, D, E & I Eagle v1.0.8", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "928335570", + "Time": "2022-06-09 19:47:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 26 + }, + "469764": { + "ID": "469764", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "PMDG – Douglas DC–6 v2.0.41", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "698625073", + "Time": "2022-06-04 18:28:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 23 + }, + "468384": { + "ID": "468384", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Red Wing Simulations – Lockheed L–1049 Super–Constellation v0.1.9", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1680423010", + "Time": "2022-05-31 22:24:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 18 + }, + "468119": { + "ID": "468119", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Big Radials – Grumman JRF–6B Goose v1.0.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1567957521", + "Time": "2022-05-30 21:05:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 21 + }, + "467259": { + "ID": "467259", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "SimWorks Studios – Van’s RV–14\/14A v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "394260686", + "Time": "2022-05-27 00:32:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "467064": { + "ID": "467064", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "BlackBox Simulation – Britten–Norman BN–2A Mk III Trislander v1.1.6", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "234866982", + "Time": "2022-05-26 04:43:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 14 + }, + "464981": { + "ID": "464981", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "IndiaFoxtEcho – Sukhoi SU–31 v1.0.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "316859267", + "Time": "2022-05-17 10:26:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 17 + }, + "463432": { + "ID": "463432", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Parallel 42 – FreedomFox & Fox2 v2022.20.1.19", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2609356957", + "Time": "2022-05-14 09:25:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 16 + }, + "462920": { + "ID": "462920", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "IndiaFoxtEcho – T–45C Goshawk v1.2.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "853404647", + "Time": "2022-05-12 10:58:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 17 + }, + "462570": { + "ID": "462570", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Aeroplane Heaven – North American P51–D Mustang v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2364822856", + "Time": "2022-05-10 10:32:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 29 + }, + "462568": { + "ID": "462568", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Roland Laborie – Canadair CL–215 v1.0.0 (Update 1)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "515279797", + "Time": "2022-05-10 10:30:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 12 + }, + "462057": { + "ID": "462057", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Sim Federation – Embraer Phenom 300E v1.0.5", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "135960494", + "Time": "2022-05-08 05:52:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 15 + }, + "462056": { + "ID": "462056", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "IndiaFoxtEcho – Rutan Model 61 Long–EZ v1.2.6", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "575140605", + "Time": "2022-05-08 05:52:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 16 + }, + "462055": { + "ID": "462055", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Roland Laborie – Vought Crusader F8–E v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1012581319", + "Time": "2022-05-08 05:51:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 16 + }, + "461753": { + "ID": "461753", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "MilViz – PC–6 Porter v1.0.9", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1164575979", + "Time": "2022-05-06 06:12:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 30 + }, + "461665": { + "ID": "461665", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "MilViz – 310R v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2119872663", + "Time": "2022-05-05 18:39:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 42 + }, + "461604": { + "ID": "461604", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Cockspur – Aeroprakt A22–LS v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "889635472", + "Time": "2022-05-05 05:11:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 21 + }, + "461603": { + "ID": "461603", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "SC Designs – F–16 C, D & I Fighting Falcon v0.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "438400606", + "Time": "2022-05-05 05:11:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 32 + }, + "461490": { + "ID": "461490", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Nemeth Designs – SIAI\/Marchetti S.205 v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "388575374", + "Time": "2022-05-04 03:36:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 20 + }, + "461322": { + "ID": "461322", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Just Flight – 146 Professional v0.1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2903715641", + "Time": "2022-05-01 20:42:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 33 + }, + "461245": { + "ID": "461245", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Sim Skunk Works – Lockheed Martin TF–104G Starfighter v3.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1305460761", + "Time": "2022-05-01 04:56:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 32 + }, + "461244": { + "ID": "461244", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Sim Skunk Works – Lockheed Martin FRF–104G Starfighter v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1370538129", + "Time": "2022-05-01 04:55:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 29 + }, + "461077": { + "ID": "461077", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Captain Sim – 767–400ER v1.0.0.1 (Added Liveries)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "653497066", + "Time": "2022-04-30 04:05:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 30 + }, + "460838": { + "ID": "460838", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "DC Designs – Concorde v1.0.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "435271891", + "Time": "2022-04-28 16:17:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 22, + "Leechers": 0, + "Snatched": 34 + }, + "460650": { + "ID": "460650", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "AzurPoly – Fouga CM.170 Magister v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "516833978", + "Time": "2022-04-27 11:10:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 23 + }, + "459985": { + "ID": "459985", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "IRIS Simulations – Tutor T.1 v2.3.7", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "252999369", + "Time": "2022-04-23 05:16:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 22 + }, + "459598": { + "ID": "459598", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Got Friends – Gee Bee R3 Special v2.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "861877422", + "Time": "2022-04-21 04:12:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 23 + }, + "459593": { + "ID": "459593", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Aeroplane Heaven – Cessna 140 v1.4.0a", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1344081107", + "Time": "2022-04-21 04:09:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 33 + }, + "459592": { + "ID": "459592", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "BRsimDesigns – Ercoupe 415C v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2292430602", + "Time": "2022-04-21 04:09:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 30 + }, + "459591": { + "ID": "459591", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "BRsimDesigns – Bonanza H35 V–tail v1.0.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "549074598", + "Time": "2022-04-21 04:08:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 26 + }, + "459590": { + "ID": "459590", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "BRsimDesigns – Debonair 35 v1.0.8", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "734255804", + "Time": "2022-04-21 04:08:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 25 + }, + "456965": { + "ID": "456965", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Big Radials – JRF–6B Goose v1.0.2a", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1567092394", + "Time": "2022-04-06 12:31:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 32 + }, + "456959": { + "ID": "456959", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Wing42 – Boeing 247D v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1538061437", + "Time": "2022-04-06 12:27:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 35 + }, + "455918": { + "ID": "455918", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Flysimware – Grumman G–44A Widgeon v1.8.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "379249325", + "Time": "2022-04-01 11:23:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 25 + }, + "455738": { + "ID": "455738", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Got Friends – EA–7 Edgley Optica v1.0.2 (Fixed)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1430096173", + "Time": "2022-03-31 08:09:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 33 + }, + "455737": { + "ID": "455737", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "BRsimDesigns – EMB200 Ipanema Crop Duster v1.0.7", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "521989694", + "Time": "2022-03-31 08:09:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 25 + }, + "454871": { + "ID": "454871", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Bredok3d – Boeing 737–MAX v1.7.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1537382094", + "Time": "2022-03-27 21:43:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 22, + "Leechers": 0, + "Snatched": 43 + }, + "453778": { + "ID": "453778", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Ants Airplanes – Drifter Ultralight v1.1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "182840308", + "Time": "2022-03-24 07:05:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 29 + }, + "453771": { + "ID": "453771", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Hype Performance Group – Airbus H145 v0.9.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1251456144", + "Time": "2022-03-24 07:02:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 34 + }, + "451961": { + "ID": "451961", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "FlyingIron Simulations – P–38L Lightning v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1157451648", + "Time": "2022-03-20 12:24:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 32 + }, + "451955": { + "ID": "451955", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Orbx – EA–7 Edgley Optica v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "384658280", + "Time": "2022-03-20 12:22:01", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 28 + }, + "444049": { + "ID": "444049", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "AzurPoly – Bede BD–5J v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "327498714", + "Time": "2022-03-10 03:05:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 29 + }, + "442288": { + "ID": "442288", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "FlyInside – Bell 47–G2 v1.71.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "811047771", + "Time": "2022-03-01 08:59:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 34 + }, + "442064": { + "ID": "442064", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "SimWorks Studios – Zenith CH701 STOL v1.5.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "698265081", + "Time": "2022-02-28 04:11:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 30 + }, + "441993": { + "ID": "441993", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Just Flight – PA–28R Arrow III v0.10.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "849086279", + "Time": "2022-02-27 13:35:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 32 + }, + "429118": { + "ID": "429118", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Sim Skunk Works – Fiat–Aeritalia G–91 v3.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1908929647", + "Time": "2022-02-11 15:52:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 33 + }, + "428668": { + "ID": "428668", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "IRIS Simulations – Jabiru J160\/J170 v1.5.6", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1086697475", + "Time": "2022-02-08 03:20:30", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 32 + }, + "426747": { + "ID": "426747", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Aeroplane Heaven – Grumman F3F–2 v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1207147583", + "Time": "2022-01-29 23:23:24", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 21, + "Leechers": 0, + "Snatched": 41 + }, + "425900": { + "ID": "425900", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Aeroplane Heaven – Supermarine Spitfire Mk1A v1.5.24", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "919461172", + "Time": "2022-01-24 23:43:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 42 + }, + "425544": { + "ID": "425544", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "BlackBox Simulation – Cessna L–19 Bird Dog v1.10.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "650808405", + "Time": "2022-01-22 12:10:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 30 + }, + "425060": { + "ID": "425060", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "BlackBox Simulation – Scottish Aviation Bulldog v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "360950080", + "Time": "2022-01-18 21:55:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 37 + }, + "424674": { + "ID": "424674", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "IndiaFoxtEcho – Aermacchi MB–339 v1.3.6", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1047388219", + "Time": "2022-01-15 19:15:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 22, + "Leechers": 0, + "Snatched": 44 + }, + "423317": { + "ID": "423317", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "DC Designs – PT–17 Stearman v1.0.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "374854865", + "Time": "2022-01-08 03:56:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 47 + }, + "423010": { + "ID": "423010", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "BlueMesh – Caudron Rafale 430 v1.5.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "511028572", + "Time": "2022-01-07 06:18:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 41 + }, + "415557": { + "ID": "415557", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Aeroplane Heaven – Electra 10A v1.2.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1731355111", + "Time": "2021-12-02 10:13:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 106 + }, + "414577": { + "ID": "414577", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Nemeth Designs – Yakovlev Yak–18T v1.0.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "588000130", + "Time": "2021-11-22 23:20:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 94 + }, + "414576": { + "ID": "414576", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Nemeth Designs – Aero–Works Aerolite 103 v1.1.6", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "539579592", + "Time": "2021-11-22 23:20:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 88 + }, + "409312": { + "ID": "409312", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Bredok3d – Eurofighter Typhoon v1.6.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "704122508", + "Time": "2021-11-03 21:43:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 41, + "Leechers": 0, + "Snatched": 121 + }, + "404367": { + "ID": "404367", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Big Radials – P–40B Tomahawk v1.0.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1099383371", + "Time": "2021-10-05 05:55:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 45, + "Leechers": 0, + "Snatched": 152 + }, + "399186": { + "ID": "399186", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Captain Sim – B777F v1.0.1.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "312582083", + "Time": "2021-09-02 22:47:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 48, + "Leechers": 0, + "Snatched": 142 + }, + "399185": { + "ID": "399185", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Captain Sim – B777–300 v1.0.1.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "340866617", + "Time": "2021-09-02 22:46:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 57, + "Leechers": 0, + "Snatched": 151 + }, + "399184": { + "ID": "399184", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Captain Sim – B777–200 v1.0.1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "603011078", + "Time": "2021-09-02 22:46:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 49, + "Leechers": 0, + "Snatched": 145 + }, + "397082": { + "ID": "397082", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Big Radials – Nieuport 17 v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "600392947", + "Time": "2021-08-25 08:52:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 51, + "Leechers": 0, + "Snatched": 166 + }, + "396321": { + "ID": "396321", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "PaperCraft Aero Design – UL Stride v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "318507444", + "Time": "2021-08-20 05:55:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 53, + "Leechers": 0, + "Snatched": 167 + }, + "395655": { + "ID": "395655", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Lionheart Creations – Trinidad TB–21 GT v4.2.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2566429750", + "Time": "2021-08-16 00:16:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 57, + "Leechers": 0, + "Snatched": 194 + }, + "395263": { + "ID": "395263", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "V.G.P. – PowerSTOL v1.3.5", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "158025231", + "Time": "2021-08-13 16:38:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 57, + "Leechers": 0, + "Snatched": 185 + }, + "384906": { + "ID": "384906", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "MilViz – FG–1D Corsair v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "555748220", + "Time": "2021-07-07 00:48:30", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 67, + "Leechers": 0, + "Snatched": 226 + }, + "380973": { + "ID": "380973", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "A1R Design Bureau – A1R Ryan ST–A Special v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "360557157", + "Time": "2021-06-23 09:39:01", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 67, + "Leechers": 0, + "Snatched": 213 + }, + "364002": { + "ID": "364002", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "V.G.P. - Powersolo v1.3.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "110324678", + "Time": "2021-04-02 02:33:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 80, + "Leechers": 0, + "Snatched": 306 + }, + "356624": { + "ID": "356624", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Virtualcol - Beechcraft Model 99 v2.1.7", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "106287713", + "Time": "2021-03-15 20:34:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 88, + "Leechers": 0, + "Snatched": 341 + }, + "343943": { + "ID": "343943", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Informatica Az - Eurofighter Typhoon 1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "676954253", + "Time": "2021-01-25 08:07:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 104, + "Leechers": 0, + "Snatched": 409 + }, + "343430": { + "ID": "343430", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Abad Studios - Airbus belugaXL A330-700 V4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "433324588", + "Time": "2021-01-23 02:42:27", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 96, + "Leechers": 0, + "Snatched": 402 + }, + "343429": { + "ID": "343429", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Abad Studios - Airbus A340-300 V4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "580485881", + "Time": "2021-01-23 02:42:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 96, + "Leechers": 0, + "Snatched": 405 + }, + "343428": { + "ID": "343428", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Abad Studios - Airbus A350 V4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "332885260", + "Time": "2021-01-23 02:42:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 96, + "Leechers": 0, + "Snatched": 405 + }, + "343427": { + "ID": "343427", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Abad Studios - Airbus A380 V4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "695472913", + "Time": "2021-01-23 02:42:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 105, + "Leechers": 0, + "Snatched": 420 + }, + "343426": { + "ID": "343426", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Abad Studios - Airbus A330 V4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "723986140", + "Time": "2021-01-23 02:42:01", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 93, + "Leechers": 0, + "Snatched": 399 + }, + "343425": { + "ID": "343425", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Abad Studios - Airbus A319 V4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "622128366", + "Time": "2021-01-23 02:41:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 100, + "Leechers": 0, + "Snatched": 406 + }, + "343424": { + "ID": "343424", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Abad Studios - Airbus A318 V4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "550928250", + "Time": "2021-01-23 02:41:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 92, + "Leechers": 0, + "Snatched": 392 + }, + "340888": { + "ID": "340888", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "IndiaFoxtEcho Visual Simulations – Long-EZ v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "546923896", + "Time": "2021-01-12 20:46:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 91, + "Leechers": 0, + "Snatched": 421 + }, + "338055": { + "ID": "338055", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "AtSimulations - Piaggio P.149 v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "605760310", + "Time": "2020-12-30 20:12:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 92, + "Leechers": 0, + "Snatched": 404 + }, + "335455": { + "ID": "335455", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Wing42 - Bleriot XI v1.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "633653347", + "Time": "2020-12-21 04:09:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 97, + "Leechers": 0, + "Snatched": 426 + }, + "335317": { + "ID": "335317", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "ATSimulations - MC-15 Cri-Cri v2.05", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "657317353", + "Time": "2020-12-20 07:14:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 103, + "Leechers": 0, + "Snatched": 430 + }, + "318249": { + "ID": "318249", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Carenado - M20R Ovation v1.1.1 - DLC", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "421585911", + "Time": "2020-10-18 08:58:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 105, + "Leechers": 0, + "Snatched": 475 + }, + "311080": { + "ID": "311080", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft", + "Scene": "0", + "ReleaseTitle": "Carenado - Cessna CT182T Skylane v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "411669214", + "Time": "2020-09-26 01:45:10", + "UserID": "14304", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 118, + "Leechers": 0, + "Snatched": 532 + }, + "473804": { + "ID": "473804", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FS2Crew – Aerosoft CRJ Edition v1.0.41", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "145688271", + "Time": "2022-06-28 02:37:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 8 + }, + "473803": { + "ID": "473803", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FS2Crew – FBW A32NX Project Edition v1.1.47", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "232874980", + "Time": "2022-06-28 02:36:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 8 + }, + "473802": { + "ID": "473802", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FS2Crew – Pushback Express v2.2.31", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "73493562", + "Time": "2022-06-28 02:36:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 10 + }, + "473801": { + "ID": "473801", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FS2Crew – RAAS Professional v1.3.7", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "55298173", + "Time": "2022-06-28 02:35:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 9 + }, + "472302": { + "ID": "472302", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – PMDG B737–700 Sound Pack (CFM) v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "44312671", + "Time": "2022-06-17 06:00:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 11 + }, + "471952": { + "ID": "471952", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – Fly the Maddog X Sound Pack v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "96512850", + "Time": "2022-06-15 23:17:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 13 + }, + "471950": { + "ID": "471950", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – A320Neo Sound Pack (CFM) v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "165946645", + "Time": "2022-06-15 23:17:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 13 + }, + "471949": { + "ID": "471949", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – B777–200ER Sound Pack (GE) v1.2.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "123807081", + "Time": "2022-06-15 23:16:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 12 + }, + "471948": { + "ID": "471948", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – ProSim A320 Sound Pack (CFM) v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "77934572", + "Time": "2022-06-15 23:15:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 12 + }, + "471947": { + "ID": "471947", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – Fenix Simulations A320 Sound Pack (CFM) v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "51343100", + "Time": "2022-06-15 23:15:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "469969": { + "ID": "469969", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "PMS50 – GTN750 Premium v2.1.38", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "11599502", + "Time": "2022-06-05 12:02:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 15 + }, + "466763": { + "ID": "466763", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "NZA Simulations – Model Library v3.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "179493084", + "Time": "2022-05-25 03:19:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 10 + }, + "466437": { + "ID": "466437", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – Fly the Maddog X Sound Pack v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "96563184", + "Time": "2022-05-24 09:06:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 14 + }, + "462303": { + "ID": "462303", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – B747 Sound Pack (PW4000) v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "178855859", + "Time": "2022-05-09 06:37:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 12 + }, + "461605": { + "ID": "461605", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – B737 Sound Pack v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "75461656", + "Time": "2022-05-05 05:12:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 15 + }, + "461503": { + "ID": "461503", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FS2Crew – Pushback Express v2.2.28", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "73493171", + "Time": "2022-05-04 03:49:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 20 + }, + "461486": { + "ID": "461486", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – Boeing 747–8 Liveries Pack v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "388278518", + "Time": "2022-05-04 03:33:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 16 + }, + "461484": { + "ID": "461484", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FS2Crew – FBW A32NX Project Edition v1.1.43", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "232874371", + "Time": "2022-05-04 03:32:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 22 + }, + "459594": { + "ID": "459594", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – Headwind A330NEO Sound Pack v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "87544047", + "Time": "2022-04-21 04:10:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 22 + }, + "458299": { + "ID": "458299", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – A320Neo Sound Pack (LEAP) v1.3.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "142037448", + "Time": "2022-04-13 06:47:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 21 + }, + "457634": { + "ID": "457634", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – C–17 Globemaster Sound Pack v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "79558292", + "Time": "2022-04-10 04:33:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 20 + }, + "457633": { + "ID": "457633", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – B747Genx Sound Pack v1.2.2a", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "102004443", + "Time": "2022-04-10 04:33:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 19 + }, + "457632": { + "ID": "457632", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – AiTraffic Sound Pack v0.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "67926750", + "Time": "2022-04-10 04:32:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 22 + }, + "456952": { + "ID": "456952", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – Twin Otter Sound Pack v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "59840435", + "Time": "2022-04-06 12:17:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 24 + }, + "455914": { + "ID": "455914", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "G–Simulations – Kneeboard v2.9.9.7", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "15635785", + "Time": "2022-04-01 11:20:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 29 + }, + "455748": { + "ID": "455748", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – B777F Sound Pack (GE) v1.2.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "123806451", + "Time": "2022-03-31 08:15:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 19 + }, + "455747": { + "ID": "455747", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – B777–300ER Sound Pack (GE) v1.2.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "123806503", + "Time": "2022-03-31 08:14:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 20 + }, + "444810": { + "ID": "444810", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – B777F Sound Pack (PW) v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "117373175", + "Time": "2022-03-15 09:18:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 24 + }, + "444809": { + "ID": "444809", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – B777–300ER Sound Pack (PW) v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "117373120", + "Time": "2022-03-15 09:18:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 24 + }, + "442565": { + "ID": "442565", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "SimPlaza – Aerosoft Twin Otter Sound Improvement v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "55046483", + "Time": "2022-03-03 00:36:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 29 + }, + "442000": { + "ID": "442000", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – B777–200ER Sound Pack (PW) v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "117373161", + "Time": "2022-02-27 13:40:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 29 + }, + "427894": { + "ID": "427894", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – CRJ Sound Pack v1.1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "76703190", + "Time": "2022-02-03 22:38:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 35 + }, + "427893": { + "ID": "427893", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – Embraer EMB 110 Sound Pack v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "129189788", + "Time": "2022-02-03 22:37:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 29 + }, + "425979": { + "ID": "425979", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – A320Neo Sound Pack (PW1000) v1.8.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "83323227", + "Time": "2022-01-25 20:40:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 37 + }, + "425978": { + "ID": "425978", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – Citation Longitude Sound Pack v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "44518067", + "Time": "2022-01-25 20:40:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 37 + }, + "425977": { + "ID": "425977", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – KingAir C90\/B200 Sound Pack v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "55225434", + "Time": "2022-01-25 20:34:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 33 + }, + "425976": { + "ID": "425976", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – C208B Sound Pack v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "40705519", + "Time": "2022-01-25 20:34:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 21, + "Leechers": 0, + "Snatched": 37 + }, + "425975": { + "ID": "425975", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – B787 Sound Pack (RR) v1.4.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "95080030", + "Time": "2022-01-25 20:23:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 37 + }, + "425972": { + "ID": "425972", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – Citation CJ4 Sound Pack v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "103669612", + "Time": "2022-01-25 20:17:21", + "UserID": "52816", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 34 + }, + "425969": { + "ID": "425969", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – B787 Sound Pack (Genx) v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "93880240", + "Time": "2022-01-25 20:14:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 38 + }, + "425062": { + "ID": "425062", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – B767–400 Sound Pack (GE) v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "71375324", + "Time": "2022-01-18 21:57:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 36 + }, + "423479": { + "ID": "423479", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ – Embraer ERJ 175 Sound Pack v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "152494299", + "Time": "2022-01-09 05:32:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 41 + }, + "416129": { + "ID": "416129", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "Illuminators – FBW Physics v1.0.23", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "14507630", + "Time": "2021-12-06 04:07:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 35, + "Leechers": 0, + "Snatched": 86 + }, + "413071": { + "ID": "413071", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ - B777-300 Sound Pack (GE) v1.2.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "93797126", + "Time": "2021-11-15 05:06:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 101 + }, + "413070": { + "ID": "413070", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FTSiM+ - B777-200 Sound Pack (GE) v1.2.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "93797123", + "Time": "2021-11-15 04:59:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 96 + }, + "395135": { + "ID": "395135", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FS2Crew – Flight Crew A320 v1.6.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "241341781", + "Time": "2021-08-12 22:18:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 47, + "Leechers": 0, + "Snatched": 151 + }, + "326541": { + "ID": "326541", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "FS2CREW - Flight Crew A320 (Button Control) v1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "240770713", + "Time": "2020-11-16 20:27:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 74, + "Leechers": 0, + "Snatched": 339 + }, + "318219": { + "ID": "318219", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft Enhancements", + "Scene": "0", + "ReleaseTitle": "Lanilogic Technology - Self-Loading Cargo", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "44010936", + "Time": "2020-10-18 00:47:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 87, + "Leechers": 0, + "Snatched": 428 + }, + "476976": { + "ID": "476976", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft that do not Fly", + "Scene": "0", + "ReleaseTitle": "IndiaFoxtEcho – America–Class LHA Ships v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "207549155", + "Time": "2022-07-11 23:30:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 11 + }, + "463431": { + "ID": "463431", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft that do not Fly", + "Scene": "0", + "ReleaseTitle": "Jeppeson2001 – Hogwarts Express Train v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "201046675", + "Time": "2022-05-14 09:25:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 15 + }, + "459586": { + "ID": "459586", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft that do not Fly", + "Scene": "0", + "ReleaseTitle": "Seafront Simulations – Vessels UK South East v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "191437925", + "Time": "2022-04-21 04:05:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 23 + }, + "458284": { + "ID": "458284", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft that do not Fly", + "Scene": "0", + "ReleaseTitle": "Seafront Simulations – Vessels The Balearic Islands v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "59303578", + "Time": "2022-04-13 06:39:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 25 + }, + "453783": { + "ID": "453783", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft that do not Fly", + "Scene": "0", + "ReleaseTitle": "Hard Deck Simulations – Functional Aircraft Carrier v1.7.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "159128585", + "Time": "2022-03-24 07:09:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 28 + }, + "444050": { + "ID": "444050", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft that do not Fly", + "Scene": "0", + "ReleaseTitle": "Marine RM – Yacht and Sailboat Pack – 5 Boats v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "380558099", + "Time": "2022-03-10 03:05:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 28 + }, + "429114": { + "ID": "429114", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft that do not Fly", + "Scene": "0", + "ReleaseTitle": "Adi S. – Luxury Speedboat v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "506094844", + "Time": "2022-02-11 15:49:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 34 + }, + "425960": { + "ID": "425960", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft that do not Fly", + "Scene": "0", + "ReleaseTitle": "IndiaFoxtEcho – Ford–Class Carriers v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "472383283", + "Time": "2022-01-25 19:17:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 38 + }, + "422569": { + "ID": "422569", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Aircraft that do not Fly", + "Scene": "0", + "ReleaseTitle": "Miltech Simulations – USS George H.W. Bush (CVN–77) v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "158123730", + "Time": "2022-01-05 22:34:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 21, + "Leechers": 0, + "Snatched": 51 + }, + "477417": { + "ID": "477417", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "Pearl Simulations – FAKN Kruger Mpumalanga International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "528122410", + "Time": "2022-07-14 02:06:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 10 + }, + "474025": { + "ID": "474025", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSXcenery – HSSS \/ HSSK Khartoum International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "84288396", + "Time": "2022-06-28 23:03:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 6 + }, + "474024": { + "ID": "474024", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSXcenery – HSSJ \/ HJJJ Juba International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "26224759", + "Time": "2022-06-28 23:02:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 6 + }, + "474023": { + "ID": "474023", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSDG – DTNH Enfidha–Hammamet International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "158936152", + "Time": "2022-06-28 23:00:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 8 + }, + "474021": { + "ID": "474021", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSXcenery – HEAX El Nouzha \/ Alexandria Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "80983659", + "Time": "2022-06-28 22:59:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 8 + }, + "473144": { + "ID": "473144", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSDG – FACT Cape Town International Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "723723261", + "Time": "2022-06-23 04:05:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 16 + }, + "472301": { + "ID": "472301", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSXcenery – DNKN Mallam Aminu Kano International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "66789189", + "Time": "2022-06-17 05:59:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "472300": { + "ID": "472300", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSXcenery – DIAP Felix–Houphouet–Boigny International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "59796768", + "Time": "2022-06-17 05:59:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "472299": { + "ID": "472299", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSXcenery – DXXX Lome–Tokoin International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "75264862", + "Time": "2022-06-17 05:59:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "471954": { + "ID": "471954", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "SimSoft – DABC Mohamed Boudiaf International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "14336746", + "Time": "2022-06-15 23:19:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 13 + }, + "460371": { + "ID": "460371", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSDG – DGAA Kotoka International Airport \/ Accra v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "632348378", + "Time": "2022-04-25 19:38:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 16 + }, + "444812": { + "ID": "444812", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSDG – FYWB Walvis Bay International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "93544564", + "Time": "2022-03-15 09:19:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 24 + }, + "434662": { + "ID": "434662", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSXcenery – MUVR Juan Gualberto Gomez Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "14549359", + "Time": "2022-02-18 03:13:01", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 32 + }, + "434658": { + "ID": "434658", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSXcenery – FVFA Victoria Falls Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "30552220", + "Time": "2022-02-18 03:12:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 31 + }, + "432710": { + "ID": "432710", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSXcenery – FKKD Douala International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "47934955", + "Time": "2022-02-16 21:22:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 33 + }, + "432709": { + "ID": "432709", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSXcenery – FCBB Maya–Maya Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "40657630", + "Time": "2022-02-16 21:22:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 33 + }, + "427895": { + "ID": "427895", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "DSky – GVBA Aristides Pereira International \/ Boa Vista Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "179240699", + "Time": "2022-02-03 22:39:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 32 + }, + "425693": { + "ID": "425693", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "Caelus Aerial – FQVL Vilankulo Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "404290060", + "Time": "2022-01-23 03:33:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 36 + }, + "399663": { + "ID": "399663", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSXcenery – HESN Aswan International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "72951930", + "Time": "2021-09-06 03:48:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 46, + "Leechers": 0, + "Snatched": 156 + }, + "397310": { + "ID": "397310", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "NMG Simulations – FAOR O. R. Tambo \/ Johannesburg International Airport v5.3.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "56210692", + "Time": "2021-08-26 15:52:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 47, + "Leechers": 0, + "Snatched": 164 + }, + "392509": { + "ID": "392509", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "Caelus Aerial - FALA Lanseria International Airport v2.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "459614176", + "Time": "2021-08-03 07:11:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 50, + "Leechers": 0, + "Snatched": 171 + }, + "383076": { + "ID": "383076", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "TropicalSim – LPSJ Sao Jorge Airport v1.1.0 Posted by SimPlaza on June 28, 20210", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "12822319", + "Time": "2021-06-29 02:00:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 60, + "Leechers": 0, + "Snatched": 208 + }, + "383075": { + "ID": "383075", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "TropicalSim – LPPI Pico Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "17266176", + "Time": "2021-06-29 02:00:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 57, + "Leechers": 0, + "Snatched": 190 + }, + "383074": { + "ID": "383074", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "Devinci – GOBD Blaise Diagne International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "196266291", + "Time": "2021-06-29 01:58:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 60, + "Leechers": 0, + "Snatched": 193 + }, + "383072": { + "ID": "383072", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "Caelus Aerial – FABL Bram Fischer International Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "303663676", + "Time": "2021-06-29 01:57:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 57, + "Leechers": 0, + "Snatched": 178 + }, + "381327": { + "ID": "381327", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "Dreamflight Studios – MRLB Daniel Oduber Quiros–Liberia International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "759709697", + "Time": "2021-06-23 23:18:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 56, + "Leechers": 0, + "Snatched": 188 + }, + "381053": { + "ID": "381053", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "Africa4FS – GLRB Roberts International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "599724504", + "Time": "2021-06-23 12:12:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 57, + "Leechers": 0, + "Snatched": 190 + }, + "381019": { + "ID": "381019", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "Project Coastline Team – HTMR Msembe Airstrip v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "42512389", + "Time": "2021-06-23 11:24:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 60, + "Leechers": 0, + "Snatched": 195 + }, + "381011": { + "ID": "381011", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSDG – GMAD Agadir–Al Massira Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "161895603", + "Time": "2021-06-23 11:14:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 60, + "Leechers": 0, + "Snatched": 183 + }, + "337684": { + "ID": "337684", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSDG Lite - FYWH Windhoek Hosea Kutako International Airport v1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "479442242", + "Time": "2020-12-29 13:28:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 79, + "Leechers": 0, + "Snatched": 344 + }, + "335189": { + "ID": "335189", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "FSDG Lite - HKJK Nairobi Jomo Kenyatta International Airport v1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1489641249", + "Time": "2020-12-19 12:55:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 91, + "Leechers": 0, + "Snatched": 413 + }, + "335165": { + "ID": "335165", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "Gaffer Simulations - FALE Durban King Shaka International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "560814309", + "Time": "2020-12-19 07:29:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 83, + "Leechers": 0, + "Snatched": 353 + }, + "331488": { + "ID": "331488", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "Simbreeze - GCTS Tenerife South Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "106265085", + "Time": "2020-12-05 07:36:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 88, + "Leechers": 0, + "Snatched": 388 + }, + "322850": { + "ID": "322850", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Africa", + "Scene": "0", + "ReleaseTitle": "Prealsoft - GMMN Casablanca Mohammed V Airport v1.1.1 - DLC", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "303789985", + "Time": "2020-11-07 10:00:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 83, + "Leechers": 0, + "Snatched": 374 + }, + "479872": { + "ID": "479872", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "SamScene – Macau City & VMMC Macau International Airport v2.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "781078918", + "Time": "2022-07-24 19:32:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 7 + }, + "479580": { + "ID": "479580", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Siberian Scenery Development – URWW Volgograd International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "34208852", + "Time": "2022-07-23 05:25:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 9 + }, + "477412": { + "ID": "477412", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "WF Scenery Studio – ZBAA Beijing Capital International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1743071919", + "Time": "2022-07-14 02:04:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 13 + }, + "477182": { + "ID": "477182", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Catch Star Simulation – ZBZL Zhalantun Chengjisihan \/ Genghis Khan Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "212184716", + "Time": "2022-07-13 06:43:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 8 + }, + "476253": { + "ID": "476253", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Drzewiecki Design – RJAA Narita International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2898150305", + "Time": "2022-07-08 00:35:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 14 + }, + "476057": { + "ID": "476057", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Zhouke Scenery Studio – ZBMZ Manzhouli Xijiao Airport & Manzhouli City v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "374550163", + "Time": "2022-07-07 00:49:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 9 + }, + "476056": { + "ID": "476056", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "WF Scenery Studio – ZSPD Shanghai Pudong International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1379071732", + "Time": "2022-07-07 00:49:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 14 + }, + "475883": { + "ID": "475883", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "MFSG – RJNT Toyama Airport v1.0.0 (Update 1)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "16452625", + "Time": "2022-07-06 13:50:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 5 + }, + "475882": { + "ID": "475882", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "MFSG – WBGS Sibu Airport v1.0.0 (Update 1)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "11920030", + "Time": "2022-07-06 13:50:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 5 + }, + "474325": { + "ID": "474325", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "DominicDesignTeam – VVPQ Phu Quoc International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1000779546", + "Time": "2022-06-30 04:11:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 10 + }, + "474324": { + "ID": "474324", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Suroboyo Simulation – WARA Abdul Rachman Saleh Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "123762986", + "Time": "2022-06-30 04:11:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 8 + }, + "473807": { + "ID": "473807", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Orbx – VTSP Phuket International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "564783469", + "Time": "2022-06-28 02:39:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 8 + }, + "473788": { + "ID": "473788", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Suroboyo Simulation – WILL Radin Inten II Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "142498714", + "Time": "2022-06-28 02:28:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 7 + }, + "471956": { + "ID": "471956", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Suroboyo Simulation – WARR Juanda International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "179381452", + "Time": "2022-06-15 23:19:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 11 + }, + "471070": { + "ID": "471070", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "CloudSurf Asia Simulations – RPLL Ninoy Aquino International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "540436450", + "Time": "2022-06-11 01:40:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 13 + }, + "470902": { + "ID": "470902", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Zhouke Scenery Studio – ZGHA Changsha Huanghua International Airport v3.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "185913636", + "Time": "2022-06-09 19:54:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 13 + }, + "469772": { + "ID": "469772", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Catch Star Simulation – ZYYJ Yanji Chaoyangchuan International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "282950688", + "Time": "2022-06-04 18:32:27", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 11 + }, + "469771": { + "ID": "469771", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "DominicDesignTeam – VTBD Don Mueang \/ Bangkok International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "495089724", + "Time": "2022-06-04 18:32:01", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 13 + }, + "468380": { + "ID": "468380", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "ST Simulations – LTAF Adana Sakirpasa Airport v1.1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "296475753", + "Time": "2022-05-31 22:19:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 9 + }, + "467066": { + "ID": "467066", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "DominicDesignTeam – ZUUU Chengdu Shuangliu International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2781445415", + "Time": "2022-05-26 04:44:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 16 + }, + "466851": { + "ID": "466851", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "DominicDesignTeam – RJCC New Chitose Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1539897365", + "Time": "2022-05-25 05:33:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 16 + }, + "466769": { + "ID": "466769", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "DominicDesignTeam – VVTS Tan Son Nhat International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "952749414", + "Time": "2022-05-25 03:27:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 15 + }, + "466433": { + "ID": "466433", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Project MAX – WAMM Sam Ratulangi International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "21496015", + "Time": "2022-05-24 09:02:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 11 + }, + "466431": { + "ID": "466431", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "DominicDesignTeam – RKPC Jeju International Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2636629318", + "Time": "2022-05-24 09:01:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 15 + }, + "466428": { + "ID": "466428", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Binersim – WAJJ Sentani \/ Dortheys Hiyo Eluay International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "895595183", + "Time": "2022-05-24 09:00:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 11 + }, + "465815": { + "ID": "465815", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "The Secret Studio – WBKK Kota Kinabalu International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "193925753", + "Time": "2022-05-21 01:09:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 8 + }, + "465363": { + "ID": "465363", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Binersim – WITT Sultan Iskandar Muda International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "290688939", + "Time": "2022-05-18 21:41:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 8 + }, + "461501": { + "ID": "461501", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Asian Airports – RKSS Gimpo Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "119704374", + "Time": "2022-05-04 03:46:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 16 + }, + "461497": { + "ID": "461497", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "SamScene – RKPK Gimhae International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1074360683", + "Time": "2022-05-04 03:43:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 24 + }, + "461248": { + "ID": "461248", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "SceneryTR Design – LTAC Ankara Esenboga Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "922608806", + "Time": "2022-05-01 04:57:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 15 + }, + "461081": { + "ID": "461081", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "SamScene – Wuhan City & ZHHH Wuhan Tianhe International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1347312143", + "Time": "2022-04-30 04:07:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 25 + }, + "459982": { + "ID": "459982", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "SamScene – Guangzhou City & ZGGG Guangzhou Baiyun International Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1492751263", + "Time": "2022-04-23 05:14:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 20 + }, + "458289": { + "ID": "458289", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "GATE15Scenery – RJOR Tottori Airport v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "68322630", + "Time": "2022-04-13 06:41:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 20 + }, + "458286": { + "ID": "458286", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "SimArc – OPIS Islamabad International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "183971760", + "Time": "2022-04-13 06:40:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 16 + }, + "457636": { + "ID": "457636", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "ACO Design Studio – RCKH Kaohsiung International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "329901900", + "Time": "2022-04-10 04:35:03", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 19 + }, + "456964": { + "ID": "456964", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "MFSG – WBSB Brunei International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "24424798", + "Time": "2022-04-06 12:30:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 23 + }, + "455753": { + "ID": "455753", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "DMD Developers – URKA Anapa Airport v1.0.0 (Fix)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "362590345", + "Time": "2022-03-31 08:18:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 21 + }, + "455740": { + "ID": "455740", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Fly 2 High – RJFM Miyazaki Bougainvillea Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1612950283", + "Time": "2022-03-31 08:11:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 27 + }, + "454872": { + "ID": "454872", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Russian Digital Simulations – URKK Krasnodar International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "177917198", + "Time": "2022-03-27 21:43:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 20 + }, + "454869": { + "ID": "454869", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Model Instruments – VHHX Kai Tak Airport v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "213975751", + "Time": "2022-03-27 21:41:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 23 + }, + "453777": { + "ID": "453777", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "TechnoBrain – RJBB Kansai International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "203872374", + "Time": "2022-03-24 07:05:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 25 + }, + "453773": { + "ID": "453773", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "GATE15Scenery – RJBD Nanki–Shirahama Airport v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "182057715", + "Time": "2022-03-24 07:03:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 24 + }, + "444811": { + "ID": "444811", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Alkee Creations – VEPT Jay Prakash Narayan \/ Patna International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "237591895", + "Time": "2022-03-15 09:19:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 23 + }, + "444056": { + "ID": "444056", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "DominicDesignTeam – RKPK Gimhae International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2103283076", + "Time": "2022-03-10 03:09:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 25 + }, + "443104": { + "ID": "443104", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "The Secret Studio – WMKK Kuala Lumpur International Airport v2.2.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "181806272", + "Time": "2022-03-05 20:06:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 22 + }, + "442561": { + "ID": "442561", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "ACO Design Studio – RCSS Taipei Songshan Airport v1.0.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "459288540", + "Time": "2022-03-03 00:33:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 33 + }, + "442054": { + "ID": "442054", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "RouteAnn–Studio – ZLDH Dunhuang Mogao International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2114496415", + "Time": "2022-02-28 04:03:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 31 + }, + "439519": { + "ID": "439519", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Double T – VTBS Suvarnabhumi Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "263181983", + "Time": "2022-02-22 02:01:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 32 + }, + "429117": { + "ID": "429117", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "DominicDesignTeam – RJBB Kansai International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3583935779", + "Time": "2022-02-11 15:51:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 34 + }, + "424425": { + "ID": "424425", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "BDOaviation – VTSP Phuket International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "513998678", + "Time": "2022-01-14 02:01:24", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 38 + }, + "422570": { + "ID": "422570", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "SiamFlight – VTCL Lampang Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "26138358", + "Time": "2022-01-05 22:34:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 42 + }, + "421966": { + "ID": "421966", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "DominicDesignTeam – VVBM Buon Ma Thuot Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "253075803", + "Time": "2022-01-03 00:10:03", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 35 + }, + "417507": { + "ID": "417507", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "WF Scenery Studio – VHHH Hong Kong International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1044140538", + "Time": "2021-12-16 10:05:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 72 + }, + "417209": { + "ID": "417209", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "MFSG – WBKK Kota Kinabalu International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "19653907", + "Time": "2021-12-13 22:52:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 66 + }, + "417207": { + "ID": "417207", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "SamScene – ZKPY Pyongyang International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2745469287", + "Time": "2021-12-13 22:52:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 23, + "Leechers": 0, + "Snatched": 68 + }, + "417093": { + "ID": "417093", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "DominicDesignTeam – VVNB Noi Bai International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1089510491", + "Time": "2021-12-12 23:00:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 76 + }, + "417039": { + "ID": "417039", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "MXI Design - LTFE Milas-Bodrum Airport v0.5.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2033742733", + "Time": "2021-12-12 15:32:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 76 + }, + "416319": { + "ID": "416319", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "WDF Avia – VTSM Samui International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1121763849", + "Time": "2021-12-07 00:56:01", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 83 + }, + "415566": { + "ID": "415566", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "SamScene – Hong Kong City Times v1.4.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "490683661", + "Time": "2021-12-02 10:15:27", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 25, + "Leechers": 0, + "Snatched": 80 + }, + "415562": { + "ID": "415562", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "DominicDesignTeam – VVDN Da Nang International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "887268555", + "Time": "2021-12-02 10:14:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 79 + }, + "415236": { + "ID": "415236", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "S–Design – VRMM Velana International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "760308443", + "Time": "2021-11-29 00:52:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 25, + "Leechers": 0, + "Snatched": 76 + }, + "413073": { + "ID": "413073", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Double T - RJOA Hiroshima Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "193681180", + "Time": "2021-11-15 05:17:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 92 + }, + "411735": { + "ID": "411735", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "SamScene – VMMC Macau International Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "837395998", + "Time": "2021-11-12 06:41:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 87 + }, + "410504": { + "ID": "410504", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "SimArc – OPFA Faisalabad International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "159144284", + "Time": "2021-11-09 07:22:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 90 + }, + "410135": { + "ID": "410135", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "DominicDesignTeam – RJGG Chubu Centrair International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "864254141", + "Time": "2021-11-07 23:08:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 92 + }, + "408112": { + "ID": "408112", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – RJFC Yakushima Airport v1.0.0 (New Build)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "171663255", + "Time": "2021-10-29 22:12:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 94 + }, + "407745": { + "ID": "407745", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "MSK productions – OPGD Gwadar International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "16154612", + "Time": "2021-10-27 00:51:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 96 + }, + "407039": { + "ID": "407039", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Double T – RCTP Taoyuan International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2818085920", + "Time": "2021-10-22 22:04:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 108 + }, + "406680": { + "ID": "406680", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Aerosoft – WATO Komodo Airport v1.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1103420161", + "Time": "2021-10-22 08:40:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 109 + }, + "405694": { + "ID": "405694", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "HomaSim – OIIE Tehran Imam Khomeini International Airport v1.1.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2405857880", + "Time": "2021-10-15 00:10:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 120 + }, + "405670": { + "ID": "405670", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "HomaSim – OIAW Ahvaz International Airport v1.0.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "868099151", + "Time": "2021-10-14 22:14:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 107 + }, + "402878": { + "ID": "402878", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Double T – RKSS Gimpo Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "861628890", + "Time": "2021-09-24 08:44:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 125 + }, + "398878": { + "ID": "398878", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "MFSG – WBTM \/ WBGT Tanjung Manis Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3973585", + "Time": "2021-09-01 21:39:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 46, + "Leechers": 0, + "Snatched": 147 + }, + "398520": { + "ID": "398520", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Aerosoft – WADD Ngurah Rai International Airport \/ Bali v1.2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2324391710", + "Time": "2021-09-01 06:42:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 42, + "Leechers": 0, + "Snatched": 150 + }, + "397980": { + "ID": "397980", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "RouteAnn–Studio – ZSOF Hefei Xinqiao International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "810286248", + "Time": "2021-08-31 03:27:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 40, + "Leechers": 0, + "Snatched": 136 + }, + "397623": { + "ID": "397623", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – RJKA Amami Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "623371237", + "Time": "2021-08-27 23:25:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 134 + }, + "397316": { + "ID": "397316", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Airwil Sceneries – RPMG Dipolog Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "34646985", + "Time": "2021-08-26 16:00:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 38, + "Leechers": 0, + "Snatched": 129 + }, + "397314": { + "ID": "397314", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "MFSG – WMKP Penang International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "15614857", + "Time": "2021-08-26 15:58:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 46, + "Leechers": 0, + "Snatched": 147 + }, + "391546": { + "ID": "391546", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "MFSG - RJFS Saga Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "14913693", + "Time": "2021-07-31 05:59:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 52, + "Leechers": 0, + "Snatched": 175 + }, + "389029": { + "ID": "389029", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "CloudSurf Asia Simulations – WSSS Singapore Changi Airport v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "439354055", + "Time": "2021-07-21 06:28:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 49, + "Leechers": 0, + "Snatched": 163 + }, + "388602": { + "ID": "388602", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Double T – ZGSG Shenzhen Bao’an International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1102525404", + "Time": "2021-07-20 06:50:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 50, + "Leechers": 0, + "Snatched": 186 + }, + "386083": { + "ID": "386083", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "MFSG – WMKL Langkawi International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "16072097", + "Time": "2021-07-10 09:01:22", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 58, + "Leechers": 0, + "Snatched": 192 + }, + "382131": { + "ID": "382131", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "SamScene – RJFF Fukuoka Airport \/ Japan Fukuoka Wow v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "277907030", + "Time": "2021-06-26 07:16:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 52, + "Leechers": 0, + "Snatched": 179 + }, + "381329": { + "ID": "381329", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – RJFC Yakushima Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "171652601", + "Time": "2021-06-23 23:20:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 54, + "Leechers": 0, + "Snatched": 181 + }, + "381307": { + "ID": "381307", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "JustSim – UUWW Vnukovo International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2090616832", + "Time": "2021-06-23 22:47:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 59, + "Leechers": 0, + "Snatched": 200 + }, + "381033": { + "ID": "381033", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Metropolitan Airport Development Brothers – RJOO Osaka International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "609195333", + "Time": "2021-06-23 11:42:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 49, + "Leechers": 0, + "Snatched": 180 + }, + "381009": { + "ID": "381009", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Metropolitan Airport Development Brothers – RJTF Chofu Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "348258945", + "Time": "2021-06-23 11:05:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 53, + "Leechers": 0, + "Snatched": 183 + }, + "356464": { + "ID": "356464", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "RUSD - UHWW The East Gate - Vladivostok International Airport v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "686105311", + "Time": "2021-03-14 09:44:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 71, + "Leechers": 0, + "Snatched": 285 + }, + "356421": { + "ID": "356421", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Aerowulf - USSS\/UUSK Airports - Yekaterinburg \/ Aramil Scenery v0.6.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1657831668", + "Time": "2021-03-13 23:08:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 78, + "Leechers": 0, + "Snatched": 316 + }, + "355293": { + "ID": "355293", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Metropolitan Airport Development Brothers - RJTF Chofu Airport, Japan v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "309749579", + "Time": "2021-03-06 13:13:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 76, + "Leechers": 0, + "Snatched": 301 + }, + "354110": { + "ID": "354110", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "Scenery Creation - UUBC Kaluga International Airport Grabtsevo Tsiolkovsky Russia v1.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "736347959", + "Time": "2021-02-28 19:30:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 66, + "Leechers": 0, + "Snatched": 288 + }, + "331049": { + "ID": "331049", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Asia", + "Scene": "0", + "ReleaseTitle": "BDOaviation - RPMD Davao Francisco Bangoy Intl Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "411564935", + "Time": "2020-12-02 11:23:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 83, + "Leechers": 0, + "Snatched": 378 + }, + "478778": { + "ID": "478778", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Pearl Simulations – AGGN Nusatupe Airport \/ Ghizo Island v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "368994349", + "Time": "2022-07-20 09:51:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 5 + }, + "475887": { + "ID": "475887", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Orbx – YBMK Mackay Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "113067838", + "Time": "2022-07-06 13:52:30", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 7 + }, + "475881": { + "ID": "475881", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "MFSG – YPPH Perth International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "26809551", + "Time": "2022-07-06 13:49:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 5 + }, + "468490": { + "ID": "468490", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "NZA Simulations – YCBG Cambridge Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "685881349", + "Time": "2022-06-01 11:24:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 9 + }, + "466767": { + "ID": "466767", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "NZA Simulations – NZMC Mount Cook Airport & NZGT Glentanner Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1562374994", + "Time": "2022-05-25 03:23:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 16 + }, + "466427": { + "ID": "466427", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "AUscene – Reefworld – Great Barrier Reef v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "482297165", + "Time": "2022-05-24 08:59:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "463003": { + "ID": "463003", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "MK–STUDIOS – EIDW Dublin Airport v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "443690943", + "Time": "2022-05-13 05:52:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 13 + }, + "462062": { + "ID": "462062", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Impulse Simulations – YSBK Bankstown Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1463260952", + "Time": "2022-05-08 05:56:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 18 + }, + "459983": { + "ID": "459983", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "MSX Creations – YKAT Katoomba Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "47386452", + "Time": "2022-04-23 05:14:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 19 + }, + "459580": { + "ID": "459580", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Flightbeam Studios – NZWN Wellington International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1426322480", + "Time": "2022-04-21 04:02:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 29 + }, + "458288": { + "ID": "458288", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Axonos – YPPH Perth International Airport v1.0.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "795574299", + "Time": "2022-04-13 06:41:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 21 + }, + "456972": { + "ID": "456972", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "FlyTampa – YSSY Kingsford Smith International Airport v1.7.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "847180869", + "Time": "2022-04-06 12:37:03", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 20 + }, + "444829": { + "ID": "444829", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Orbx – YMEN Essendon Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2406754663", + "Time": "2022-03-15 09:32:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 26 + }, + "442052": { + "ID": "442052", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Impulse Simulations – YCFS Coffs Harbour Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2568179645", + "Time": "2022-02-28 04:02:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 32 + }, + "430494": { + "ID": "430494", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Pushback Studio – YCAB Caboolture Airport v1.1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "711405582", + "Time": "2022-02-15 01:59:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 32 + }, + "430492": { + "ID": "430492", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "AUscene – YBNA Ballina Byron Gateway Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2130551689", + "Time": "2022-02-15 01:59:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 35 + }, + "430488": { + "ID": "430488", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "AUscene – YAYE Ayers Rock Airport v1.3.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1471566128", + "Time": "2022-02-15 01:58:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 35 + }, + "429110": { + "ID": "429110", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "AUscene – YSPT Southport Airport v2.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1036472098", + "Time": "2022-02-11 15:46:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 34 + }, + "429105": { + "ID": "429105", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "AUscene – YPPF Parafield Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "695535200", + "Time": "2022-02-11 15:43:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 32 + }, + "428034": { + "ID": "428034", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "AUscene – YLHI Lord Howe Island Airport v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3504483773", + "Time": "2022-02-05 03:16:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 25 + }, + "428030": { + "ID": "428030", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "VueloSimple – NTTB Bora Bora \/ Motu Mute Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "18149118", + "Time": "2022-02-05 03:14:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 26 + }, + "427899": { + "ID": "427899", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "MFSG – YPKA Karratha Airport v1.0.0 (Reduced Size)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "10968337", + "Time": "2022-02-03 22:42:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 21, + "Leechers": 0, + "Snatched": 37 + }, + "425777": { + "ID": "425777", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Flightbeam Studios – NZAA Auckland International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2336766796", + "Time": "2022-01-24 03:44:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 45 + }, + "422398": { + "ID": "422398", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Shunt Scenery – YBSU Sunshine Coast Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "698521307", + "Time": "2022-01-05 02:08:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 38 + }, + "422397": { + "ID": "422397", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Shunt Scenery – YCDR Caloundra Airport v2.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "200411231", + "Time": "2022-01-05 02:02:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 42 + }, + "421964": { + "ID": "421964", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "NZA Simulations – YMHB Hobart Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2742218270", + "Time": "2022-01-03 00:09:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 40 + }, + "407219": { + "ID": "407219", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Impulse Simulations – YPAD Adelaide International Airport v1.2.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1719396690", + "Time": "2021-10-23 14:11:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 110 + }, + "406128": { + "ID": "406128", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Godzone Virtual Flight – NZTI Taieri Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "489846534", + "Time": "2021-10-19 00:24:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 98 + }, + "404485": { + "ID": "404485", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "NZA Simulations – NZNS Nelson Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2793804377", + "Time": "2021-10-06 03:59:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 123 + }, + "404023": { + "ID": "404023", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "iniBuilds – NZQN Queenstown Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1747447239", + "Time": "2021-10-02 14:56:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 132 + }, + "403380": { + "ID": "403380", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Orbx – YBBN Brisbane International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1040399081", + "Time": "2021-09-28 00:54:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 122 + }, + "398879": { + "ID": "398879", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – SCIP Mataveri International Airport v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "279393545", + "Time": "2021-09-01 21:40:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 39, + "Leechers": 0, + "Snatched": 126 + }, + "390575": { + "ID": "390575", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "MFSG - YPKA Karratha Airport v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2307815894", + "Time": "2021-07-26 21:08:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 44, + "Leechers": 0, + "Snatched": 175 + }, + "384529": { + "ID": "384529", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Northern Sky Studio – PHMK Molokai Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1280758942", + "Time": "2021-07-05 03:55:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 50, + "Leechers": 0, + "Snatched": 190 + }, + "381324": { + "ID": "381324", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Terrapearl Studios – PHMK Molokai Airport v1.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "765803479", + "Time": "2021-06-23 23:12:22", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 51, + "Leechers": 0, + "Snatched": 181 + }, + "381014": { + "ID": "381014", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Taburet – TVSU Union Island Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "15901384", + "Time": "2021-06-23 11:17:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 52, + "Leechers": 0, + "Snatched": 198 + }, + "354112": { + "ID": "354112", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Binersim - Halim Perdanakusuma Airport v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "602486227", + "Time": "2021-02-28 19:34:27", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 70, + "Leechers": 0, + "Snatched": 296 + }, + "344096": { + "ID": "344096", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "ORBX - YSSY Sydney International Airport v1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "929065827", + "Time": "2021-01-26 08:38:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 84, + "Leechers": 0, + "Snatched": 342 + }, + "343229": { + "ID": "343229", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Australia\/Pacific", + "Scene": "0", + "ReleaseTitle": "Auscene1 - YSPT Gold Coast Southport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "291658018", + "Time": "2021-01-22 13:34:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 86, + "Leechers": 0, + "Snatched": 356 + }, + "479781": { + "ID": "479781", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – EGNT Newcastle Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1898707387", + "Time": "2022-07-24 07:20:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 13 + }, + "479582": { + "ID": "479582", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JetStream Designs – LFPO Paris Orly Airport v1.2.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1188710326", + "Time": "2022-07-23 05:26:03", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 12 + }, + "479579": { + "ID": "479579", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Pearl Simulations – BGMQ Maniitsoq Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "175477135", + "Time": "2022-07-23 05:24:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 8 + }, + "479577": { + "ID": "479577", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MK–STUDIOS – LIRF Rome–Fiumicino International Airport v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "741763483", + "Time": "2022-07-23 05:24:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 9 + }, + "479576": { + "ID": "479576", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "RDPresets – LIRN Naples International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1716377591", + "Time": "2022-07-23 05:23:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 13 + }, + "478786": { + "ID": "478786", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Digital Design – LFLL Lyon–Saint Exupery Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2720622554", + "Time": "2022-07-20 09:57:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 10 + }, + "478785": { + "ID": "478785", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "PILOT’S FSG – LEAL Alicante–Elche Miguel Hernandez Airport v1.5.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1886442944", + "Time": "2022-07-20 09:56:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 10 + }, + "478780": { + "ID": "478780", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Pearl Simulations – NTTM Moorea Temae Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "965212486", + "Time": "2022-07-20 09:52:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 7 + }, + "478779": { + "ID": "478779", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Pearl Simulations – NTTH Huahine – Fare Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "436569157", + "Time": "2022-07-20 09:52:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 5 + }, + "478548": { + "ID": "478548", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JetStream Designs – LFRS Nantes Atlantique International Airport v1.2.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "133369180", + "Time": "2022-07-19 01:03:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 9 + }, + "478218": { + "ID": "478218", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Salvuz – LIPX Verona Villafranca Airport v1.3.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "319809639", + "Time": "2022-07-17 07:49:03", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 9 + }, + "478216": { + "ID": "478216", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MK–STUDIOS – GCFV Fuerteventura Airport v1.0.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "861056717", + "Time": "2022-07-17 07:47:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 10 + }, + "478215": { + "ID": "478215", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MK–STUDIOS – GCTS Tenerife South Airport & GCXO Tenerife North Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2052084554", + "Time": "2022-07-17 07:47:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 12 + }, + "478212": { + "ID": "478212", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "SLH Sim Designs – TQPF Clayton J. Lloyd International Airport v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "532524853", + "Time": "2022-07-17 07:45:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 10 + }, + "478211": { + "ID": "478211", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Troglodytus Design – LOAV Voeslau Airport v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "523098004", + "Time": "2022-07-17 07:44:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 11 + }, + "478210": { + "ID": "478210", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JetStream Designs – LICG Pantelleria Airport v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "114696171", + "Time": "2022-07-17 07:44:03", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 9 + }, + "478209": { + "ID": "478209", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JetStream Designs – LICJ Falcone Borsellino \/ Palermo Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "508008387", + "Time": "2022-07-17 07:43:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 12 + }, + "477413": { + "ID": "477413", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MK–STUDIOS – LIRF Rome–Fiumicino International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "242294209", + "Time": "2022-07-14 02:04:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 9 + }, + "476889": { + "ID": "476889", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "SLH Sim Designs – TFFA La Desirade Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "67773931", + "Time": "2022-07-11 07:40:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 4 + }, + "475891": { + "ID": "475891", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – LGSA Chania International Airport v1.0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "188194071", + "Time": "2022-07-06 13:54:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 8 + }, + "475886": { + "ID": "475886", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FSXcenery – OYAA Aden International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "31108227", + "Time": "2022-07-06 13:52:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 7 + }, + "475885": { + "ID": "475885", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MFSG – OERK King Khalid International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "26122208", + "Time": "2022-07-06 13:51:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 5 + }, + "475884": { + "ID": "475884", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MFSG – OJAI Queen Alia International Airport v1.0.0 (Update 2)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "14607804", + "Time": "2022-07-06 13:51:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 6 + }, + "475879": { + "ID": "475879", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LEVX Vigo Airport v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "393949541", + "Time": "2022-07-06 13:48:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 8 + }, + "475476": { + "ID": "475476", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JetStream Designs – LICG Pantelleria Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "114696048", + "Time": "2022-07-04 07:03:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 7 + }, + "475472": { + "ID": "475472", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JetStream Designs – LICJ Falcone Borsellino \/ Palermo Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "508007441", + "Time": "2022-07-04 06:58:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 8 + }, + "475471": { + "ID": "475471", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JetStream Designs – LICD Lampedusa Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "988136780", + "Time": "2022-07-04 06:57:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 9 + }, + "474547": { + "ID": "474547", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Red Wing Simulations – LSHU Geneva University Hospital Heliport \/ HUG v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "71392367", + "Time": "2022-07-01 01:10:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 9 + }, + "474546": { + "ID": "474546", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Red Wing Simulations – LSHS Sion \/ Du Valais Hospital Heliport v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "130537205", + "Time": "2022-07-01 01:10:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 9 + }, + "474545": { + "ID": "474545", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "SPINOZA – LSGL Lausanne Airport v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "395554240", + "Time": "2022-07-01 01:09:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 9 + }, + "474544": { + "ID": "474544", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aviation–Sim–Design – EDWE Emden Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1108349228", + "Time": "2022-07-01 01:09:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 15 + }, + "474542": { + "ID": "474542", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LIPZ Venice Marco Polo Airport v2.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "452772814", + "Time": "2022-07-01 01:08:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 9 + }, + "474326": { + "ID": "474326", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "HomaSim – OIII Mehrabad International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2873541208", + "Time": "2022-06-30 04:11:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 14 + }, + "474019": { + "ID": "474019", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Sim Wings – GCLP Gran Canaria Airport v1.0.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1060140520", + "Time": "2022-06-28 22:57:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 11 + }, + "473800": { + "ID": "473800", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Sim Wings – GCLA La Palma Airport v1.1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "576154703", + "Time": "2022-06-28 02:35:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 8 + }, + "473799": { + "ID": "473799", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – ENVA Trondheim–Vaernes Airport v1.1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1340278893", + "Time": "2022-06-28 02:34:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "473798": { + "ID": "473798", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – EDDK Cologne Bonn Airport v1.0.8.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1369901272", + "Time": "2022-06-28 02:34:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "473797": { + "ID": "473797", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – LLBG Ben Gurion Airport v1.1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3141120976", + "Time": "2022-06-28 02:33:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "473796": { + "ID": "473796", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – LDZA Zagreb Franjo Tudman Airport v2.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "590576185", + "Time": "2022-06-28 02:33:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 8 + }, + "473795": { + "ID": "473795", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – EBBR Brussels Airport v1.0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1813639124", + "Time": "2022-06-28 02:32:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "473785": { + "ID": "473785", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Red Wing Simulations – LSGG Geneva Airport v0.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1393686255", + "Time": "2022-06-28 02:26:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "473145": { + "ID": "473145", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Just Flight – GCRR Cesar Manrique–Lanzarote Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "470498974", + "Time": "2022-06-23 04:05:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 13 + }, + "473043": { + "ID": "473043", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MXI Design – LGTS Thessaloniki Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "878704639", + "Time": "2022-06-22 09:04:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 11 + }, + "473042": { + "ID": "473042", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MK–STUDIOS – LESO San Sebastian Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1190186568", + "Time": "2022-06-22 09:04:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 17 + }, + "472761": { + "ID": "472761", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "VueloSimple – MWCR Owen Roberts International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "101329390", + "Time": "2022-06-20 05:53:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 11 + }, + "472760": { + "ID": "472760", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "RWY26 Simulations – MWCR Owen Roberts International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "171285995", + "Time": "2022-06-20 05:53:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 10 + }, + "471958": { + "ID": "471958", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Fly 2 High – LBSF Sofia Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2579251587", + "Time": "2022-06-15 23:24:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 16 + }, + "471686": { + "ID": "471686", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ST Simulations – LJBO Bovec Airport v1.1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "328044589", + "Time": "2022-06-14 10:20:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 11 + }, + "471684": { + "ID": "471684", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Drzewiecki Design – EPRZ Rzeszow–Jasionka Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1699948162", + "Time": "2022-06-14 10:18:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 13 + }, + "471395": { + "ID": "471395", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "PILOT’S FSG – LEAL Alicante–Elche Miguel Hernandez Airport v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1886441266", + "Time": "2022-06-12 10:43:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 21 + }, + "470900": { + "ID": "470900", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – EDQ1 Kronach Airport v1.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "222663107", + "Time": "2022-06-09 19:53:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 14 + }, + "470891": { + "ID": "470891", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – LYPG Podgorica Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "372838536", + "Time": "2022-06-09 19:48:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 14 + }, + "470890": { + "ID": "470890", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Pilot Experience Sim – LFKJ Ajaccio Napoleon Bonaparte Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "840730889", + "Time": "2022-06-09 19:48:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 14 + }, + "469770": { + "ID": "469770", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Flightbeam Studios – LFBO Toulouse–Blagnac Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "846847668", + "Time": "2022-06-04 18:31:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 13 + }, + "469769": { + "ID": "469769", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MK–STUDIOS – LPPT Lisbon \/ Humberto Delgado Airport v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "686973764", + "Time": "2022-06-04 18:31:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 13 + }, + "469768": { + "ID": "469768", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Sim Wings – GCTS Tenerife South \/ Tenerife Sur Airport v1.2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "967825538", + "Time": "2022-06-04 18:30:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 14 + }, + "468489": { + "ID": "468489", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FlyLogic – LSPV & LSPW Wangen Lachen Airports v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "42199448", + "Time": "2022-06-01 11:24:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 11 + }, + "468118": { + "ID": "468118", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FeelThere – EDDF Frankfurt Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1350611509", + "Time": "2022-05-30 21:05:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 17 + }, + "467262": { + "ID": "467262", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FSDreamTeam – LFNC Mont–Dauphin – Saint–Crepin Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "259121824", + "Time": "2022-05-27 00:35:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 11 + }, + "466761": { + "ID": "466761", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "AmSim – LIEE Cagliari Elmas Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1050263344", + "Time": "2022-05-25 03:18:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 14 + }, + "466759": { + "ID": "466759", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "UK2000 Scenery – EGJJ Jersey Airport v1.0.7", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "44070732", + "Time": "2022-05-25 03:18:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 10 + }, + "465814": { + "ID": "465814", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "AG Sim – LSZP Biel–Kappelen Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "111775184", + "Time": "2022-05-21 01:08:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 10 + }, + "465813": { + "ID": "465813", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "AG Sim – LSPV Wangen–Lachen Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "75446283", + "Time": "2022-05-21 01:07:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 11 + }, + "465680": { + "ID": "465680", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Fly 2 High – LFQA Reims – Prunay Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "696865793", + "Time": "2022-05-20 00:52:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 9 + }, + "465679": { + "ID": "465679", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "S–Design – HESH Sharm El Sheikh International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4279944713", + "Time": "2022-05-20 00:51:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 15 + }, + "465678": { + "ID": "465678", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "SLH Sim Designs – TFFR Pointe–a–Pitre Le Raizet Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "388195221", + "Time": "2022-05-20 00:51:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 8 + }, + "464978": { + "ID": "464978", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MXI Design – LSZG Grenchen Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "832536285", + "Time": "2022-05-17 10:25:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 11 + }, + "464977": { + "ID": "464977", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FlyLogic – LSZK Speck–Fehraltorf Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "64535814", + "Time": "2022-05-17 10:24:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "464976": { + "ID": "464976", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Red Wing Simulations – LSGE Fribourg–Ecuvillens Airport v0.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "310775532", + "Time": "2022-05-17 10:24:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 10 + }, + "464975": { + "ID": "464975", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "HawkSim – LSTO Motiers Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "299655892", + "Time": "2022-05-17 10:23:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 11 + }, + "464974": { + "ID": "464974", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "HawkSim – LSZJ Courtelary Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "227067138", + "Time": "2022-05-17 10:23:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 11 + }, + "464973": { + "ID": "464973", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Taburet – LSTZ Zweisimmen Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "38596949", + "Time": "2022-05-17 10:22:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 11 + }, + "464971": { + "ID": "464971", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "RDPresets – EHRD Rotterdam The Hague Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "756102732", + "Time": "2022-05-17 10:22:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 9 + }, + "463947": { + "ID": "463947", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Gaya Simulations – LIRQ Florence Airport v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "756865231", + "Time": "2022-05-14 23:13:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 12 + }, + "463946": { + "ID": "463946", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "PerfectSoft Studio – GMMX Marrakesh Menara Airport v1.0.0 (Update 1)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1066331629", + "Time": "2022-05-14 23:13:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 12 + }, + "463945": { + "ID": "463945", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FeelThere – OMDB Dubai International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "792176376", + "Time": "2022-05-14 23:12:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "463435": { + "ID": "463435", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – EGHE St. Mary \/ Isles of Scilly Airport v1.1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "340604914", + "Time": "2022-05-14 09:26:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 11 + }, + "463434": { + "ID": "463434", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Drzewiecki Design – EPMO Warsaw Modlin Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1168126207", + "Time": "2022-05-14 09:26:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 15 + }, + "463004": { + "ID": "463004", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Sierrasim Simulation – NWWW La Tontouta International Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "598712731", + "Time": "2022-05-13 05:53:24", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 10 + }, + "463002": { + "ID": "463002", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Macco Simulations – EGBB Birmingham Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "683908560", + "Time": "2022-05-13 05:52:24", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 11 + }, + "462921": { + "ID": "462921", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MK–STUDIOS – EICK Cork Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1094073711", + "Time": "2022-05-12 10:58:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 16 + }, + "462567": { + "ID": "462567", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ST Simulations – LSTS St. Stephan Airport v1.1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "277871030", + "Time": "2022-05-10 10:29:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 10 + }, + "462565": { + "ID": "462565", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JustSim – LTFE Milas–Bodrum Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1265207411", + "Time": "2022-05-10 10:28:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 16 + }, + "462063": { + "ID": "462063", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Burning Blue Design – EGLF Farnborough Airport v1.4.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "566807662", + "Time": "2022-05-08 05:57:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 12 + }, + "462061": { + "ID": "462061", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "AG Sim – LSZE Bad Ragaz Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "393879755", + "Time": "2022-05-08 05:54:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 12 + }, + "461612": { + "ID": "461612", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "iniBuilds – EGLL Heathrow Airport v1.2.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3730001337", + "Time": "2022-05-05 05:31:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 26 + }, + "461611": { + "ID": "461611", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Drzewiecki Design – EPBY Bydgoszcz Ignacy Jan Paderewski Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "976466175", + "Time": "2022-05-05 05:30:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 18 + }, + "461609": { + "ID": "461609", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "NKSim – EVLA Liepaja International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "722950504", + "Time": "2022-05-05 05:30:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 14 + }, + "461500": { + "ID": "461500", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "AG Sim – LSMF \/ LSZM Mollis Airport v1.2.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "285638533", + "Time": "2022-05-04 03:45:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 16 + }, + "461499": { + "ID": "461499", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Pilot Experience Sim – BIIS Isafjoerdur Airport v1.1.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "548572747", + "Time": "2022-05-04 03:44:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 15 + }, + "461498": { + "ID": "461498", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "SuperSonic – LFMK Carcassonne Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "124439762", + "Time": "2022-05-04 03:44:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 14 + }, + "461487": { + "ID": "461487", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – LKPR Vaclav Havel Airport Prague v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1706909351", + "Time": "2022-05-04 03:34:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 25 + }, + "461482": { + "ID": "461482", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ARIMA – LIBD Bari Karol Wojtyla Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "859587474", + "Time": "2022-05-04 03:29:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 15 + }, + "461194": { + "ID": "461194", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Chudoba Design – HEMA Marsa Alam International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "156404510", + "Time": "2022-04-30 17:32:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 18 + }, + "460781": { + "ID": "460781", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FSDreamTeam – LFSB Euroairport Basel Mulhouse Freiburg v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "330604685", + "Time": "2022-04-28 05:29:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 17 + }, + "460373": { + "ID": "460373", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FSDreamTeam – LSZH Zurich Airport v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "283341812", + "Time": "2022-04-25 19:42:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 16 + }, + "460370": { + "ID": "460370", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MXI Design – LATI Tirana International Airport Nene Tereza v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1515302605", + "Time": "2022-04-25 19:37:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 21 + }, + "460369": { + "ID": "460369", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FSX3D – LFNJ Aspres–sur–Buech Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "610909573", + "Time": "2022-04-25 19:36:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 16 + }, + "459587": { + "ID": "459587", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JetStream Designs – LFRS Nantes Atlantique International Airport v1.2.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "169367268", + "Time": "2022-04-21 04:06:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 19 + }, + "459585": { + "ID": "459585", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "TropicalSim – LPLA Lajes Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "48636008", + "Time": "2022-04-21 04:05:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 18 + }, + "459581": { + "ID": "459581", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "M’M SIMULATIONS – ENTC Tromso Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3326959792", + "Time": "2022-04-21 04:02:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 24 + }, + "458816": { + "ID": "458816", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Footage Design – LEIG Igualada–Odena Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "380302873", + "Time": "2022-04-16 07:13:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 18 + }, + "458660": { + "ID": "458660", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "AmSim – LPMA Madeira \/ Cristiano Ronaldo International Airport v1.1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "880653531", + "Time": "2022-04-15 09:44:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 16 + }, + "458656": { + "ID": "458656", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "LMT Simulation – LFBR Muret–Lherm Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "225613054", + "Time": "2022-04-15 09:42:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 16 + }, + "458297": { + "ID": "458297", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "UK2000 Scenery – EGGW Luton Airport v1.2.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "155848349", + "Time": "2022-04-13 06:46:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 16 + }, + "458296": { + "ID": "458296", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "UK2000 Scenery – EGGD Bristol Airport v1.2.7", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "147361869", + "Time": "2022-04-13 06:46:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 18 + }, + "458293": { + "ID": "458293", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "VueloSimple – MBPV Providenciales International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "36078105", + "Time": "2022-04-13 06:44:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 19 + }, + "457410": { + "ID": "457410", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Footage Design – LELL Sabadell Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "212354511", + "Time": "2022-04-09 06:57:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 19 + }, + "457409": { + "ID": "457409", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "LatinVFR – LEMD Adolfo Suarez Madrid–Barajas Airport v1.0.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1118003093", + "Time": "2022-04-09 06:56:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 22 + }, + "457408": { + "ID": "457408", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Red Wing Simulations – LSXX Valais Alps Cabanes Heliport v0.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "347334391", + "Time": "2022-04-09 06:54:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 16 + }, + "457041": { + "ID": "457041", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FlyTampa – LGAV Athens International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2003483598", + "Time": "2022-04-07 05:25:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 25 + }, + "456967": { + "ID": "456967", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FlyLogic – LSZU Buttwil Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "53552396", + "Time": "2022-04-06 12:32:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 20 + }, + "455917": { + "ID": "455917", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Red Wing Simulations – LSXL Lauterbrunnen Heliport \/ Bernese Alps Cabane v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "345685529", + "Time": "2022-04-01 11:22:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 20 + }, + "455916": { + "ID": "455916", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Red Wing Simulations – LSDX Grande Dixence Dam Heliport v0.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "129446134", + "Time": "2022-04-01 11:21:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 20 + }, + "455915": { + "ID": "455915", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Red Wing Simulations – LSEZ Zermatt Heliport v0.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "177870946", + "Time": "2022-04-01 11:21:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 18 + }, + "455798": { + "ID": "455798", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – EGHC Land’s End Airport v1.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "320084315", + "Time": "2022-03-31 16:01:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 18 + }, + "455796": { + "ID": "455796", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "LMT Simulation – LFMA Aix–en–Provence Airport v1.0.6", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "215533464", + "Time": "2022-03-31 16:00:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 19 + }, + "455752": { + "ID": "455752", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – ENTO Sandefjord Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3744582433", + "Time": "2022-03-31 08:17:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 25 + }, + "455751": { + "ID": "455751", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Davor Puljevic – LDSB Brac Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "196681071", + "Time": "2022-03-31 08:17:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 20 + }, + "455750": { + "ID": "455750", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "AmSim – UGSB Alexander Kartveli Batumi International Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "841683205", + "Time": "2022-03-31 08:16:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 20 + }, + "455743": { + "ID": "455743", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FSX3D – LFMR Barcelonnette – Saint–Pons Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "766491287", + "Time": "2022-03-31 08:12:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 20 + }, + "455739": { + "ID": "455739", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Real Environment Design – NWWM Noumea Magenta Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1126345470", + "Time": "2022-03-31 08:10:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 23 + }, + "453766": { + "ID": "453766", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – LYNI Nis Constantine the Great Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "194699401", + "Time": "2022-03-24 06:59:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 20 + }, + "453765": { + "ID": "453765", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – EDDN Nuernberg Airport v1.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "349114032", + "Time": "2022-03-24 06:59:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 22 + }, + "451962": { + "ID": "451962", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "LLH Creations – LFLB Chambery Airport v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "505636707", + "Time": "2022-03-20 12:25:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 19 + }, + "451949": { + "ID": "451949", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FlyTampa – EKCH Copenhagen Kastrup International Airport v1.6.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1446292860", + "Time": "2022-03-20 12:18:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 25 + }, + "447257": { + "ID": "447257", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Drzewiecki Design – UUEE Sheremetyevo International Airport v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3087441452", + "Time": "2022-03-16 10:28:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 28 + }, + "444819": { + "ID": "444819", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Troglodytus Design – LOAV Voeslau Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "522686098", + "Time": "2022-03-15 09:25:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 21 + }, + "444817": { + "ID": "444817", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Onfinal Studio – EKEB Esbjerg Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "87242084", + "Time": "2022-03-15 09:23:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 22 + }, + "444816": { + "ID": "444816", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "TBLFscenery – LFRI La Roche–sur–Yon Les Ajoncs Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "428212426", + "Time": "2022-03-15 09:22:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 20 + }, + "444815": { + "ID": "444815", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FSX3D – LFNA Gap Tallard Airport v0.0.8", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1514978140", + "Time": "2022-03-15 09:21:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 24 + }, + "444807": { + "ID": "444807", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "SimSoft – OLBA Beirut–Rafic Hariri International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "941728", + "Time": "2022-03-15 09:16:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 28 + }, + "444058": { + "ID": "444058", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Barelli MSFS Addon – LICC Catania–Fontanarossa Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "50151226", + "Time": "2022-03-10 03:10:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 23 + }, + "444052": { + "ID": "444052", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ClearPropStudios – Bavarian Airfields 1 v1.0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4629443223", + "Time": "2022-03-10 03:07:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 25 + }, + "442560": { + "ID": "442560", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "TropicalSim – TNCA Queen Beatrix International \/ Aruba Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "76452816", + "Time": "2022-03-03 00:32:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 28 + }, + "442067": { + "ID": "442067", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Digital Design – EGGP Liverpool John Lennon Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "856876442", + "Time": "2022-02-28 04:12:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 28 + }, + "442066": { + "ID": "442066", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – ESMS Malmo Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4235518725", + "Time": "2022-02-28 04:12:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 31 + }, + "442065": { + "ID": "442065", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – ESGG Gothenburg Landvetter Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4066114664", + "Time": "2022-02-28 04:11:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 30 + }, + "442057": { + "ID": "442057", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "M’M SIMULATIONS – EDWE Emden Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1424351724", + "Time": "2022-02-28 04:07:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 29 + }, + "442053": { + "ID": "442053", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "AmSim – LICJ Falcone Borsellino \/ Palermo Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1401134876", + "Time": "2022-02-28 04:03:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 30 + }, + "442050": { + "ID": "442050", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MXI Design – LGZA Zakynthos International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "902612541", + "Time": "2022-02-28 04:01:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 29 + }, + "441990": { + "ID": "441990", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Terrainy Studios – LGSM Samos International Airport v1.2.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1918002740", + "Time": "2022-02-27 13:33:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 20 + }, + "441940": { + "ID": "441940", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – LGMK Mykonos Airport v2.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "341548599", + "Time": "2022-02-27 11:26:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 24 + }, + "440174": { + "ID": "440174", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "France VFR – VFR France North–West v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2487039108", + "Time": "2022-02-23 00:44:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 34 + }, + "440171": { + "ID": "440171", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LFKF Figari–Sud Corse Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "486921773", + "Time": "2022-02-23 00:42:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 27 + }, + "439518": { + "ID": "439518", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "PYREEGUE Dev Co. – UKBB Boryspil International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "630150287", + "Time": "2022-02-22 02:01:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 29 + }, + "438895": { + "ID": "438895", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "TDM Scenery Design – LEST Santiago–Rosalia de Castro Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1302597338", + "Time": "2022-02-21 10:32:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 32 + }, + "438880": { + "ID": "438880", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Scenic Routes – LJLJ Ljubljana Joze Pucnik Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1993111099", + "Time": "2022-02-21 10:25:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 31 + }, + "434669": { + "ID": "434669", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LICC Catania–Fontanarossa Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "610716190", + "Time": "2022-02-18 03:13:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 27 + }, + "432712": { + "ID": "432712", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MK–STUDIOS – EKVG Vagar Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "277774940", + "Time": "2022-02-16 21:24:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 31 + }, + "432711": { + "ID": "432711", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MK–STUDIOS – EFRO Rovaniemi Airport v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "970504172", + "Time": "2022-02-16 21:23:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 33 + }, + "432706": { + "ID": "432706", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Pilot Experience Sim – LFMT Montpellier–Mediterranee Airport v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "311798555", + "Time": "2022-02-16 21:19:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 30 + }, + "430479": { + "ID": "430479", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "M’M SIMULATIONS – EFIV Ivalo Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1197783179", + "Time": "2022-02-15 01:55:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 35 + }, + "429266": { + "ID": "429266", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LFQQ Lille Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "384916532", + "Time": "2022-02-12 20:15:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 30 + }, + "429121": { + "ID": "429121", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "iniBuilds – EIKY Kerry Airport v1.1.0 (Fixed)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "329952362", + "Time": "2022-02-11 15:54:01", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 29 + }, + "429120": { + "ID": "429120", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Burning Blue Design – EGHP Popham Airport v1.0.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "485205015", + "Time": "2022-02-11 15:53:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 26 + }, + "429109": { + "ID": "429109", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Stealthy Duck – LSZC Buochs Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "223448882", + "Time": "2022-02-11 15:46:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 28 + }, + "429108": { + "ID": "429108", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FlyLogic – LSZC Buochs Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "119479999", + "Time": "2022-02-11 15:45:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 29 + }, + "428672": { + "ID": "428672", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MXI Design – LJMB Maribor Edvard Rusjan Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "60836830", + "Time": "2022-02-08 03:22:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 30 + }, + "428601": { + "ID": "428601", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Troglodytus Design – LOAN Wiener Neustadt East Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "571190472", + "Time": "2022-02-07 17:52:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 29 + }, + "428035": { + "ID": "428035", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MK–STUDIOS – EFHK Helsinki–Vantaa Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1564655563", + "Time": "2022-02-05 03:22:22", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 24 + }, + "428031": { + "ID": "428031", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "PYREEGUE Dev Co. – EGPF Glasgow Airport v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1045403632", + "Time": "2022-02-05 03:15:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 22 + }, + "427896": { + "ID": "427896", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FSimStudios – CYXU London International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1671885809", + "Time": "2022-02-03 22:40:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 34 + }, + "426161": { + "ID": "426161", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MK–STUDIOS – BIKF Keflavik Airport v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1425044698", + "Time": "2022-01-27 05:15:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 41 + }, + "425899": { + "ID": "425899", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – EDXB Heide–Buesum Airport v1.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "27945135", + "Time": "2022-01-24 23:41:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 32 + }, + "425551": { + "ID": "425551", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Terrainy Studios – LSZN Hausen am Albis Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "670383576", + "Time": "2022-01-22 12:14:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 27 + }, + "425550": { + "ID": "425550", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "M’M SIMULATIONS – LTBS Dalaman Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "807847435", + "Time": "2022-01-22 12:13:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 30 + }, + "425068": { + "ID": "425068", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Digital Design – EDDP Leipzig\/Halle Airport Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3519349448", + "Time": "2022-01-18 22:38:22", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 39 + }, + "424981": { + "ID": "424981", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – ENMH Mehamn Airport v1.0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "258188027", + "Time": "2022-01-18 07:19:01", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 33 + }, + "424980": { + "ID": "424980", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Freds Airports – EDJA Memmingen Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1158637483", + "Time": "2022-01-18 07:18:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 35 + }, + "424676": { + "ID": "424676", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – ENML Molde Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2840396630", + "Time": "2022-01-15 19:26:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 34 + }, + "423478": { + "ID": "423478", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LIPB Bolzano Airport v3.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "414657800", + "Time": "2022-01-09 05:32:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 39 + }, + "423321": { + "ID": "423321", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Pilot Plus – EGTB Wycombe Air Park v1.1.5", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1443382699", + "Time": "2022-01-08 04:10:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 40 + }, + "423318": { + "ID": "423318", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "TDM Scenery Design – LECO A Coruna Airport v1.5.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1295657860", + "Time": "2022-01-08 03:57:01", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 39 + }, + "422400": { + "ID": "422400", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Barelli MSFS Addon – LICC Catania–Fontanarossa Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "42954710", + "Time": "2022-01-05 02:09:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 41 + }, + "421965": { + "ID": "421965", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Azurpoly – LFTH Toulon – Hyeres Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3089220924", + "Time": "2022-01-03 00:09:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 35 + }, + "421682": { + "ID": "421682", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Onfinal Studio – ENSK Stokmarknes Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "214157065", + "Time": "2022-01-01 20:08:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 37 + }, + "421681": { + "ID": "421681", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Onfinal Studio – ENBV Berlevag Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "99388943", + "Time": "2022-01-01 20:08:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 38 + }, + "421680": { + "ID": "421680", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Onfinal Studio – ENBN Bronnoysund Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "115997103", + "Time": "2022-01-01 20:07:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 41 + }, + "421196": { + "ID": "421196", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "UK2000 Scenery – EGFF Cardiff Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "92772666", + "Time": "2021-12-31 06:31:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 51 + }, + "421192": { + "ID": "421192", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Just Flight – LEPA Palma de Mallorca Airport v1.1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "489862011", + "Time": "2021-12-31 06:29:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 21, + "Leechers": 0, + "Snatched": 53 + }, + "421186": { + "ID": "421186", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Digital Design – LOWS Salzburg Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2863237776", + "Time": "2021-12-31 06:28:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 61 + }, + "421184": { + "ID": "421184", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ARIMA – LEZL Seville Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1114931099", + "Time": "2021-12-31 06:28:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 63 + }, + "418571": { + "ID": "418571", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LIMJ Genoa Airport v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "489888638", + "Time": "2021-12-24 01:56:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 21, + "Leechers": 0, + "Snatched": 56 + }, + "418570": { + "ID": "418570", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JustSim – ELLX Luxembourg Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1164375923", + "Time": "2021-12-24 01:55:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 61 + }, + "418568": { + "ID": "418568", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JustSim – LCLK Larnaca International Airport v1.1.0 (New Build)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "900582562", + "Time": "2021-12-24 01:44:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 59 + }, + "418566": { + "ID": "418566", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "AmSim – UMMS Minsk National Airport v1.0.0 (Hotfix)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "713201948", + "Time": "2021-12-24 01:43:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 21, + "Leechers": 0, + "Snatched": 57 + }, + "418565": { + "ID": "418565", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JustSim – LFMN Nice Cote d’Azur Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "594882494", + "Time": "2021-12-24 01:42:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 23, + "Leechers": 0, + "Snatched": 60 + }, + "418125": { + "ID": "418125", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Flightbeam Studios – LFBZ Biarritz Pays Basque Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "696294288", + "Time": "2021-12-21 00:08:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 62 + }, + "417362": { + "ID": "417362", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "UK2000 Scenery – EGPE Inverness Airport v1.1.5", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "80852447", + "Time": "2021-12-15 02:49:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 68 + }, + "417357": { + "ID": "417357", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Pilot Experience Sim – LFBD Bordeaux–Merignac Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "423557500", + "Time": "2021-12-15 02:48:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 25, + "Leechers": 0, + "Snatched": 63 + }, + "417356": { + "ID": "417356", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FSDreamTeam – LFEQ Quiberon Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "210657438", + "Time": "2021-12-15 02:48:03", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 25, + "Leechers": 0, + "Snatched": 64 + }, + "416614": { + "ID": "416614", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – ENAT Alta Airport v1.1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2565085247", + "Time": "2021-12-09 19:39:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 25, + "Leechers": 0, + "Snatched": 77 + }, + "416613": { + "ID": "416613", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "M’M SIMULATIONS – ESKN Stockholm Skavsta Airport v1.1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1317647701", + "Time": "2021-12-09 19:31:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 82 + }, + "416450": { + "ID": "416450", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Tailstrike Designs – LIME Orio al Serio International \/ Bergamo Airport v1.0.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3878572836", + "Time": "2021-12-08 07:10:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 23, + "Leechers": 0, + "Snatched": 84 + }, + "416441": { + "ID": "416441", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Tailstrike Designs – LICR Reggio di Calabria Airport v1.0.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1511839485", + "Time": "2021-12-08 06:34:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 22, + "Leechers": 0, + "Snatched": 77 + }, + "416321": { + "ID": "416321", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JustSim – LTBS Dalaman Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "697650151", + "Time": "2021-12-07 01:04:24", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 76 + }, + "416290": { + "ID": "416290", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FlyLogic – LSPN Triengen Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "67875994", + "Time": "2021-12-06 19:14:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 78 + }, + "416126": { + "ID": "416126", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "RCStudio – LIQL Lucca–Tassignano Airport v1.2.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "764332525", + "Time": "2021-12-06 04:06:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 73 + }, + "416125": { + "ID": "416125", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – LGSK Skiathos International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "380343933", + "Time": "2021-12-06 04:05:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 77 + }, + "415874": { + "ID": "415874", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – EGHI Southampton Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "318302083", + "Time": "2021-12-04 00:01:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 70 + }, + "415872": { + "ID": "415872", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – ENSG Sogndal Haukasen Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "476698013", + "Time": "2021-12-03 23:56:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 68 + }, + "415865": { + "ID": "415865", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – EGPB Sumburgh Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "111915731", + "Time": "2021-12-03 23:53:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 23, + "Leechers": 0, + "Snatched": 72 + }, + "415864": { + "ID": "415864", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Freds Airports – EDDN Nuernberg Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "393508203", + "Time": "2021-12-03 23:53:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 74 + }, + "415647": { + "ID": "415647", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Terrainy Studios – LGIK Ikaria Island National Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1669285507", + "Time": "2021-12-03 02:41:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 21, + "Leechers": 0, + "Snatched": 80 + }, + "415645": { + "ID": "415645", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "M’M SIMULATIONS – EDQD Bayreuth Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "642862536", + "Time": "2021-12-03 02:38:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 23, + "Leechers": 0, + "Snatched": 73 + }, + "415644": { + "ID": "415644", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "DMD Developers – URKG Gelendzhik Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "248462409", + "Time": "2021-12-03 02:38:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 23, + "Leechers": 0, + "Snatched": 72 + }, + "415565": { + "ID": "415565", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Scenery Creation – UWWW Kurumoch International Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1495756925", + "Time": "2021-12-02 10:15:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 21, + "Leechers": 0, + "Snatched": 79 + }, + "415561": { + "ID": "415561", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Simultech – LESU Andorra–La Seu d’Urgell Airport v1.2.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "114934501", + "Time": "2021-12-02 10:14:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 74 + }, + "415442": { + "ID": "415442", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LFMP Perpignan–Rivesaltes Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "287957569", + "Time": "2021-11-30 22:59:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 25, + "Leechers": 0, + "Snatched": 75 + }, + "415001": { + "ID": "415001", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Drzewiecki Design – EPZG Zielona Gora Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "720397518", + "Time": "2021-11-26 07:41:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 73 + }, + "414794": { + "ID": "414794", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – LFTZ St. Tropez Airport v1.1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "701676317", + "Time": "2021-11-24 22:20:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 22, + "Leechers": 0, + "Snatched": 70 + }, + "414444": { + "ID": "414444", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JustSim – EFHK Helsinki–Vantaa Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2747380255", + "Time": "2021-11-22 00:07:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 88 + }, + "414443": { + "ID": "414443", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LFBH La Rochelle Airport v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "266308883", + "Time": "2021-11-22 00:03:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 78 + }, + "414441": { + "ID": "414441", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "France VFR – Paris VFR Airports v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1080693408", + "Time": "2021-11-21 23:53:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 23, + "Leechers": 0, + "Snatched": 85 + }, + "414147": { + "ID": "414147", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx - ENSD Sandane Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "596748710", + "Time": "2021-11-20 00:50:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 81 + }, + "412090": { + "ID": "412090", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "4Simmers – LFRG Deauville – Normandie Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "404969829", + "Time": "2021-11-13 06:26:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 82 + }, + "411738": { + "ID": "411738", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "UK2000 Scenery – EGPF Glasgow Airport v1.2.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "108089763", + "Time": "2021-11-12 06:43:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 85 + }, + "411737": { + "ID": "411737", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Drzewiecki Design – EPKK Krakow John Paul II International Airport v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1443630989", + "Time": "2021-11-12 06:42:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 90 + }, + "411732": { + "ID": "411732", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – ENHF Hammerfest Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2357510374", + "Time": "2021-11-12 06:40:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 89 + }, + "411141": { + "ID": "411141", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JetStream Designs – LIML Milan Linate Airport v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "251491193", + "Time": "2021-11-11 00:51:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 82 + }, + "411139": { + "ID": "411139", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JustSim – EBBR Brussels Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1879082522", + "Time": "2021-11-11 00:50:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 91 + }, + "411138": { + "ID": "411138", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JustSim – EDDH Hamburg Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "884625320", + "Time": "2021-11-11 00:49:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 85 + }, + "411137": { + "ID": "411137", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JustSim – EDDL Duesseldorf Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "980206067", + "Time": "2021-11-11 00:48:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 86 + }, + "411136": { + "ID": "411136", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JustSim – EVRA Riga International Airport v1.0.0 (New Build)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "846932692", + "Time": "2021-11-11 00:48:22", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 84 + }, + "411134": { + "ID": "411134", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JustSim – LOWK Klagenfurt Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "426635131", + "Time": "2021-11-11 00:47:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 84 + }, + "410780": { + "ID": "410780", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – EDPI Moosburg auf der Kippe Airport v1.1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "890259886", + "Time": "2021-11-09 22:16:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 25, + "Leechers": 0, + "Snatched": 80 + }, + "410134": { + "ID": "410134", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JustSim – EDDC Dresden Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "733888425", + "Time": "2021-11-07 23:07:27", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 88 + }, + "409956": { + "ID": "409956", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – LDZD Zadar Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "819125899", + "Time": "2021-11-07 07:58:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 85 + }, + "409318": { + "ID": "409318", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Freds Airports – EDQM Hof–Plauen Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1328353438", + "Time": "2021-11-03 21:45:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 102 + }, + "409317": { + "ID": "409317", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Freds Airports – EDNL Leutkirch Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "63137405", + "Time": "2021-11-03 21:45:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 94 + }, + "409314": { + "ID": "409314", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Freds Airports – EDDR Saarbruecken Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "154922546", + "Time": "2021-11-03 21:44:22", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 97 + }, + "409153": { + "ID": "409153", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – ESSB Stockholm Bromma Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "9461971938", + "Time": "2021-11-03 05:05:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 25, + "Leechers": 0, + "Snatched": 107 + }, + "409120": { + "ID": "409120", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JustSim – LOWL Linz Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "740167744", + "Time": "2021-11-03 03:38:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 86 + }, + "409109": { + "ID": "409109", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Vref Simulations – LFKC Calvi – Sainte–Catherine Airport v1.6.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "219409147", + "Time": "2021-11-03 02:19:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 92 + }, + "409103": { + "ID": "409103", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Davor Puljevic – LDPL Pula Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "102907071", + "Time": "2021-11-03 02:16:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 93 + }, + "407613": { + "ID": "407613", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LERS Reus Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "241271639", + "Time": "2021-10-26 00:52:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 99 + }, + "407218": { + "ID": "407218", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – UHMP Pevek Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "162727358", + "Time": "2021-10-23 14:11:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 101 + }, + "406671": { + "ID": "406671", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – ENOV Orsta–Volda Airport v1.1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "240878649", + "Time": "2021-10-22 07:29:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 95 + }, + "405989": { + "ID": "405989", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "UK2000 Scenery – EGNS Isle of Man Airport v1.0.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "64006674", + "Time": "2021-10-18 01:23:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 107 + }, + "405838": { + "ID": "405838", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MK–STUDIOS – LPPR Francisco Sa Carneiro \/ Porto Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "865418517", + "Time": "2021-10-16 05:42:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 110 + }, + "405355": { + "ID": "405355", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "M’M SIMULATIONS – LSGK Saanen–Gstaad Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "108941633", + "Time": "2021-10-12 23:30:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 106 + }, + "405354": { + "ID": "405354", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "M’M SIMULATIONS – LECH Castellon–Costa Azahar Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "262479730", + "Time": "2021-10-12 23:29:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 107 + }, + "404953": { + "ID": "404953", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Drzewiecki Design – EPSY Olsztyn–Mazury Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "696692764", + "Time": "2021-10-10 00:03:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 109 + }, + "404788": { + "ID": "404788", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – EGLC London City Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2482513491", + "Time": "2021-10-09 02:51:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 122 + }, + "404787": { + "ID": "404787", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Drzewiecki Design – EPLB Lublin Airport Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1272868388", + "Time": "2021-10-09 01:37:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 139 + }, + "404577": { + "ID": "404577", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – ENAL Alesund Vigra Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2149766340", + "Time": "2021-10-07 00:41:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 118 + }, + "404481": { + "ID": "404481", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LIRU Rome Urbe Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "265547119", + "Time": "2021-10-06 01:40:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 35, + "Leechers": 0, + "Snatched": 110 + }, + "404480": { + "ID": "404480", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LEVC Valencia Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "365142113", + "Time": "2021-10-06 01:40:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 108 + }, + "404221": { + "ID": "404221", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – LOWI Innsbruck Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3201260809", + "Time": "2021-10-03 22:53:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 127 + }, + "404220": { + "ID": "404220", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Salvuz – LIPX Verona Villafranca Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "277063634", + "Time": "2021-10-03 22:53:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 113 + }, + "403809": { + "ID": "403809", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "M’M SIMULATIONS – LTBJ Izmir Adnan Menderes Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "90662254", + "Time": "2021-10-01 04:00:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 108 + }, + "403806": { + "ID": "403806", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "M’M SIMULATIONS – LYPG Podgorica Airport v1.0.0 (New Build)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "115910436", + "Time": "2021-10-01 04:00:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 113 + }, + "403520": { + "ID": "403520", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LFLP Annecy Airport v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "209949996", + "Time": "2021-09-29 02:12:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 103 + }, + "403518": { + "ID": "403518", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Red Wing Simulations – LSHV Lausanne University Hospital Heliport v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "95278717", + "Time": "2021-09-29 02:12:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 110 + }, + "403517": { + "ID": "403517", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Red Wing Simulations – LSEZ Zermatt Heliport v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "120494862", + "Time": "2021-09-29 02:12:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 105 + }, + "403516": { + "ID": "403516", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Red Wing Simulations – LSDX Grande Dixence Dam Heliport v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "86140433", + "Time": "2021-09-29 02:11:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 108 + }, + "403515": { + "ID": "403515", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Red Wing Simulations – LSGT Gruyeres Airport v0.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "313408649", + "Time": "2021-09-29 02:11:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 105 + }, + "403514": { + "ID": "403514", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Red Wing Simulations – LSGB Bex Airport v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "329658019", + "Time": "2021-09-29 02:11:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 105 + }, + "403513": { + "ID": "403513", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FlyLogic – LSZA Lugano Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "156913337", + "Time": "2021-09-29 02:11:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 114 + }, + "403383": { + "ID": "403383", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – EDDB Berlin Brandenburg Airport v1.0.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4981653320", + "Time": "2021-09-28 01:02:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 124 + }, + "403317": { + "ID": "403317", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "M’M SIMULATIONS – LSZR St. Gallen–Altenrhein Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "237871371", + "Time": "2021-09-27 12:09:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 112 + }, + "402873": { + "ID": "402873", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – EDER Wasserkuppe Airport v1.1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3190580261", + "Time": "2021-09-24 08:25:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 121 + }, + "402868": { + "ID": "402868", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – EDNY Friedrichshafen Airport v1.0.7.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "166248305", + "Time": "2021-09-24 08:19:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 35, + "Leechers": 0, + "Snatched": 116 + }, + "402693": { + "ID": "402693", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Digital Design – URSS Sochi International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3248907696", + "Time": "2021-09-22 06:45:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 132 + }, + "402689": { + "ID": "402689", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LEBB Bilbao Airport v2.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "358169805", + "Time": "2021-09-22 06:26:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 36, + "Leechers": 0, + "Snatched": 120 + }, + "402466": { + "ID": "402466", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Red Wing Simulations – LSZL Locarno Airport v0.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "394281596", + "Time": "2021-09-20 11:44:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 123 + }, + "402352": { + "ID": "402352", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FlyLogic – LSZF Birrfeld Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "25139440", + "Time": "2021-09-18 23:11:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 38, + "Leechers": 0, + "Snatched": 131 + }, + "402351": { + "ID": "402351", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FlyLogic – LSGC Les Eplatures Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "28192053", + "Time": "2021-09-18 23:11:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 36, + "Leechers": 0, + "Snatched": 127 + }, + "402272": { + "ID": "402272", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "LMT Simulation – LFMV Avignon Provence Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "151879812", + "Time": "2021-09-17 18:42:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 36, + "Leechers": 0, + "Snatched": 126 + }, + "402129": { + "ID": "402129", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LELN Leon Airport v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "328994763", + "Time": "2021-09-16 20:40:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 111 + }, + "401890": { + "ID": "401890", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LIPR Federico Fellini International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "282291489", + "Time": "2021-09-16 04:09:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 113 + }, + "401888": { + "ID": "401888", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LIOL San Mauro Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "55621703", + "Time": "2021-09-16 04:07:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 39, + "Leechers": 0, + "Snatched": 123 + }, + "401887": { + "ID": "401887", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LIBP Abruzzo Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "182496714", + "Time": "2021-09-16 04:06:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 38, + "Leechers": 0, + "Snatched": 116 + }, + "401886": { + "ID": "401886", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LFLP Annecy Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "201850643", + "Time": "2021-09-16 04:05:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 100 + }, + "401881": { + "ID": "401881", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Pilot Plus – EGGD Bristol Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1449736032", + "Time": "2021-09-16 04:01:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 36, + "Leechers": 0, + "Snatched": 134 + }, + "401879": { + "ID": "401879", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FlyDesign – LFMD Cannes–Mandelieu Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "497438516", + "Time": "2021-09-16 03:59:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 126 + }, + "401877": { + "ID": "401877", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "DominicDesignTeam – OEDF King Fahd International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2357677686", + "Time": "2021-09-16 03:56:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 36, + "Leechers": 0, + "Snatched": 133 + }, + "401166": { + "ID": "401166", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "PYREEGUE Dev Co. – EGPH Edinburgh Airport v1.1.5", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "992371518", + "Time": "2021-09-11 23:34:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 41, + "Leechers": 0, + "Snatched": 144 + }, + "401161": { + "ID": "401161", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – LOIK Kufstein–Langkampfen Airport v1.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "51175163", + "Time": "2021-09-11 23:18:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 41, + "Leechers": 0, + "Snatched": 133 + }, + "401128": { + "ID": "401128", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "SimNord – EKBI Billund Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "197981618", + "Time": "2021-09-11 22:35:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 39, + "Leechers": 0, + "Snatched": 133 + }, + "399664": { + "ID": "399664", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "iniBuilds – EGKK Gatwick Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4551662532", + "Time": "2021-09-06 03:48:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 42, + "Leechers": 0, + "Snatched": 155 + }, + "399538": { + "ID": "399538", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "4Simmers – EKSV Skive Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1324851717", + "Time": "2021-09-05 07:40:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 149 + }, + "399379": { + "ID": "399379", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MFSG – OJAQ Aqaba \/ King Hussein International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "12093939", + "Time": "2021-09-04 04:48:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 132 + }, + "399377": { + "ID": "399377", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – EGNT Newcastle Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2338696367", + "Time": "2021-09-04 04:47:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 133 + }, + "399183": { + "ID": "399183", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "TropicalSim – TFFF Martinique Aime Cesaire International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "80132094", + "Time": "2021-09-02 22:45:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 39, + "Leechers": 0, + "Snatched": 128 + }, + "399181": { + "ID": "399181", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BDOaviation – LFRK Caen – Carpiquet Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "461786510", + "Time": "2021-09-02 22:45:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 36, + "Leechers": 0, + "Snatched": 127 + }, + "398891": { + "ID": "398891", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – LDSP Split Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4119833042", + "Time": "2021-09-01 22:29:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 140 + }, + "397967": { + "ID": "397967", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "TropicalSim – LPFR Faro Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "77447964", + "Time": "2021-08-31 02:13:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 41, + "Leechers": 0, + "Snatched": 142 + }, + "397365": { + "ID": "397365", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MSK productions – OMSJ Sharjah International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "78107431", + "Time": "2021-08-26 18:48:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 41, + "Leechers": 0, + "Snatched": 136 + }, + "397363": { + "ID": "397363", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "PYREEGUE Dev Co. – UKOO Odesa International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "410092683", + "Time": "2021-08-26 18:41:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 126 + }, + "397315": { + "ID": "397315", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Airwil Sceneries – RPME Bancasi \/ Butuan Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "29077225", + "Time": "2021-08-26 15:59:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 41, + "Leechers": 0, + "Snatched": 136 + }, + "397312": { + "ID": "397312", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ARIMA – EDLW Dortmund Airport v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "112256302", + "Time": "2021-08-26 15:55:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 43, + "Leechers": 0, + "Snatched": 138 + }, + "397077": { + "ID": "397077", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MK–STUDIOS – LPPD Ponta Delgada – Joao Paulo II Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1938589312", + "Time": "2021-08-25 08:10:30", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 40, + "Leechers": 0, + "Snatched": 139 + }, + "396883": { + "ID": "396883", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Macco Simulations – EGCC Manchester Airport v2.1.5", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "639989491", + "Time": "2021-08-24 07:57:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 41, + "Leechers": 0, + "Snatched": 153 + }, + "396772": { + "ID": "396772", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – EGTP Perranporth Airfield v1.1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "207238809", + "Time": "2021-08-23 07:07:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 44, + "Leechers": 0, + "Snatched": 143 + }, + "396294": { + "ID": "396294", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MK–STUDIOS – GCFV Fuerteventura Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1102529384", + "Time": "2021-08-20 03:50:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 40, + "Leechers": 0, + "Snatched": 151 + }, + "392074": { + "ID": "392074", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Macco Simulations - EGBB Birmingham Airport v0.9.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "522150038", + "Time": "2021-08-01 13:10:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 45, + "Leechers": 0, + "Snatched": 159 + }, + "390584": { + "ID": "390584", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx - EGPN Dundee Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1584662338", + "Time": "2021-07-26 21:48:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 42, + "Leechers": 0, + "Snatched": 169 + }, + "390576": { + "ID": "390576", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "LatinVFR - LEBL Barcelona Airport v1.0.7", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "905065846", + "Time": "2021-07-26 21:25:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 46, + "Leechers": 0, + "Snatched": 170 + }, + "390574": { + "ID": "390574", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JustSim - LGIR Heraklion International Airport v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "766881160", + "Time": "2021-07-26 21:02:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 43, + "Leechers": 0, + "Snatched": 165 + }, + "388742": { + "ID": "388742", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Double T – OEJN King Abdulaziz International Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "269252808", + "Time": "2021-07-20 21:11:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 46, + "Leechers": 0, + "Snatched": 151 + }, + "387292": { + "ID": "387292", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "DMD Developers – URKA Anapa Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "359625178", + "Time": "2021-07-14 21:47:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 43, + "Leechers": 0, + "Snatched": 155 + }, + "387288": { + "ID": "387288", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Pilot Experience Sim – LFBZ Biarritz Pays Basque Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "289744547", + "Time": "2021-07-14 21:46:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 43, + "Leechers": 0, + "Snatched": 152 + }, + "387269": { + "ID": "387269", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LIDT Trento–Mattarello Airport v1.6.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "273823908", + "Time": "2021-07-14 21:27:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 45, + "Leechers": 0, + "Snatched": 148 + }, + "387266": { + "ID": "387266", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LICB Comiso Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "212772983", + "Time": "2021-07-14 21:23:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 46, + "Leechers": 0, + "Snatched": 146 + }, + "387264": { + "ID": "387264", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LIBP Abruzzo Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "189954121", + "Time": "2021-07-14 21:20:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 50, + "Leechers": 0, + "Snatched": 150 + }, + "386843": { + "ID": "386843", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JetStream Designs – LFPO Paris Orly Airport v1.2.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1239623164", + "Time": "2021-07-13 07:11:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 48, + "Leechers": 0, + "Snatched": 176 + }, + "386834": { + "ID": "386834", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Simbreeze – HEGN Hurghada International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "114149455", + "Time": "2021-07-13 04:53:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 48, + "Leechers": 0, + "Snatched": 164 + }, + "386567": { + "ID": "386567", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LFBZ Biarritz Pays Basque Airport v2.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "414602283", + "Time": "2021-07-12 18:47:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 46, + "Leechers": 0, + "Snatched": 150 + }, + "386556": { + "ID": "386556", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "BEAUTIFUL MODEL of the WORLD – LEBG Burgos Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "168821768", + "Time": "2021-07-12 18:14:24", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 51, + "Leechers": 0, + "Snatched": 159 + }, + "386098": { + "ID": "386098", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – ENST Sandnessjoen–Stokka Airport v1.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "325388840", + "Time": "2021-07-10 09:31:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 48, + "Leechers": 0, + "Snatched": 146 + }, + "386002": { + "ID": "386002", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "AmSim – UDYZ Zvartnots International Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "866564527", + "Time": "2021-07-09 20:20:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 45, + "Leechers": 0, + "Snatched": 153 + }, + "386000": { + "ID": "386000", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "AmSim – UGTB Tbilisi International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "693382018", + "Time": "2021-07-09 20:03:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 45, + "Leechers": 0, + "Snatched": 160 + }, + "385998": { + "ID": "385998", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Burning Blue Design – EGLM White Waltham Airport v1.4.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "689443374", + "Time": "2021-07-09 20:02:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 45, + "Leechers": 0, + "Snatched": 153 + }, + "385991": { + "ID": "385991", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Burning Blue Design – EGMD Lydd Airport v1.4.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "268579954", + "Time": "2021-07-09 19:34:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 49, + "Leechers": 0, + "Snatched": 161 + }, + "385982": { + "ID": "385982", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Burning Blue Design – EGKH Headcorn Airport v1.4.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "197298229", + "Time": "2021-07-09 19:18:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 49, + "Leechers": 0, + "Snatched": 160 + }, + "385980": { + "ID": "385980", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "AmSim – UDKS Stepanakert Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "113783908", + "Time": "2021-07-09 19:16:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 49, + "Leechers": 0, + "Snatched": 150 + }, + "385979": { + "ID": "385979", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "AmSim – UDSG Shirak International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "123042797", + "Time": "2021-07-09 19:16:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 51, + "Leechers": 0, + "Snatched": 153 + }, + "383694": { + "ID": "383694", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ORBX - EGMC London Southend Airport v1.0.5", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1762248958", + "Time": "2021-07-01 14:00:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 45, + "Leechers": 0, + "Snatched": 182 + }, + "383422": { + "ID": "383422", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MXI Design – LDRI Rijeka Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "38468572", + "Time": "2021-06-29 22:01:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 46, + "Leechers": 0, + "Snatched": 146 + }, + "383421": { + "ID": "383421", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MXI Design – LFLB Chambery Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "137684638", + "Time": "2021-06-29 21:58:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 47, + "Leechers": 0, + "Snatched": 157 + }, + "381394": { + "ID": "381394", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "RUSD - UHMM Magadan v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "157404701", + "Time": "2021-06-24 03:03:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 51, + "Leechers": 0, + "Snatched": 169 + }, + "381393": { + "ID": "381393", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbyx - UKLL Lviv Danylo Halytskyi International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "562730506", + "Time": "2021-06-24 02:57:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 44, + "Leechers": 0, + "Snatched": 177 + }, + "381343": { + "ID": "381343", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – LSZS Samedan Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3269694617", + "Time": "2021-06-23 23:35:01", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 46, + "Leechers": 0, + "Snatched": 175 + }, + "381339": { + "ID": "381339", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "RUSD – UHPP Elizovo Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1941338748", + "Time": "2021-06-23 23:31:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 45, + "Leechers": 0, + "Snatched": 180 + }, + "381335": { + "ID": "381335", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – LEVT Vitoria Airport v1.2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "984357483", + "Time": "2021-06-23 23:26:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 46, + "Leechers": 0, + "Snatched": 156 + }, + "381334": { + "ID": "381334", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – LOWG Graz Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4432976519", + "Time": "2021-06-23 23:25:22", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 45, + "Leechers": 0, + "Snatched": 175 + }, + "381326": { + "ID": "381326", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JustSim – LMML Malta International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1297119670", + "Time": "2021-06-23 23:17:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 49, + "Leechers": 0, + "Snatched": 181 + }, + "381297": { + "ID": "381297", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FlyLogic – LSZQ Bressaucourt Airport v1.0.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "55083494", + "Time": "2021-06-23 22:37:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 53, + "Leechers": 0, + "Snatched": 171 + }, + "381293": { + "ID": "381293", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Gaffer Simulations – FAPE Port Elizabeth \/ Chief Dawid Stuurman International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1125470080", + "Time": "2021-06-23 22:33:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 49, + "Leechers": 0, + "Snatched": 182 + }, + "381116": { + "ID": "381116", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "France VFR – Airport France Pack 1 v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1321132107", + "Time": "2021-06-23 13:26:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 45, + "Leechers": 0, + "Snatched": 169 + }, + "381105": { + "ID": "381105", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – LIPV Venice–Lido Airport v1.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "486227986", + "Time": "2021-06-23 13:23:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 47, + "Leechers": 0, + "Snatched": 156 + }, + "381101": { + "ID": "381101", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Footage Design – LECD La Cerdanya Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "185969618", + "Time": "2021-06-23 13:19:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 53, + "Leechers": 0, + "Snatched": 161 + }, + "381093": { + "ID": "381093", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Red Wing Simulations – LSGS Sion Airport v0.2.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "644945986", + "Time": "2021-06-23 13:09:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 45, + "Leechers": 0, + "Snatched": 159 + }, + "381089": { + "ID": "381089", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – EGNM Leeds Bradford Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4706470194", + "Time": "2021-06-23 13:03:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 50, + "Leechers": 0, + "Snatched": 174 + }, + "381088": { + "ID": "381088", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – EGSG Stapleford Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "193832181", + "Time": "2021-06-23 13:02:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 48, + "Leechers": 0, + "Snatched": 153 + }, + "381087": { + "ID": "381087", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – EGKA Shoreham Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "241762530", + "Time": "2021-06-23 13:01:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 48, + "Leechers": 0, + "Snatched": 151 + }, + "381079": { + "ID": "381079", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – EGTR Elstree Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "87768035", + "Time": "2021-06-23 12:49:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 53, + "Leechers": 0, + "Snatched": 158 + }, + "381071": { + "ID": "381071", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – EGCK Caernarfon Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "682714488", + "Time": "2021-06-23 12:48:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 44, + "Leechers": 0, + "Snatched": 156 + }, + "381067": { + "ID": "381067", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "RCStudio – LIDT Trento–Mattarello Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "749424870", + "Time": "2021-06-23 12:40:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 43, + "Leechers": 0, + "Snatched": 164 + }, + "381058": { + "ID": "381058", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FSDG – Rhodes v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "217485840", + "Time": "2021-06-23 12:17:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 51, + "Leechers": 0, + "Snatched": 152 + }, + "381054": { + "ID": "381054", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – LFKX Meribel Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "266471418", + "Time": "2021-06-23 12:13:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 49, + "Leechers": 0, + "Snatched": 156 + }, + "381024": { + "ID": "381024", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Davor Puljevic – LDSP Split Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "225212068", + "Time": "2021-06-23 11:28:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 48, + "Leechers": 0, + "Snatched": 160 + }, + "381020": { + "ID": "381020", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FSXcenery – LEST Santiago–Rosalia de Castro Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "12656317", + "Time": "2021-06-23 11:24:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 53, + "Leechers": 0, + "Snatched": 183 + }, + "381017": { + "ID": "381017", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Sim Wings – GCGM La Gomera Airport v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "428914254", + "Time": "2021-06-23 11:22:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 47, + "Leechers": 0, + "Snatched": 161 + }, + "381015": { + "ID": "381015", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – EDMA Augsburg Airport v1.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "710304762", + "Time": "2021-06-23 11:18:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 48, + "Leechers": 0, + "Snatched": 162 + }, + "381013": { + "ID": "381013", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FSDG – FMCZ Dzaoudzi–Pamandzi International Airport \/ Mayotte Pamandzi v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2194842045", + "Time": "2021-06-23 11:16:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 46, + "Leechers": 0, + "Snatched": 168 + }, + "381003": { + "ID": "381003", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "SC Designs – EGLK Blackbushe Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "96521138", + "Time": "2021-06-23 10:57:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 50, + "Leechers": 0, + "Snatched": 171 + }, + "381002": { + "ID": "381002", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Sim Wings – EDDH Hamburg Airport v1.0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1796925792", + "Time": "2021-06-23 10:56:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 45, + "Leechers": 0, + "Snatched": 174 + }, + "380998": { + "ID": "380998", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx – LFKB Bastia–Poretta Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "314478794", + "Time": "2021-06-23 10:52:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 47, + "Leechers": 0, + "Snatched": 165 + }, + "380959": { + "ID": "380959", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft – LGSA Chania International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "176605067", + "Time": "2021-06-23 09:31:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 53, + "Leechers": 0, + "Snatched": 166 + }, + "364092": { + "ID": "364092", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "iniBuilds - EGKA Shoreham Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1023722555", + "Time": "2021-04-02 12:47:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 56, + "Leechers": 0, + "Snatched": 229 + }, + "363986": { + "ID": "363986", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Pyreegue Dev Co - TIVAT Montenegro v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "330632797", + "Time": "2021-04-02 01:39:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 55, + "Leechers": 0, + "Snatched": 231 + }, + "361140": { + "ID": "361140", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ORBX - LWOH Ohrid St Paul the Apostle Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "177914281", + "Time": "2021-03-25 21:48:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 63, + "Leechers": 0, + "Snatched": 236 + }, + "361035": { + "ID": "361035", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JUSTSIM - EDDV Hannover Airport v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1615613929", + "Time": "2021-03-25 15:02:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 62, + "Leechers": 0, + "Snatched": 260 + }, + "361033": { + "ID": "361033", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "PILOTPLUS - EGTK London Oxford Airport", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1992583240", + "Time": "2021-03-25 14:58:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 61, + "Leechers": 0, + "Snatched": 254 + }, + "361027": { + "ID": "361027", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JUSTSIM - LGSR Santorini International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "433385093", + "Time": "2021-03-25 14:52:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 60, + "Leechers": 0, + "Snatched": 232 + }, + "355726": { + "ID": "355726", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Gaya Simulations - ENCN Kristiansand Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1224195951", + "Time": "2021-03-09 19:10:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 71, + "Leechers": 0, + "Snatched": 304 + }, + "355188": { + "ID": "355188", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JUSTSIM - EDDS Stuttgart Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1419600533", + "Time": "2021-03-05 17:31:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 72, + "Leechers": 0, + "Snatched": 301 + }, + "349774": { + "ID": "349774", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ORBX - UKOO Odesa International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "408627431", + "Time": "2021-02-19 19:42:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 68, + "Leechers": 0, + "Snatched": 285 + }, + "349769": { + "ID": "349769", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ORBX - UKBB Boryspil International Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "800052847", + "Time": "2021-02-19 19:33:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 65, + "Leechers": 0, + "Snatched": 278 + }, + "347322": { + "ID": "347322", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Deimos INC - LFMN - Nice Côte d'Azur v1.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "337371783", + "Time": "2021-02-12 21:56:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 68, + "Leechers": 0, + "Snatched": 282 + }, + "346656": { + "ID": "346656", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FSDT - Zurich V1.1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "345685912", + "Time": "2021-02-10 14:33:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 67, + "Leechers": 0, + "Snatched": 283 + }, + "346650": { + "ID": "346650", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Gaya Simulations - Kos International Airport LGKO v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3005691220", + "Time": "2021-02-10 14:15:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 68, + "Leechers": 0, + "Snatched": 315 + }, + "345698": { + "ID": "345698", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MXI Design - LQSA Sarajevo International Airport v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "115531449", + "Time": "2021-02-05 19:25:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 77, + "Leechers": 0, + "Snatched": 291 + }, + "344438": { + "ID": "344438", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ORBX - EGTB Wycombe Air Park v1.1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1470632417", + "Time": "2021-01-28 09:34:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 70, + "Leechers": 0, + "Snatched": 330 + }, + "344097": { + "ID": "344097", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Redwing Simulations - LFLY Leon-Bron Airport v0.1.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "631882546", + "Time": "2021-01-26 08:38:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 68, + "Leechers": 0, + "Snatched": 297 + }, + "343550": { + "ID": "343550", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Justsim - LEPA Palma de Mallorca Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1751842350", + "Time": "2021-01-23 13:48:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 75, + "Leechers": 0, + "Snatched": 336 + }, + "341597": { + "ID": "341597", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ORBX - LPVL Maia-Vilar de Luz Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "370110321", + "Time": "2021-01-16 07:25:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 72, + "Leechers": 0, + "Snatched": 329 + }, + "340610": { + "ID": "340610", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ORBX - LOWW Vienna International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2436823640", + "Time": "2021-01-11 12:05:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 74, + "Leechers": 0, + "Snatched": 382 + }, + "340440": { + "ID": "340440", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FlyDesign - EPGD Gdańsk Lech Wałęsa Airport v1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "546522465", + "Time": "2021-01-10 14:22:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 71, + "Leechers": 0, + "Snatched": 340 + }, + "340439": { + "ID": "340439", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FlyDesign - EPSY Olsztyn-Mazury International Airport v1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "255776567", + "Time": "2021-01-10 14:22:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 74, + "Leechers": 0, + "Snatched": 345 + }, + "340426": { + "ID": "340426", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Deimos INC - LIMC Milano Malpensa International v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "355985740", + "Time": "2021-01-10 09:00:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 74, + "Leechers": 0, + "Snatched": 345 + }, + "339955": { + "ID": "339955", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft - EDDM Munich Airport v1.0.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2786966638", + "Time": "2021-01-08 11:02:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 75, + "Leechers": 0, + "Snatched": 408 + }, + "339016": { + "ID": "339016", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ORBX - LOWZ Zell am See Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "561265689", + "Time": "2021-01-04 13:40:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 68, + "Leechers": 0, + "Snatched": 323 + }, + "338984": { + "ID": "338984", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "MXI Design - LDDU Dubrovnik Airport v1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "180741457", + "Time": "2021-01-04 10:35:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 77, + "Leechers": 0, + "Snatched": 349 + }, + "338717": { + "ID": "338717", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ORBX - LFKB Bastia-Poretta Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "258453656", + "Time": "2021-01-02 13:12:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 69, + "Leechers": 0, + "Snatched": 336 + }, + "338301": { + "ID": "338301", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Azurpoly - Toulon-Hyères Airport v1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1856253730", + "Time": "2020-12-31 12:49:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 69, + "Leechers": 0, + "Snatched": 350 + }, + "338060": { + "ID": "338060", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "JUSTSIM - LGRP Rhodes International Airport Diagoras V1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "429956220", + "Time": "2020-12-30 20:14:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 72, + "Leechers": 0, + "Snatched": 325 + }, + "337690": { + "ID": "337690", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "TBLFscenery - LFFO Beauvoir-sur-Mer Vendée Airport v1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "65485302", + "Time": "2020-12-29 13:32:30", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 75, + "Leechers": 0, + "Snatched": 341 + }, + "337446": { + "ID": "337446", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "EGKK Gatwick Airport England V7.7", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "847176748", + "Time": "2020-12-28 11:16:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 70, + "Leechers": 0, + "Snatched": 341 + }, + "335302": { + "ID": "335302", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Vref Simulations - LPCO Coimbra Aerodrome v1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "363275051", + "Time": "2020-12-20 03:40:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 72, + "Leechers": 0, + "Snatched": 336 + }, + "334467": { + "ID": "334467", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ORBX - LIRQ Florence Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "940695469", + "Time": "2020-12-15 02:21:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 74, + "Leechers": 0, + "Snatched": 341 + }, + "332810": { + "ID": "332810", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ORBX - LOIJ Sankt Johann Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "450877839", + "Time": "2020-12-09 02:07:30", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 73, + "Leechers": 0, + "Snatched": 344 + }, + "332807": { + "ID": "332807", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ORBX - LIEO Olbia Costa Smeralda Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "417784510", + "Time": "2020-12-09 02:04:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 72, + "Leechers": 0, + "Snatched": 346 + }, + "332584": { + "ID": "332584", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FSXcenery - LEMI Región de Murcia International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "17380227", + "Time": "2020-12-08 09:26:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 81, + "Leechers": 0, + "Snatched": 367 + }, + "331926": { + "ID": "331926", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "FSDreamteam - FSDT Zurich V1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "340174623", + "Time": "2020-12-06 09:18:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 72, + "Leechers": 0, + "Snatched": 333 + }, + "331282": { + "ID": "331282", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Aerosoft - LEIB Ibiza Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "700550643", + "Time": "2020-12-04 03:27:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 78, + "Leechers": 0, + "Snatched": 358 + }, + "331281": { + "ID": "331281", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Justsim - LTAI Antalya International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1075005139", + "Time": "2020-12-04 02:54:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 75, + "Leechers": 0, + "Snatched": 371 + }, + "331280": { + "ID": "331280", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ORBX - LOWS Salzburg Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2857220348", + "Time": "2020-12-04 02:52:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 78, + "Leechers": 0, + "Snatched": 377 + }, + "331233": { + "ID": "331233", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ORBX - EGNT Newcastle International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2500294465", + "Time": "2020-12-03 15:04:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 76, + "Leechers": 0, + "Snatched": 371 + }, + "322852": { + "ID": "322852", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Justsim - LFSB LSZM Europort Basel Mulhouse Freiburg v1.0.0 - DLC", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1191782449", + "Time": "2020-11-07 10:21:24", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 74, + "Leechers": 0, + "Snatched": 372 + }, + "319790": { + "ID": "319790", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ORBX - ENNO Notodden Airport", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1361203243", + "Time": "2020-10-25 12:13:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 78, + "Leechers": 0, + "Snatched": 415 + }, + "318247": { + "ID": "318247", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "RDS - UUML Severka Airfield v0.1.0 - DLC", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "254499762", + "Time": "2020-10-18 08:53:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 77, + "Leechers": 0, + "Snatched": 375 + }, + "316420": { + "ID": "316420", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "ORBX - EDDT Berlin-Tegel Airport v1.1.0 - DLC", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "858832393", + "Time": "2020-10-12 11:48:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 77, + "Leechers": 0, + "Snatched": 395 + }, + "312604": { + "ID": "312604", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - Europe", + "Scene": "0", + "ReleaseTitle": "Orbx - LGKO Kos International Airport", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2053080576", + "Time": "2020-09-30 10:07:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 77, + "Leechers": 0, + "Snatched": 421 + }, + "479875": { + "ID": "479875", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Orbx – KCRW West Virginia International Yeager Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1706536013", + "Time": "2022-07-24 19:40:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 11 + }, + "479874": { + "ID": "479874", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Flight FX – KPWK Chicago Executive Airport v1.7.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1324982227", + "Time": "2022-07-24 19:38:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 11 + }, + "479782": { + "ID": "479782", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Sierrasim Simulation – KSYR Syracuse Hancock International Airport v1.2.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "189617467", + "Time": "2022-07-24 07:20:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 8 + }, + "479779": { + "ID": "479779", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "iniBuilds – 58CA Hooper Heliport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "583304732", + "Time": "2022-07-24 07:20:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 9 + }, + "478783": { + "ID": "478783", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Fly 2 High – KRSW Southwest Florida International Airport v1.0.0 (Update 2)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2994938352", + "Time": "2022-07-20 09:55:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 10 + }, + "478782": { + "ID": "478782", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FeelThere – KLGA LaGuardia Airport v1.9.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "443061422", + "Time": "2022-07-20 09:54:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 4 + }, + "478781": { + "ID": "478781", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Pearl Simulations – PHTO Hilo International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1549270276", + "Time": "2022-07-20 09:53:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 10 + }, + "478777": { + "ID": "478777", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Pearl Simulations – X01 Everglades Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "441093422", + "Time": "2022-07-20 09:51:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 6 + }, + "478208": { + "ID": "478208", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Final Approach Simulations – MKJS Sangster International Airport v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "216057606", + "Time": "2022-07-17 07:43:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 10 + }, + "477418": { + "ID": "477418", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "MSX Creations – KMYL McCall Municipal Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "986871057", + "Time": "2022-07-14 02:07:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 12 + }, + "477416": { + "ID": "477416", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FeelThere – KLAS McCarran \/ Harry Reid International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1621686638", + "Time": "2022-07-14 02:06:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 14 + }, + "477181": { + "ID": "477181", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Roman Design – CYOO Oshawa Executive Airport v1.2.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "157524998", + "Time": "2022-07-13 06:42:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 9 + }, + "477180": { + "ID": "477180", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Fly 2 High – KFAT Fresno Yosemite International Airport v1.0.0 (Update 1)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2097115345", + "Time": "2022-07-13 06:42:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 14 + }, + "476978": { + "ID": "476978", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Stealthy Duck – KTLH Tallahassee International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "212189971", + "Time": "2022-07-11 23:32:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 10 + }, + "476977": { + "ID": "476977", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "BravoAirspace – MDSD Las Americas International Airport v1.2.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "524069846", + "Time": "2022-07-11 23:31:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 11 + }, + "476902": { + "ID": "476902", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Drzewiecki Design – KDCA Ronald Reagan Washington National Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "563394959", + "Time": "2022-07-11 07:49:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 10 + }, + "476888": { + "ID": "476888", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "SLH Sim Designs – TDPD Douglas–Charles Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "123051480", + "Time": "2022-07-11 07:40:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 8 + }, + "476887": { + "ID": "476887", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSDG – TLPC George F. L. Charles Airport \/ St. Lucia v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "435798181", + "Time": "2022-07-11 07:40:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 9 + }, + "476886": { + "ID": "476886", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "LatinVFR – KLSV Nellis Air Force Base \/ AFB Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "369111689", + "Time": "2022-07-11 07:39:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 10 + }, + "475474": { + "ID": "475474", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "LatinVFR – KSAN San Diego International Airport v1.0.5", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "587417434", + "Time": "2022-07-04 07:00:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 10 + }, + "474543": { + "ID": "474543", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "DominicDesignTeam – KIND Indianapolis International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1749350432", + "Time": "2022-07-01 01:08:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 16 + }, + "474329": { + "ID": "474329", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "UK2000 Scenery – KSNA John Wayne Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "34467304", + "Time": "2022-06-30 04:12:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 9 + }, + "473808": { + "ID": "473808", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Sim Wings – PANC Ted Stevens Anchorage International Airport v1.0.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4131292721", + "Time": "2022-06-28 02:39:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 15 + }, + "473143": { + "ID": "473143", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "iniBuilds – KBUF Buffalo Niagara International Airport v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1848942308", + "Time": "2022-06-23 04:04:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 21 + }, + "472904": { + "ID": "472904", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSDreamTeam – KEYW Key West International Airport v1.3.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "191674823", + "Time": "2022-06-21 06:25:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 14 + }, + "472543": { + "ID": "472543", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "PhotoSimLabs – St. Croix Island & TISX Henry E. Rohlsen Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1231927224", + "Time": "2022-06-18 08:53:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 18 + }, + "471685": { + "ID": "471685", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Final Approach Simulations – MKJS Sangster International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "207686098", + "Time": "2022-06-14 10:19:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "470903": { + "ID": "470903", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Final Approach Simulations – KEWR Newark Liberty International Airport v1.3.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "171785659", + "Time": "2022-06-09 19:55:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 13 + }, + "470899": { + "ID": "470899", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "WingSim – MKJP Norman Manley International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "471443054", + "Time": "2022-06-09 19:53:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 15 + }, + "470898": { + "ID": "470898", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FeelThere – KLAX Los Angeles International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1352530073", + "Time": "2022-06-09 19:52:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 19 + }, + "470887": { + "ID": "470887", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Stealthy Duck – KTVL Lake Tahoe Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "332139247", + "Time": "2022-06-09 19:46:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 16 + }, + "469918": { + "ID": "469918", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Orbx – KBOI Boise Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1944443980", + "Time": "2022-06-05 04:48:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 18 + }, + "468486": { + "ID": "468486", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Xometry Design – KVCV Victorville \/ Southern California Logistics Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1731552805", + "Time": "2022-06-01 11:23:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 14 + }, + "468117": { + "ID": "468117", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "UK2000 Scenery – KGYY Gary\/Chicago International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "22095347", + "Time": "2022-05-30 21:04:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 11 + }, + "467432": { + "ID": "467432", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "iniBuilds – 3MI2 South Fox Island Airport & 6Y3 North Fox Island Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "97599951", + "Time": "2022-05-27 20:01:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 11 + }, + "467264": { + "ID": "467264", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Xometry Design – KEGE Eagle County Regional Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1089630348", + "Time": "2022-05-27 00:37:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 16 + }, + "467263": { + "ID": "467263", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Vertical Simulations – KOMA Eppley Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1094669451", + "Time": "2022-05-27 00:35:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 15 + }, + "466426": { + "ID": "466426", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSXcenery – KOAK Oakland International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "119268995", + "Time": "2022-05-24 08:58:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 14 + }, + "466423": { + "ID": "466423", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Magsoft Studios – MMCV Ciudad Victoria International Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "129292447", + "Time": "2022-05-24 08:56:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 11 + }, + "466422": { + "ID": "466422", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Magsoft Studios – MMJC Jorge Jimenez Cantu National Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "49094078", + "Time": "2022-05-24 08:55:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 13 + }, + "465685": { + "ID": "465685", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Sierrasim Simulation – KSYR Syracuse Hancock International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "185235080", + "Time": "2022-05-20 00:55:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 8 + }, + "465681": { + "ID": "465681", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Fly 2 High – KRSW Southwest Florida International Airport v1.0.0 (Update 1)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2991117026", + "Time": "2022-05-20 00:52:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 17 + }, + "465361": { + "ID": "465361", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Orbx – KBUR Hollywood Burbank Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "585187851", + "Time": "2022-05-18 21:40:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 8 + }, + "464969": { + "ID": "464969", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Flightbeam Studios – KPDX Portland International Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2829221529", + "Time": "2022-05-17 10:21:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 18 + }, + "462064": { + "ID": "462064", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FeelThere – KRDU Raleigh–Durham International Airport v1.7.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1949341174", + "Time": "2022-05-08 05:57:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 19 + }, + "461607": { + "ID": "461607", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Macco Simulations – MMUN Cancun International Airport v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1045393875", + "Time": "2022-05-05 05:28:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 22 + }, + "461496": { + "ID": "461496", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FlyTampa – KBOS General Edward Lawrence Logan International \/ Boston Logan Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "663584462", + "Time": "2022-05-04 03:43:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 17 + }, + "461495": { + "ID": "461495", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FeelThere – KLGA LaGuardia Airport v1.7.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "443571218", + "Time": "2022-05-04 03:42:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 17 + }, + "461494": { + "ID": "461494", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Just Flight – KSBP San Luis Obispo County Regional Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "401282015", + "Time": "2022-05-04 03:41:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 15 + }, + "461493": { + "ID": "461493", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Vertical Simulations – KORF Norfolk International Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "308871682", + "Time": "2022-05-04 03:41:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 14 + }, + "460648": { + "ID": "460648", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSDreamTeam – CYVR Vancouver International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "157351098", + "Time": "2022-04-27 11:09:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 16 + }, + "460647": { + "ID": "460647", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Vertical Simulations – KMYR Myrtle Beach International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "617094469", + "Time": "2022-04-27 11:09:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 15 + }, + "460375": { + "ID": "460375", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Orbx – KCRW West Virginia International Yeager Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1706549212", + "Time": "2022-04-25 19:49:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 19 + }, + "460366": { + "ID": "460366", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSDreamTeam – KORD O’Hare International Airport v1.3.0 (New Build 5)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "375589636", + "Time": "2022-04-25 19:35:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 19 + }, + "459984": { + "ID": "459984", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSimStudios – CYTZ Billy Bishop Toronto City Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1233068035", + "Time": "2022-04-23 05:15:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 20 + }, + "459596": { + "ID": "459596", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Flight FX – KPWK Chicago Executive Airport v1.6.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1346783796", + "Time": "2022-04-21 04:11:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 23 + }, + "459595": { + "ID": "459595", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Northern Sky Studio – HI01 Princeville Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "503040106", + "Time": "2022-04-21 04:11:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 16 + }, + "458295": { + "ID": "458295", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Final Approach Simulations – TBPB Grantley Adams International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "87491585", + "Time": "2022-04-13 06:45:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 20 + }, + "458287": { + "ID": "458287", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Northern Sky Studio – PHOG Kahului Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1643453218", + "Time": "2022-04-13 06:40:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 22 + }, + "456966": { + "ID": "456966", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Centralsim – TJBQ Rafael Hernandez International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "913794649", + "Time": "2022-04-06 12:31:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 19 + }, + "456340": { + "ID": "456340", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Airworthy Designs – TNCM Princess Juliana & TFFG Grand Case Airport v1.5.0 - DLC", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "544142454", + "Time": "2022-04-03 10:29:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 25 + }, + "455797": { + "ID": "455797", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Orbx – KTIW Tacoma Narrows Airport v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "275444662", + "Time": "2022-03-31 16:01:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 17 + }, + "453774": { + "ID": "453774", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FlyTampa – CYYZ Toronto Pearson International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1544784014", + "Time": "2022-03-24 07:03:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 26 + }, + "453768": { + "ID": "453768", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Northern Sky Studio – PAWD Seward Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2240070800", + "Time": "2022-03-24 07:00:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 24 + }, + "451966": { + "ID": "451966", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Vertical Simulations – KDYT Duluth Sky Harbor Airport v1.1.0 (New Build)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "160196249", + "Time": "2022-03-20 12:27:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 17 + }, + "451965": { + "ID": "451965", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Vertical Simulations – KPCM Plant City Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "361380138", + "Time": "2022-03-20 12:27:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 17 + }, + "447254": { + "ID": "447254", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Drzewiecki Design – KRNT Renton Municipal Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1064653302", + "Time": "2022-03-16 10:26:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 26 + }, + "444827": { + "ID": "444827", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "DC Scenery Design – X06 Arcadia Municipal Airport v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "72396497", + "Time": "2022-03-15 09:29:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 22 + }, + "444826": { + "ID": "444826", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "DC Scenery Design – S20 Goldendale Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "59653143", + "Time": "2022-03-15 09:29:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 22 + }, + "444824": { + "ID": "444824", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "DC Scenery Design – PAPG Petersburg James A. Johnson Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "73122293", + "Time": "2022-03-15 09:28:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 21 + }, + "444823": { + "ID": "444823", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "DC Scenery Design – PAKW Klawock Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "124493522", + "Time": "2022-03-15 09:27:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 22 + }, + "444822": { + "ID": "444822", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "DC Scenery Design – PACV Merle K. (Mudhole) Smith Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "476694610", + "Time": "2022-03-15 09:27:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 22 + }, + "444821": { + "ID": "444821", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "DC Scenery Design – KTBR Statesboro–Bulloch County Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "135697797", + "Time": "2022-03-15 09:26:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 20 + }, + "444820": { + "ID": "444820", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "DC Scenery Design – FD48 Deep Forest Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "76431394", + "Time": "2022-03-15 09:25:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 23 + }, + "444814": { + "ID": "444814", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Flight Simulator World Sceneries – KCUT Custer County Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "132468239", + "Time": "2022-03-15 09:21:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 22 + }, + "444813": { + "ID": "444813", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "RegDesigns – CZBA Burlington Executive Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1236195756", + "Time": "2022-03-15 09:20:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 23 + }, + "444057": { + "ID": "444057", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "RegDesigns – CYKF Region of Waterloo International Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "637405110", + "Time": "2022-03-10 03:10:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 21 + }, + "444051": { + "ID": "444051", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "LatinVFR – KNKX Marine Corps Air Station Miramar v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "310274996", + "Time": "2022-03-10 03:06:27", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 21 + }, + "444046": { + "ID": "444046", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "RegDesigns – PHLI Lihue Airport v0.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "225455701", + "Time": "2022-03-10 03:02:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 20 + }, + "442743": { + "ID": "442743", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "RegDesigns – CNC4 Guelph Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1251719729", + "Time": "2022-03-03 18:54:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 28 + }, + "442287": { + "ID": "442287", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Flightbeam Studios – KIAD Washington Dulles International Airport v1.1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2264240570", + "Time": "2022-03-01 08:58:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 34 + }, + "442286": { + "ID": "442286", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Orbx – KEYW Key West International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "435417501", + "Time": "2022-03-01 08:57:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 30 + }, + "442063": { + "ID": "442063", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Dreamflight Studios – KCRQ McClellan–Palomar Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "553334351", + "Time": "2022-02-28 04:10:24", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 28 + }, + "442059": { + "ID": "442059", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSXcenery – KRFD Chicago Rockford International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "18367263", + "Time": "2022-02-28 04:08:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 33 + }, + "442058": { + "ID": "442058", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FlyMex Software – MMCZ Cozumel International Airport v1.1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "11562156", + "Time": "2022-02-28 04:08:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 31 + }, + "441999": { + "ID": "441999", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSXcenery – KMOT Minot International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "96197540", + "Time": "2022-02-27 13:39:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 30 + }, + "441989": { + "ID": "441989", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSXcenery – KORL Orlando Executive Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "14915707", + "Time": "2022-02-27 13:33:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 29 + }, + "441985": { + "ID": "441985", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Skyline Simulations – KAST Astoria Regional Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1154616223", + "Time": "2022-02-27 13:30:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 20 + }, + "439517": { + "ID": "439517", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSXcenery – KHSV Huntsville International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "85648717", + "Time": "2022-02-22 02:01:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 28 + }, + "438900": { + "ID": "438900", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSXcenery – KGRR Gerald R. Ford International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "33890346", + "Time": "2022-02-21 10:33:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 29 + }, + "438897": { + "ID": "438897", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSXcenery – KGSO Piedmont Triad International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "111249349", + "Time": "2022-02-21 10:32:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 32 + }, + "438887": { + "ID": "438887", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "PILOT’S FSG – KCDK George T. Lewis \/ Cedar Key Airport v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2811911587", + "Time": "2022-02-21 10:29:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 32 + }, + "438883": { + "ID": "438883", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSXcenery – KGTF Great Falls International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "34399202", + "Time": "2022-02-21 10:27:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 25 + }, + "430495": { + "ID": "430495", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSXcenery – KECP Northwest Florida Beaches International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "72287638", + "Time": "2022-02-15 02:00:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 34 + }, + "430487": { + "ID": "430487", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSXcenery – KFSD Sioux Falls Regional Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "47835043", + "Time": "2022-02-15 01:57:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 30 + }, + "429265": { + "ID": "429265", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSXcenery – KDLH Duluth International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "81875098", + "Time": "2022-02-12 20:15:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 28 + }, + "429115": { + "ID": "429115", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Jeppeson2001 – KFFZ Falcon Field Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "351290741", + "Time": "2022-02-11 15:50:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 25 + }, + "428673": { + "ID": "428673", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "TropicalSim – KOMA Eppley Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "110062714", + "Time": "2022-02-08 03:23:22", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 29 + }, + "428599": { + "ID": "428599", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSimStudios – CYLW Kelowna International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3138965680", + "Time": "2022-02-07 17:51:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 31 + }, + "428036": { + "ID": "428036", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSimStudios – CYVR Vancouver International Airport v1.2.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4080195578", + "Time": "2022-02-05 03:46:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 30 + }, + "427902": { + "ID": "427902", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSimStudios – CYHZ Halifax Stanfield International Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4323948979", + "Time": "2022-02-03 22:52:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 37 + }, + "425776": { + "ID": "425776", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Flightbeam Studios – KDEN Denver International Airport v1.0.8", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "919105039", + "Time": "2022-01-24 03:43:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 39 + }, + "421678": { + "ID": "421678", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Drzewiecki Design – KMDW Chicago Midway International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1588699461", + "Time": "2022-01-01 20:06:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 41 + }, + "421182": { + "ID": "421182", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "DC Scenery Design – PAWG Wrangell Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "60959693", + "Time": "2021-12-31 06:27:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 22, + "Leechers": 0, + "Snatched": 57 + }, + "418562": { + "ID": "418562", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Northern Sky Studio – PHMU Waimea–Kohala Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1328945518", + "Time": "2021-12-24 01:39:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 64 + }, + "418555": { + "ID": "418555", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Axonos – KPSP Palm Springs International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "481283771", + "Time": "2021-12-24 01:30:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 25, + "Leechers": 0, + "Snatched": 65 + }, + "417360": { + "ID": "417360", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Vertical Simulations – KGSP Greenville Spartanburg International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "160791711", + "Time": "2021-12-15 02:49:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 63 + }, + "417359": { + "ID": "417359", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Vertical Simulations – KFAY Fayetteville Regional Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "629711468", + "Time": "2021-12-15 02:48:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 61 + }, + "417358": { + "ID": "417358", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSDreamTeam – KCLT Charlotte Douglas International Airport v1.0.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "649614800", + "Time": "2021-12-15 02:48:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 69 + }, + "416320": { + "ID": "416320", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Vref Simulations – KGPI Glacier Park International Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "430010806", + "Time": "2021-12-07 00:56:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 67 + }, + "416317": { + "ID": "416317", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Vref Simulations – KHVN Tweed New Haven Airport v2.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "326713257", + "Time": "2021-12-07 00:44:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 69 + }, + "416314": { + "ID": "416314", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSXcenery – KBTV Burlington International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "94571064", + "Time": "2021-12-07 00:39:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 78 + }, + "416127": { + "ID": "416127", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "LatinVFR – TJSJ Luis Munoz Marin International Airport v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "420921750", + "Time": "2021-12-06 04:06:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 75 + }, + "416121": { + "ID": "416121", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Landing Area Scenery Design – KJZP Pickens County Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "108851156", + "Time": "2021-12-06 04:02:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 84 + }, + "415875": { + "ID": "415875", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "CanadianFlightSimStudios – CYAZ Tofino\/Long Beach Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "980502188", + "Time": "2021-12-04 00:06:01", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 23, + "Leechers": 0, + "Snatched": 71 + }, + "415873": { + "ID": "415873", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "MP Scenery – KHAF Half Moon Bay Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "193903752", + "Time": "2021-12-03 23:59:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 71 + }, + "415866": { + "ID": "415866", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Vref Simulations – KMTP Montauk Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "120538503", + "Time": "2021-12-03 23:54:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 75 + }, + "415863": { + "ID": "415863", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Taburet – Central America and Caribbean Roads v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "35426262", + "Time": "2021-12-03 23:53:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 75 + }, + "415648": { + "ID": "415648", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Orbx – KAVX Catalina Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "5570729521", + "Time": "2021-12-03 02:47:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 22, + "Leechers": 0, + "Snatched": 81 + }, + "415646": { + "ID": "415646", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Northern Sky Studio – PHJH Kapalua Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "687319822", + "Time": "2021-12-03 02:38:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 71 + }, + "415453": { + "ID": "415453", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "CanadianFlightSimStudios – CAK3 Delta Heritage Air Park v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1076477946", + "Time": "2021-11-30 23:29:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 79 + }, + "415439": { + "ID": "415439", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Orbx – 1WA6 Fall City Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "86040047", + "Time": "2021-11-30 22:56:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 74 + }, + "415438": { + "ID": "415438", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Orbx – S45 Siletz Bay State Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "100596730", + "Time": "2021-11-30 22:56:30", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 75 + }, + "415004": { + "ID": "415004", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Just Flight – KSZP Santa Paula Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "283135887", + "Time": "2021-11-26 07:43:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 25, + "Leechers": 0, + "Snatched": 72 + }, + "412952": { + "ID": "412952", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "TropicalSim – TNCC Curacao \/ Hato International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "266210007", + "Time": "2021-11-15 00:38:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 78 + }, + "410781": { + "ID": "410781", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "SamScene – New York City Times v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "580734275", + "Time": "2021-11-09 22:16:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 85 + }, + "408835": { + "ID": "408835", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Project MAX – CYZF Yellowknife Airport v0.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "45749524", + "Time": "2021-11-02 07:43:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 97 + }, + "408141": { + "ID": "408141", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "South Oak Co – PHNY Lanai Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1380330547", + "Time": "2021-10-30 05:59:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 99 + }, + "408140": { + "ID": "408140", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "South Oak Co – PHPA Port Allen Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "231164333", + "Time": "2021-10-30 05:59:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 89 + }, + "408139": { + "ID": "408139", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "South Oak Co – PHLU Kalaupapa Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "74446833", + "Time": "2021-10-30 05:58:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 91 + }, + "408138": { + "ID": "408138", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "South Oak Co – PHHN Hana Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "449913441", + "Time": "2021-10-30 05:58:27", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 91 + }, + "408136": { + "ID": "408136", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "South Oak Co – PHDH Dillingham Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "853029980", + "Time": "2021-10-30 05:57:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 25, + "Leechers": 0, + "Snatched": 86 + }, + "407611": { + "ID": "407611", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Magsoft Studios – MMMY Monterrey International Airport Airport v2.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "571033119", + "Time": "2021-10-26 00:35:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 97 + }, + "405911": { + "ID": "405911", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "PacSim – KCLE Cleveland Hopkins International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "78672230", + "Time": "2021-10-17 08:58:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 107 + }, + "405593": { + "ID": "405593", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Gaya Simulations – KBID Block Island State Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "263724290", + "Time": "2021-10-14 06:09:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 110 + }, + "404576": { + "ID": "404576", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Orbx – KSBA Santa Barbara Municipal Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "77070820", + "Time": "2021-10-07 00:41:22", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 38, + "Leechers": 0, + "Snatched": 118 + }, + "403962": { + "ID": "403962", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Imagine Simulation – KATL Hartsfield–Jackson Atlanta International Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "264996021", + "Time": "2021-10-02 02:51:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 38, + "Leechers": 0, + "Snatched": 116 + }, + "403811": { + "ID": "403811", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "LatinVFR – KFLL Fort Lauderdale–Hollywood International Airport v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "668577945", + "Time": "2021-10-01 04:01:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 115 + }, + "403807": { + "ID": "403807", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "LatinVFR – KMIA Miami International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "698524844", + "Time": "2021-10-01 04:00:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 121 + }, + "403379": { + "ID": "403379", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FeelThere – TIST Cyril E. King Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "769058896", + "Time": "2021-09-28 00:54:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 113 + }, + "401893": { + "ID": "401893", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Roman Design – CYKZ Toronto\/Buttonville Municipal Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "90876270", + "Time": "2021-09-16 04:14:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 121 + }, + "401892": { + "ID": "401892", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Roman Design – CNC3 Brampton–Caledon Airport v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "108350867", + "Time": "2021-09-16 04:13:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 35, + "Leechers": 0, + "Snatched": 122 + }, + "401160": { + "ID": "401160", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSDG – TLPL Hewanorra International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "142320324", + "Time": "2021-09-11 23:17:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 41, + "Leechers": 0, + "Snatched": 133 + }, + "401159": { + "ID": "401159", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSXcenery – KPIE St. Pete–Clearwater International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "26536102", + "Time": "2021-09-11 23:16:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 39, + "Leechers": 0, + "Snatched": 137 + }, + "401157": { + "ID": "401157", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Roman Design – CYOW Ottawa Macdonald–Cartier International Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "348776404", + "Time": "2021-09-11 23:15:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 127 + }, + "399536": { + "ID": "399536", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Terrapearl Studios – 11S Sekiu Airport v1.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "624564652", + "Time": "2021-09-05 07:39:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 132 + }, + "399378": { + "ID": "399378", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "4Simmers – KEKA Murray Field Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "935623656", + "Time": "2021-09-04 04:48:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 36, + "Leechers": 0, + "Snatched": 126 + }, + "398885": { + "ID": "398885", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Orbx – PAKT Ketchikan International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "150960549", + "Time": "2021-09-01 22:19:24", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 39, + "Leechers": 0, + "Snatched": 127 + }, + "397311": { + "ID": "397311", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "TropicalSim – MDPC Punta Cana International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "88950574", + "Time": "2021-08-26 15:54:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 41, + "Leechers": 0, + "Snatched": 138 + }, + "396540": { + "ID": "396540", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "LD Improvement – SBSP Sao Paulo–Congonhas Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "17294952", + "Time": "2021-08-22 03:28:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 44, + "Leechers": 0, + "Snatched": 147 + }, + "394912": { + "ID": "394912", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "LatinVFR – KMSY Louis Armstrong New Orleans International Airport v1.0.5", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "614528720", + "Time": "2021-08-11 13:16:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 40, + "Leechers": 0, + "Snatched": 140 + }, + "394910": { + "ID": "394910", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Northern Sky Studio – PAKT Ketchikan International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1208581581", + "Time": "2021-08-11 13:15:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 41, + "Leechers": 0, + "Snatched": 145 + }, + "394909": { + "ID": "394909", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Northern Sky Studio – PATK Talkeetna Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1570167163", + "Time": "2021-08-11 13:14:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 145 + }, + "394908": { + "ID": "394908", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Northern Sky Studio – PAEN Kenai Municipal Airport v0.1.14", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2852140578", + "Time": "2021-08-11 13:13:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 35, + "Leechers": 0, + "Snatched": 144 + }, + "394906": { + "ID": "394906", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "PacSim – KRNO Reno–Tahoe International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "105032272", + "Time": "2021-08-11 13:12:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 44, + "Leechers": 0, + "Snatched": 153 + }, + "394563": { + "ID": "394563", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "4Simmers – KEKA Murray Field Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "966678169", + "Time": "2021-08-09 03:04:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 42, + "Leechers": 0, + "Snatched": 137 + }, + "394562": { + "ID": "394562", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Axonos – KJAC Jackson Hole Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "728043550", + "Time": "2021-08-09 03:04:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 42, + "Leechers": 0, + "Snatched": 142 + }, + "394510": { + "ID": "394510", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "4Simmers – KLXV Lake County Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "206206370", + "Time": "2021-08-08 19:39:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 43, + "Leechers": 0, + "Snatched": 143 + }, + "394100": { + "ID": "394100", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSDreamTeam – KSDF Louisville Muhammad Ali International Airport v1.0.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "314894790", + "Time": "2021-08-06 10:01:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 46, + "Leechers": 0, + "Snatched": 148 + }, + "391534": { + "ID": "391534", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Orbx - KVNY Van Nuys Airport v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "506728624", + "Time": "2021-07-31 05:33:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 45, + "Leechers": 0, + "Snatched": 154 + }, + "390581": { + "ID": "390581", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Realworld Scenery - KSTL St. Louis Lambert International Airport v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3059890459", + "Time": "2021-07-26 21:42:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 43, + "Leechers": 0, + "Snatched": 166 + }, + "390569": { + "ID": "390569", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Vertical Simulations - KSRQ Sarasota-Bradenton International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "827864438", + "Time": "2021-07-26 20:38:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 43, + "Leechers": 0, + "Snatched": 156 + }, + "390566": { + "ID": "390566", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Vertical Simulations - KTPF Peter O. Knight Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "508993430", + "Time": "2021-07-26 20:25:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 43, + "Leechers": 0, + "Snatched": 149 + }, + "390565": { + "ID": "390565", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Realworldscenery - PAUN Unalakleet Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "234006443", + "Time": "2021-07-26 20:19:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 45, + "Leechers": 0, + "Snatched": 155 + }, + "389324": { + "ID": "389324", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "LatinVFR – KBDL Bradley International Airport v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "708121028", + "Time": "2021-07-23 05:45:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 43, + "Leechers": 0, + "Snatched": 148 + }, + "388693": { + "ID": "388693", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Skyline Simulations – KLGB Long Beach Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1982695641", + "Time": "2021-07-20 17:11:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 41, + "Leechers": 0, + "Snatched": 166 + }, + "387260": { + "ID": "387260", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "TropicalSim – TAPA V. C. Bird International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "50813464", + "Time": "2021-07-14 21:17:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 48, + "Leechers": 0, + "Snatched": 151 + }, + "381338": { + "ID": "381338", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Dreamflight Studios – KTEB Teterboro Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "935407215", + "Time": "2021-06-23 23:30:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 46, + "Leechers": 0, + "Snatched": 164 + }, + "381323": { + "ID": "381323", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Guillermo Zulueta – KCGX Merrill C. Meigs Field Airport v2.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "117966827", + "Time": "2021-06-23 23:11:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 53, + "Leechers": 0, + "Snatched": 170 + }, + "381306": { + "ID": "381306", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Orbx – CYBD Bella Coola Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "114010953", + "Time": "2021-06-23 22:45:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 48, + "Leechers": 0, + "Snatched": 398 + }, + "381107": { + "ID": "381107", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Aerosoft – TNCB Flamingo–Bonaire International Airport v1.0.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "967105334", + "Time": "2021-06-23 13:24:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 48, + "Leechers": 0, + "Snatched": 155 + }, + "381045": { + "ID": "381045", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Aerosoft – CYQM Greater Moncton Roméo LeBlanc International Airport v1.1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2487439297", + "Time": "2021-06-23 11:54:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 48, + "Leechers": 0, + "Snatched": 168 + }, + "381022": { + "ID": "381022", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSDG – SPZO Alejandro Velasco Astete International Airport \/ Cusco v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "252257619", + "Time": "2021-06-23 11:26:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 49, + "Leechers": 0, + "Snatched": 158 + }, + "381018": { + "ID": "381018", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Realworld Scenery – PAOM Nome Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "165677121", + "Time": "2021-06-23 11:23:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 49, + "Leechers": 0, + "Snatched": 171 + }, + "380996": { + "ID": "380996", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Final Approach Simulations – TTPP TTCP TGPY Caribbean Airports Vol. 1 v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "52430917", + "Time": "2021-06-23 10:50:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 55, + "Leechers": 0, + "Snatched": 186 + }, + "380951": { + "ID": "380951", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FS - MMAN Del Norte INTL + Monterreu City Landmarks v1.1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "89455795", + "Time": "2021-06-23 08:06:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 52, + "Leechers": 0, + "Snatched": 173 + }, + "351753": { + "ID": "351753", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "DC Scenery Design - KMNE Minden-Webster v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "102482483", + "Time": "2021-02-24 23:32:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 70, + "Leechers": 0, + "Snatched": 276 + }, + "347328": { + "ID": "347328", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Orbx - KORS Orcas Island Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "815546069", + "Time": "2021-02-12 22:11:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 65, + "Leechers": 0, + "Snatched": 287 + }, + "343502": { + "ID": "343502", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "ORBX - KHVN Tweed New Haven Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "107237139", + "Time": "2021-01-23 09:50:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 78, + "Leechers": 0, + "Snatched": 314 + }, + "342609": { + "ID": "342609", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSXScenery - KPBI West Palm Beach International Airport v1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "17175524", + "Time": "2021-01-20 10:49:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 85, + "Leechers": 0, + "Snatched": 347 + }, + "340690": { + "ID": "340690", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FSXScenery - KAPF Naples Municipal Airport v1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "48996411", + "Time": "2021-01-12 02:23:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 78, + "Leechers": 0, + "Snatched": 355 + }, + "338983": { + "ID": "338983", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Realworldscenery - PADQ Kodiak Airport v1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "471772549", + "Time": "2021-01-04 10:35:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 69, + "Leechers": 0, + "Snatched": 327 + }, + "332804": { + "ID": "332804", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "ORBX - KSJC San Jose International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "602302379", + "Time": "2020-12-09 02:00:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 78, + "Leechers": 0, + "Snatched": 348 + }, + "331836": { + "ID": "331836", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "ORBX - 3W5 Concrete Municipal Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "480970491", + "Time": "2020-12-06 02:55:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 71, + "Leechers": 0, + "Snatched": 328 + }, + "331212": { + "ID": "331212", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "Verticalsim - KCLW Clearwater Air Park v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "342329281", + "Time": "2020-12-03 12:48:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 73, + "Leechers": 0, + "Snatched": 336 + }, + "314416": { + "ID": "314416", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "ORBX - KBCE Bryce Canyon Airport v1.0.0 - DLC", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1449053483", + "Time": "2020-10-04 12:33:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 79, + "Leechers": 0, + "Snatched": 407 + }, + "312628": { + "ID": "312628", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "FLYT Simulations - C16 FRASCA FIELD v1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1686809662", + "Time": "2020-09-30 12:50:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 76, + "Leechers": 0, + "Snatched": 400 + }, + "312599": { + "ID": "312599", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - North America", + "Scene": "0", + "ReleaseTitle": "ORBX - 1S2 Darrington Municipal Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "280062097", + "Time": "2020-09-30 09:36:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 74, + "Leechers": 0, + "Snatched": 366 + }, + "478784": { + "ID": "478784", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "TEIKOF Studio – SKCL Alfonso Bonilla Aragon International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "168192695", + "Time": "2022-07-20 09:56:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 3, + "Leechers": 0, + "Snatched": 6 + }, + "478217": { + "ID": "478217", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "LushoDev – SCAR Chacalluta International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "240613389", + "Time": "2022-07-17 07:48:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 8 + }, + "478213": { + "ID": "478213", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "V Pilot Designs – SKBO El Dorado International Airport v0.1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "400362367", + "Time": "2022-07-17 07:45:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 8 + }, + "476895": { + "ID": "476895", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Sierrasim Simulation – MHLM La Mesa \/ Ramon Villeda Morales International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "597014620", + "Time": "2022-07-11 07:44:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 9 + }, + "476893": { + "ID": "476893", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "TEIKOF Studio – SKCL Alfonso Bonilla Aragon International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "152371969", + "Time": "2022-07-11 07:43:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 7 + }, + "475473": { + "ID": "475473", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "DominicDesignTeam – SPJC Jorge Chavez International Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1107367019", + "Time": "2022-07-04 07:00:03", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 11 + }, + "473806": { + "ID": "473806", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "TEIKOF Studio – SKPE Matecana International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "116003942", + "Time": "2022-06-28 02:38:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 7 + }, + "472764": { + "ID": "472764", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "FlightSimChile – SCCH General Bernardo O’Higgins Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "18188", + "Time": "2022-06-20 05:55:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 10 + }, + "472547": { + "ID": "472547", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Exabit – SBSV Salvador International Airport v2.2.7", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "427074656", + "Time": "2022-06-18 08:56:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 12 + }, + "472546": { + "ID": "472546", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "RmStudios – SBJD Comte. Rolim Adolfo Amaro State Airport v3.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "281956218", + "Time": "2022-06-18 08:55:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 11 + }, + "471399": { + "ID": "471399", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "GearDown Simulations – SWPI Parintins Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "97186318", + "Time": "2022-06-12 10:45:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 16 + }, + "471398": { + "ID": "471398", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Exabit – SIRI Barra Grande Airport v0.2.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "111247673", + "Time": "2022-06-12 10:45:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 16 + }, + "471396": { + "ID": "471396", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "FlightSimChile – SCGZ Guardia Marina Zanartu Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "86044497", + "Time": "2022-06-12 10:44:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 16 + }, + "471071": { + "ID": "471071", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "TropicalSim – SAEZ Ministro Pistarini \/ Ezeiza International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "149978766", + "Time": "2022-06-11 01:41:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 13 + }, + "471069": { + "ID": "471069", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "FlyMex Software – MMMX Mexico City International Airport v1.0.5", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "240544630", + "Time": "2022-06-11 01:40:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 13 + }, + "470886": { + "ID": "470886", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "PortalFrame – MSLP El Salvador International Airport & MSSS Ilopango Airport v0.1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "635059815", + "Time": "2022-06-09 19:45:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 14 + }, + "469925": { + "ID": "469925", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "VirtualDesign3d – Santiago Chile City v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "36690073", + "Time": "2022-06-05 04:51:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "469919": { + "ID": "469919", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Exabit – SNCL Lorenzo Airport v0.2.5", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "454140720", + "Time": "2022-06-05 04:49:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 13 + }, + "469773": { + "ID": "469773", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Sierrasim Simulation – MHPR Palmerola \/ Comayagua International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1086688001", + "Time": "2022-06-04 18:32:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 15 + }, + "468487": { + "ID": "468487", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "FlightSimChile – SCAT Desierto De Atacama Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "122638472", + "Time": "2022-06-01 11:24:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 9 + }, + "468382": { + "ID": "468382", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "GearDown Simulations – SNIH Fazenda Rio Negro Airport v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "174331298", + "Time": "2022-05-31 22:23:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 8 + }, + "467434": { + "ID": "467434", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "PKSIM – SVMI Maiquetia Simon Bolivar International Airport \/ Caracas v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "267842328", + "Time": "2022-05-27 20:02:30", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 9 + }, + "467260": { + "ID": "467260", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "VirtualDesign3d – SCTB Eulogio Sanchez \/ Tobalaba Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "65652396", + "Time": "2022-05-27 00:32:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 9 + }, + "465817": { + "ID": "465817", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Magsoft Studios – MMGL Guadalajara International Airport v3.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "629496283", + "Time": "2022-05-21 01:10:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 9 + }, + "465365": { + "ID": "465365", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "RmStudios – SBAE Bauru\/Arealva–Moussa Nakhal Tobias State Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "95609867", + "Time": "2022-05-18 21:42:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 8 + }, + "463944": { + "ID": "463944", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Sierrasim Simulation – SKPS Antonio Narino Airport v1.3.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "62660346", + "Time": "2022-05-14 23:10:30", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 3, + "Leechers": 0, + "Snatched": 8 + }, + "463005": { + "ID": "463005", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Centralsim – SABE Jorge Newbery Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "172601326", + "Time": "2022-05-13 05:53:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 10 + }, + "462054": { + "ID": "462054", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Sierrasim Simulation – SLAL Alcantari International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2550713650", + "Time": "2022-05-08 05:51:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 15 + }, + "461610": { + "ID": "461610", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "PKSIM – SKBQ Ernesto Cortissoz International Airport \/ Barranquilla v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1158710050", + "Time": "2022-05-05 05:30:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 22 + }, + "461608": { + "ID": "461608", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Sierrasim Simulation – MGGT La Aurora International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "879017678", + "Time": "2022-05-05 05:29:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 14 + }, + "461489": { + "ID": "461489", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Dreamflight Studios – MDPP Gregorio Luperon International \/ Puerto Plata Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "203090964", + "Time": "2022-05-04 03:35:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 20 + }, + "461488": { + "ID": "461488", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Centralsim – MPPA Panama Pacifico International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1698246258", + "Time": "2022-05-04 03:35:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 23 + }, + "455745": { + "ID": "455745", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "EB Cenarios – SBAR Aracaju–Santa Maria International Airport v0.3.6", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "36837283", + "Time": "2022-03-31 08:13:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 23 + }, + "442320": { + "ID": "442320", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – SCBA Balmaceda Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "106107001", + "Time": "2022-03-01 15:27:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 24 + }, + "440173": { + "ID": "440173", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – SAWH Malvinas Argentinas Ushuaia International Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "341672420", + "Time": "2022-02-23 00:43:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 26 + }, + "440172": { + "ID": "440172", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "FSXcenery – SYCJ Cheddi Jagan International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "52870181", + "Time": "2022-02-23 00:42:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 25 + }, + "438890": { + "ID": "438890", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – SCTE El Tepual Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "252020136", + "Time": "2022-02-21 10:30:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 27 + }, + "438889": { + "ID": "438889", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – SCQP La Araucania International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "222496341", + "Time": "2022-02-21 10:30:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 29 + }, + "438884": { + "ID": "438884", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "TropicalSim – LPPR Francisco Sa Carneiro \/ Porto Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "107235287", + "Time": "2022-02-21 10:28:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 26 + }, + "430482": { + "ID": "430482", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "VueloSimple – SAME El Plumerillo International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "39996630", + "Time": "2022-02-15 01:56:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 29 + }, + "430478": { + "ID": "430478", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – SCDA Diego Aracena International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "76640959", + "Time": "2022-02-15 01:54:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 30 + }, + "429106": { + "ID": "429106", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "FSoares – SBVC Glauber Rocha\/Vitoria da Conquista Airport v1.3.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "627381258", + "Time": "2022-02-11 15:44:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 28 + }, + "427384": { + "ID": "427384", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazil Land Games - SBMG Silvio Name Junior Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "139397937", + "Time": "2022-02-01 13:20:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 28 + }, + "423477": { + "ID": "423477", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "TDM Scenery Design – SVSO Mayor Buenaventura Vivas Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "454572737", + "Time": "2022-01-09 05:31:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 33 + }, + "422572": { + "ID": "422572", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – SCCI Presidente Carlos Ibanez International Airport v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "189189480", + "Time": "2022-01-05 22:35:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 40 + }, + "421963": { + "ID": "421963", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "GearDown Simulations – SBTV Terravista Airport v2.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "142841333", + "Time": "2022-01-03 00:08:30", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 35 + }, + "421193": { + "ID": "421193", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Voo Simulado Brasil – SBBI Bacacheri Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "285815865", + "Time": "2021-12-31 06:29:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 48 + }, + "421175": { + "ID": "421175", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Cmte Pena – SNQV Curvelo Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "389739255", + "Time": "2021-12-31 06:26:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 22, + "Leechers": 0, + "Snatched": 54 + }, + "418557": { + "ID": "418557", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "RmStudios – SDAG Angra dos Reis Airport v3.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "52367049", + "Time": "2021-12-24 01:31:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 22, + "Leechers": 0, + "Snatched": 57 + }, + "417917": { + "ID": "417917", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "GearDown Simulations – SNDT Juscelino Kubitschek Airport v1.0.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1201098759", + "Time": "2021-12-19 19:32:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 23, + "Leechers": 0, + "Snatched": 67 + }, + "417915": { + "ID": "417915", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "GearDown Simulations – SNCT Ubaporanga Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "76103009", + "Time": "2021-12-19 19:29:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 61 + }, + "417610": { + "ID": "417610", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "RmStudios – SBBP Arthur Siqueira State Airport v1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "150708992", + "Time": "2021-12-17 07:51:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 62 + }, + "417094": { + "ID": "417094", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "V1 Studio – SJGK Guaratiba Heliport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "59226509", + "Time": "2021-12-12 23:00:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 25, + "Leechers": 0, + "Snatched": 62 + }, + "416313": { + "ID": "416313", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Double T – SKBO El Dorado International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "262403062", + "Time": "2021-12-07 00:39:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 74 + }, + "416123": { + "ID": "416123", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "V1 Studio – SSUB HBR Sao Paulo Heliport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "141711375", + "Time": "2021-12-06 04:03:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 72 + }, + "415643": { + "ID": "415643", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "TropicalSim – SBRJ Santos Dumont Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "173910108", + "Time": "2021-12-03 02:37:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 75 + }, + "415563": { + "ID": "415563", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Paulo Ricardo – SBRJ Santos Dumont Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "506958311", + "Time": "2021-12-02 10:14:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 73 + }, + "414677": { + "ID": "414677", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "FlightSimChile – Chile VFR Pack 1 v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "56031383", + "Time": "2021-11-23 21:45:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 77 + }, + "414676": { + "ID": "414676", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "FlightSimChile – SCSF Victor Lafon Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "56003939", + "Time": "2021-11-23 21:45:03", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 77 + }, + "414675": { + "ID": "414675", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "FlightSimChile – SCVH La Victoria de Chacabuco Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "7257", + "Time": "2021-11-23 21:44:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 90 + }, + "414440": { + "ID": "414440", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "VirtualDesign3d – SCFA Andres Sabella Galvez International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "24997107", + "Time": "2021-11-21 23:49:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 78 + }, + "414148": { + "ID": "414148", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema - SCNT Teniente Julio Gallardo \/ Puerto Natales Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "294609851", + "Time": "2021-11-20 00:55:27", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 79 + }, + "413722": { + "ID": "413722", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – SAZS San Carlos de Bariloche Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "71545661", + "Time": "2021-11-17 11:14:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 25, + "Leechers": 0, + "Snatched": 75 + }, + "413088": { + "ID": "413088", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – SAWG Rio Gallegos International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "128153942", + "Time": "2021-11-15 07:41:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 78 + }, + "412953": { + "ID": "412953", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – SAWC El Calafate \/ Comandante Armando Tola International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "61149268", + "Time": "2021-11-15 00:38:30", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 80 + }, + "411736": { + "ID": "411736", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Sierrasim Simulation – SKBG Palonegro International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "104259707", + "Time": "2021-11-12 06:42:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 82 + }, + "410782": { + "ID": "410782", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "VueloSimple – SAZM Astor Piazzolla International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "58896618", + "Time": "2021-11-09 22:16:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 83 + }, + "409313": { + "ID": "409313", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Pachilabs – SKGY Guaymaral Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "71350758", + "Time": "2021-11-03 21:43:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 90 + }, + "404954": { + "ID": "404954", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "VueloSimple – SAAR Rosario – Islas Malvinas International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "26451178", + "Time": "2021-10-10 00:03:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 109 + }, + "403095": { + "ID": "403095", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBUG Ruben Berta 1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "21438639", + "Time": "2021-09-25 19:26:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 110 + }, + "403094": { + "ID": "403094", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBUL Uberlandia 2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "40181095", + "Time": "2021-09-25 19:26:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 112 + }, + "403093": { + "ID": "403093", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBVT Eurico De Aguiar Salles 2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "18035508", + "Time": "2021-09-25 19:25:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 111 + }, + "403092": { + "ID": "403092", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SSPR Porto Walter 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "625419", + "Time": "2021-09-25 19:24:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 35, + "Leechers": 0, + "Snatched": 121 + }, + "403091": { + "ID": "403091", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SWBC Barcelos 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4500751", + "Time": "2021-09-25 19:24:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 116 + }, + "403090": { + "ID": "403090", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SWHT Humaita 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4819784", + "Time": "2021-09-25 19:23:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 126 + }, + "403089": { + "ID": "403089", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SWLB Labrea 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2636342", + "Time": "2021-09-25 19:22:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 117 + }, + "403088": { + "ID": "403088", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SWMW Maues 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2716607", + "Time": "2021-09-25 19:22:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 114 + }, + "403087": { + "ID": "403087", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SWNK Novo Campo 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "78386", + "Time": "2021-09-25 19:21:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 35, + "Leechers": 0, + "Snatched": 124 + }, + "403086": { + "ID": "403086", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SWNO Nova Olinda Do Norte 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "131497", + "Time": "2021-09-25 19:20:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 126 + }, + "403085": { + "ID": "403085", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SWPI Parintins 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "27063448", + "Time": "2021-09-25 19:19:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 113 + }, + "403083": { + "ID": "403083", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames Brazil Ground Handling 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "6482556", + "Time": "2021-09-25 19:19:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 117 + }, + "403082": { + "ID": "403082", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames Extras Obrigatorios 2.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "27667340", + "Time": "2021-09-25 19:18:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 109 + }, + "403081": { + "ID": "403081", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBJA Jaguaruna 1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "22139036", + "Time": "2021-09-25 19:12:24", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 112 + }, + "403080": { + "ID": "403080", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBRF Recife 3.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "70554185", + "Time": "2021-09-25 19:11:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 106 + }, + "403079": { + "ID": "403079", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBRJ Santos Dumont 1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "43387140", + "Time": "2021-09-25 19:10:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 111 + }, + "403078": { + "ID": "403078", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBRP Ribeirao Preto 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "16924815", + "Time": "2021-09-25 19:10:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 118 + }, + "403077": { + "ID": "403077", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBSL Marechal Cunha Machado 2.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "175133456", + "Time": "2021-09-25 19:09:27", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 110 + }, + "403076": { + "ID": "403076", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBSR Sao Jose Do Rio Preto 1.2.5", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "90195619", + "Time": "2021-09-25 19:08:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 107 + }, + "403075": { + "ID": "403075", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBTE Teresina 1.1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "66696572", + "Time": "2021-09-25 19:07:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 110 + }, + "403074": { + "ID": "403074", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBTT Tabatinga 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "34224614", + "Time": "2021-09-25 19:07:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 115 + }, + "403073": { + "ID": "403073", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBUA Sao Gabriel Da Cachoeira 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "9058824", + "Time": "2021-09-25 19:06:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 121 + }, + "403071": { + "ID": "403071", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBUF Paulo Afonso 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "53863674", + "Time": "2021-09-25 19:05:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 113 + }, + "403070": { + "ID": "403070", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBJE Comte Ariston Pessoa 1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "9694677", + "Time": "2021-09-25 19:00:30", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 120 + }, + "403069": { + "ID": "403069", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBJU Juazeiro Do Norte 1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "15202903", + "Time": "2021-09-25 18:59:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 113 + }, + "403068": { + "ID": "403068", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBJV Joinville 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "111504596", + "Time": "2021-09-25 18:58:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 112 + }, + "403067": { + "ID": "403067", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBKP Viracopos 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "73520631", + "Time": "2021-09-25 18:57:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 112 + }, + "403065": { + "ID": "403065", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBMO Maceio 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "31489510", + "Time": "2021-09-25 18:56:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 108 + }, + "403064": { + "ID": "403064", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBPA Salgado Filho 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "18237241", + "Time": "2021-09-25 18:55:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 111 + }, + "403063": { + "ID": "403063", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBPB Parnaiba 2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "30322845", + "Time": "2021-09-25 18:54:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 108 + }, + "403061": { + "ID": "403061", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBPJ Palmas 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "16663783", + "Time": "2021-09-25 18:54:03", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 109 + }, + "403060": { + "ID": "403060", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBPS Porto Seguro 1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "10066925", + "Time": "2021-09-25 18:53:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 121 + }, + "403059": { + "ID": "403059", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBPV Porto Velho v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "21768896", + "Time": "2021-09-25 18:52:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 108 + }, + "403029": { + "ID": "403029", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SSPG Santos Dumont v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "16492528", + "Time": "2021-09-25 08:53:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 106 + }, + "403028": { + "ID": "403028", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SDCG Senadora Eunice Michiles v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "5548239", + "Time": "2021-09-25 08:52:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 112 + }, + "403027": { + "ID": "403027", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBTU Tucurui v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "13492902", + "Time": "2021-09-25 08:51:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 122 + }, + "403026": { + "ID": "403026", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBTC Una Comandatuba v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "5094756", + "Time": "2021-09-25 08:50:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 116 + }, + "403025": { + "ID": "403025", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBSG Sao Gonzalo Do Amarante v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "928293796", + "Time": "2021-09-25 08:49:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 99 + }, + "403024": { + "ID": "403024", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBMQ Macapa v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "26264943", + "Time": "2021-09-25 08:47:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 113 + }, + "403023": { + "ID": "403023", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames Airport SBLO Londrina v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "32447571", + "Time": "2021-09-25 08:46:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 111 + }, + "403022": { + "ID": "403022", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBKG Campina Grande v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "21034203", + "Time": "2021-09-25 08:45:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 107 + }, + "403021": { + "ID": "403021", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBJP Presidente Castro Pinto v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "55620144", + "Time": "2021-09-25 08:44:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 112 + }, + "403020": { + "ID": "403020", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBIL Ilheus Jorge Amado v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "48590722", + "Time": "2021-09-25 08:43:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 111 + }, + "403019": { + "ID": "403019", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBHT Altamira v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "298839654", + "Time": "2021-09-25 08:42:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 103 + }, + "403018": { + "ID": "403018", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBFZ Fortaleza v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "101549551", + "Time": "2021-09-25 08:41:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 108 + }, + "403017": { + "ID": "403017", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBFL Florianopolis v1.0.6", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "362638375", + "Time": "2021-09-25 08:40:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 106 + }, + "403016": { + "ID": "403016", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBFI Foz Do Iguacu v2.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "18918191", + "Time": "2021-09-25 08:39:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 114 + }, + "403015": { + "ID": "403015", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBEG Manaus v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "33244511", + "Time": "2021-09-25 08:38:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 114 + }, + "403011": { + "ID": "403011", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBCZ Cruzeiro Do Sul v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "11833383", + "Time": "2021-09-25 08:31:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 116 + }, + "403010": { + "ID": "403010", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBCX Caxias Do Sul v2.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "10607631", + "Time": "2021-09-25 08:30:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 120 + }, + "403008": { + "ID": "403008", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBCH Serafin Enoss Bertaso v2.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "46928056", + "Time": "2021-09-25 08:28:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 116 + }, + "403007": { + "ID": "403007", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBCF Belo Horizonte v2.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "166125229", + "Time": "2021-09-25 08:27:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 108 + }, + "403006": { + "ID": "403006", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBBV Boa Vista v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "38105973", + "Time": "2021-09-25 08:26:22", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 114 + }, + "403005": { + "ID": "403005", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames - SBBG Comandante Gustavo Kraemer v1.2.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "15001508", + "Time": "2021-09-25 08:25:24", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 114 + }, + "403004": { + "ID": "403004", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames SBBE Val De Cans v3.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "123810322", + "Time": "2021-09-25 08:24:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 110 + }, + "403003": { + "ID": "403003", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazillandgames SBAR Santa Maria v3.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "13836384", + "Time": "2021-09-25 08:23:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 118 + }, + "402353": { + "ID": "402353", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – SCAS Cabo Juan Roman Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "338549133", + "Time": "2021-09-18 23:11:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 108 + }, + "401143": { + "ID": "401143", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "GearDown Simulations – SSDK Sao Pedro Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "86828975", + "Time": "2021-09-11 22:45:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 35, + "Leechers": 0, + "Snatched": 117 + }, + "401142": { + "ID": "401142", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "GearDown Simulations – SNPA Para de Minas Airport v1.2.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "481631373", + "Time": "2021-09-11 22:45:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 111 + }, + "401141": { + "ID": "401141", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "GearDown Simulations – SNMX Sao Mateus Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "44509199", + "Time": "2021-09-11 22:44:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 34, + "Leechers": 0, + "Snatched": 121 + }, + "401139": { + "ID": "401139", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "GearDown Simulations – SBGV Governador Valadares Airport v2.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "228065078", + "Time": "2021-09-11 22:43:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 36, + "Leechers": 0, + "Snatched": 116 + }, + "401138": { + "ID": "401138", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "GearDown Simulations – SBBH Pampulha–Carlos Drummond de Andrade Airport + Mesh v1.3.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "58112040", + "Time": "2021-09-11 22:43:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 35, + "Leechers": 0, + "Snatched": 125 + }, + "401134": { + "ID": "401134", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Pedro PilotX – SDTK Paraty Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "156556779", + "Time": "2021-09-11 22:40:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 35, + "Leechers": 0, + "Snatched": 117 + }, + "401133": { + "ID": "401133", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Pedro PilotX – SBBZ Umberto Modiano Airport v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "369983914", + "Time": "2021-09-11 22:39:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 36, + "Leechers": 0, + "Snatched": 113 + }, + "401132": { + "ID": "401132", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "DC Scenery Design – SNPJ Patrocinio Airport v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "66952613", + "Time": "2021-09-11 22:39:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 124 + }, + "401131": { + "ID": "401131", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "DC Scenery Design – SDDR Dracena Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "132469996", + "Time": "2021-09-11 22:38:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 118 + }, + "399182": { + "ID": "399182", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – SCCY Teniente Vidal Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "37623640", + "Time": "2021-09-02 22:45:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 36, + "Leechers": 0, + "Snatched": 124 + }, + "397970": { + "ID": "397970", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Simulacion Extrema – SCIE Carriel Sur International Airport v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "78500027", + "Time": "2021-08-31 02:15:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 36, + "Leechers": 0, + "Snatched": 132 + }, + "396773": { + "ID": "396773", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "LatinVFR – SCEL Arturo Merino Benitez International Airport v1.0.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "705717911", + "Time": "2021-08-23 07:28:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 39, + "Leechers": 0, + "Snatched": 131 + }, + "396555": { + "ID": "396555", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "VirtualDesign3d – SCSE La Florida Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "60372499", + "Time": "2021-08-22 07:57:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 135 + }, + "396541": { + "ID": "396541", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Mex High Flight – MUHA Jose Marti International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1008759090", + "Time": "2021-08-22 03:29:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 36, + "Leechers": 0, + "Snatched": 136 + }, + "394967": { + "ID": "394967", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazil Land Games – SBCT Afonso Pena International Airport v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "84097646", + "Time": "2021-08-12 01:31:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 39, + "Leechers": 0, + "Snatched": 133 + }, + "394966": { + "ID": "394966", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazil Land Games – SBCF Belo Horizonte\/Confins – Tancredo Neves International Airport v3.5.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "227927296", + "Time": "2021-08-12 01:30:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 40, + "Leechers": 0, + "Snatched": 129 + }, + "388037": { + "ID": "388037", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Sierrasim Simulation – MNMG Augusto C. Sandino International Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "108974451", + "Time": "2021-07-17 07:10:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 40, + "Leechers": 0, + "Snatched": 143 + }, + "385981": { + "ID": "385981", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Arka506 – MPTO Tocumen International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "23097121", + "Time": "2021-07-09 19:17:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 49, + "Leechers": 0, + "Snatched": 401 + }, + "381313": { + "ID": "381313", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazil Land Games – SBKP Viracopos–Campinas International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "87123082", + "Time": "2021-06-23 22:56:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 48, + "Leechers": 0, + "Snatched": 154 + }, + "381311": { + "ID": "381311", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Brazil Land Games – SBMO Maceio\/Zumbi dos Palmares International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "24804289", + "Time": "2021-06-23 22:53:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 50, + "Leechers": 0, + "Snatched": 165 + }, + "381023": { + "ID": "381023", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "DSky – FMNN Fascene Airport v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "155710927", + "Time": "2021-06-23 11:28:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 43, + "Leechers": 0, + "Snatched": 150 + }, + "365574": { + "ID": "365574", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Sierrasim - SKMD Olaya Herrera Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1587132373", + "Time": "2021-04-07 21:19:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 52, + "Leechers": 0, + "Snatched": 235 + }, + "346491": { + "ID": "346491", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "SimulationExtrema - SCCI SCJO Canal Bajo Carlos Hott Siebert Airport v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "83550980", + "Time": "2021-02-10 02:31:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 71, + "Leechers": 0, + "Snatched": 286 + }, + "332869": { + "ID": "332869", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Sierrasim - SEGU Guayaquil José Joaquín de Olmedo International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "177394708", + "Time": "2020-12-09 06:53:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 75, + "Leechers": 0, + "Snatched": 344 + }, + "332250": { + "ID": "332250", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Sierrasim - SKCC Cucuta Camilo Daza International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "94206606", + "Time": "2020-12-07 07:19:27", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 78, + "Leechers": 0, + "Snatched": 343 + }, + "326524": { + "ID": "326524", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "MROC - MROC Juan Santamaría International Airport Costa Rica v1.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "73441184", + "Time": "2020-11-16 18:59:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 78, + "Leechers": 0, + "Snatched": 346 + }, + "324847": { + "ID": "324847", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Sierrasim Simulation - SEGU Jose Joaquin de Olmedo International Airport v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "135932325", + "Time": "2020-11-12 18:42:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 75, + "Leechers": 0, + "Snatched": 341 + }, + "318911": { + "ID": "318911", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Airports - South America", + "Scene": "0", + "ReleaseTitle": "Sierrasim - SKMZ La Nubia Airport v1.0.0 - DLC", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "56098390", + "Time": "2020-10-21 04:24:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 82, + "Leechers": 0, + "Snatched": 370 + }, + "477414": { + "ID": "477414", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – Wizz Air A320 Missions Pack v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "27544442", + "Time": "2022-07-14 02:05:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 8 + }, + "476901": { + "ID": "476901", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "PilotEdge – SimVenture 2022 v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1052946041", + "Time": "2022-07-11 07:47:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 13 + }, + "470897": { + "ID": "470897", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – Orient Express v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "115169731", + "Time": "2022-06-09 19:52:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 17 + }, + "470896": { + "ID": "470896", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – Beautiful World v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "234661974", + "Time": "2022-06-09 19:51:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 16 + }, + "470895": { + "ID": "470895", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Adventum Simulations – Adventum Tours: Hawaii v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2251309017", + "Time": "2022-06-09 19:51:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 20 + }, + "469924": { + "ID": "469924", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – North America IFR v1.0.0 (Update 1)", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "89567446", + "Time": "2022-06-05 04:51:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 17 + }, + "469923": { + "ID": "469923", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – Ryanair A320 Missions Pack v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "239615875", + "Time": "2022-06-05 04:50:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 15 + }, + "469922": { + "ID": "469922", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – Eurowings A320 Missions Pack v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "261824675", + "Time": "2022-06-05 04:50:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 14 + }, + "466435": { + "ID": "466435", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "FS Academy – Jetliner v1.4.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "615360218", + "Time": "2022-05-24 09:04:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 17 + }, + "466434": { + "ID": "466434", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "FS Academy – IFR v1.5.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "652490506", + "Time": "2022-05-24 09:03:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 17 + }, + "465364": { + "ID": "465364", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "FS Academy – Navigator v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "959246882", + "Time": "2022-05-18 21:41:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 18 + }, + "453784": { + "ID": "453784", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Just Flight – Air Hauler 2 v3.0.0.13", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "222390446", + "Time": "2022-03-24 07:09:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 28 + }, + "444832": { + "ID": "444832", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "FS Academy – Voyager v1.6.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "120022255", + "Time": "2022-03-15 09:34:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 26 + }, + "426159": { + "ID": "426159", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "FS Academy – VFR v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "632668251", + "Time": "2022-01-27 05:15:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 48 + }, + "425546": { + "ID": "425546", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – Greece Scenic Tour v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "234719811", + "Time": "2022-01-22 12:11:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 31 + }, + "421198": { + "ID": "421198", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – Flying Germany v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "259314309", + "Time": "2021-12-31 06:31:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 21, + "Leechers": 0, + "Snatched": 56 + }, + "395656": { + "ID": "395656", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Parallel 42 – The Skypark v2021.32.4.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "867641977", + "Time": "2021-08-16 00:17:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 40, + "Leechers": 0, + "Snatched": 148 + }, + "381355": { + "ID": "381355", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – Discovery Flights – United Kingdom & Ireland v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "279425582", + "Time": "2021-06-24 00:19:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 45, + "Leechers": 0, + "Snatched": 160 + }, + "381354": { + "ID": "381354", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – Bush Trip – The Fjords v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "34511914", + "Time": "2021-06-24 00:19:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 52, + "Leechers": 0, + "Snatched": 166 + }, + "381353": { + "ID": "381353", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – Flying Hawaii v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "266953452", + "Time": "2021-06-24 00:18:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 54, + "Leechers": 0, + "Snatched": 163 + }, + "381352": { + "ID": "381352", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – Flying Nepal v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "204928389", + "Time": "2021-06-24 00:16:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 52, + "Leechers": 0, + "Snatched": 163 + }, + "381351": { + "ID": "381351", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – Flying Japan v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "136609539", + "Time": "2021-06-24 00:16:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 55, + "Leechers": 0, + "Snatched": 166 + }, + "381349": { + "ID": "381349", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – Discovery Flights – Aerial Chauffeur v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "87450982", + "Time": "2021-06-24 00:13:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 50, + "Leechers": 0, + "Snatched": 160 + }, + "381348": { + "ID": "381348", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – Bush Trip – The Alps v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "71083065", + "Time": "2021-06-24 00:13:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 50, + "Leechers": 0, + "Snatched": 158 + }, + "381347": { + "ID": "381347", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Missions \/ Tutorials", + "Scene": "0", + "ReleaseTitle": "Perfect Flight – USA Coast to Coast v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "76189091", + "Time": "2021-06-24 00:11:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 51, + "Leechers": 0, + "Snatched": 172 + }, + "479780": { + "ID": "479780", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Orbx – Alaska Mesh v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "7068776176", + "Time": "2022-07-24 07:20:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 14 + }, + "479581": { + "ID": "479581", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Taburet – Night 3D USA South v4.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "19523505", + "Time": "2022-07-23 05:25:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 7 + }, + "479575": { + "ID": "479575", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Orbx – South America Mesh v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "26197495823", + "Time": "2022-07-23 05:23:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 15 + }, + "469775": { + "ID": "469775", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Project Coastline Team – Project Coastline Italy & LIRS Grosseto Airport v3.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "130554316", + "Time": "2022-06-04 18:34:01", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 12 + }, + "468121": { + "ID": "468121", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Taburet – Denmark Norway Sweden Powerlines v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "74232909", + "Time": "2022-05-30 21:06:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 11 + }, + "468120": { + "ID": "468120", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Taburet – Night 3D Denmark – Norway v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2117139", + "Time": "2022-05-30 21:06:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 12 + }, + "466758": { + "ID": "466758", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "UK2000 Scenery – Common Library v1.1.6", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "72938019", + "Time": "2022-05-25 03:17:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 11 + }, + "462060": { + "ID": "462060", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Orbx – EU Great Britain North v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2696239797", + "Time": "2022-05-08 05:54:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 21 + }, + "461082": { + "ID": "461082", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "RKbridger – Boston & Cape Cod Canal Bridges & Water Fixes v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "17792784", + "Time": "2022-04-30 04:08:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 17 + }, + "458822": { + "ID": "458822", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Black Square – Real Taxiways USA – Military Airfields v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3912093", + "Time": "2022-04-16 07:15:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 24 + }, + "458820": { + "ID": "458820", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Black Square – Real Taxiways USA – Class B, C, D & Non–towered Airports v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "8748361", + "Time": "2022-04-16 07:15:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 23 + }, + "458819": { + "ID": "458819", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Black Square – Real Taxiways Europe v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4456603", + "Time": "2022-04-16 07:14:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 21 + }, + "453767": { + "ID": "453767", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Orbx – EU Great Britain Central v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2728418514", + "Time": "2022-03-24 07:00:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 26 + }, + "451942": { + "ID": "451942", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Seafront Simulations – Vessels Anguilla, St Martin and St Barts v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "303930956", + "Time": "2022-03-20 12:15:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 19 + }, + "451941": { + "ID": "451941", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Seafront Simulations – Vessels Global Shipping v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "207798398", + "Time": "2022-03-20 12:14:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 22 + }, + "444830": { + "ID": "444830", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Bijan Studio – Project: Islands, Sunken Boats, Huts, PG Trees v3.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "117431219", + "Time": "2022-03-15 09:32:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 25 + }, + "429267": { + "ID": "429267", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Bijan Studio – Four Season Pack v7.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "751862938", + "Time": "2022-02-12 20:15:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 40 + }, + "418036": { + "ID": "418036", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds Central USA v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "27308816", + "Time": "2021-12-20 15:01:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 68 + }, + "415559": { + "ID": "415559", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds Northeast USA v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "22453692", + "Time": "2021-12-02 10:14:03", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 25, + "Leechers": 0, + "Snatched": 77 + }, + "415558": { + "ID": "415558", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds Southeast USA v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "24025779", + "Time": "2021-12-02 10:13:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 80 + }, + "414681": { + "ID": "414681", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Zinertek – Enhanced Airport Graphics v2.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "309514520", + "Time": "2021-11-23 22:23:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 76 + }, + "409108": { + "ID": "409108", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Taburet – USA West Roads v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "24126038", + "Time": "2021-11-03 02:19:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 99 + }, + "409107": { + "ID": "409107", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Taburet – USA South Roads v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "40138732", + "Time": "2021-11-03 02:18:57", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 100 + }, + "409106": { + "ID": "409106", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Taburet – USA North East Roads v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "12468638", + "Time": "2021-11-03 02:18:27", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 101 + }, + "409105": { + "ID": "409105", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Taburet – USA Midwest Roads v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "22827640", + "Time": "2021-11-03 02:18:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 102 + }, + "409104": { + "ID": "409104", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Taburet – USA Pacific Roads v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "5491997", + "Time": "2021-11-03 02:17:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 105 + }, + "407610": { + "ID": "407610", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "RKbridger – New York Bridges v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "50437928", + "Time": "2021-10-26 00:35:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 102 + }, + "406893": { + "ID": "406893", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "LatinVFR – Airport Jetway Pro v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "82167041", + "Time": "2021-10-22 18:12:03", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 29, + "Leechers": 0, + "Snatched": 100 + }, + "403659": { + "ID": "403659", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Taburet – Florida, Georgia & South Carolina Water Bodies v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "20773588", + "Time": "2021-09-29 23:45:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 114 + }, + "401147": { + "ID": "401147", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Taburet – USA Midwest Roads v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "22811766", + "Time": "2021-09-11 22:49:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 36, + "Leechers": 0, + "Snatched": 127 + }, + "401146": { + "ID": "401146", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Taburet – USA North East Roads v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "12613022", + "Time": "2021-09-11 22:48:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 36, + "Leechers": 0, + "Snatched": 125 + }, + "401145": { + "ID": "401145", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Taburet – USA South Roads v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "40134078", + "Time": "2021-09-11 22:47:03", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 36, + "Leechers": 0, + "Snatched": 122 + }, + "401144": { + "ID": "401144", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "Taburet – USA West Roads v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "24151236", + "Time": "2021-09-11 22:46:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 35, + "Leechers": 0, + "Snatched": 124 + }, + "395270": { + "ID": "395270", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery", + "Scene": "0", + "ReleaseTitle": "DXR Simulations – Cancun, Riviera Maya, Tulum, Chichen–Itza Mexico Super Scenery v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "205354585", + "Time": "2021-08-13 17:04:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 45, + "Leechers": 0, + "Snatched": 142 + }, + "478776": { + "ID": "478776", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds Europe Central v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "81150546", + "Time": "2022-07-20 09:50:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 8 + }, + "478775": { + "ID": "478775", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds British Isles v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "29805013", + "Time": "2022-07-20 09:49:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 7 + }, + "478770": { + "ID": "478770", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds West USA v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "31220249", + "Time": "2022-07-20 09:24:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 7 + }, + "478769": { + "ID": "478769", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds Central USA v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "26994413", + "Time": "2022-07-20 09:23:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 7 + }, + "478768": { + "ID": "478768", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds Midwest USA v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "27313024", + "Time": "2022-07-20 09:22:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 7 + }, + "478767": { + "ID": "478767", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds Southeast USA v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "23711370", + "Time": "2022-07-20 09:22:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 7 + }, + "478766": { + "ID": "478766", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds Northeast USA v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "22139276", + "Time": "2022-07-20 09:21:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 7 + }, + "478765": { + "ID": "478765", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds Canada East v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "37857537", + "Time": "2022-07-20 09:19:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 7 + }, + "477185": { + "ID": "477185", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "Seafront Simulations – Vessels Core Library v1.8.5", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1317196551", + "Time": "2022-07-13 06:45:00", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 15 + }, + "477184": { + "ID": "477184", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "Seafront Simulations – Vessels Enhanced AI v2.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "305760301", + "Time": "2022-07-13 06:44:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 10 + }, + "476251": { + "ID": "476251", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds Europe Central v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "81507114", + "Time": "2022-07-08 00:33:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 10 + }, + "472769": { + "ID": "472769", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "Seafront Simulations – Vessels The Virgin Islands v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "512071496", + "Time": "2022-06-20 05:57:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 13 + }, + "467063": { + "ID": "467063", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "Taburet – China Roads v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "90910547", + "Time": "2022-05-26 04:42:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 11 + }, + "461079": { + "ID": "461079", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds Midwest USA v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "27669587", + "Time": "2022-04-30 04:06:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 17 + }, + "461078": { + "ID": "461078", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds West USA v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "31576814", + "Time": "2022-04-30 04:06:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 18 + }, + "460368": { + "ID": "460368", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds British Isles v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "30119399", + "Time": "2022-04-25 19:36:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 18 + }, + "460367": { + "ID": "460367", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds Canada East v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "38171920", + "Time": "2022-04-25 19:35:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 19 + }, + "459986": { + "ID": "459986", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "South Oak Co – FS Birds Europe West v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "46124229", + "Time": "2022-04-23 05:16:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 18 + }, + "456951": { + "ID": "456951", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "LatinVFR – AREX Global v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1174952699", + "Time": "2022-04-06 12:16:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 31 + }, + "456448": { + "ID": "456448", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "LatinVFR – Global Vehicle Traffic v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "59931096", + "Time": "2022-04-04 00:21:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 27 + }, + "451948": { + "ID": "451948", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "LatinVFR – AREX Tropics South America v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "240573186", + "Time": "2022-03-20 12:17:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 20 + }, + "423476": { + "ID": "423476", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "LatinVFR – Static Aircraft Bundle v2.0.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "667057917", + "Time": "2022-01-09 05:31:30", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 44 + }, + "416316": { + "ID": "416316", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "LatinVFR – AREX Middle East Africa v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "255678625", + "Time": "2021-12-07 00:42:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 66 + }, + "396543": { + "ID": "396543", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "LatinVFR – AREX North America v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "317178489", + "Time": "2021-08-22 03:30:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 39, + "Leechers": 0, + "Snatched": 131 + }, + "391273": { + "ID": "391273", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery AirportRegionEnvironmentX", + "Scene": "0", + "ReleaseTitle": "LatinVFR – AREX Asia Pacific v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "421376106", + "Time": "2021-07-30 05:01:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 40, + "Leechers": 0, + "Snatched": 137 + }, + "479877": { + "ID": "479877", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "CloudSurf Asia Simulations – Mega Manila Scenery v0.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1031814137", + "Time": "2022-07-21 20:26:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 9 + }, + "478552": { + "ID": "478552", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "SamScene – Beijing City Times v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "535460510", + "Time": "2022-07-19 01:06:01", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 10 + }, + "476252": { + "ID": "476252", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "Drzewiecki Design – Washington Landmarks v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1039283192", + "Time": "2022-07-08 00:34:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 13 + }, + "471074": { + "ID": "471074", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "Orbx – Landmarks Melbourne City Pack v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1590051208", + "Time": "2022-06-11 01:42:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 19 + }, + "467065": { + "ID": "467065", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "SamScene – Hong Kong City Times & VHHH Hong Kong International Airport v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "509441884", + "Time": "2022-05-26 04:44:09", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 11 + }, + "466429": { + "ID": "466429", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "SamScene – Shenzhen City v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1764415801", + "Time": "2022-05-24 09:00:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 15 + }, + "466424": { + "ID": "466424", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "SamScene – Chongqing Magic City 8D & ZUCK Chongqing Jiangbei International Airport v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "467161094", + "Time": "2022-05-24 08:57:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 11 + }, + "465827": { + "ID": "465827", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "SamScene – Guangzhou City & ZGGG Guangzhou Baiyun International Airport v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1492810878", + "Time": "2022-05-21 02:03:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 15 + }, + "462304": { + "ID": "462304", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "Zhouke Scenery Studio – Changsha City Scenery v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "279551720", + "Time": "2022-05-09 06:38:03", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 11 + }, + "460784": { + "ID": "460784", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "Orbx – Cityscape Sydney v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "7897379550", + "Time": "2022-04-28 05:41:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 25 + }, + "456961": { + "ID": "456961", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "Impulse Simulations – Landmarks Cairns v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "163710064", + "Time": "2022-04-06 12:28:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 17 + }, + "454868": { + "ID": "454868", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "Orbx – Landmarks Brisbane City Pack v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2607324938", + "Time": "2022-03-27 21:41:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 24 + }, + "444047": { + "ID": "444047", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "AviaJam Production – Bangkok Landmarks v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "437733345", + "Time": "2022-03-10 03:03:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 23 + }, + "441997": { + "ID": "441997", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "Orbx – Landmarks Panama City Pack v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4317261973", + "Time": "2022-02-27 13:38:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 29 + }, + "438893": { + "ID": "438893", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "Taburet – Japan Roads v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "24714597", + "Time": "2022-02-21 10:31:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 33 + }, + "432779": { + "ID": "432779", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "Orbx – Landmarks Cape Town City Pack v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3509009280", + "Time": "2022-02-16 21:45:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 33 + }, + "430490": { + "ID": "430490", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "Orbx – Landmarks Adelaide City Pack v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3027147111", + "Time": "2022-02-15 01:58:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 33 + }, + "428598": { + "ID": "428598", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "Prealsoft – Vienna Landmarks v1.3.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "42972261", + "Time": "2022-02-07 17:50:27", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 32 + }, + "425778": { + "ID": "425778", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "Orbx – Landmarks Dubai City Pack v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3864770517", + "Time": "2022-01-24 03:44:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 42 + }, + "423005": { + "ID": "423005", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "SamScene – New York City Times v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "580589325", + "Time": "2022-01-07 05:25:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 47 + }, + "421195": { + "ID": "421195", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "SamScene – Shanghai City Times v2.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "371835409", + "Time": "2021-12-31 06:30:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 21, + "Leechers": 0, + "Snatched": 57 + }, + "417208": { + "ID": "417208", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "SamScene – Busan City Wow v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1600273027", + "Time": "2021-12-13 22:52:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 22, + "Leechers": 0, + "Snatched": 67 + }, + "410502": { + "ID": "410502", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "AeroWulf – Ekaterinburg \/ Yekaterinburg City v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1732271683", + "Time": "2021-11-09 07:21:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 23, + "Leechers": 0, + "Snatched": 85 + }, + "405924": { + "ID": "405924", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "FlyTampa – Las Vegas City v1.6.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1310710975", + "Time": "2021-10-17 10:14:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 38, + "Leechers": 0, + "Snatched": 122 + }, + "404666": { + "ID": "404666", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "SamScene – Seoul City Wow v1.2.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "191634513", + "Time": "2021-10-08 00:40:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 32, + "Leechers": 0, + "Snatched": 103 + }, + "381388": { + "ID": "381388", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery City", + "Scene": "0", + "ReleaseTitle": "SamScene – Chongqing Magic City 8D v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "490758360", + "Time": "2021-06-24 02:35:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 41, + "Leechers": 0, + "Snatched": 145 + }, + "453775": { + "ID": "453775", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Islands", + "Scene": "0", + "ReleaseTitle": "FSDG – Mauritius v1.4.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4026132617", + "Time": "2022-03-24 07:04:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 32 + }, + "440170": { + "ID": "440170", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Islands", + "Scene": "0", + "ReleaseTitle": "Aerosoft – Antarctica Vol. 1 – British Rothera and Beyond v1.1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1022691970", + "Time": "2022-02-23 00:41:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 33 + }, + "415454": { + "ID": "415454", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Islands", + "Scene": "0", + "ReleaseTitle": "Aerosoft – Airfields East Frisian Islands v1.4.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2246466598", + "Time": "2021-12-01 00:00:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 23, + "Leechers": 0, + "Snatched": 77 + }, + "405990": { + "ID": "405990", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Islands", + "Scene": "0", + "ReleaseTitle": "FSDG – Seychelles v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4117983685", + "Time": "2021-10-18 01:27:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 33, + "Leechers": 0, + "Snatched": 116 + }, + "381084": { + "ID": "381084", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Islands", + "Scene": "0", + "ReleaseTitle": "DSky – TVSB TVSM TVSC Grenadines Islands Vol. 2 v1.0.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "217420377", + "Time": "2021-06-23 12:55:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 48, + "Leechers": 0, + "Snatched": 145 + }, + "380990": { + "ID": "380990", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Islands", + "Scene": "0", + "ReleaseTitle": "DSky – Grenadines Islands Vol. 1 v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "64269842", + "Time": "2021-06-23 09:52:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 51, + "Leechers": 0, + "Snatched": 158 + }, + "348576": { + "ID": "348576", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Islands", + "Scene": "0", + "ReleaseTitle": "Seafront Simulations - Vessels Channel Islands v1.0.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "722393013", + "Time": "2021-02-16 18:44:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 65, + "Leechers": 0, + "Snatched": 272 + }, + "346830": { + "ID": "346830", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Islands", + "Scene": "0", + "ReleaseTitle": "Stairport Sceneries \/ Aerosoft - Airfields East Frisian Islands v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2613638176", + "Time": "2021-02-10 21:12:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 65, + "Leechers": 0, + "Snatched": 312 + }, + "476894": { + "ID": "476894", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "AviaJam Production – Beijing Landmarks v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "660017901", + "Time": "2022-07-11 07:43:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 11 + }, + "461191": { + "ID": "461191", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "RKbridger – Minneapolis–St. Paul Bridges v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "27864733", + "Time": "2022-04-30 17:30:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 19 + }, + "457411": { + "ID": "457411", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "AviaJam Production – Yaroslavl Landmarks v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "295505958", + "Time": "2022-04-09 06:57:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 22 + }, + "430483": { + "ID": "430483", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "Prealsoft – Casablanca Landmarks v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "108420065", + "Time": "2022-02-15 01:56:30", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 34 + }, + "430476": { + "ID": "430476", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "AviaJam Production – Tianjin Landmarks v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "51383664", + "Time": "2022-02-15 01:54:04", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 34 + }, + "428671": { + "ID": "428671", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "AviaJam Production – New Delhi Landmarks v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "127118575", + "Time": "2022-02-08 03:22:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 34 + }, + "418684": { + "ID": "418684", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "AviaJam Production – Riyadh Landmarks v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "86781977", + "Time": "2021-12-25 02:40:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 69 + }, + "415870": { + "ID": "415870", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "SamScene – Tokyo Landmarks Enhanced v1.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "95413854", + "Time": "2021-12-03 23:55:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 77 + }, + "406127": { + "ID": "406127", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "AviaJam Production – Kuala Lumpur Landmarks v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "356204148", + "Time": "2021-10-19 00:23:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 99 + }, + "406126": { + "ID": "406126", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "Orbx – Landmarks Auckland City Pack v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "5388625112", + "Time": "2021-10-19 00:22:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 110 + }, + "402872": { + "ID": "402872", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "Orbx – Landmarks Frankfurt City Pack v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "111529025", + "Time": "2021-09-24 08:20:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 31, + "Leechers": 0, + "Snatched": 114 + }, + "397309": { + "ID": "397309", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "AviaJam Production – Abu Dhabi Landmarks v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "143764601", + "Time": "2021-08-26 15:51:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 38, + "Leechers": 0, + "Snatched": 133 + }, + "396542": { + "ID": "396542", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "Orbx – Landmarks London City Pack v2.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "899267242", + "Time": "2021-08-22 03:30:22", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 42, + "Leechers": 0, + "Snatched": 137 + }, + "394963": { + "ID": "394963", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "FlyMex Software – Mexico City Landmarks v1.1.3", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "72767007", + "Time": "2021-08-12 01:27:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 43, + "Leechers": 0, + "Snatched": 143 + }, + "394318": { + "ID": "394318", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "Orbx – Landmarks Mumbai City Pack v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3957885084", + "Time": "2021-08-07 17:51:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 143 + }, + "389323": { + "ID": "389323", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "Drzewiecki Design – Seattle Landmarks v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "826505039", + "Time": "2021-07-23 05:45:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 39, + "Leechers": 0, + "Snatched": 139 + }, + "380955": { + "ID": "380955", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "ORBX - Landmarks Paris City Pack V1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1527839323", + "Time": "2021-06-23 08:14:35", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 50, + "Leechers": 0, + "Snatched": 177 + }, + "361032": { + "ID": "361032", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "Drzewiecki Design - Chicago Landmarks v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2866246217", + "Time": "2021-03-25 14:57:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 65, + "Leechers": 0, + "Snatched": 261 + }, + "352328": { + "ID": "352328", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "ORBX - Landmarks Singapore City Pack v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1035404520", + "Time": "2021-02-26 02:38:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 66, + "Leechers": 0, + "Snatched": 281 + }, + "349538": { + "ID": "349538", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "AviaJam Production - Samara Landmarks v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "242554813", + "Time": "2021-02-19 02:23:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 65, + "Leechers": 0, + "Snatched": 272 + }, + "335875": { + "ID": "335875", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "France VFR - Obstacles and VFR Landmarks France V4 v1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "65826276", + "Time": "2020-12-24 12:38:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 82, + "Leechers": 0, + "Snatched": 367 + }, + "334578": { + "ID": "334578", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Landmarks", + "Scene": "0", + "ReleaseTitle": "Drzewiecki Design - Moscow Landmarks v1.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1256728673", + "Time": "2020-12-15 10:50:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 81, + "Leechers": 0, + "Snatched": 371 + }, + "470892": { + "ID": "470892", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Mesh", + "Scene": "0", + "ReleaseTitle": "Orbx – New Zealand Mesh v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2716540035", + "Time": "2022-06-09 19:49:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 23 + }, + "422402": { + "ID": "422402", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Mesh", + "Scene": "0", + "ReleaseTitle": "Orbx – Alaska Mesh v1.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "6266072905", + "Time": "2022-01-05 02:39:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 43 + }, + "421180": { + "ID": "421180", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Mesh", + "Scene": "0", + "ReleaseTitle": "Taburet – Hawaii Mesh v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "88259845", + "Time": "2021-12-31 06:27:34", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 58 + }, + "418059": { + "ID": "418059", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Mesh", + "Scene": "0", + "ReleaseTitle": "SimWorks Studios – Okavango Delta v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "769618902", + "Time": "2021-12-20 16:06:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 60 + }, + "414145": { + "ID": "414145", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Mesh", + "Scene": "0", + "ReleaseTitle": "Orbx - Himalaya and Central Asia Mesh v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "21441263868", + "Time": "2021-11-20 00:12:56", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 92 + }, + "403657": { + "ID": "403657", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Mesh", + "Scene": "0", + "ReleaseTitle": "Taburet – Nepal Bhutan Mesh v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4319255507", + "Time": "2021-09-29 23:45:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 30, + "Leechers": 0, + "Snatched": 109 + }, + "396546": { + "ID": "396546", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Mesh", + "Scene": "0", + "ReleaseTitle": "Taburet – Canary Islands Mesh v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "219074730", + "Time": "2021-08-22 03:32:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 131 + }, + "384152": { + "ID": "384152", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "DLC - Scenery Mesh", + "Scene": "0", + "ReleaseTitle": "FSDreamTeam – Switzerland Mesh v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1547175921", + "Time": "2021-07-03 13:43:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 48, + "Leechers": 0, + "Snatched": 173 + }, + "461462": { + "ID": "461462", + "GroupID": "84781", + "CategoryID": "1", + "Format": "PDF", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Microsoft Flight Simulator Extended Edition Sofly Guide - Landscape (2022) v1.75", + "Miscellaneous": "GameDOX", + "GameDOXType": "Guide", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "421500064", + "Time": "2022-05-03 19:41:18", + "UserID": "61490", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 26 + }, + "461461": { + "ID": "461461", + "GroupID": "84781", + "CategoryID": "1", + "Format": "PDF", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Microsoft Flight Simulator Extended Edition Sofly Guide - Portrait (2022) v1.75", + "Miscellaneous": "GameDOX", + "GameDOXType": "Guide", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "422683645", + "Time": "2022-05-03 19:40:28", + "UserID": "61490", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 27 + }, + "447264": { + "ID": "447264", + "GroupID": "84781", + "CategoryID": "1", + "Format": "PDF", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "RDPresets – Online Flying \/ ATC Guide v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "Guide", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "14421288", + "Time": "2022-03-16 10:35:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 34 + }, + "444279": { + "ID": "444279", + "GroupID": "84781", + "CategoryID": "1", + "Format": "PDF", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "RDPresets – Microsoft Flight Simulator 2020 Guide v2.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "Guide", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "34925478", + "Time": "2022-03-11 06:03:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 27 + }, + "419456": { + "ID": "419456", + "GroupID": "84781", + "CategoryID": "1", + "Format": "PDF", + "Encoding": "", + "Region": "", + "Language": "Polish", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Microsoft Flight Simulator", + "Miscellaneous": "GameDOX", + "GameDOXType": "Guide", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "12382713", + "Time": "2021-12-26 17:59:54", + "UserID": "64589", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 44 + }, + "419428": { + "ID": "419428", + "GroupID": "84781", + "CategoryID": "1", + "Format": "EPUB", + "Encoding": "", + "Region": "", + "Language": "Polish", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Microsoft Flight Simulator", + "Miscellaneous": "GameDOX", + "GameDOXType": "Guide", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "11907032", + "Time": "2021-12-26 16:25:46", + "UserID": "64589", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 60 + }, + "312608": { + "ID": "312608", + "GroupID": "84781", + "CategoryID": "1", + "Format": "PDF", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "The MSFS 2020 Guide By RDPresets", + "Miscellaneous": "GameDOX", + "GameDOXType": "Guide", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "6196757", + "Time": "2020-09-30 10:33:36", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 101, + "Leechers": 0, + "Snatched": 421 + }, + "3323": { + "ID": "3323", + "GroupID": "84781", + "CategoryID": "0", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "PMDG Operations Center", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "0", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "0", + "Time": "2022-05-15 14:00:12", + "UserID": "52816", + "Link": "https:\/\/pmdg.com\/downloads\/", + "TorrentType": "Link", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 0, + "Leechers": 0, + "Snatched": 0 + }, + "478787": { + "ID": "478787", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "M. A. RealTurb – RealTurb CAT Areas Global for MSFS v1.0.0 (Update 2)", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "11354763", + "Time": "2022-07-20 09:58:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 5 + }, + "478220": { + "ID": "478220", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Navigraph – Navdata Installers AIRAC Cycle 2207", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1943794549", + "Time": "2022-07-17 07:50:01", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 10 + }, + "478219": { + "ID": "478219", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Navigraph – Navdata MSFS 2020 AIRAC Cycle 2207 rev 1", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "15507101", + "Time": "2022-07-17 07:49:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 6 + }, + "476896": { + "ID": "476896", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "M. A. RealTurb – RealTurb CAT Areas Global for MSFS v1.0.0 (Update 1)", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "11218726", + "Time": "2022-07-11 07:44:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 7 + }, + "476890": { + "ID": "476890", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "rkApps – FSRealistic Pro v2.0.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "546381888", + "Time": "2022-07-11 07:41:22", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 12 + }, + "473041": { + "ID": "473041", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "REX Simulations – REX Real Global Airport Textures v2022.06.16", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1188851330", + "Time": "2022-06-22 09:03:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 20 + }, + "472905": { + "ID": "472905", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "TFDi Design – PACX v1.2.20 (Fixed)", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "397940700", + "Time": "2022-06-21 06:25:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 15 + }, + "472768": { + "ID": "472768", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "South Oak Co – Traffic in Sight Northeast USA v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "162945080", + "Time": "2022-06-20 05:57:23", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 11 + }, + "472765": { + "ID": "472765", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Stick and Rudder Studios – FS–ATC–Chatter v1.2.1 (2022–06–19)", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2725243435", + "Time": "2022-06-20 05:55:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 21 + }, + "472545": { + "ID": "472545", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Sky4Sim – Sky4Sim Pad v1.3.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "116880576", + "Time": "2022-06-18 08:55:01", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 13 + }, + "472544": { + "ID": "472544", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "REX Simulations – REX AccuSeason (RIP) v2022.06.14", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "49149844", + "Time": "2022-06-18 08:54:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 10 + }, + "472303": { + "ID": "472303", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Navigraph – Navdata Installers AIRAC Cycle 2206", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1942598951", + "Time": "2022-06-17 06:01:30", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 20 + }, + "472298": { + "ID": "472298", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Navigraph – Navdata MSFS 2020 AIRAC Cycle 2206 rev 1", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "15495030", + "Time": "2022-06-17 05:58:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 11 + }, + "469761": { + "ID": "469761", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "SoFly – Storm v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "597825454", + "Time": "2022-06-04 18:24:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 16 + }, + "467437": { + "ID": "467437", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Pilot2ATC – Pilot2ATC v2.6.3.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "208964004", + "Time": "2022-05-27 20:03:40", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 15 + }, + "461247": { + "ID": "461247", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "rkApps – FSRealistic Core v1.0.5.1", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "514169881", + "Time": "2022-05-01 04:56:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 17 + }, + "451964": { + "ID": "451964", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Aerosoft – Simple Traffic v1.2.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "449703507", + "Time": "2022-03-20 12:26:32", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 26 + }, + "451946": { + "ID": "451946", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Aviationly – 11 Realistic Reshade Presets v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "33578450", + "Time": "2022-03-20 12:16:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 28 + }, + "444278": { + "ID": "444278", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Misty Eagle Gaming – Ultimate Weather Presets Pack v1.0.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "189306", + "Time": "2022-03-11 05:58:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 25, + "Leechers": 0, + "Snatched": 40 + }, + "443103": { + "ID": "443103", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Simultech – My Jetways v1.2.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "34739525", + "Time": "2022-03-05 20:03:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 30 + }, + "443076": { + "ID": "443076", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "FlightSimulator.me – Ingamepanels Pack for MSFS v2.1.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "91186788", + "Time": "2022-03-05 17:29:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 29 + }, + "443075": { + "ID": "443075", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "REX Simulations – REX Weather Force v2022.03.01", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "19095638", + "Time": "2022-03-05 17:28:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 30 + }, + "426157": { + "ID": "426157", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "SoFly – Weather Preset Pro v1.3.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "129178", + "Time": "2022-01-27 05:15:16", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 50 + }, + "425548": { + "ID": "425548", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Fabio Merlo – Flight Control Replay v4.5.2201.12", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "13879317", + "Time": "2022-01-22 12:12:39", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 40 + }, + "418560": { + "ID": "418560", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "GearDown Simulations – Improved Physics for MSFS v2.0.4", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1895544", + "Time": "2021-12-24 01:37:26", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 27, + "Leechers": 0, + "Snatched": 71 + }, + "418559": { + "ID": "418559", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "GearDown Simulations – Improved Physics XBox Control v1.0.2", + "Miscellaneous": "GameDOX", + "GameDOXType": "Tool", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1533471", + "Time": "2021-12-24 01:36:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 28, + "Leechers": 0, + "Snatched": 72 + }, + "356610": { + "ID": "356610", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Microsoft Flight Simulator - Update 13 - v1.14.5.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.14.5.0", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "14195980870", + "Time": "2021-03-15 18:45:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 78, + "Leechers": 0, + "Snatched": 380 + }, + "356608": { + "ID": "356608", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Microsoft Flight Simulator - Update 12 - v1.13.17.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.13.17.0", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "308810571", + "Time": "2021-03-15 18:26:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 80, + "Leechers": 0, + "Snatched": 312 + }, + "351424": { + "ID": "351424", + "GroupID": "84781", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Microsoft Flight Simulator - Update 11 - v1.13.16.0", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.13.16.0", + "FileCount": "2", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "77614813027", + "Time": "2021-02-24 06:15:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 73, + "Leechers": 0, + "Snatched": 500 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/2e00pz.jpg", + "Year": "2020", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Microsoft Flight Simulator", + "gsrating": 9, + "ignrating": 10, + "leechers": 0, + "metarating": 91, + "scene": 1, + "seeders": 33770, + "size": 93820769, + "snatched": 114987, + "time": 1658694364, + "totalcount": 1285, + "userrating": 78, + "weight": "1501", + "year": 2020 + }, + "124956": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure action platform | co_op co_op_support controller controller_support gamepad gamepad_support local_co_op_support local_multiplayer native_controller_support native_gamepad_support shared_screen shared_screen_multiplayer single_screen_multiplayer", + "ID": "124956", + "Name": "Mari and Bayu - The Road Home", + "Rating": "13", + "TagList": "adventure action platform", + "Torrents": { + "479876": { + "ID": "479876", + "GroupID": "124956", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Mari and Bayu: The Road Home [FitGirl Repack]", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "9", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1029361587", + "Time": "2022-07-24 19:55:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 10 + }, + "479129": { + "ID": "479129", + "GroupID": "124956", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Mari and Bayu - The Road Home v1.0 (57391)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1590979328", + "Time": "2022-07-21 16:47:15", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 14 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/ja7u47.jpg", + "Year": "2022", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Mari and Bayu - The Road Home", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 25, + "size": 1553691, + "snatched": 24, + "time": 1658692506, + "totalcount": 2, + "userrating": 0, + "weight": "1500", + "year": 2022 + }, + "3181": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure action role_playing_game fantasy hack_and_slash | axonometric_games co_op co_op_support funsoft iron_lore_entertainment isometric_games lan_compatible local_area_network local_co_op_support local_multiplayer nordic_games parallel_projection thq_nordic", + "ID": "3181", + "Name": "Titan Quest", + "Rating": "5", + "TagList": "adventure action role_playing_game fantasy hack_and_slash", + "Torrents": { + "475938": { + "ID": "475938", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "German", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Titan.Quest.GERMAN-SiLENTGATE", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "67", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3218899518", + "Time": "2022-07-06 17:24:59", + "UserID": "56727", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 12 + }, + "4813": { + "ID": "4813", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Titan.Quest-RELOADED", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "70", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3392206145", + "Time": "2012-07-02 19:13:43", + "UserID": "2261", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 1, + "Snatched": 199 + }, + "479873": { + "ID": "479873", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2016", + "RemasterTitle": "Anniversary Edition", + "Scene": "1", + "ReleaseTitle": "Titan.Quest.Anniversary.Edition.Eternal.Embers.v2.10.20820-I_KnoW", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "90", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "21870281360", + "Time": "2022-07-24 19:37:01", + "UserID": "57571", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 14 + }, + "415828": { + "ID": "415828", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2016", + "RemasterTitle": "Anniversary Edition", + "Scene": "1", + "ReleaseTitle": "Titan.Quest.Anniversary.Edition.Eternal.Embers-PLAZA", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "83", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "16139261554", + "Time": "2021-12-03 18:21:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 30 + }, + "58241": { + "ID": "58241", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2016", + "RemasterTitle": "Anniversary Edition", + "Scene": "1", + "ReleaseTitle": "Titan.Quest.Anniversary.Edition-PLAZA", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "62", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "5916565786", + "Time": "2016-08-31 22:26:38", + "UserID": "49865", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 87 + }, + "416964": { + "ID": "416964", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2016", + "RemasterTitle": "Anniversary Edition", + "Scene": "0", + "ReleaseTitle": "Titan Quest: Anniversary Edition v2.10.19520 + HotFix 2\/7849119 + 3 DLCs [FitGirl Repack]", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "15", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "10863855684", + "Time": "2021-12-12 06:18:51", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 1, + "Snatched": 37 + }, + "476625": { + "ID": "476625", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2016", + "RemasterTitle": "GOG Anniversary Edition", + "Scene": "0", + "ReleaseTitle": "Titan Quest: Anniversary Edition v2.10.4 (57135)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "11", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "21669880369", + "Time": "2022-07-09 17:11:44", + "UserID": "48186", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 24 + }, + "477323": { + "ID": "477323", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "German", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "TITAN.QUEST.IMMORTAL.THRONE.GERMAN-POSTMORTEM", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "52", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2466117534", + "Time": "2022-07-13 19:52:22", + "UserID": "56727", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "4812": { + "ID": "4812", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Titan.Quest.Immortal.Throne-Unleashed", + "Miscellaneous": "GameDOX", + "GameDOXType": "DLC", + "GameDOXVers": "", + "FileCount": "48", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2266712572", + "Time": "2012-07-02 19:11:32", + "UserID": "2261", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 170 + }, + "197964": { + "ID": "197964", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Other", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Titan Quest Ragnarok OST", + "Miscellaneous": "GameDOX", + "GameDOXType": "GOG-Goodies", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "326971585", + "Time": "2019-05-19 15:15:25", + "UserID": "59341", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 57 + }, + "389287": { + "ID": "389287", + "GroupID": "3181", + "CategoryID": "1", + "Format": "PDF", + "Encoding": "", + "Region": "", + "Language": "Polish", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Titan Quest", + "Miscellaneous": "GameDOX", + "GameDOXType": "Guide", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "20691971", + "Time": "2021-07-23 03:40:22", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 32 + }, + "383182": { + "ID": "383182", + "GroupID": "3181", + "CategoryID": "1", + "Format": "EPUB", + "Encoding": "", + "Region": "", + "Language": "Polish", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Titan Quest", + "Miscellaneous": "GameDOX", + "GameDOXType": "Guide", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "8079895", + "Time": "2021-06-29 13:59:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 38 + }, + "399475": { + "ID": "399475", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Titan.Quest.v1.15.Plus.14.Trainer-AGES", + "Miscellaneous": "GameDOX", + "GameDOXType": "Trainer", + "GameDOXVers": "", + "FileCount": "3", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "98554", + "Time": "2021-09-04 18:45:45", + "UserID": "8362", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 42 + }, + "208308": { + "ID": "208308", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Titan Quest - Anniversary Edition v2.7b (30770) to v2.8 (31223) [GOG]", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "2.8", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "514598984", + "Time": "2019-07-28 23:07:30", + "UserID": "59341", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 45 + }, + "416608": { + "ID": "416608", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Titan Quest: Anniversary Edition v2.10c (51934) to v2.10d (52048) [GOG]", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "2.10d", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4737184", + "Time": "2021-12-09 18:55:41", + "UserID": "65096", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 21 + }, + "465108": { + "ID": "465108", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Titan Quest: Anniversary Edition v2.10.2 (53756) to v2.10.3 (55864) [GOG]", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "2.10.3", + "FileCount": "2", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2054469231", + "Time": "2022-05-17 20:26:46", + "UserID": "65096", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 12 + }, + "435132": { + "ID": "435132", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Titan Quest: Anniversary Edition v2.10.1 (52964) to v2.10.2 (53756) [GOG]", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "2.10.2", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "644566312", + "Time": "2022-02-18 10:36:29", + "UserID": "65096", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 11 + }, + "437449": { + "ID": "437449", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Titan.Quest.Anniversary.Edition.Eternal.Embers.Update.v2.10.19934-PLAZA", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "2.10.19934", + "FileCount": "51", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "722428121", + "Time": "2022-02-19 17:52:15", + "UserID": "66679", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 3, + "Leechers": 0, + "Snatched": 8 + }, + "428326": { + "ID": "428326", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Titan.Quest.Anniversary.Edition.Eternal.Embers.Update.v2.10.19714-PLAZA", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "2.10.19714", + "FileCount": "13", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "155443580", + "Time": "2022-02-06 14:38:06", + "UserID": "66679", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 9 + }, + "424710": { + "ID": "424710", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Titan Quest: Anniversary Edition v2.10d (52048) to v2.10.1 (52964) [GOG]", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "2.10.1", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "100634616", + "Time": "2022-01-16 02:34:25", + "UserID": "65096", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 12 + }, + "89179": { + "ID": "89179", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Titan.Quest.Anniversary.Edition.Update.v1.44-PLAZA", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.44", + "FileCount": "48", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "689853768", + "Time": "2017-07-26 14:54:28", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 63 + }, + "76336": { + "ID": "76336", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Titan.Quest.Anniversary.Edition.Update.v1.42-PLAZA", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.42", + "FileCount": "13", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "156211020", + "Time": "2017-03-26 16:12:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 117 + }, + "71228": { + "ID": "71228", + "GroupID": "3181", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Titan.Quest.Anniversary.Edition.Update.v1.4-BAT", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.4", + "FileCount": "35", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "162208032", + "Time": "2016-12-17 20:18:41", + "UserID": "50693", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 121 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/k85vv5.jpg", + "Year": "2006", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Titan Quest", + "gsrating": 7, + "ignrating": 8, + "leechers": 2, + "metarating": 77, + "scene": 1, + "seeders": 224, + "size": 21357697, + "snatched": 1173, + "time": 1658691421, + "totalcount": 23, + "userrating": 27, + "weight": "1501", + "year": 2006 + }, + "125072": { + "Artists": [ + { + "id": 142, + "name": "PlayStation 4" + } + ], + "CategoryID": "1", + "FullTagList": "adventure platform | ", + "ID": "125072", + "Name": "Jump King", + "Rating": "13", + "TagList": "adventure platform", + "Torrents": { + "479869": { + "ID": "479869", + "GroupID": "125072", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "USA", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Jump King", + "Miscellaneous": "Home Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "2", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1210843136", + "Time": "2022-07-24 19:20:40", + "UserID": "42192", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 9 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/3ce8l9.png", + "Year": "2019", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Jump King", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 10, + "size": 1182464, + "snatched": 9, + "time": 1658690440, + "totalcount": 1, + "userrating": 0, + "weight": "1500", + "year": 2019 + }, + "75321": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure casual | controller controller_support daedalic_entertainment daedalic_entertainment_gmbh female_protagonist gamepad gamepad_support native_controller_support native_gamepad_support", + "ID": "75321", + "Name": "The Suicide of Rachel Foster", + "Rating": "7", + "TagList": "adventure casual", + "Torrents": { + "479868": { + "ID": "479868", + "GroupID": "75321", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "The_Suicide_of_Rachel_Foster_v1.0.9V-Razor1911", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "62", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "8939631010", + "Time": "2022-07-24 19:06:48", + "UserID": "57571", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 0, + "Snatched": 14 + }, + "239375": { + "ID": "239375", + "GroupID": "75321", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "The.Suicide.of.Rachel.Foster-CODEX", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "66", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "9553891525", + "Time": "2020-02-19 17:11:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 50 + }, + "239508": { + "ID": "239508", + "GroupID": "75321", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "The Suicide of Rachel Foster (v1.0.3B, MULTi8) [FitGirl Repack]", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "9", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "5739065259", + "Time": "2020-02-20 14:34:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 48 + }, + "479813": { + "ID": "479813", + "GroupID": "75321", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "The Suicide of Rachel Foste v1.0.9v (57374)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "4", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "8921396637", + "Time": "2022-07-24 08:46:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 2, + "Snatched": 13 + }, + "239481": { + "ID": "239481", + "GroupID": "75321", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "The Suicide of Rachel Foster v1.0.3b (36231)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "4", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "9808577625", + "Time": "2020-02-20 10:53:00", + "UserID": "48186", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 48 + }, + "240665": { + "ID": "240665", + "GroupID": "75321", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "The.Suicide.of.Rachel.Foster.Update.v1.0.3D-CODEX", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.0.3d", + "FileCount": "46", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4355161566", + "Time": "2020-03-04 18:33:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 37 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/q138o0.jpg", + "Year": "2020", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "The Suicide of Rachel Foster", + "gsrating": 0, + "ignrating": 0, + "leechers": 2, + "metarating": 72, + "scene": 1, + "seeders": 51, + "size": 9578690, + "snatched": 210, + "time": 1658689608, + "totalcount": 6, + "userrating": 3, + "weight": "1502", + "year": 2020 + }, + "125071": { + "Artists": [ + { + "id": 142, + "name": "PlayStation 4" + } + ], + "CategoryID": "1", + "FullTagList": "action arcade | ", + "ID": "125071", + "Name": "Mayhem Brawler", + "Rating": "7", + "TagList": "action arcade", + "Torrents": { + "479867": { + "ID": "479867", + "GroupID": "125071", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "USA", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Mayhem Brawler", + "Miscellaneous": "Home Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "2", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2537816064", + "Time": "2022-07-24 18:13:45", + "UserID": "42192", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 8 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/7739sf.png", + "Year": "2021", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Mayhem Brawler", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 9, + "size": 2478336, + "snatched": 8, + "time": 1658686425, + "totalcount": 1, + "userrating": 0, + "weight": "1502", + "year": 2021 + }, + "120057": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "action first_person_shooter shooter | ", + "ID": "120057", + "Name": "Carnage Offering", + "Rating": "13", + "TagList": "action first_person_shooter shooter", + "Torrents": { + "460924": { + "ID": "460924", + "GroupID": "120057", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "CARNAGE.OFFERING-DOGE", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "106", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "25754560266", + "Time": "2022-04-29 06:18:13", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 19 + }, + "479866": { + "ID": "479866", + "GroupID": "120057", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "CARNAGE.OFFERING.REPACK-KaOs", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "7", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "18015686284", + "Time": "2022-07-24 17:28:19", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 15 + }, + "461241": { + "ID": "461241", + "GroupID": "120057", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Carnage Offering [FitGirl Repack]", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "8", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "17733962661", + "Time": "2022-05-01 03:22:49", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 3, + "Leechers": 0, + "Snatched": 20 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/9g42rd.jpg", + "Year": "2022", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Carnage Offering", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 1, + "seeders": 24, + "size": 25150938, + "snatched": 54, + "time": 1658683699, + "totalcount": 3, + "userrating": -1, + "weight": "1500", + "year": 2022 + }, + "85747": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "action real_time_strategy historical | age_of_empires forgotten_empires microsoft_game_studios microsoft_studios stephen_rippy tantalus_entertainment tantalus_interactive tantalus_media xbox_game_studios", + "ID": "85747", + "Name": "Age of Empires III: Definitive Edition", + "Rating": "5", + "TagList": "action real_time_strategy historical", + "Torrents": { + "471019": { + "ID": "471019", + "GroupID": "85747", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Age_of_Empires_III_Definitive_Edition_Knights_of_the_Mediterranean-Razor1911", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "189", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "46667888063", + "Time": "2022-06-10 12:08:27", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 38 + }, + "317043": { + "ID": "317043", + "GroupID": "85747", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Age.of.Empires.III.Definitive.Edition-CODEX", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "135", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "33199237863", + "Time": "2020-10-15 14:16:05", + "UserID": "54831", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 49, + "Leechers": 0, + "Snatched": 353 + }, + "479865": { + "ID": "479865", + "GroupID": "85747", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Age.of.Empires.III.Definitive.Edition.Build.13.5088.MULTi13.REPACK-KaOs", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "10", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "28407000025", + "Time": "2022-07-24 17:19:03", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 2, + "Snatched": 17 + }, + "467907": { + "ID": "467907", + "GroupID": "85747", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Age of Empires III: Definitive Edition v100.13.9057.0 + 4 DLCs [FitGirl Repack]", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "22", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "27300764765", + "Time": "2022-05-29 22:32:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 22, + "Leechers": 1, + "Snatched": 37 + }, + "460348": { + "ID": "460348", + "GroupID": "85747", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Age.of.Empires.III.Definitive.Edition.Mexico.Civilization.REPACK-KaOs", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "9", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "24649130487", + "Time": "2022-04-25 13:27:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 23 + }, + "478727": { + "ID": "478727", + "GroupID": "85747", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Age.of.Empires.III.Definitive.Edition.v13.12327.Plus.10.Trainer-FLiNG", + "Miscellaneous": "GameDOX", + "GameDOXType": "Trainer", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "915864", + "Time": "2022-07-20 03:52:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 4 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/7967b6.jpg", + "Year": "2020", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Age of Empires III: Definitive Edition", + "gsrating": 0, + "ignrating": 0, + "leechers": 2, + "metarating": 79, + "scene": 1, + "seeders": 122, + "size": 45574110, + "snatched": 473, + "time": 1658683143, + "totalcount": 6, + "userrating": 1, + "weight": "1501", + "year": 2020 + }, + "25850": { + "Artists": [], + "CategoryID": "4", + "FullTagList": "ambient rock electronic synth | chris_remo polygon_top_100_best_games_of_all_time_2017", + "ID": "25850", + "Name": "Gone Home Original Soundtrack by Chris Remo", + "Rating": "0", + "TagList": "ambient rock electronic synth", + "Torrents": { + "479863": { + "ID": "479863", + "GroupID": "25850", + "CategoryID": "4", + "Format": "FLAC", + "Encoding": "24bit Lossless", + "Region": "", + "Language": "", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Gone Home Original Soundtrack by Chris Remo (Humble Bundle)", + "Miscellaneous": "", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "19", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "294277788", + "Time": "2022-07-24 16:57:04", + "UserID": "59908", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 5 + }, + "165077": { + "ID": "165077", + "GroupID": "25850", + "CategoryID": "4", + "Format": "MP3", + "Encoding": "320", + "Region": "", + "Language": "", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Gone Home Original Soundtrack by Chris Remo", + "Miscellaneous": "", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "19", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "79476746", + "Time": "2018-11-03 14:37:34", + "UserID": "5328", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 12 + }, + "165076": { + "ID": "165076", + "GroupID": "25850", + "CategoryID": "4", + "Format": "MP3", + "Encoding": "V0 (VBR)", + "Region": "", + "Language": "", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Gone Home Original Soundtrack by Chris Remo", + "Miscellaneous": "", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "19", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "58667156", + "Time": "2018-11-03 14:37:21", + "UserID": "5328", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 14 + }, + "165075": { + "ID": "165075", + "GroupID": "25850", + "CategoryID": "4", + "Format": "FLAC", + "Encoding": "Lossless", + "Region": "", + "Language": "", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Gone Home Original Soundtrack by Chris Remo", + "Miscellaneous": "", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "19", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "112317827", + "Time": "2018-11-03 14:37:09", + "UserID": "5328", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 16 + }, + "165074": { + "ID": "165074", + "GroupID": "25850", + "CategoryID": "4", + "Format": "FLAC", + "Encoding": "24bit Lossless", + "Region": "", + "Language": "", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Gone Home Original Soundtrack by Chris Remo", + "Miscellaneous": "", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "19", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "266896064", + "Time": "2018-11-03 14:36:45", + "UserID": "5328", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 15 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/p49z1u.jpg", + "Year": "2013", + "categoryid": 4, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Gone Home Original Soundtrack by Chris Remo", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 22, + "size": 287381, + "snatched": 62, + "time": 1658681824, + "totalcount": 5, + "userrating": 1, + "weight": "1489", + "year": 2013 + }, + "77088": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "construction_simulation simulation strategy management | axonometric_games chasing_carrots gazellegames_internals_v2 isometric_games out_of_early_access parallel_projection unity", + "ID": "77088", + "Name": "Good Company", + "Rating": "13", + "TagList": "construction_simulation simulation strategy management", + "Torrents": { + "474408": { + "ID": "474408", + "GroupID": "77088", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Good_Company_RIP-VACE", + "Miscellaneous": "Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "32", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "294507189", + "Time": "2022-06-30 12:34:52", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 3, + "Leechers": 0, + "Snatched": 6 + }, + "473703": { + "ID": "473703", + "GroupID": "77088", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Good.Company-SKIDROW", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "43", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "611871267", + "Time": "2022-06-27 02:58:50", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 17 + }, + "473170": { + "ID": "473170", + "GroupID": "77088", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Good Company v1.0.2", + "Miscellaneous": "Home Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "549188337", + "Time": "2022-06-23 10:24:04", + "UserID": "67651", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 21 + }, + "479862": { + "ID": "479862", + "GroupID": "77088", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Good Company v1.0.10b (57398)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "3", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "767065341", + "Time": "2022-07-24 16:23:12", + "UserID": "20360", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 11 + }, + "476249": { + "ID": "476249", + "GroupID": "77088", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Good Company v1.0.8 (57061)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "3", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "763147855", + "Time": "2022-07-08 00:20:52", + "UserID": "20360", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 23 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/808856.jpg", + "Year": "2022", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Good Company", + "gsrating": 0, + "ignrating": 0, + "leechers": 1, + "metarating": 0, + "scene": 1, + "seeders": 59, + "size": 749088, + "snatched": 78, + "time": 1658679792, + "totalcount": 5, + "userrating": 0, + "weight": "1500", + "year": 2022 + }, + "125069": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "puzzle platform | ", + "ID": "125069", + "Name": "Swung", + "Rating": "13", + "TagList": "puzzle platform", + "Torrents": { + "479861": { + "ID": "479861", + "GroupID": "125069", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "itch.io", + "Scene": "0", + "ReleaseTitle": "Swung v1.0", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "49868485", + "Time": "2022-07-24 16:11:46", + "UserID": "67369", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 0, + "Leechers": 4, + "Snatched": 0 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/bh7z49.jpg", + "Year": "2020", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Swung", + "gsrating": 0, + "ignrating": 0, + "leechers": 4, + "metarating": 0, + "scene": 0, + "seeders": 0, + "size": 48700, + "snatched": 0, + "time": 1658679106, + "totalcount": 1, + "userrating": 0, + "weight": "1500", + "year": 2020 + }, + "103846": { + "Artists": [ + { + "id": 29, + "name": "Mac" + } + ], + "CategoryID": "1", + "FullTagList": "simulation strategy sandbox | controller controller_support gamepad gamepad_support god_game native_controller_support native_gamepad_support unity", + "ID": "103846", + "Name": "Intelligent Design: An Evolutionary Sandbox", + "Rating": "13", + "TagList": "simulation strategy sandbox", + "Torrents": { + "479860": { + "ID": "479860", + "GroupID": "103846", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2017", + "RemasterTitle": "itch.io", + "Scene": "0", + "ReleaseTitle": "Intelligent Design: An Evolutionary Sandbox (app.tar) v18.06.2020", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "203676672", + "Time": "2022-07-24 16:06:12", + "UserID": "67369", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 0, + "Leechers": 6, + "Snatched": 0 + }, + "377993": { + "ID": "377993", + "GroupID": "103846", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2017", + "RemasterTitle": "itch.io", + "Scene": "0", + "ReleaseTitle": "Intelligent Design: An Evolutionary Sandbox v12.10.2018", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "103080040", + "Time": "2021-06-11 17:04:28", + "UserID": "56449", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 9 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/06y18c.jpg", + "Year": "2017", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Intelligent Design: An Evolutionary Sandbox", + "gsrating": 0, + "ignrating": 0, + "leechers": 6, + "metarating": 0, + "scene": 0, + "seeders": 4, + "size": 198903, + "snatched": 9, + "time": 1658678772, + "totalcount": 2, + "userrating": 0, + "weight": "1500", + "year": 2017 + }, + "125068": { + "Artists": [ + { + "id": 24, + "name": "Linux" + } + ], + "CategoryID": "1", + "FullTagList": "action casual | ", + "ID": "125068", + "Name": "Sub-Uber-Marine", + "Rating": "13", + "TagList": "action casual", + "Torrents": { + "479859": { + "ID": "479859", + "GroupID": "125068", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2021", + "RemasterTitle": "itch.io", + "Scene": "0", + "ReleaseTitle": "Sub-Uber-Marine v1.0", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "735172", + "Time": "2022-07-24 16:03:04", + "UserID": "67369", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 0, + "Leechers": 3, + "Snatched": 0 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/3pce28.png", + "Year": "2021", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Sub-Uber-Marine", + "gsrating": 0, + "ignrating": 0, + "leechers": 3, + "metarating": 0, + "scene": 0, + "seeders": 0, + "size": 718, + "snatched": 0, + "time": 1658678584, + "totalcount": 1, + "userrating": 0, + "weight": "1500", + "year": 2021 + }, + "125067": { + "Artists": [ + { + "id": 29, + "name": "Mac" + } + ], + "CategoryID": "1", + "FullTagList": "action casual | ", + "ID": "125067", + "Name": "Sub-Uber-Marine", + "Rating": "13", + "TagList": "action casual", + "Torrents": { + "479858": { + "ID": "479858", + "GroupID": "125067", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2021", + "RemasterTitle": "itch.io", + "Scene": "0", + "ReleaseTitle": "Sub-Uber-Marine v1.0", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3414850", + "Time": "2022-07-24 16:02:34", + "UserID": "67369", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 0, + "Leechers": 2, + "Snatched": 0 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/3pce28.png", + "Year": "2021", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Sub-Uber-Marine", + "gsrating": 0, + "ignrating": 0, + "leechers": 2, + "metarating": 0, + "scene": 0, + "seeders": 0, + "size": 3335, + "snatched": 0, + "time": 1658678554, + "totalcount": 1, + "userrating": 0, + "weight": "1500", + "year": 2021 + }, + "125066": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "action casual | ", + "ID": "125066", + "Name": "Sub-Uber-Marine", + "Rating": "13", + "TagList": "action casual", + "Torrents": { + "479857": { + "ID": "479857", + "GroupID": "125066", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2021", + "RemasterTitle": "itch.io", + "Scene": "0", + "ReleaseTitle": "Sub-Uber-Marine v1.0", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "983634", + "Time": "2022-07-24 16:01:54", + "UserID": "67369", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 0, + "Leechers": 6, + "Snatched": 0 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/3pce28.png", + "Year": "2021", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Sub-Uber-Marine", + "gsrating": 0, + "ignrating": 0, + "leechers": 6, + "metarating": 0, + "scene": 0, + "seeders": 0, + "size": 961, + "snatched": 0, + "time": 1658678514, + "totalcount": 1, + "userrating": 0, + "weight": "1500", + "year": 2021 + }, + "125065": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "horror comedy visual_novel | ", + "ID": "125065", + "Name": "RB: Axolotl", + "Rating": "13", + "TagList": "horror comedy visual_novel", + "Torrents": { + "479856": { + "ID": "479856", + "GroupID": "125065", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "itch.io", + "Scene": "0", + "ReleaseTitle": "RB: Axolotl v2022-03-06", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "505798159", + "Time": "2022-07-24 15:45:07", + "UserID": "67369", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 0, + "Leechers": 4, + "Snatched": 0 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/j8k4oi.jpg", + "Year": "2018", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "RB: Axolotl", + "gsrating": 0, + "ignrating": 0, + "leechers": 4, + "metarating": 0, + "scene": 0, + "seeders": 0, + "size": 493944, + "snatched": 0, + "time": 1658677507, + "totalcount": 1, + "userrating": 0, + "weight": "1500", + "year": 2018 + }, + "125064": { + "Artists": [ + { + "id": 70, + "name": "Android" + } + ], + "CategoryID": "1", + "FullTagList": "role_playing_game turn_based_strategy | ", + "ID": "125064", + "Name": "Catlandia: Crisis at Fort Pawprint", + "Rating": "13", + "TagList": "role_playing_game turn_based_strategy", + "Torrents": { + "479855": { + "ID": "479855", + "GroupID": "125064", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "itch.io", + "Scene": "0", + "ReleaseTitle": "Catlandia: Crisis at Fort Pawprint v1.1", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "180193554", + "Time": "2022-07-24 15:38:56", + "UserID": "67369", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 0, + "Leechers": 3, + "Snatched": 0 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/vitmm0.jpg", + "Year": "2020", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Catlandia: Crisis at Fort Pawprint", + "gsrating": 0, + "ignrating": 0, + "leechers": 3, + "metarating": 0, + "scene": 0, + "seeders": 0, + "size": 175971, + "snatched": 0, + "time": 1658677136, + "totalcount": 1, + "userrating": 0, + "weight": "1500", + "year": 2020 + }, + "125063": { + "Artists": [ + { + "id": 29, + "name": "Mac" + } + ], + "CategoryID": "1", + "FullTagList": "role_playing_game turn_based_strategy | ", + "ID": "125063", + "Name": "Catlandia: Crisis at Fort Pawprint", + "Rating": "13", + "TagList": "role_playing_game turn_based_strategy", + "Torrents": { + "479854": { + "ID": "479854", + "GroupID": "125063", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "itch.io", + "Scene": "0", + "ReleaseTitle": "Catlandia: Crisis at Fort Pawprint v1.1", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "157921193", + "Time": "2022-07-24 15:37:23", + "UserID": "67369", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 0, + "Leechers": 3, + "Snatched": 0 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/vitmm0.jpg", + "Year": "2020", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Catlandia: Crisis at Fort Pawprint", + "gsrating": 0, + "ignrating": 0, + "leechers": 3, + "metarating": 0, + "scene": 0, + "seeders": 0, + "size": 154220, + "snatched": 0, + "time": 1658677043, + "totalcount": 1, + "userrating": 0, + "weight": "1500", + "year": 2020 + }, + "125062": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "role_playing_game turn_based_strategy | ", + "ID": "125062", + "Name": "Catlandia: Crisis at Fort Pawprint", + "Rating": "13", + "TagList": "role_playing_game turn_based_strategy", + "Torrents": { + "479853": { + "ID": "479853", + "GroupID": "125062", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "itch.io", + "Scene": "0", + "ReleaseTitle": "Catlandia: Crisis at Fort Pawprint v1.1", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "158327568", + "Time": "2022-07-24 15:36:12", + "UserID": "67369", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 0, + "Leechers": 7, + "Snatched": 0 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/vitmm0.jpg", + "Year": "2020", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Catlandia: Crisis at Fort Pawprint", + "gsrating": 0, + "ignrating": 0, + "leechers": 7, + "metarating": 0, + "scene": 0, + "seeders": 0, + "size": 154617, + "snatched": 0, + "time": 1658676972, + "totalcount": 1, + "userrating": 0, + "weight": "1500", + "year": 2020 + }, + "125061": { + "Artists": [ + { + "id": 132, + "name": "Retro - Other" + } + ], + "CategoryID": "1", + "FullTagList": "music rhythm dancing | ", + "ID": "125061", + "Name": "Dance Dance Revolution SuperNova", + "Rating": "3", + "TagList": "music rhythm dancing", + "Torrents": { + "479852": { + "ID": "479852", + "GroupID": "125061", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "Japan", + "Language": "Japanese", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Dance Dance Revolution SuperNova", + "Miscellaneous": "ROM", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "7980787463", + "Time": "2022-07-24 15:32:18", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 9 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/jsvvv8.png", + "Year": "2006", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Dance Dance Revolution SuperNova", + "gsrating": 7, + "ignrating": 7, + "leechers": 0, + "metarating": 73, + "scene": 0, + "seeders": 10, + "size": 7793738, + "snatched": 9, + "time": 1658676738, + "totalcount": 1, + "userrating": 0, + "weight": "1501", + "year": 2006 + }, + "19478": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure action role_playing_game fantasy roguelike | alpha_access axonometric_games dark_ages early_access early_funding female_protagonist games_in_development gog_indev indev isometric_games medieval middle_ages paid_alpha parallel_projection procedural_generation steam_deck_verified", + "ID": "19478", + "Name": "Exanima", + "Rating": "13", + "TagList": "adventure action role_playing_game fantasy roguelike", + "Torrents": { + "196812": { + "ID": "196812", + "GroupID": "19478", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2015", + "RemasterTitle": "Early Access", + "Scene": "0", + "ReleaseTitle": "Exanima.Early.Access.v0.7.2", + "Miscellaneous": "Home Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3835142980", + "Time": "2019-05-06 17:11:12", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 22 + }, + "51612": { + "ID": "51612", + "GroupID": "19478", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2015", + "RemasterTitle": "Early Access", + "Scene": "0", + "ReleaseTitle": "Exanima v0.6.3.7", + "Miscellaneous": "Home Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "942449696", + "Time": "2016-07-03 21:19:44", + "UserID": "47965", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 68 + }, + "479851": { + "ID": "479851", + "GroupID": "19478", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2016", + "RemasterTitle": "GOG Early Access Edition", + "Scene": "0", + "ReleaseTitle": "Exanima v0.8.4c (57443)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "2", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3675049388", + "Time": "2022-07-24 15:28:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 13 + }, + "436624": { + "ID": "436624", + "GroupID": "19478", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2016", + "RemasterTitle": "GOG Early Access Edition", + "Scene": "0", + "ReleaseTitle": "Exanima v0.8.3q (53756)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "2", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3582230881", + "Time": "2022-02-19 12:08:45", + "UserID": "65096", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 29 + }, + "418220": { + "ID": "418220", + "GroupID": "19478", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2016", + "RemasterTitle": "GOG Early Access Edition", + "Scene": "0", + "ReleaseTitle": "Exanima v0.8.3 (52330)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "2", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3583109262", + "Time": "2021-12-21 21:42:07", + "UserID": "65096", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 21 + }, + "277315": { + "ID": "277315", + "GroupID": "19478", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2016", + "RemasterTitle": "GOG Early Access Edition", + "Scene": "0", + "ReleaseTitle": "Exanima v0.8.0.1 (37362)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "2", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2952037965", + "Time": "2020-04-13 18:30:30", + "UserID": "48186", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 82 + }, + "277316": { + "ID": "277316", + "GroupID": "19478", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Exanima", + "Miscellaneous": "GameDOX", + "GameDOXType": "GOG-Goodies", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3925656", + "Time": "2020-04-13 18:32:48", + "UserID": "48186", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 17 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/486174.jpg", + "Year": "2015", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Exanima", + "gsrating": 0, + "ignrating": 0, + "leechers": 1, + "metarating": 0, + "scene": 0, + "seeders": 62, + "size": 3745257, + "snatched": 252, + "time": 1658676539, + "totalcount": 7, + "userrating": 8, + "weight": "1500", + "year": 2015 + }, + "125017": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "puzzle role_playing_game science_fiction | ", + "ID": "125017", + "Name": "World of Haiku", + "Rating": "13", + "TagList": "puzzle role_playing_game science_fiction", + "Torrents": { + "479584": { + "ID": "479584", + "GroupID": "125017", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "World.Of.Haiku-TiNYiSO", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "19", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "846468377", + "Time": "2022-07-23 05:43:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 6 + }, + "479850": { + "ID": "479850", + "GroupID": "125017", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "World.of.Haiku.REPACK-KaOs", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "4", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "560622790", + "Time": "2022-07-24 15:21:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 7 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/xl00rf.jpg", + "Year": "2022", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "World of Haiku", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 1, + "seeders": 16, + "size": 826630, + "snatched": 13, + "time": 1658676101, + "totalcount": 2, + "userrating": 0, + "weight": "1500", + "year": 2022 + }, + "125060": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "action simulation casual | ", + "ID": "125060", + "Name": "Fly Free", + "Rating": "13", + "TagList": "action simulation casual", + "Torrents": [], + "WikiImage": "https:\/\/ptpimg.me\/4o2xb9.jpg", + "Year": "2022", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Fly Free", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 0, + "size": 0, + "snatched": 0, + "time": 1658675127, + "totalcount": 0, + "userrating": 0, + "weight": "1500", + "year": 2022 + }, + "125059": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "simulation strategy casual | ", + "ID": "125059", + "Name": "The Manga Works", + "Rating": "13", + "TagList": "simulation strategy casual", + "Torrents": [], + "WikiImage": "https:\/\/ptpimg.me\/y4k8u8.jpg", + "Year": "2022", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "The Manga Works", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 0, + "size": 0, + "snatched": 0, + "time": 1658674914, + "totalcount": 0, + "userrating": 0, + "weight": "1500", + "year": 2022 + }, + "125058": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure casual | ", + "ID": "125058", + "Name": "Tiki Tiki Hop", + "Rating": "13", + "TagList": "adventure casual", + "Torrents": [], + "WikiImage": "https:\/\/ptpimg.me\/j8q9m4.jpg", + "Year": "2022", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Tiki Tiki Hop", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 0, + "size": 0, + "snatched": 0, + "time": 1658674802, + "totalcount": 0, + "userrating": 0, + "weight": "1500", + "year": 2022 + }, + "125057": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "strategy | ", + "ID": "125057", + "Name": "The Three Kingdoms of the Sword", + "Rating": "13", + "TagList": "strategy", + "Torrents": [], + "WikiImage": "https:\/\/ptpimg.me\/86mtz0.jpg", + "Year": "2022", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "The Three Kingdoms of the Sword", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 0, + "size": 0, + "snatched": 0, + "time": 1658674550, + "totalcount": 0, + "userrating": 0, + "weight": "1500", + "year": 2022 + }, + "125024": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure walking_simulation | ", + "ID": "125024", + "Name": "Deer Journey", + "Rating": "13", + "TagList": "adventure walking_simulation", + "Torrents": { + "479626": { + "ID": "479626", + "GroupID": "125024", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Deer.Journey-TiNYiSO", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2002683904", + "Time": "2022-07-23 12:24:02", + "UserID": "68175", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 12 + }, + "479849": { + "ID": "479849", + "GroupID": "125024", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Deer.Journey.MULTi11.REPACK-KaOs", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "4", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1487074997", + "Time": "2022-07-24 14:40:05", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 13 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/x1l6ej.jpg", + "Year": "2022", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Deer Journey", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 1, + "seeders": 26, + "size": 1955746, + "snatched": 25, + "time": 1658673605, + "totalcount": 2, + "userrating": 0, + "weight": "1500", + "year": 2022 + }, + "103148": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "survival simulation strategy sandbox management | alpha_access dark_ages early_access early_funding games_in_development gog_indev indev medieval middle_ages paid_alpha the_irregular_corporation", + "ID": "103148", + "Name": "Going Medieval", + "Rating": "13", + "TagList": "survival simulation strategy sandbox management", + "Torrents": { + "479848": { + "ID": "479848", + "GroupID": "103148", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2021", + "RemasterTitle": "GOG Edition (InDev)", + "Scene": "0", + "ReleaseTitle": "Going Medieval v0.8.36 (57419)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "300588832", + "Time": "2022-07-24 14:39:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 9 + }, + "472538": { + "ID": "472538", + "GroupID": "103148", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2021", + "RemasterTitle": "GOG Edition (InDev)", + "Scene": "0", + "ReleaseTitle": "Going Medieval v0.8.26REL (56574)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "300612760", + "Time": "2022-06-18 08:31:43", + "UserID": "48186", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 20 + }, + "469912": { + "ID": "469912", + "GroupID": "103148", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2021", + "RemasterTitle": "GOG Edition (InDev)", + "Scene": "0", + "ReleaseTitle": "Going Medieval v0.8.20 (56309)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "299220136", + "Time": "2022-06-05 04:14:30", + "UserID": "48186", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 21 + }, + "444010": { + "ID": "444010", + "GroupID": "103148", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2021", + "RemasterTitle": "GOG Edition (InDev)", + "Scene": "0", + "ReleaseTitle": "Going Medieval v0.7.17-REL (54080)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "307651200", + "Time": "2022-03-09 20:41:55", + "UserID": "65096", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 24, + "Leechers": 0, + "Snatched": 40 + }, + "376909": { + "ID": "376909", + "GroupID": "103148", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Going Medieval Soundtrack", + "Miscellaneous": "GameDOX", + "GameDOXType": "GOG-Goodies", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "101917876", + "Time": "2021-06-04 05:05:07", + "UserID": "8362", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 12 + }, + "428628": { + "ID": "428628", + "GroupID": "103148", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Going.Medieval.Early.Access.Plus.14.Trainer.Updated.2022.02.05-FLiNG", + "Miscellaneous": "GameDOX", + "GameDOXType": "Trainer", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "890538", + "Time": "2022-02-08 00:52:44", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 11 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/2h6cud.jpg", + "Year": "2021", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Going Medieval", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 68, + "size": 300441, + "snatched": 113, + "time": 1658673557, + "totalcount": 6, + "userrating": 10, + "weight": "1500", + "year": 2021 + }, + "70750": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "survival simulation strategy sandbox city_building management | alpha_access cel_shading_games early_access early_funding games_in_development gog_indev indev kongregate paid_alpha pajama_llama_games unity", + "ID": "70750", + "Name": "Flotsam", + "Rating": "13", + "TagList": "survival simulation strategy sandbox city_building management", + "Torrents": { + "295082": { + "ID": "295082", + "GroupID": "70750", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2019", + "RemasterTitle": "Early Access", + "Scene": "0", + "ReleaseTitle": "Flotsam v0.3.4e1", + "Miscellaneous": "Home Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "370934118", + "Time": "2020-07-11 02:00:37", + "UserID": "50133", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 42 + }, + "479847": { + "ID": "479847", + "GroupID": "70750", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2019", + "RemasterTitle": "GOG Early Access", + "Scene": "0", + "ReleaseTitle": "Flotsam v0.6.3p2 (57300)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "469078904", + "Time": "2022-07-24 14:25:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 9 + }, + "472553": { + "ID": "472553", + "GroupID": "70750", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2019", + "RemasterTitle": "GOG Early Access", + "Scene": "0", + "ReleaseTitle": "Flotsam v0.6.2p1 (56445)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "468119192", + "Time": "2022-06-18 09:34:29", + "UserID": "48186", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 17 + }, + "461820": { + "ID": "461820", + "GroupID": "70750", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2019", + "RemasterTitle": "GOG Early Access", + "Scene": "0", + "ReleaseTitle": "Flotsam v0.6.1 (55406)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "481371272", + "Time": "2022-05-06 10:42:47", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 12 + }, + "458984": { + "ID": "458984", + "GroupID": "70750", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2019", + "RemasterTitle": "GOG Early Access", + "Scene": "0", + "ReleaseTitle": "Flotsam v0.6.0p1 (55020)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "480998688", + "Time": "2022-04-17 10:07:58", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 16 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/0kwu5s.jpg", + "Year": "2019", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Flotsam", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 37, + "size": 470090, + "snatched": 96, + "time": 1658672747, + "totalcount": 5, + "userrating": 4, + "weight": "1500", + "year": 2019 + }, + "111982": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure role_playing_game turn_based_strategy strategy roguelike | ", + "ID": "111982", + "Name": "Brutal Orchestra", + "Rating": "13", + "TagList": "adventure role_playing_game turn_based_strategy strategy roguelike", + "Torrents": { + "417693": { + "ID": "417693", + "GroupID": "111982", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Brutal.Orchestra-Unleashed", + "Miscellaneous": "Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "18", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "151351080", + "Time": "2021-12-17 21:28:35", + "UserID": "58071", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 22 + }, + "479846": { + "ID": "479846", + "GroupID": "111982", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Brutal.Orchestra.v1.2.1-ALI213", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "180727771", + "Time": "2022-07-24 14:09:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 8 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/p68hdd.jpg", + "Year": "2021", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Brutal Orchestra", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 1, + "seeders": 18, + "size": 176492, + "snatched": 30, + "time": 1658671777, + "totalcount": 2, + "userrating": 0, + "weight": "1500", + "year": 2021 + }, + "103462": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "puzzle science_fiction turn_based_strategy strategy 4x management | outer_space unity", + "ID": "103462", + "Name": "Slipways", + "Rating": "5", + "TagList": "puzzle science_fiction turn_based_strategy strategy 4x management", + "Torrents": { + "475836": { + "ID": "475836", + "GroupID": "103462", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Slipways_v1.3_RIP-VACE", + "Miscellaneous": "Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "19", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "160396514", + "Time": "2022-07-06 05:56:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 2, + "Leechers": 0, + "Snatched": 5 + }, + "420871": { + "ID": "420871", + "GroupID": "103462", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Slipways.v1.2-DARKSiDERS", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "30", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "408189256", + "Time": "2021-12-30 08:54:35", + "UserID": "66679", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 8 + }, + "377338": { + "ID": "377338", + "GroupID": "103462", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Slipways-SKIDROW", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "36", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "497193016", + "Time": "2021-06-07 01:13:22", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 18 + }, + "479845": { + "ID": "479845", + "GroupID": "103462", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2021", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Slipways v1.3-1086 (57226)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "622120944", + "Time": "2022-07-24 13:56:46", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 7 + }, + "476987": { + "ID": "476987", + "GroupID": "103462", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2021", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Slipways v1.3-1083 (57159)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "620796976", + "Time": "2022-07-12 01:25:53", + "UserID": "48186", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 12 + }, + "377130": { + "ID": "377130", + "GroupID": "103462", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2021", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Slipways v1.0-612 (47510)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "455317784", + "Time": "2021-06-05 10:06:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 31 + }, + "428859": { + "ID": "428859", + "GroupID": "103462", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Slipways.Update.v1.2.Build.926-SiMPLEX", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.2", + "FileCount": "3", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "5061689", + "Time": "2022-02-09 15:10:19", + "UserID": "66679", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 11 + }, + "424886": { + "ID": "424886", + "GroupID": "103462", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Slipways.Update.v1.2.Build.908-SiMPLEX", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.2", + "FileCount": "3", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4944302", + "Time": "2022-01-17 17:20:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 9 + }, + "422907": { + "ID": "422907", + "GroupID": "103462", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Slipways.Update.v1.2.Build.896-SiMPLEX", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.2", + "FileCount": "3", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "5033102", + "Time": "2022-01-06 19:38:46", + "UserID": "66679", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 16 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/596fde.jpg", + "Year": "2021", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Slipways", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 1, + "seeders": 55, + "size": 607540, + "snatched": 117, + "time": 1658671006, + "totalcount": 9, + "userrating": 3, + "weight": "1501", + "year": 2021 + }, + "125055": { + "Artists": [ + { + "id": 29, + "name": "Mac" + } + ], + "CategoryID": "1", + "FullTagList": "survival casual | games_based_on_novels local_co_op_support pixel_art pixel_graphics unity", + "ID": "125055", + "Name": "Mending Wall", + "Rating": "13", + "TagList": "survival casual", + "Torrents": { + "479844": { + "ID": "479844", + "GroupID": "125055", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2021", + "RemasterTitle": "itch.io", + "Scene": "0", + "ReleaseTitle": "Mending Wall (2021.01.03)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "26059329", + "Time": "2022-07-24 13:33:34", + "UserID": "65030", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 3 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/iq9234.png", + "Year": "2021", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Mending Wall", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 4, + "size": 25449, + "snatched": 3, + "time": 1658669614, + "totalcount": 1, + "userrating": 0, + "weight": "1500", + "year": 2021 + }, + "125054": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "survival casual | games_based_on_novels local_co_op_support pixel_art pixel_graphics unity", + "ID": "125054", + "Name": "Mending Wall", + "Rating": "13", + "TagList": "survival casual", + "Torrents": { + "479843": { + "ID": "479843", + "GroupID": "125054", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2021", + "RemasterTitle": "itch.io", + "Scene": "0", + "ReleaseTitle": "Mending Wall (2021.01.03)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "24292432", + "Time": "2022-07-24 13:33:32", + "UserID": "65030", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 4 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/iq9234.png", + "Year": "2021", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Mending Wall", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 5, + "size": 23724, + "snatched": 4, + "time": 1658669612, + "totalcount": 1, + "userrating": 0, + "weight": "1500", + "year": 2021 + }, + "125056": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "action bullet_hell | ", + "ID": "125056", + "Name": "Touhou Gouyoku Ibun ~ Suibotsushita Chinshuu Jigoku", + "Rating": "13", + "TagList": "action bullet_hell", + "Torrents": { + "479842": { + "ID": "479842", + "GroupID": "125056", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Japanese", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Touhou Gouyoku Ibun ~ Suibotsushita Chinshuu Jigoku", + "Miscellaneous": "Home Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "10", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "317709264", + "Time": "2022-07-24 13:27:10", + "UserID": "68230", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 6 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/z6j0ea.jpg", + "Year": "2021", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Touhou Gouyoku Ibun ~ Suibotsushita Chinshuu Jigoku", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 6, + "size": 310263, + "snatched": 6, + "time": 1658669230, + "totalcount": 1, + "userrating": 0, + "weight": "1500", + "year": 2021 + }, + "87175": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure action first_person_shooter | co_op co_op_support controller controller_support croteam devolver_digital gamepad gamepad_support native_controller_support native_gamepad_support nucleus_co_op_supported_games serious_engine serious_sam", + "ID": "87175", + "Name": "Serious Sam 4", + "Rating": "9", + "TagList": "adventure action first_person_shooter", + "Torrents": { + "316216": { + "ID": "316216", + "GroupID": "87175", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Serious_Sam_4-HOODLUM", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "172", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "42484592935", + "Time": "2020-10-10 22:47:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 121 + }, + "479841": { + "ID": "479841", + "GroupID": "87175", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "Digital Deluxe Edition", + "Scene": "0", + "ReleaseTitle": "Serious.Sam.4.v1.08.REPACK-KaOs", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "7", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "29377778924", + "Time": "2022-07-24 12:48:41", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 17 + }, + "364876": { + "ID": "364876", + "GroupID": "87175", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "Digital Deluxe Edition", + "Scene": "0", + "ReleaseTitle": "Serious Sam 4: Digital Deluxe Edition v1.08\/591667 + DLC + Bonus [FitGirl Repack]", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "12", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "31057192478", + "Time": "2021-04-04 17:29:53", + "UserID": "63901", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 18, + "Leechers": 2, + "Snatched": 61 + }, + "362589": { + "ID": "362589", + "GroupID": "87175", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Serious Sam 4 v1.08 (45801)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "13", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "46668760517", + "Time": "2021-03-28 12:22:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 52 + }, + "310897": { + "ID": "310897", + "GroupID": "87175", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Serious Sam 4 v1.01 (41481)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "12", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "41175321171", + "Time": "2020-09-24 14:57:11", + "UserID": "54831", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 43, + "Leechers": 0, + "Snatched": 294 + }, + "311014": { + "ID": "311014", + "GroupID": "87175", + "CategoryID": "1", + "Format": "PDF", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "The Art of Serious Sam 4", + "Miscellaneous": "GameDOX", + "GameDOXType": "Artwork", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "97273678", + "Time": "2020-09-25 16:42:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 58 + }, + "310906": { + "ID": "310906", + "GroupID": "87175", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Serious Sam 4", + "Miscellaneous": "GameDOX", + "GameDOXType": "GOG-Goodies", + "GameDOXVers": "", + "FileCount": "5", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3341980766", + "Time": "2020-09-24 17:24:45", + "UserID": "54831", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 2, + "Snatched": 118 + }, + "330205": { + "ID": "330205", + "GroupID": "87175", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Serious.Sam.4.v1.0-v1.05.Plus.15.Trainer-FLiNG", + "Miscellaneous": "GameDOX", + "GameDOXType": "Trainer", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "826150", + "Time": "2020-11-27 15:35:27", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 21 + }, + "320403": { + "ID": "320403", + "GroupID": "87175", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Serious Sam 4 v1.04 (41822) to v1.05 (42296) - Update", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.05", + "FileCount": "2", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3516536967", + "Time": "2020-10-28 23:04:16", + "UserID": "62976", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 13, + "Leechers": 0, + "Snatched": 101 + }, + "316486": { + "ID": "316486", + "GroupID": "87175", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Serious Sam 4 v1.03 (41633) to v1.04 (41822)", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.04", + "FileCount": "4", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "9454923052", + "Time": "2020-10-13 04:27:05", + "UserID": "61542", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 78 + }, + "315074": { + "ID": "315074", + "GroupID": "87175", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Serious Sam 4 v1.02 (41512) to v1.03 (41633)", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.03", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1169820320", + "Time": "2020-10-06 23:08:59", + "UserID": "8362", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 75 + }, + "315073": { + "ID": "315073", + "GroupID": "87175", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Serious Sam 4 v1.01 (41481) to v1.02 (41512)", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.02", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "833017392", + "Time": "2020-10-06 23:08:36", + "UserID": "8362", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 61 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/n8moz5.jpg", + "Year": "2020", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Serious Sam 4", + "gsrating": 0, + "ignrating": 5, + "leechers": 4, + "metarating": 68, + "scene": 1, + "seeders": 178, + "size": 45574962, + "snatched": 1057, + "time": 1658666921, + "totalcount": 12, + "userrating": 0, + "weight": "1503", + "year": 2020 + }, + "124633": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure strategy fantasy tower_defense bullet_hell tactics | alawar_entertainment alawar_entertainment_inc axonometric_games isometric_games parallel_projection pixel_art pixel_graphics unity", + "ID": "124633", + "Name": "Necrosmith", + "Rating": "13", + "TagList": "adventure strategy fantasy tower_defense bullet_hell tactics", + "Torrents": { + "477491": { + "ID": "477491", + "GroupID": "124633", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Necrosmith.v1.0.0.190-ALI213", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "92519754", + "Time": "2022-07-14 11:15:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 7 + }, + "479578": { + "ID": "479578", + "GroupID": "124633", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Necrosmith v1.0.0.235", + "Miscellaneous": "Home Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "120525429", + "Time": "2022-07-23 05:24:29", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 14 + }, + "479840": { + "ID": "479840", + "GroupID": "124633", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Necrosmith v1.1.0.238 (57468)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "127657616", + "Time": "2022-07-24 12:47:32", + "UserID": "65096", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 14 + }, + "477695": { + "ID": "477695", + "GroupID": "124633", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Necrosmith v1.0.0.204 (57295)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "126454552", + "Time": "2022-07-15 12:36:54", + "UserID": "48186", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 37, + "Leechers": 0, + "Snatched": 47 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/33753r.jpg", + "Year": "2022", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Necrosmith", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 68, + "size": 124666, + "snatched": 82, + "time": 1658666852, + "totalcount": 4, + "userrating": 1, + "weight": "1500", + "year": 2022 + }, + "110129": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "action first_person_shooter fantasy | 1c_company 1c_entertainment byte_barrel fulqrum_games hp_lovecraft_inspired_games out_of_early_access physx unreal_engine", + "ID": "110129", + "Name": "Forgive Me Father", + "Rating": "13", + "TagList": "action first_person_shooter fantasy", + "Torrents": { + "458112": { + "ID": "458112", + "GroupID": "110129", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Forgive.Me.Father-DOGE", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "85", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4134416123", + "Time": "2022-04-12 07:36:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 35, + "Leechers": 0, + "Snatched": 63 + }, + "457360": { + "ID": "457360", + "GroupID": "110129", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Forgive Me Father [FitGirl Repack]", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "7", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2284434775", + "Time": "2022-04-08 20:05:21", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 46, + "Leechers": 0, + "Snatched": 73 + }, + "479839": { + "ID": "479839", + "GroupID": "110129", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Forgive Me Father v1.3.8 (57443)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "2", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4268978187", + "Time": "2022-07-24 12:47:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 19 + }, + "473673": { + "ID": "473673", + "GroupID": "110129", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Forgive Me Father v1.3.6 (56774)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "2", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4266486206", + "Time": "2022-06-26 16:50:24", + "UserID": "48186", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 26, + "Leechers": 0, + "Snatched": 43 + }, + "457358": { + "ID": "457358", + "GroupID": "110129", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Forgive Me Father v1.0 (54920)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "2", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4232007840", + "Time": "2022-04-08 18:44:48", + "UserID": "48186", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 56, + "Leechers": 0, + "Snatched": 104 + }, + "471735": { + "ID": "471735", + "GroupID": "110129", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Forgive.Me.Father.Update.v1.2-ANOMALY", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.2", + "FileCount": "24", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1082000060", + "Time": "2022-06-14 18:35:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 13 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/g5pt0r.jpg", + "Year": "2022", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Forgive Me Father", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 74, + "scene": 1, + "seeders": 186, + "size": 4168925, + "snatched": 315, + "time": 1658666837, + "totalcount": 6, + "userrating": 6, + "weight": "1500", + "year": 2022 + }, + "124667": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure role_playing_game fantasy | co_op co_op_support controller controller_support gamepad gamepad_support gamera_interactive local_co_op_support local_multiplayer native_controller_support native_gamepad_support shared_screen shared_screen_multiplayer single_screen_multiplayer", + "ID": "124667", + "Name": "Alaloth: Champions of The Four Kingdoms", + "Rating": "13", + "TagList": "adventure role_playing_game fantasy", + "Torrents": { + "479838": { + "ID": "479838", + "GroupID": "124667", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "GOG (InDev)", + "Scene": "0", + "ReleaseTitle": "Alaloth Champions of the Four Kingdoms v2022.07.22. 32a4522 (57473)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "3", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "7982170548", + "Time": "2022-07-24 12:44:10", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 17, + "Leechers": 0, + "Snatched": 17 + }, + "477594": { + "ID": "477594", + "GroupID": "124667", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "GOG (InDev)", + "Scene": "0", + "ReleaseTitle": "Alaloth Champions of the Four Kingdoms v2022.07.13.62ea5af(57258)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "3", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "7976891311", + "Time": "2022-07-14 16:59:32", + "UserID": "59908", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 18 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/881o61.jpg", + "Year": "2022", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Alaloth: Champions of The Four Kingdoms", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 29, + "size": 7795089, + "snatched": 35, + "time": 1658666650, + "totalcount": 2, + "userrating": 0, + "weight": "1500", + "year": 2022 + }, + "124952": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure simulation | ", + "ID": "124952", + "Name": "Endling - Extinction is Forever", + "Rating": "7", + "TagList": "adventure simulation", + "Torrents": { + "479837": { + "ID": "479837", + "GroupID": "124952", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Endling: Extinction is Forever [FitGirl Repack]", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "10", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1438397145", + "Time": "2022-07-24 12:19:20", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 14 + }, + "479123": { + "ID": "479123", + "GroupID": "124952", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Endling - Extinction is Forever v0.16.25 (64bit) (57084)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "2", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "2637312175", + "Time": "2022-07-21 16:36:52", + "UserID": "63133", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 15, + "Leechers": 0, + "Snatched": 20 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/24zw6t.jpg", + "Year": "2022", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Endling - Extinction is Forever", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 31, + "size": 2575501, + "snatched": 34, + "time": 1658665160, + "totalcount": 2, + "userrating": 0, + "weight": "1502", + "year": 2022 + }, + "124146": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure action role_playing_game fantasy | unity", + "ID": "124146", + "Name": "Xel", + "Rating": "13", + "TagList": "adventure action role_playing_game fantasy", + "Torrents": { + "477408": { + "ID": "477408", + "GroupID": "124146", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "XEL v1.0.3.144 [FitGirl Repack]", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "10", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3298029235", + "Time": "2022-07-14 00:48:54", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 17 + }, + "479836": { + "ID": "479836", + "GroupID": "124146", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "XEL v1.0.3.6 (64bit) (57439)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "3", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4686575314", + "Time": "2022-07-24 11:48:27", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 16 + }, + "477958": { + "ID": "477958", + "GroupID": "124146", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "XEL v1.0.3.179.(57278)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "3", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4661616923", + "Time": "2022-07-16 13:25:33", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 14 + }, + "477566": { + "ID": "477566", + "GroupID": "124146", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "XEL v1.0.3.130 (64bit) (57133)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "3", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4733278061", + "Time": "2022-07-14 15:52:39", + "UserID": "63133", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 16 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/66t5wu.jpg", + "Year": "2022", + "categoryid": 1, + "checked": 1, + "dupable": 0, + "freetorrent": 0, + "groupname": "Xel", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 45, + "size": 4622342, + "snatched": 63, + "time": 1658663307, + "totalcount": 4, + "userrating": 0, + "weight": "1500", + "year": 2022 + }, + "125053": { + "Artists": [ + { + "id": 144, + "name": "Switch" + } + ], + "CategoryID": "1", + "FullTagList": "simulation strategy | koei_tecmo nobunagas_ambition", + "ID": "125053", + "Name": "Nobunaga's Ambition: Rebirth", + "Rating": "13", + "TagList": "simulation strategy", + "Torrents": { + "479835": { + "ID": "479835", + "GroupID": "125053", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "Other", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Nobunaga_no_Yabou_Shinsei_MULTI_NSW-HR", + "Miscellaneous": "ROM", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "88", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "4252631302", + "Time": "2022-07-24 11:43:07", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 13 + }, + "479834": { + "ID": "479834", + "GroupID": "125053", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "Other", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Nobunaga_no_Yabou_Shinsei_Update_v1.0.1_MULTI_NSW-HR", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.0.1", + "FileCount": "3", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "44633296", + "Time": "2022-07-24 11:40:08", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 5 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/23235n.jpg", + "Year": "2022", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Nobunaga's Ambition: Rebirth", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 1, + "seeders": 24, + "size": 4152961, + "snatched": 18, + "time": 1658662987, + "totalcount": 2, + "userrating": 0, + "weight": "1500", + "year": 2022 + }, + "80891": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "action shooter roguelike | co_op co_op_support controller controller_support gamepad gamepad_support headup_games local_co_op_support local_multiplayer native_controller_support native_gamepad_support procedural_generation retrific retrific_game_studio shared_screen shared_screen_multiplayer single_screen_multiplayer western", + "ID": "80891", + "Name": "Colt Canyon", + "Rating": "13", + "TagList": "action shooter roguelike", + "Torrents": { + "417762": { + "ID": "417762", + "GroupID": "80891", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Colt.Canyon.v1.1.1.0-SiMPLEX", + "Miscellaneous": "Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "13", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "103170548", + "Time": "2021-12-18 15:35:43", + "UserID": "65052", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 15 + }, + "341171": { + "ID": "341171", + "GroupID": "80891", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Colt.Canyon.v1.0.2.0.RIP-SiMPLEX", + "Miscellaneous": "Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "13", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "101449596", + "Time": "2021-01-14 07:25:43", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 29 + }, + "304061": { + "ID": "304061", + "GroupID": "80891", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Colt.Canyon.v1.0.1.6-SiMPLEX", + "Miscellaneous": "Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "13", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "100557019", + "Time": "2020-08-20 18:50:13", + "UserID": "54928", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 3, + "Leechers": 0, + "Snatched": 24 + }, + "289969": { + "ID": "289969", + "GroupID": "80891", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "ColtCanyon_RIP-VACE", + "Miscellaneous": "Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "12", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "91153336", + "Time": "2020-06-17 16:52:33", + "UserID": "61490", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 15 + }, + "479833": { + "ID": "479833", + "GroupID": "80891", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Colt Canyon v1.2.0.1 (57420)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "536246216", + "Time": "2022-07-24 11:25:45", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 9, + "Leechers": 0, + "Snatched": 8 + }, + "475214": { + "ID": "475214", + "GroupID": "80891", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Colt Canyon v1.2.0.0 (56968)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "532474480", + "Time": "2022-07-03 07:25:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 8 + }, + "289971": { + "ID": "289971", + "GroupID": "80891", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Colt Canyon v1.0.0.0.1 (39087)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "341850336", + "Time": "2020-06-17 17:05:11", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 3, + "Leechers": 0, + "Snatched": 34 + }, + "475216": { + "ID": "475216", + "GroupID": "80891", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Colt Canyon", + "Miscellaneous": "GameDOX", + "GameDOXType": "GOG-Goodies", + "GameDOXVers": "", + "FileCount": "2", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "343632022", + "Time": "2022-07-03 08:00:30", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 3, + "Leechers": 0, + "Snatched": 5 + }, + "431220": { + "ID": "431220", + "GroupID": "80891", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Colt.Canyon.Update.v1.1.1.1-SiMPLEX", + "Miscellaneous": "GameDOX", + "GameDOXType": "Update", + "GameDOXVers": "1.1.1.1", + "FileCount": "4", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "11440050", + "Time": "2022-02-15 16:45:31", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 9 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/o41756.jpg", + "Year": "2020", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Colt Canyon", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 1, + "seeders": 41, + "size": 523678, + "snatched": 147, + "time": 1658661944, + "totalcount": 9, + "userrating": 0, + "weight": "1500", + "year": 2020 + }, + "105323": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure action role_playing_game shooter open_world | alpha_access controller controller_support early_access early_funding gamepad gamepad_support games_in_development gog_indev indev native_controller_support native_gamepad_support paid_alpha pixel_art pixel_graphics steam_deck_verified tinybuild_games unity", + "ID": "105323", + "Name": "Black Skylands", + "Rating": "13", + "TagList": "adventure action role_playing_game shooter open_world", + "Torrents": { + "479832": { + "ID": "479832", + "GroupID": "105323", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2021", + "RemasterTitle": "GOG Edition (InDev)", + "Scene": "0", + "ReleaseTitle": "Black Skylands v0.3.3 (bb30d8cc72) (57204)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "532198064", + "Time": "2022-07-24 11:16:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 12, + "Leechers": 0, + "Snatched": 8 + }, + "473979": { + "ID": "473979", + "GroupID": "105323", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2021", + "RemasterTitle": "GOG Edition (InDev)", + "Scene": "0", + "ReleaseTitle": "Black Skylands v0.3.2 (9572fc40d0) (56777)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "531954600", + "Time": "2022-06-28 19:22:56", + "UserID": "20360", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 11 + }, + "454846": { + "ID": "454846", + "GroupID": "105323", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2021", + "RemasterTitle": "GOG Edition (InDev)", + "Scene": "0", + "ReleaseTitle": "Black Skylands v0.2.6 (ebeccfb195) (53773)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "304951280", + "Time": "2022-03-27 19:58:58", + "UserID": "65096", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 15 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/4149hn.jpg", + "Year": "2021", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Black Skylands", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 25, + "size": 519725, + "snatched": 34, + "time": 1658661407, + "totalcount": 3, + "userrating": 2, + "weight": "1500", + "year": 2021 + }, + "81057": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure action role_playing_game strategy | gato_studio gato_studios out_of_early_access unreal_engine", + "ID": "81057", + "Name": "The Waylanders", + "Rating": "13", + "TagList": "adventure action role_playing_game strategy", + "Torrents": { + "473973": { + "ID": "473973", + "GroupID": "81057", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "The.Waylanders.v1.10-DOGE", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "123", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "30089545597", + "Time": "2022-06-28 17:35:02", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 15 + }, + "427696": { + "ID": "427696", + "GroupID": "81057", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "The.Waylanders-DOGE", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "123", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "30047727756", + "Time": "2022-02-02 18:12:25", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 16 + }, + "479831": { + "ID": "479831", + "GroupID": "81057", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "The.Waylanders.V1.04.REPACK-KaOs", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "7", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "18675529252", + "Time": "2022-07-24 10:57:14", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 16, + "Leechers": 0, + "Snatched": 15 + }, + "476188": { + "ID": "476188", + "GroupID": "81057", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "The Waylanders v1.10 [FitGirl Repack]", + "Miscellaneous": "P2P", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "8", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "18665266057", + "Time": "2022-07-07 16:50:17", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 2, + "Snatched": 18 + }, + "462107": { + "ID": "462107", + "GroupID": "81057", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "The Waylanders v1.10 (55410)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "9", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "31613819664", + "Time": "2022-05-08 10:49:00", + "UserID": "65096", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 14 + }, + "427890": { + "ID": "427890", + "GroupID": "81057", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "The Waylanders v1.04 (53394)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "9", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "31573295636", + "Time": "2022-02-03 21:23:37", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 3, + "Leechers": 0, + "Snatched": 16 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/ob0an5.jpg", + "Year": "2020", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "The Waylanders", + "gsrating": 0, + "ignrating": 0, + "leechers": 2, + "metarating": 0, + "scene": 1, + "seeders": 48, + "size": 30872871, + "snatched": 94, + "time": 1658660234, + "totalcount": 6, + "userrating": -2, + "weight": "1500", + "year": 2020 + }, + "121154": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure action survival fantasy open_world hack_and_slash | alpha_access co_op co_op_support early_access early_funding games_in_development gog_indev indev nucleus_co_op_supported_games paid_alpha stunlock_studios unity vampire", + "ID": "121154", + "Name": "V Rising", + "Rating": "13", + "TagList": "adventure action survival fantasy open_world hack_and_slash", + "Torrents": { + "479829": { + "ID": "479829", + "GroupID": "121154", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "Early Access", + "Scene": "0", + "ReleaseTitle": "V Rising v0.5.42584 + 2 DLCs", + "Miscellaneous": "Home Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3460932255", + "Time": "2022-07-24 10:53:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 14, + "Leechers": 0, + "Snatched": 15 + }, + "475867": { + "ID": "475867", + "GroupID": "121154", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "Early Access", + "Scene": "0", + "ReleaseTitle": "V Rising v0.5.42405", + "Miscellaneous": "Home Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3486014607", + "Time": "2022-07-06 11:28:55", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 30 + }, + "473282": { + "ID": "473282", + "GroupID": "121154", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2022", + "RemasterTitle": "Early Access", + "Scene": "0", + "ReleaseTitle": "V Rising v0.5.42236", + "Miscellaneous": "Home Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "3478217940", + "Time": "2022-06-24 10:03:48", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 38 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/673s69.jpg", + "Year": "2022", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "V Rising", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 54, + "size": 3404312, + "snatched": 83, + "time": 1658660022, + "totalcount": 3, + "userrating": 6, + "weight": "1500", + "year": 2022 + }, + "83580": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure role_playing_game simulation fantasy casual management | alpha_access early_access early_funding games_in_development gog_indev indev isolated_games paid_alpha pixel_art pixel_graphics unity", + "ID": "83580", + "Name": "Travellers Rest", + "Rating": "1", + "TagList": "adventure role_playing_game simulation fantasy casual management", + "Torrents": { + "331365": { + "ID": "331365", + "GroupID": "83580", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "Early Access", + "Scene": "0", + "ReleaseTitle": "Travellers Rest x64 Build 2020-11-15", + "Miscellaneous": "Home Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "110268154", + "Time": "2020-12-04 15:52:40", + "UserID": "44169", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 3, + "Leechers": 0, + "Snatched": 18 + }, + "298253": { + "ID": "298253", + "GroupID": "83580", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "Early Access", + "Scene": "0", + "ReleaseTitle": "Travellers Rest Build 5336191", + "Miscellaneous": "Home Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "115132662", + "Time": "2020-07-29 12:39:40", + "UserID": "54831", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 42 + }, + "479830": { + "ID": "479830", + "GroupID": "83580", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "GOG Early Access", + "Scene": "0", + "ReleaseTitle": "Travellers Rest v0.5.1.9 (57225)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "189708136", + "Time": "2022-07-24 10:53:42", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 7 + }, + "476154": { + "ID": "476154", + "GroupID": "83580", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "GOG Early Access", + "Scene": "0", + "ReleaseTitle": "Travellers Rest v0.5.1.8f (57083)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "188866024", + "Time": "2022-07-07 13:49:48", + "UserID": "48186", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 10, + "Leechers": 0, + "Snatched": 14 + }, + "472568": { + "ID": "472568", + "GroupID": "83580", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "GOG Early Access", + "Scene": "0", + "ReleaseTitle": "Travellers Rest v0.5.1.1 (56633)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "192432496", + "Time": "2022-06-18 11:08:51", + "UserID": "48186", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 12 + }, + "383740": { + "ID": "383740", + "GroupID": "83580", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Travellers Rest Soundtrack", + "Miscellaneous": "GameDOX", + "GameDOXType": "GOG-Goodies", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "51264565", + "Time": "2021-07-01 15:35:12", + "UserID": "8362", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 2, + "Leechers": 0, + "Snatched": 12 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/c73z37.jpg", + "Year": "2020", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Travellers Rest", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 34, + "size": 187923, + "snatched": 105, + "time": 1658660022, + "totalcount": 6, + "userrating": 2, + "weight": "1501", + "year": 2020 + }, + "125052": { + "Artists": [], + "CategoryID": "4", + "FullTagList": "electronic | ", + "ID": "125052", + "Name": "World War III: Black Gold Official Soundtrack by Maciej Pawlowski", + "Rating": "0", + "TagList": "electronic", + "Torrents": { + "479827": { + "ID": "479827", + "GroupID": "125052", + "CategoryID": "4", + "Format": "MP3", + "Encoding": "320", + "Region": "", + "Language": "", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "World War III: Black Gold Official Soundtrack by Maciej Pawlowski", + "Miscellaneous": "", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "27", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "150448924", + "Time": "2022-07-24 10:51:48", + "UserID": "67854", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 3 + }, + "479826": { + "ID": "479826", + "GroupID": "125052", + "CategoryID": "4", + "Format": "MP3", + "Encoding": "V0 (VBR)", + "Region": "", + "Language": "", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "World War III: Black Gold Official Soundtrack by Maciej Pawlowski", + "Miscellaneous": "", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "27", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "101543244", + "Time": "2022-07-24 10:51:13", + "UserID": "67854", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 4 + }, + "479825": { + "ID": "479825", + "GroupID": "125052", + "CategoryID": "4", + "Format": "FLAC", + "Encoding": "Lossless", + "Region": "", + "Language": "", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "World War III: Black Gold Official Soundtrack by Maciej Pawlowski", + "Miscellaneous": "", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "27", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "322585766", + "Time": "2022-07-24 10:50:20", + "UserID": "67854", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 5 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/693x41.jpg", + "Year": "2018", + "categoryid": 4, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "World War III: Black Gold Official Soundtrack by Maciej Pawlowski", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 13, + "size": 315026, + "snatched": 12, + "time": 1658659908, + "totalcount": 3, + "userrating": 0, + "weight": "1489", + "year": 2018 + }, + "41613": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure | controller controller_support episodic_story gamepad gamepad_support native_controller_support native_gamepad_support portable_moose unity", + "ID": "41613", + "Name": "Sally Face", + "Rating": "13", + "TagList": "adventure", + "Torrents": { + "171244": { + "ID": "171244", + "GroupID": "41613", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Sally.Face.Episode.4.RIP-SiMPLEX", + "Miscellaneous": "Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "42", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "395859501", + "Time": "2018-12-02 16:32:18", + "UserID": "58206", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 24 + }, + "232801": { + "ID": "232801", + "GroupID": "41613", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Sally.Face.Episode.5-PLAZA", + "Miscellaneous": "Full ISO", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "26", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "1172881125", + "Time": "2019-12-13 17:57:18", + "UserID": "55139", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 46 + }, + "479824": { + "ID": "479824", + "GroupID": "41613", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2019", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Sally Face v1.5.42 (57309)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "519677008", + "Time": "2022-07-24 10:48:53", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 6 + }, + "241012": { + "ID": "241012", + "GroupID": "41613", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2019", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Sally Face v1.5.09 (36456)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "518981304", + "Time": "2020-03-07 16:36:38", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 6, + "Leechers": 0, + "Snatched": 39 + }, + "232819": { + "ID": "232819", + "GroupID": "41613", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2019", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Sally Face v1.5.04 (34587)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "992746792", + "Time": "2019-12-14 01:00:04", + "UserID": "60996", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 3, + "Leechers": 0, + "Snatched": 37 + }, + "171245": { + "ID": "171245", + "GroupID": "41613", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Sally.Face.Episode.4.RIP.MUSIC.ADDON-SiMPLEX", + "Miscellaneous": "GameDOX", + "GameDOXType": "Audio", + "GameDOXVers": "", + "FileCount": "29", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "268920504", + "Time": "2018-12-02 16:38:22", + "UserID": "58206", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 3, + "Leechers": 0, + "Snatched": 19 + }, + "232828": { + "ID": "232828", + "GroupID": "41613", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "English", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "Sally Face", + "Miscellaneous": "GameDOX", + "GameDOXType": "GOG-Goodies", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "112094887", + "Time": "2019-12-14 05:06:51", + "UserID": "48186", + "Link": "", + "TorrentType": "IntLink", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 31 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/9017r4.jpg", + "Year": "2016", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Sally Face", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 1, + "seeders": 28, + "size": 1145392, + "snatched": 171, + "time": 1658659732, + "totalcount": 7, + "userrating": 3, + "weight": "1500", + "year": 2016 + }, + "72989": { + "Artists": [ + { + "id": 38, + "name": "Windows" + } + ], + "CategoryID": "1", + "FullTagList": "adventure action role_playing_game | controller controller_support dangen_entertainment gamepad gamepad_support macro_environment native_controller_support native_gamepad_support steam_deck_verified turn_based_combat unity", + "ID": "72989", + "Name": "Bug Fables: The Everlasting Sapling", + "Rating": "13", + "TagList": "adventure action role_playing_game", + "Torrents": { + "236540": { + "ID": "236540", + "GroupID": "72989", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Bug.Fables.The.Everlasting.Sapling.v1.0.5-SiMPLEX", + "Miscellaneous": "Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "18", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "157412789", + "Time": "2020-01-22 19:53:03", + "UserID": "54928", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 11, + "Leechers": 0, + "Snatched": 53 + }, + "229395": { + "ID": "229395", + "GroupID": "72989", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "1", + "ReleaseTitle": "Bug.Fables.The.Everlasting.Sapling-DARKZER0", + "Miscellaneous": "Rip", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "22", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "189485908", + "Time": "2019-11-21 22:30:17", + "UserID": "55139", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 66 + }, + "479823": { + "ID": "479823", + "GroupID": "72989", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Bug Fables: The Everlasting Sapling v1.1.2 (64bit) (57433)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "212408016", + "Time": "2022-07-24 10:42:06", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 8, + "Leechers": 0, + "Snatched": 9 + }, + "381427": { + "ID": "381427", + "GroupID": "72989", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Bug Fables: The Everlasting Sapling v1.1b (32bit) (43028)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "204823464", + "Time": "2021-06-24 06:24:44", + "UserID": "48186", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 7, + "Leechers": 0, + "Snatched": 18 + }, + "381426": { + "ID": "381426", + "GroupID": "72989", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Bug Fables: The Everlasting Sapling v1.1 (32bit) (42484)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "205120880", + "Time": "2021-06-24 06:24:15", + "UserID": "48186", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 11 + }, + "378305": { + "ID": "378305", + "GroupID": "72989", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Bug Fables: The Everlasting Sapling v1.1.1 (64bit) (47378)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "209982208", + "Time": "2021-06-13 09:40:54", + "UserID": "48186", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 19, + "Leechers": 0, + "Snatched": 41 + }, + "322212": { + "ID": "322212", + "GroupID": "72989", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Bug Fables: The Everlasting Sapling v1.1 (64bit) (42484)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "208916112", + "Time": "2020-11-06 07:17:11", + "UserID": "8362", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 3, + "Leechers": 0, + "Snatched": 26 + }, + "281445": { + "ID": "281445", + "GroupID": "72989", + "CategoryID": "1", + "Format": "", + "Encoding": "", + "Region": "", + "Language": "Multi-Language", + "Remastered": "1", + "RemasterYear": "2020", + "RemasterTitle": "GOG Edition", + "Scene": "0", + "ReleaseTitle": "Bug Fables: The Everlasting Sapling v1.0.5 (64bit) (36098)", + "Miscellaneous": "DRM Free", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "1", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "207061000", + "Time": "2020-05-03 10:59:59", + "UserID": "-1", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 20, + "Leechers": 0, + "Snatched": 84 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/qw635y.jpg", + "Year": "2019", + "categoryid": 1, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "Bug Fables: The Everlasting Sapling", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 1, + "seeders": 80, + "size": 207430, + "snatched": 308, + "time": 1658659326, + "totalcount": 8, + "userrating": 6, + "weight": "1500", + "year": 2019 + }, + "125051": { + "Artists": [], + "CategoryID": "4", + "FullTagList": "electronic | ", + "ID": "125051", + "Name": "REI-JIN-G-LU-P ORIGINAL SOUNDTRACK by", + "Rating": "0", + "TagList": "electronic", + "Torrents": { + "479822": { + "ID": "479822", + "GroupID": "125051", + "CategoryID": "4", + "Format": "MP3", + "Encoding": "320", + "Region": "", + "Language": "", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "REI-JIN-G-LU-P ORIGINAL SOUNDTRACK by", + "Miscellaneous": "", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "31", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "183413867", + "Time": "2022-07-24 10:31:42", + "UserID": "67854", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 3, + "Leechers": 0, + "Snatched": 3 + }, + "479821": { + "ID": "479821", + "GroupID": "125051", + "CategoryID": "4", + "Format": "MP3", + "Encoding": "V0 (VBR)", + "Region": "", + "Language": "", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "REI-JIN-G-LU-P ORIGINAL SOUNDTRACK by", + "Miscellaneous": "", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "31", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "152547690", + "Time": "2022-07-24 10:30:56", + "UserID": "67854", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 4, + "Leechers": 0, + "Snatched": 4 + }, + "479820": { + "ID": "479820", + "GroupID": "125051", + "CategoryID": "4", + "Format": "FLAC", + "Encoding": "Lossless", + "Region": "", + "Language": "", + "Remastered": "0", + "RemasterYear": "0", + "RemasterTitle": "", + "Scene": "0", + "ReleaseTitle": "REI-JIN-G-LU-P ORIGINAL SOUNDTRACK by", + "Miscellaneous": "", + "GameDOXType": "", + "GameDOXVers": "", + "FileCount": "31", + "FreeTorrent": "0", + "Dupable": "0", + "DupeType": "0", + "dupereason": "", + "Size": "491817809", + "Time": "2022-07-24 10:30:14", + "UserID": "67854", + "Link": "", + "TorrentType": "Torrent", + "DupeTime": "0", + "PersonalFL": false, + "LowSeedFL": false, + "IsSnatched": false, + "Seeders": 5, + "Leechers": 0, + "Snatched": 5 + } + }, + "WikiImage": "https:\/\/ptpimg.me\/m9a280.jpg", + "Year": "2018", + "categoryid": 4, + "checked": 0, + "dupable": 0, + "freetorrent": 0, + "groupname": "REI-JIN-G-LU-P ORIGINAL SOUNDTRACK by", + "gsrating": 0, + "ignrating": 0, + "leechers": 0, + "metarating": 0, + "scene": 0, + "seeders": 14, + "size": 480291, + "snatched": 12, + "time": 1658658702, + "totalcount": 3, + "userrating": 0, + "weight": "1489", + "year": 2018 + } + } +} \ No newline at end of file diff --git a/src/NzbDrone.Core.Test/IndexerTests/GazelleGamesTests/GazelleGamesFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/GazelleGamesTests/GazelleGamesFixture.cs new file mode 100644 index 000000000..dd3d7f7ae --- /dev/null +++ b/src/NzbDrone.Core.Test/IndexerTests/GazelleGamesTests/GazelleGamesFixture.cs @@ -0,0 +1,68 @@ +using System; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Common.Http; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Indexers.Definitions; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.IndexerTests.GazelleGamesTests +{ + [TestFixture] + public class GazelleGamesFixture : CoreTest<GazelleGames> + { + [SetUp] + public void Setup() + { + Subject.Definition = new IndexerDefinition() + { + Name = "GazelleGames", + Settings = new GazelleGamesSettings() { Apikey = "somekey" } + }; + } + + [Test] + public async Task should_parse_recent_feed_from_GazelleGames() + { + var recentFeed = ReadAllText(@"Files/Indexers/GazelleGames/recentfeed.json"); + + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader { { "Content-Type", "application/json" } }, new CookieCollection(), recentFeed))); + + var releases = (await Subject.Fetch(new BasicSearchCriteria { Categories = new int[] { 2000 } })).Releases; + + releases.Should().HaveCount(1464); + releases.First().Should().BeOfType<TorrentInfo>(); + + var torrentInfo = releases.First() as TorrentInfo; + + torrentInfo.Title.Should().Be("Microsoft_Flight_Simulator-HOODLUM"); + torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent); + torrentInfo.DownloadUrl.Should().Be("https://gazellegames.net/torrents.php?action=download&id=303216&authkey=prowlarr&torrent_pass="); + torrentInfo.InfoUrl.Should().Be("https://gazellegames.net/torrents.php?id=84781&torrentid=303216"); + torrentInfo.CommentUrl.Should().BeNullOrEmpty(); + torrentInfo.Indexer.Should().Be(Subject.Definition.Name); + torrentInfo.PublishDate.Should().Be(DateTime.Parse("2022-07-25 6:39:11").ToUniversalTime()); + torrentInfo.Size.Should().Be(80077617780); + torrentInfo.InfoHash.Should().Be(null); + torrentInfo.MagnetUrl.Should().Be(null); + torrentInfo.Peers.Should().Be(383); + torrentInfo.Seeders.Should().Be(383); + torrentInfo.ImdbId.Should().Be(0); + torrentInfo.TmdbId.Should().Be(0); + torrentInfo.TvdbId.Should().Be(0); + torrentInfo.Languages.Should().HaveCount(0); + torrentInfo.Subs.Should().HaveCount(0); + torrentInfo.DownloadVolumeFactor.Should().Be(1); + torrentInfo.UploadVolumeFactor.Should().Be(1); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs b/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs index 13ec8dd5c..d94a4addd 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs @@ -1,21 +1,22 @@ using System; using System.Collections.Generic; -using System.Collections.Specialized; -using System.Globalization; using System.Linq; +using System.Net; using System.Text; -using AngleSharp.Html.Parser; +using System.Threading.Tasks; using FluentValidation; +using FluentValidation.Results; +using Newtonsoft.Json.Linq; using NLog; using NzbDrone.Common.Http; +using NzbDrone.Common.Serializer; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions @@ -38,7 +39,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IIndexerRequestGenerator GetRequestGenerator() { - return new GazelleGamesRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; + return new GazelleGamesRequestGenerator() { Settings = Settings, Capabilities = Capabilities, HttpClient = _httpClient }; } public override IParseIndexerResponse GetParser() @@ -46,38 +47,27 @@ namespace NzbDrone.Core.Indexers.Definitions return new GazelleGamesParser(Settings, Capabilities.Categories); } - protected override IDictionary<string, string> GetCookies() - { - return CookieUtil.CookieHeaderToDictionary(Settings.Cookie); - } - - protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) - { - if (httpResponse.HasHttpRedirect && httpResponse.RedirectUrl.EndsWith("login.php")) - { - return true; - } - - return false; - } - private IndexerCapabilities SetCapabilities() { var caps = new IndexerCapabilities { }; + // Apple caps.Categories.AddCategoryMapping("Mac", NewznabStandardCategory.ConsoleOther, "Mac"); caps.Categories.AddCategoryMapping("iOS", NewznabStandardCategory.PCMobileiOS, "iOS"); caps.Categories.AddCategoryMapping("Apple Bandai Pippin", NewznabStandardCategory.ConsoleOther, "Apple Bandai Pippin"); + // Google caps.Categories.AddCategoryMapping("Android", NewznabStandardCategory.PCMobileAndroid, "Android"); + // Microsoft caps.Categories.AddCategoryMapping("DOS", NewznabStandardCategory.PCGames, "DOS"); caps.Categories.AddCategoryMapping("Windows", NewznabStandardCategory.PCGames, "Windows"); caps.Categories.AddCategoryMapping("Xbox", NewznabStandardCategory.ConsoleXBox, "Xbox"); caps.Categories.AddCategoryMapping("Xbox 360", NewznabStandardCategory.ConsoleXBox360, "Xbox 360"); + // Nintendo caps.Categories.AddCategoryMapping("Game Boy", NewznabStandardCategory.ConsoleOther, "Game Boy"); caps.Categories.AddCategoryMapping("Game Boy Advance", NewznabStandardCategory.ConsoleOther, "Game Boy Advance"); caps.Categories.AddCategoryMapping("Game Boy Color", NewznabStandardCategory.ConsoleOther, "Game Boy Color"); @@ -93,6 +83,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping("Wii", NewznabStandardCategory.ConsoleWii, "Wii"); caps.Categories.AddCategoryMapping("Wii U", NewznabStandardCategory.ConsoleWiiU, "Wii U"); + // Sony caps.Categories.AddCategoryMapping("PlayStation 1", NewznabStandardCategory.ConsoleOther, "PlayStation 1"); caps.Categories.AddCategoryMapping("PlayStation 2", NewznabStandardCategory.ConsoleOther, "PlayStation 2"); caps.Categories.AddCategoryMapping("PlayStation 3", NewznabStandardCategory.ConsolePS3, "PlayStation 3"); @@ -100,6 +91,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping("PlayStation Portable", NewznabStandardCategory.ConsolePSP, "PlayStation Portable"); caps.Categories.AddCategoryMapping("PlayStation Vita", NewznabStandardCategory.ConsolePSVita, "PlayStation Vita"); + // Sega caps.Categories.AddCategoryMapping("Dreamcast", NewznabStandardCategory.ConsoleOther, "Dreamcast"); caps.Categories.AddCategoryMapping("Game Gear", NewznabStandardCategory.ConsoleOther, "Game Gear"); caps.Categories.AddCategoryMapping("Master System", NewznabStandardCategory.ConsoleOther, "Master System"); @@ -108,6 +100,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping("Saturn", NewznabStandardCategory.ConsoleOther, "Saturn"); caps.Categories.AddCategoryMapping("SG-1000", NewznabStandardCategory.ConsoleOther, "SG-1000"); + // Atari caps.Categories.AddCategoryMapping("Atari 2600", NewznabStandardCategory.ConsoleOther, "Atari 2600"); caps.Categories.AddCategoryMapping("Atari 5200", NewznabStandardCategory.ConsoleOther, "Atari 5200"); caps.Categories.AddCategoryMapping("Atari 7800", NewznabStandardCategory.ConsoleOther, "Atari 7800"); @@ -115,24 +108,31 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping("Atari Lynx", NewznabStandardCategory.ConsoleOther, "Atari Lynx"); caps.Categories.AddCategoryMapping("Atari ST", NewznabStandardCategory.ConsoleOther, "Atari ST"); + // Amstrad caps.Categories.AddCategoryMapping("Amstrad CPC", NewznabStandardCategory.ConsoleOther, "Amstrad CPC"); + // Sinclair caps.Categories.AddCategoryMapping("ZX Spectrum", NewznabStandardCategory.ConsoleOther, "ZX Spectrum"); + // Spectravideo caps.Categories.AddCategoryMapping("MSX", NewznabStandardCategory.ConsoleOther, "MSX"); caps.Categories.AddCategoryMapping("MSX 2", NewznabStandardCategory.ConsoleOther, "MSX 2"); + // Tiger caps.Categories.AddCategoryMapping("Game.com", NewznabStandardCategory.ConsoleOther, "Game.com"); caps.Categories.AddCategoryMapping("Gizmondo", NewznabStandardCategory.ConsoleOther, "Gizmondo"); + // VTech caps.Categories.AddCategoryMapping("V.Smile", NewznabStandardCategory.ConsoleOther, "V.Smile"); caps.Categories.AddCategoryMapping("CreatiVision", NewznabStandardCategory.ConsoleOther, "CreatiVision"); + // Tabletop Games caps.Categories.AddCategoryMapping("Board Game", NewznabStandardCategory.ConsoleOther, "Board Game"); caps.Categories.AddCategoryMapping("Card Game", NewznabStandardCategory.ConsoleOther, "Card Game"); caps.Categories.AddCategoryMapping("Miniature Wargames", NewznabStandardCategory.ConsoleOther, "Miniature Wargames"); caps.Categories.AddCategoryMapping("Pen and Paper RPG", NewznabStandardCategory.ConsoleOther, "Pen and Paper RPG"); + // Other caps.Categories.AddCategoryMapping("3DO", NewznabStandardCategory.ConsoleOther, "3DO"); caps.Categories.AddCategoryMapping("Bandai WonderSwan", NewznabStandardCategory.ConsoleOther, "Bandai WonderSwan"); caps.Categories.AddCategoryMapping("Bandai WonderSwan Color", NewznabStandardCategory.ConsoleOther, "Bandai WonderSwan Color"); @@ -178,59 +178,36 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping("Watara Supervision", NewznabStandardCategory.ConsoleOther, "Watara Supervision"); caps.Categories.AddCategoryMapping("Retro - Other", NewznabStandardCategory.ConsoleOther, "Retro - Other"); + // special categories (real categories/not platforms) caps.Categories.AddCategoryMapping("OST", NewznabStandardCategory.AudioOther, "OST"); caps.Categories.AddCategoryMapping("Applications", NewznabStandardCategory.PC0day, "Applications"); caps.Categories.AddCategoryMapping("E-Books", NewznabStandardCategory.BooksEBook, "E-Books"); return caps; } + + protected override async Task Test(List<ValidationFailure> failures) + { + ((GazelleGamesRequestGenerator)GetRequestGenerator()).FetchPasskey(); + await base.Test(failures); + } } public class GazelleGamesRequestGenerator : IIndexerRequestGenerator { public GazelleGamesSettings Settings { get; set; } public IndexerCapabilities Capabilities { get; set; } + public IIndexerHttpClient HttpClient { get; set; } public GazelleGamesRequestGenerator() { } - private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories) - { - var searchUrl = string.Format("{0}/torrents.php", Settings.BaseUrl.TrimEnd('/')); - - var searchString = term; - - var searchType = Settings.SearchGroupNames ? "groupname" : "searchstr"; - - var queryCollection = new NameValueCollection - { - { searchType, searchString }, - { "order_by", "time" }, - { "order_way", "desc" }, - { "action", "basic" }, - { "searchsubmit", "1" } - }; - - var i = 0; - - foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories)) - { - queryCollection.Add($"artistcheck[{i++}]", cat); - } - - searchUrl += "?" + queryCollection.GetQueryString(); - - var request = new IndexerRequest(searchUrl, HttpAccept.Html); - - yield return request; - } - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + pageableRequests.Add(GetRequest(GetBasicSearchParameters(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories))); return pageableRequests; } @@ -239,7 +216,7 @@ namespace NzbDrone.Core.Indexers.Definitions { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + pageableRequests.Add(GetRequest(GetBasicSearchParameters(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories))); return pageableRequests; } @@ -248,7 +225,7 @@ namespace NzbDrone.Core.Indexers.Definitions { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories)); + pageableRequests.Add(GetRequest(GetBasicSearchParameters(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories))); return pageableRequests; } @@ -257,7 +234,7 @@ namespace NzbDrone.Core.Indexers.Definitions { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + pageableRequests.Add(GetRequest(GetBasicSearchParameters(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories))); return pageableRequests; } @@ -266,11 +243,67 @@ namespace NzbDrone.Core.Indexers.Definitions { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + pageableRequests.Add(GetRequest(GetBasicSearchParameters(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories))); return pageableRequests; } + public void FetchPasskey() + { + // GET on index for the passkey + var request = RequestBuilder().Resource("api.php?request=quick_user").Build(); + var indexResponse = HttpClient.Execute(request); + var index = Json.Deserialize<GazelleGamesUserResponse>(indexResponse.Content); + if (index == null || + string.IsNullOrWhiteSpace(index.Status) || + index.Status != "success" || + string.IsNullOrWhiteSpace(index.Response.PassKey)) + { + throw new Exception("Failed to authenticate with GazelleGames."); + } + + // Set passkey on settings so it can be used to generate the download URL + Settings.Passkey = index.Response.PassKey; + } + + private IEnumerable<IndexerRequest> GetRequest(string parameters) + { + var req = RequestBuilder() + .Resource($"api.php?{parameters}") + .Build(); + + yield return new IndexerRequest(req); + } + + private HttpRequestBuilder RequestBuilder() + { + return new HttpRequestBuilder($"{Settings.BaseUrl.Trim().TrimEnd('/')}") + .Accept(HttpAccept.Json) + .SetHeader("X-API-Key", Settings.Apikey); + } + + private string GetBasicSearchParameters(string searchTerm, int[] categories) + { + var parameters = "request=search&search_type=torrents&empty_groups=filled&order_by=time&order_way=desc"; + + if (!string.IsNullOrWhiteSpace(searchTerm)) + { + var searchType = Settings.SearchGroupNames ? "groupname" : "searchstr"; + + parameters += string.Format("&{1}={0}", searchTerm.Replace(".", " "), searchType); + } + + if (categories != null) + { + foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories)) + { + parameters += string.Format("&artistcheck[]={0}", cat); + } + } + + return parameters; + } + public Func<IDictionary<string, string>> GetCookies { get; set; } public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } @@ -290,117 +323,183 @@ namespace NzbDrone.Core.Indexers.Definitions { var torrentInfos = new List<ReleaseInfo>(); - var rowsSelector = ".torrent_table > tbody > tr"; - - var searchResultParser = new HtmlParser(); - var searchResultDocument = searchResultParser.ParseDocument(indexerResponse.Content); - var rows = searchResultDocument.QuerySelectorAll(rowsSelector); - - var stickyGroup = false; - string categoryStr; - ICollection<IndexerCategory> groupCategory = null; - string groupTitle = null; - - foreach (var row in rows) + if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) { - if (row.ClassList.Contains("torrent")) + throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request"); + } + + if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value)) + { + throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}"); + } + + var jsonResponse = new HttpResponse<GazelleGamesResponse>(indexerResponse.HttpResponse); + if (jsonResponse.Resource.Status != "success" || + string.IsNullOrWhiteSpace(jsonResponse.Resource.Status) || + jsonResponse.Resource.Response == null) + { + return torrentInfos; + } + + foreach (var result in jsonResponse.Resource.Response) + { + Dictionary<string, GazelleGamesTorrent> torrents; + + try + { + torrents = ((JObject)result.Value.Torrents).ToObject<Dictionary<string, GazelleGamesTorrent>>(); + } + catch { - // garbage rows continue; } - else if (row.ClassList.Contains("group")) + + if (result.Value.Torrents != null) { - stickyGroup = row.ClassList.Contains("sticky"); - var dispalyname = row.QuerySelector("#displayname"); - var qCat = row.QuerySelector("td.cats_col > div"); - categoryStr = qCat.GetAttribute("title"); - var qArtistLink = dispalyname.QuerySelector("#groupplatform > a"); - if (qArtistLink != null) + var categories = result.Value.Artists.Select(a => a.Name); + + foreach (var torrent in torrents) { - categoryStr = ParseUtil.GetArgumentFromQueryString(qArtistLink.GetAttribute("href"), "artistname"); + var id = int.Parse(torrent.Key); + + var infoUrl = GetInfoUrl(result.Key, id); + + var release = new TorrentInfo() + { + Guid = infoUrl, + Title = torrent.Value.ReleaseTitle, + Files = torrent.Value.FileCount, + Grabs = torrent.Value.Snatched, + Size = long.Parse(torrent.Value.Size), + DownloadUrl = GetDownloadUrl(id), + InfoUrl = infoUrl, + Seeders = torrent.Value.Seeders, + Categories = _categories.MapTrackerCatDescToNewznab(categories.FirstOrDefault()), + Peers = torrent.Value.Leechers + torrent.Value.Seeders, + PublishDate = torrent.Value.Time.ToUniversalTime(), + DownloadVolumeFactor = torrent.Value.FreeTorrent == GazelleGamesFreeTorrent.FreeLeech || torrent.Value.FreeTorrent == GazelleGamesFreeTorrent.Neutral || torrent.Value.LowSeedFL ? 0 : 1, + UploadVolumeFactor = torrent.Value.FreeTorrent == GazelleGamesFreeTorrent.Neutral ? 0 : 1 + }; + + torrentInfos.Add(release); } - - groupCategory = _categories.MapTrackerCatToNewznab(categoryStr); - - var qDetailsLink = dispalyname.QuerySelector("#groupname > a"); - groupTitle = qDetailsLink.TextContent; - } - else if (row.ClassList.Contains("group_torrent")) - { - if (row.QuerySelector("td.edition_info") != null) - { - continue; - } - - var sizeString = row.QuerySelector("td:nth-child(4)").TextContent; - if (string.IsNullOrEmpty(sizeString)) - { - continue; - } - - var qDetailsLink = row.QuerySelector("a[href^=\"torrents.php?id=\"]"); - var title = qDetailsLink.TextContent.Replace(", Freeleech!", "").Replace(", Neutral Leech!", ""); - - //if (stickyGroup && (query.ImdbID == null || !NewznabStandardCategory.MovieSearchImdbAvailable) && !query.MatchQueryStringAND(title)) // AND match for sticky releases - //{ - // continue; - //} - var qDescription = qDetailsLink.QuerySelector("span.torrent_info_tags"); - var qDLLink = row.QuerySelector("a[href^=\"torrents.php?action=download\"]"); - var qTime = row.QuerySelector("span.time"); - var qGrabs = row.QuerySelector("td:nth-child(5)"); - var qSeeders = row.QuerySelector("td:nth-child(6)"); - var qLeechers = row.QuerySelector("td:nth-child(7)"); - var qFreeLeech = row.QuerySelector("strong.freeleech_label"); - var qNeutralLeech = row.QuerySelector("strong.neutralleech_label"); - var time = qTime.GetAttribute("title"); - var link = _settings.BaseUrl + qDLLink.GetAttribute("href"); - var seeders = ParseUtil.CoerceInt(qSeeders.TextContent); - var publishDate = DateTime.SpecifyKind( - DateTime.ParseExact(time, "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture), - DateTimeKind.Unspecified).ToLocalTime(); - var details = _settings.BaseUrl + qDetailsLink.GetAttribute("href"); - var grabs = ParseUtil.CoerceInt(qGrabs.TextContent); - var leechers = ParseUtil.CoerceInt(qLeechers.TextContent); - var size = ParseUtil.GetBytes(sizeString); - - var release = new TorrentInfo - { - MinimumRatio = 1, - MinimumSeedTime = 288000, //80 hours - Categories = groupCategory, - PublishDate = publishDate, - Size = size, - InfoUrl = details, - DownloadUrl = link, - Guid = link, - Grabs = grabs, - Seeders = seeders, - Peers = leechers + seeders, - Title = title, - Description = qDescription?.TextContent, - UploadVolumeFactor = qNeutralLeech is null ? 1 : 0, - DownloadVolumeFactor = qFreeLeech != null || qNeutralLeech != null ? 0 : 1 - }; - - torrentInfos.Add(release); } } - return torrentInfos.ToArray(); + // order by date + return + torrentInfos + .OrderByDescending(o => o.PublishDate) + .ToArray(); + } + + private string GetDownloadUrl(int torrentId) + { + // AuthKey is required but not checked, just pass in a dummy variable + // to avoid having to track authkey, which is randomly cycled + var url = new HttpUri(_settings.BaseUrl) + .CombinePath("/torrents.php") + .AddQueryParam("action", "download") + .AddQueryParam("id", torrentId) + .AddQueryParam("authkey", "prowlarr") + .AddQueryParam("torrent_pass", _settings.Passkey); + + return url.FullUri; + } + + private string GetInfoUrl(string groupId, int torrentId) + { + var url = new HttpUri(_settings.BaseUrl) + .CombinePath("/torrents.php") + .AddQueryParam("id", groupId) + .AddQueryParam("torrentid", torrentId); + + return url.FullUri; } public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - public class GazelleGamesSettings : CookieTorrentBaseSettings + public class GazelleGamesSettingsValidator : AbstractValidator<GazelleGamesSettings> { + public GazelleGamesSettingsValidator() + { + RuleFor(c => c.Apikey).NotEmpty(); + } + } + + public class GazelleGamesSettings : NoAuthTorrentBaseSettings + { + private static readonly GazelleGamesSettingsValidator Validator = new GazelleGamesSettingsValidator(); + public GazelleGamesSettings() { - SearchGroupNames = false; + Apikey = ""; + Passkey = ""; } + [FieldDefinition(2, Label = "API Key", HelpText = "API Key from the Site (Found in Settings => Access Settings), Must have User Permissions", Privacy = PrivacyLevel.ApiKey)] + public string Apikey { get; set; } + [FieldDefinition(3, Label = "Search Group Names", Type = FieldType.Checkbox, HelpText = "Search Group Names Only")] public bool SearchGroupNames { get; set; } + + public string Passkey { get; set; } + + public override NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } + + public class GazelleGamesResponse + { + public string Status { get; set; } + public Dictionary<string, GazelleGamesGroup> Response { get; set; } + } + + public class GazelleGamesGroup + { + public List<GazelleGamesArtist> Artists { get; set; } + public object Torrents { get; set; } + } + + public class GazelleGamesArtist + { + public string Id { get; set; } + public string Name { get; set; } + } + + public class GazelleGamesTorrent + { + public string Size { get; set; } + public int? Snatched { get; set; } + public int Seeders { get; set; } + public int Leechers { get; set; } + public string ReleaseTitle { get; set; } + public DateTime Time { get; set; } + public int FileCount { get; set; } + public GazelleGamesFreeTorrent FreeTorrent { get; set; } + public bool PersonalFL { get; set; } + public bool LowSeedFL { get; set; } + } + + public class GazelleGamesUserResponse + { + public string Status { get; set; } + public GazelleGamesUser Response { get; set; } + } + + public class GazelleGamesUser + { + public string PassKey { get; set; } + } + + public enum GazelleGamesFreeTorrent + { + Normal, + FreeLeech, + Neutral, + Either } } From 6412048eb92b7bb001f133778b36ec375feb839a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 29 Jul 2022 12:19:39 -0500 Subject: [PATCH 0553/2320] Bump version to 0.4.4 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8fed1455f..4035c39bc 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: testsFolder: './_tests' yarnCacheFolder: $(Pipeline.Workspace)/.yarn nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages - majorVersion: '0.4.3' + majorVersion: '0.4.4' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From ee6467073f64cfaa5ef0de2225f39f0fd0eb5c05 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 29 Jul 2022 22:22:29 -0500 Subject: [PATCH 0554/2320] New: (Cardigann) Additional query support v7 --- .../Definitions/BookSearchCriteria.cs | 3 ++ .../Definitions/TvSearchCriteria.cs | 2 + .../IndexerSearch/NewznabRequest.cs | 8 +++- .../IndexerSearch/ReleaseSearchService.cs | 5 ++ .../IndexerDefinitionUpdateService.cs | 2 +- .../Definitions/Cardigann/CardigannBase.cs | 2 +- .../Definitions/Cardigann/CardigannParser.cs | 9 ++++ .../Cardigann/CardigannRequestGenerator.cs | 12 ++++- .../Indexers/IndexerCapabilities.cs | 48 +++++++++++++++++-- src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs | 1 + 10 files changed, 85 insertions(+), 7 deletions(-) diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/BookSearchCriteria.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/BookSearchCriteria.cs index 9ae52049e..f45cb03ec 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/BookSearchCriteria.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/BookSearchCriteria.cs @@ -6,6 +6,9 @@ namespace NzbDrone.Core.IndexerSearch.Definitions { public string Author { get; set; } public string Title { get; set; } + public string Publisher { get; set; } + public int? Year { get; set; } + public string Genre { get; set; } public override bool RssSearch { diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/TvSearchCriteria.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/TvSearchCriteria.cs index 35ba12dd2..f04761c3d 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/TvSearchCriteria.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/TvSearchCriteria.cs @@ -18,6 +18,8 @@ namespace NzbDrone.Core.IndexerSearch.Definitions public int? TraktId { get; set; } public int? TmdbId { get; set; } public int? DoubanId { get; set; } + public int? Year { get; set; } + public string Genre { get; set; } public string SanitizedTvSearchString => (SanitizedSearchTerm + " " + EpisodeSearchString).Trim(); public string EpisodeSearchString => GetEpisodeSearchString(); diff --git a/src/NzbDrone.Core/IndexerSearch/NewznabRequest.cs b/src/NzbDrone.Core/IndexerSearch/NewznabRequest.cs index 56dac00de..b8ba22e76 100644 --- a/src/NzbDrone.Core/IndexerSearch/NewznabRequest.cs +++ b/src/NzbDrone.Core/IndexerSearch/NewznabRequest.cs @@ -7,7 +7,7 @@ namespace NzbDrone.Core.IndexerSearch private static readonly Regex TvRegex = new Regex(@"\{((?:imdbid\:)(?<imdbid>[^{]+)|(?:tvdbid\:)(?<tvdbid>[^{]+)|(?:tmdbid\:)(?<tmdbid>[^{]+)|(?:doubanid\:)(?<doubanid>[^{]+)|(?:season\:)(?<season>[^{]+)|(?:episode\:)(?<episode>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex MovieRegex = new Regex(@"\{((?:imdbid\:)(?<imdbid>[^{]+)|(?:doubanid\:)(?<doubanid>[^{]+)|(?:tmdbid\:)(?<tmdbid>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex MusicRegex = new Regex(@"\{((?:artist\:)(?<artist>[^{]+)|(?:album\:)(?<album>[^{]+)|(?:track\:)(?<track>[^{]+)|(?:label\:)(?<label>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); - private static readonly Regex BookRegex = new Regex(@"\{((?:author\:)(?<author>[^{]+)|(?:title\:)(?<title>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex BookRegex = new Regex(@"\{((?:author\:)(?<author>[^{]+)|(?:publisher\:)(?<publisher>[^{]+)|(?:title\:)(?<title>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); public string t { get; set; } public string q { get; set; } @@ -32,6 +32,7 @@ namespace NzbDrone.Core.IndexerSearch public string genre { get; set; } public string author { get; set; } public string title { get; set; } + public string publisher { get; set; } public string configured { get; set; } public string source { get; set; } public string host { get; set; } @@ -150,6 +151,11 @@ namespace NzbDrone.Core.IndexerSearch title = match.Groups["title"].Value; } + if (match.Groups["publisher"].Success) + { + publisher = match.Groups["publisher"].Value; + } + q = q.Replace(match.Value, "").Trim(); } } diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs index c4e40bd4e..20b0bf1e5 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs @@ -93,6 +93,8 @@ namespace NzbDrone.Core.IndexerSearch searchSpec.DoubanId = request.doubanid; searchSpec.RId = request.rid; searchSpec.TvMazeId = request.tvmazeid; + searchSpec.Year = request.year; + searchSpec.Genre = request.genre; return new NewznabResults { Releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) }; } @@ -103,6 +105,9 @@ namespace NzbDrone.Core.IndexerSearch searchSpec.Author = request.author; searchSpec.Title = request.title; + searchSpec.Publisher = request.publisher; + searchSpec.Year = request.year; + searchSpec.Genre = request.genre; return new NewznabResults { Releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) }; } diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index b48b790b2..408959075 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.IndexerVersions /* Update Service will fall back if version # does not exist for an indexer per Ta */ private const string DEFINITION_BRANCH = "master"; - private const int DEFINITION_VERSION = 6; + private const int DEFINITION_VERSION = 7; //Used when moving yml to C# private readonly List<string> _defintionBlocklist = new List<string>() diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index 3c725792f..a50858cff 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.Indexers.Cardigann protected readonly IndexerCapabilitiesCategories _categories = new IndexerCapabilitiesCategories(); protected readonly List<string> _defaultCategories = new List<string>(); - protected readonly string[] OptionalFields = new string[] { "imdb", "imdbid", "rageid", "tmdbid", "tvdbid", "poster", "banner", "description", "doubanid" }; + protected readonly string[] OptionalFields = new string[] { "imdb", "imdbid", "tmdbid", "rageid", "tvdbid", "tvmazeid", "traktid", "doubanid", "poster", "banner", "description" }; protected static readonly string[] _SupportedLogicFunctions = { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index 414ca8e53..0585af217 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -607,12 +607,21 @@ namespace NzbDrone.Core.Indexers.Cardigann case "booktitle": release.BookTitle = value; break; + case "publisher": + release.Publisher = value; + break; case "artist": release.Artist = value; break; case "album": release.Album = value; break; + case "label": + release.Label = value; + break; + case "track": + release.Track = value; + break; default: break; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 73d619f95..910a8dbb5 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -49,10 +49,12 @@ namespace NzbDrone.Core.Indexers.Cardigann variables[".Query.Movie"] = null; variables[".Query.Year"] = searchCriteria.Year?.ToString() ?? null; + variables[".Query.Genre"] = searchCriteria.Genre; variables[".Query.IMDBID"] = searchCriteria.FullImdbId; variables[".Query.IMDBIDShort"] = searchCriteria.ImdbId; variables[".Query.TMDBID"] = searchCriteria.TmdbId?.ToString() ?? null; variables[".Query.TraktID"] = searchCriteria.TraktId?.ToString() ?? null; + variables[".Query.DoubanID"] = searchCriteria.DoubanId?.ToString() ?? null; pageableRequests.Add(GetRequest(variables)); @@ -70,7 +72,9 @@ namespace NzbDrone.Core.Indexers.Cardigann variables[".Query.Album"] = searchCriteria.Album; variables[".Query.Artist"] = searchCriteria.Artist; variables[".Query.Label"] = searchCriteria.Label; - variables[".Query.Track"] = null; + variables[".Query.Genre"] = searchCriteria.Genre; + variables[".Query.Year"] = searchCriteria.Year?.ToString() ?? null; + variables[".Query.Track"] = searchCriteria.Track; pageableRequests.Add(GetRequest(variables)); @@ -88,6 +92,8 @@ namespace NzbDrone.Core.Indexers.Cardigann variables[".Query.Series"] = null; variables[".Query.Ep"] = searchCriteria.Episode; variables[".Query.Season"] = searchCriteria.Season?.ToString() ?? null; + variables[".Query.Genre"] = searchCriteria.Genre; + variables[".Query.Year"] = searchCriteria.Year?.ToString() ?? null; variables[".Query.IMDBID"] = searchCriteria.FullImdbId; variables[".Query.IMDBIDShort"] = searchCriteria.ImdbId; variables[".Query.TVDBID"] = searchCriteria.TvdbId?.ToString() ?? null; @@ -95,6 +101,7 @@ namespace NzbDrone.Core.Indexers.Cardigann variables[".Query.TVRageID"] = searchCriteria.RId?.ToString() ?? null; variables[".Query.TVMazeID"] = searchCriteria.TvMazeId?.ToString() ?? null; variables[".Query.TraktID"] = searchCriteria.TraktId?.ToString() ?? null; + variables[".Query.DoubanID"] = searchCriteria.DoubanId?.ToString() ?? null; variables[".Query.Episode"] = searchCriteria.EpisodeSearchString; pageableRequests.Add(GetRequest(variables)); @@ -112,6 +119,9 @@ namespace NzbDrone.Core.Indexers.Cardigann variables[".Query.Author"] = searchCriteria.Author; variables[".Query.Title"] = searchCriteria.Title; + variables[".Query.Genre"] = searchCriteria.Genre; + variables[".Query.Publisher"] = searchCriteria.Publisher; + variables[".Query.Year"] = searchCriteria.Year?.ToString() ?? null; pageableRequests.Add(GetRequest(variables)); diff --git a/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs b/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs index b20c0d17e..cec5f59db 100644 --- a/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs +++ b/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs @@ -16,7 +16,9 @@ namespace NzbDrone.Core.Indexers TvMazeId, TraktId, TmdbId, - DoubanId + DoubanId, + Genre, + Year } public enum MovieSearchParam @@ -28,7 +30,8 @@ namespace NzbDrone.Core.Indexers ImdbYear, TraktId, Genre, - DoubanId + DoubanId, + Year } public enum MusicSearchParam @@ -51,7 +54,10 @@ namespace NzbDrone.Core.Indexers { Q, Title, - Author + Author, + Publisher, + Genre, + Year } public class IndexerCapabilities @@ -75,6 +81,8 @@ namespace NzbDrone.Core.Indexers public bool TvSearchTraktAvailable => TvSearchParams.Contains(TvSearchParam.TraktId); public bool TvSearchTmdbAvailable => TvSearchParams.Contains(TvSearchParam.TmdbId); public bool TvSearchDoubanAvailable => TvSearchParams.Contains(TvSearchParam.DoubanId); + public bool TvSearchGenreAvailable => TvSearchParams.Contains(TvSearchParam.Genre); + public bool TvSearchYearAvailable => TvSearchParams.Contains(TvSearchParam.Year); public List<MovieSearchParam> MovieSearchParams; public bool MovieSearchAvailable => MovieSearchParams.Count > 0; @@ -82,6 +90,7 @@ namespace NzbDrone.Core.Indexers public bool MovieSearchTmdbAvailable => MovieSearchParams.Contains(MovieSearchParam.TmdbId); public bool MovieSearchTraktAvailable => MovieSearchParams.Contains(MovieSearchParam.TraktId); public bool MovieSearchGenreAvailable => MovieSearchParams.Contains(MovieSearchParam.Genre); + public bool MovieSearchYearAvailable => MovieSearchParams.Contains(MovieSearchParam.Year); public bool MovieSearchDoubanAvailable => MovieSearchParams.Contains(MovieSearchParam.DoubanId); public List<MusicSearchParam> MusicSearchParams; @@ -97,6 +106,9 @@ namespace NzbDrone.Core.Indexers public bool BookSearchAvailable => BookSearchParams.Count > 0; public bool BookSearchTitleAvailable => BookSearchParams.Contains(BookSearchParam.Title); public bool BookSearchAuthorAvailable => BookSearchParams.Contains(BookSearchParam.Author); + public bool BookSearchPublisherAvailable => BookSearchParams.Contains(BookSearchParam.Publisher); + public bool BookSearchYearAvailable => BookSearchParams.Contains(BookSearchParam.Year); + public bool BookSearchGenreAvailable => BookSearchParams.Contains(BookSearchParam.Genre); public readonly IndexerCapabilitiesCategories Categories; public List<IndexerFlag> Flags; @@ -313,6 +325,16 @@ namespace NzbDrone.Core.Indexers parameters.Add("doubanid"); } + if (TvSearchGenreAvailable) + { + parameters.Add("genre"); + } + + if (TvSearchYearAvailable) + { + parameters.Add("year"); + } + return string.Join(",", parameters); } @@ -351,6 +373,11 @@ namespace NzbDrone.Core.Indexers parameters.Add("doubanid"); } + if (MovieSearchYearAvailable) + { + parameters.Add("year"); + } + return string.Join(",", parameters); } @@ -403,6 +430,21 @@ namespace NzbDrone.Core.Indexers parameters.Add("author"); } + if (BookSearchPublisherAvailable) + { + parameters.Add("publisher"); + } + + if (BookSearchGenreAvailable) + { + parameters.Add("genre"); + } + + if (BookSearchYearAvailable) + { + parameters.Add("year"); + } + return string.Join(",", parameters); } diff --git a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs index a3bb5169e..f0f66fc1b 100644 --- a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs +++ b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs @@ -38,6 +38,7 @@ namespace NzbDrone.Core.Parser.Model public int Year { get; set; } public string Author { get; set; } public string BookTitle { get; set; } + public string Publisher { get; set; } public string Artist { get; set; } public string Album { get; set; } public string Label { get; set; } From 8c314439cd342933ae3c2d50847c87a696ab2e95 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 29 Jul 2022 22:40:50 -0500 Subject: [PATCH 0555/2320] Fixed: (Cardigann) messy row strdump --- .../Indexers/Definitions/Cardigann/CardigannParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index 0585af217..95aae7c2e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -279,7 +279,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } var filters = search.Rows.Filters; - var skipRelease = ParseRowFilters(filters, release, variables, row); + var skipRelease = ParseRowFilters(filters, release, variables, row.ToHtmlPretty()); if (skipRelease) { From cb35a3948e3fa62684b925e3bb3f6ec6cd611020 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 29 Jul 2022 22:42:46 -0500 Subject: [PATCH 0556/2320] Fixed: (Cardigann) Genre Parsing for Releases --- .../Indexers/Definitions/Cardigann/CardigannParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index 95aae7c2e..1dda23ec6 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -595,7 +595,7 @@ namespace NzbDrone.Core.Indexers.Cardigann break; case "genre": release.Genres = release.Genres.Union(value.Split(',')).ToList(); - value = release.Genres.ToString(); + value = string.Join(",", release.Genres); break; case "year": release.Year = ParseUtil.CoerceInt(value); From 2db24d454ece3bba74f63eb90c10648a1a82fb06 Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Sat, 30 Jul 2022 04:31:22 +0000 Subject: [PATCH 0557/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index 938b8153e..aadfde6f3 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -2833,6 +2833,13 @@ "type": "string" } }, + { + "name": "publisher", + "in": "query", + "schema": { + "type": "string" + } + }, { "name": "configured", "in": "query", @@ -3055,6 +3062,13 @@ "type": "string" } }, + { + "name": "publisher", + "in": "query", + "schema": { + "type": "string" + } + }, { "name": "configured", "in": "query", @@ -4547,7 +4561,10 @@ "enum": [ "q", "title", - "author" + "author", + "publisher", + "genre", + "year" ], "type": "string" }, @@ -5789,7 +5806,8 @@ "imdbYear", "traktId", "genre", - "doubanId" + "doubanId", + "year" ], "type": "string" }, @@ -6250,7 +6268,9 @@ "tvMazeId", "traktId", "tmdbId", - "doubanId" + "doubanId", + "genre", + "year" ], "type": "string" }, From 5c5dfbb66b1d4725f903ae7f727d5016e24cd2b6 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 1 Aug 2022 08:55:46 -0500 Subject: [PATCH 0558/2320] Fixed: (Cardigann) Genre Parsing New: (Cardigann) Add Validate Field Filter v7 --- .../Definitions/Cardigann/CardigannParser.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index 1dda23ec6..6544b624d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -594,8 +594,9 @@ namespace NzbDrone.Core.Indexers.Cardigann value = release.PosterUrl; break; case "genre": - release.Genres = release.Genres.Union(value.Split(',')).ToList(); - value = string.Join(",", release.Genres); + char[] delimiters = { ',', ' ', '/', ')', '(', '.', ';', '[', ']' }; + release.Genres = release.Genres.Union(value.Split(delimiters, System.StringSplitOptions.RemoveEmptyEntries)).ToList(); + value = string.Join(", ", release.Genres); break; case "year": release.Year = ParseUtil.CoerceInt(value); @@ -653,6 +654,14 @@ namespace NzbDrone.Core.Indexers.Cardigann // for debugging _logger.Debug(string.Format("CardigannIndexer ({0}): row strdump: {1}", _definition.Id, row.ToString())); break; + case "validate": + char[] delimiters = { ',', ' ', '/', ')', '(', '.', ';', '[', ']' }; + var args = (string)filter.Args; + var argsList = args.ToLower().Split(delimiters, StringSplitOptions.RemoveEmptyEntries); + var validList = argsList.ToList(); + var validIntersect = validList.Intersect(row.ToString().ToLower().Split(delimiters, StringSplitOptions.RemoveEmptyEntries)).ToList(); + row = string.Join(", ", validIntersect); + break; default: _logger.Error(string.Format("CardigannIndexer ({0}): Unsupported rows filter: {1}", _definition.Id, filter.Name)); break; From f9e2c5b6733784ca82338772547e0da1876bbc1f Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 2 Aug 2022 08:49:11 -0500 Subject: [PATCH 0559/2320] Fixed: (Cardigann) Genre is optional Fixed: (Cardigann) Expand Genre Validate characters --- .../Indexers/Definitions/Cardigann/CardigannBase.cs | 2 +- .../Indexers/Definitions/Cardigann/CardigannParser.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index a50858cff..e24d28aa6 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.Indexers.Cardigann protected readonly IndexerCapabilitiesCategories _categories = new IndexerCapabilitiesCategories(); protected readonly List<string> _defaultCategories = new List<string>(); - protected readonly string[] OptionalFields = new string[] { "imdb", "imdbid", "tmdbid", "rageid", "tvdbid", "tvmazeid", "traktid", "doubanid", "poster", "banner", "description" }; + protected readonly string[] OptionalFields = new string[] { "imdb", "imdbid", "tmdbid", "rageid", "tvdbid", "tvmazeid", "traktid", "doubanid", "poster", "banner", "description", "genre" }; protected static readonly string[] _SupportedLogicFunctions = { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index 6544b624d..2c427c53e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -594,7 +594,7 @@ namespace NzbDrone.Core.Indexers.Cardigann value = release.PosterUrl; break; case "genre": - char[] delimiters = { ',', ' ', '/', ')', '(', '.', ';', '[', ']' }; + char[] delimiters = { ',', ' ', '/', ')', '(', '.', ';', '[', ']', '"', '|', ':' }; release.Genres = release.Genres.Union(value.Split(delimiters, System.StringSplitOptions.RemoveEmptyEntries)).ToList(); value = string.Join(", ", release.Genres); break; @@ -655,7 +655,7 @@ namespace NzbDrone.Core.Indexers.Cardigann _logger.Debug(string.Format("CardigannIndexer ({0}): row strdump: {1}", _definition.Id, row.ToString())); break; case "validate": - char[] delimiters = { ',', ' ', '/', ')', '(', '.', ';', '[', ']' }; + char[] delimiters = { ',', ' ', '/', ')', '(', '.', ';', '[', ']', '"', '|', ':' }; var args = (string)filter.Args; var argsList = args.ToLower().Split(delimiters, StringSplitOptions.RemoveEmptyEntries); var validList = argsList.ToList(); From fbde3fe2cd13dce7e842273aec0fe1e343fe2dd6 Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Thu, 6 Aug 2020 21:17:45 +0100 Subject: [PATCH 0560/2320] Support for digest auth with HttpRequests Changes from de243991dd78c0fa4cfd2b629839874bbd8f2650 missed b7b5a6e7e1150e2a34aac37deff84f02840111cf --- src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenProxy.cs | 2 +- src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetProxy.cs | 2 +- .../Download/Clients/QBittorrent/QBittorrentProxyV1.cs | 2 +- .../Download/Clients/QBittorrent/QBittorrentProxyV2.cs | 2 +- .../Download/Clients/Transmission/TransmissionProxy.cs | 2 +- src/NzbDrone.Core/Download/Clients/uTorrent/UTorrentProxy.cs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenProxy.cs b/src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenProxy.cs index b78a66df5..b695ef1da 100644 --- a/src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenProxy.cs @@ -73,7 +73,7 @@ namespace NzbDrone.Core.Download.Clients.Hadouken baseUrl = HttpUri.CombinePath(baseUrl, "api"); var requestBuilder = new JsonRpcRequestBuilder(baseUrl, method, parameters); requestBuilder.LogResponseContent = true; - requestBuilder.NetworkCredential = new NetworkCredential(settings.Username, settings.Password); + requestBuilder.NetworkCredential = new BasicNetworkCredential(settings.Username, settings.Password); requestBuilder.Headers.Add("Accept-Encoding", "gzip,deflate"); var httpRequest = requestBuilder.Build(); diff --git a/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetProxy.cs b/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetProxy.cs index f63a941b6..76cff3220 100644 --- a/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetProxy.cs @@ -242,7 +242,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget var requestBuilder = new JsonRpcRequestBuilder(baseUrl, method, parameters); requestBuilder.LogResponseContent = true; - requestBuilder.NetworkCredential = new NetworkCredential(settings.Username, settings.Password); + requestBuilder.NetworkCredential = new BasicNetworkCredential(settings.Username, settings.Password); var httpRequest = requestBuilder.Build(); diff --git a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxyV1.cs b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxyV1.cs index f955cb243..e8b1c2e14 100644 --- a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxyV1.cs +++ b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxyV1.cs @@ -276,7 +276,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent var requestBuilder = new HttpRequestBuilder(settings.UseSsl, settings.Host, settings.Port, settings.UrlBase) { LogResponseContent = true, - NetworkCredential = new NetworkCredential(settings.Username, settings.Password) + NetworkCredential = new BasicNetworkCredential(settings.Username, settings.Password) }; return requestBuilder; } diff --git a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxyV2.cs b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxyV2.cs index bb07e86ef..ed5165e67 100644 --- a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxyV2.cs +++ b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxyV2.cs @@ -317,7 +317,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent var requestBuilder = new HttpRequestBuilder(settings.UseSsl, settings.Host, settings.Port, settings.UrlBase) { LogResponseContent = true, - NetworkCredential = new NetworkCredential(settings.Username, settings.Password) + NetworkCredential = new BasicNetworkCredential(settings.Username, settings.Password) }; return requestBuilder; } diff --git a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionProxy.cs b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionProxy.cs index b30d14497..1172b600a 100644 --- a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionProxy.cs @@ -200,7 +200,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission .Accept(HttpAccept.Json); requestBuilder.LogResponseContent = true; - requestBuilder.NetworkCredential = new NetworkCredential(settings.Username, settings.Password); + requestBuilder.NetworkCredential = new BasicNetworkCredential(settings.Username, settings.Password); requestBuilder.AllowAutoRedirect = false; return requestBuilder; diff --git a/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrentProxy.cs b/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrentProxy.cs index 252cca7a1..9ced7181b 100644 --- a/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrentProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrentProxy.cs @@ -196,7 +196,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent .Accept(HttpAccept.Json); requestBuilder.LogResponseContent = true; - requestBuilder.NetworkCredential = new NetworkCredential(settings.Username, settings.Password); + requestBuilder.NetworkCredential = new BasicNetworkCredential(settings.Username, settings.Password); return requestBuilder; } From 69b8be5b67b4358a4c525e0cd991e29d2e68d8aa Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Thu, 11 Aug 2022 10:27:53 -0500 Subject: [PATCH 0561/2320] Fixed: (Cardigann) fix imatch for rows based on jackett 9768fd288ba299f8a2d1aada1a539d156e7e97b9 --- .../Definitions/Cardigann/CardigannParser.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index 2c427c53e..8faa0b113 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -145,14 +145,14 @@ namespace NzbDrone.Core.Indexers.Cardigann throw new CardigannException(string.Format("Error while parsing field={0}, selector={1}, value={2}: {3}", field.Key, field.Value.Selector, value ?? "<null>", ex.Message)); } + } - var filters = search.Rows.Filters; - var skipRelease = ParseRowFilters(filters, release, variables, row); + var filters = search.Rows.Filters; + var skipRelease = ParseRowFilters(filters, release, variables, row); - if (skipRelease) - { - continue; - } + if (skipRelease) + { + continue; } releases.Add(release); From fd88f44865a5160a5c90bd3a526c80009bb1e390 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 13 Aug 2022 16:41:09 -0500 Subject: [PATCH 0562/2320] Remove duplicate package NLog.Extensions in Prowlarr.Common --- src/NzbDrone.Common/Prowlarr.Common.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index 38d0fbc3e..e121d6480 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -6,7 +6,6 @@ <ItemGroup> <PackageReference Include="DryIoc.dll" Version="4.8.8" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" /> - <PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="NLog" Version="5.0.1" /> From 4473551182fa8478e96882e0d33e01909eadaf5f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 13 Aug 2022 17:27:58 -0500 Subject: [PATCH 0563/2320] Fixed: Correctly use FlareSolverr User Agent --- .../Http/Dispatchers/ManagedHttpDispatcher.cs | 1 + .../IndexerProxies/FlareSolverr/FlareSolverr.cs | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs index 20b407a69..da4269363 100644 --- a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs +++ b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs @@ -234,6 +234,7 @@ namespace NzbDrone.Common.Http.Dispatchers webRequest.Headers.TransferEncoding.ParseAdd(header.Value); break; case "User-Agent": + webRequest.Headers.UserAgent.Clear(); webRequest.Headers.UserAgent.ParseAdd(header.Value); break; case "Proxy-Connection": diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index baa873222..7cbf6844d 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -112,9 +112,9 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr } else if (request.Method == HttpMethod.Post) { - var contentTypeType = request.Headers.ContentType; + var contentTypeType = request.Headers.ContentType.ToLower() ?? "<null>"; - if (contentTypeType == "application/x-www-form-urlencoded") + if (contentTypeType.Contains("application/x-www-form-urlencoded")) { var contentTypeValue = request.Headers.ContentType.ToString(); var postData = request.GetContent(); @@ -133,7 +133,8 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr UserAgent = userAgent }; } - else if (contentTypeType.Contains("multipart/form-data")) + else if (contentTypeType.Contains("multipart/form-data") + || contentTypeType.Contains("text/html")) { //TODO Implement - check if we just need to pass the content-type with the relevant headers throw new FlareSolverrException("Unimplemented POST Content-Type: " + request.Headers.ContentType); @@ -153,9 +154,10 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr newRequest.Headers.ContentType = "application/json"; newRequest.Method = HttpMethod.Post; + newRequest.LogResponseContent = true; newRequest.SetContent(req.ToJson()); - _logger.Debug("Applying FlareSolverr Proxy {0} to request {1}", Name, request.Url); + _logger.Debug("Cloudflare Detected, Applying FlareSolverr Proxy {0} to request {1}", Name, request.Url); return newRequest; } From b5d789df3a533226f228ee4561a55f02edd2e031 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 13 Aug 2022 17:30:25 -0500 Subject: [PATCH 0564/2320] Fixed: Correctly persist FlareSolverr Cookies to ensure it doesn't run on every request --- src/NzbDrone.Core/Indexers/HttpIndexerBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index 9adc525e2..802803997 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -403,7 +403,7 @@ namespace NzbDrone.Core.Indexers throw new CloudFlareProtectionException(response); } - UpdateCookies(Cookies, DateTime.Now + TimeSpan.FromDays(30)); + UpdateCookies(request.HttpRequest.Cookies, DateTime.Now + TimeSpan.FromDays(30)); return new IndexerResponse(request, response); } From 7f63757e06286c4d31eadab8e67596edf089c4b2 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Mon, 8 Aug 2022 07:09:09 +0000 Subject: [PATCH 0565/2320] Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 100.0% (462 of 462 strings) Co-authored-by: Jessie <1355239678@qq.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/zh_CN.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index f331b6085..538748708 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -321,7 +321,7 @@ "TableOptions": "表格选项", "TableOptionsColumnsMessage": "选择显示哪些列并排序", "Tags": "标签", - "TagsHelpText": "应用于具有至少一个匹配标签的电影", + "TagsHelpText": "适用于至少有一个匹配标签的索引器", "TagsSettingsSummary": "显示全部标签和标签使用情况,可删除未使用的标签", "Tasks": "任务", "Test": "测试", @@ -358,7 +358,7 @@ "ResetAPIKey": "重置API Key", "Restart": "重启", "RestartNow": "马上重启", - "UnableToLoadIndexerProxies": "无法加载搜刮器代理", + "UnableToLoadIndexerProxies": "无法加载索引器代理", "UnableToLoadDevelopmentSettings": "无法加载开发设置", "UnableToLoadAppProfiles": "无法加载应用配置", "UISettingsSummary": "日期,语言及色盲选项", @@ -405,7 +405,7 @@ "Categories": "分类", "Database": "数据库", "HistoryCleanup": "清理历史记录", - "IndexerAlreadySetup": "至少有一个索引器已经设置完毕", + "IndexerAlreadySetup": "至少已经设置了一个索引器", "IndexerInfo": "索引器信息", "IndexerNoDefCheckMessage": "索引器没有定义,将无法工作: {0}. 请删除或重新添加到Prowlarr", "MovieSearch": "搜索电影", From 64465280226f801ba3de256f37f4812f4bebd4a7 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 15 Aug 2022 22:40:22 -0500 Subject: [PATCH 0566/2320] Bump version to 0.4.5 --- azure-pipelines.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 4035c39bc..f58644717 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: testsFolder: './_tests' yarnCacheFolder: $(Pipeline.Workspace)/.yarn nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages - majorVersion: '0.4.4' + majorVersion: '0.4.5' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' @@ -541,7 +541,7 @@ stages: Prowlarr__Postgres__Password: 'prowlarr' pool: - vmImage: 'ubuntu-18.04' + vmImage: ${{ variables.linuxImage }} timeoutInMinutes: 10 @@ -675,7 +675,7 @@ stages: Prowlarr__Postgres__Password: 'prowlarr' pool: - vmImage: 'ubuntu-18.04' + vmImage: ${{ variables.linuxImage }} steps: - task: UseDotNet@2 From d58f6551e6b1c1070f2830ad86b79abdfce45e18 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 18 Aug 2022 19:56:13 -0500 Subject: [PATCH 0567/2320] Fixed: Set Units for Seed Time settings --- src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs index 228b38858..622c59e37 100644 --- a/src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs @@ -41,7 +41,7 @@ namespace NzbDrone.Core.Indexers [FieldDefinition(1, Type = FieldType.Textbox, Label = "Seed Ratio", HelpText = "The ratio a torrent should reach before stopping, empty is app's default", Advanced = true)] public double? SeedRatio { get; set; } - [FieldDefinition(2, Type = FieldType.Number, Label = "Seed Time", HelpText = "The time a torrent should be seeded before stopping, empty is app's default", Advanced = true)] + [FieldDefinition(2, Type = FieldType.Number, Label = "Seed Time", HelpText = "The time a torrent should be seeded before stopping, empty is app's default", Unit = "minutes", Advanced = true)] public int? SeedTime { get; set; } } } From 7e01c93b2cf2292660add5b3fee7fc49103d6f1a Mon Sep 17 00:00:00 2001 From: Chris <1967906+psylenced@users.noreply.github.com> Date: Thu, 18 Aug 2022 22:00:58 +1000 Subject: [PATCH 0568/2320] Fixed: Regex in log cleanser taking 10+ minutes on messages longer than 100k. (cherry picked from commit d01bae92bfd68b04c54ab19bafe8af16c68ce711) --- src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index 9a501d607..6170019e9 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -18,6 +18,7 @@ namespace NzbDrone.Common.Instrumentation new Regex(@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"/fetch/[a-z0-9]{32}/(?<secret>[a-z0-9]{32})", RegexOptions.Compiled), new Regex(@"getnzb.*?(?<=\?|&)(r)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"\b[^=]*?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"(?<=authkey = "")(?<secret>[^&=]+?)(?="")", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"(?<=beyond-hd\.[a-z]+/api/torrents/)(?<secret>[^&=][a-z0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), From 232a6efd0d6010a2bd6e121dea37dbc29adf75fd Mon Sep 17 00:00:00 2001 From: Yukine <DevYukine@gmx.de> Date: Fri, 19 Aug 2022 03:04:29 +0200 Subject: [PATCH 0569/2320] New: (Indexer) GreatPosterWall (#1085) * New: (Indexer) GreatPosterWall * fix(GreatPosterWall): time is Chinese and not UTC * feat(GreatPosterWall): add canUseToken check to GetDownloadUrl * feat(GreatPosterWall): add fileName property as title --- .../Indexers/Definitions/GreatPosterWall.cs | 354 ++++++++++++++++++ 1 file changed, 354 insertions(+) create mode 100644 src/NzbDrone.Core/Indexers/Definitions/GreatPosterWall.cs diff --git a/src/NzbDrone.Core/Indexers/Definitions/GreatPosterWall.cs b/src/NzbDrone.Core/Indexers/Definitions/GreatPosterWall.cs new file mode 100644 index 000000000..bdee19c3f --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/GreatPosterWall.cs @@ -0,0 +1,354 @@ +using System; +using System.Collections.Generic; +using System.Net; +using Newtonsoft.Json; +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Gazelle; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; + +namespace NzbDrone.Core.Indexers.Definitions; + +public class GreatPosterWall : Gazelle.Gazelle +{ + public override string Name => "GreatPosterWall"; + public override string[] IndexerUrls => new string[] { "https://greatposterwall.com/" }; + public override string Description => "GreatPosterWall (GPW) is a CHINESE Private site for MOVIES"; + public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + + public GreatPosterWall(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) + { + } + + public override IIndexerRequestGenerator GetRequestGenerator() + { + return new GreatPosterWallRequestGenerator() + { + Settings = Settings, + HttpClient = _httpClient, + Logger = _logger, + Capabilities = Capabilities + }; + } + + public override IParseIndexerResponse GetParser() + { + return new GreatPosterWallParser(Settings, Capabilities); + } + + protected override IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities + { + MovieSearchParams = new List<MovieSearchParam> + { + MovieSearchParam.Q, MovieSearchParam.ImdbId + } + }; + + caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movies 电影"); + + return caps; + } +} + +public class GreatPosterWallRequestGenerator : GazelleRequestGenerator +{ + protected override bool ImdbInTags => false; +} + +public class GreatPosterWallParser : GazelleParser +{ + public GreatPosterWallParser(GazelleSettings settings, IndexerCapabilities capabilities) + : base(settings, capabilities) + { + } + + public override IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) + { + var torrentInfos = new List<ReleaseInfo>(); + + if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) + { + // Remove cookie cache + CookiesUpdater(null, null); + + throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request"); + } + + if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value)) + { + // Remove cookie cache + CookiesUpdater(null, null); + + throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}"); + } + + var jsonResponse = new HttpResponse<GreatPosterWallResponse>(indexerResponse.HttpResponse); + if (jsonResponse.Resource.Status != "success" || + jsonResponse.Resource.Status.IsNullOrWhiteSpace() || + jsonResponse.Resource.Response == null) + { + return torrentInfos; + } + + foreach (var result in jsonResponse.Resource.Response.Results) + { + foreach (var torrent in result.Torrents) + { + var infoUrl = GetInfoUrl(result.GroupId.ToString(), torrent.TorrentId); + + var time = DateTime.SpecifyKind(torrent.Time, DateTimeKind.Unspecified); + + var release = new GazelleInfo + { + MinimumRatio = 1, + MinimumSeedTime = 172800, + Title = torrent.FileName, + InfoUrl = infoUrl, + Guid = infoUrl, + PosterUrl = GetPosterUrl(result.Cover), + DownloadUrl = GetDownloadUrl(torrent.TorrentId, torrent.CanUseToken), + PublishDate = new DateTimeOffset(time, TimeSpan.FromHours(8)).LocalDateTime, // Time is Chinese Time, add 8 hours difference from UTC and then convert back to local time + Categories = new List<IndexerCategory> { NewznabStandardCategory.Movies }, + Size = torrent.Size, + Seeders = torrent.Seeders, + Peers = torrent.Seeders + torrent.Leechers, + Grabs = torrent.Snatches, + Files = torrent.FileCount, + Scene = torrent.Scene, + DownloadVolumeFactor = torrent.IsFreeleech || torrent.IsNeutralLeech || torrent.IsPersonalFreeleech ? 0 : 1, + UploadVolumeFactor = torrent.IsNeutralLeech ? 0 : 1 + }; + + var imdbId = ParseUtil.GetImdbID(result.ImdbId); + + if (imdbId != null) + { + release.ImdbId = (int)imdbId; + } + + switch (torrent.FreeType) + { + case "11": + release.DownloadVolumeFactor = 0.75; + break; + case "12": + release.DownloadVolumeFactor = 0.5; + break; + case "13": + release.DownloadVolumeFactor = 0.25; + break; + case "1": + release.DownloadVolumeFactor = 0; + break; + case "2": + release.DownloadVolumeFactor = 0; + release.UploadVolumeFactor = 0; + break; + } + + torrentInfos.Add(release); + } + } + + return torrentInfos; + } + + protected string GetDownloadUrl(int torrentId, bool canUseToken) + { + var url = new HttpUri(_settings.BaseUrl) + .CombinePath("/torrents.php") + .AddQueryParam("action", "download") + .AddQueryParam("usetoken", _settings.UseFreeleechToken && canUseToken ? "1" : "0") + .AddQueryParam("id", torrentId); + + return url.FullUri; + } +} + +public class GreatPosterWallResponse +{ + [JsonProperty("status")] + public string Status { get; set; } + + [JsonProperty("response")] + public Response Response { get; set; } +} + +public class Response +{ + [JsonProperty("currentPage")] + public int CurrentPage { get; set; } + + [JsonProperty("pages")] + public int Pages { get; set; } + + [JsonProperty("results")] + public List<Result> Results { get; set; } +} + +public class Result +{ + [JsonProperty("groupId")] + public int GroupId { get; set; } + + [JsonProperty("groupName")] + public string GroupName { get; set; } + + [JsonProperty("groupSubName")] + public string GroupSubName { get; set; } + + [JsonProperty("cover")] + public string Cover { get; set; } + + [JsonProperty("tags")] + public List<string> Tags { get; set; } + + [JsonProperty("bookmarked")] + public bool Bookmarked { get; set; } + + [JsonProperty("groupYear")] + public int GroupYear { get; set; } + + [JsonProperty("releaseType")] + public string ReleaseType { get; set; } + + [JsonProperty("groupTime")] + public string GroupTime { get; set; } + + [JsonProperty("maxSize")] + public object MaxSize { get; set; } + + [JsonProperty("totalSnatched")] + public int TotalSnatched { get; set; } + + [JsonProperty("totalSeeders")] + public int TotalSeeders { get; set; } + + [JsonProperty("totalLeechers")] + public int TotalLeechers { get; set; } + + [JsonProperty("imdbId")] + public string ImdbId { get; set; } + + [JsonProperty("imdbRating")] + public string ImdbRating { get; set; } + + [JsonProperty("imdbVote")] + public string ImdbVote { get; set; } + + [JsonProperty("doubanId")] + public string DoubanId { get; set; } + + [JsonProperty("doubanRating")] + public string DoubanRating { get; set; } + + [JsonProperty("doubanVote")] + public string DoubanVote { get; set; } + + [JsonProperty("rtRating")] + public string RtRating { get; set; } + + [JsonProperty("region")] + public string Region { get; set; } + + [JsonProperty("torrents")] + public List<GreatPosterWallTorrent> Torrents { get; set; } +} + +public class GreatPosterWallTorrent +{ + [JsonProperty("torrentId")] + public int TorrentId { get; set; } + + [JsonProperty("editionId")] + public int EditionId { get; set; } + + [JsonProperty("remasterYear")] + public int RemasterYear { get; set; } + + [JsonProperty("remasterTitle")] + public string RemasterTitle { get; set; } + + [JsonProperty("remasterCustomTitle")] + public string RemasterCustomTitle { get; set; } + + [JsonProperty("scene")] + public bool Scene { get; set; } + + [JsonProperty("jinzhuan")] + public bool Jinzhuan { get; set; } + + [JsonProperty("fileCount")] + public int FileCount { get; set; } + + [JsonProperty("time")] + public DateTime Time { get; set; } + + [JsonProperty("size")] + public long Size { get; set; } + + [JsonProperty("snatches")] + public int Snatches { get; set; } + + [JsonProperty("seeders")] + public int Seeders { get; set; } + + [JsonProperty("leechers")] + public int Leechers { get; set; } + + [JsonProperty("isFreeleech")] + public bool IsFreeleech { get; set; } + + [JsonProperty("isNeutralLeech")] + public bool IsNeutralLeech { get; set; } + + [JsonProperty("freeType")] + public string FreeType { get; set; } + + [JsonProperty("isPersonalFreeleech")] + public bool IsPersonalFreeleech { get; set; } + + [JsonProperty("canUseToken")] + public bool CanUseToken { get; set; } + + [JsonProperty("hasSnatched")] + public bool HasSnatched { get; set; } + + [JsonProperty("resolution")] + public string Resolution { get; set; } + + [JsonProperty("source")] + public string Source { get; set; } + + [JsonProperty("codec")] + public string Codec { get; set; } + + [JsonProperty("container")] + public string Container { get; set; } + + [JsonProperty("processing")] + public string Processing { get; set; } + + [JsonProperty("chineseDubbed")] + public string ChineseDubbed { get; set; } + + [JsonProperty("specialSub")] + public string SpecialSub { get; set; } + + [JsonProperty("subtitles")] + public string Subtitles { get; set; } + + [JsonProperty("fileName")] + public string FileName { get; set; } + + [JsonProperty("releaseGroup")] + public string ReleaseGroup { get; set; } +} From 5a278f4e9d48869b8676fb0413751bc1b5a5d9cc Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 18 Aug 2022 22:30:04 -0500 Subject: [PATCH 0570/2320] Fixed: Set default null value for Genre, Publisher, Douban parameters --- .../Definitions/Cardigann/CardigannRequestGenerator.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 910a8dbb5..a1c322a23 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -152,6 +152,7 @@ namespace NzbDrone.Core.Indexers.Cardigann variables[".Query.Offset"] = searchCriteria.Offset?.ToString() ?? null; variables[".Query.Extended"] = null; variables[".Query.APIKey"] = null; + variables[".Query.Genre"] = null; //Movie variables[".Query.Movie"] = null; @@ -168,6 +169,7 @@ namespace NzbDrone.Core.Indexers.Cardigann variables[".Query.TVRageID"] = null; variables[".Query.TVMazeID"] = null; variables[".Query.TraktID"] = null; + variables[".Query.DoubanID"] = null; variables[".Query.Episode"] = null; //Music @@ -179,6 +181,7 @@ namespace NzbDrone.Core.Indexers.Cardigann //Book variables[".Query.Author"] = null; variables[".Query.Title"] = null; + variables[".Query.Publisher"] = null; return variables; } From bf2e0572478931c27492cbf9dd07e8a240a79f7c Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Wed, 17 Aug 2022 20:09:13 +0000 Subject: [PATCH 0571/2320] Translated using Weblate (Russian) Currently translated at 76.1% (352 of 462 strings) Translated using Weblate (Romanian) Currently translated at 71.8% (332 of 462 strings) Co-authored-by: AlexR-sf <omg.portal.supp@gmail.com> Co-authored-by: emanuelsipos <emanuelsipos1@gmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ro/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ru/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/ro.json | 153 +++++++++++++------- src/NzbDrone.Core/Localization/Core/ru.json | 6 +- 2 files changed, 102 insertions(+), 57 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/ro.json b/src/NzbDrone.Core/Localization/Core/ro.json index 87d681064..2e0489443 100644 --- a/src/NzbDrone.Core/Localization/Core/ro.json +++ b/src/NzbDrone.Core/Localization/Core/ro.json @@ -19,25 +19,25 @@ "Added": "Adăugat", "Actions": "Acțiuni", "About": "Despre", - "IndexerStatusCheckAllClientMessage": "Niciun indexator nu este disponibil datorită eșuărilor", + "IndexerStatusCheckAllClientMessage": "Niciun indexator nu este disponibil datorită erorilor", "Indexers": "Indexatori", "Indexer": "Indexator", "Host": "Gazdă", - "History": "Istorie", + "History": "Istoric", "HideAdvanced": "Ascunde Avansat", "Health": "Sănătate", - "Grabbed": "Prins", + "Grabbed": "În curs de descărcare", "GeneralSettingsSummary": "Port, SSL, utilizator/parolă, proxy, statistici și actualizări", "General": "General", "Folder": "Dosar", "Filter": "Filtru", "Files": "Fișiere", - "Filename": "Numele Fișierului", + "Filename": "Numele fișierului", "Failed": "Eșuat", "EventType": "Tip de eveniment", "Events": "Evenimente", "Edit": "Editează", - "DownloadClientStatusCheckSingleClientMessage": "Clienții de descărcare sunt indisponibili datorită erorii: {0}", + "DownloadClientStatusCheckSingleClientMessage": "Clienții de descărcare sunt indisponibili datorită erorilor: {0}", "DownloadClientStatusCheckAllClientMessage": "Toți clienții de descărcare sunt indisponibili datorită erorilor", "Peers": "Parteneri", "PageSize": "Mărimea Paginii", @@ -56,11 +56,11 @@ "Language": "Limbă", "KeyboardShortcuts": "Scurtături din tastatură", "Info": "Info", - "IndexerStatusCheckSingleClientMessage": "Indexator indisponibil datorită erorilor: {0}", - "HealthNoIssues": "Nicio problemă în configurare", + "IndexerStatusCheckSingleClientMessage": "Indexatoare indisponibile datorită erorilor: {0}", + "HealthNoIssues": "Nicio problemă de configurare", "Error": "Eroare", "ConnectionLostMessage": "Prowlarr a pierdut conexiunea cu backend-ul și trebuie reîncărcat pentru a restabili funcționalitatea.", - "ConnectionLostAutomaticMessage": "Prowlarr va încerca să se reconecteze automat sau poți apăsa reîncarcă mai jos.", + "ConnectionLostAutomaticMessage": "Prowlarr va încerca să se conecteze automat, sau poți apăsa reîncarcă mai jos.", "ConnectionLost": "Conexiune Pierdută", "Component": "Componentă", "Columns": "Coloane", @@ -68,7 +68,7 @@ "Cancel": "Anulează", "Apply": "Aplică", "Age": "Vechime", - "PtpOldSettingsCheckMessage": "Următorul indexer PassThePopcorn are setări depreciate și ar trebui actualizate: {0}", + "PtpOldSettingsCheckMessage": "Următoarele indexatoare PassThePopcorn au setări depreciate și ar trebui actualizate: {0}", "ProxyCheckResolveIpMessage": "Nu am putut găsi adresa IP pentru Hostul Proxy Configurat {0}", "ProxyCheckFailedToTestMessage": "Nu am putut testa proxy: {0}", "ProxyCheckBadRequestMessage": "Testul proxy a eșuat. StatusCode: {0}", @@ -125,7 +125,7 @@ "SettingsLongDateFormat": "Format de dată lungă", "SettingsShortDateFormat": "Format scurt de dată", "SettingsTimeFormat": "Format de timp", - "RSSIsNotSupportedWithThisIndexer": "RSS nu este acceptat cu acest indexer", + "RSSIsNotSupportedWithThisIndexer": "RSS nu este suportat de acest indexator", "ShowSearchHelpText": "Afișați butonul de căutare pe hover", "UILanguageHelpText": "Limba pe care Radarr o va folosi pentru interfața de utilizare", "UILanguageHelpTextWarning": "Reîncărcare browser necesară", @@ -137,35 +137,35 @@ "AddingTag": "Se adaugă etichetă", "LaunchBrowserHelpText": " Deschideți un browser web și navigați la pagina de pornire Radarr la pornirea aplicației.", "AppDataDirectory": "Directorul AppData", - "ApplicationStatusCheckAllClientMessage": "Toate listele sunt indisponibile datorită erorilor", + "ApplicationStatusCheckAllClientMessage": "Toate aplicațiile sunt indisponibile datorită erorilor", "AreYouSureYouWantToResetYourAPIKey": "Sigur doriți să vă resetați cheia API?", "Authentication": "Autentificare", - "AuthenticationMethodHelpText": "Solicitați numele de utilizator și parola pentru a accesa Radarr", + "AuthenticationMethodHelpText": "Solicitați numele de utilizator și parola pentru a accesa Prowlarr", "AutomaticSearch": "Căutare automată", - "BackupFolderHelpText": "Căile relative vor fi în directorul AppData al lui Radarr", - "BackupIntervalHelpText": "Interval între copiile de rezervă automate", - "Backups": "Copii de rezervă", + "BackupFolderHelpText": "Căile relative vor fi în directorul AppData al lui Prowlarr", + "BackupIntervalHelpText": "Interval între crearea copiile de siguranță automate", + "Backups": "Copii de siguranță", "BeforeUpdate": "Înainte de actualizare", - "BindAddressHelpText": "Adresă IP4 validă sau „*” pentru toate interfețele", + "BindAddressHelpText": "Adresă IPv4 validă sau '*' pentru toate interfațele", "Branch": "Ramură", - "BranchUpdate": "Sucursală de utilizat pentru actualizarea Radarr", + "BranchUpdate": "Ramură utilizată pentru a actualiza Prowlarr", "BranchUpdateMechanism": "Ramură utilizată de mecanismul extern de actualizare", - "BypassProxyForLocalAddresses": "Bypass Proxy pentru adrese locale", + "BypassProxyForLocalAddresses": "Nu folosiți Proxy pentru adrese locale", "CancelPendingTask": "Sigur doriți să anulați această sarcină în așteptare?", "CertificateValidation": "Validarea certificatului", "CertificateValidationHelpText": "Modificați cât de strictă este validarea certificării HTTPS", "ClientPriority": "Prioritatea clientului", "CloseCurrentModal": "Închideți modul curent", - "EnableAutomaticSearch": "Activați Căutarea automată", - "EnableAutomaticSearchHelpText": "Va fi utilizat atunci când căutările automate sunt efectuate prin interfața de utilizare sau de către Radarr", + "EnableAutomaticSearch": "Activați căutarea automată", + "EnableAutomaticSearchHelpText": "Va fi utilizat atunci când căutările automate sunt efectuate prin interfața de utilizare sau de către Prowlarr", "EnableInteractiveSearchHelpText": "Va fi utilizat atunci când este utilizată căutarea interactivă", "ForMoreInformationOnTheIndividualDownloadClients": "Pentru mai multe informații despre clienții individuali de descărcare, faceți clic pe butoanele de informații.", "IllRestartLater": "Voi reporni mai târziu", - "IndexerProxyStatusCheckAllClientMessage": "Niciun indexator nu este disponibil datorită eșuărilor", - "IndexerProxyStatusCheckSingleClientMessage": "Liste indisponibile datorită erorilor: {0}", - "Add": "Adăuga", + "IndexerProxyStatusCheckAllClientMessage": "Niciun indexator nu este disponibil datorită erorilor", + "IndexerProxyStatusCheckSingleClientMessage": "Proxiuri indisponibile datorită erorilor: {0}", + "Add": "Adaugă", "Custom": "Personalizat", - "DeleteBackup": "Ștergeți Backup", + "DeleteBackup": "Ștergeți copie de siguranță", "MovieIndexScrollBottom": "Index film: Derulați partea de jos", "NoLinks": "Fără legături", "NoUpdatesAreAvailable": "Nu sunt disponibile actualizări", @@ -189,8 +189,8 @@ "URLBase": "Baza URL", "UrlBaseHelpText": "Pentru suport proxy invers, implicit este gol", "Usenet": "Usenet", - "EditIndexer": "Editați Indexer", - "Enable": "Permite", + "EditIndexer": "Editați indexator", + "Enable": "Activați", "EnableRss": "Activați RSS", "ErrorLoadingContents": "Eroare la încărcarea conținutului", "FocusSearchBox": "Caseta de căutare Focus", @@ -203,10 +203,10 @@ "Torrents": "Torente", "UnableToAddANewApplicationPleaseTryAgain": "Imposibil de adăugat o nouă notificare, încercați din nou.", "UnableToAddANewDownloadClientPleaseTryAgain": "Imposibil de adăugat un nou client de descărcare, încercați din nou.", - "DownloadClientSettings": "Descărcați setările clientului", + "DownloadClientSettings": "Setări client de descărcare", "Enabled": "Activat", "IncludeHealthWarningsHelpText": "Includeți avertismente de sănătate", - "IndexerPriorityHelpText": "Prioritatea indexerului de la 1 (cea mai mare) la 50 (cea mai mică). Implicit: 25.", + "IndexerPriorityHelpText": "Prioritatea indexatorului de la 1 (cea mai mare) la 50 (cea mai mică). Implicit: 25.", "InteractiveSearch": "Căutare interactivă", "LogLevel": "Nivel jurnal", "LogLevelTraceHelpTextWarning": "Înregistrarea urmăririi trebuie activată doar temporar", @@ -227,15 +227,15 @@ "UnableToLoadTags": "Nu se pot încărca etichete", "UnableToLoadUISettings": "Nu se pot încărca setările UI", "UpdateMechanismHelpText": "Utilizați actualizatorul încorporat al lui Radarr sau un script", - "AnalyticsEnabledHelpText": "Trimiteți informații anonime privind utilizarea și erorile către serverele Radarr. Aceasta include informații despre browserul dvs., ce pagini WebUI Radarr utilizați, raportarea erorilor, precum și sistemul de operare și versiunea de execuție. Vom folosi aceste informații pentru a acorda prioritate caracteristicilor și remedierilor de erori.", + "AnalyticsEnabledHelpText": "Trimiteți informații anonime privind utilizarea și erorile către serverele Prowlarr. Aceasta include informații despre browserul folosit, ce pagini WebUI Prowlarr utilizați, raportarea erorilor, precum și sistemul de operare și versiunea de execuție. Vom folosi aceste informații pentru a acorda prioritate caracteristicilor și remedierilor de erori.", "ApiKey": "Cheie API", - "BackupRetentionHelpText": "Copiile de rezervă automate mai vechi de perioada de păstrare vor fi curățate automat", + "BackupRetentionHelpText": "Copiile de siguranță automate mai vechi decât perioada de păstrare vor fi curățate automat", "BindAddress": "Adresa de legare", "ChangeHasNotBeenSavedYet": "Modificarea nu a fost încă salvată", - "CloneProfile": "Profil de clonare", + "CloneProfile": "Clonați profil", "NoLeaveIt": "Nu, lasă-l", - "DBMigration": "Migrarea DB", - "DeleteBackupMessageText": "Sigur doriți să ștergeți copia de rezervă „{0}”?", + "DBMigration": "Migrarea BD", + "DeleteBackupMessageText": "Sigur doriți să ștergeți copia de siguranță „{0}”?", "DeleteTagMessageText": "Sigur doriți să ștergeți eticheta „{0}”?", "EnableInteractiveSearch": "Activați căutarea interactivă", "EnableSSL": "Activați SSL", @@ -243,12 +243,12 @@ "ExistingTag": "Etichetă existentă", "FeatureRequests": "Cereri de caracteristici", "HiddenClickToShow": "Ascuns, faceți clic pentru a afișa", - "HomePage": "Pagina principala", + "HomePage": "Pagina principală", "Hostname": "Numele gazdei", "IgnoredAddresses": "Adrese ignorate", - "IndexerLongTermStatusCheckAllClientMessage": "Toți indexatorii nu sunt disponibili din cauza unor eșecuri de mai mult de 6 ore", - "IndexerLongTermStatusCheckSingleClientMessage": "Indexatori indisponibili din cauza unor eșecuri de mai mult de 6 ore: {0}", - "IndexerPriority": "Prioritatea indexerului", + "IndexerLongTermStatusCheckAllClientMessage": "Toți indexatorii sunt indisponibili datorită erorilor de mai mult de 6 ore", + "IndexerLongTermStatusCheckSingleClientMessage": "Indexatori indisponibili datorită erorilor de mai mult de 6 ore: {0}", + "IndexerPriority": "Prioritatea indexatorului", "Mode": "Mod", "MovieIndexScrollTop": "Index film: Derulați sus", "NoBackupsAreAvailable": "Nu sunt disponibile copii de rezervă", @@ -266,14 +266,14 @@ "ShowSearch": "Afișați Căutare", "TagCannotBeDeletedWhileInUse": "Nu poate fi șters în timpul utilizării", "TagIsNotUsedAndCanBeDeleted": "Eticheta nu este utilizată și poate fi ștearsă", - "TagsHelpText": "Se aplică filmelor cu cel puțin o etichetă potrivită", + "TagsHelpText": "Se aplică indexatoarelor cu cel puțin o etichetă potrivită", "Tomorrow": "Mâine", "Torrent": "Torente", "UILanguage": "Limbajul UI", "UISettings": "Setări UI", "UnableToAddANewAppProfilePleaseTryAgain": "Imposibil de adăugat un nou profil de calitate, încercați din nou.", - "UnableToAddANewIndexerPleaseTryAgain": "Imposibil de adăugat un nou indexer, încercați din nou.", - "UnableToAddANewIndexerProxyPleaseTryAgain": "Imposibil de adăugat un nou indexer, încercați din nou.", + "UnableToAddANewIndexerPleaseTryAgain": "Nu se poate adăuga un nou indexator, vă rugăm să încercați din nou.", + "UnableToAddANewIndexerProxyPleaseTryAgain": "Nu se poate adăuga un nou proxy indexator, vă rugăm să încercați din nou.", "UpdateScriptPathHelpText": "Calea către un script personalizat care preia un pachet de actualizare extras și se ocupă de restul procesului de actualizare", "Uptime": "Timp de funcționare", "UseProxy": "Utilizarea proxy", @@ -281,10 +281,10 @@ "Version": "Versiune", "Yesterday": "Ieri", "AcceptConfirmationModal": "Acceptați Modul de confirmare", - "DeleteIndexerProxyMessageText": "Sigur doriți să ștergeți eticheta „{0}”?", + "DeleteIndexerProxyMessageText": "Sigur doriți să ștergeți proxyul „{0}”?", "Disabled": "Dezactivat", - "Discord": "Discordie", - "Docker": "Docher", + "Discord": "Discord", + "Docker": "Docker", "Donations": "Donații", "Interval": "Interval", "Manual": "Manual", @@ -293,14 +293,14 @@ "UnsavedChanges": "Modificări nesalvate", "UpdateAutomaticallyHelpText": "Descărcați și instalați automat actualizări. Veți putea în continuare să instalați din System: Updates", "AddDownloadClient": "Adăugați client de descărcare", - "AddIndexer": "Adăugați Indexer", - "AllIndexersHiddenDueToFilter": "Toate filmele sunt ascunse datorită filtrelor aplicate.", + "AddIndexer": "Adăugați Indexator", + "AllIndexersHiddenDueToFilter": "Toate indexatoarele sunt ascunse datorită filtrelor aplicate.", "DeleteDownloadClient": "Ștergeți clientul de descărcare", "DeleteDownloadClientMessageText": "Sigur doriți să ștergeți clientul de descărcare „{0}”?", "ConnectSettings": "Setări conectare", "CouldNotConnectSignalR": "Nu s-a putut conecta la SignalR, UI nu se va actualiza", - "GeneralSettings": "setari generale", - "Grabs": "Apuca", + "GeneralSettings": "Setări generale", + "Grabs": "Descărcări", "Port": "Port", "PortNumber": "Numarul portului", "Reset": "Resetați", @@ -313,27 +313,68 @@ "StartTypingOrSelectAPathBelow": "Începeți să tastați sau selectați o cale de mai jos", "StartupDirectory": "Director de pornire", "SuggestTranslationChange": "Sugerează modificarea traducerii", - "ApplicationStatusCheckSingleClientMessage": "Liste indisponibile datorită erorilor: {0}", + "ApplicationStatusCheckSingleClientMessage": "Aplicații indisponibile datorită erorilor: {0}", "ApplyTags": "Aplicați etichete", - "ApplyTagsHelpTexts1": "Cum se aplică etichete filmelor selectate", + "ApplyTagsHelpTexts1": "Cum se aplică etichete indexatoarelor selectate", "ApplyTagsHelpTexts2": "Adăugare: adăugați etichetele la lista de etichete existentă", "ApplyTagsHelpTexts3": "Eliminați: eliminați etichetele introduse", "ApplyTagsHelpTexts4": "Înlocuire: înlocuiți etichetele cu etichetele introduse (nu introduceți etichete pentru a șterge toate etichetele)", "Automatic": "Automat", - "DeleteApplicationMessageText": "Sigur doriți să ștergeți notificarea „{0}”?", + "DeleteApplicationMessageText": "Sigur doriți să ștergeți aplicația „{0}”?", "Exception": "Excepție", "MaintenanceRelease": "Versiune de întreținere: remedieri de erori și alte îmbunătățiri. Consultați Istoricul comiterilor Github pentru mai multe detalii", - "Filters": "Filtru", + "Filters": "Filtre", "HistoryCleanupDaysHelpText": "Setați la 0 pentru a dezactiva curățarea automată", - "HistoryCleanupDaysHelpTextWarning": "Fișierele din coșul de reciclare mai vechi de numărul de zile selectat vor fi curățate automat", + "HistoryCleanupDaysHelpTextWarning": "Obiectele din istoric în coșul de reciclare mai vechi de numărul de zile selectat vor fi curățate automat", "OnGrab": "Pe Grab", "OnHealthIssue": "Cu privire la problema sănătății", - "TestAllIndexers": "Testați toți indexatorii", + "TestAllIndexers": "Testați toate indexatoarele", "Link": "Link-uri", "NetCore": ".NET Core", - "UnableToLoadIndexers": "Imposibil de încărcat indexatori", - "GrabReleases": "Grab Release", + "UnableToLoadIndexers": "Nu se pot încărca indexatoarele", + "GrabReleases": "Descarcă fișier(e)", "MappedDrivesRunningAsService": "Unitățile de rețea mapate nu sunt disponibile atunci când rulează ca serviciu Windows. Vă rugăm să consultați FAQ pentru mai multe informații", "No": "Nu", - "Yes": "da" + "Yes": "da", + "IndexerSettingsSummary": "Configurați diverse setări globale indexatoare inclusiv proxiuri.", + "EnableRssHelpText": "Activați flux RSS pentru indexator", + "IndexerHealthCheckNoIndexers": "Niciun indexator nu este activat, Prowlarr nu va returna rezultate la căutare.", + "IndexerProxy": "Proxy indexator", + "IndexerVipCheckExpiredClientMessage": "Beneficiile VIP pentru indexator au expirat: {0}", + "IndexerNoDefCheckMessage": "Indexatorii nu au definiție și nu vor funcționa: {0}. Vă rugăm să-i ștergeți și (sau) să-i adăugați din nou în Prowlarr", + "IndexerRss": "RSS indexator", + "EnabledRedirected": "Activat, Redirecționat", + "Ended": "Finalizat", + "EnableIndexer": "Activați indexator", + "GrabTitle": "Descarcă titlu", + "HistoryCleanup": "Istoric curățare", + "Id": "Id", + "FilterPlaceHolder": "Căutați folosind indexatoare", + "IndexerAuth": "Autentificare indexator", + "IndexerDetails": "Detalii indexator", + "IndexerName": "Nume indexator", + "IndexerInfo": "Informații indexator", + "IndexerQuery": "Căutare indexator", + "IndexerSite": "Site indexator", + "IndexersSelectedInterp": "{0} Indexatoare selectate", + "IndexerTagsHelpText": "Folosiți etichete pentru a specifica proxiurile indexatoarelor, cu ce aplicații sunt sincronizate indexatoarele, sau doar pentru a le organiza.", + "SyncAppIndexers": "Sincronizați indexatoare aplicații", + "SyncLevelAddRemove": "Doar Adaugă sau Șterge: Când indexatoarele sunt adăugate sau șterse din Prowlarr, va actualiza această aplicație.", + "DeleteIndexerProxy": "Ștergeți proxy indexator", + "UnableToLoadIndexerProxies": "Nu se pot încărca proxiurile indexatoarelor", + "SettingsIndexerLoggingHelpText": "Logați informații adiționale despre indexatoare, inclusiv răspunsul", + "AddIndexerProxy": "Adăugați proxy indexator", + "AddNewIndexer": "Adăugați indexator nou", + "IndexerAlreadySetup": "Cel puțin o instanță de indexator e deja configurată", + "MinimumSeedersHelpText": "Seederi necesari pentru ca aplicația să descarce folosind indexatorul", + "ProwlarrSupportsAnyIndexer": "Prowlarr suportă multe indexatoare pe lângă orice indexator ce folosește standardul Newznab/Torznab folosind 'Generic Newznab' (pentru usenet) sau 'Generic Torznab' (pentru torrent). Căutați și selectați-vă indexatorul mai jos.", + "RedirectHelpText": "Redirecționați cererile de descărcare pentru indexator și predați descărcarea direct, in loc de a-o trece prin Prowlarr", + "SearchIndexers": "Căutare folosind indexatoare", + "SettingsIndexerLogging": "Logare îmbunătățită indexator", + "SyncLevelFull": "Sincronizare Completă: Va păstra indexatoarele acestei aplicații sincronizate complet. Schimbările făcute indexatoarelor în Prowlarr sunt sincronizate cu această aplicație. Orice schimbare făcută indexatoarelor în această aplicație vor fi șterse la următoarea sincronizare cu Prowlarr.", + "Encoding": "Encodare", + "FullSync": "Sincronizare completă", + "IndexerObsoleteCheckMessage": "Indexatorii sunt învechiți sau nu au fost actualizați: {0}. Vă rugăm să-i ștergeți și (sau) să-i adăugați din nou în Prowlarr", + "IndexerProxies": "Proxiuri indexatoare", + "IndexerVipCheckExpiringClientMessage": "Beneficiile VIP pentru indexator expiră în curând: {0}" } diff --git a/src/NzbDrone.Core/Localization/Core/ru.json b/src/NzbDrone.Core/Localization/Core/ru.json index c98499754..e20b8d0d5 100644 --- a/src/NzbDrone.Core/Localization/Core/ru.json +++ b/src/NzbDrone.Core/Localization/Core/ru.json @@ -347,5 +347,9 @@ "Encoding": "Кодирование", "Applications": "Приложения", "Application": "Приложения", - "Notifications": "Оповещения" + "Notifications": "Оповещения", + "InstanceName": "Имя экземпляра", + "InstanceNameHelpText": "Имя экземпляра на вкладке и для имени приложения системного журнала", + "Started": "Запущено", + "Database": "База данных" } From f97b35403d24e752f5a2442056d5cdd3e155d283 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 5 Sep 2022 19:55:46 -0500 Subject: [PATCH 0572/2320] Fixed: Indexer proxies not applying to requests Fixes #1107 --- .../Http/Dispatchers/ManagedHttpDispatcher.cs | 6 +++--- src/NzbDrone.Common/Http/HttpRequest.cs | 3 ++- src/NzbDrone.Core/IndexerProxies/Http/Http.cs | 17 +++++++++-------- .../IndexerProxies/Socks4/Socks4.cs | 16 ++++++++-------- .../IndexerProxies/Socks5/Socks5.cs | 16 ++++++++-------- 5 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs index da4269363..ea4b3790f 100644 --- a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs +++ b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs @@ -99,7 +99,7 @@ namespace NzbDrone.Common.Http.Dispatchers AddRequestHeaders(requestMessage, request.Headers); } - var httpClient = GetClient(request.Url); + var httpClient = GetClient(request.Url, request.ProxySettings); var sw = new Stopwatch(); @@ -154,9 +154,9 @@ namespace NzbDrone.Common.Http.Dispatchers } } - protected virtual System.Net.Http.HttpClient GetClient(HttpUri uri) + protected virtual System.Net.Http.HttpClient GetClient(HttpUri uri, HttpProxySettings requestProxy) { - var proxySettings = _proxySettingsProvider.GetProxySettings(uri); + var proxySettings = requestProxy ?? _proxySettingsProvider.GetProxySettings(uri); var key = proxySettings?.Key ?? NO_PROXY_KEY; diff --git a/src/NzbDrone.Common/Http/HttpRequest.cs b/src/NzbDrone.Common/Http/HttpRequest.cs index 5092207bc..779774a24 100644 --- a/src/NzbDrone.Common/Http/HttpRequest.cs +++ b/src/NzbDrone.Common/Http/HttpRequest.cs @@ -6,6 +6,7 @@ using System.Net.Http; using System.Text; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http.Proxy; namespace NzbDrone.Common.Http { @@ -37,7 +38,7 @@ namespace NzbDrone.Common.Http public HttpMethod Method { get; set; } public HttpHeader Headers { get; set; } public Encoding Encoding { get; set; } - public IWebProxy Proxy { get; set; } + public HttpProxySettings ProxySettings { get; set; } public byte[] ContentData { get; set; } public string ContentSummary { get; set; } public ICredentials Credentials { get; set; } diff --git a/src/NzbDrone.Core/IndexerProxies/Http/Http.cs b/src/NzbDrone.Core/IndexerProxies/Http/Http.cs index 838b3b2c8..8994f2919 100644 --- a/src/NzbDrone.Core/IndexerProxies/Http/Http.cs +++ b/src/NzbDrone.Core/IndexerProxies/Http/Http.cs @@ -3,7 +3,9 @@ using NLog; using NzbDrone.Common.Cloud; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Common.Http.Proxy; using NzbDrone.Core.Localization; +using NzbDrone.Core.Notifications.Prowl; namespace NzbDrone.Core.IndexerProxies.Http { @@ -18,14 +20,13 @@ namespace NzbDrone.Core.IndexerProxies.Http public override HttpRequest PreRequest(HttpRequest request) { - if (Settings.Username.IsNotNullOrWhiteSpace() && Settings.Password.IsNotNullOrWhiteSpace()) - { - request.Proxy = new WebProxy(Settings.Host + ":" + Settings.Port, false, null, new NetworkCredential(Settings.Username, Settings.Password)); - } - else - { - request.Proxy = new WebProxy(Settings.Host + ":" + Settings.Port, false, null); - } + request.ProxySettings = new HttpProxySettings(ProxyType.Http, + Settings.Host, + Settings.Port, + null, + false, + Settings.Username, + Settings.Password); _logger.Debug("Applying HTTP(S) Proxy {0} to request {1}", Name, request.Url); diff --git a/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs b/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs index 9fccb766a..554d8a78b 100644 --- a/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs +++ b/src/NzbDrone.Core/IndexerProxies/Socks4/Socks4.cs @@ -4,6 +4,7 @@ using NLog; using NzbDrone.Common.Cloud; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Common.Http.Proxy; using NzbDrone.Core.Localization; namespace NzbDrone.Core.IndexerProxies.Socks4 @@ -25,14 +26,13 @@ namespace NzbDrone.Core.IndexerProxies.Socks4 return null; } - if (Settings.Username.IsNotNullOrWhiteSpace() && Settings.Password.IsNotNullOrWhiteSpace()) - { - request.Proxy = new WebProxy(uri, false, null, new NetworkCredential(Settings.Username, Settings.Password)); - } - else - { - request.Proxy = new WebProxy(uri); - } + request.ProxySettings = new HttpProxySettings(ProxyType.Socks4, + Settings.Host, + Settings.Port, + null, + false, + Settings.Username, + Settings.Password); _logger.Debug("Applying Socks4 Proxy {0} to request {1}", Name, request.Url); diff --git a/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs b/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs index dfd572977..3a7ed0dbe 100644 --- a/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs +++ b/src/NzbDrone.Core/IndexerProxies/Socks5/Socks5.cs @@ -4,6 +4,7 @@ using NLog; using NzbDrone.Common.Cloud; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Common.Http.Proxy; using NzbDrone.Core.Localization; namespace NzbDrone.Core.IndexerProxies.Socks5 @@ -26,14 +27,13 @@ namespace NzbDrone.Core.IndexerProxies.Socks5 return null; } - if (Settings.Username.IsNotNullOrWhiteSpace() && Settings.Password.IsNotNullOrWhiteSpace()) - { - request.Proxy = new WebProxy(uri, false, null, new NetworkCredential(Settings.Username, Settings.Password)); - } - else - { - request.Proxy = new WebProxy(uri); - } + request.ProxySettings = new HttpProxySettings(ProxyType.Socks5, + Settings.Host, + Settings.Port, + null, + false, + Settings.Username, + Settings.Password); _logger.Debug("Applying Socks5 Proxy {0} to request {1}", Name, request.Url); From bfa68347e69a10d10fd56c4912615234a07f7c66 Mon Sep 17 00:00:00 2001 From: psylenced <1967906+psylenced@users.noreply.github.com> Date: Tue, 6 Sep 2022 22:59:32 +1000 Subject: [PATCH 0573/2320] Fix: Trace logging postgres cleanse for large json files. --- .../CleanseLogMessageFixture.cs | 17 ++++++++++++++++- .../Instrumentation/CleanseLogMessage.cs | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs index d78034b2f..dc17e834c 100644 --- a/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs +++ b/src/NzbDrone.Common.Test/InstrumentationTests/CleanseLogMessageFixture.cs @@ -98,15 +98,30 @@ namespace NzbDrone.Common.Test.InstrumentationTests // Internal [TestCase(@"[Info] MigrationController: *** Migrating Database=prowlarr-main;Host=postgres14;Username=mySecret;Password=mySecret;Port=5432;Enlist=False ***")] [TestCase("/readarr/signalr/messages/negotiate?access_token=1234530f422f4aacb6b301233210aaaa&negotiateVersion=1")] - + [TestCase(@"[Info] MigrationController: *** Migrating Database=prowlarr-main;Host=postgres14;Username=mySecret;Password=mySecret;Port=5432;token=mySecret;Enlist=False&username=mySecret;mypassword=mySecret;mypass=shouldkeep1;test_token=mySecret;password=123%@%_@!#^#@;use_password=mySecret;get_token=shouldkeep2;usetoken=shouldkeep3;passwrd=mySecret;")] public void should_clean_message(string message) { var cleansedMessage = CleanseLogMessage.Cleanse(message); cleansedMessage.Should().NotContain("mySecret"); + cleansedMessage.Should().NotContain("123%@%_@!#^#@"); cleansedMessage.Should().NotContain("01233210"); } + [TestCase(@"[Info] MigrationController: *** Migrating Database=radarr-main;Host=postgres14;Username=mySecret;Password=mySecret;Port=5432;token=mySecret;Enlist=False&username=mySecret;mypassword=mySecret;mypass=shouldkeep1;test_token=mySecret;password=123%@%_@!#^#@;use_password=mySecret;get_token=shouldkeep2;usetoken=shouldkeep3;passwrd=mySecret;")] + public void should_keep_message(string message) + { + var cleansedMessage = CleanseLogMessage.Cleanse(message); + + cleansedMessage.Should().NotContain("mySecret"); + cleansedMessage.Should().NotContain("123%@%_@!#^#@"); + cleansedMessage.Should().NotContain("01233210"); + + cleansedMessage.Should().Contain("shouldkeep1"); + cleansedMessage.Should().Contain("shouldkeep2"); + cleansedMessage.Should().Contain("shouldkeep3"); + } + [TestCase(@"Some message (from 32.2.3.5 user agent)")] [TestCase(@"Auth-Invalidated ip 32.2.3.5")] [TestCase(@"Auth-Success ip 32.2.3.5")] diff --git a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs index 6170019e9..f4d96a7a7 100644 --- a/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs +++ b/src/NzbDrone.Common/Instrumentation/CleanseLogMessage.cs @@ -18,7 +18,7 @@ namespace NzbDrone.Common.Instrumentation new Regex(@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"/fetch/[a-z0-9]{32}/(?<secret>[a-z0-9]{32})", RegexOptions.Compiled), new Regex(@"getnzb.*?(?<=\?|&)(r)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), - new Regex(@"\b[^=]*?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase), + new Regex(@"\b(\w*)?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"(?<=authkey = "")(?<secret>[^&=]+?)(?="")", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"(?<=beyond-hd\.[a-z]+/api/torrents/)(?<secret>[^&=][a-z0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), From 4cf9fb0e79dcad66fd3c51533b06ac7fa5811fef Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sun, 4 Sep 2022 14:09:18 +0000 Subject: [PATCH 0574/2320] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (462 of 462 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.7% (461 of 462 strings) Translated using Weblate (French) Currently translated at 95.6% (442 of 462 strings) Translated using Weblate (French) Currently translated at 95.2% (440 of 462 strings) Translated using Weblate (German) Currently translated at 99.1% (458 of 462 strings) Translated using Weblate (French) Currently translated at 95.2% (440 of 462 strings) Translated using Weblate (French) Currently translated at 94.8% (438 of 462 strings) Translated using Weblate (Spanish) Currently translated at 77.7% (359 of 462 strings) Co-authored-by: Fradri <adrien.riotte@live.fr> Co-authored-by: Gian Klug <gian.klug@ict-scouts.ch> Co-authored-by: Havok Dan <havokdan@yahoo.com.br> Co-authored-by: Mijail Todorovich <mijailtodorovich+git@gmail.com> Co-authored-by: Thomas Schwery <thomas@schwery.me> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: berrre <zdch6W75@gmail.com> Co-authored-by: cikyw <cikyw@vomoto.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/de.json | 31 +++++++++++++++++-- src/NzbDrone.Core/Localization/Core/es.json | 9 ++++-- src/NzbDrone.Core/Localization/Core/fr.json | 8 +++-- .../Localization/Core/pt_BR.json | 2 +- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/de.json b/src/NzbDrone.Core/Localization/Core/de.json index 3c4312370..2205cc382 100644 --- a/src/NzbDrone.Core/Localization/Core/de.json +++ b/src/NzbDrone.Core/Localization/Core/de.json @@ -397,7 +397,7 @@ "BookSearch": "Buch Suche", "Id": "Id", "IndexerProxies": "Indexer-Proxies", - "IndexerTagsHelpText": "Benutze Tags, um Indexer-Proxies zu spezifizieren oder um Indexer zu organisieren.", + "IndexerTagsHelpText": "Benutze Tags, um Indexer-Proxies zu spezifizieren, mit welchen Apps der Indexer synchronisiert oder um Indexer zu organisieren.", "MovieSearch": "Film Suche", "QueryOptions": "Abfrage-Optionen", "Categories": "Kategorien", @@ -433,5 +433,32 @@ "UnableToLoadIndexers": "Indexer konnten nicht geladen werden", "Yes": "Ja", "InstanceName": "Instanzname", - "InstanceNameHelpText": "Instanzname im Browser-Tab und für Syslog-Anwendungsname" + "InstanceNameHelpText": "Instanzname im Browser-Tab und für Syslog-Anwendungsname", + "SyncProfiles": "Sync-Profile", + "ThemeHelpText": "Prowlarr UI Theme ändern, inspiriert von {0}", + "Duration": "Dauer", + "EditSyncProfile": "Synchronisationsprofil bearbeiten", + "ElapsedTime": "Vergangene Zeit", + "EnabledRedirected": "Aktiviert, Weitergeleitet", + "Ended": "Beendet", + "GrabTitle": "Titel holen", + "LastDuration": "Letzte Dauer", + "LastExecution": "Letzte Ausführung", + "MinimumSeeders": "Mindest-Seeder", + "MinimumSeedersHelpText": "Mindest-Seeder sind benötigt von der App für den Indexer um zu holen", + "NextExecution": "Nächste Ausführung", + "Parameters": "Parameter", + "Queued": "In der Warteschlange", + "Started": "gestartet", + "SyncProfile": "Sync-Profile", + "IndexerSite": "Indexer-Seite", + "MovieSearchTypes": "Film-Suchtypen", + "MusicSearchTypes": "Musik-Suchtypen", + "NotSupported": "Nicht unterstützt", + "RawSearchSupported": "Raw-Suche unterstützt", + "SearchCapabilities": "Suchfähigkeiten", + "AddSyncProfile": "Synchronisationsprofil hinzufügen", + "BookSearchTypes": "Buch-Suchtypen", + "IndexerDetails": "Indexer-Details", + "IndexerName": "Indexer-Name" } diff --git a/src/NzbDrone.Core/Localization/Core/es.json b/src/NzbDrone.Core/Localization/Core/es.json index ceedcd52e..fae62c915 100644 --- a/src/NzbDrone.Core/Localization/Core/es.json +++ b/src/NzbDrone.Core/Localization/Core/es.json @@ -336,8 +336,8 @@ "OnHealthIssue": "En Problema de Salud", "TestAllIndexers": "Comprobar Todos los Indexers", "NotificationTriggersHelpText": "Seleccione qué eventos deben activar esta notificación", - "OnApplicationUpdate": "Al actualizar la aplicación", - "OnApplicationUpdateHelpText": "Al actualizar la aplicación", + "OnApplicationUpdate": "Al Actualizar La Aplicación", + "OnApplicationUpdateHelpText": "Al Actualizar La Aplicación", "AddRemoveOnly": "Sólo añadir y eliminar", "AddedToDownloadClient": "Descarga añadida al cliente", "AddNewIndexer": "Añadir nuevo indexador", @@ -361,5 +361,8 @@ "Notifications": "Notificaciones", "UnableToLoadIndexers": "No se pueden cargar los indexers", "Yes": "si", - "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent proporcionado por la aplicación llamó a la API" + "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent proporcionado por la aplicación llamó a la API", + "InstanceName": "Nombre de Instancia", + "InstanceNameHelpText": "Nombre de instancia en pestaña y para nombre de aplicación en Syslog", + "Database": "Base de Datos" } diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index 7057a5fe9..aa2704977 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -358,7 +358,7 @@ "Description": "Description", "Donations": "Dons", "Enabled": "Activé", - "Grabs": "Saisie", + "Grabs": "Complétés", "Id": "Id", "Presets": "Préconfigurations", "Privacy": "Vie privée", @@ -440,5 +440,9 @@ "MovieSearchTypes": "Types de recherches de films", "MusicSearchTypes": "Type de recherche de musiques", "NotSupported": "Non supporté", - "SearchCapabilities": "Capacités de recherche" + "SearchCapabilities": "Capacités de recherche", + "Duration": "Durée", + "LastDuration": "Dernière durée", + "InstanceName": "Nom de l'instance", + "InstanceNameHelpText": "Nom de l'instance dans l'onglet du navigateur et pour le nom d'application dans Syslog" } diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index c4bd039e1..967283eb5 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -404,7 +404,7 @@ "HistoryCleanupDaysHelpText": "Defina como 0 para desabilitar a limpeza automática", "OnApplicationUpdate": "Ao Atualizar o Aplicativo", "OnApplicationUpdateHelpText": "Ao Atualizar o Aplicativo", - "OnGrab": "Ao Baixar", + "OnGrab": "Em Espera", "OnHealthIssue": "Ao ter problema de integridade", "TestAllIndexers": "Testar todos os indexadores", "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent fornecido pelo aplicativo que chamou a API", From f958c4aefa46be2b51931e753d9422a49b4534c7 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 8 Sep 2022 20:57:06 -0500 Subject: [PATCH 0575/2320] Bump version to 0.4.6 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f58644717..8851dd931 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: testsFolder: './_tests' yarnCacheFolder: $(Pipeline.Workspace)/.yarn nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages - majorVersion: '0.4.5' + majorVersion: '0.4.6' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From eadea745f84a071abdaac18f59afed55fa4f39ec Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 10 Sep 2022 11:00:41 -0500 Subject: [PATCH 0576/2320] Warn on redirect to alt domain when checking if login required --- .../Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index a1c322a23..be7d2a81e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -952,7 +952,7 @@ namespace NzbDrone.Core.Indexers.Cardigann { var errormessage = "Got redirected to another domain. Try changing the indexer URL to " + domainHint + "."; - throw new CardigannException(errormessage); + _logger.Warn(errormessage); } return true; From ae2d9b795b4f53b88a7a35fe8302872ddbc6f717 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 10 Sep 2022 11:24:45 -0500 Subject: [PATCH 0577/2320] Don't reset request Url when calculating RedirectUrl --- src/NzbDrone.Common/Http/HttpResponse.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Common/Http/HttpResponse.cs b/src/NzbDrone.Common/Http/HttpResponse.cs index c92444d76..53459b5fc 100644 --- a/src/NzbDrone.Common/Http/HttpResponse.cs +++ b/src/NzbDrone.Common/Http/HttpResponse.cs @@ -89,13 +89,13 @@ namespace NzbDrone.Common.Http if (match.Success) { - return (Request.Url += new HttpUri(match.Groups[2].Value)).FullUri; + return (Request.Url + new HttpUri(match.Groups[2].Value)).FullUri; } return string.Empty; } - return (Request.Url += new HttpUri(newUrl)).FullUri; + return (Request.Url + new HttpUri(newUrl)).FullUri; } } From 33de7ca7ab2429b5512245098c236f10c2593a25 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 10 Sep 2022 12:49:59 -0500 Subject: [PATCH 0578/2320] Fixed: (MoreThanTv) Parsing issue when download url is null Fixes #1047 --- src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs b/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs index 2db6042c5..0ede86e38 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs @@ -190,6 +190,12 @@ public class MoreThanTVParser : IParseIndexerResponse { // Parse required data var downloadAnchor = torrent.QuerySelector("span a[href^=\"/torrents.php?action=download\"]"); + + if (downloadAnchor == null) + { + continue; + } + var title = downloadAnchor.ParentElement.ParentElement.ParentElement.QuerySelector("a[class=\"overlay_torrent\"]").TextContent.Trim(); title = CleanUpTitle(title); From 68df4394986e66a26413fcfff350239b01cf8a5d Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 12 Sep 2022 21:16:05 -0500 Subject: [PATCH 0579/2320] New: (Avistaz) Freeleech Only Setting #1108 --- .../Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs | 5 +++++ .../Indexers/Definitions/Avistaz/AvistazSettings.cs | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs index 424b5def3..16a099870 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs @@ -34,6 +34,11 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz { "type", categoryMapping.Any() ? categoryMapping.First() : "0" } }; + if (Settings.FreeleechOnly) + { + qc.Add("discount[]", "1"); + } + // resolution filter to improve the search if (!categories.Contains(NewznabStandardCategory.Movies.Id) && !categories.Contains(NewznabStandardCategory.TV.Id) && !categories.Contains(NewznabStandardCategory.Audio.Id)) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazSettings.cs index 2f81274f6..88b8993ca 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazSettings.cs @@ -22,6 +22,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz public AvistazSettings() { Token = ""; + FreeleechOnly = false; } public string Token { get; set; } @@ -35,6 +36,9 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz [FieldDefinition(4, Label = "PID", HelpText = "PID from My Account or My Profile page")] public string Pid { get; set; } + [FieldDefinition(5, Label = "Freeleech Only", HelpText = "Search freeleech only")] + public bool FreeleechOnly { get; set; } + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); From 01e970e1a7317fd845d84cdb12756a1d052356b2 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 12 Sep 2022 21:27:32 -0500 Subject: [PATCH 0580/2320] New: (Avistaz) Genre Search Support Fixes #1097 --- src/NzbDrone.Core/Indexers/Definitions/AvistaZ.cs | 4 ++-- .../Avistaz/AvistazRequestGenerator.cs | 15 ++++++++++----- src/NzbDrone.Core/Indexers/Definitions/CinemaZ.cs | 4 ++-- .../Indexers/Definitions/PrivateHD.cs | 4 ++-- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/AvistaZ.cs b/src/NzbDrone.Core/Indexers/Definitions/AvistaZ.cs index 69721505c..5a5b1ca53 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AvistaZ.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AvistaZ.cs @@ -36,11 +36,11 @@ namespace NzbDrone.Core.Indexers.Definitions { TvSearchParams = new List<TvSearchParam> { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId, TvSearchParam.Genre }, MovieSearchParams = new List<MovieSearchParam> { - MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId + MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId, MovieSearchParam.Genre } }; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs index 16a099870..aceb18885 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs @@ -25,7 +25,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } // hook to adjust the search category - protected virtual List<KeyValuePair<string, string>> GetBasicSearchParameters(int[] categories) + protected virtual List<KeyValuePair<string, string>> GetBasicSearchParameters(int[] categories, string genre) { var categoryMapping = Capabilities.Categories.MapTorznabCapsToTrackers(categories).Distinct().ToList(); var qc = new List<KeyValuePair<string, string>> // NameValueCollection don't support cat[]=19&cat[]=6 @@ -39,6 +39,11 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz qc.Add("discount[]", "1"); } + if (genre.IsNotNullOrWhiteSpace()) + { + qc.Add("tags", genre); + } + // resolution filter to improve the search if (!categories.Contains(NewznabStandardCategory.Movies.Id) && !categories.Contains(NewznabStandardCategory.TV.Id) && !categories.Contains(NewznabStandardCategory.Audio.Id)) @@ -76,7 +81,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) { - var parameters = GetBasicSearchParameters(searchCriteria.Categories); + var parameters = GetBasicSearchParameters(searchCriteria.Categories, searchCriteria.Genre); if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace()) { @@ -98,7 +103,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) { - var parameters = GetBasicSearchParameters(searchCriteria.Categories); + var parameters = GetBasicSearchParameters(searchCriteria.Categories, null); parameters.Add("search", GetSearchTerm(searchCriteria.SanitizedSearchTerm).Trim()); @@ -109,7 +114,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) { - var parameters = GetBasicSearchParameters(searchCriteria.Categories); + var parameters = GetBasicSearchParameters(searchCriteria.Categories, searchCriteria.Genre); if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace()) { @@ -141,7 +146,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) { - var parameters = GetBasicSearchParameters(searchCriteria.Categories); + var parameters = GetBasicSearchParameters(searchCriteria.Categories, null); parameters.Add("search", GetSearchTerm(searchCriteria.SanitizedSearchTerm).Trim()); diff --git a/src/NzbDrone.Core/Indexers/Definitions/CinemaZ.cs b/src/NzbDrone.Core/Indexers/Definitions/CinemaZ.cs index 0f872ee08..37019d1cf 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/CinemaZ.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/CinemaZ.cs @@ -36,11 +36,11 @@ namespace NzbDrone.Core.Indexers.Definitions { TvSearchParams = new List<TvSearchParam> { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.Genre }, MovieSearchParams = new List<MovieSearchParam> { - MovieSearchParam.Q, MovieSearchParam.ImdbId + MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.Genre } }; diff --git a/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs b/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs index b8fd39c10..dc8feb1d2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs @@ -35,11 +35,11 @@ namespace NzbDrone.Core.Indexers.Definitions { TvSearchParams = new List<TvSearchParam> { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId, TvSearchParam.Genre }, MovieSearchParams = new List<MovieSearchParam> { - MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId + MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId, MovieSearchParam.Genre }, MusicSearchParams = new List<MusicSearchParam> { From f68915c5ddc4c61d06dc556a63c8562b1fa3f309 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 12 Sep 2022 22:28:07 -0500 Subject: [PATCH 0581/2320] New: Don't query indexers if they don't support query categories --- .../IndexerSearch/ReleaseSearchService.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs index 20b0bf1e5..faba15d2c 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs @@ -160,6 +160,18 @@ namespace NzbDrone.Core.IndexerSearch .ToList(); } + if (criteriaBase.Categories != null && criteriaBase.Categories.Length > 0) + { + //Only query supported indexers + indexers = indexers.Where(i => i.Capabilities.Categories.SupportedCategories(criteriaBase.Categories).Any()).ToList(); + + if (indexers.Count == 0) + { + _logger.Debug("All provided categories are unsupported by selected indexers: {0}", string.Join(", ", criteriaBase.Categories)); + return new List<ReleaseInfo>(); + } + } + _logger.ProgressInfo("Searching indexer(s): [{0}] for {1}", string.Join(", ", indexers.Select(i => i.Definition.Name).ToList()), criteriaBase.ToString()); var tasks = indexers.Select(x => DispatchIndexer(searchAction, x, criteriaBase)); From d292d086ee6fd33ed1c5ac26deb3247bf0aa8a7f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 12 Sep 2022 22:49:28 -0500 Subject: [PATCH 0582/2320] Prevent query failures on Cardigann Indexers --- src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs index faba15d2c..a760bebba 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs @@ -163,7 +163,7 @@ namespace NzbDrone.Core.IndexerSearch if (criteriaBase.Categories != null && criteriaBase.Categories.Length > 0) { //Only query supported indexers - indexers = indexers.Where(i => i.Capabilities.Categories.SupportedCategories(criteriaBase.Categories).Any()).ToList(); + indexers = indexers.Where(i => ((IndexerDefinition)i.Definition).Capabilities.Categories.SupportedCategories(criteriaBase.Categories).Any()).ToList(); if (indexers.Count == 0) { From 1ed5ed9179352b905ce71067789102ff92a6959d Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Sep 2022 14:55:58 -0500 Subject: [PATCH 0583/2320] Bump version to 0.4.7 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8851dd931..c4a218f82 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: testsFolder: './_tests' yarnCacheFolder: $(Pipeline.Workspace)/.yarn nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages - majorVersion: '0.4.6' + majorVersion: '0.4.7' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From 04e3ed0ffe172d567a4525dbcbea79769698fe1c Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Sep 2022 15:39:09 -0500 Subject: [PATCH 0584/2320] Fixed: (Gazelle) Download fails if out of FL tokens Fixes #1088 --- .../Indexers/Definitions/Gazelle/Gazelle.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs index a30436849..ec9f3fe3a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/Gazelle.cs @@ -80,6 +80,30 @@ namespace NzbDrone.Core.Indexers.Gazelle _logger.Debug("Gazelle authentication succeeded."); } + public override async Task<byte[]> Download(Uri link) + { + var response = await base.Download(link); + + if (response.Length >= 1 + && response[0] != 'd' // simple test for torrent vs HTML content + && link.Query.Contains("usetoken=1")) + { + var html = Encoding.GetString(response); + if (html.Contains("You do not have any freeleech tokens left.") + || html.Contains("You do not have enough freeleech tokens") + || html.Contains("This torrent is too large.") + || html.Contains("You cannot use tokens here")) + { + // download again with usetoken=0 + var requestLinkNew = link.ToString().Replace("usetoken=1", "usetoken=0"); + + response = await base.Download(new Uri(requestLinkNew)); + } + } + + return response; + } + protected override bool CheckIfLoginNeeded(HttpResponse response) { if (response.HasHttpRedirect || (response.Content != null && response.Content.Contains("\"bad credentials\""))) From dcae6dc1513c74afa73c0ea3a10d1a671b391c92 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sat, 17 Sep 2022 16:09:23 +0000 Subject: [PATCH 0585/2320] Translated using Weblate (Slovak) Currently translated at 12.5% (58 of 462 strings) Translated using Weblate (Portuguese) Currently translated at 78.3% (362 of 462 strings) Translated using Weblate (Portuguese) Currently translated at 78.3% (362 of 462 strings) Translated using Weblate (Chinese (Traditional) (zh_TW)) Currently translated at 2.8% (13 of 462 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (462 of 462 strings) Added translation using Weblate (Latvian) Co-authored-by: Dainel Amendoeira <daniel@amendoeira.eu> Co-authored-by: Gylesie <github-anon.dasheens@aleeas.com> Co-authored-by: HiNesslio <chi.lio@shms-mail.ch> Co-authored-by: Oskari Lavinto <olavinto@protonmail.com> Co-authored-by: Weblate <noreply@weblate.org> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sk/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_TW/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/fi.json | 6 +++--- src/NzbDrone.Core/Localization/Core/lv.json | 1 + src/NzbDrone.Core/Localization/Core/pt.json | 7 ++++--- src/NzbDrone.Core/Localization/Core/sk.json | 14 +++++++++++++- src/NzbDrone.Core/Localization/Core/zh_TW.json | 2 +- 5 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 src/NzbDrone.Core/Localization/Core/lv.json diff --git a/src/NzbDrone.Core/Localization/Core/fi.json b/src/NzbDrone.Core/Localization/Core/fi.json index e9887452b..385a7767b 100644 --- a/src/NzbDrone.Core/Localization/Core/fi.json +++ b/src/NzbDrone.Core/Localization/Core/fi.json @@ -55,7 +55,7 @@ "UpdateCheckStartupTranslocationMessage": "Päivitystä ei voi asentaa, koska käynnistyskansio '{0}' sijaitsee 'App Translocation' -kansiossa.", "UpdateCheckUINotWritableMessage": "Päivitystä ei voi asentaa, koska käyttäjällä '{1}' ei ole kirjoitusoikeutta käyttöliittymäkansioon '{0}'.", "UpdateMechanismHelpText": "Käytä Prowlarrin sisäänrakennettua päivitystoimintoa tai omaa komentosarjaasi.", - "ApplyTagsHelpTexts3": "– 'Poista' ainoastaan syötetyt tunnisteet", + "ApplyTagsHelpTexts3": "- \"Poista\" tyhjentää syötetyt tunnisteet.", "Enable": "Käytä", "UI": "Käyttöliittymä", "UrlBaseHelpText": "Käänteisen välityspalvelimen tuki (esim. 'http://[host]:[port]/[urlBase]'). Käytä oletusta jättämällä tyhjäksi.", @@ -71,7 +71,7 @@ "Username": "Käyttäjätunnus", "YesCancel": "Kyllä, peruuta", "NoTagsHaveBeenAddedYet": "Tunnisteita ei ole vielä lisätty.", - "ApplyTags": "Toimenpide tunnisteille", + "ApplyTags": "Tunnistetoimenpide", "Authentication": "Todennus", "AuthenticationMethodHelpText": "Vaadi käyttäjätunnus ja salasana.", "BindAddressHelpText": "Toimiva IPv4-osoite tai jokerimerkkinä '*' (tähti) kaikille yhteyksille.", @@ -224,7 +224,7 @@ "Wiki": "Wiki", "ApplyTagsHelpTexts1": "Tunnisteisiin kohdistettavat toimenpiteet:", "ApplyTagsHelpTexts2": "– 'Lisää' syötetyt tunnisteet aiempiin tunnisteisiin", - "ApplyTagsHelpTexts4": "– 'Korvaa' kaikki aiemmat tunnisteet tai poista kaikki tunnisteet jättämällä tyhjäksi", + "ApplyTagsHelpTexts4": "- \"Korvaa\" nykyiset tunnisteet syötetyillä tai tyhjennä kaikki tunnisteet jättämällä tyhjäksi.", "Port": "Portti", "AreYouSureYouWantToResetYourAPIKey": "Haluatko varmasti uudistaa API-avaimesi?", "Automatic": "Automaattinen", diff --git a/src/NzbDrone.Core/Localization/Core/lv.json b/src/NzbDrone.Core/Localization/Core/lv.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/src/NzbDrone.Core/Localization/Core/lv.json @@ -0,0 +1 @@ +{} diff --git a/src/NzbDrone.Core/Localization/Core/pt.json b/src/NzbDrone.Core/Localization/Core/pt.json index ab5f36be1..3e43d9d4d 100644 --- a/src/NzbDrone.Core/Localization/Core/pt.json +++ b/src/NzbDrone.Core/Localization/Core/pt.json @@ -153,7 +153,7 @@ "NetCore": ".NET", "Mode": "Modo", "Mechanism": "Mecanismo", - "Logs": "Logs", + "Logs": "Registos", "LogLevel": "Nível de log", "Interval": "Intervalo", "IndexerFlags": "Sinalizadores do indexador", @@ -392,7 +392,7 @@ "UserAgentProvidedByTheAppThatCalledTheAPI": "Par Utilizador-Agente fornecido pela aplicação que chamou a API", "OnApplicationUpdate": "Quando a aplicação atualizar", "OnApplicationUpdateHelpText": "Quando a aplicação atualizar", - "Database": "base de dados", + "Database": "Base de dados", "HistoryCleanupDaysHelpTextWarning": "Ficheiros na reciclagem serão eliminados automaticamente após o número de dias selecionado", "Application": "Aplicações", "Link": "Ligações", @@ -401,5 +401,6 @@ "UnableToLoadIndexers": "Não foi possível carregar os indexadores", "Yes": "Sim", "GrabReleases": "Capturar versão", - "InstanceName": "Nome da Instancia" + "InstanceName": "Nome da Instancia", + "InstanceNameHelpText": "Nome da instância na aba e nome da aplicação para Syslog" } diff --git a/src/NzbDrone.Core/Localization/Core/sk.json b/src/NzbDrone.Core/Localization/Core/sk.json index ac09f2be5..9dcf3e5e4 100644 --- a/src/NzbDrone.Core/Localization/Core/sk.json +++ b/src/NzbDrone.Core/Localization/Core/sk.json @@ -44,5 +44,17 @@ "AuthenticationMethodHelpText": "Vyžadovať používateľské meno a heslo pre prístup k Radarru", "BackupFolderHelpText": "Relatívne cesty budú v priečinku AppData Radarru", "BranchUpdate": "Vetva, ktorá sa má použiť k aktualizácií Radarru", - "DeleteDownloadClientMessageText": "Naozaj chcete zmazať značku formátu {0} ?" + "DeleteDownloadClientMessageText": "Naozaj chcete zmazať značku formátu {0} ?", + "ChangeHasNotBeenSavedYet": "Zmena ešte nebola uložená", + "Clear": "Vymazať", + "Close": "Zatvoriť", + "CertificateValidation": "Overenie certifikátu", + "CloneProfile": "Klonovať profil", + "BindAddress": "Viazať adresu", + "CancelPendingTask": "Naozaj chcete zrušiť túto prebiehajúcu úlohu?", + "ClientPriority": "Priorita klienta", + "CloseCurrentModal": "Zatvoriť aktuálne okno", + "Columns": "Stĺpce", + "Component": "Komponent", + "ConnectionLost": "Spojenie prerušené" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_TW.json b/src/NzbDrone.Core/Localization/Core/zh_TW.json index 85f52e977..560875121 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_TW.json +++ b/src/NzbDrone.Core/Localization/Core/zh_TW.json @@ -1,7 +1,7 @@ { "About": "關於", "Add": "新增", - "Added": "以新增", + "Added": "已新增", "Actions": "執行", "Age": "年齡", "AddIndexer": "新增索引", From 06a26b5c871b6d27105aa510d1431c941b695116 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Sep 2022 15:52:59 -0500 Subject: [PATCH 0586/2320] Fixed: (RarBG) Don't disable indexer on temp rate limit Fixes #1027 --- src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs index 667e532a4..690c82d6d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs @@ -40,9 +40,10 @@ namespace NzbDrone.Core.Indexers.Rarbg if (jsonResponse.Resource.error_code.HasValue) { if (jsonResponse.Resource.error_code == 20 || jsonResponse.Resource.error_code == 8 - || jsonResponse.Resource.error_code == 9 || jsonResponse.Resource.error_code == 10) + || jsonResponse.Resource.error_code == 9 || jsonResponse.Resource.error_code == 10 + || jsonResponse.Resource.error_code == 5) { - // No results or imdbid not found + // No results, rate limit, or imdbid not found return results; } From 0593ca6b9ef84ca160f31c3eba3deac9e175fe13 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Sep 2022 21:40:32 -0500 Subject: [PATCH 0587/2320] Bump DryIoc to 5.2.2 --- src/NzbDrone.Common/Prowlarr.Common.csproj | 2 +- src/NzbDrone.Host/Prowlarr.Host.csproj | 4 ++-- src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs | 2 +- src/NzbDrone.Update/Prowlarr.Update.csproj | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index e121d6480..e08ac3304 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -4,7 +4,7 @@ <DefineConstants Condition="'$(RuntimeIdentifier)' == 'linux-musl-x64' or '$(RuntimeIdentifier)' == 'linux-musl-arm64'">ISMUSL</DefineConstants> </PropertyGroup> <ItemGroup> - <PackageReference Include="DryIoc.dll" Version="4.8.8" /> + <PackageReference Include="DryIoc.dll" Version="5.2.2" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> diff --git a/src/NzbDrone.Host/Prowlarr.Host.csproj b/src/NzbDrone.Host/Prowlarr.Host.csproj index 2d46ee94d..ff3ba4a5f 100644 --- a/src/NzbDrone.Host/Prowlarr.Host.csproj +++ b/src/NzbDrone.Host/Prowlarr.Host.csproj @@ -8,8 +8,8 @@ <PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.3.1" /> - <PackageReference Include="DryIoc.dll" Version="4.8.8" /> - <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="5.1.0" /> + <PackageReference Include="DryIoc.dll" Version="5.2.2" /> + <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="6.1.0" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Common\Prowlarr.Common.csproj" /> diff --git a/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs b/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs index c32a06f2a..7414a407a 100644 --- a/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs +++ b/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs @@ -100,7 +100,7 @@ namespace NzbDrone.Test.Common.AutoMoq if (serviceType.IsInterface || serviceType.IsAbstract) { var mockType = typeof(Mock<>).MakeGenericType(serviceType); - var mockFactory = new DelegateFactory(r => + var mockFactory = DelegateFactory.Of(r => { var mock = (Mock)r.Resolve(mockType); SetMock(serviceType, mock); diff --git a/src/NzbDrone.Update/Prowlarr.Update.csproj b/src/NzbDrone.Update/Prowlarr.Update.csproj index ba6785fc3..7af53f202 100644 --- a/src/NzbDrone.Update/Prowlarr.Update.csproj +++ b/src/NzbDrone.Update/Prowlarr.Update.csproj @@ -4,8 +4,8 @@ <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> - <PackageReference Include="DryIoc.dll" Version="4.8.8" /> - <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="5.1.0" /> + <PackageReference Include="DryIoc.dll" Version="5.2.2" /> + <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="6.1.0" /> <PackageReference Include="NLog" Version="5.0.1" /> </ItemGroup> <ItemGroup> From 7fa0a2b33c2659ffae20a215aab150dbfa1f1c59 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Sep 2022 21:43:06 -0500 Subject: [PATCH 0588/2320] Bump Swashbuckle to 6.4.0 --- src/NzbDrone.Host/Prowlarr.Host.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Host/Prowlarr.Host.csproj b/src/NzbDrone.Host/Prowlarr.Host.csproj index ff3ba4a5f..04faad891 100644 --- a/src/NzbDrone.Host/Prowlarr.Host.csproj +++ b/src/NzbDrone.Host/Prowlarr.Host.csproj @@ -7,7 +7,7 @@ <PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> - <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.3.1" /> + <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.4.0" /> <PackageReference Include="DryIoc.dll" Version="5.2.2" /> <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="6.1.0" /> </ItemGroup> From 59e5b5bd527c79da6d66b17dc69686cef73acc1f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Sep 2022 21:45:10 -0500 Subject: [PATCH 0589/2320] Set PooledConnectionLifetime to 10 minutes Setting PooledConnectinLifetime to a defined number will ensure we don't run into DNS refresh issues --- src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs index ea4b3790f..27688234b 100644 --- a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs +++ b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs @@ -174,6 +174,7 @@ namespace NzbDrone.Common.Http.Dispatchers PreAuthenticate = true, MaxConnectionsPerServer = 12, ConnectCallback = onConnect, + PooledConnectionLifetime = TimeSpan.FromMinutes(10), SslOptions = new SslClientAuthenticationOptions { RemoteCertificateValidationCallback = _certificateValidationService.ShouldByPassValidationError From 99816bfd36b19510c9fc103adcfa5ee7cf29525d Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 24 Sep 2022 20:24:17 -0500 Subject: [PATCH 0590/2320] Fix test error due to DryIOC update --- src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs b/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs index 7414a407a..945dd3aae 100644 --- a/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs +++ b/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs @@ -96,6 +96,11 @@ namespace NzbDrone.Test.Common.AutoMoq return null; } + if (serviceType == typeof(System.Text.Json.Serialization.JsonConverter)) + { + return null; + } + // get the Mock object for the abstract class or interface if (serviceType.IsInterface || serviceType.IsAbstract) { From 4137193a606d212efe09c269e7d56f97af1aae0b Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 25 Sep 2022 10:08:12 -0500 Subject: [PATCH 0591/2320] Fixed: (Avistaz) FL Only should be checkbox --- .../Indexers/Definitions/Avistaz/AvistazSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazSettings.cs index 88b8993ca..4fd19af5c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazSettings.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz [FieldDefinition(4, Label = "PID", HelpText = "PID from My Account or My Profile page")] public string Pid { get; set; } - [FieldDefinition(5, Label = "Freeleech Only", HelpText = "Search freeleech only")] + [FieldDefinition(5, Label = "Freeleech Only", Type = FieldType.Checkbox, HelpText = "Search freeleech only")] public bool FreeleechOnly { get; set; } public override NzbDroneValidationResult Validate() From 791592927cf6a7d2038e6835aa98f5aef22c88c8 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 25 Sep 2022 12:13:49 -0500 Subject: [PATCH 0592/2320] Purge old PTP Radarr check --- .../HealthCheck/Checks/PTPOldSettingsCheck.cs | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 src/NzbDrone.Core/HealthCheck/Checks/PTPOldSettingsCheck.cs diff --git a/src/NzbDrone.Core/HealthCheck/Checks/PTPOldSettingsCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/PTPOldSettingsCheck.cs deleted file mode 100644 index 084c7c1da..000000000 --- a/src/NzbDrone.Core/HealthCheck/Checks/PTPOldSettingsCheck.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Linq; -using NzbDrone.Common.Extensions; -using NzbDrone.Core.Indexers; -using NzbDrone.Core.Indexers.PassThePopcorn; -using NzbDrone.Core.Localization; - -namespace NzbDrone.Core.HealthCheck.Checks -{ - public class PTPOldSettingsCheck : HealthCheckBase - { - private readonly IIndexerFactory _indexerFactory; - - public PTPOldSettingsCheck(IIndexerFactory indexerFactory, ILocalizationService localizationService) - : base(localizationService) - { - _indexerFactory = indexerFactory; - } - - public override HealthCheck Check() - { - var ptpIndexers = _indexerFactory.All().Where(i => i.Settings.GetType() == typeof(PassThePopcornSettings)); - - var ptpIndexerOldSettings = ptpIndexers - .Where(i => (i.Settings as PassThePopcornSettings).APIUser.IsNullOrWhiteSpace()).Select(i => i.Name); - - if (ptpIndexerOldSettings.Any()) - { - return new HealthCheck(GetType(), HealthCheckResult.Warning, string.Format(_localizationService.GetLocalizedString("PtpOldSettingsCheckMessage"), string.Join(", ", ptpIndexerOldSettings))); - } - - return new HealthCheck(GetType()); - } - } -} From 25217c0ee8b150b5278382f73542a87796fd976e Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 25 Sep 2022 20:44:26 -0500 Subject: [PATCH 0593/2320] Fixed: TypeError on Keyup in Firefox for IndexerIndex --- frontend/src/Indexer/Index/IndexerIndex.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Indexer/Index/IndexerIndex.js b/frontend/src/Indexer/Index/IndexerIndex.js index 841bc1c00..e8057147c 100644 --- a/frontend/src/Indexer/Index/IndexerIndex.js +++ b/frontend/src/Indexer/Index/IndexerIndex.js @@ -221,7 +221,7 @@ class IndexerIndex extends Component { onKeyUp = (event) => { const jumpBarItems = this.state.jumpBarItems.order; - if (event.path.length === 4) { + if (event.composedPath && event.composedPath().length === 4) { if (event.keyCode === keyCodes.HOME && event.ctrlKey) { this.setState({ jumpToCharacter: jumpBarItems[0] }); } From 0a111e7572963fd5cbbe9c3cdc91f2d29a2e4127 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 26 Sep 2022 21:13:57 -0500 Subject: [PATCH 0594/2320] Fixed: (Cardigann) Search path redirect Fixes #1102 --- .../Cardigann/CardigannRequestGenerator.cs | 12 +++++++----- .../Definitions/Newznab/NewznabRequestGenerator.cs | 6 +++++- src/NzbDrone.Core/Indexers/HttpIndexerBase.cs | 2 -- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index be7d2a81e..46d951b95 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -945,6 +945,11 @@ namespace NzbDrone.Core.Indexers.Cardigann public bool CheckIfLoginIsNeeded(HttpResponse response) { + if (_definition.Login == null || _definition.Login.Test == null) + { + return false; + } + if (response.HasHttpRedirect) { var domainHint = GetRedirectDomainHint(response); @@ -958,11 +963,6 @@ namespace NzbDrone.Core.Indexers.Cardigann return true; } - if (_definition.Login == null || _definition.Login.Test == null) - { - return false; - } - if (response.HasHttpError) { return true; @@ -1124,6 +1124,8 @@ namespace NzbDrone.Core.Indexers.Cardigann var request = new CardigannRequest(requestbuilder.SetEncoding(_encoding).Build(), variables, searchPath); + request.HttpRequest.AllowAutoRedirect = searchPath.Followredirect; + yield return request; } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs index 08a05debb..4ca28f18e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; +using DryIoc; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.IndexerSearch.Definitions; @@ -268,7 +269,10 @@ namespace NzbDrone.Core.Indexers.Newznab parameters.Add("offset", searchCriteria.Offset.ToString()); } - yield return new IndexerRequest(string.Format("{0}&{1}", baseUrl, parameters.GetQueryString()), HttpAccept.Rss); + var request = new IndexerRequest(string.Format("{0}&{1}", baseUrl, parameters.GetQueryString()), HttpAccept.Rss); + request.HttpRequest.AllowAutoRedirect = true; + + yield return request; } private static string NewsnabifyTitle(string title) diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index 802803997..7ab4417a4 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -355,8 +355,6 @@ namespace NzbDrone.Core.Indexers request.HttpRequest.LogResponseContent = true; } - request.HttpRequest.AllowAutoRedirect = FollowRedirect; - var originalUrl = request.Url; Cookies = GetCookies(); From 2e85a21576ecae4bb29fd59cb96d0d3e58a32fe5 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 29 Sep 2022 20:14:18 -0500 Subject: [PATCH 0595/2320] Fixed: (GazelleGames) Serialization error on empty response Fixes #1137 --- .../Indexers/GazelleGames/recentfeed-empty.json | 4 ++++ .../GazelleGamesTests/GazelleGamesFixture.cs | 15 +++++++++++++++ .../Indexers/Definitions/GazelleGames.cs | 15 +++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 src/NzbDrone.Core.Test/Files/Indexers/GazelleGames/recentfeed-empty.json diff --git a/src/NzbDrone.Core.Test/Files/Indexers/GazelleGames/recentfeed-empty.json b/src/NzbDrone.Core.Test/Files/Indexers/GazelleGames/recentfeed-empty.json new file mode 100644 index 000000000..7230cc0e0 --- /dev/null +++ b/src/NzbDrone.Core.Test/Files/Indexers/GazelleGames/recentfeed-empty.json @@ -0,0 +1,4 @@ +{ + "status": "success", + "response": [] +} \ No newline at end of file diff --git a/src/NzbDrone.Core.Test/IndexerTests/GazelleGamesTests/GazelleGamesFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/GazelleGamesTests/GazelleGamesFixture.cs index dd3d7f7ae..e21852bf3 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/GazelleGamesTests/GazelleGamesFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/GazelleGamesTests/GazelleGamesFixture.cs @@ -12,6 +12,7 @@ using NzbDrone.Core.Indexers.Definitions; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Test.Framework; +using NzbDrone.Test.Common; namespace NzbDrone.Core.Test.IndexerTests.GazelleGamesTests { @@ -64,5 +65,19 @@ namespace NzbDrone.Core.Test.IndexerTests.GazelleGamesTests torrentInfo.DownloadVolumeFactor.Should().Be(1); torrentInfo.UploadVolumeFactor.Should().Be(1); } + + [Test] + public async Task should_not_error_if_empty_response() + { + var recentFeed = ReadAllText(@"Files/Indexers/GazelleGames/recentfeed-empty.json"); + + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader { { "Content-Type", "application/json" } }, new CookieCollection(), recentFeed))); + + var releases = (await Subject.Fetch(new BasicSearchCriteria { Categories = new int[] { 2000 } })).Releases; + + releases.Should().HaveCount(0); + } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs b/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs index d94a4addd..19afcbfd1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs @@ -341,7 +341,18 @@ namespace NzbDrone.Core.Indexers.Definitions return torrentInfos; } - foreach (var result in jsonResponse.Resource.Response) + Dictionary<string, GazelleGamesGroup> response; + + try + { + response = ((JObject)jsonResponse.Resource.Response).ToObject<Dictionary<string, GazelleGamesGroup>>(); + } + catch + { + return torrentInfos; + } + + foreach (var result in response) { Dictionary<string, GazelleGamesTorrent> torrents; @@ -455,7 +466,7 @@ namespace NzbDrone.Core.Indexers.Definitions public class GazelleGamesResponse { public string Status { get; set; } - public Dictionary<string, GazelleGamesGroup> Response { get; set; } + public object Response { get; set; } } public class GazelleGamesGroup From e4ffa1873ef827ed36bde77d8329c8cf8b5d0755 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 29 Sep 2022 22:13:21 -0500 Subject: [PATCH 0596/2320] Fixed: Definition not updating if local file is missing --- .../IndexerVersions/IndexerDefinitionUpdateService.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index 408959075..bbb854ec5 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -281,6 +281,7 @@ namespace NzbDrone.Core.IndexerVersions private void UpdateLocalDefinitions() { var startupFolder = _appFolderInfo.AppDataFolder; + var definitionFolder = Path.Combine(startupFolder, "Definitions"); var request = new HttpRequest($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}"); var response = _httpClient.Get<List<CardigannMetaDefinition>>(request); @@ -291,13 +292,16 @@ namespace NzbDrone.Core.IndexerVersions { EnsureDefinitionsFolder(); + var directoryInfo = new DirectoryInfo(definitionFolder); + var files = directoryInfo.GetFiles($"*.yml", SearchOption.TopDirectoryOnly).Select(f => Path.GetFileNameWithoutExtension(f.Name)); + foreach (var def in response.Resource) { try { - var saveFile = Path.Combine(startupFolder, "Definitions", $"{def.File}.yml"); + var saveFile = Path.Combine(definitionFolder, $"{def.File}.yml"); - if (currentDefs.TryGetValue(def.Id, out var defSha) && defSha == def.Sha) + if (currentDefs.TryGetValue(def.Id, out var defSha) && defSha == def.Sha && files.Any(x => x == def.File)) { _logger.Trace("Indexer already up to date: {0}", def.File); From 3547028b96e0eb59e763e6e890b399dcde10016a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 25 Sep 2022 12:53:05 -0500 Subject: [PATCH 0597/2320] Bump YamlDotNet to 12.0.1 --- src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj | 2 +- src/NzbDrone.Core/Prowlarr.Core.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj index 50edb2d4c..109a8badb 100644 --- a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj @@ -6,7 +6,7 @@ <PackageReference Include="Dapper" Version="2.0.123" /> <PackageReference Include="NBuilder" Version="6.1.0" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> - <PackageReference Include="YamlDotNet" Version="11.2.1" /> + <PackageReference Include="YamlDotNet" Version="12.0.1" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" /> diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index fae223961..2e081ce26 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -21,7 +21,7 @@ <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> <PackageReference Include="System.Text.Json" Version="6.0.5" /> <PackageReference Include="MonoTorrent" Version="2.0.5" /> - <PackageReference Include="YamlDotNet" Version="11.2.1" /> + <PackageReference Include="YamlDotNet" Version="12.0.1" /> <PackageReference Include="AngleSharp" Version="0.17.1" /> </ItemGroup> <ItemGroup> From 148d8ee249368da253161594348a097f369a8b76 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 25 Sep 2022 19:37:15 -0500 Subject: [PATCH 0598/2320] Bump Sentry to 3.21.0 --- src/NzbDrone.Common/Prowlarr.Common.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index e08ac3304..90c255d24 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -10,7 +10,7 @@ <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="NLog" Version="5.0.1" /> <PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" /> - <PackageReference Include="Sentry" Version="3.19.0" /> + <PackageReference Include="Sentry" Version="3.21.0" /> <PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" /> <PackageReference Include="SharpZipLib" Version="1.3.3" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" /> From f56a13a375d427a06cfc2fef88ea20da9160c286 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 26 Sep 2022 13:42:36 -0500 Subject: [PATCH 0599/2320] Bump Mailkit to 3.4.1 --- src/NzbDrone.Core/Prowlarr.Core.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index 2e081ce26..fae8e0d2e 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -6,7 +6,7 @@ <PackageReference Include="AngleSharp.Xml" Version="0.17.0" /> <PackageReference Include="Dapper" Version="2.0.123" /> <PackageReference Include="FluentMigrator.Runner" Version="3.3.2" /> - <PackageReference Include="MailKit" Version="3.3.0" /> + <PackageReference Include="MailKit" Version="3.4.1" /> <PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" /> <PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" /> <PackageReference Include="Npgsql" Version="5.0.11" /> From c29735741cc327dddaabc7ead8ea3b4252e8c27f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 29 Sep 2022 22:46:27 -0500 Subject: [PATCH 0600/2320] Optimize Indexer updates (v2) --- .../IndexerDefinitionUpdateService.cs | 46 ++++++------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs index bbb854ec5..e8e799ca9 100644 --- a/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs +++ b/src/NzbDrone.Core/IndexerVersions/IndexerDefinitionUpdateService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.Linq; using NLog; using NzbDrone.Common.Cache; @@ -281,49 +282,30 @@ namespace NzbDrone.Core.IndexerVersions private void UpdateLocalDefinitions() { var startupFolder = _appFolderInfo.AppDataFolder; - var definitionFolder = Path.Combine(startupFolder, "Definitions"); - - var request = new HttpRequest($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}"); - var response = _httpClient.Get<List<CardigannMetaDefinition>>(request); - - var currentDefs = _versionService.All().ToDictionary(x => x.DefinitionId, x => x.Sha); try { EnsureDefinitionsFolder(); - var directoryInfo = new DirectoryInfo(definitionFolder); - var files = directoryInfo.GetFiles($"*.yml", SearchOption.TopDirectoryOnly).Select(f => Path.GetFileNameWithoutExtension(f.Name)); + var definitionsFolder = Path.Combine(startupFolder, "Definitions"); + var saveFile = Path.Combine(definitionsFolder, $"indexers.zip"); - foreach (var def in response.Resource) + _httpClient.DownloadFile($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}/package.zip", saveFile); + + using (ZipArchive archive = ZipFile.OpenRead(saveFile)) { - try - { - var saveFile = Path.Combine(definitionFolder, $"{def.File}.yml"); - - if (currentDefs.TryGetValue(def.Id, out var defSha) && defSha == def.Sha && files.Any(x => x == def.File)) - { - _logger.Trace("Indexer already up to date: {0}", def.File); - - continue; - } - - _httpClient.DownloadFile($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}/{def.File}", saveFile); - - _versionService.Upsert(new IndexerDefinitionVersion { Sha = def.Sha, DefinitionId = def.Id, File = def.File, LastUpdated = DateTime.UtcNow }); - - _cache.Remove(def.File); - _logger.Debug("Updated definition: {0}", def.File); - } - catch (Exception ex) - { - _logger.Error("Definition download failed: {0}, {1}", def.File, ex.Message); - } + archive.ExtractToDirectory(definitionsFolder, true); } + + _diskProvider.DeleteFile(saveFile); + + _cache.Clear(); + + _logger.Debug("Updated indexer definitions"); } catch (Exception ex) { - _logger.Error(ex, "Definition download failed, error creating definitions folder in {0}", startupFolder); + _logger.Error(ex, "Definition update failed"); } } } From e7b1380b851a75e342499dfef2580ef5078a673c Mon Sep 17 00:00:00 2001 From: h96kikh6 <114868118+h96kikh6@users.noreply.github.com> Date: Sun, 2 Oct 2022 17:45:55 +0200 Subject: [PATCH 0601/2320] Fixed: (Indexer) HDSpace - Added new categories Added new categories: 45 - HDTV 2160 -> Prowlarr: Movies/UHD (2045), 46 - Movies 2160 -> Prowlarr: TV/UHD (5045), 47 - Doc 2160 -> Prowlarr: TV/Documentary (5080), 48 - Animation 2160 -> Prowlarr: TV/Anime (5070), 49 - XXX 2160 -> Prowlarr: XXX/UHD (6045) --- src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs b/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs index 14293fbd0..544390727 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/HDSpace.cs @@ -124,19 +124,24 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.MoviesBluRay, "Movie / Blu-ray"); caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.MoviesHD, "Movie / 1080p"); caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.MoviesHD, "Movie / 720p"); + caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.MoviesUHD, "Movie / 2160p"); caps.Categories.AddCategoryMapping(40, NewznabStandardCategory.MoviesHD, "Movie / Remux"); caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.MoviesHD, "Movie / HD-DVD"); caps.Categories.AddCategoryMapping(41, NewznabStandardCategory.MoviesUHD, "Movie / 4K UHD"); caps.Categories.AddCategoryMapping(21, NewznabStandardCategory.TVHD, "TV Show / 720p HDTV"); caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.TVHD, "TV Show / 1080p HDTV"); + caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.TVUHD, "TV Show / 2160p HDTV"); caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.TVDocumentary, "Documentary / 720p"); caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.TVDocumentary, "Documentary / 1080p"); + caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.TVDocumentary, "Documentary / 2160p"); caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.TVAnime, "Animation / 720p"); caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.TVAnime, "Animation / 1080p"); + caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.TVAnime, "Animation / 2160p"); caps.Categories.AddCategoryMapping(30, NewznabStandardCategory.AudioLossless, "Music / HQ Audio"); caps.Categories.AddCategoryMapping(31, NewznabStandardCategory.AudioVideo, "Music / Videos"); caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.XXX, "XXX / 720p"); caps.Categories.AddCategoryMapping(34, NewznabStandardCategory.XXX, "XXX / 1080p"); + caps.Categories.AddCategoryMapping(49, NewznabStandardCategory.XXX, "XXX / 2160p"); caps.Categories.AddCategoryMapping(36, NewznabStandardCategory.MoviesOther, "Trailers"); caps.Categories.AddCategoryMapping(37, NewznabStandardCategory.PC, "Software"); caps.Categories.AddCategoryMapping(38, NewznabStandardCategory.Other, "Others"); From be430732f583bc4a497b93acd5a2f529d7e2d213 Mon Sep 17 00:00:00 2001 From: Yukine <devyukine@gmx.de> Date: Sun, 2 Oct 2022 11:46:12 +0200 Subject: [PATCH 0602/2320] Fixed: (GreatPosterWall) move imdb id search to searchstr query param --- .../Gazelle/GazelleRequestGenerator.cs | 4 ++-- .../Indexers/Definitions/GreatPosterWall.cs | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs index 67ad1987d..641309a6f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Indexers.Gazelle return pageableRequests; } - private IEnumerable<IndexerRequest> GetRequest(string searchParameters) + protected IEnumerable<IndexerRequest> GetRequest(string searchParameters) { var filter = ""; if (searchParameters == null) @@ -45,7 +45,7 @@ namespace NzbDrone.Core.Indexers.Gazelle yield return request; } - private string GetBasicSearchParameters(string searchTerm, int[] categories) + protected string GetBasicSearchParameters(string searchTerm, int[] categories) { var searchString = GetSearchTerm(searchTerm); diff --git a/src/NzbDrone.Core/Indexers/Definitions/GreatPosterWall.cs b/src/NzbDrone.Core/Indexers/Definitions/GreatPosterWall.cs index bdee19c3f..d0a4d7a2d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/GreatPosterWall.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/GreatPosterWall.cs @@ -8,6 +8,7 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Gazelle; +using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; @@ -61,6 +62,20 @@ public class GreatPosterWall : Gazelle.Gazelle public class GreatPosterWallRequestGenerator : GazelleRequestGenerator { protected override bool ImdbInTags => false; + + public new IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + { + var parameters = GetBasicSearchParameters(searchCriteria.SearchTerm, searchCriteria.Categories); + + if (searchCriteria.ImdbId != null) + { + parameters += string.Format("&searchstr={0}", searchCriteria.FullImdbId); + } + + var pageableRequests = new IndexerPageableRequestChain(); + pageableRequests.Add(GetRequest(parameters)); + return pageableRequests; + } } public class GreatPosterWallParser : GazelleParser From 8797bb7d1c98ddc18507a6b6a9c02032983d64a2 Mon Sep 17 00:00:00 2001 From: Yukine <devyukine@gmx.de> Date: Sun, 2 Oct 2022 11:47:40 +0200 Subject: [PATCH 0603/2320] Remove unused Gazelle legacy code --- .../Definitions/Gazelle/GazelleRequestGenerator.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs index 641309a6f..e0627020f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs @@ -32,14 +32,9 @@ namespace NzbDrone.Core.Indexers.Gazelle protected IEnumerable<IndexerRequest> GetRequest(string searchParameters) { - var filter = ""; - if (searchParameters == null) - { - } - var request = new IndexerRequest( - $"{APIUrl}?{searchParameters}{filter}", + $"{APIUrl}?{searchParameters}", HttpAccept.Json); yield return request; From b8ca28d955addceb97c0c077d5a8085634d984f0 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 8 Oct 2022 15:31:51 -0500 Subject: [PATCH 0604/2320] Fixed: Explicitly forbid redirects on Gazelle search requests Fixes #1144 --- .../Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs | 2 ++ src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs | 2 ++ src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs | 2 ++ src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs | 2 ++ 4 files changed, 8 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs index e0627020f..7b6885dbd 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs @@ -37,6 +37,8 @@ namespace NzbDrone.Core.Indexers.Gazelle $"{APIUrl}?{searchParameters}", HttpAccept.Json); + request.HttpRequest.AllowAutoRedirect = false; + yield return request; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs b/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs index 8e9198486..ec0c22cf6 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PreToMe.cs @@ -255,6 +255,8 @@ namespace NzbDrone.Core.Indexers.Definitions var request = new IndexerRequest(searchUrl, HttpAccept.Html); + request.HttpRequest.AllowAutoRedirect = false; + yield return request; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs b/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs index 8c0268708..35beb5a30 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RevolutionTT.cs @@ -194,6 +194,8 @@ namespace NzbDrone.Core.Indexers.Definitions var request = new IndexerRequest(searchUrl, HttpAccept.Html); + request.HttpRequest.AllowAutoRedirect = false; + yield return request; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs index 054acbda3..fbd509b19 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RuTracker.cs @@ -1480,6 +1480,8 @@ namespace NzbDrone.Core.Indexers.Definitions var request = new IndexerRequest(searchUrl, HttpAccept.Html); + request.HttpRequest.AllowAutoRedirect = false; + yield return request; } From 3b7c59e9bbfac2b33004fea8840b977066f5c3f7 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 8 Oct 2022 18:11:22 -0500 Subject: [PATCH 0605/2320] Fixed: (Rarbg) More reliable token handling and retry Fixes #1148 --- .../Indexers/Definitions/Rarbg/Rarbg.cs | 58 +++++++++++++++++++ .../Indexers/Definitions/Rarbg/RarbgParser.cs | 5 +- .../Rarbg/RarbgRequestGenerator.cs | 32 +++++----- .../Definitions/Rarbg/RarbgResponse.cs | 1 + .../Definitions/Rarbg/RarbgTokenProvider.cs | 15 +++-- 5 files changed, 85 insertions(+), 26 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs index 4fc04fbf4..3f3befd76 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs @@ -1,6 +1,11 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Net.Http.Json; +using System.Threading.Tasks; +using System.Web; +using Newtonsoft.Json; using NLog; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; @@ -8,7 +13,9 @@ using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; using NzbDrone.Core.Exceptions; using NzbDrone.Core.Http.CloudFlare; +using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Rarbg @@ -95,6 +102,57 @@ namespace NzbDrone.Core.Indexers.Rarbg return caps; } + protected override async Task<IndexerQueryResult> FetchPage(IndexerRequest request, IParseIndexerResponse parser) + { + var response = await FetchIndexerResponse(request); + + // try and recover from token or rate limit errors + var jsonResponse = new HttpResponse<RarbgResponse>(response.HttpResponse); + + if (jsonResponse.Resource.error_code.HasValue) + { + if (jsonResponse.Resource.error_code == 4 || jsonResponse.Resource.error_code == 2) + { + _logger.Debug("Invalid or expired token, refreshing token from Rarbg"); + _tokenProvider.ExpireToken(Settings); + var newToken = _tokenProvider.GetToken(Settings); + + var qs = HttpUtility.ParseQueryString(request.HttpRequest.Url.Query); + qs.Set("token", newToken); + + request.HttpRequest.Url = request.Url.SetQuery(qs.GetQueryString()); + response = await FetchIndexerResponse(request); + } + else if (jsonResponse.Resource.error_code == 5 || jsonResponse.Resource.rate_limit.HasValue) + { + _logger.Debug("Rarbg rate limit hit, retying request"); + response = await FetchIndexerResponse(request); + } + } + + try + { + var releases = parser.ParseResponse(response).ToList(); + + if (releases.Count == 0) + { + _logger.Trace(response.Content); + } + + return new IndexerQueryResult + { + Releases = releases, + Response = response.HttpResponse + }; + } + catch (Exception ex) + { + ex.WithData(response.HttpResponse, 128 * 1024); + _logger.Trace("Unexpected Response content ({0} bytes): {1}", response.HttpResponse.ResponseData.Length, response.HttpResponse.Content); + throw; + } + } + public override object RequestAction(string action, IDictionary<string, string> query) { if (action == "checkCaptcha") diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs index 690c82d6d..e2fcf3a7c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs @@ -41,9 +41,10 @@ namespace NzbDrone.Core.Indexers.Rarbg { if (jsonResponse.Resource.error_code == 20 || jsonResponse.Resource.error_code == 8 || jsonResponse.Resource.error_code == 9 || jsonResponse.Resource.error_code == 10 - || jsonResponse.Resource.error_code == 5) + || jsonResponse.Resource.error_code == 5 || jsonResponse.Resource.error_code == 13 + || jsonResponse.Resource.error_code == 14) { - // No results, rate limit, or imdbid not found + // No results, rate limit, or imdbid/tvdb not found return results; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs index cef7b90f0..d4d9548c6 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs @@ -69,42 +69,36 @@ namespace NzbDrone.Core.Indexers.Rarbg public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) { - var request = GetRequest(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories, searchCriteria.FullImdbId, searchCriteria.TmdbId); - return GetRequestChain(request, 2); + var pageableRequests = new IndexerPageableRequestChain(); + pageableRequests.Add(GetRequest(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories, searchCriteria.FullImdbId, searchCriteria.TmdbId)); + return pageableRequests; } public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) { - var request = GetRequest(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories); - return GetRequestChain(request, 2); + var pageableRequests = new IndexerPageableRequestChain(); + pageableRequests.Add(GetRequest(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories)); + return pageableRequests; } public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) { - var request = GetRequest(searchCriteria.SanitizedTvSearchString, searchCriteria.Categories, searchCriteria.FullImdbId, tvdbId: searchCriteria.TvdbId); - return GetRequestChain(request, 2); + var pageableRequests = new IndexerPageableRequestChain(); + pageableRequests.Add(GetRequest(searchCriteria.SanitizedTvSearchString, searchCriteria.Categories, searchCriteria.FullImdbId, tvdbId: searchCriteria.TvdbId)); + return pageableRequests; } public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) { - var request = GetRequest(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories); - return GetRequestChain(request, 2); + var pageableRequests = new IndexerPageableRequestChain(); + pageableRequests.Add(GetRequest(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories)); + return pageableRequests; } public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - var request = GetRequest(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories); - return GetRequestChain(request, 2); - } - - private IndexerPageableRequestChain GetRequestChain(IEnumerable<IndexerRequest> requests, int retry) { var pageableRequests = new IndexerPageableRequestChain(); - - for (int i = 0; i < retry; i++) - { - pageableRequests.AddTier(requests); - } + pageableRequests.Add(GetRequest(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories)); return pageableRequests; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgResponse.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgResponse.cs index 2ba32d32b..c93535400 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgResponse.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgResponse.cs @@ -7,6 +7,7 @@ namespace NzbDrone.Core.Indexers.Rarbg { public string error { get; set; } public int? error_code { get; set; } + public int? rate_limit { get; set; } public List<RarbgTorrent> torrent_results { get; set; } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs index 60069d089..5e2c37d74 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs @@ -3,14 +3,14 @@ using Newtonsoft.Json.Linq; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.EnvironmentInfo; -using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; namespace NzbDrone.Core.Indexers.Rarbg { public interface IRarbgTokenProvider { - string GetToken(RarbgSettings settings, string baseUrl); + string GetToken(RarbgSettings settings); + void ExpireToken(RarbgSettings settings); } public class RarbgTokenProvider : IRarbgTokenProvider @@ -26,12 +26,17 @@ namespace NzbDrone.Core.Indexers.Rarbg _logger = logger; } - public string GetToken(RarbgSettings settings, string baseUrl) + public void ExpireToken(RarbgSettings settings) { - return _tokenCache.Get(baseUrl, + _tokenCache.Remove(settings.BaseUrl); + } + + public string GetToken(RarbgSettings settings) + { + return _tokenCache.Get(settings.BaseUrl, () => { - var requestBuilder = new HttpRequestBuilder(baseUrl.Trim('/')) + var requestBuilder = new HttpRequestBuilder(settings.BaseUrl.Trim('/')) .WithRateLimit(3.0) .Resource($"/pubapi_v2.php?get_token=get_token&app_id={BuildInfo.AppName}") .Accept(HttpAccept.Json); From 738a690aac175e927e7f95a52a30ca106db0bd82 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 8 Oct 2022 18:19:34 -0500 Subject: [PATCH 0606/2320] Fixed: (Rarbg) Incorrect TVDB param logic Fixes #1129 Co-Authored-By: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> --- .../IndexerTests/RarbgTests/RarbgFixture.cs | 2 +- .../Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs index e8da2e1b3..39a9c84a7 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests }; Mocker.GetMock<IRarbgTokenProvider>() - .Setup(v => v.GetToken(It.IsAny<RarbgSettings>(), It.IsAny<string>())) + .Setup(v => v.GetToken(It.IsAny<RarbgSettings>())) .Returns("validtoken"); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs index d4d9548c6..100e91f8a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Core.Indexers.Rarbg { requestBuilder.AddQueryParam("search_themoviedb", tmdbId); } - else if (tvdbId.HasValue && tmdbId > 0) + else if (tvdbId.HasValue && tvdbId > 0) { requestBuilder.AddQueryParam("search_tvdb", tvdbId); } @@ -60,7 +60,7 @@ namespace NzbDrone.Core.Indexers.Rarbg } requestBuilder.AddQueryParam("limit", "100"); - requestBuilder.AddQueryParam("token", _tokenProvider.GetToken(Settings, Settings.BaseUrl)); + requestBuilder.AddQueryParam("token", _tokenProvider.GetToken(Settings)); requestBuilder.AddQueryParam("format", "json_extended"); requestBuilder.AddQueryParam("app_id", BuildInfo.AppName); From 9e3b43ef12f9b7b9a9f92c3df142b7e409e98955 Mon Sep 17 00:00:00 2001 From: Yukine <devyukine@gmx.de> Date: Sun, 9 Oct 2022 01:20:46 +0200 Subject: [PATCH 0607/2320] Fixed: (GreatPosterWall) correctly override Gazelle base method --- .../Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/GreatPosterWall.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs index 7b6885dbd..8a9f10a0f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleRequestGenerator.cs @@ -64,7 +64,7 @@ namespace NzbDrone.Core.Indexers.Gazelle return parameters; } - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + public virtual IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) { var parameters = GetBasicSearchParameters(searchCriteria.SearchTerm, searchCriteria.Categories); diff --git a/src/NzbDrone.Core/Indexers/Definitions/GreatPosterWall.cs b/src/NzbDrone.Core/Indexers/Definitions/GreatPosterWall.cs index d0a4d7a2d..5866a8e18 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/GreatPosterWall.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/GreatPosterWall.cs @@ -63,7 +63,7 @@ public class GreatPosterWallRequestGenerator : GazelleRequestGenerator { protected override bool ImdbInTags => false; - public new IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + public override IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) { var parameters = GetBasicSearchParameters(searchCriteria.SearchTerm, searchCriteria.Categories); From e9e4248af49e21dd63046d050197c90fae99ad05 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 8 Oct 2022 19:18:12 -0500 Subject: [PATCH 0608/2320] New: (Indexer) RetroFlix --- .../Indexers/Definitions/RetroFlix.cs | 61 ++ .../Indexers/Definitions/SpeedApp.cs | 517 +---------------- .../Definitions/SpeedApp/SpeedAppBase.cs | 533 ++++++++++++++++++ 3 files changed, 597 insertions(+), 514 deletions(-) create mode 100644 src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs create mode 100644 src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs diff --git a/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs b/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs new file mode 100644 index 000000000..d1d193f62 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using NLog; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Messaging.Events; + +namespace NzbDrone.Core.Indexers.Definitions +{ + public class RetroFlix : SpeedAppBase + { + public override string Name => "RetroFlix"; + + public override string[] IndexerUrls => new string[] { "https://retroflix.net/" }; + + public override string Description => "Private Torrent Tracker for Classic Movies / TV / General Releases"; + + public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + public override TimeSpan RateLimit => TimeSpan.FromSeconds(2.1); + + public RetroFlix(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger, IIndexerRepository indexerRepository) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger, indexerRepository) + { + } + + protected override IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities + { + TvSearchParams = new List<TvSearchParam> + { + TvSearchParam.Q, + TvSearchParam.Season, + TvSearchParam.Ep, + TvSearchParam.ImdbId + }, + MovieSearchParams = new List<MovieSearchParam> + { + MovieSearchParam.Q, + MovieSearchParam.ImdbId + }, + MusicSearchParams = new List<MusicSearchParam> + { + MusicSearchParam.Q, + }, + BookSearchParams = new List<BookSearchParam> + { + BookSearchParam.Q, + }, + }; + + caps.Categories.AddCategoryMapping(401, NewznabStandardCategory.Movies, "Movies"); + caps.Categories.AddCategoryMapping(402, NewznabStandardCategory.TV, "TV Series"); + caps.Categories.AddCategoryMapping(406, NewznabStandardCategory.AudioVideo, "Music Videos"); + caps.Categories.AddCategoryMapping(407, NewznabStandardCategory.TVSport, "Sports"); + caps.Categories.AddCategoryMapping(409, NewznabStandardCategory.Books, "Books"); + caps.Categories.AddCategoryMapping(408, NewznabStandardCategory.Audio, "HQ Audio"); + + return caps; + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs index d4b696246..88ea57608 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs @@ -1,187 +1,28 @@ -using System; using System.Collections.Generic; -using System.Collections.Specialized; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Net.Mime; -using System.Text; -using System.Threading.Tasks; -using FluentValidation; -using Newtonsoft.Json; using NLog; -using NzbDrone.Common.Extensions; -using NzbDrone.Common.Http; -using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; -using NzbDrone.Core.Exceptions; -using NzbDrone.Core.Indexers.Exceptions; -using NzbDrone.Core.Indexers.Settings; -using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.Parser; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.ThingiProvider; -using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class SpeedApp : TorrentIndexerBase<SpeedAppSettings> + public class SpeedApp : SpeedAppBase { public override string Name => "SpeedApp.io"; public override string[] IndexerUrls => new string[] { "https://speedapp.io" }; - private string ApiUrl => $"{Settings.BaseUrl}/api"; - - private string LoginUrl => $"{ApiUrl}/login"; - public override string Description => "SpeedApp is a ROMANIAN Private Torrent Tracker for MOVIES / TV / GENERAL"; public override string Language => "ro-RO"; - public override Encoding Encoding => Encoding.UTF8; - - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; - public override IndexerCapabilities Capabilities => SetCapabilities(); - - private IIndexerRepository _indexerRepository; - public SpeedApp(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger, IIndexerRepository indexerRepository) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger, indexerRepository) { - _indexerRepository = indexerRepository; } - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new SpeedAppRequestGenerator(Capabilities, Settings); - } - - public override IParseIndexerResponse GetParser() - { - return new SpeedAppParser(Settings, Capabilities.Categories); - } - - protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) - { - return Settings.ApiKey.IsNullOrWhiteSpace() || httpResponse.StatusCode == HttpStatusCode.Unauthorized; - } - - protected override async Task DoLogin() - { - var requestBuilder = new HttpRequestBuilder(LoginUrl) - { - LogResponseContent = true, - AllowAutoRedirect = true, - Method = HttpMethod.Post, - }; - - var request = requestBuilder.Build(); - - var data = new SpeedAppAuthenticationRequest - { - Email = Settings.Email, - Password = Settings.Password - }; - - request.SetContent(JsonConvert.SerializeObject(data)); - - request.Headers.ContentType = MediaTypeNames.Application.Json; - - var response = await ExecuteAuth(request); - - var statusCode = (int)response.StatusCode; - - if (statusCode is < 200 or > 299) - { - throw new HttpException(response); - } - - var parsedResponse = JsonConvert.DeserializeObject<SpeedAppAuthenticationResponse>(response.Content); - - Settings.ApiKey = parsedResponse.Token; - - if (Definition.Id > 0) - { - _indexerRepository.UpdateSettings((IndexerDefinition)Definition); - } - - _logger.Debug("SpeedApp authentication succeeded."); - } - - protected override void ModifyRequest(IndexerRequest request) - { - request.HttpRequest.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}"); - } - - public override async Task<byte[]> Download(Uri link) - { - Cookies = GetCookies(); - - if (link.Scheme == "magnet") - { - ValidateMagnet(link.OriginalString); - return Encoding.UTF8.GetBytes(link.OriginalString); - } - - var requestBuilder = new HttpRequestBuilder(link.AbsoluteUri); - - if (Cookies != null) - { - requestBuilder.SetCookies(Cookies); - } - - var request = requestBuilder.Build(); - request.AllowAutoRedirect = FollowRedirect; - request.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}"); - - byte[] torrentData; - - try - { - var response = await _httpClient.ExecuteProxiedAsync(request, Definition); - torrentData = response.ResponseData; - } - catch (HttpException ex) - { - if (ex.Response.StatusCode == HttpStatusCode.NotFound) - { - _logger.Error(ex, "Downloading torrent file for release failed since it no longer exists ({0})", link.AbsoluteUri); - throw new ReleaseUnavailableException("Downloading torrent failed", ex); - } - - if (ex.Response.StatusCode == HttpStatusCode.TooManyRequests) - { - _logger.Error("API Grab Limit reached for {0}", link.AbsoluteUri); - } - else - { - _logger.Error(ex, "Downloading torrent file for release failed ({0})", link.AbsoluteUri); - } - - throw new ReleaseDownloadException("Downloading torrent failed", ex); - } - catch (WebException ex) - { - _logger.Error(ex, "Downloading torrent file for release failed ({0})", link.AbsoluteUri); - - throw new ReleaseDownloadException("Downloading torrent failed", ex); - } - catch (Exception) - { - _indexerStatusService.RecordFailure(Definition.Id); - _logger.Error("Downloading torrent failed"); - throw; - } - - return torrentData; - } - - private IndexerCapabilities SetCapabilities() + protected override IndexerCapabilities SetCapabilities() { var caps = new IndexerCapabilities { @@ -253,356 +94,4 @@ namespace NzbDrone.Core.Indexers.Definitions return caps; } } - - public class SpeedAppRequestGenerator : IIndexerRequestGenerator - { - public Func<IDictionary<string, string>> GetCookies { get; set; } - - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - - private IndexerCapabilities Capabilities { get; } - - private SpeedAppSettings Settings { get; } - - public SpeedAppRequestGenerator(IndexerCapabilities capabilities, SpeedAppSettings settings) - { - Capabilities = capabilities; - Settings = settings; - } - - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - return GetSearch(searchCriteria, searchCriteria.FullImdbId); - } - - public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) - { - return GetSearch(searchCriteria); - } - - public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) - { - return GetSearch(searchCriteria, searchCriteria.FullImdbId, searchCriteria.Season, searchCriteria.Episode); - } - - public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) - { - return GetSearch(searchCriteria); - } - - public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) - { - return GetSearch(searchCriteria); - } - - private IndexerPageableRequestChain GetSearch(SearchCriteriaBase searchCriteria, string imdbId = null, int? season = null, string episode = null) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories, imdbId, season, episode)); - - return pageableRequests; - } - - private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null, int? season = null, string episode = null) - { - var qc = new NameValueCollection(); - - if (imdbId.IsNotNullOrWhiteSpace()) - { - qc.Add("imdbId", imdbId); - } - else - { - qc.Add("search", term); - } - - if (season != null) - { - qc.Add("season", season.Value.ToString()); - } - - if (episode != null) - { - qc.Add("episode", episode); - } - - var cats = Capabilities.Categories.MapTorznabCapsToTrackers(categories); - - if (cats.Count > 0) - { - foreach (var cat in cats) - { - qc.Add("categories[]", cat); - } - } - - var searchUrl = Settings.BaseUrl + "/api/torrent?" + qc.GetQueryString(duplicateKeysIfMulti: true); - - var request = new IndexerRequest(searchUrl, HttpAccept.Json); - - request.HttpRequest.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}"); - - yield return request; - } - } - - public class SpeedAppParser : IParseIndexerResponse - { - private readonly SpeedAppSettings _settings; - private readonly IndexerCapabilitiesCategories _categories; - - public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } - - public SpeedAppParser(SpeedAppSettings settings, IndexerCapabilitiesCategories categories) - { - _settings = settings; - _categories = categories; - } - - public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) - { - if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) - { - throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request"); - } - - if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value)) - { - throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}"); - } - - var jsonResponse = new HttpResponse<List<SpeedAppTorrent>>(indexerResponse.HttpResponse); - - return jsonResponse.Resource.Select(torrent => new TorrentInfo - { - Guid = torrent.Id.ToString(), - Title = torrent.Name, - Description = torrent.ShortDescription, - Size = torrent.Size, - ImdbId = ParseUtil.GetImdbID(torrent.ImdbId).GetValueOrDefault(), - DownloadUrl = $"{_settings.BaseUrl}/api/torrent/{torrent.Id}/download", - PosterUrl = torrent.Poster, - InfoUrl = torrent.Url, - Grabs = torrent.TimesCompleted, - PublishDate = torrent.CreatedAt, - Categories = _categories.MapTrackerCatToNewznab(torrent.Category.Id.ToString()), - InfoHash = null, - Seeders = torrent.Seeders, - Peers = torrent.Leechers + torrent.Seeders, - MinimumRatio = 1, - MinimumSeedTime = 172800, - DownloadVolumeFactor = torrent.DownloadVolumeFactor, - UploadVolumeFactor = torrent.UploadVolumeFactor, - }).ToArray(); - } - } - - public class SpeedAppSettingsValidator : AbstractValidator<SpeedAppSettings> - { - public SpeedAppSettingsValidator() - { - RuleFor(c => c.Email).NotEmpty(); - RuleFor(c => c.Password).NotEmpty(); - } - } - - public class SpeedAppSettings : NoAuthTorrentBaseSettings - { - private static readonly SpeedAppSettingsValidator Validator = new (); - - public SpeedAppSettings() - { - Email = ""; - Password = ""; - } - - [FieldDefinition(2, Label = "Email", HelpText = "Site Email", Privacy = PrivacyLevel.UserName)] - public string Email { get; set; } - - [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] - public string Password { get; set; } - - [FieldDefinition(4, Label = "API Key", Hidden = HiddenType.Hidden)] - public string ApiKey { get; set; } - - public override NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } - - public class SpeedAppCategory - { - [JsonProperty("id")] - public int Id { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - } - - public class SpeedAppCountry - { - [JsonProperty("id")] - public int Id { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("flag_image")] - public string FlagImage { get; set; } - } - - public class SpeedAppUploadedBy - { - [JsonProperty("id")] - public int Id { get; set; } - - [JsonProperty("username")] - public string Username { get; set; } - - [JsonProperty("email")] - public string Email { get; set; } - - [JsonProperty("created_at")] - public DateTime CreatedAt { get; set; } - - [JsonProperty("class")] - public int Class { get; set; } - - [JsonProperty("avatar")] - public string Avatar { get; set; } - - [JsonProperty("uploaded")] - public int Uploaded { get; set; } - - [JsonProperty("downloaded")] - public int Downloaded { get; set; } - - [JsonProperty("title")] - public string Title { get; set; } - - [JsonProperty("country")] - public SpeedAppCountry Country { get; set; } - - [JsonProperty("passkey")] - public string Passkey { get; set; } - - [JsonProperty("invites")] - public int Invites { get; set; } - - [JsonProperty("timezone")] - public string Timezone { get; set; } - - [JsonProperty("hit_and_run_count")] - public int HitAndRunCount { get; set; } - - [JsonProperty("snatch_count")] - public int SnatchCount { get; set; } - - [JsonProperty("need_seed")] - public int NeedSeed { get; set; } - - [JsonProperty("average_seed_time")] - public int AverageSeedTime { get; set; } - - [JsonProperty("free_leech_tokens")] - public int FreeLeechTokens { get; set; } - - [JsonProperty("double_upload_tokens")] - public int DoubleUploadTokens { get; set; } - } - - public class SpeedAppTag - { - [JsonProperty("translated_name")] - public string TranslatedName { get; set; } - - [JsonProperty("id")] - public int Id { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("match_list")] - public List<string> MatchList { get; set; } - - [JsonProperty("created_at")] - public DateTime CreatedAt { get; set; } - } - - public class SpeedAppTorrent - { - [JsonProperty("download_volume_factor")] - public float DownloadVolumeFactor { get; set; } - - [JsonProperty("upload_volume_factor")] - public float UploadVolumeFactor { get; set; } - - [JsonProperty("url")] - public string Url { get; set; } - - [JsonProperty("id")] - public int Id { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("description")] - public string Description { get; set; } - - [JsonProperty("category")] - public SpeedAppCategory Category { get; set; } - - [JsonProperty("size")] - public long Size { get; set; } - - [JsonProperty("created_at")] - public DateTime CreatedAt { get; set; } - - [JsonProperty("times_completed")] - public int TimesCompleted { get; set; } - - [JsonProperty("leechers")] - public int Leechers { get; set; } - - [JsonProperty("seeders")] - public int Seeders { get; set; } - - [JsonProperty("uploaded_by")] - public SpeedAppUploadedBy UploadedBy { get; set; } - - [JsonProperty("short_description")] - public string ShortDescription { get; set; } - - [JsonProperty("poster")] - public string Poster { get; set; } - - [JsonProperty("season")] - public int Season { get; set; } - - [JsonProperty("episode")] - public int Episode { get; set; } - - [JsonProperty("tags")] - public List<SpeedAppTag> Tags { get; set; } - - [JsonProperty("imdb_id")] - public string ImdbId { get; set; } - } - - public class SpeedAppAuthenticationRequest - { - [JsonProperty("username")] - public string Email { get; set; } - - [JsonProperty("password")] - public string Password { get; set; } - } - - public class SpeedAppAuthenticationResponse - { - [JsonProperty("token")] - public string Token { get; set; } - } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs new file mode 100644 index 000000000..621889b64 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs @@ -0,0 +1,533 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Mime; +using System.Text; +using System.Threading.Tasks; +using FluentValidation; +using Newtonsoft.Json; +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Exceptions; +using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Indexers.Definitions +{ + public abstract class SpeedAppBase : TorrentIndexerBase<SpeedAppSettings> + { + private string ApiUrl => $"{Settings.BaseUrl}/api"; + + private string LoginUrl => $"{ApiUrl}/login"; + + public override Encoding Encoding => Encoding.UTF8; + + public override DownloadProtocol Protocol => DownloadProtocol.Torrent; + + public override IndexerCapabilities Capabilities => SetCapabilities(); + + private IIndexerRepository _indexerRepository; + + public SpeedAppBase(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger, IIndexerRepository indexerRepository) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) + { + _indexerRepository = indexerRepository; + } + + public override IIndexerRequestGenerator GetRequestGenerator() + { + return new SpeedAppRequestGenerator(Capabilities, Settings); + } + + public override IParseIndexerResponse GetParser() + { + return new SpeedAppParser(Settings, Capabilities.Categories); + } + + protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) + { + return Settings.ApiKey.IsNullOrWhiteSpace() || httpResponse.StatusCode == HttpStatusCode.Unauthorized; + } + + protected override async Task DoLogin() + { + var requestBuilder = new HttpRequestBuilder(LoginUrl) + { + LogResponseContent = true, + AllowAutoRedirect = true, + Method = HttpMethod.Post, + }; + + var request = requestBuilder.Build(); + + var data = new SpeedAppAuthenticationRequest + { + Email = Settings.Email, + Password = Settings.Password + }; + + request.SetContent(JsonConvert.SerializeObject(data)); + + request.Headers.ContentType = MediaTypeNames.Application.Json; + + var response = await ExecuteAuth(request); + + var statusCode = (int)response.StatusCode; + + if (statusCode is < 200 or > 299) + { + throw new HttpException(response); + } + + var parsedResponse = JsonConvert.DeserializeObject<SpeedAppAuthenticationResponse>(response.Content); + + Settings.ApiKey = parsedResponse.Token; + + if (Definition.Id > 0) + { + _indexerRepository.UpdateSettings((IndexerDefinition)Definition); + } + + _logger.Debug("SpeedApp authentication succeeded."); + } + + protected override void ModifyRequest(IndexerRequest request) + { + request.HttpRequest.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}"); + } + + public override async Task<byte[]> Download(Uri link) + { + Cookies = GetCookies(); + + if (link.Scheme == "magnet") + { + ValidateMagnet(link.OriginalString); + return Encoding.UTF8.GetBytes(link.OriginalString); + } + + var requestBuilder = new HttpRequestBuilder(link.AbsoluteUri); + + if (Cookies != null) + { + requestBuilder.SetCookies(Cookies); + } + + var request = requestBuilder.Build(); + request.AllowAutoRedirect = FollowRedirect; + request.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}"); + + byte[] torrentData; + + try + { + var response = await _httpClient.ExecuteProxiedAsync(request, Definition); + torrentData = response.ResponseData; + } + catch (HttpException ex) + { + if (ex.Response.StatusCode == HttpStatusCode.NotFound) + { + _logger.Error(ex, "Downloading torrent file for release failed since it no longer exists ({0})", link.AbsoluteUri); + throw new ReleaseUnavailableException("Downloading torrent failed", ex); + } + + if (ex.Response.StatusCode == HttpStatusCode.TooManyRequests) + { + _logger.Error("API Grab Limit reached for {0}", link.AbsoluteUri); + } + else + { + _logger.Error(ex, "Downloading torrent file for release failed ({0})", link.AbsoluteUri); + } + + throw new ReleaseDownloadException("Downloading torrent failed", ex); + } + catch (WebException ex) + { + _logger.Error(ex, "Downloading torrent file for release failed ({0})", link.AbsoluteUri); + + throw new ReleaseDownloadException("Downloading torrent failed", ex); + } + catch (Exception) + { + _indexerStatusService.RecordFailure(Definition.Id); + _logger.Error("Downloading torrent failed"); + throw; + } + + return torrentData; + } + + protected virtual IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities(); + + return caps; + } + } + + public class SpeedAppRequestGenerator : IIndexerRequestGenerator + { + public Func<IDictionary<string, string>> GetCookies { get; set; } + + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + + private IndexerCapabilities Capabilities { get; } + + private SpeedAppSettings Settings { get; } + + public SpeedAppRequestGenerator(IndexerCapabilities capabilities, SpeedAppSettings settings) + { + Capabilities = capabilities; + Settings = settings; + } + + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + { + return GetSearch(searchCriteria, searchCriteria.FullImdbId); + } + + public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) + { + return GetSearch(searchCriteria); + } + + public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) + { + return GetSearch(searchCriteria, searchCriteria.FullImdbId, searchCriteria.Season, searchCriteria.Episode); + } + + public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + { + return GetSearch(searchCriteria); + } + + public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) + { + return GetSearch(searchCriteria); + } + + private IndexerPageableRequestChain GetSearch(SearchCriteriaBase searchCriteria, string imdbId = null, int? season = null, string episode = null) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories, imdbId, season, episode)); + + return pageableRequests; + } + + private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null, int? season = null, string episode = null) + { + var qc = new NameValueCollection(); + + if (imdbId.IsNotNullOrWhiteSpace()) + { + qc.Add("imdbId", imdbId); + } + else + { + qc.Add("search", term); + } + + if (season != null) + { + qc.Add("season", season.Value.ToString()); + } + + if (episode != null) + { + qc.Add("episode", episode); + } + + var cats = Capabilities.Categories.MapTorznabCapsToTrackers(categories); + + if (cats.Count > 0) + { + foreach (var cat in cats) + { + qc.Add("categories[]", cat); + } + } + + var searchUrl = Settings.BaseUrl + "/api/torrent?" + qc.GetQueryString(duplicateKeysIfMulti: true); + + var request = new IndexerRequest(searchUrl, HttpAccept.Json); + + request.HttpRequest.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}"); + + yield return request; + } + } + + public class SpeedAppParser : IParseIndexerResponse + { + private readonly SpeedAppSettings _settings; + private readonly IndexerCapabilitiesCategories _categories; + + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + + public SpeedAppParser(SpeedAppSettings settings, IndexerCapabilitiesCategories categories) + { + _settings = settings; + _categories = categories; + } + + public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) + { + if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) + { + throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request"); + } + + if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value)) + { + throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}"); + } + + var jsonResponse = new HttpResponse<List<SpeedAppTorrent>>(indexerResponse.HttpResponse); + + return jsonResponse.Resource.Select(torrent => new TorrentInfo + { + Guid = torrent.Id.ToString(), + Title = torrent.Name, + Description = torrent.ShortDescription, + Size = torrent.Size, + ImdbId = ParseUtil.GetImdbID(torrent.ImdbId).GetValueOrDefault(), + DownloadUrl = $"{_settings.BaseUrl}/api/torrent/{torrent.Id}/download", + PosterUrl = torrent.Poster, + InfoUrl = torrent.Url, + Grabs = torrent.TimesCompleted, + PublishDate = torrent.CreatedAt, + Categories = _categories.MapTrackerCatToNewznab(torrent.Category.Id.ToString()), + InfoHash = null, + Seeders = torrent.Seeders, + Peers = torrent.Leechers + torrent.Seeders, + MinimumRatio = 1, + MinimumSeedTime = 172800, + DownloadVolumeFactor = torrent.DownloadVolumeFactor, + UploadVolumeFactor = torrent.UploadVolumeFactor, + }).ToArray(); + } + } + + public class SpeedAppSettingsValidator : AbstractValidator<SpeedAppSettings> + { + public SpeedAppSettingsValidator() + { + RuleFor(c => c.Email).NotEmpty(); + RuleFor(c => c.Password).NotEmpty(); + } + } + + public class SpeedAppSettings : NoAuthTorrentBaseSettings + { + private static readonly SpeedAppSettingsValidator Validator = new (); + + public SpeedAppSettings() + { + Email = ""; + Password = ""; + } + + [FieldDefinition(2, Label = "Email", HelpText = "Site Email", Privacy = PrivacyLevel.UserName)] + public string Email { get; set; } + + [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] + public string Password { get; set; } + + [FieldDefinition(4, Label = "API Key", Hidden = HiddenType.Hidden)] + public string ApiKey { get; set; } + + public override NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } + + public class SpeedAppCategory + { + [JsonProperty("id")] + public int Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + } + + public class SpeedAppCountry + { + [JsonProperty("id")] + public int Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("flag_image")] + public string FlagImage { get; set; } + } + + public class SpeedAppUploadedBy + { + [JsonProperty("id")] + public int Id { get; set; } + + [JsonProperty("username")] + public string Username { get; set; } + + [JsonProperty("email")] + public string Email { get; set; } + + [JsonProperty("created_at")] + public DateTime CreatedAt { get; set; } + + [JsonProperty("class")] + public int Class { get; set; } + + [JsonProperty("avatar")] + public string Avatar { get; set; } + + [JsonProperty("uploaded")] + public int Uploaded { get; set; } + + [JsonProperty("downloaded")] + public int Downloaded { get; set; } + + [JsonProperty("title")] + public string Title { get; set; } + + [JsonProperty("country")] + public SpeedAppCountry Country { get; set; } + + [JsonProperty("passkey")] + public string Passkey { get; set; } + + [JsonProperty("invites")] + public int Invites { get; set; } + + [JsonProperty("timezone")] + public string Timezone { get; set; } + + [JsonProperty("hit_and_run_count")] + public int HitAndRunCount { get; set; } + + [JsonProperty("snatch_count")] + public int SnatchCount { get; set; } + + [JsonProperty("need_seed")] + public int NeedSeed { get; set; } + + [JsonProperty("average_seed_time")] + public int AverageSeedTime { get; set; } + + [JsonProperty("free_leech_tokens")] + public int FreeLeechTokens { get; set; } + + [JsonProperty("double_upload_tokens")] + public int DoubleUploadTokens { get; set; } + } + + public class SpeedAppTag + { + [JsonProperty("translated_name")] + public string TranslatedName { get; set; } + + [JsonProperty("id")] + public int Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("match_list")] + public List<string> MatchList { get; set; } + + [JsonProperty("created_at")] + public DateTime CreatedAt { get; set; } + } + + public class SpeedAppTorrent + { + [JsonProperty("download_volume_factor")] + public float DownloadVolumeFactor { get; set; } + + [JsonProperty("upload_volume_factor")] + public float UploadVolumeFactor { get; set; } + + [JsonProperty("url")] + public string Url { get; set; } + + [JsonProperty("id")] + public int Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + [JsonProperty("category")] + public SpeedAppCategory Category { get; set; } + + [JsonProperty("size")] + public long Size { get; set; } + + [JsonProperty("created_at")] + public DateTime CreatedAt { get; set; } + + [JsonProperty("times_completed")] + public int TimesCompleted { get; set; } + + [JsonProperty("leechers")] + public int Leechers { get; set; } + + [JsonProperty("seeders")] + public int Seeders { get; set; } + + [JsonProperty("uploaded_by")] + public SpeedAppUploadedBy UploadedBy { get; set; } + + [JsonProperty("short_description")] + public string ShortDescription { get; set; } + + [JsonProperty("poster")] + public string Poster { get; set; } + + [JsonProperty("season")] + public int Season { get; set; } + + [JsonProperty("episode")] + public int Episode { get; set; } + + [JsonProperty("tags")] + public List<SpeedAppTag> Tags { get; set; } + + [JsonProperty("imdb_id")] + public string ImdbId { get; set; } + } + + public class SpeedAppAuthenticationRequest + { + [JsonProperty("username")] + public string Email { get; set; } + + [JsonProperty("password")] + public string Password { get; set; } + } + + public class SpeedAppAuthenticationResponse + { + [JsonProperty("token")] + public string Token { get; set; } + } +} From f929a7e62f2404b6a360a71b8fc147bdc751ac77 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 8 Oct 2022 22:14:46 -0500 Subject: [PATCH 0609/2320] New: (Indexer) NZBIndex --- .../Indexers/Definitions/NzbIndex.cs | 258 ++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 src/NzbDrone.Core/Indexers/Definitions/NzbIndex.cs diff --git a/src/NzbDrone.Core/Indexers/Definitions/NzbIndex.cs b/src/NzbDrone.Core/Indexers/Definitions/NzbIndex.cs new file mode 100644 index 000000000..098d6e3ea --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/NzbIndex.cs @@ -0,0 +1,258 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using DryIoc; +using FluentValidation; +using Newtonsoft.Json.Linq; +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Settings; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Indexers.Definitions +{ + public class NzbIndex : TorrentIndexerBase<NzbIndexSettings> + { + public override string Name => "NZBIndex"; + public override string[] IndexerUrls => new[] { "https://nzbindex.com/" }; + public override string Description => "A Usenet Indexer"; + public override DownloadProtocol Protocol => DownloadProtocol.Usenet; + public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPrivate; + public override IndexerCapabilities Capabilities => SetCapabilities(); + + public NzbIndex(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) + { + } + + public override IIndexerRequestGenerator GetRequestGenerator() + { + return new NzbIndexRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; + } + + public override IParseIndexerResponse GetParser() + { + return new NzbIndexParser(Settings, Capabilities.Categories); + } + + private IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities + { + TvSearchParams = new List<TvSearchParam> + { + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep + }, + MovieSearchParams = new List<MovieSearchParam> + { + MovieSearchParam.Q + }, + MusicSearchParams = new List<MusicSearchParam> + { + MusicSearchParam.Q + }, + BookSearchParams = new List<BookSearchParam> + { + BookSearchParam.Q + } + }; + + // TODO build this out more + caps.Categories.AddCategoryMapping(83, NewznabStandardCategory.BooksComics, "a.b.comics"); + caps.Categories.AddCategoryMapping(234, NewznabStandardCategory.Console, "a.b.games"); + caps.Categories.AddCategoryMapping(244, NewznabStandardCategory.ConsoleWii, "a.b.games.wii"); + caps.Categories.AddCategoryMapping(246, NewznabStandardCategory.ConsoleXBox, "a.b.games.xbox"); + caps.Categories.AddCategoryMapping(247, NewznabStandardCategory.ConsoleXBox, "a.b.games.xbox360"); + caps.Categories.AddCategoryMapping(327, NewznabStandardCategory.Movies, "a.b.movies"); + caps.Categories.AddCategoryMapping(358, NewznabStandardCategory.Movies, "a.b.movies.x264"); + caps.Categories.AddCategoryMapping(409, NewznabStandardCategory.XXX, "a.b.multimedia.erotica"); + caps.Categories.AddCategoryMapping(587, NewznabStandardCategory.AudioMP3, "a.b.sounds.lossless"); + caps.Categories.AddCategoryMapping(604, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3"); + caps.Categories.AddCategoryMapping(731, NewznabStandardCategory.TV, "a.b.tv"); + + return caps; + } + } + + public class NzbIndexRequestGenerator : IIndexerRequestGenerator + { + public NzbIndexSettings Settings { get; set; } + public IndexerCapabilities Capabilities { get; set; } + + public NzbIndexRequestGenerator() + { + } + + private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, int limit, int offset) + { + var searchString = term; + + var queryCollection = new NameValueCollection + { + { "key", Settings.ApiKey }, + { "max", limit.ToString() }, + { "q", searchString }, + { "p", ((offset / limit) + 1).ToString() } + }; + + var searchUrl = string.Format("{0}/api/v3/search/?{1}", Settings.BaseUrl.TrimEnd('/'), queryCollection.GetQueryString()); + + if (categories != null) + { + foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories)) + { + searchUrl += string.Format("&g[]={0}", cat); + } + } + + var request = new IndexerRequest(searchUrl, HttpAccept.Html); + + yield return request; + } + + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.Limit ?? 100, searchCriteria.Offset ?? 0)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.Limit ?? 100, searchCriteria.Offset ?? 0)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.Limit ?? 100, searchCriteria.Offset ?? 0)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.Limit ?? 100, searchCriteria.Offset ?? 0)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.Limit ?? 100, searchCriteria.Offset ?? 0)); + + return pageableRequests; + } + + public Func<IDictionary<string, string>> GetCookies { get; set; } + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + } + + public class NzbIndexParser : IParseIndexerResponse + { + private readonly NzbIndexSettings _settings; + private readonly IndexerCapabilitiesCategories _categories; + + public NzbIndexParser(NzbIndexSettings settings, IndexerCapabilitiesCategories categories) + { + _settings = settings; + _categories = categories; + } + + public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) + { + var releaseInfos = new List<ReleaseInfo>(); + + // TODO Deserialize to TorrentSyndikatResponse Type + var jsonContent = JObject.Parse(indexerResponse.Content); + + foreach (var row in jsonContent.Value<JArray>("results")) + { + var dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); + + var id = row.Value<string>("id"); + var details = _settings.BaseUrl + "collection/" + id; + + var parsedTitle = ParseTitleRegex.Match(row.Value<string>("name")); + + if (!parsedTitle.Success || parsedTitle.Groups["title"].Value.IsNullOrWhiteSpace()) + { + continue; + } + + var release = new ReleaseInfo + { + Guid = details, + InfoUrl = details, + DownloadUrl = _settings.BaseUrl + "download/" + id, + Title = parsedTitle.Groups["title"].Value, + Categories = row.Value<JArray>("group_ids").SelectMany(g => _categories.MapTrackerCatToNewznab(g.Value<string>())).Distinct().ToList(), + PublishDate = dateTime.AddMilliseconds(row.Value<long>("posted")).ToLocalTime(), + Size = row.Value<long>("size"), + Files = row.Value<int>("file_count") + }; + + releaseInfos.Add(release); + } + + return releaseInfos.ToArray(); + } + + private static readonly Regex ParseTitleRegex = new Regex(@"\""(?<title>[^:\/]*?)(?:\.(rar|nfo|mkv|par2|001|nzb|url|zip|r[0-9]{2}))?\"""); + + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + } + + public class NzbIndexSettingsValidator : AbstractValidator<NzbIndexSettings> + { + public NzbIndexSettingsValidator() + { + RuleFor(c => c.ApiKey).NotEmpty(); + } + } + + public class NzbIndexSettings : IIndexerSettings + { + private static readonly NzbIndexSettingsValidator Validator = new NzbIndexSettingsValidator(); + + public NzbIndexSettings() + { + ApiKey = ""; + } + + [FieldDefinition(1, Label = "Base Url", HelpText = "Select which baseurl Prowlarr will use for requests to the site", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls")] + public string BaseUrl { get; set; } + + [FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpText = "Site API Key")] + public string ApiKey { get; set; } + + [FieldDefinition(3)] + public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} From 74a1d95ab74e6b4ede077e02995033a7dcc611e4 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 8 Oct 2022 22:52:17 -0500 Subject: [PATCH 0610/2320] Update NZBIndex Categories --- .../Indexers/Definitions/NzbIndex.cs | 950 +++++++++++++++++- 1 file changed, 941 insertions(+), 9 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/NzbIndex.cs b/src/NzbDrone.Core/Indexers/Definitions/NzbIndex.cs index 098d6e3ea..bc007588f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/NzbIndex.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/NzbIndex.cs @@ -2,9 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; -using System.Text; using System.Text.RegularExpressions; -using DryIoc; using FluentValidation; using Newtonsoft.Json.Linq; using NLog; @@ -12,7 +10,6 @@ using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; -using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -68,17 +65,954 @@ namespace NzbDrone.Core.Indexers.Definitions }; // TODO build this out more + caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Other, "a2000.beeld.binaries"); + caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.Other, "a2000.binaries"); + caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Other, "a2000.erotica.binaries"); + caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.Other, "a2000.games.binaries"); + caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Other, "a2000.geluid.binaries"); + caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.Other, "a.b"); + caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.Other, "a.b.0day.stuffz"); + caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.Other, "a.b.1place4nzb"); + caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.Other, "a.b.3d"); + caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.Other, "a.b.a51"); + caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.Other, "a.b.aa"); + caps.Categories.AddCategoryMapping(904, NewznabStandardCategory.Other, "a.b.all-your-base-are-belong-to-us"); + caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.Other, "a.b.alt"); + caps.Categories.AddCategoryMapping(905, NewznabStandardCategory.Other, "a.b.alt5"); + caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.Other, "a.b.amazing"); + caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.Other, "a.b.amp"); + caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.Other, "a.b.android"); + caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.TVAnime, "a.b.anime"); + caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.Other, "a.b.anime.german"); + caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.Other, "a.b.anime.repost"); + caps.Categories.AddCategoryMapping(906, NewznabStandardCategory.Other, "a.b.appletv"); + caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.Other, "a.b.applications"); + caps.Categories.AddCategoryMapping(907, NewznabStandardCategory.Other, "a.b.aquaria"); + caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.Other, "a.b.archive.encrypted"); + caps.Categories.AddCategoryMapping(867, NewznabStandardCategory.Other, "a.b.art-of-usenet"); + caps.Categories.AddCategoryMapping(21, NewznabStandardCategory.Other, "a.b.asianusenet"); + caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.Other, "a.b.astronomy"); + caps.Categories.AddCategoryMapping(946, NewznabStandardCategory.Other, "a.b.atari"); + caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.Other, "a.b.ath"); + caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.Other, "a.b.aubergine"); + caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.Other, "a.b.audio.warez"); + caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.Other, "a.b.audiobooks"); + caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.Other, "a.b.b4e"); + caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.Other, "a.b.b4e.erotica"); + caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.Other, "a.b.barbarella"); + caps.Categories.AddCategoryMapping(30, NewznabStandardCategory.Other, "a.b.bbs"); + caps.Categories.AddCategoryMapping(31, NewznabStandardCategory.Other, "a.b.bd.french"); + caps.Categories.AddCategoryMapping(32, NewznabStandardCategory.Other, "a.b.beatles"); + caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.Other, "a.b.big"); + caps.Categories.AddCategoryMapping(947, NewznabStandardCategory.Other, "a.b.bitburger"); + caps.Categories.AddCategoryMapping(34, NewznabStandardCategory.Other, "a.b.bloaf"); + caps.Categories.AddCategoryMapping(36, NewznabStandardCategory.Other, "a.b.blu-ray"); + caps.Categories.AddCategoryMapping(37, NewznabStandardCategory.Other, "a.b.blu-ray.subtitles"); + caps.Categories.AddCategoryMapping(35, NewznabStandardCategory.Other, "a.b.blue-ray"); + caps.Categories.AddCategoryMapping(38, NewznabStandardCategory.Other, "a.b.bollywood"); + caps.Categories.AddCategoryMapping(39, NewznabStandardCategory.Other, "a.b.bollywood.movies"); + caps.Categories.AddCategoryMapping(40, NewznabStandardCategory.Other, "a.b.boneless"); + caps.Categories.AddCategoryMapping(41, NewznabStandardCategory.Other, "a.b.boneless.nl"); + caps.Categories.AddCategoryMapping(944, NewznabStandardCategory.Other, "a.b.bos"); + caps.Categories.AddCategoryMapping(951, NewznabStandardCategory.Other, "a.b.brg"); + caps.Categories.AddCategoryMapping(42, NewznabStandardCategory.Other, "a.b.british.documentaries"); + caps.Categories.AddCategoryMapping(43, NewznabStandardCategory.Other, "a.b.british.drama"); + caps.Categories.AddCategoryMapping(44, NewznabStandardCategory.Other, "a.b.brothers-of-usenet.game"); + caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.Other, "a.b.brothers-of-usenet.movie"); + caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.Other, "a.b.brothers-of-usenet.musik"); + caps.Categories.AddCategoryMapping(866, NewznabStandardCategory.Other, "a.b.bungabunga"); + caps.Categories.AddCategoryMapping(908, NewznabStandardCategory.Other, "a.b.bungalow"); + caps.Categories.AddCategoryMapping(909, NewznabStandardCategory.Other, "a.b.busca-usenet"); + caps.Categories.AddCategoryMapping(948, NewznabStandardCategory.Other, "a.b.butthedd"); + caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.Other, "a.b.buttnuggets"); + caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.Other, "a.b.cartoons.french"); + caps.Categories.AddCategoryMapping(49, NewznabStandardCategory.Other, "a.b.cartoons.french.animes-fansub"); + caps.Categories.AddCategoryMapping(50, NewznabStandardCategory.Other, "a.b.cartoons.french.reposts"); + caps.Categories.AddCategoryMapping(910, NewznabStandardCategory.Other, "a.b.cats"); + caps.Categories.AddCategoryMapping(51, NewznabStandardCategory.Other, "a.b.cavebox"); + caps.Categories.AddCategoryMapping(52, NewznabStandardCategory.Other, "a.b.cbts"); + caps.Categories.AddCategoryMapping(53, NewznabStandardCategory.Other, "a.b.cccb"); + caps.Categories.AddCategoryMapping(54, NewznabStandardCategory.Other, "a.b.cd"); + caps.Categories.AddCategoryMapping(55, NewznabStandardCategory.Other, "a.b.cd.image"); + caps.Categories.AddCategoryMapping(56, NewznabStandardCategory.Other, "a.b.cd.image.0-day"); + caps.Categories.AddCategoryMapping(57, NewznabStandardCategory.Other, "a.b.cd.image.clonecd"); + caps.Categories.AddCategoryMapping(58, NewznabStandardCategory.Console, "a.b.cd.image.dreamcast"); + caps.Categories.AddCategoryMapping(59, NewznabStandardCategory.Other, "a.b.cd.image.french"); + caps.Categories.AddCategoryMapping(60, NewznabStandardCategory.Other, "a.b.cd.image.game"); + caps.Categories.AddCategoryMapping(61, NewznabStandardCategory.Console, "a.b.cd.image.gamecube"); + caps.Categories.AddCategoryMapping(62, NewznabStandardCategory.Other, "a.b.cd.image.games"); + caps.Categories.AddCategoryMapping(63, NewznabStandardCategory.Other, "a.b.cd.image.highspeed"); + caps.Categories.AddCategoryMapping(64, NewznabStandardCategory.Other, "a.b.cd.image.iso"); + caps.Categories.AddCategoryMapping(65, NewznabStandardCategory.Other, "a.b.cd.image.linux"); + caps.Categories.AddCategoryMapping(66, NewznabStandardCategory.Other, "a.b.cd.image.other"); + caps.Categories.AddCategoryMapping(67, NewznabStandardCategory.Console, "a.b.cd.image.playstation"); + caps.Categories.AddCategoryMapping(68, NewznabStandardCategory.Console, "a.b.cd.image.playstation2"); + caps.Categories.AddCategoryMapping(69, NewznabStandardCategory.Console, "a.b.cd.image.playstation2.dvdiso"); + caps.Categories.AddCategoryMapping(70, NewznabStandardCategory.Console, "a.b.cd.image.playstation2.repost"); + caps.Categories.AddCategoryMapping(71, NewznabStandardCategory.Console, "a.b.cd.image.ps2.dvdiso"); + caps.Categories.AddCategoryMapping(72, NewznabStandardCategory.Other, "a.b.cd.image.repost"); + caps.Categories.AddCategoryMapping(73, NewznabStandardCategory.Other, "a.b.cd.image.reposts"); + caps.Categories.AddCategoryMapping(74, NewznabStandardCategory.Other, "a.b.cd.image.twilights"); + caps.Categories.AddCategoryMapping(75, NewznabStandardCategory.Other, "a.b.cd.image.winapps"); + caps.Categories.AddCategoryMapping(76, NewznabStandardCategory.ConsoleXBox, "a.b.cd.image.xbox"); + caps.Categories.AddCategoryMapping(77, NewznabStandardCategory.Other, "a.b.cd.images"); + caps.Categories.AddCategoryMapping(78, NewznabStandardCategory.Other, "a.b.cd.images.games"); + caps.Categories.AddCategoryMapping(79, NewznabStandardCategory.Other, "a.b.cd.other"); + caps.Categories.AddCategoryMapping(80, NewznabStandardCategory.Other, "a.b.chakotay"); + caps.Categories.AddCategoryMapping(911, NewznabStandardCategory.Other, "a.b.chello"); + caps.Categories.AddCategoryMapping(81, NewznabStandardCategory.Other, "a.b.chello.nl"); + caps.Categories.AddCategoryMapping(82, NewznabStandardCategory.Other, "a.b.classic.tv.shows"); + caps.Categories.AddCategoryMapping(87, NewznabStandardCategory.Other, "a.b.comic-strips"); caps.Categories.AddCategoryMapping(83, NewznabStandardCategory.BooksComics, "a.b.comics"); + caps.Categories.AddCategoryMapping(84, NewznabStandardCategory.BooksComics, "a.b.comics.british"); + caps.Categories.AddCategoryMapping(85, NewznabStandardCategory.BooksComics, "a.b.comics.dcp"); + caps.Categories.AddCategoryMapping(86, NewznabStandardCategory.BooksComics, "a.b.comics.reposts"); + caps.Categories.AddCategoryMapping(88, NewznabStandardCategory.Other, "a.b.comp"); + caps.Categories.AddCategoryMapping(89, NewznabStandardCategory.Other, "a.b.console.ps3"); + caps.Categories.AddCategoryMapping(90, NewznabStandardCategory.Other, "a.b.conspiracy"); + caps.Categories.AddCategoryMapping(91, NewznabStandardCategory.Other, "a.b.coolkidweb"); + caps.Categories.AddCategoryMapping(92, NewznabStandardCategory.Other, "a.b.cores"); + caps.Categories.AddCategoryMapping(93, NewznabStandardCategory.Other, "a.b.criterion"); + caps.Categories.AddCategoryMapping(94, NewznabStandardCategory.Other, "a.b.crosspost2"); + caps.Categories.AddCategoryMapping(873, NewznabStandardCategory.Other, "a.b.csv"); + caps.Categories.AddCategoryMapping(95, NewznabStandardCategory.Other, "a.b.ctb"); + caps.Categories.AddCategoryMapping(96, NewznabStandardCategory.Other, "a.b.danskefilm"); + caps.Categories.AddCategoryMapping(97, NewznabStandardCategory.Other, "a.b.dc"); + caps.Categories.AddCategoryMapping(98, NewznabStandardCategory.Other, "a.b.ddf"); + caps.Categories.AddCategoryMapping(99, NewznabStandardCategory.Other, "a.b.de"); + caps.Categories.AddCategoryMapping(100, NewznabStandardCategory.Other, "a.b.department"); + caps.Categories.AddCategoryMapping(101, NewznabStandardCategory.Other, "a.b.department.pron"); + caps.Categories.AddCategoryMapping(102, NewznabStandardCategory.Other, "a.b.dgma"); + caps.Categories.AddCategoryMapping(103, NewznabStandardCategory.Other, "a.b.divx"); + caps.Categories.AddCategoryMapping(104, NewznabStandardCategory.Other, "a.b.divx.french"); + caps.Categories.AddCategoryMapping(105, NewznabStandardCategory.Other, "a.b.divx.german"); + caps.Categories.AddCategoryMapping(106, NewznabStandardCategory.Other, "a.b.divx.movies"); + caps.Categories.AddCategoryMapping(107, NewznabStandardCategory.Other, "a.b.divx.sweden"); + caps.Categories.AddCategoryMapping(108, NewznabStandardCategory.Other, "a.b.documentaries"); + caps.Categories.AddCategoryMapping(109, NewznabStandardCategory.Other, "a.b.documentaries.french"); + caps.Categories.AddCategoryMapping(110, NewznabStandardCategory.Other, "a.b.dominion"); + caps.Categories.AddCategoryMapping(111, NewznabStandardCategory.Other, "a.b.dominion.silly-group"); + caps.Categories.AddCategoryMapping(912, NewznabStandardCategory.Other, "a.b.downunder"); + caps.Categories.AddCategoryMapping(112, NewznabStandardCategory.Other, "a.b.dragonball"); + caps.Categories.AddCategoryMapping(113, NewznabStandardCategory.Other, "a.b.dream"); + caps.Categories.AddCategoryMapping(117, NewznabStandardCategory.Other, "a.b.dream-teamers"); + caps.Categories.AddCategoryMapping(114, NewznabStandardCategory.Other, "a.b.dream.movie"); + caps.Categories.AddCategoryMapping(115, NewznabStandardCategory.Other, "a.b.dream.musik"); + caps.Categories.AddCategoryMapping(116, NewznabStandardCategory.Other, "a.b.dreamcast"); + caps.Categories.AddCategoryMapping(118, NewznabStandardCategory.Other, "a.b.drummers"); + caps.Categories.AddCategoryMapping(119, NewznabStandardCategory.Other, "a.b.drwho"); + caps.Categories.AddCategoryMapping(120, NewznabStandardCategory.Other, "a.b.dump"); + caps.Categories.AddCategoryMapping(121, NewznabStandardCategory.Other, "a.b.dutch.ebook"); + caps.Categories.AddCategoryMapping(122, NewznabStandardCategory.Other, "a.b.dvd"); + caps.Categories.AddCategoryMapping(156, NewznabStandardCategory.Other, "a.b.dvd-covers"); + caps.Categories.AddCategoryMapping(159, NewznabStandardCategory.Other, "a.b.dvd-r"); + caps.Categories.AddCategoryMapping(123, NewznabStandardCategory.Other, "a.b.dvd.animation"); + caps.Categories.AddCategoryMapping(124, NewznabStandardCategory.Other, "a.b.dvd.anime"); + caps.Categories.AddCategoryMapping(125, NewznabStandardCategory.Other, "a.b.dvd.anime.repost"); + caps.Categories.AddCategoryMapping(126, NewznabStandardCategory.Other, "a.b.dvd.asian"); + caps.Categories.AddCategoryMapping(127, NewznabStandardCategory.Other, "a.b.dvd.classic.movies"); + caps.Categories.AddCategoryMapping(128, NewznabStandardCategory.Other, "a.b.dvd.classics"); + caps.Categories.AddCategoryMapping(129, NewznabStandardCategory.Other, "a.b.dvd.criterion"); + caps.Categories.AddCategoryMapping(130, NewznabStandardCategory.Other, "a.b.dvd.english"); + caps.Categories.AddCategoryMapping(131, NewznabStandardCategory.Other, "a.b.dvd.erotica"); + caps.Categories.AddCategoryMapping(132, NewznabStandardCategory.Other, "a.b.dvd.erotica.classics"); + caps.Categories.AddCategoryMapping(133, NewznabStandardCategory.Other, "a.b.dvd.erotica.male"); + caps.Categories.AddCategoryMapping(134, NewznabStandardCategory.Other, "a.b.dvd.french"); + caps.Categories.AddCategoryMapping(135, NewznabStandardCategory.Other, "a.b.dvd.french.repost"); + caps.Categories.AddCategoryMapping(136, NewznabStandardCategory.Other, "a.b.dvd.genealogy"); + caps.Categories.AddCategoryMapping(137, NewznabStandardCategory.Other, "a.b.dvd.german"); + caps.Categories.AddCategoryMapping(138, NewznabStandardCategory.Other, "a.b.dvd.german.repost"); + caps.Categories.AddCategoryMapping(139, NewznabStandardCategory.Other, "a.b.dvd.image"); + caps.Categories.AddCategoryMapping(140, NewznabStandardCategory.Other, "a.b.dvd.image.wii"); + caps.Categories.AddCategoryMapping(141, NewznabStandardCategory.Other, "a.b.dvd.italian"); + caps.Categories.AddCategoryMapping(142, NewznabStandardCategory.Other, "a.b.dvd.midnightmovies"); + caps.Categories.AddCategoryMapping(143, NewznabStandardCategory.Other, "a.b.dvd.misc"); + caps.Categories.AddCategoryMapping(144, NewznabStandardCategory.Other, "a.b.dvd.movies"); + caps.Categories.AddCategoryMapping(145, NewznabStandardCategory.Other, "a.b.dvd.music"); + caps.Categories.AddCategoryMapping(146, NewznabStandardCategory.Other, "a.b.dvd.music.classical"); + caps.Categories.AddCategoryMapping(147, NewznabStandardCategory.Other, "a.b.dvd.ntsc"); + caps.Categories.AddCategoryMapping(148, NewznabStandardCategory.Other, "a.b.dvd.repost"); + caps.Categories.AddCategoryMapping(149, NewznabStandardCategory.Other, "a.b.dvd.spanish"); + caps.Categories.AddCategoryMapping(150, NewznabStandardCategory.Other, "a.b.dvd.swedish"); + caps.Categories.AddCategoryMapping(151, NewznabStandardCategory.Other, "a.b.dvd.war"); + caps.Categories.AddCategoryMapping(152, NewznabStandardCategory.Other, "a.b.dvd2svcd"); + caps.Categories.AddCategoryMapping(153, NewznabStandardCategory.Other, "a.b.dvd9"); + caps.Categories.AddCategoryMapping(154, NewznabStandardCategory.Other, "a.b.dvdcore"); + caps.Categories.AddCategoryMapping(155, NewznabStandardCategory.Other, "a.b.dvdcovers"); + caps.Categories.AddCategoryMapping(157, NewznabStandardCategory.Other, "a.b.dvdnordic.org"); + caps.Categories.AddCategoryMapping(158, NewznabStandardCategory.Other, "a.b.dvdr"); + caps.Categories.AddCategoryMapping(168, NewznabStandardCategory.Other, "a.b.dvdr-tv"); + caps.Categories.AddCategoryMapping(160, NewznabStandardCategory.Other, "a.b.dvdr.asian"); + caps.Categories.AddCategoryMapping(161, NewznabStandardCategory.Other, "a.b.dvdr.french"); + caps.Categories.AddCategoryMapping(162, NewznabStandardCategory.Other, "a.b.dvdr.german"); + caps.Categories.AddCategoryMapping(163, NewznabStandardCategory.Other, "a.b.dvdr.repost"); + caps.Categories.AddCategoryMapping(164, NewznabStandardCategory.Other, "a.b.dvdrcore"); + caps.Categories.AddCategoryMapping(165, NewznabStandardCategory.Other, "a.b.dvdrip"); + caps.Categories.AddCategoryMapping(166, NewznabStandardCategory.Other, "a.b.dvdrs"); + caps.Categories.AddCategoryMapping(167, NewznabStandardCategory.Other, "a.b.dvdrs.pw"); + caps.Categories.AddCategoryMapping(169, NewznabStandardCategory.Other, "a.b.dvds"); + caps.Categories.AddCategoryMapping(171, NewznabStandardCategory.Books, "a.b.e-book"); + caps.Categories.AddCategoryMapping(172, NewznabStandardCategory.Books, "a.b.e-book.fantasy"); + caps.Categories.AddCategoryMapping(173, NewznabStandardCategory.Books, "a.b.e-book.flood"); + caps.Categories.AddCategoryMapping(176, NewznabStandardCategory.BooksForeign, "a.b.e-book.german"); + caps.Categories.AddCategoryMapping(177, NewznabStandardCategory.BooksMags, "a.b.e-book.magazines"); + caps.Categories.AddCategoryMapping(178, NewznabStandardCategory.Books, "a.b.e-book.rpg"); + caps.Categories.AddCategoryMapping(179, NewznabStandardCategory.Books, "a.b.e-book.technical"); + caps.Categories.AddCategoryMapping(180, NewznabStandardCategory.Books, "a.b.e-books"); + caps.Categories.AddCategoryMapping(182, NewznabStandardCategory.BooksForeign, "a.b.e-books.german"); + caps.Categories.AddCategoryMapping(170, NewznabStandardCategory.Books, "a.b.ebook"); + caps.Categories.AddCategoryMapping(174, NewznabStandardCategory.Books, "a.b.ebook.french"); + caps.Categories.AddCategoryMapping(175, NewznabStandardCategory.Books, "a.b.ebook.german"); + caps.Categories.AddCategoryMapping(913, NewznabStandardCategory.Books, "a.b.ebook.magazines"); + caps.Categories.AddCategoryMapping(181, NewznabStandardCategory.Books, "a.b.ebooks.german"); + caps.Categories.AddCategoryMapping(183, NewznabStandardCategory.Other, "a.b.echange-web"); + caps.Categories.AddCategoryMapping(184, NewznabStandardCategory.Other, "a.b.emulator"); + caps.Categories.AddCategoryMapping(185, NewznabStandardCategory.Other, "a.b.emulators"); + caps.Categories.AddCategoryMapping(186, NewznabStandardCategory.Other, "a.b.emulators.arcade"); + caps.Categories.AddCategoryMapping(187, NewznabStandardCategory.Other, "a.b.emulators.gameboy.advance"); + caps.Categories.AddCategoryMapping(188, NewznabStandardCategory.Other, "a.b.emulators.mame"); + caps.Categories.AddCategoryMapping(189, NewznabStandardCategory.Other, "a.b.emulators.misc"); + caps.Categories.AddCategoryMapping(190, NewznabStandardCategory.Other, "a.b.emulators.nintendo"); + caps.Categories.AddCategoryMapping(191, NewznabStandardCategory.Other, "a.b.emulators.nintendo-64"); + caps.Categories.AddCategoryMapping(192, NewznabStandardCategory.Other, "a.b.emulators.nintendo-ds"); + caps.Categories.AddCategoryMapping(193, NewznabStandardCategory.Other, "a.b.emulators.playstation"); + caps.Categories.AddCategoryMapping(930, NewznabStandardCategory.Other, "a.b.encrypted"); + caps.Categories.AddCategoryMapping(194, NewznabStandardCategory.BooksEBook, "a.b.epub"); + caps.Categories.AddCategoryMapping(195, NewznabStandardCategory.BooksEBook, "a.b.epub.dutch"); + caps.Categories.AddCategoryMapping(196, NewznabStandardCategory.XXX, "a.b.erotica"); + caps.Categories.AddCategoryMapping(206, NewznabStandardCategory.XXX, "a.b.erotica-underground"); + caps.Categories.AddCategoryMapping(197, NewznabStandardCategory.XXX, "a.b.erotica.collections.rars"); + caps.Categories.AddCategoryMapping(198, NewznabStandardCategory.XXX, "a.b.erotica.divx"); + caps.Categories.AddCategoryMapping(199, NewznabStandardCategory.XXXDVD, "a.b.erotica.dvd"); + caps.Categories.AddCategoryMapping(200, NewznabStandardCategory.XXX, "a.b.erotica.nospam.creampie"); + caps.Categories.AddCategoryMapping(201, NewznabStandardCategory.XXX, "a.b.erotica.older-woman"); + caps.Categories.AddCategoryMapping(202, NewznabStandardCategory.XXX, "a.b.erotica.pornstars.80s"); + caps.Categories.AddCategoryMapping(203, NewznabStandardCategory.XXX, "a.b.erotica.pornstars.90s"); + caps.Categories.AddCategoryMapping(928, NewznabStandardCategory.XXX, "a.b.erotica.sex"); + caps.Categories.AddCategoryMapping(204, NewznabStandardCategory.XXX, "a.b.erotica.urine"); + caps.Categories.AddCategoryMapping(205, NewznabStandardCategory.XXX, "a.b.erotica.vcd"); + caps.Categories.AddCategoryMapping(207, NewznabStandardCategory.Other, "a.b.etc"); + caps.Categories.AddCategoryMapping(914, NewznabStandardCategory.Other, "a.b.faded-glory"); + caps.Categories.AddCategoryMapping(208, NewznabStandardCategory.Other, "a.b.fetish.scat"); + caps.Categories.AddCategoryMapping(209, NewznabStandardCategory.Other, "a.b.film"); + caps.Categories.AddCategoryMapping(210, NewznabStandardCategory.Other, "a.b.filmclub"); + caps.Categories.AddCategoryMapping(211, NewznabStandardCategory.Other, "a.b.fitness"); + caps.Categories.AddCategoryMapping(871, NewznabStandardCategory.Other, "a.b.flowed"); + caps.Categories.AddCategoryMapping(941, NewznabStandardCategory.Other, "a.b.font"); + caps.Categories.AddCategoryMapping(212, NewznabStandardCategory.Other, "a.b.fonts"); + caps.Categories.AddCategoryMapping(213, NewznabStandardCategory.Other, "a.b.fonts.floods"); + caps.Categories.AddCategoryMapping(214, NewznabStandardCategory.Other, "a.b.formula1"); + caps.Categories.AddCategoryMapping(215, NewznabStandardCategory.Other, "a.b.freeware"); + caps.Categories.AddCategoryMapping(216, NewznabStandardCategory.Other, "a.b.freewareclub"); + caps.Categories.AddCategoryMapping(217, NewznabStandardCategory.Other, "a.b.french"); + caps.Categories.AddCategoryMapping(218, NewznabStandardCategory.Other, "a.b.french-tv"); + caps.Categories.AddCategoryMapping(949, NewznabStandardCategory.Other, "a.b.friends"); + caps.Categories.AddCategoryMapping(870, NewznabStandardCategory.Other, "a.b.frogs"); + caps.Categories.AddCategoryMapping(219, NewznabStandardCategory.Other, "a.b.fta"); + caps.Categories.AddCategoryMapping(220, NewznabStandardCategory.Other, "a.b.ftb"); + caps.Categories.AddCategoryMapping(221, NewznabStandardCategory.Other, "a.b.ftd"); + caps.Categories.AddCategoryMapping(222, NewznabStandardCategory.Other, "a.b.ftd.nzb"); + caps.Categories.AddCategoryMapping(223, NewznabStandardCategory.Other, "a.b.ftn"); + caps.Categories.AddCategoryMapping(224, NewznabStandardCategory.Other, "a.b.ftn.applications"); + caps.Categories.AddCategoryMapping(225, NewznabStandardCategory.Other, "a.b.ftn.games"); + caps.Categories.AddCategoryMapping(226, NewznabStandardCategory.Other, "a.b.ftn.movie"); + caps.Categories.AddCategoryMapping(227, NewznabStandardCategory.Other, "a.b.ftn.nzb"); + caps.Categories.AddCategoryMapping(228, NewznabStandardCategory.Other, "a.b.ftr"); + caps.Categories.AddCategoryMapping(229, NewznabStandardCategory.Other, "a.b.ftwclub"); + caps.Categories.AddCategoryMapping(230, NewznabStandardCategory.Other, "a.b.fz"); + caps.Categories.AddCategoryMapping(231, NewznabStandardCategory.Other, "a.b.galaxy4all"); + caps.Categories.AddCategoryMapping(232, NewznabStandardCategory.Other, "a.b.game"); + caps.Categories.AddCategoryMapping(233, NewznabStandardCategory.Console, "a.b.gamecube"); caps.Categories.AddCategoryMapping(234, NewznabStandardCategory.Console, "a.b.games"); + caps.Categories.AddCategoryMapping(235, NewznabStandardCategory.Console, "a.b.games.adventures"); + caps.Categories.AddCategoryMapping(236, NewznabStandardCategory.Console, "a.b.games.dox"); + caps.Categories.AddCategoryMapping(237, NewznabStandardCategory.Console, "a.b.games.encrypted"); + caps.Categories.AddCategoryMapping(238, NewznabStandardCategory.Console, "a.b.games.kidstuff"); + caps.Categories.AddCategoryMapping(239, NewznabStandardCategory.Console, "a.b.games.kidstuff.nl"); + caps.Categories.AddCategoryMapping(240, NewznabStandardCategory.Console, "a.b.games.nintendo3ds"); + caps.Categories.AddCategoryMapping(241, NewznabStandardCategory.Console, "a.b.games.nintendods"); + caps.Categories.AddCategoryMapping(242, NewznabStandardCategory.Console, "a.b.games.repost"); + caps.Categories.AddCategoryMapping(243, NewznabStandardCategory.Console, "a.b.games.reposts"); caps.Categories.AddCategoryMapping(244, NewznabStandardCategory.ConsoleWii, "a.b.games.wii"); + caps.Categories.AddCategoryMapping(245, NewznabStandardCategory.Console, "a.b.games.worms"); caps.Categories.AddCategoryMapping(246, NewznabStandardCategory.ConsoleXBox, "a.b.games.xbox"); - caps.Categories.AddCategoryMapping(247, NewznabStandardCategory.ConsoleXBox, "a.b.games.xbox360"); + caps.Categories.AddCategoryMapping(247, NewznabStandardCategory.ConsoleXBox360, "a.b.games.xbox360"); + caps.Categories.AddCategoryMapping(248, NewznabStandardCategory.Other, "a.b.german.divx"); + caps.Categories.AddCategoryMapping(249, NewznabStandardCategory.Other, "a.b.german.movies"); + caps.Categories.AddCategoryMapping(250, NewznabStandardCategory.Other, "a.b.german.mp3"); + caps.Categories.AddCategoryMapping(251, NewznabStandardCategory.Other, "a.b.ghosts"); + caps.Categories.AddCategoryMapping(252, NewznabStandardCategory.Other, "a.b.global.quake"); + caps.Categories.AddCategoryMapping(872, NewznabStandardCategory.Other, "a.b.goat"); + caps.Categories.AddCategoryMapping(253, NewznabStandardCategory.Other, "a.b.goonies"); + caps.Categories.AddCategoryMapping(254, NewznabStandardCategory.Other, "a.b.gougouland"); + caps.Categories.AddCategoryMapping(915, NewznabStandardCategory.Other, "a.b.graveyard"); + caps.Categories.AddCategoryMapping(255, NewznabStandardCategory.Other, "a.b.guitar.tab"); + caps.Categories.AddCategoryMapping(256, NewznabStandardCategory.Other, "a.b.hd.ger.moviez"); + caps.Categories.AddCategoryMapping(257, NewznabStandardCategory.Other, "a.b.hdtv"); + caps.Categories.AddCategoryMapping(258, NewznabStandardCategory.Other, "a.b.hdtv.french"); + caps.Categories.AddCategoryMapping(259, NewznabStandardCategory.Other, "a.b.hdtv.french.repost"); + caps.Categories.AddCategoryMapping(260, NewznabStandardCategory.Other, "a.b.hdtv.german"); + caps.Categories.AddCategoryMapping(261, NewznabStandardCategory.Other, "a.b.hdtv.german-audio"); + caps.Categories.AddCategoryMapping(262, NewznabStandardCategory.Other, "a.b.hdtv.repost"); + caps.Categories.AddCategoryMapping(263, NewznabStandardCategory.Other, "a.b.hdtv.tv-episodes"); + caps.Categories.AddCategoryMapping(264, NewznabStandardCategory.Other, "a.b.hdtv.x264"); + caps.Categories.AddCategoryMapping(265, NewznabStandardCategory.Other, "a.b.hdtv.x264.french"); + caps.Categories.AddCategoryMapping(266, NewznabStandardCategory.Other, "a.b.highspeed"); + caps.Categories.AddCategoryMapping(267, NewznabStandardCategory.Other, "a.b.hitoshirezu"); + caps.Categories.AddCategoryMapping(268, NewznabStandardCategory.Other, "a.b.holiday"); + caps.Categories.AddCategoryMapping(269, NewznabStandardCategory.Other, "a.b.hotrod"); + caps.Categories.AddCategoryMapping(270, NewznabStandardCategory.Other, "a.b.hou"); + caps.Categories.AddCategoryMapping(271, NewznabStandardCategory.Other, "a.b.howard-stern"); + caps.Categories.AddCategoryMapping(272, NewznabStandardCategory.Other, "a.b.howard-stern.on-demand"); + caps.Categories.AddCategoryMapping(273, NewznabStandardCategory.Other, "a.b.hunters"); + caps.Categories.AddCategoryMapping(274, NewznabStandardCategory.Other, "a.b.hunters.movie"); + caps.Categories.AddCategoryMapping(275, NewznabStandardCategory.Other, "a.b.hunters.musik"); + caps.Categories.AddCategoryMapping(277, NewznabStandardCategory.Other, "a.b.ibm-pc"); + caps.Categories.AddCategoryMapping(278, NewznabStandardCategory.Other, "a.b.ibm-pc.games"); + caps.Categories.AddCategoryMapping(279, NewznabStandardCategory.Other, "a.b.ibm-pc.warez"); + caps.Categories.AddCategoryMapping(276, NewznabStandardCategory.Other, "a.b.ibm.pc.warez"); + caps.Categories.AddCategoryMapping(280, NewznabStandardCategory.Other, "a.b.ijsklontje"); + caps.Categories.AddCategoryMapping(281, NewznabStandardCategory.Other, "a.b.illuminaten"); + caps.Categories.AddCategoryMapping(282, NewznabStandardCategory.Other, "a.b.image"); + caps.Categories.AddCategoryMapping(283, NewznabStandardCategory.Other, "a.b.image.cd.french"); + caps.Categories.AddCategoryMapping(284, NewznabStandardCategory.Other, "a.b.image.games"); + caps.Categories.AddCategoryMapping(285, NewznabStandardCategory.Other, "a.b.images"); + caps.Categories.AddCategoryMapping(287, NewznabStandardCategory.Other, "a.b.images.afos-fans"); + caps.Categories.AddCategoryMapping(286, NewznabStandardCategory.Other, "a.b.images.afos.fans"); + caps.Categories.AddCategoryMapping(288, NewznabStandardCategory.Other, "a.b.inner-sanctum"); + caps.Categories.AddCategoryMapping(289, NewznabStandardCategory.Other, "a.b.insiderz"); + caps.Categories.AddCategoryMapping(935, NewznabStandardCategory.Other, "a.b.ipod.videos"); + caps.Categories.AddCategoryMapping(936, NewznabStandardCategory.Other, "a.b.ipod.videos.movies"); + caps.Categories.AddCategoryMapping(290, NewznabStandardCategory.Other, "a.b.iso"); + caps.Categories.AddCategoryMapping(291, NewznabStandardCategory.Other, "a.b.japan.aidoru"); + caps.Categories.AddCategoryMapping(292, NewznabStandardCategory.Other, "a.b.japan.fashion.j-class"); + caps.Categories.AddCategoryMapping(293, NewznabStandardCategory.Other, "a.b.japan.iroppoi"); + caps.Categories.AddCategoryMapping(294, NewznabStandardCategory.Other, "a.b.jph"); + caps.Categories.AddCategoryMapping(295, NewznabStandardCategory.Other, "a.b.just4fun.nl"); + caps.Categories.AddCategoryMapping(296, NewznabStandardCategory.Other, "a.b.karagarga"); + caps.Categories.AddCategoryMapping(297, NewznabStandardCategory.Other, "a.b.kenpsx"); + caps.Categories.AddCategoryMapping(298, NewznabStandardCategory.Other, "a.b.kleverig"); + caps.Categories.AddCategoryMapping(299, NewznabStandardCategory.Other, "a.b.korea"); + caps.Categories.AddCategoryMapping(300, NewznabStandardCategory.Other, "a.b.laumovie.nl"); + caps.Categories.AddCategoryMapping(301, NewznabStandardCategory.Other, "a.b.librateam"); + caps.Categories.AddCategoryMapping(302, NewznabStandardCategory.Other, "a.b.lou"); + caps.Categories.AddCategoryMapping(303, NewznabStandardCategory.Other, "a.b.lucas-arts"); + caps.Categories.AddCategoryMapping(304, NewznabStandardCategory.Other, "a.b.mac"); + caps.Categories.AddCategoryMapping(305, NewznabStandardCategory.Other, "a.b.mac.applications"); + caps.Categories.AddCategoryMapping(306, NewznabStandardCategory.Other, "a.b.mac.apps"); + caps.Categories.AddCategoryMapping(307, NewznabStandardCategory.Other, "a.b.mac.audio"); + caps.Categories.AddCategoryMapping(308, NewznabStandardCategory.Other, "a.b.mac.cd-images"); + caps.Categories.AddCategoryMapping(309, NewznabStandardCategory.Other, "a.b.mac.games"); + caps.Categories.AddCategoryMapping(310, NewznabStandardCategory.Other, "a.b.mac.osx.apps"); + caps.Categories.AddCategoryMapping(311, NewznabStandardCategory.Other, "a.b.madcow.highspeed"); + caps.Categories.AddCategoryMapping(312, NewznabStandardCategory.Other, "a.b.magic"); + caps.Categories.AddCategoryMapping(313, NewznabStandardCategory.Other, "a.b.masternzb"); + caps.Categories.AddCategoryMapping(314, NewznabStandardCategory.Other, "a.b.matrix"); + caps.Categories.AddCategoryMapping(315, NewznabStandardCategory.Other, "a.b.misc"); + caps.Categories.AddCategoryMapping(929, NewznabStandardCategory.Other, "a.b.misc.xxx"); + caps.Categories.AddCategoryMapping(316, NewznabStandardCategory.Other, "a.b.mma"); + caps.Categories.AddCategoryMapping(317, NewznabStandardCategory.Other, "a.b.models"); + caps.Categories.AddCategoryMapping(318, NewznabStandardCategory.Other, "a.b.mojo"); + caps.Categories.AddCategoryMapping(319, NewznabStandardCategory.Other, "a.b.mom"); + caps.Categories.AddCategoryMapping(320, NewznabStandardCategory.Other, "a.b.mom.xxx"); + caps.Categories.AddCategoryMapping(321, NewznabStandardCategory.Other, "a.b.monster-movies"); + caps.Categories.AddCategoryMapping(322, NewznabStandardCategory.Other, "a.b.monter-movies"); + caps.Categories.AddCategoryMapping(323, NewznabStandardCategory.Other, "a.b.moovee"); + caps.Categories.AddCategoryMapping(324, NewznabStandardCategory.Other, "a.b.mou"); + caps.Categories.AddCategoryMapping(325, NewznabStandardCategory.Movies, "a.b.movie"); + caps.Categories.AddCategoryMapping(326, NewznabStandardCategory.Other, "a.b.moviereleases.nl"); caps.Categories.AddCategoryMapping(327, NewznabStandardCategory.Movies, "a.b.movies"); + caps.Categories.AddCategoryMapping(328, NewznabStandardCategory.Movies, "a.b.movies.arthouse"); + caps.Categories.AddCategoryMapping(329, NewznabStandardCategory.Movies, "a.b.movies.classic"); + caps.Categories.AddCategoryMapping(330, NewznabStandardCategory.Movies, "a.b.movies.divx"); + caps.Categories.AddCategoryMapping(331, NewznabStandardCategory.MoviesForeign, "a.b.movies.divx.france"); + caps.Categories.AddCategoryMapping(332, NewznabStandardCategory.MoviesForeign, "a.b.movies.divx.french"); + caps.Categories.AddCategoryMapping(333, NewznabStandardCategory.MoviesForeign, "a.b.movies.divx.french.old"); + caps.Categories.AddCategoryMapping(334, NewznabStandardCategory.MoviesForeign, "a.b.movies.divx.french.reposts"); + caps.Categories.AddCategoryMapping(335, NewznabStandardCategory.MoviesForeign, "a.b.movies.divx.french.vost"); + caps.Categories.AddCategoryMapping(336, NewznabStandardCategory.MoviesForeign, "a.b.movies.divx.german"); + caps.Categories.AddCategoryMapping(337, NewznabStandardCategory.Movies, "a.b.movies.divx.repost"); + caps.Categories.AddCategoryMapping(338, NewznabStandardCategory.MoviesForeign, "a.b.movies.divx.russian"); + caps.Categories.AddCategoryMapping(339, NewznabStandardCategory.MoviesForeign, "a.b.movies.dutch"); + caps.Categories.AddCategoryMapping(340, NewznabStandardCategory.MoviesForeign, "a.b.movies.dutch.repost"); + caps.Categories.AddCategoryMapping(341, NewznabStandardCategory.Movies, "a.b.movies.dvd"); + caps.Categories.AddCategoryMapping(342, NewznabStandardCategory.Movies, "a.b.movies.dvd-r"); + caps.Categories.AddCategoryMapping(343, NewznabStandardCategory.XXX, "a.b.movies.erotica"); + caps.Categories.AddCategoryMapping(344, NewznabStandardCategory.MoviesForeign, "a.b.movies.french"); + caps.Categories.AddCategoryMapping(943, NewznabStandardCategory.Movies, "a.b.movies.from.hell"); + caps.Categories.AddCategoryMapping(345, NewznabStandardCategory.Movies, "a.b.movies.gay"); + caps.Categories.AddCategoryMapping(346, NewznabStandardCategory.MoviesForeign, "a.b.movies.german"); + caps.Categories.AddCategoryMapping(347, NewznabStandardCategory.MoviesForeign, "a.b.movies.italian.divx"); + caps.Categories.AddCategoryMapping(348, NewznabStandardCategory.Movies, "a.b.movies.kidstuff"); + caps.Categories.AddCategoryMapping(349, NewznabStandardCategory.Movies, "a.b.movies.martial.arts"); + caps.Categories.AddCategoryMapping(350, NewznabStandardCategory.Movies, "a.b.movies.mkv"); + caps.Categories.AddCategoryMapping(351, NewznabStandardCategory.Movies, "a.b.movies.purity"); + caps.Categories.AddCategoryMapping(352, NewznabStandardCategory.Movies, "a.b.movies.repost"); + caps.Categories.AddCategoryMapping(353, NewznabStandardCategory.Movies, "a.b.movies.shadowrealm"); + caps.Categories.AddCategoryMapping(354, NewznabStandardCategory.MoviesForeign, "a.b.movies.spanish"); + caps.Categories.AddCategoryMapping(355, NewznabStandardCategory.MoviesForeign, "a.b.movies.swedish"); + caps.Categories.AddCategoryMapping(356, NewznabStandardCategory.Movies, "a.b.movies.thelostmovies"); + caps.Categories.AddCategoryMapping(357, NewznabStandardCategory.Movies, "a.b.movies.war"); caps.Categories.AddCategoryMapping(358, NewznabStandardCategory.Movies, "a.b.movies.x264"); + caps.Categories.AddCategoryMapping(359, NewznabStandardCategory.MoviesSD, "a.b.movies.xvid"); + caps.Categories.AddCategoryMapping(360, NewznabStandardCategory.Other, "a.b.movies.zeromovies"); + caps.Categories.AddCategoryMapping(361, NewznabStandardCategory.Other, "a.b.moviez.ger"); + caps.Categories.AddCategoryMapping(362, NewznabStandardCategory.Other, "a.b.mp3"); + caps.Categories.AddCategoryMapping(363, NewznabStandardCategory.Other, "a.b.mp3.abooks"); + caps.Categories.AddCategoryMapping(364, NewznabStandardCategory.Other, "a.b.mp3.audiobooks"); + caps.Categories.AddCategoryMapping(365, NewznabStandardCategory.Other, "a.b.mp3.audiobooks.highspeed"); + caps.Categories.AddCategoryMapping(366, NewznabStandardCategory.Other, "a.b.mp3.audiobooks.repost"); + caps.Categories.AddCategoryMapping(367, NewznabStandardCategory.Other, "a.b.mp3.bootlegs"); + caps.Categories.AddCategoryMapping(368, NewznabStandardCategory.Other, "a.b.mp3.comedy"); + caps.Categories.AddCategoryMapping(369, NewznabStandardCategory.Other, "a.b.mp3.complete_cd"); + caps.Categories.AddCategoryMapping(370, NewznabStandardCategory.Other, "a.b.mp3.dance"); + caps.Categories.AddCategoryMapping(371, NewznabStandardCategory.Other, "a.b.mp3.full_albums"); + caps.Categories.AddCategoryMapping(372, NewznabStandardCategory.Other, "a.b.mp3.german.hoerbuecher"); + caps.Categories.AddCategoryMapping(373, NewznabStandardCategory.Other, "a.b.mp3.hoerspiele"); + caps.Categories.AddCategoryMapping(374, NewznabStandardCategory.Other, "a.b.mpeg"); + caps.Categories.AddCategoryMapping(375, NewznabStandardCategory.Other, "a.b.mpeg.video"); + caps.Categories.AddCategoryMapping(376, NewznabStandardCategory.Other, "a.b.mpeg.video.music"); + caps.Categories.AddCategoryMapping(377, NewznabStandardCategory.Other, "a.b.mpeg.videos"); + caps.Categories.AddCategoryMapping(378, NewznabStandardCategory.Other, "a.b.mpeg.videos.country"); + caps.Categories.AddCategoryMapping(379, NewznabStandardCategory.Other, "a.b.mpeg.videos.german"); + caps.Categories.AddCategoryMapping(380, NewznabStandardCategory.Other, "a.b.mpeg.videos.music"); + caps.Categories.AddCategoryMapping(864, NewznabStandardCategory.Other, "a.b.ms-windows"); + caps.Categories.AddCategoryMapping(381, NewznabStandardCategory.Other, "a.b.mst3k.riffs.etc.nopasswords"); + caps.Categories.AddCategoryMapping(382, NewznabStandardCategory.Other, "a.b.multimedia"); + caps.Categories.AddCategoryMapping(383, NewznabStandardCategory.Other, "a.b.multimedia.24"); + caps.Categories.AddCategoryMapping(384, NewznabStandardCategory.Other, "a.b.multimedia.alias"); + caps.Categories.AddCategoryMapping(385, NewznabStandardCategory.Other, "a.b.multimedia.anime"); + caps.Categories.AddCategoryMapping(386, NewznabStandardCategory.Other, "a.b.multimedia.anime.highspeed"); + caps.Categories.AddCategoryMapping(387, NewznabStandardCategory.Other, "a.b.multimedia.anime.repost"); + caps.Categories.AddCategoryMapping(388, NewznabStandardCategory.Other, "a.b.multimedia.aviation"); + caps.Categories.AddCategoryMapping(389, NewznabStandardCategory.Other, "a.b.multimedia.babylon5"); + caps.Categories.AddCategoryMapping(390, NewznabStandardCategory.Other, "a.b.multimedia.bdsm"); + caps.Categories.AddCategoryMapping(391, NewznabStandardCategory.Other, "a.b.multimedia.buffy-v-slayer"); + caps.Categories.AddCategoryMapping(392, NewznabStandardCategory.Other, "a.b.multimedia.cartoons"); + caps.Categories.AddCategoryMapping(393, NewznabStandardCategory.Other, "a.b.multimedia.cartoons.looneytunes"); + caps.Categories.AddCategoryMapping(394, NewznabStandardCategory.Other, "a.b.multimedia.cartoons.repost"); + caps.Categories.AddCategoryMapping(395, NewznabStandardCategory.Other, "a.b.multimedia.charmed"); + caps.Categories.AddCategoryMapping(396, NewznabStandardCategory.Other, "a.b.multimedia.chinese"); + caps.Categories.AddCategoryMapping(398, NewznabStandardCategory.Other, "a.b.multimedia.classic-films"); + caps.Categories.AddCategoryMapping(397, NewznabStandardCategory.Other, "a.b.multimedia.classical.treblevoices"); + caps.Categories.AddCategoryMapping(399, NewznabStandardCategory.Other, "a.b.multimedia.comedy"); + caps.Categories.AddCategoryMapping(400, NewznabStandardCategory.Other, "a.b.multimedia.comedy.british"); + caps.Categories.AddCategoryMapping(401, NewznabStandardCategory.Other, "a.b.multimedia.cooking"); + caps.Categories.AddCategoryMapping(402, NewznabStandardCategory.Other, "a.b.multimedia.csi"); + caps.Categories.AddCategoryMapping(403, NewznabStandardCategory.Other, "a.b.multimedia.disney"); + caps.Categories.AddCategoryMapping(404, NewznabStandardCategory.Other, "a.b.multimedia.disney.parks"); + caps.Categories.AddCategoryMapping(405, NewznabStandardCategory.Other, "a.b.multimedia.divx"); + caps.Categories.AddCategoryMapping(406, NewznabStandardCategory.Other, "a.b.multimedia.documentaries"); + caps.Categories.AddCategoryMapping(407, NewznabStandardCategory.Other, "a.b.multimedia.elvispresley"); + caps.Categories.AddCategoryMapping(408, NewznabStandardCategory.Other, "a.b.multimedia.erotic.playboy"); caps.Categories.AddCategoryMapping(409, NewznabStandardCategory.XXX, "a.b.multimedia.erotica"); - caps.Categories.AddCategoryMapping(587, NewznabStandardCategory.AudioMP3, "a.b.sounds.lossless"); + caps.Categories.AddCategoryMapping(410, NewznabStandardCategory.XXX, "a.b.multimedia.erotica.amateur"); + caps.Categories.AddCategoryMapping(411, NewznabStandardCategory.XXX, "a.b.multimedia.erotica.amature"); + caps.Categories.AddCategoryMapping(412, NewznabStandardCategory.XXX, "a.b.multimedia.erotica.anime"); + caps.Categories.AddCategoryMapping(413, NewznabStandardCategory.XXX, "a.b.multimedia.erotica.asian"); + caps.Categories.AddCategoryMapping(414, NewznabStandardCategory.XXX, "a.b.multimedia.erotica.black"); + caps.Categories.AddCategoryMapping(415, NewznabStandardCategory.XXX, "a.b.multimedia.erotica.interracial"); + caps.Categories.AddCategoryMapping(416, NewznabStandardCategory.XXX, "a.b.multimedia.erotica.lesbians"); + caps.Categories.AddCategoryMapping(417, NewznabStandardCategory.XXX, "a.b.multimedia.erotica.male"); + caps.Categories.AddCategoryMapping(418, NewznabStandardCategory.XXX, "a.b.multimedia.erotica.male.repost"); + caps.Categories.AddCategoryMapping(419, NewznabStandardCategory.XXX, "a.b.multimedia.erotica.plumpers"); + caps.Categories.AddCategoryMapping(420, NewznabStandardCategory.XXX, "a.b.multimedia.erotica.repost"); + caps.Categories.AddCategoryMapping(421, NewznabStandardCategory.XXX, "a.b.multimedia.erotica.strap-on-sex"); + caps.Categories.AddCategoryMapping(422, NewznabStandardCategory.XXX, "a.b.multimedia.erotica.transexuals"); + caps.Categories.AddCategoryMapping(423, NewznabStandardCategory.XXX, "a.b.multimedia.erotica.transsexuals"); + caps.Categories.AddCategoryMapping(424, NewznabStandardCategory.XXX, "a.b.multimedia.erotica.urine"); + caps.Categories.AddCategoryMapping(425, NewznabStandardCategory.XXX, "a.b.multimedia.erotica.voyeurism"); + caps.Categories.AddCategoryMapping(426, NewznabStandardCategory.Other, "a.b.multimedia.fitness"); + caps.Categories.AddCategoryMapping(427, NewznabStandardCategory.Other, "a.b.multimedia.futurama"); + caps.Categories.AddCategoryMapping(428, NewznabStandardCategory.Other, "a.b.multimedia.horror"); + caps.Categories.AddCategoryMapping(429, NewznabStandardCategory.Other, "a.b.multimedia.japanese"); + caps.Categories.AddCategoryMapping(430, NewznabStandardCategory.Other, "a.b.multimedia.japanese.repost"); + caps.Categories.AddCategoryMapping(431, NewznabStandardCategory.Other, "a.b.multimedia.late-night-talkshows"); + caps.Categories.AddCategoryMapping(432, NewznabStandardCategory.Other, "a.b.multimedia.mst3k"); + caps.Categories.AddCategoryMapping(433, NewznabStandardCategory.Other, "a.b.multimedia.musicals"); + caps.Categories.AddCategoryMapping(434, NewznabStandardCategory.XXX, "a.b.multimedia.nude.celebrities"); + caps.Categories.AddCategoryMapping(435, NewznabStandardCategory.Other, "a.b.multimedia.prince"); + caps.Categories.AddCategoryMapping(436, NewznabStandardCategory.Other, "a.b.multimedia.rail"); + caps.Categories.AddCategoryMapping(437, NewznabStandardCategory.Other, "a.b.multimedia.rap"); + caps.Categories.AddCategoryMapping(438, NewznabStandardCategory.Other, "a.b.multimedia.repost"); + caps.Categories.AddCategoryMapping(439, NewznabStandardCategory.Other, "a.b.multimedia.reposts"); + caps.Categories.AddCategoryMapping(441, NewznabStandardCategory.Other, "a.b.multimedia.sci-fi"); + caps.Categories.AddCategoryMapping(440, NewznabStandardCategory.Other, "a.b.multimedia.scifi"); + caps.Categories.AddCategoryMapping(442, NewznabStandardCategory.Other, "a.b.multimedia.scifi-and-fantasy"); + caps.Categories.AddCategoryMapping(443, NewznabStandardCategory.Other, "a.b.multimedia.sd-6"); + caps.Categories.AddCategoryMapping(444, NewznabStandardCategory.Other, "a.b.multimedia.sitcoms"); + caps.Categories.AddCategoryMapping(445, NewznabStandardCategory.Other, "a.b.multimedia.smallville"); + caps.Categories.AddCategoryMapping(446, NewznabStandardCategory.Other, "a.b.multimedia.sports"); + caps.Categories.AddCategoryMapping(447, NewznabStandardCategory.Other, "a.b.multimedia.startrek"); + caps.Categories.AddCategoryMapping(449, NewznabStandardCategory.Other, "a.b.multimedia.teen-idols"); + caps.Categories.AddCategoryMapping(448, NewznabStandardCategory.Other, "a.b.multimedia.teen.male"); + caps.Categories.AddCategoryMapping(450, NewznabStandardCategory.Other, "a.b.multimedia.thai"); + caps.Categories.AddCategoryMapping(451, NewznabStandardCategory.Other, "a.b.multimedia.utilities"); + caps.Categories.AddCategoryMapping(452, NewznabStandardCategory.Other, "a.b.multimedia.vietnamese"); + caps.Categories.AddCategoryMapping(453, NewznabStandardCategory.Other, "a.b.multimedia.vintage-film"); + caps.Categories.AddCategoryMapping(454, NewznabStandardCategory.Other, "a.b.multimedia.vintage-film.pre-1960"); + caps.Categories.AddCategoryMapping(455, NewznabStandardCategory.Other, "a.b.multimedia.vintage-tv"); + caps.Categories.AddCategoryMapping(456, NewznabStandardCategory.Audio, "a.b.music"); + caps.Categories.AddCategoryMapping(457, NewznabStandardCategory.Audio, "a.b.music.classical"); + caps.Categories.AddCategoryMapping(458, NewznabStandardCategory.Audio, "a.b.music.dvd"); + caps.Categories.AddCategoryMapping(459, NewznabStandardCategory.Audio, "a.b.music.heavy-metal"); + caps.Categories.AddCategoryMapping(460, NewznabStandardCategory.Audio, "a.b.music.jungle"); + caps.Categories.AddCategoryMapping(461, NewznabStandardCategory.Audio, "a.b.music.makers.samples"); + caps.Categories.AddCategoryMapping(462, NewznabStandardCategory.AudioMP3, "a.b.music.mp3"); + caps.Categories.AddCategoryMapping(463, NewznabStandardCategory.Audio, "a.b.music.oasis"); + caps.Categories.AddCategoryMapping(464, NewznabStandardCategory.Audio, "a.b.music.springsteen"); + caps.Categories.AddCategoryMapping(465, NewznabStandardCategory.Audio, "a.b.music.techno"); + caps.Categories.AddCategoryMapping(466, NewznabStandardCategory.AudioVideo, "a.b.music.videos"); + caps.Categories.AddCategoryMapping(467, NewznabStandardCategory.Other, "a.b.mutlimedia"); + caps.Categories.AddCategoryMapping(468, NewznabStandardCategory.Other, "a.b.nerodigital"); + caps.Categories.AddCategoryMapping(469, NewznabStandardCategory.Other, "a.b.new-movies"); + caps.Categories.AddCategoryMapping(470, NewznabStandardCategory.Other, "a.b.newzbin"); + caps.Categories.AddCategoryMapping(875, NewznabStandardCategory.Other, "a.b.newznzb.alpha"); + caps.Categories.AddCategoryMapping(876, NewznabStandardCategory.Other, "a.b.newznzb.beta"); + caps.Categories.AddCategoryMapping(877, NewznabStandardCategory.Other, "a.b.newznzb.bravo"); + caps.Categories.AddCategoryMapping(878, NewznabStandardCategory.Other, "a.b.newznzb.charlie"); + caps.Categories.AddCategoryMapping(879, NewznabStandardCategory.Other, "a.b.newznzb.delta"); + caps.Categories.AddCategoryMapping(880, NewznabStandardCategory.Other, "a.b.newznzb.echo"); + caps.Categories.AddCategoryMapping(881, NewznabStandardCategory.Other, "a.b.newznzb.foxtrot"); + caps.Categories.AddCategoryMapping(882, NewznabStandardCategory.Other, "a.b.newznzb.golf"); + caps.Categories.AddCategoryMapping(883, NewznabStandardCategory.Other, "a.b.newznzb.hotel"); + caps.Categories.AddCategoryMapping(884, NewznabStandardCategory.Other, "a.b.newznzb.india"); + caps.Categories.AddCategoryMapping(885, NewznabStandardCategory.Other, "a.b.newznzb.juliet"); + caps.Categories.AddCategoryMapping(886, NewznabStandardCategory.Other, "a.b.newznzb.juliett"); + caps.Categories.AddCategoryMapping(887, NewznabStandardCategory.Other, "a.b.newznzb.kilo"); + caps.Categories.AddCategoryMapping(888, NewznabStandardCategory.Other, "a.b.newznzb.lima"); + caps.Categories.AddCategoryMapping(889, NewznabStandardCategory.Other, "a.b.newznzb.mike"); + caps.Categories.AddCategoryMapping(890, NewznabStandardCategory.Other, "a.b.newznzb.november"); + caps.Categories.AddCategoryMapping(891, NewznabStandardCategory.Other, "a.b.newznzb.novemeber"); + caps.Categories.AddCategoryMapping(892, NewznabStandardCategory.Other, "a.b.newznzb.oscar"); + caps.Categories.AddCategoryMapping(893, NewznabStandardCategory.Other, "a.b.newznzb.papa"); + caps.Categories.AddCategoryMapping(894, NewznabStandardCategory.Other, "a.b.newznzb.quebec"); + caps.Categories.AddCategoryMapping(895, NewznabStandardCategory.Other, "a.b.newznzb.romeo"); + caps.Categories.AddCategoryMapping(896, NewznabStandardCategory.Other, "a.b.newznzb.sierra"); + caps.Categories.AddCategoryMapping(897, NewznabStandardCategory.Other, "a.b.newznzb.tango"); + caps.Categories.AddCategoryMapping(898, NewznabStandardCategory.Other, "a.b.newznzb.uniform"); + caps.Categories.AddCategoryMapping(899, NewznabStandardCategory.Other, "a.b.newznzb.victor"); + caps.Categories.AddCategoryMapping(900, NewznabStandardCategory.Other, "a.b.newznzb.whiskey"); + caps.Categories.AddCategoryMapping(901, NewznabStandardCategory.Other, "a.b.newznzb.xray"); + caps.Categories.AddCategoryMapping(902, NewznabStandardCategory.Other, "a.b.newznzb.yankee"); + caps.Categories.AddCategoryMapping(903, NewznabStandardCategory.Other, "a.b.newznzb.zulu"); + caps.Categories.AddCategoryMapping(471, NewznabStandardCategory.Other, "a.b.nfonews"); + caps.Categories.AddCategoryMapping(472, NewznabStandardCategory.Other, "a.b.nintendo.ds"); + caps.Categories.AddCategoryMapping(473, NewznabStandardCategory.Other, "a.b.nirpaia"); + caps.Categories.AddCategoryMapping(474, NewznabStandardCategory.Other, "a.b.nl"); + caps.Categories.AddCategoryMapping(475, NewznabStandardCategory.Other, "a.b.noprobs"); + caps.Categories.AddCategoryMapping(476, NewznabStandardCategory.Other, "a.b.nordic.apps"); + caps.Categories.AddCategoryMapping(477, NewznabStandardCategory.Other, "a.b.nordic.dvd"); + caps.Categories.AddCategoryMapping(478, NewznabStandardCategory.Other, "a.b.nordic.dvdr"); + caps.Categories.AddCategoryMapping(479, NewznabStandardCategory.Other, "a.b.nordic.password.protected"); + caps.Categories.AddCategoryMapping(480, NewznabStandardCategory.Other, "a.b.nordic.xvid"); + caps.Categories.AddCategoryMapping(481, NewznabStandardCategory.Other, "a.b.norge"); + caps.Categories.AddCategoryMapping(482, NewznabStandardCategory.Other, "a.b.nospam.cheerleaders"); + caps.Categories.AddCategoryMapping(483, NewznabStandardCategory.Other, "a.b.nospam.female.bodyhair"); + caps.Categories.AddCategoryMapping(484, NewznabStandardCategory.Other, "a.b.nospam.female.bodyhair.pubes"); + caps.Categories.AddCategoryMapping(485, NewznabStandardCategory.Other, "a.b.nospam.female.short-hair"); + caps.Categories.AddCategoryMapping(486, NewznabStandardCategory.Other, "a.b.nospam.multimedia.erotica"); + caps.Categories.AddCategoryMapping(487, NewznabStandardCategory.Other, "a.b.nospam.multimedia.facials"); + caps.Categories.AddCategoryMapping(488, NewznabStandardCategory.Other, "a.b.nospam.prao"); + caps.Categories.AddCategoryMapping(489, NewznabStandardCategory.Other, "a.b.novarip"); + caps.Categories.AddCategoryMapping(490, NewznabStandardCategory.Other, "a.b.nzb"); + caps.Categories.AddCategoryMapping(491, NewznabStandardCategory.Other, "a.b.nzb-nordic"); + caps.Categories.AddCategoryMapping(916, NewznabStandardCategory.Other, "a.b.nzbc"); + caps.Categories.AddCategoryMapping(492, NewznabStandardCategory.Other, "a.b.nzbpirates"); + caps.Categories.AddCategoryMapping(493, NewznabStandardCategory.Other, "a.b.nzbs4u"); + caps.Categories.AddCategoryMapping(494, NewznabStandardCategory.Other, "a.b.nzm"); + caps.Categories.AddCategoryMapping(495, NewznabStandardCategory.Other, "a.b.old.games"); + caps.Categories.AddCategoryMapping(496, NewznabStandardCategory.Other, "a.b.operaworld"); + caps.Categories.AddCategoryMapping(497, NewznabStandardCategory.Other, "a.b.opie-and-anthony"); + caps.Categories.AddCategoryMapping(917, NewznabStandardCategory.Other, "a.b.outlaws"); + caps.Categories.AddCategoryMapping(498, NewznabStandardCategory.Other, "a.b.paranormal"); + caps.Categories.AddCategoryMapping(499, NewznabStandardCategory.Other, "a.b.paxer"); + caps.Categories.AddCategoryMapping(500, NewznabStandardCategory.Other, "a.b.pcgame"); + caps.Categories.AddCategoryMapping(501, NewznabStandardCategory.Other, "a.b.picasa_benelux_team"); + caps.Categories.AddCategoryMapping(502, NewznabStandardCategory.Other, "a.b.pictures"); + caps.Categories.AddCategoryMapping(503, NewznabStandardCategory.Other, "a.b.pictures.bluebird"); + caps.Categories.AddCategoryMapping(504, NewznabStandardCategory.Other, "a.b.pictures.bluebird.reposts"); + caps.Categories.AddCategoryMapping(505, NewznabStandardCategory.Other, "a.b.pictures.cd-covers"); + caps.Categories.AddCategoryMapping(510, NewznabStandardCategory.Other, "a.b.pictures.comic-strips"); + caps.Categories.AddCategoryMapping(506, NewznabStandardCategory.Other, "a.b.pictures.comics"); + caps.Categories.AddCategoryMapping(507, NewznabStandardCategory.Other, "a.b.pictures.comics.complete"); + caps.Categories.AddCategoryMapping(508, NewznabStandardCategory.Other, "a.b.pictures.comics.dcp"); + caps.Categories.AddCategoryMapping(509, NewznabStandardCategory.Other, "a.b.pictures.comics.reposts"); + caps.Categories.AddCategoryMapping(511, NewznabStandardCategory.Other, "a.b.pictures.diva"); + caps.Categories.AddCategoryMapping(918, NewznabStandardCategory.Other, "a.b.pictures.earlmiller"); + caps.Categories.AddCategoryMapping(512, NewznabStandardCategory.XXXImageSet, "a.b.pictures.erotica"); + caps.Categories.AddCategoryMapping(513, NewznabStandardCategory.XXXImageSet, "a.b.pictures.erotica.anime"); + caps.Categories.AddCategoryMapping(514, NewznabStandardCategory.XXXImageSet, "a.b.pictures.erotica.comics"); + caps.Categories.AddCategoryMapping(515, NewznabStandardCategory.XXXImageSet, "a.b.pictures.erotica.femdom"); + caps.Categories.AddCategoryMapping(516, NewznabStandardCategory.XXXImageSet, "a.b.pictures.erotica.fetish.latex"); + caps.Categories.AddCategoryMapping(517, NewznabStandardCategory.XXXImageSet, "a.b.pictures.erotica.lactating"); + caps.Categories.AddCategoryMapping(518, NewznabStandardCategory.XXXImageSet, "a.b.pictures.erotica.scanmaster"); + caps.Categories.AddCategoryMapping(519, NewznabStandardCategory.XXXImageSet, "a.b.pictures.erotica.smoking"); + caps.Categories.AddCategoryMapping(520, NewznabStandardCategory.XXXImageSet, "a.b.pictures.erotica.spanking"); + caps.Categories.AddCategoryMapping(521, NewznabStandardCategory.XXXImageSet, "a.b.pictures.erotica.urine"); + caps.Categories.AddCategoryMapping(522, NewznabStandardCategory.Other, "a.b.pictures.manga"); + caps.Categories.AddCategoryMapping(523, NewznabStandardCategory.Other, "a.b.pictures.nude"); + caps.Categories.AddCategoryMapping(524, NewznabStandardCategory.Other, "a.b.pictures.photo-modeling"); + caps.Categories.AddCategoryMapping(525, NewznabStandardCategory.Other, "a.b.pictures.rika-nishimura"); + caps.Categories.AddCategoryMapping(526, NewznabStandardCategory.Other, "a.b.pictures.sierra"); + caps.Categories.AddCategoryMapping(527, NewznabStandardCategory.Other, "a.b.pictures.sierra.offtopic"); + caps.Categories.AddCategoryMapping(528, NewznabStandardCategory.Other, "a.b.pictures.tinygirls"); + caps.Categories.AddCategoryMapping(529, NewznabStandardCategory.Other, "a.b.pictures.utilities"); + caps.Categories.AddCategoryMapping(530, NewznabStandardCategory.Other, "a.b.pictures.vintage.magazines"); + caps.Categories.AddCategoryMapping(531, NewznabStandardCategory.Other, "a.b.pictures.wallpaper"); + caps.Categories.AddCategoryMapping(532, NewznabStandardCategory.Other, "a.b.pictures.youth-and-beauty"); + caps.Categories.AddCategoryMapping(919, NewznabStandardCategory.Other, "a.b.pl.divx"); + caps.Categories.AddCategoryMapping(533, NewznabStandardCategory.Other, "a.b.pl.multimedia"); + caps.Categories.AddCategoryMapping(534, NewznabStandardCategory.Other, "a.b.pl.multimedia.reposts"); + caps.Categories.AddCategoryMapping(535, NewznabStandardCategory.Other, "a.b.pocketpc.gps"); + caps.Categories.AddCategoryMapping(536, NewznabStandardCategory.Other, "a.b.pro-wrestling"); + caps.Categories.AddCategoryMapping(537, NewznabStandardCategory.Other, "a.b.psp"); + caps.Categories.AddCategoryMapping(538, NewznabStandardCategory.Other, "a.b.punk"); + caps.Categories.AddCategoryMapping(539, NewznabStandardCategory.Other, "a.b.putteam"); + caps.Categories.AddCategoryMapping(540, NewznabStandardCategory.Other, "a.b.pwp"); + caps.Categories.AddCategoryMapping(541, NewznabStandardCategory.Other, "a.b.rar.pw-required"); + caps.Categories.AddCategoryMapping(869, NewznabStandardCategory.Other, "a.b.ratcave"); + caps.Categories.AddCategoryMapping(542, NewznabStandardCategory.Other, "a.b.ratdvd.german"); + caps.Categories.AddCategoryMapping(543, NewznabStandardCategory.Other, "a.b.remixes.mp3"); + caps.Categories.AddCategoryMapping(544, NewznabStandardCategory.Other, "a.b.residents"); + caps.Categories.AddCategoryMapping(545, NewznabStandardCategory.Other, "a.b.rock-n-roll"); + caps.Categories.AddCategoryMapping(546, NewznabStandardCategory.Other, "a.b.roger"); + caps.Categories.AddCategoryMapping(547, NewznabStandardCategory.Other, "a.b.rusenet.org"); + caps.Categories.AddCategoryMapping(934, NewznabStandardCategory.Other, "a.b.sacd.iso"); + caps.Categories.AddCategoryMapping(548, NewznabStandardCategory.Other, "a.b.scary.exe.files"); + caps.Categories.AddCategoryMapping(945, NewznabStandardCategory.Other, "a.b.sea-monkeys"); + caps.Categories.AddCategoryMapping(549, NewznabStandardCategory.Other, "a.b.series.tv.divx.french"); + caps.Categories.AddCategoryMapping(550, NewznabStandardCategory.Other, "a.b.series.tv.divx.french.reposts"); + caps.Categories.AddCategoryMapping(551, NewznabStandardCategory.Other, "a.b.series.tv.french"); + caps.Categories.AddCategoryMapping(552, NewznabStandardCategory.Other, "a.b.shareware"); + caps.Categories.AddCategoryMapping(553, NewznabStandardCategory.Other, "a.b.sheet-music"); + caps.Categories.AddCategoryMapping(554, NewznabStandardCategory.Other, "a.b.shitsony"); + caps.Categories.AddCategoryMapping(555, NewznabStandardCategory.Other, "a.b.skewed"); + caps.Categories.AddCategoryMapping(556, NewznabStandardCategory.Other, "a.b.sleazemovies"); + caps.Categories.AddCategoryMapping(557, NewznabStandardCategory.Other, "a.b.smallville"); + caps.Categories.AddCategoryMapping(558, NewznabStandardCategory.Other, "a.b.smoking.videos"); + caps.Categories.AddCategoryMapping(559, NewznabStandardCategory.Other, "a.b.software"); + caps.Categories.AddCategoryMapping(931, NewznabStandardCategory.Other, "a.b.solar"); + caps.Categories.AddCategoryMapping(560, NewznabStandardCategory.Other, "a.b.solar-xl"); + caps.Categories.AddCategoryMapping(561, NewznabStandardCategory.Other, "a.b.sony.psp"); + caps.Categories.AddCategoryMapping(562, NewznabStandardCategory.Other, "a.b.sony.psp.movies"); + caps.Categories.AddCategoryMapping(563, NewznabStandardCategory.Other, "a.b.sound.mp3"); + caps.Categories.AddCategoryMapping(564, NewznabStandardCategory.Other, "a.b.sound.mp3.complete_cd"); + caps.Categories.AddCategoryMapping(565, NewznabStandardCategory.Other, "a.b.sound.radio.oldtime"); + caps.Categories.AddCategoryMapping(566, NewznabStandardCategory.Other, "a.b.sound.utilities"); + caps.Categories.AddCategoryMapping(567, NewznabStandardCategory.Other, "a.b.sounds"); + caps.Categories.AddCategoryMapping(568, NewznabStandardCategory.Other, "a.b.sounds.1940s.mp3"); + caps.Categories.AddCategoryMapping(569, NewznabStandardCategory.Other, "a.b.sounds.1950s.mp3"); + caps.Categories.AddCategoryMapping(570, NewznabStandardCategory.Other, "a.b.sounds.1960s.mp3"); + caps.Categories.AddCategoryMapping(571, NewznabStandardCategory.Other, "a.b.sounds.1970s.mp3"); + caps.Categories.AddCategoryMapping(572, NewznabStandardCategory.Other, "a.b.sounds.1980s.mp3"); + caps.Categories.AddCategoryMapping(573, NewznabStandardCategory.Other, "a.b.sounds.78rpm-era"); + caps.Categories.AddCategoryMapping(574, NewznabStandardCategory.Other, "a.b.sounds.aac"); + caps.Categories.AddCategoryMapping(575, NewznabStandardCategory.Other, "a.b.sounds.anime"); + caps.Categories.AddCategoryMapping(576, NewznabStandardCategory.Other, "a.b.sounds.audiobook"); + caps.Categories.AddCategoryMapping(577, NewznabStandardCategory.Other, "a.b.sounds.audiobooks"); + caps.Categories.AddCategoryMapping(578, NewznabStandardCategory.Other, "a.b.sounds.audiobooks.scifi-fantasy"); + caps.Categories.AddCategoryMapping(579, NewznabStandardCategory.Other, "a.b.sounds.country.mp3"); + caps.Categories.AddCategoryMapping(580, NewznabStandardCategory.Other, "a.b.sounds.dts"); + caps.Categories.AddCategoryMapping(581, NewznabStandardCategory.Other, "a.b.sounds.flac"); + caps.Categories.AddCategoryMapping(582, NewznabStandardCategory.Other, "a.b.sounds.flac.classical"); + caps.Categories.AddCategoryMapping(583, NewznabStandardCategory.Other, "a.b.sounds.flac.jazz"); + caps.Categories.AddCategoryMapping(584, NewznabStandardCategory.Other, "a.b.sounds.jpop"); + caps.Categories.AddCategoryMapping(585, NewznabStandardCategory.Other, "a.b.sounds.karaoke"); + caps.Categories.AddCategoryMapping(586, NewznabStandardCategory.Other, "a.b.sounds.korean"); + caps.Categories.AddCategoryMapping(587, NewznabStandardCategory.Other, "a.b.sounds.lossless"); + caps.Categories.AddCategoryMapping(588, NewznabStandardCategory.AudioLossless, "a.b.sounds.lossless.1960s"); + caps.Categories.AddCategoryMapping(589, NewznabStandardCategory.AudioLossless, "a.b.sounds.lossless.1970s"); + caps.Categories.AddCategoryMapping(590, NewznabStandardCategory.AudioLossless, "a.b.sounds.lossless.1980s"); + caps.Categories.AddCategoryMapping(591, NewznabStandardCategory.AudioLossless, "a.b.sounds.lossless.1990s"); + caps.Categories.AddCategoryMapping(592, NewznabStandardCategory.AudioLossless, "a.b.sounds.lossless.2000s"); + caps.Categories.AddCategoryMapping(933, NewznabStandardCategory.AudioLossless, "a.b.sounds.lossless.24bit"); + caps.Categories.AddCategoryMapping(593, NewznabStandardCategory.AudioLossless, "a.b.sounds.lossless.blues"); + caps.Categories.AddCategoryMapping(594, NewznabStandardCategory.AudioLossless, "a.b.sounds.lossless.classical"); + caps.Categories.AddCategoryMapping(595, NewznabStandardCategory.AudioLossless, "a.b.sounds.lossless.country"); + caps.Categories.AddCategoryMapping(596, NewznabStandardCategory.AudioLossless, "a.b.sounds.lossless.flac"); + caps.Categories.AddCategoryMapping(597, NewznabStandardCategory.AudioLossless, "a.b.sounds.lossless.french"); + caps.Categories.AddCategoryMapping(598, NewznabStandardCategory.AudioLossless, "a.b.sounds.lossless.jazz"); + caps.Categories.AddCategoryMapping(599, NewznabStandardCategory.AudioLossless, "a.b.sounds.lossless.metal"); + caps.Categories.AddCategoryMapping(600, NewznabStandardCategory.AudioLossless, "a.b.sounds.lossless.rap-hiphop"); + caps.Categories.AddCategoryMapping(601, NewznabStandardCategory.Other, "a.b.sounds.midi"); + caps.Categories.AddCategoryMapping(602, NewznabStandardCategory.Other, "a.b.sounds.misc"); + caps.Categories.AddCategoryMapping(603, NewznabStandardCategory.Other, "a.b.sounds.monkeysaudio"); caps.Categories.AddCategoryMapping(604, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3"); + caps.Categories.AddCategoryMapping(605, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.1940s"); + caps.Categories.AddCategoryMapping(606, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.1950s"); + caps.Categories.AddCategoryMapping(607, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.1960s"); + caps.Categories.AddCategoryMapping(608, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.1970s"); + caps.Categories.AddCategoryMapping(609, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.1980s"); + caps.Categories.AddCategoryMapping(610, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.1990s"); + caps.Categories.AddCategoryMapping(611, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.2000s"); + caps.Categories.AddCategoryMapping(940, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.acoustic"); + caps.Categories.AddCategoryMapping(612, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.alternative-rock"); + caps.Categories.AddCategoryMapping(613, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.ambient"); + caps.Categories.AddCategoryMapping(614, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.audiobooks"); + caps.Categories.AddCategoryMapping(874, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.big-band"); + caps.Categories.AddCategoryMapping(615, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.bluegrass"); + caps.Categories.AddCategoryMapping(616, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.blues"); + caps.Categories.AddCategoryMapping(617, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.books"); + caps.Categories.AddCategoryMapping(618, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.bootlegs"); + caps.Categories.AddCategoryMapping(619, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.brazilian"); + caps.Categories.AddCategoryMapping(620, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.celtic"); + caps.Categories.AddCategoryMapping(621, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.chinese"); + caps.Categories.AddCategoryMapping(622, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.christian"); + caps.Categories.AddCategoryMapping(623, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.christmas"); + caps.Categories.AddCategoryMapping(626, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.classic-rock"); + caps.Categories.AddCategoryMapping(624, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.classical"); + caps.Categories.AddCategoryMapping(625, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.classical-guitar"); + caps.Categories.AddCategoryMapping(627, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.comedy"); + caps.Categories.AddCategoryMapping(629, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.complete-cd"); + caps.Categories.AddCategoryMapping(628, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.complete_cd"); + caps.Categories.AddCategoryMapping(630, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.country"); + caps.Categories.AddCategoryMapping(631, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.dance"); + caps.Categories.AddCategoryMapping(632, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.dancehall"); + caps.Categories.AddCategoryMapping(932, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.disco"); + caps.Categories.AddCategoryMapping(633, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.disney"); + caps.Categories.AddCategoryMapping(634, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.easy-listening"); + caps.Categories.AddCategoryMapping(635, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.electronic"); + caps.Categories.AddCategoryMapping(636, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.emo"); + caps.Categories.AddCategoryMapping(637, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.extreme-metal"); + caps.Categories.AddCategoryMapping(638, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.folk"); + caps.Categories.AddCategoryMapping(639, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.french"); + caps.Categories.AddCategoryMapping(640, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.full_album"); + caps.Categories.AddCategoryMapping(641, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.full_albums"); + caps.Categories.AddCategoryMapping(642, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.german"); + caps.Categories.AddCategoryMapping(643, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.german.charts"); + caps.Categories.AddCategoryMapping(644, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.german.hoerbuecher"); + caps.Categories.AddCategoryMapping(645, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.german.hoerspiele"); + caps.Categories.AddCategoryMapping(646, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.german.music"); + caps.Categories.AddCategoryMapping(647, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.goa-trance"); + caps.Categories.AddCategoryMapping(648, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.gothic-industrial"); + caps.Categories.AddCategoryMapping(649, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.heavy-metal"); + caps.Categories.AddCategoryMapping(650, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.holland"); + caps.Categories.AddCategoryMapping(651, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.holland.piraat"); + caps.Categories.AddCategoryMapping(652, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.hollands"); + caps.Categories.AddCategoryMapping(653, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.house"); + caps.Categories.AddCategoryMapping(654, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.indie"); + caps.Categories.AddCategoryMapping(655, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.jazz"); + caps.Categories.AddCategoryMapping(656, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.jazz.vocals"); + caps.Categories.AddCategoryMapping(657, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.karaoke"); + caps.Categories.AddCategoryMapping(658, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.latin"); + caps.Categories.AddCategoryMapping(659, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.lounge"); + caps.Categories.AddCategoryMapping(660, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.metal.full-albums"); + caps.Categories.AddCategoryMapping(661, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.modern-composers"); + caps.Categories.AddCategoryMapping(662, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.musicals"); + caps.Categories.AddCategoryMapping(663, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.new-age"); + caps.Categories.AddCategoryMapping(664, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.norwegian"); + caps.Categories.AddCategoryMapping(665, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.nu-jazz"); + caps.Categories.AddCategoryMapping(666, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.pop"); + caps.Categories.AddCategoryMapping(667, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.prog"); + caps.Categories.AddCategoryMapping(668, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.punk"); + caps.Categories.AddCategoryMapping(669, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.rap-hiphop"); + caps.Categories.AddCategoryMapping(670, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.reggae"); + caps.Categories.AddCategoryMapping(671, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.repost"); + caps.Categories.AddCategoryMapping(672, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.rock"); + caps.Categories.AddCategoryMapping(673, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.rock.full-album"); + caps.Categories.AddCategoryMapping(674, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.rock.full-albums"); + caps.Categories.AddCategoryMapping(675, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.secular"); + caps.Categories.AddCategoryMapping(676, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.soul-rhythm-and-blues"); + caps.Categories.AddCategoryMapping(677, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.sound-effects"); + caps.Categories.AddCategoryMapping(678, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.soundtracks"); + caps.Categories.AddCategoryMapping(920, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.stoner"); + caps.Categories.AddCategoryMapping(679, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.techno"); + caps.Categories.AddCategoryMapping(680, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.video-games"); + caps.Categories.AddCategoryMapping(681, NewznabStandardCategory.AudioMP3, "a.b.sounds.mp3.world-music"); + caps.Categories.AddCategoryMapping(682, NewznabStandardCategory.Other, "a.b.sounds.music"); + caps.Categories.AddCategoryMapping(683, NewznabStandardCategory.Other, "a.b.sounds.music.classical"); + caps.Categories.AddCategoryMapping(684, NewznabStandardCategory.Other, "a.b.sounds.music.opera"); + caps.Categories.AddCategoryMapping(685, NewznabStandardCategory.Other, "a.b.sounds.music.rock.metal"); + caps.Categories.AddCategoryMapping(686, NewznabStandardCategory.Other, "a.b.sounds.nl.hoorspel"); + caps.Categories.AddCategoryMapping(687, NewznabStandardCategory.Other, "a.b.sounds.ogg"); + caps.Categories.AddCategoryMapping(688, NewznabStandardCategory.Other, "a.b.sounds.pac"); + caps.Categories.AddCategoryMapping(689, NewznabStandardCategory.Other, "a.b.sounds.radio.bbc"); + caps.Categories.AddCategoryMapping(690, NewznabStandardCategory.Other, "a.b.sounds.radio.british"); + caps.Categories.AddCategoryMapping(691, NewznabStandardCategory.Other, "a.b.sounds.radio.coasttocoast.am"); + caps.Categories.AddCategoryMapping(692, NewznabStandardCategory.Other, "a.b.sounds.radio.misc"); + caps.Categories.AddCategoryMapping(693, NewznabStandardCategory.Other, "a.b.sounds.radio.mp3"); + caps.Categories.AddCategoryMapping(694, NewznabStandardCategory.Other, "a.b.sounds.radio.oldtime"); + caps.Categories.AddCategoryMapping(695, NewznabStandardCategory.Other, "a.b.sounds.radio.oldtime.highspeed"); + caps.Categories.AddCategoryMapping(696, NewznabStandardCategory.Other, "a.b.sounds.samples"); + caps.Categories.AddCategoryMapping(697, NewznabStandardCategory.Other, "a.b.sounds.samples.music"); + caps.Categories.AddCategoryMapping(698, NewznabStandardCategory.Other, "a.b.sounds.utilities"); + caps.Categories.AddCategoryMapping(699, NewznabStandardCategory.Other, "a.b.sounds.whitburn.country"); + caps.Categories.AddCategoryMapping(700, NewznabStandardCategory.Other, "a.b.sounds.whitburn.lossless"); + caps.Categories.AddCategoryMapping(701, NewznabStandardCategory.Other, "a.b.sounds.whitburn.pop"); + caps.Categories.AddCategoryMapping(702, NewznabStandardCategory.Other, "a.b.sounds.whitburn.reposts"); + caps.Categories.AddCategoryMapping(703, NewznabStandardCategory.Other, "a.b.southern-charms"); + caps.Categories.AddCategoryMapping(704, NewznabStandardCategory.Other, "a.b.southern-charms.pictures"); + caps.Categories.AddCategoryMapping(705, NewznabStandardCategory.Other, "a.b.southpark"); + caps.Categories.AddCategoryMapping(706, NewznabStandardCategory.Other, "a.b.squaresoft"); + caps.Categories.AddCategoryMapping(707, NewznabStandardCategory.Other, "a.b.stargate-atlantis"); + caps.Categories.AddCategoryMapping(708, NewznabStandardCategory.Other, "a.b.stargate-sg1"); + caps.Categories.AddCategoryMapping(709, NewznabStandardCategory.Other, "a.b.startrek"); + caps.Categories.AddCategoryMapping(710, NewznabStandardCategory.Other, "a.b.starwars"); + caps.Categories.AddCategoryMapping(711, NewznabStandardCategory.Other, "a.b.stripboeken.nl"); + caps.Categories.AddCategoryMapping(712, NewznabStandardCategory.Other, "a.b.superman"); + caps.Categories.AddCategoryMapping(713, NewznabStandardCategory.Other, "a.b.svcd"); + caps.Categories.AddCategoryMapping(714, NewznabStandardCategory.Other, "a.b.swe"); + caps.Categories.AddCategoryMapping(715, NewznabStandardCategory.Other, "a.b.swebinz"); + caps.Categories.AddCategoryMapping(716, NewznabStandardCategory.Other, "a.b.swedish"); + caps.Categories.AddCategoryMapping(717, NewznabStandardCategory.Other, "a.b.swedvdr"); + caps.Categories.AddCategoryMapping(718, NewznabStandardCategory.Other, "a.b.tatu"); + caps.Categories.AddCategoryMapping(719, NewznabStandardCategory.Other, "a.b.team-casanova"); + caps.Categories.AddCategoryMapping(720, NewznabStandardCategory.Other, "a.b.teevee"); + caps.Categories.AddCategoryMapping(721, NewznabStandardCategory.Other, "a.b.test"); + caps.Categories.AddCategoryMapping(722, NewznabStandardCategory.Other, "a.b.the-portal"); + caps.Categories.AddCategoryMapping(723, NewznabStandardCategory.Other, "a.b.the-terminal"); + caps.Categories.AddCategoryMapping(921, NewznabStandardCategory.Other, "a.b.thundernews"); + caps.Categories.AddCategoryMapping(724, NewznabStandardCategory.Other, "a.b.tiesto"); + caps.Categories.AddCategoryMapping(725, NewznabStandardCategory.Other, "a.b.town"); + caps.Categories.AddCategoryMapping(726, NewznabStandardCategory.Other, "a.b.town.cine"); + caps.Categories.AddCategoryMapping(727, NewznabStandardCategory.Other, "a.b.town.serien"); + caps.Categories.AddCategoryMapping(728, NewznabStandardCategory.Other, "a.b.town.xxx"); + caps.Categories.AddCategoryMapping(729, NewznabStandardCategory.Other, "a.b.triballs"); + caps.Categories.AddCategoryMapping(730, NewznabStandardCategory.Other, "a.b.tun"); caps.Categories.AddCategoryMapping(731, NewznabStandardCategory.TV, "a.b.tv"); + caps.Categories.AddCategoryMapping(732, NewznabStandardCategory.TVForeign, "a.b.tv.aus"); + caps.Categories.AddCategoryMapping(733, NewznabStandardCategory.TV, "a.b.tv.big-brother"); + caps.Categories.AddCategoryMapping(734, NewznabStandardCategory.TVForeign, "a.b.tv.canadian"); + caps.Categories.AddCategoryMapping(735, NewznabStandardCategory.TVForeign, "a.b.tv.deutsch"); + caps.Categories.AddCategoryMapping(736, NewznabStandardCategory.TVForeign, "a.b.tv.deutsch.dokumentation"); + caps.Categories.AddCategoryMapping(737, NewznabStandardCategory.TV, "a.b.tv.farscape"); + caps.Categories.AddCategoryMapping(738, NewznabStandardCategory.TV, "a.b.tv.friends"); + caps.Categories.AddCategoryMapping(739, NewznabStandardCategory.TV, "a.b.tv.simpsons"); + caps.Categories.AddCategoryMapping(740, NewznabStandardCategory.TVForeign, "a.b.tv.swedish"); + caps.Categories.AddCategoryMapping(741, NewznabStandardCategory.TV, "a.b.tv.us-sitcoms"); + caps.Categories.AddCategoryMapping(742, NewznabStandardCategory.TV, "a.b.tvseries"); + caps.Categories.AddCategoryMapping(868, NewznabStandardCategory.TV, "a.b.tvshows"); + caps.Categories.AddCategoryMapping(743, NewznabStandardCategory.Other, "a.b.u-4all"); + caps.Categories.AddCategoryMapping(744, NewznabStandardCategory.Other, "a.b.u4e"); + caps.Categories.AddCategoryMapping(745, NewznabStandardCategory.Other, "a.b.ucc"); + caps.Categories.AddCategoryMapping(746, NewznabStandardCategory.Other, "a.b.ufg"); + caps.Categories.AddCategoryMapping(747, NewznabStandardCategory.Other, "a.b.ufo"); + caps.Categories.AddCategoryMapping(748, NewznabStandardCategory.Other, "a.b.ufo.files"); + caps.Categories.AddCategoryMapping(749, NewznabStandardCategory.Other, "a.b.uhq"); + caps.Categories.AddCategoryMapping(750, NewznabStandardCategory.Other, "a.b.underground"); + caps.Categories.AddCategoryMapping(751, NewznabStandardCategory.Other, "a.b.united-forums"); + caps.Categories.AddCategoryMapping(752, NewznabStandardCategory.Other, "a.b.unity"); + caps.Categories.AddCategoryMapping(753, NewznabStandardCategory.Other, "a.b.usc"); + caps.Categories.AddCategoryMapping(754, NewznabStandardCategory.Other, "a.b.usenet"); + caps.Categories.AddCategoryMapping(922, NewznabStandardCategory.Other, "a.b.usenet-of-inferno"); + caps.Categories.AddCategoryMapping(923, NewznabStandardCategory.Other, "a.b.usenet-of-outlaws"); + caps.Categories.AddCategoryMapping(761, NewznabStandardCategory.Other, "a.b.usenet-space-cowboys"); + caps.Categories.AddCategoryMapping(762, NewznabStandardCategory.Other, "a.b.usenet-world.com"); + caps.Categories.AddCategoryMapping(755, NewznabStandardCategory.Other, "a.b.usenet2day"); + caps.Categories.AddCategoryMapping(756, NewznabStandardCategory.Other, "a.b.usenetdevils"); + caps.Categories.AddCategoryMapping(757, NewznabStandardCategory.Other, "a.b.usenetrevo.serien"); + caps.Categories.AddCategoryMapping(758, NewznabStandardCategory.Other, "a.b.usenetrevolution"); + caps.Categories.AddCategoryMapping(759, NewznabStandardCategory.Other, "a.b.usenetrevolution.musik"); + caps.Categories.AddCategoryMapping(760, NewznabStandardCategory.Other, "a.b.usenetrevolution.xxx"); + caps.Categories.AddCategoryMapping(763, NewznabStandardCategory.Other, "a.b.usewarez"); + caps.Categories.AddCategoryMapping(764, NewznabStandardCategory.Other, "a.b.uzenet"); + caps.Categories.AddCategoryMapping(765, NewznabStandardCategory.Other, "a.b.vcd"); + caps.Categories.AddCategoryMapping(766, NewznabStandardCategory.Other, "a.b.vcd.french"); + caps.Categories.AddCategoryMapping(767, NewznabStandardCategory.Other, "a.b.vcd.highspeed"); + caps.Categories.AddCategoryMapping(768, NewznabStandardCategory.Other, "a.b.vcd.other"); + caps.Categories.AddCategoryMapping(769, NewznabStandardCategory.Other, "a.b.vcd.repost"); + caps.Categories.AddCategoryMapping(770, NewznabStandardCategory.Other, "a.b.vcd.svcd"); + caps.Categories.AddCategoryMapping(771, NewznabStandardCategory.Other, "a.b.vcd.svcd.repost"); + caps.Categories.AddCategoryMapping(772, NewznabStandardCategory.Other, "a.b.vcd.westerns"); + caps.Categories.AddCategoryMapping(773, NewznabStandardCategory.Other, "a.b.vcd.xxx"); + caps.Categories.AddCategoryMapping(774, NewznabStandardCategory.Other, "a.b.vcdz"); + caps.Categories.AddCategoryMapping(775, NewznabStandardCategory.Other, "a.b.verified.photoshoots"); + caps.Categories.AddCategoryMapping(776, NewznabStandardCategory.Other, "a.b.vesdaris"); + caps.Categories.AddCategoryMapping(824, NewznabStandardCategory.Other, "a.b.w-software"); + caps.Categories.AddCategoryMapping(777, NewznabStandardCategory.Other, "a.b.wallpaper"); + caps.Categories.AddCategoryMapping(778, NewznabStandardCategory.Other, "a.b.warcraft"); + caps.Categories.AddCategoryMapping(779, NewznabStandardCategory.Other, "a.b.wares"); + caps.Categories.AddCategoryMapping(780, NewznabStandardCategory.Other, "a.b.warez"); + caps.Categories.AddCategoryMapping(813, NewznabStandardCategory.PC, "a.b.warez-pc"); + caps.Categories.AddCategoryMapping(814, NewznabStandardCategory.PC0day, "a.b.warez-pc.0-day"); + caps.Categories.AddCategoryMapping(781, NewznabStandardCategory.PC0day, "a.b.warez.0-day"); + caps.Categories.AddCategoryMapping(782, NewznabStandardCategory.PC0day, "a.b.warez.0-day.games"); + caps.Categories.AddCategoryMapping(783, NewznabStandardCategory.PC, "a.b.warez.autocad"); + caps.Categories.AddCategoryMapping(784, NewznabStandardCategory.PC, "a.b.warez.educational"); + caps.Categories.AddCategoryMapping(785, NewznabStandardCategory.PC, "a.b.warez.flightsim"); + caps.Categories.AddCategoryMapping(786, NewznabStandardCategory.PC, "a.b.warez.games"); + caps.Categories.AddCategoryMapping(788, NewznabStandardCategory.PC, "a.b.warez.ibm-pc"); + caps.Categories.AddCategoryMapping(789, NewznabStandardCategory.PC, "a.b.warez.ibm-pc.0-day"); + caps.Categories.AddCategoryMapping(790, NewznabStandardCategory.PC, "a.b.warez.ibm-pc.games"); + caps.Categories.AddCategoryMapping(791, NewznabStandardCategory.PC, "a.b.warez.ibm-pc.german"); + caps.Categories.AddCategoryMapping(792, NewznabStandardCategory.PC, "a.b.warez.ibm-pc.ms-beta"); + caps.Categories.AddCategoryMapping(793, NewznabStandardCategory.PC, "a.b.warez.ibm-pc.o-day"); + caps.Categories.AddCategoryMapping(794, NewznabStandardCategory.PC, "a.b.warez.ibm-pc.os"); + caps.Categories.AddCategoryMapping(787, NewznabStandardCategory.PC, "a.b.warez.ibm.pc"); + caps.Categories.AddCategoryMapping(795, NewznabStandardCategory.PC, "a.b.warez.linux"); + caps.Categories.AddCategoryMapping(796, NewznabStandardCategory.PC, "a.b.warez.palmpilot"); + caps.Categories.AddCategoryMapping(797, NewznabStandardCategory.PC, "a.b.warez.pocketpc"); + caps.Categories.AddCategoryMapping(798, NewznabStandardCategory.PC, "a.b.warez.pocketpc.gps"); + caps.Categories.AddCategoryMapping(799, NewznabStandardCategory.PC, "a.b.warez.pocketpc.movies"); + caps.Categories.AddCategoryMapping(800, NewznabStandardCategory.PC, "a.b.warez.quebec-hackers"); + caps.Categories.AddCategoryMapping(801, NewznabStandardCategory.PC, "a.b.warez.quebec-hackers.d"); + caps.Categories.AddCategoryMapping(802, NewznabStandardCategory.PC, "a.b.warez.quebec-hackers.dvd"); + caps.Categories.AddCategoryMapping(803, NewznabStandardCategory.PC, "a.b.warez.raptorweb"); + caps.Categories.AddCategoryMapping(804, NewznabStandardCategory.PC, "a.b.warez.smartphone"); + caps.Categories.AddCategoryMapping(805, NewznabStandardCategory.PC, "a.b.warez.uk"); + caps.Categories.AddCategoryMapping(806, NewznabStandardCategory.PC, "a.b.warez.uk.mp3"); + caps.Categories.AddCategoryMapping(807, NewznabStandardCategory.PC, "a.b.warez.win2000"); + caps.Categories.AddCategoryMapping(808, NewznabStandardCategory.PC, "a.b.warez.win95-apps"); + caps.Categories.AddCategoryMapping(809, NewznabStandardCategory.PC, "a.b.warez.win95-games"); + caps.Categories.AddCategoryMapping(810, NewznabStandardCategory.Other, "a.b.warez4kiddies"); + caps.Categories.AddCategoryMapping(811, NewznabStandardCategory.Other, "a.b.warez4kiddies.apps"); + caps.Categories.AddCategoryMapping(812, NewznabStandardCategory.Other, "a.b.warez4kiddies.mp3"); + caps.Categories.AddCategoryMapping(815, NewznabStandardCategory.Other, "a.b.wb"); + caps.Categories.AddCategoryMapping(924, NewznabStandardCategory.Other, "a.b.webcam"); + caps.Categories.AddCategoryMapping(925, NewznabStandardCategory.Other, "a.b.webcam.videos"); + caps.Categories.AddCategoryMapping(816, NewznabStandardCategory.Other, "a.b.welovehelix"); + caps.Categories.AddCategoryMapping(817, NewznabStandardCategory.Other, "a.b.welovelori"); + caps.Categories.AddCategoryMapping(818, NewznabStandardCategory.Other, "a.b.whitburn"); + caps.Categories.AddCategoryMapping(863, NewznabStandardCategory.Other, "a.b.windows"); + caps.Categories.AddCategoryMapping(950, NewznabStandardCategory.Other, "a.b.wiseguys"); + caps.Categories.AddCategoryMapping(819, NewznabStandardCategory.Other, "a.b.witchblade"); + caps.Categories.AddCategoryMapping(821, NewznabStandardCategory.Other, "a.b.wmv-hd"); + caps.Categories.AddCategoryMapping(820, NewznabStandardCategory.Other, "a.b.wmvhd"); + caps.Categories.AddCategoryMapping(926, NewznabStandardCategory.Other, "a.b.wolfsteamers.info"); + caps.Categories.AddCategoryMapping(942, NewznabStandardCategory.Other, "a.b.wood"); + caps.Categories.AddCategoryMapping(822, NewznabStandardCategory.Other, "a.b.world-languages"); + caps.Categories.AddCategoryMapping(823, NewznabStandardCategory.Other, "a.b.worms"); + caps.Categories.AddCategoryMapping(825, NewznabStandardCategory.Other, "a.b.ww2mwa"); + caps.Categories.AddCategoryMapping(826, NewznabStandardCategory.Other, "a.b.x"); + caps.Categories.AddCategoryMapping(831, NewznabStandardCategory.Other, "a.b.x-files"); + caps.Categories.AddCategoryMapping(827, NewznabStandardCategory.Other, "a.b.x264"); + caps.Categories.AddCategoryMapping(828, NewznabStandardCategory.Other, "a.b.x2l"); + caps.Categories.AddCategoryMapping(829, NewznabStandardCategory.Other, "a.b.x2l.nzb"); + caps.Categories.AddCategoryMapping(830, NewznabStandardCategory.Other, "a.b.xbox"); + caps.Categories.AddCategoryMapping(832, NewznabStandardCategory.Other, "a.b.xvid"); + caps.Categories.AddCategoryMapping(833, NewznabStandardCategory.Other, "a.b.xvid.movies"); + caps.Categories.AddCategoryMapping(834, NewznabStandardCategory.Other, "a.b.xxibite"); + caps.Categories.AddCategoryMapping(835, NewznabStandardCategory.Other, "a.b.xylo"); + caps.Categories.AddCategoryMapping(836, NewznabStandardCategory.Other, "a.b.zines"); + caps.Categories.AddCategoryMapping(837, NewznabStandardCategory.Other, "alt.chello.binaries"); + caps.Categories.AddCategoryMapping(838, NewznabStandardCategory.Other, "alt.dvdnordic.org"); + caps.Categories.AddCategoryMapping(839, NewznabStandardCategory.Other, "alt.games.microsoft.flight-sim"); + caps.Categories.AddCategoryMapping(840, NewznabStandardCategory.Other, "alt.games.video.xbox"); + caps.Categories.AddCategoryMapping(841, NewznabStandardCategory.Other, "alt.games.warcraft"); + caps.Categories.AddCategoryMapping(842, NewznabStandardCategory.Other, "alt.nl.ftp.binaries"); + caps.Categories.AddCategoryMapping(843, NewznabStandardCategory.Other, "alt.no-advertising.files.audio.mp3.techno"); + caps.Categories.AddCategoryMapping(844, NewznabStandardCategory.Other, "alt.sex.erotica"); + caps.Categories.AddCategoryMapping(865, NewznabStandardCategory.Other, "alt.windows7.general"); + caps.Categories.AddCategoryMapping(845, NewznabStandardCategory.Other, "dk.binaer.film"); + caps.Categories.AddCategoryMapping(846, NewznabStandardCategory.Other, "dk.binaer.film.divx"); + caps.Categories.AddCategoryMapping(847, NewznabStandardCategory.Other, "dk.binaer.musik"); + caps.Categories.AddCategoryMapping(848, NewznabStandardCategory.Other, "dk.binaer.tv"); + caps.Categories.AddCategoryMapping(849, NewznabStandardCategory.Other, "dk.binaries.film"); + caps.Categories.AddCategoryMapping(927, NewznabStandardCategory.Other, "es.binaries.bd"); + caps.Categories.AddCategoryMapping(850, NewznabStandardCategory.Other, "es.binarios.hd"); + caps.Categories.AddCategoryMapping(851, NewznabStandardCategory.Other, "es.binarios.misc"); + caps.Categories.AddCategoryMapping(852, NewznabStandardCategory.Other, "es.binarios.sexo"); + caps.Categories.AddCategoryMapping(853, NewznabStandardCategory.Other, "esp.binarios.misc"); + caps.Categories.AddCategoryMapping(854, NewznabStandardCategory.Other, "esp.binarios.series.misc"); + caps.Categories.AddCategoryMapping(855, NewznabStandardCategory.Other, "korea.binaries.movies"); + caps.Categories.AddCategoryMapping(856, NewznabStandardCategory.Other, "korea.binaries.tv"); + caps.Categories.AddCategoryMapping(857, NewznabStandardCategory.Other, "korea.binaries.warez"); + caps.Categories.AddCategoryMapping(858, NewznabStandardCategory.Other, "nl.media.dvd"); + caps.Categories.AddCategoryMapping(859, NewznabStandardCategory.Other, "planet.binaries.games"); + caps.Categories.AddCategoryMapping(860, NewznabStandardCategory.Other, "planet.binaries.movies"); + caps.Categories.AddCategoryMapping(861, NewznabStandardCategory.Other, "planet.binaries.sounds"); + caps.Categories.AddCategoryMapping(862, NewznabStandardCategory.Other, "uk.games.video.xbox"); return caps; } @@ -115,7 +1049,7 @@ namespace NzbDrone.Core.Indexers.Definitions } } - var request = new IndexerRequest(searchUrl, HttpAccept.Html); + var request = new IndexerRequest(searchUrl, HttpAccept.Json); yield return request; } @@ -248,9 +1182,7 @@ namespace NzbDrone.Core.Indexers.Definitions public string ApiKey { get; set; } [FieldDefinition(3)] - public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - - public NzbDroneValidationResult Validate() + public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } From e78b8d534652dc9dfdf6b0a9dfec59d0c74de648 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 9 Oct 2022 10:15:50 -0500 Subject: [PATCH 0611/2320] New: Add long term Application status Healthcheck --- .../Checks/ApplicationLongTermStatusCheck.cs | 59 +++++++++++++++++++ src/NzbDrone.Core/Localization/Core/en.json | 2 + 2 files changed, 61 insertions(+) create mode 100644 src/NzbDrone.Core/HealthCheck/Checks/ApplicationLongTermStatusCheck.cs diff --git a/src/NzbDrone.Core/HealthCheck/Checks/ApplicationLongTermStatusCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/ApplicationLongTermStatusCheck.cs new file mode 100644 index 000000000..0ea4bbd3c --- /dev/null +++ b/src/NzbDrone.Core/HealthCheck/Checks/ApplicationLongTermStatusCheck.cs @@ -0,0 +1,59 @@ +using System; +using System.Linq; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Applications; +using NzbDrone.Core.Localization; +using NzbDrone.Core.ThingiProvider.Events; + +namespace NzbDrone.Core.HealthCheck.Checks +{ + [CheckOn(typeof(ProviderUpdatedEvent<IApplication>))] + [CheckOn(typeof(ProviderDeletedEvent<IApplication>))] + [CheckOn(typeof(ProviderStatusChangedEvent<IApplication>))] + public class ApplicationLongTermStatusCheck : HealthCheckBase + { + private readonly IApplicationFactory _providerFactory; + private readonly IApplicationStatusService _providerStatusService; + + public ApplicationLongTermStatusCheck(IApplicationFactory providerFactory, + IApplicationStatusService providerStatusService, + ILocalizationService localizationService) + : base(localizationService) + { + _providerFactory = providerFactory; + _providerStatusService = providerStatusService; + } + + public override HealthCheck Check() + { + var enabledProviders = _providerFactory.GetAvailableProviders(); + var backOffProviders = enabledProviders.Join(_providerStatusService.GetBlockedProviders(), + i => i.Definition.Id, + s => s.ProviderId, + (i, s) => new { Provider = i, Status = s }) + .Where(p => p.Status.InitialFailure.HasValue && + p.Status.InitialFailure.Value.Before( + DateTime.UtcNow.AddHours(-6))) + .ToList(); + + if (backOffProviders.Empty()) + { + return new HealthCheck(GetType()); + } + + if (backOffProviders.Count == enabledProviders.Count) + { + return new HealthCheck(GetType(), + HealthCheckResult.Error, + _localizationService.GetLocalizedString("ApplicationLongTermStatusCheckAllClientMessage"), + "#applications-are-unavailable-due-to-failures"); + } + + return new HealthCheck(GetType(), + HealthCheckResult.Warning, + string.Format(_localizationService.GetLocalizedString("ApplicationLongTermStatusCheckSingleClientMessage"), + string.Join(", ", backOffProviders.Select(v => v.Provider.Definition.Name))), + "#applications-are-unavailable-due-to-failures"); + } + } +} diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 8411402df..79ea9e092 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -23,6 +23,8 @@ "AppDataDirectory": "AppData directory", "AppDataLocationHealthCheckMessage": "Updating will not be possible to prevent deleting AppData on Update", "Application": "Application", + "ApplicationLongTermStatusCheckAllClientMessage": "All applications are unavailable due to failures for more than 6 hours", + "ApplicationLongTermStatusCheckSingleClientMessage": "Applications unavailable due to failures for more than 6 hours: {0}", "Applications": "Applications", "ApplicationStatusCheckAllClientMessage": "All applications are unavailable due to failures", "ApplicationStatusCheckSingleClientMessage": "Applications unavailable due to failures: {0}", From dd05a9dbd415af666c207ab0dba0b6262387cd32 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 9 Oct 2022 10:34:40 -0500 Subject: [PATCH 0612/2320] Obsolete Anthelion C# Indexer --- src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs b/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs index f1464f07a..bdffbbca5 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs @@ -19,6 +19,7 @@ using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers.Definitions { + [Obsolete("Moved to YML for Cardigann")] public class Anthelion : TorrentIndexerBase<UserPassTorrentBaseSettings> { public override string Name => "Anthelion"; From 4a75f92cb5543f1736610f90379012521879844c Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 9 Oct 2022 18:33:41 -0500 Subject: [PATCH 0613/2320] Fixed: (FlareSolverr) Send non-auth global proxy when set Fixes #1142 --- .../FlareSolverr/FlareSolverr.cs | 60 +++++++++++++++---- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index 7cbf6844d..08e6c06da 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -10,6 +10,7 @@ using NzbDrone.Common.Cache; using NzbDrone.Common.Cloud; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Common.Http.Proxy; using NzbDrone.Common.Serializer; using NzbDrone.Core.Http.CloudFlare; using NzbDrone.Core.Localization; @@ -20,10 +21,12 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr public class FlareSolverr : HttpIndexerProxyBase<FlareSolverrSettings> { private readonly ICached<string> _cache; + private readonly IHttpProxySettingsProvider _proxySettingsProvider; - public FlareSolverr(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger, ILocalizationService localizationService, ICacheManager cacheManager) + public FlareSolverr(IHttpProxySettingsProvider proxySettingsProvider, IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger, ILocalizationService localizationService, ICacheManager cacheManager) : base(cloudRequestBuilder, httpClient, logger, localizationService) { + _proxySettingsProvider = proxySettingsProvider; _cache = cacheManager.GetCache<string>(typeof(string), "UserAgent"); } @@ -100,6 +103,10 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr var userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"; var maxTimeout = Settings.RequestTimeout * 1000; + // Use Proxy if no credentials are set (creds not supported as of FS 2.2.9) + var proxySettings = _proxySettingsProvider.GetProxySettings(); + var proxyUrl = proxySettings.Username.IsNullOrWhiteSpace() && proxySettings.Password.IsNullOrWhiteSpace() ? GetProxyUri(proxySettings) : null; + if (request.Method == HttpMethod.Get) { req = new FlareSolverrRequestGet @@ -107,7 +114,11 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr Cmd = "request.get", Url = url, MaxTimeout = maxTimeout, - UserAgent = userAgent + UserAgent = userAgent, + Proxy = new FlareSolverrProxy + { + Url = proxyUrl.AbsoluteUri + } }; } else if (request.Method == HttpMethod.Post) @@ -130,7 +141,11 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr ContentLength = null }, MaxTimeout = maxTimeout, - UserAgent = userAgent + UserAgent = userAgent, + Proxy = new FlareSolverrProxy + { + Url = proxyUrl.AbsoluteUri + } }; } else if (contentTypeType.Contains("multipart/form-data") @@ -191,38 +206,59 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr return new ValidationResult(failures); } - public class FlareSolverrRequest + private Uri GetProxyUri(HttpProxySettings proxySettings) + { + switch (proxySettings.Type) + { + case ProxyType.Http: + return new Uri("http://" + proxySettings.Host + ":" + proxySettings.Port); + case ProxyType.Socks4: + return new Uri("socks4://" + proxySettings.Host + ":" + proxySettings.Port); + case ProxyType.Socks5: + return new Uri("socks5://" + proxySettings.Host + ":" + proxySettings.Port); + default: + return null; + } + } + + private class FlareSolverrRequest { public string Cmd { get; set; } public string Url { get; set; } public string UserAgent { get; set; } public Cookie[] Cookies { get; set; } + public FlareSolverrProxy Proxy { get; set; } } - public class FlareSolverrRequestGet : FlareSolverrRequest + private class FlareSolverrRequestGet : FlareSolverrRequest { public string Headers { get; set; } public int MaxTimeout { get; set; } } - public class FlareSolverrRequestPost : FlareSolverrRequest + private class FlareSolverrRequestPost : FlareSolverrRequest { public string PostData { get; set; } public int MaxTimeout { get; set; } } - public class FlareSolverrRequestPostUrlEncoded : FlareSolverrRequestPost + private class FlareSolverrRequestPostUrlEncoded : FlareSolverrRequestPost { public HeadersPost Headers { get; set; } } - public class HeadersPost + private class FlareSolverrProxy + { + public string Url { get; set; } + } + + private class HeadersPost { public string ContentType { get; set; } public string ContentLength { get; set; } } - public class FlareSolverrResponse + private class FlareSolverrResponse { public string Status { get; set; } public string Message { get; set; } @@ -232,7 +268,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr public Solution Solution { get; set; } } - public class Solution + private class Solution { public string Url { get; set; } public string Status { get; set; } @@ -242,7 +278,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr public string UserAgent { get; set; } } - public class Cookie + private class Cookie { public string Name { get; set; } public string Value { get; set; } @@ -259,7 +295,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr public System.Net.Cookie ToCookieObj() => new System.Net.Cookie(Name, Value); } - public class Headers + private class Headers { public string Status { get; set; } public string Date { get; set; } From f96dbbfc215b476b82ff0c5ad89e97abb5bb48d5 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 9 Oct 2022 19:03:53 -0500 Subject: [PATCH 0614/2320] Ensure FS doesn't fail when no proxy --- src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index 08e6c06da..9071e212f 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -105,7 +105,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr // Use Proxy if no credentials are set (creds not supported as of FS 2.2.9) var proxySettings = _proxySettingsProvider.GetProxySettings(); - var proxyUrl = proxySettings.Username.IsNullOrWhiteSpace() && proxySettings.Password.IsNullOrWhiteSpace() ? GetProxyUri(proxySettings) : null; + var proxyUrl = proxySettings != null && proxySettings.Username.IsNullOrWhiteSpace() && proxySettings.Password.IsNullOrWhiteSpace() ? GetProxyUri(proxySettings) : null; if (request.Method == HttpMethod.Get) { @@ -117,7 +117,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr UserAgent = userAgent, Proxy = new FlareSolverrProxy { - Url = proxyUrl.AbsoluteUri + Url = proxyUrl?.AbsoluteUri } }; } From df0b8fc6606ab59395e5f070017985c08cff0949 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 9 Oct 2022 19:04:30 -0500 Subject: [PATCH 0615/2320] And another..... --- src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs index 9071e212f..0f048fd6d 100644 --- a/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs +++ b/src/NzbDrone.Core/IndexerProxies/FlareSolverr/FlareSolverr.cs @@ -144,7 +144,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr UserAgent = userAgent, Proxy = new FlareSolverrProxy { - Url = proxyUrl.AbsoluteUri + Url = proxyUrl?.AbsoluteUri } }; } From 3e700b63c26b247fcac83428ba79e53c88f797ff Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 10 Oct 2022 22:30:00 -0500 Subject: [PATCH 0616/2320] New: Retry Postgres connection 3 times (with 5 second sleep) on Startup --- src/NzbDrone.Core/Datastore/DbFactory.cs | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/NzbDrone.Core/Datastore/DbFactory.cs b/src/NzbDrone.Core/Datastore/DbFactory.cs index c62442d1b..38702abc4 100644 --- a/src/NzbDrone.Core/Datastore/DbFactory.cs +++ b/src/NzbDrone.Core/Datastore/DbFactory.cs @@ -1,6 +1,7 @@ using System; using System.Data.Common; using System.Data.SQLite; +using System.Net.Sockets; using NLog; using Npgsql; using NzbDrone.Common.Disk; @@ -125,6 +126,37 @@ namespace NzbDrone.Core.Datastore throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://wiki.servarr.com/prowlarr/faq#i-am-getting-an-error-database-disk-image-is-malformed", e, fileName); } + catch (NpgsqlException e) + { + if (e.InnerException is SocketException) + { + var retryCount = 3; + + while (true) + { + Logger.Error(e, "Failure to connect to Postgres DB, {0} retries remaining", retryCount); + + try + { + _migrationController.Migrate(connectionString, migrationContext); + } + catch (Exception ex) + { + if (--retryCount > 0) + { + System.Threading.Thread.Sleep(5000); + continue; + } + + throw new ProwlarrStartupException(ex, "Error creating main database"); + } + } + } + else + { + throw new ProwlarrStartupException(e, "Error creating main database"); + } + } catch (Exception e) { throw new ProwlarrStartupException(e, "Error creating main database"); From 22face385f8706b5a4305ee33c14ad5a67d212dd Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Mon, 3 Oct 2022 21:09:29 +0000 Subject: [PATCH 0617/2320] Translated using Weblate (Portuguese) Currently translated at 78.7% (364 of 462 strings) Translated using Weblate (Chinese (Traditional) (zh_TW)) Currently translated at 2.8% (13 of 462 strings) Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: korax1970 <duxlatronum@gmail.com> Co-authored-by: libsu <libsu@qq.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_TW/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/pt.json | 4 +++- src/NzbDrone.Core/Localization/Core/zh_TW.json | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/pt.json b/src/NzbDrone.Core/Localization/Core/pt.json index 3e43d9d4d..d1cd7f057 100644 --- a/src/NzbDrone.Core/Localization/Core/pt.json +++ b/src/NzbDrone.Core/Localization/Core/pt.json @@ -402,5 +402,7 @@ "Yes": "Sim", "GrabReleases": "Capturar versão", "InstanceName": "Nome da Instancia", - "InstanceNameHelpText": "Nome da instância na aba e nome da aplicação para Syslog" + "InstanceNameHelpText": "Nome da instância na aba e nome da aplicação para Syslog", + "UnableToLoadIndexerProxies": "Incapaz de ler o indexador de proxies", + "UnableToLoadApplicationList": "Não foi possível carregar a lista de aplicações" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_TW.json b/src/NzbDrone.Core/Localization/Core/zh_TW.json index 560875121..47e11bfd4 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_TW.json +++ b/src/NzbDrone.Core/Localization/Core/zh_TW.json @@ -11,5 +11,6 @@ "AddIndexerProxy": "新增索引器代理", "AddingTag": "新增標籤", "All": "全部", - "AddRemoveOnly": "僅限新增或移除" + "AddRemoveOnly": "僅限新增或移除", + "AcceptConfirmationModal": "接受確認模式" } From b911f8cc08dbd6c0f637fd81ce889795042a21ef Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 18 Oct 2022 07:23:22 -0500 Subject: [PATCH 0618/2320] Fix: (RetroFlix) Update URL to .club Fixes #1159 --- src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs b/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs index d1d193f62..ae4c476ea 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs @@ -10,7 +10,8 @@ namespace NzbDrone.Core.Indexers.Definitions { public override string Name => "RetroFlix"; - public override string[] IndexerUrls => new string[] { "https://retroflix.net/" }; + public override string[] IndexerUrls => new string[] { "https://retroflix.club/" }; + public override string[] LegacyUrls => new string[] { "http://retroflix.net/" }; public override string Description => "Private Torrent Tracker for Classic Movies / TV / General Releases"; From 4be41ff3fbde6b76b8517905e82067fac463dd99 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Tue, 18 Oct 2022 07:24:24 -0500 Subject: [PATCH 0619/2320] fixup! --- src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs b/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs index ae4c476ea..23027a5f1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs @@ -11,7 +11,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "RetroFlix"; public override string[] IndexerUrls => new string[] { "https://retroflix.club/" }; - public override string[] LegacyUrls => new string[] { "http://retroflix.net/" }; + public override string[] LegacyUrls => new string[] { "https://retroflix.net/" }; public override string Description => "Private Torrent Tracker for Classic Movies / TV / General Releases"; From b583ac3a9733ad86db681c90ff18ff8afc02bc05 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 25 Oct 2022 20:21:27 -0500 Subject: [PATCH 0620/2320] Fixed: (Cardigann) Rework login required logic Fixes #1166 --- .../Cardigann/CardigannRequestGenerator.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 46d951b95..c6d330c44 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -945,7 +945,7 @@ namespace NzbDrone.Core.Indexers.Cardigann public bool CheckIfLoginIsNeeded(HttpResponse response) { - if (_definition.Login == null || _definition.Login.Test == null) + if (_definition.Login == null) { return false; } @@ -969,18 +969,15 @@ namespace NzbDrone.Core.Indexers.Cardigann } // Only run html test selector on html responses - if (response.Headers.ContentType?.Contains("text/html") ?? true) + if (_definition.Login.Test.Selector != null && (response.Headers.ContentType?.Contains("text/html") ?? true)) { var parser = new HtmlParser(); var document = parser.ParseDocument(response.Content); - if (_definition.Login.Test.Selector != null) + var selection = document.QuerySelectorAll(_definition.Login.Test.Selector); + if (selection.Length == 0) { - var selection = document.QuerySelectorAll(_definition.Login.Test.Selector); - if (selection.Length == 0) - { - return true; - } + return true; } } From 0a9bd8287f662ce9b94a81857fb6f6789da59c07 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 23 Oct 2022 20:01:55 -0500 Subject: [PATCH 0621/2320] New: Return 429 for Query and Grab Limits --- src/Prowlarr.Api.V1/Indexers/NewznabController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Prowlarr.Api.V1/Indexers/NewznabController.cs b/src/Prowlarr.Api.V1/Indexers/NewznabController.cs index f2c111c75..8ef9c3e18 100644 --- a/src/Prowlarr.Api.V1/Indexers/NewznabController.cs +++ b/src/Prowlarr.Api.V1/Indexers/NewznabController.cs @@ -131,7 +131,7 @@ namespace NzbDrone.Api.V1.Indexers //TODO Optimize this so it's not called here and in NzbSearchService (for manual search) if (_indexerLimitService.AtQueryLimit(indexerDef)) { - return Content(CreateErrorXML(500, $"Request limit reached ({((IIndexerSettings)indexer.Definition.Settings).BaseSettings.QueryLimit})"), "application/rss+xml"); + return Content(CreateErrorXML(429, $"Request limit reached ({((IIndexerSettings)indexer.Definition.Settings).BaseSettings.QueryLimit})"), "application/rss+xml"); } switch (requestType) @@ -171,7 +171,7 @@ namespace NzbDrone.Api.V1.Indexers if (_indexerLimitService.AtDownloadLimit(indexerDef)) { - throw new BadRequestException("Grab limit reached"); + return Content(CreateErrorXML(429, $"Grab limit reached ({((IIndexerSettings)indexer.Definition.Settings).BaseSettings.DownloadLimit})"), "application/rss+xml"); } if (link.IsNullOrWhiteSpace() || file.IsNullOrWhiteSpace()) From 4eec675d614f10300448f4722a9643caae0756ca Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 25 Oct 2022 21:51:48 -0500 Subject: [PATCH 0622/2320] Fix Baker Problems --- src/Prowlarr.Api.V1/Indexers/NewznabController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Prowlarr.Api.V1/Indexers/NewznabController.cs b/src/Prowlarr.Api.V1/Indexers/NewznabController.cs index 8ef9c3e18..5d6720eb3 100644 --- a/src/Prowlarr.Api.V1/Indexers/NewznabController.cs +++ b/src/Prowlarr.Api.V1/Indexers/NewznabController.cs @@ -171,7 +171,7 @@ namespace NzbDrone.Api.V1.Indexers if (_indexerLimitService.AtDownloadLimit(indexerDef)) { - return Content(CreateErrorXML(429, $"Grab limit reached ({((IIndexerSettings)indexer.Definition.Settings).BaseSettings.DownloadLimit})"), "application/rss+xml"); + return Content(CreateErrorXML(429, $"Grab limit reached ({((IIndexerSettings)indexer.Definition.Settings).BaseSettings.GrabLimit})"), "application/rss+xml"); } if (link.IsNullOrWhiteSpace() || file.IsNullOrWhiteSpace()) From 438ea380f543928801a7bf664c9133878bcb8697 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 25 Oct 2022 21:54:19 -0500 Subject: [PATCH 0623/2320] Temp disable BSD Tests --- azure-pipelines.yml | 98 ++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c4a218f82..21bb54b19 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -429,11 +429,11 @@ stages: testName: 'linux-x64' poolName: 'Azure Pipelines' imageName: ${{ variables.linuxImage }} - FreebsdCore: - osName: 'Linux' - testName: 'freebsd-x64' - poolName: 'FreeBSD' - imageName: + # FreebsdCore: + # osName: 'Linux' + # testName: 'freebsd-x64' + # poolName: 'FreeBSD' + # imageName: pool: name: $(poolName) @@ -724,51 +724,51 @@ stages: failTaskOnFailedTests: true displayName: Publish Test Results - - job: Integration_FreeBSD - displayName: Integration Native FreeBSD - dependsOn: Prepare - condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0')) - workspace: - clean: all - variables: - pattern: 'Prowlarr.*.freebsd-core-x64.tar.gz' - pool: - name: 'FreeBSD' + # - job: Integration_FreeBSD + # displayName: Integration Native FreeBSD + # dependsOn: Prepare + # condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0')) + # workspace: + # clean: all + # variables: + # pattern: 'Prowlarr.*.freebsd-core-x64.tar.gz' + # pool: + # name: 'FreeBSD' - steps: - - checkout: none - - task: DownloadPipelineArtifact@2 - displayName: Download Test Artifact - inputs: - buildType: 'current' - artifactName: 'freebsd-x64-tests' - targetPath: $(testsFolder) - - task: DownloadPipelineArtifact@2 - displayName: Download Build Artifact - inputs: - buildType: 'current' - artifactName: Packages - itemPattern: '/$(pattern)' - targetPath: $(Build.ArtifactStagingDirectory) - - bash: | - mkdir -p ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin - tar xf ${BUILD_ARTIFACTSTAGINGDIRECTORY}/$(pattern) -C ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin - displayName: Extract Package - - bash: | - mkdir -p ./bin/ - cp -r -v ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin/Prowlarr/. ./bin/ - displayName: Move Package Contents - - bash: | - chmod a+x ${TESTSFOLDER}/test.sh - ${TESTSFOLDER}/test.sh Linux Integration Test - displayName: Run Integration Tests - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'NUnit' - testResultsFiles: '**/TestResult.xml' - testRunTitle: 'FreeBSD Integration Tests' - failTaskOnFailedTests: true - displayName: Publish Test Results + # steps: + # - checkout: none + # - task: DownloadPipelineArtifact@2 + # displayName: Download Test Artifact + # inputs: + # buildType: 'current' + # artifactName: 'freebsd-x64-tests' + # targetPath: $(testsFolder) + # - task: DownloadPipelineArtifact@2 + # displayName: Download Build Artifact + # inputs: + # buildType: 'current' + # artifactName: Packages + # itemPattern: '/$(pattern)' + # targetPath: $(Build.ArtifactStagingDirectory) + # - bash: | + # mkdir -p ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin + # tar xf ${BUILD_ARTIFACTSTAGINGDIRECTORY}/$(pattern) -C ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin + # displayName: Extract Package + # - bash: | + # mkdir -p ./bin/ + # cp -r -v ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin/Prowlarr/. ./bin/ + # displayName: Move Package Contents + # - bash: | + # chmod a+x ${TESTSFOLDER}/test.sh + # ${TESTSFOLDER}/test.sh Linux Integration Test + # displayName: Run Integration Tests + # - task: PublishTestResults@2 + # inputs: + # testResultsFormat: 'NUnit' + # testResultsFiles: '**/TestResult.xml' + # testRunTitle: 'FreeBSD Integration Tests' + # failTaskOnFailedTests: true + # displayName: Publish Test Results - job: Integration_Docker displayName: Integration Docker From 7029e0d6eea6720bc10abb2da783e00575a89a7e Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 25 Oct 2022 21:59:08 -0500 Subject: [PATCH 0624/2320] Enable new Servarr build notifications --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 21bb54b19..b8e0ae7d1 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1108,4 +1108,5 @@ stages: SYSTEM_ACCESSTOKEN: $(System.AccessToken) DISCORDCHANNELID: $(discordChannelId) DISCORDWEBHOOKKEY: $(discordWebhookKey) + DISCORDTHREADID: $(discordThreadId) From b74c46c5543398a5b137409892091f396a8ee4ae Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 30 Oct 2022 13:25:34 -0500 Subject: [PATCH 0625/2320] Ignore brotli test on osx --- src/NzbDrone.Common.Test/Http/HttpClientFixture.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs index 026d0aae5..9b48e77ca 100644 --- a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs +++ b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs @@ -212,6 +212,7 @@ namespace NzbDrone.Common.Test.Http } [Test] + [Platform(Exclude = "MacOsX", Reason = "Azure agent update prevents brotli on OSX")] public void should_execute_get_using_brotli() { var request = new HttpRequest($"https://{_httpBinHost}/brotli"); From 2ed51cd93371c420df9407d8b37dc30fe66451cf Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 30 Oct 2022 18:06:19 -0500 Subject: [PATCH 0626/2320] Fixed: Nullref on Cardigann without login test --- .../Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index c6d330c44..a298c1bda 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -969,7 +969,7 @@ namespace NzbDrone.Core.Indexers.Cardigann } // Only run html test selector on html responses - if (_definition.Login.Test.Selector != null && (response.Headers.ContentType?.Contains("text/html") ?? true)) + if (_definition.Login.Test?.Selector != null && (response.Headers.ContentType?.Contains("text/html") ?? true)) { var parser = new HtmlParser(); var document = parser.ParseDocument(response.Content); From 635335d876c104e5daea2469d34dc555c1406676 Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Wed, 2 Nov 2022 21:44:58 +0000 Subject: [PATCH 0627/2320] Revert "Temp disable BSD Tests" This reverts commit 438ea380f543928801a7bf664c9133878bcb8697. --- azure-pipelines.yml | 98 ++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b8e0ae7d1..12be8fddf 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -429,11 +429,11 @@ stages: testName: 'linux-x64' poolName: 'Azure Pipelines' imageName: ${{ variables.linuxImage }} - # FreebsdCore: - # osName: 'Linux' - # testName: 'freebsd-x64' - # poolName: 'FreeBSD' - # imageName: + FreebsdCore: + osName: 'Linux' + testName: 'freebsd-x64' + poolName: 'FreeBSD' + imageName: pool: name: $(poolName) @@ -724,51 +724,51 @@ stages: failTaskOnFailedTests: true displayName: Publish Test Results - # - job: Integration_FreeBSD - # displayName: Integration Native FreeBSD - # dependsOn: Prepare - # condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0')) - # workspace: - # clean: all - # variables: - # pattern: 'Prowlarr.*.freebsd-core-x64.tar.gz' - # pool: - # name: 'FreeBSD' + - job: Integration_FreeBSD + displayName: Integration Native FreeBSD + dependsOn: Prepare + condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0')) + workspace: + clean: all + variables: + pattern: 'Prowlarr.*.freebsd-core-x64.tar.gz' + pool: + name: 'FreeBSD' - # steps: - # - checkout: none - # - task: DownloadPipelineArtifact@2 - # displayName: Download Test Artifact - # inputs: - # buildType: 'current' - # artifactName: 'freebsd-x64-tests' - # targetPath: $(testsFolder) - # - task: DownloadPipelineArtifact@2 - # displayName: Download Build Artifact - # inputs: - # buildType: 'current' - # artifactName: Packages - # itemPattern: '/$(pattern)' - # targetPath: $(Build.ArtifactStagingDirectory) - # - bash: | - # mkdir -p ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin - # tar xf ${BUILD_ARTIFACTSTAGINGDIRECTORY}/$(pattern) -C ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin - # displayName: Extract Package - # - bash: | - # mkdir -p ./bin/ - # cp -r -v ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin/Prowlarr/. ./bin/ - # displayName: Move Package Contents - # - bash: | - # chmod a+x ${TESTSFOLDER}/test.sh - # ${TESTSFOLDER}/test.sh Linux Integration Test - # displayName: Run Integration Tests - # - task: PublishTestResults@2 - # inputs: - # testResultsFormat: 'NUnit' - # testResultsFiles: '**/TestResult.xml' - # testRunTitle: 'FreeBSD Integration Tests' - # failTaskOnFailedTests: true - # displayName: Publish Test Results + steps: + - checkout: none + - task: DownloadPipelineArtifact@2 + displayName: Download Test Artifact + inputs: + buildType: 'current' + artifactName: 'freebsd-x64-tests' + targetPath: $(testsFolder) + - task: DownloadPipelineArtifact@2 + displayName: Download Build Artifact + inputs: + buildType: 'current' + artifactName: Packages + itemPattern: '/$(pattern)' + targetPath: $(Build.ArtifactStagingDirectory) + - bash: | + mkdir -p ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin + tar xf ${BUILD_ARTIFACTSTAGINGDIRECTORY}/$(pattern) -C ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin + displayName: Extract Package + - bash: | + mkdir -p ./bin/ + cp -r -v ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin/Prowlarr/. ./bin/ + displayName: Move Package Contents + - bash: | + chmod a+x ${TESTSFOLDER}/test.sh + ${TESTSFOLDER}/test.sh Linux Integration Test + displayName: Run Integration Tests + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'NUnit' + testResultsFiles: '**/TestResult.xml' + testRunTitle: 'FreeBSD Integration Tests' + failTaskOnFailedTests: true + displayName: Publish Test Results - job: Integration_Docker displayName: Integration Docker From 1068ba89159e23e495a39c43fc3a97c31aceae53 Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Wed, 2 Nov 2022 21:45:47 +0000 Subject: [PATCH 0628/2320] Use wildcard pattern now we have better bsd agent --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 12be8fddf..18c62884d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -748,7 +748,7 @@ stages: inputs: buildType: 'current' artifactName: Packages - itemPattern: '/$(pattern)' + itemPattern: '**/$(pattern)' targetPath: $(Build.ArtifactStagingDirectory) - bash: | mkdir -p ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin From a9c210f8e7e8e3c3ee6db1b59d05f07d9b1332c4 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 3 Nov 2022 15:58:57 -0500 Subject: [PATCH 0629/2320] Create CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 132 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..4b06f1db6 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,132 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +<development@prowlarr.com>. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations From 6f122fb2e4abc4b3a7f3c5f1edfa6d5909273c6d Mon Sep 17 00:00:00 2001 From: Yukine <devyukine@gmx.de> Date: Sun, 30 Oct 2022 14:44:04 +0100 Subject: [PATCH 0630/2320] New: (AnimeBytes) add filename support for single episodes --- .../Indexers/Definitions/AnimeBytes.cs | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs index e698adb33..43e0033eb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs @@ -449,6 +449,37 @@ namespace NzbDrone.Core.Indexers.Definitions // Additional 5 hours per GB minimumSeedTime += (int)((size / 1000000000) * 18000); + if (_settings.UseFilenameForSingleEpisodes && torrent.FileCount == 1) + { + var fileName = torrent.Files.First().FileName; + + var guid = new Uri(details + "&nh=" + StringUtil.Hash(fileName)); + + var release = new TorrentInfo + { + MinimumRatio = 1, + MinimumSeedTime = minimumSeedTime, + Title = fileName, + InfoUrl = details.AbsoluteUri, + Guid = guid.AbsoluteUri, + DownloadUrl = link.AbsoluteUri, + PublishDate = publishDate, + Categories = category, + Description = description, + Size = size, + Seeders = seeders, + Peers = peers, + Grabs = snatched, + Files = fileCount, + DownloadVolumeFactor = rawDownMultiplier, + UploadVolumeFactor = rawUpMultiplier, + }; + + torrentInfos.Add(release); + + continue; + } + foreach (var title in synonyms) { var releaseTitle = groupName == "Movie" ? @@ -510,6 +541,7 @@ namespace NzbDrone.Core.Indexers.Definitions Passkey = ""; Username = ""; EnableSonarrCompatibility = true; + UseFilenameForSingleEpisodes = false; } [FieldDefinition(2, Label = "Passkey", HelpText = "Site Passkey", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] @@ -521,6 +553,9 @@ namespace NzbDrone.Core.Indexers.Definitions [FieldDefinition(4, Label = "Enable Sonarr Compatibility", Type = FieldType.Checkbox, HelpText = "Makes Prowlarr try to add Season information into Release names, without this Sonarr can't match any Seasons, but it has a lot of false positives as well")] public bool EnableSonarrCompatibility { get; set; } + [FieldDefinition(5, Label = "Use Filenames for Single Episodes", Type = FieldType.Checkbox, HelpText = "Makes Prowlarr replace AnimeBytes release names with the actual filename, this currently only works for single episode releases")] + public bool UseFilenameForSingleEpisodes { get; set; } + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); @@ -678,10 +713,22 @@ namespace NzbDrone.Core.Indexers.Definitions [JsonProperty("FileCount")] public int FileCount { get; set; } + [JsonProperty("FileList")] + public List<File> Files { get; set; } + [JsonProperty("UploadTime")] public DateTimeOffset UploadTime { get; set; } } + public class File + { + [JsonProperty("filename")] + public string FileName { get; set; } + + [JsonProperty("size")] + public string FileSize { get; set; } + } + public class EditionData { [JsonProperty("EditionTitle")] From c400575aacf557e4d5b91a9db940e6e5fb4f8ea3 Mon Sep 17 00:00:00 2001 From: Yukine <devyukine@gmx.de> Date: Sun, 30 Oct 2022 14:53:00 +0100 Subject: [PATCH 0631/2320] Fixed: (AnimeBytes) add delimiter to episode release --- src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs index 43e0033eb..005242e83 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs @@ -321,9 +321,10 @@ namespace NzbDrone.Core.Indexers.Definitions if (episode != null) { - releaseInfo = episode is > 0 and < 10 + var episodeString = episode is > 0 and < 10 ? "0" + episode : episode.ToString(); + releaseInfo = $" - {episodeString}"; } else { From 049668f30760a8e17660996f8f28c43e56dd62ff Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Tue, 1 Nov 2022 12:09:40 +0000 Subject: [PATCH 0632/2320] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (464 of 464 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 100.0% (464 of 464 strings) Translated using Weblate (Dutch) Currently translated at 87.0% (404 of 464 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (464 of 464 strings) Translated using Weblate (Portuguese) Currently translated at 78.7% (364 of 462 strings) Translated using Weblate (Chinese (Traditional) (zh_TW)) Currently translated at 2.8% (13 of 462 strings) Co-authored-by: Csaba <csab0825@gmail.com> Co-authored-by: Havok Dan <havokdan@yahoo.com.br> Co-authored-by: Thirrian <matthiaslantermann@gmail.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: korax1970 <duxlatronum@gmail.com> Co-authored-by: libsu <libsu@qq.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_TW/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/hu.json | 4 +++- src/NzbDrone.Core/Localization/Core/nl.json | 4 ++-- src/NzbDrone.Core/Localization/Core/pt_BR.json | 4 +++- src/NzbDrone.Core/Localization/Core/zh_CN.json | 6 ++++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index 0e82e860b..ad3c70d77 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -460,5 +460,7 @@ "Parameters": "Paraméterek", "Queued": "Sorba helyezve", "Started": "Elkezdődött", - "NextExecution": "Következő végrehajtás" + "NextExecution": "Következő végrehajtás", + "ApplicationLongTermStatusCheckSingleClientMessage": "Az alkamazások elérhetetlenek több mint 6 órája az alábbi hiba miatt: {0}", + "ApplicationLongTermStatusCheckAllClientMessage": "Az összes alkalmazás elérhetetlen több mint 6 órája meghibásodás miatt" } diff --git a/src/NzbDrone.Core/Localization/Core/nl.json b/src/NzbDrone.Core/Localization/Core/nl.json index 68b223a87..430e9dc9f 100644 --- a/src/NzbDrone.Core/Localization/Core/nl.json +++ b/src/NzbDrone.Core/Localization/Core/nl.json @@ -301,8 +301,8 @@ "IndexerLongTermStatusCheckAllClientMessage": "Alle indexeerders zijn niet beschikbaar vanwege storingen gedurende meer dan 6 uur", "ClearHistoryMessageText": "Weet je zeker dat je alle geschiedenis van Prowlarr wilt verwijderen", "ClearHistory": "Geschiedenis verwijderen", - "ApplicationStatusCheckSingleClientMessage": "Applicaties niet toegankelijk door fouten", - "ApplicationStatusCheckAllClientMessage": "Alle applicaties niet toegankelijk door fouten", + "ApplicationStatusCheckSingleClientMessage": "Applicaties onbeschikbaar door fouten", + "ApplicationStatusCheckAllClientMessage": "Alle applicaties onbeschikbaar door fouten", "AllIndexersHiddenDueToFilter": "Alle indexeerders zijn verborgen door actieve filter", "AddToDownloadClient": "Release toevoegen aan download client", "AddNewIndexer": "Voeg nieuwe Indexeerder Toe", diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index 967283eb5..7a00c054b 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -460,5 +460,7 @@ "GrabTitle": "Obter Título", "LastDuration": "Última Duração", "NextExecution": "Próxima Execução", - "Started": "Iniciado" + "Started": "Iniciado", + "ApplicationLongTermStatusCheckAllClientMessage": "Todos os aplicativos estão indisponíveis devido a falhas por mais de 6 horas", + "ApplicationLongTermStatusCheckSingleClientMessage": "Aplicativos indisponíveis devido a falhas por mais de 6 horas: {0}" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index 538748708..cfc726c11 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -282,7 +282,7 @@ "RemovedFromTaskQueue": "从任务队列中移除", "RemoveFilter": "移除过滤条件", "RemovingTag": "移除标签", - "RestartRequiredHelpTextWarning": "重启生效", + "RestartRequiredHelpTextWarning": "需要重新启动才能生效", "RestoreBackup": "恢复备份", "Result": "结果", "Retention": "保留", @@ -460,5 +460,7 @@ "Parameters": "参数", "Queued": "队列中", "Started": "已开始", - "LastDuration": "上一次用时" + "LastDuration": "上一次用时", + "ApplicationLongTermStatusCheckAllClientMessage": "由于故障超过6小时,所有程序都不可用", + "ApplicationLongTermStatusCheckSingleClientMessage": "由于故障超过6小时而无法使用的程序:{0}" } From d3dfa620ac65a87a05e6f5ff8eb115bee8d31a04 Mon Sep 17 00:00:00 2001 From: Bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Fri, 4 Nov 2022 09:45:36 -0500 Subject: [PATCH 0633/2320] Fix confusing session expired test message --- .../Indexers/Definitions/Cardigann/CardigannParser.cs | 2 +- .../Indexers/Definitions/PassThePopcorn/PassThePopcornParser.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index 8faa0b113..b5984fba2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -45,7 +45,7 @@ namespace NzbDrone.Core.Indexers.Cardigann .ContainsIgnoreCase("login.php")) { CookiesUpdater(null, null); - throw new IndexerException(indexerResponse, "We are being redirected to the login page. Most likely your session expired or was killed. Try testing the indexer in the settings."); + throw new IndexerException(indexerResponse, "We are being redirected to the login page. Most likely your session expired or was killed. Recheck your cookie or credentials and try testing the indexer."); } throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request"); diff --git a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornParser.cs b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornParser.cs index d7ce9c862..c31570230 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PassThePopcorn/PassThePopcornParser.cs @@ -34,7 +34,7 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn .ContainsIgnoreCase("login.php")) { CookiesUpdater(null, null); - throw new IndexerAuthException("We are being redirected to the PTP login page. Most likely your session expired or was killed. Try testing the indexer in the settings."); + throw new IndexerAuthException("We are being redirected to the PTP login page. Most likely your session expired or was killed. Recheck your cookie or credentials and try testing the indexer."); } if (indexerHttpResponse.StatusCode == HttpStatusCode.Forbidden) From b8cb0fd2912bbb65cbaec1625151e0e09d3a400d Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 5 Oct 2022 16:04:18 -0500 Subject: [PATCH 0634/2320] update bug report template [skip ci] --- .github/ISSUE_TEMPLATE/bug_report.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index ce79e928c..41a2d84b9 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -5,9 +5,9 @@ body: - type: checkboxes attributes: label: Is there an existing issue for this? - description: Please search to see if an issue already exists for the bug you encountered. + description: Please search to see if an open or closed issue already exists for the bug you encountered. If a bug exists and is closed note that it may only be fixed in an unstable branch. options: - - label: I have searched the existing issues + - label: I have searched the existing open and closed issues required: true - type: textarea attributes: From ea98d41472ef042e219ecf14766d714cdb454d4a Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 5 Oct 2022 16:08:08 -0500 Subject: [PATCH 0635/2320] Update feature_request.yml [skip ci] --- .github/ISSUE_TEMPLATE/feature_request.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index df8fc1f4e..b695e1c61 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -5,9 +5,9 @@ body: - type: checkboxes attributes: label: Is there an existing issue for this? - description: Please search to see if an issue already exists for the feature you are requesting. + description: Please search to see if an open or closed issue already exists for the feature you are requesting. If a request exists and is closed note that it may only be fixed in an unstable branch. options: - - label: I have searched the existing issues + - label: I have searched the existing open and closed issues required: true - type: textarea attributes: From f4bbf2f8af473d6c4156d310e2cd6e1ee296422f Mon Sep 17 00:00:00 2001 From: Bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Thu, 27 Oct 2022 16:20:27 -0500 Subject: [PATCH 0636/2320] Fixed: (Avistaz) Handle 429 Request Limit Reached --- .../Indexers/Definitions/Avistaz/AvistazParser.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs index c38fb9df4..183a8ef03 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs @@ -29,6 +29,11 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz return torrentInfos.ToArray(); } + if (indexerResponse.HttpResponse.StatusCode == HttpStatusCode.TooManyRequests) + { + throw new RequestLimitReachedException(indexerResponse, "API Request Limit Reached"); + } + if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) { throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request"); From ec8cf5f57aad15488bae7fdf2bee2f09815fd9e5 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sun, 6 Nov 2022 08:09:40 +0000 Subject: [PATCH 0637/2320] Translated using Weblate (Finnish) Currently translated at 99.5% (462 of 464 strings) Co-authored-by: Oskari Lavinto <olavinto@protonmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/fi.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/fi.json b/src/NzbDrone.Core/Localization/Core/fi.json index 385a7767b..48e3ac115 100644 --- a/src/NzbDrone.Core/Localization/Core/fi.json +++ b/src/NzbDrone.Core/Localization/Core/fi.json @@ -74,7 +74,7 @@ "ApplyTags": "Tunnistetoimenpide", "Authentication": "Todennus", "AuthenticationMethodHelpText": "Vaadi käyttäjätunnus ja salasana.", - "BindAddressHelpText": "Toimiva IPv4-osoite tai jokerimerkkinä '*' (tähti) kaikille yhteyksille.", + "BindAddressHelpText": "Toimiva IPv4-osoite tai '*' (tähti) kaikille yhteyksille.", "Close": "Sulje", "DeleteNotification": "Poista kytkentä", "Docker": "Docker", @@ -186,7 +186,7 @@ "Discord": "Discord", "Donations": "Lahjoitukset", "Edit": "Muokkaa", - "EnableAutomaticSearchHelpText": "Profiilia käytetään automaattihaun yhteydessä, kun sellainen suoritetaan käyttöliittymästä tai Prowlarin toimesta.", + "EnableAutomaticSearchHelpText": "Profiilia käytetään automaattihaun yhteydessä, kun haku suoritetaan käyttöliittymästä tai Prowlarrin toimesta.", "Enabled": "Käytössä", "EventType": "Tapahtumatyyppi", "Exception": "Poikkeus", @@ -243,7 +243,7 @@ "Cancel": "Peruuta", "CancelPendingTask": "Haluatko varmasti perua tämän odottavan tehtävän?", "CertificateValidation": "Varmenteen vahvistus", - "CertificateValidationHelpText": "Valitse HTTPS-varmenteen vahvistuksen tarkkuus. Älä muuta, jollet ymmärrä tähän liittyviä riskejä.", + "CertificateValidationHelpText": "Muuta HTTPS-varmennevahvistuksen tarkkuutta. Älä muuta, jollet ymmärrä tähän liittyviä riskejä.", "ChangeHasNotBeenSavedYet": "Muutosta ei ole vielä tallennettu", "Clear": "Tyhjennä", "CloneProfile": "Kloonaa profiili", @@ -402,7 +402,7 @@ "Filters": "Suodattimet", "OnGrab": "Kun elokuva siepataan", "OnHealthIssue": "Kun havaitaan kuntoon liittyvä ongelma", - "HistoryCleanupDaysHelpText": "Älä tyhjennä automaattisesti asettamalla arvoksi '0'.", + "HistoryCleanupDaysHelpText": "Poista automaattinen tyhjennys käytöstä asettamalla arvoksi '0'.", "HistoryCleanupDaysHelpTextWarning": "Tässä määritettyä aikaa vanhemmat tiedostot poistetaan automaattisesti roskakorista pysyvästi.", "TestAllIndexers": "Testaa tietolähteet", "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent-tiedon ilmoitti sovellus, joka kommunikoi API:n kanssa", From 90e3c809c33a28700806dcc2b42b3e24d798f213 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 13 Jul 2022 10:43:41 -0500 Subject: [PATCH 0638/2320] New: Notifiarr moved from webhook to API New: Notifiarr Add Instance Name Support Fixed: Notifiarr - Better HTTP Error Handling also quiet sentry move apikey to header from url (cherry picked from commit 1db690ad39ec103c0f4dc89ac4545801ef95bec7) Fixed: Improve Notifiarr Exception Handling and Validation Errors (cherry picked from commit 6aaa024d71b939030950460ae986ada5bbae5ad7) --- .../Notifications/Notifiarr/NotifiarrProxy.cs | 68 +++++++++++-------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/src/NzbDrone.Core/Notifications/Notifiarr/NotifiarrProxy.cs b/src/NzbDrone.Core/Notifications/Notifiarr/NotifiarrProxy.cs index d6b476d5a..67728f88b 100644 --- a/src/NzbDrone.Core/Notifications/Notifiarr/NotifiarrProxy.cs +++ b/src/NzbDrone.Core/Notifications/Notifiarr/NotifiarrProxy.cs @@ -1,9 +1,10 @@ -using System; +using System; using System.Collections.Specialized; -using System.Net; using FluentValidation.Results; using NLog; +using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Core.Configuration; namespace NzbDrone.Core.Notifications.Notifiarr { @@ -15,27 +16,21 @@ namespace NzbDrone.Core.Notifications.Notifiarr public class NotifiarrProxy : INotifiarrProxy { - private const string URL = "https://notifiarr.com/notifier.php"; + private const string URL = "https://notifiarr.com"; private readonly IHttpClient _httpClient; + private readonly IConfigFileProvider _configFileProvider; private readonly Logger _logger; - public NotifiarrProxy(IHttpClient httpClient, Logger logger) + public NotifiarrProxy(IHttpClient httpClient, IConfigFileProvider configFileProvider, Logger logger) { _httpClient = httpClient; + _configFileProvider = configFileProvider; _logger = logger; } public void SendNotification(StringDictionary message, NotifiarrSettings settings) { - try - { ProcessNotification(message, settings); - } - catch (NotifiarrException ex) - { - _logger.Error(ex, "Unable to send notification"); - throw new NotifiarrException("Unable to send notification"); - } } public ValidationFailure Test(NotifiarrSettings settings) @@ -48,21 +43,14 @@ namespace NzbDrone.Core.Notifications.Notifiarr SendNotification(variables, settings); return null; } - catch (HttpException ex) + catch (NotifiarrException ex) { - if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) - { - _logger.Error(ex, "API key is invalid: " + ex.Message); - return new ValidationFailure("APIKey", "API key is invalid"); - } - - _logger.Error(ex, "Unable to send test message: " + ex.Message); - return new ValidationFailure("APIKey", "Unable to send test notification"); + return new ValidationFailure("APIKey", ex.Message); } catch (Exception ex) { - _logger.Error(ex, "Unable to send test notification: " + ex.Message); - return new ValidationFailure("", "Unable to send test notification"); + _logger.Error(ex, ex.Message); + return new ValidationFailure("", "Unable to send test notification. Check the log for more details."); } } @@ -70,8 +58,10 @@ namespace NzbDrone.Core.Notifications.Notifiarr { try { - var requestBuilder = new HttpRequestBuilder(URL).Post(); - requestBuilder.AddFormParameter("api", settings.APIKey).Build(); + var instanceName = _configFileProvider.InstanceName; + var requestBuilder = new HttpRequestBuilder(URL + "/api/v1/notification/prowlarr").Post(); + requestBuilder.AddFormParameter("instanceName", instanceName).Build(); + requestBuilder.SetHeader("X-API-Key", settings.APIKey); foreach (string key in message.Keys) { @@ -84,13 +74,31 @@ namespace NzbDrone.Core.Notifications.Notifiarr } catch (HttpException ex) { - if (ex.Response.StatusCode == HttpStatusCode.BadRequest) + var responseCode = ex.Response.StatusCode; + switch ((int)responseCode) { - _logger.Error(ex, "API key is invalid"); - throw; + case 401: + _logger.Error("Unauthorized", "HTTP 401 - API key is invalid"); + throw new NotifiarrException("API key is invalid"); + case 400: + _logger.Error("Invalid Request", "HTTP 400 - Unable to send notification. Ensure Prowlarr Integration is enabled & assigned a channel on Notifiarr"); + throw new NotifiarrException("Unable to send notification. Ensure Prowlarr Integration is enabled & assigned a channel on Notifiarr"); + case 502: + case 503: + case 504: + _logger.Error("Service Unavailable", "Unable to send notification. Service Unavailable"); + throw new NotifiarrException("Unable to send notification. Service Unavailable", ex); + case 520: + case 521: + case 522: + case 523: + case 524: + _logger.Error(ex, "Cloudflare Related HTTP Error - Unable to send notification"); + throw new NotifiarrException("Cloudflare Related HTTP Error - Unable to send notification", ex); + default: + _logger.Error(ex, "Unknown HTTP Error - Unable to send notification"); + throw new NotifiarrException("Unknown HTTP Error - Unable to send notification", ex); } - - throw new NotifiarrException("Unable to send notification", ex); } } } From 7ddbe09eca16ceafbbac6c9b89852ebf0c8c61db Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 7 Nov 2022 19:26:54 -0600 Subject: [PATCH 0639/2320] New: Base API info endpoint --- src/Prowlarr.Http/ApiInfoController.cs | 23 +++++++++++++++++++++++ src/Prowlarr.Http/ApiInfoResource.cs | 14 ++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 src/Prowlarr.Http/ApiInfoController.cs create mode 100644 src/Prowlarr.Http/ApiInfoResource.cs diff --git a/src/Prowlarr.Http/ApiInfoController.cs b/src/Prowlarr.Http/ApiInfoController.cs new file mode 100644 index 000000000..2101392d5 --- /dev/null +++ b/src/Prowlarr.Http/ApiInfoController.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc; + +namespace Prowlarr.Http +{ + public class ApiInfoController : Controller + { + public ApiInfoController() + { + } + + [HttpGet("/api")] + [Produces("application/json")] + public ApiInfoResource GetApiInfo() + { + return new ApiInfoResource + { + Current = "v1", + Deprecated = new List<string>() + }; + } + } +} diff --git a/src/Prowlarr.Http/ApiInfoResource.cs b/src/Prowlarr.Http/ApiInfoResource.cs new file mode 100644 index 000000000..b8f34301c --- /dev/null +++ b/src/Prowlarr.Http/ApiInfoResource.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Prowlarr.Http +{ + public class ApiInfoResource + { + public string Current { get; set; } + public List<string> Deprecated { get; set; } + } +} From dae21f22b92d4100d04ffc7c65af108862f486dc Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Mon, 7 Nov 2022 19:30:14 -0600 Subject: [PATCH 0640/2320] Bump version to 0.4.8 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 18c62884d..2ac8ca144 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: testsFolder: './_tests' yarnCacheFolder: $(Pipeline.Workspace)/.yarn nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages - majorVersion: '0.4.7' + majorVersion: '0.4.8' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From 2805c4f18b292abb04034808bc6e78effd8f23c5 Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Tue, 8 Nov 2022 01:35:52 +0000 Subject: [PATCH 0641/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index aadfde6f3..e6bdc2f83 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -27,6 +27,25 @@ } ], "paths": { + "/api": { + "get": { + "tags": [ + "ApiInfo" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiInfoResource" + } + } + } + } + } + } + }, "/api/v1/applications/{id}": { "get": { "tags": [ @@ -4406,6 +4425,23 @@ }, "components": { "schemas": { + "ApiInfoResource": { + "type": "object", + "properties": { + "current": { + "type": "string", + "nullable": true + }, + "deprecated": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, "AppProfileResource": { "type": "object", "properties": { From 9e37f692242c556d30c0eb3d580068400198e787 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 10 Nov 2022 06:54:20 -0600 Subject: [PATCH 0642/2320] Fixed: (RetroFlix) Urls built with double slash Fixes #1188 Closes #1192 --- src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs | 2 +- .../Indexers/Definitions/SpeedApp/SpeedAppBase.cs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs index 88ea57608..95ae6a773 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs @@ -9,7 +9,7 @@ namespace NzbDrone.Core.Indexers.Definitions { public override string Name => "SpeedApp.io"; - public override string[] IndexerUrls => new string[] { "https://speedapp.io" }; + public override string[] IndexerUrls => new string[] { "https://speedapp.io/" }; public override string Description => "SpeedApp is a ROMANIAN Private Torrent Tracker for MOVIES / TV / GENERAL"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs index 621889b64..1e30bb7cb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs @@ -28,9 +28,7 @@ namespace NzbDrone.Core.Indexers.Definitions { public abstract class SpeedAppBase : TorrentIndexerBase<SpeedAppSettings> { - private string ApiUrl => $"{Settings.BaseUrl}/api"; - - private string LoginUrl => $"{ApiUrl}/login"; + private string LoginUrl => Settings.BaseUrl + "api/login"; public override Encoding Encoding => Encoding.UTF8; @@ -262,7 +260,7 @@ namespace NzbDrone.Core.Indexers.Definitions } } - var searchUrl = Settings.BaseUrl + "/api/torrent?" + qc.GetQueryString(duplicateKeysIfMulti: true); + var searchUrl = Settings.BaseUrl + "api/torrent?" + qc.GetQueryString(duplicateKeysIfMulti: true); var request = new IndexerRequest(searchUrl, HttpAccept.Json); From d935b0df8246be66a4b3992c62bcce8e438a79b1 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 10 Nov 2022 17:39:14 -0600 Subject: [PATCH 0643/2320] Fix regression in release analytics service after debounce added Fixes #1193 --- src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs index 1bf364ffe..b058dc461 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs @@ -37,7 +37,7 @@ namespace NzbDrone.Core.IndexerSearch public void HandleAsync(IndexerQueryEvent message) { - if (message.QueryResult?.Releases != null) + if (_analyticsService.IsEnabled && message.QueryResult?.Releases != null) { lock (_pendingUpdates) { From a0d18c546e93e19cc03f7d1cc64f8dab2cdda214 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 12 Nov 2022 20:03:35 -0600 Subject: [PATCH 0644/2320] Bump version to 0.4.9 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2ac8ca144..c67f79b56 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: testsFolder: './_tests' yarnCacheFolder: $(Pipeline.Workspace)/.yarn nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages - majorVersion: '0.4.8' + majorVersion: '0.4.9' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From bd0115931f08b8868730e8d7b6286f34e7ba6575 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 12 Nov 2022 22:02:13 -0600 Subject: [PATCH 0645/2320] Bump version to 0.4.10 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c67f79b56..1664dbd8e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: testsFolder: './_tests' yarnCacheFolder: $(Pipeline.Workspace)/.yarn nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages - majorVersion: '0.4.9' + majorVersion: '0.4.10' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From 4f4c0114369a1b0448c78f87c92a3ed3a4ebfd6f Mon Sep 17 00:00:00 2001 From: ta264 <ta264@users.noreply.github.com> Date: Sun, 13 Nov 2022 17:07:55 +0000 Subject: [PATCH 0646/2320] Swap Orpheus to API key (#946) * New: Orpheus uses API key instead of user/pass * fixup! New: Orpheus uses API key instead of user/pass Co-authored-by: Qstick <qstick@gmail.com> --- .../Datastore/Migration/022_orpheus_api.cs | 63 ++++ .../Definitions/Gazelle/GazelleSettings.cs | 2 +- .../Indexers/Definitions/Orpheus.cs | 315 +++++++++++++++++- .../Indexers/Definitions/Redacted.cs | 49 ++- 4 files changed, 389 insertions(+), 40 deletions(-) create mode 100644 src/NzbDrone.Core/Datastore/Migration/022_orpheus_api.cs diff --git a/src/NzbDrone.Core/Datastore/Migration/022_orpheus_api.cs b/src/NzbDrone.Core/Datastore/Migration/022_orpheus_api.cs new file mode 100644 index 000000000..3907af367 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/022_orpheus_api.cs @@ -0,0 +1,63 @@ +using System.Data; +using FluentMigrator; +using Newtonsoft.Json.Linq; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(22)] + public class orpheus_api : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Execute.WithConnection(MigrateToRedactedApi); + } + + private void MigrateToRedactedApi(IDbConnection conn, IDbTransaction tran) + { + using (var cmd = conn.CreateCommand()) + { + cmd.Transaction = tran; + cmd.CommandText = "SELECT \"Id\", \"Settings\" FROM \"Indexers\" WHERE \"Implementation\" = 'Orpheus'"; + + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + var id = reader.GetInt32(0); + var settings = reader.GetString(1); + if (!string.IsNullOrWhiteSpace(settings)) + { + var jsonObject = Json.Deserialize<JObject>(settings); + + // Remove username + if (jsonObject.ContainsKey("username")) + { + jsonObject.Remove("username"); + } + + // Remove password + if (jsonObject.ContainsKey("password")) + { + jsonObject.Remove("password"); + } + + // write new json back to db, switch to new ConfigContract, and disable the indexer + settings = jsonObject.ToJson(); + using (var updateCmd = conn.CreateCommand()) + { + updateCmd.Transaction = tran; + updateCmd.CommandText = "UPDATE \"Indexers\" SET \"Settings\" = ?, \"ConfigContract\" = ?, \"Enable\" = 0 WHERE \"Id\" = ?"; + updateCmd.AddParameter(settings); + updateCmd.AddParameter("OrpheusSettings"); + updateCmd.AddParameter(id); + updateCmd.ExecuteNonQuery(); + } + } + } + } + } + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleSettings.cs index 3461543d8..8f3dc85ea 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleSettings.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Core.Indexers.Gazelle public string AuthKey; public string PassKey; - [FieldDefinition(4, Type = FieldType.Checkbox, Label = "Use Freeleech Token", HelpText = "Use Freeleech Token")] + [FieldDefinition(4, Type = FieldType.Checkbox, Label = "Use Freeleech Token", HelpText = "Use freeleech tokens when available")] public bool UseFreeleechToken { get; set; } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs index cd7286542..b52287137 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs @@ -1,25 +1,51 @@ +using System; using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using FluentValidation; using NLog; using NzbDrone.Common.Http; +using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Gazelle; +using NzbDrone.Core.Indexers.Settings; +using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { - public class Orpheus : Gazelle.Gazelle + public class Orpheus : TorrentIndexerBase<OrpheusSettings> { public override string Name => "Orpheus"; public override string[] IndexerUrls => new string[] { "https://orpheus.network/" }; public override string Description => "Orpheus (APOLLO) is a Private Torrent Tracker for MUSIC"; + public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + public override IndexerCapabilities Capabilities => SetCapabilities(); + public override bool SupportsRedirect => true; public Orpheus(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) - : base(httpClient, eventAggregator, indexerStatusService, configService, logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) { } - protected override IndexerCapabilities SetCapabilities() + public override IIndexerRequestGenerator GetRequestGenerator() + { + return new OrpheusRequestGenerator() { Settings = Settings, Capabilities = Capabilities, HttpClient = _httpClient }; + } + + public override IParseIndexerResponse GetParser() + { + return new OrpheusParser(Settings, Capabilities.Categories); + } + + private IndexerCapabilities SetCapabilities() { var caps = new IndexerCapabilities { @@ -44,23 +70,252 @@ namespace NzbDrone.Core.Indexers.Definitions return caps; } - public override IParseIndexerResponse GetParser() + public override async Task<byte[]> Download(Uri link) { - return new OrpheusParser(Settings, Capabilities); + var request = new HttpRequestBuilder(link.AbsoluteUri) + .SetHeader("Authorization", $"token {Settings.Apikey}") + .Build(); + + var downloadBytes = Array.Empty<byte>(); + + try + { + var response = await _httpClient.ExecuteProxiedAsync(request, Definition); + downloadBytes = response.ResponseData; + + if (downloadBytes.Length >= 1 + && downloadBytes[0] != 'd' // simple test for torrent vs HTML content + && link.Query.Contains("usetoken=1")) + { + var html = Encoding.GetString(downloadBytes); + if (html.Contains("You do not have any freeleech tokens left.") + || html.Contains("You do not have enough freeleech tokens") + || html.Contains("This torrent is too large.") + || html.Contains("You cannot use tokens here")) + { + // download again without usetoken + request.Url = new HttpUri(link.ToString().Replace("&usetoken=1", "")); + + response = await _httpClient.ExecuteProxiedAsync(request, Definition); + downloadBytes = response.ResponseData; + } + } + } + catch (Exception) + { + _indexerStatusService.RecordFailure(Definition.Id); + _logger.Error("Download failed"); + } + + return downloadBytes; } } - public class OrpheusParser : GazelleParser + public class OrpheusRequestGenerator : IIndexerRequestGenerator { - public OrpheusParser(GazelleSettings settings, IndexerCapabilities capabilities) - : base(settings, capabilities) + public OrpheusSettings Settings { get; set; } + public IndexerCapabilities Capabilities { get; set; } + public Func<IDictionary<string, string>> GetCookies { get; set; } + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + public IIndexerHttpClient HttpClient { get; set; } + + public OrpheusRequestGenerator() { } - protected override string GetDownloadUrl(int torrentId) + public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetRequest(string.Format("&artistname={0}&groupname={1}", searchCriteria.Artist, searchCriteria.Album))); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetRequest(searchCriteria.SanitizedSearchTerm)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + { + return new IndexerPageableRequestChain(); + } + + public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) + { + return new IndexerPageableRequestChain(); + } + + public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetRequest(searchCriteria.SanitizedSearchTerm)); + + return pageableRequests; + } + + private IEnumerable<IndexerRequest> GetRequest(string searchParameters) + { + var req = RequestBuilder() + .Resource($"ajax.php?action=browse&searchstr={searchParameters}") + .Build(); + + yield return new IndexerRequest(req); + } + + private HttpRequestBuilder RequestBuilder() + { + return new HttpRequestBuilder($"{Settings.BaseUrl.Trim().TrimEnd('/')}") + .Accept(HttpAccept.Json) + .SetHeader("Authorization", $"token {Settings.Apikey}"); + } + } + + public class OrpheusParser : IParseIndexerResponse + { + private readonly OrpheusSettings _settings; + private readonly IndexerCapabilitiesCategories _categories; + public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } + + public OrpheusParser(OrpheusSettings settings, IndexerCapabilitiesCategories categories) + { + _settings = settings; + _categories = categories; + } + + public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse) + { + var torrentInfos = new List<ReleaseInfo>(); + + if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) + { + throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request"); + } + + if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value)) + { + throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}"); + } + + var jsonResponse = new HttpResponse<GazelleResponse>(indexerResponse.HttpResponse); + if (jsonResponse.Resource.Status != "success" || + string.IsNullOrWhiteSpace(jsonResponse.Resource.Status) || + jsonResponse.Resource.Response == null) + { + return torrentInfos; + } + + foreach (var result in jsonResponse.Resource.Response.Results) + { + if (result.Torrents != null) + { + foreach (var torrent in result.Torrents) + { + var id = torrent.TorrentId; + var artist = WebUtility.HtmlDecode(result.Artist); + var album = WebUtility.HtmlDecode(result.GroupName); + + var title = $"{result.Artist} - {result.GroupName} ({result.GroupYear}) [{torrent.Format} {torrent.Encoding}] [{torrent.Media}]"; + if (torrent.HasCue) + { + title += " [Cue]"; + } + + var infoUrl = GetInfoUrl(result.GroupId, id); + + GazelleInfo release = new GazelleInfo() + { + Guid = infoUrl, + + // Splice Title from info to avoid calling API again for every torrent. + Title = WebUtility.HtmlDecode(title), + + Container = torrent.Encoding, + Codec = torrent.Format, + Size = long.Parse(torrent.Size), + DownloadUrl = GetDownloadUrl(id, torrent.CanUseToken), + InfoUrl = infoUrl, + Seeders = int.Parse(torrent.Seeders), + Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders), + PublishDate = torrent.Time.ToUniversalTime(), + Scene = torrent.Scene, + Freeleech = torrent.IsFreeLeech || torrent.IsPersonalFreeLeech, + Files = torrent.FileCount, + Grabs = torrent.Snatches, + DownloadVolumeFactor = torrent.IsFreeLeech || torrent.IsNeutralLeech || torrent.IsPersonalFreeLeech ? 0 : 1, + UploadVolumeFactor = torrent.IsNeutralLeech ? 0 : 1 + }; + + var category = torrent.Category; + if (category == null || category.Contains("Select Category")) + { + release.Categories = _categories.MapTrackerCatToNewznab("1"); + } + else + { + release.Categories = _categories.MapTrackerCatDescToNewznab(category); + } + + torrentInfos.Add(release); + } + } + + // Non-Audio files are formatted a little differently (1:1 for group and torrents) + else + { + var id = result.TorrentId; + var infoUrl = GetInfoUrl(result.GroupId, id); + + GazelleInfo release = new GazelleInfo() + { + Guid = infoUrl, + Title = WebUtility.HtmlDecode(result.GroupName), + Size = long.Parse(result.Size), + DownloadUrl = GetDownloadUrl(id, result.CanUseToken), + InfoUrl = infoUrl, + Seeders = int.Parse(result.Seeders), + Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders), + PublishDate = DateTimeOffset.FromUnixTimeSeconds(ParseUtil.CoerceLong(result.GroupTime)).UtcDateTime, + Freeleech = result.IsFreeLeech || result.IsPersonalFreeLeech, + Files = result.FileCount, + Grabs = result.Snatches, + DownloadVolumeFactor = result.IsFreeLeech || result.IsNeutralLeech || result.IsPersonalFreeLeech ? 0 : 1, + UploadVolumeFactor = result.IsNeutralLeech ? 0 : 1 + }; + + var category = result.Category; + if (category == null || category.Contains("Select Category")) + { + release.Categories = _categories.MapTrackerCatToNewznab("1"); + } + else + { + release.Categories = _categories.MapTrackerCatDescToNewznab(category); + } + + torrentInfos.Add(release); + } + } + + // order by date + return + torrentInfos + .OrderByDescending(o => o.PublishDate) + .ToArray(); + } + + private string GetDownloadUrl(int torrentId, bool canUseToken) + { + // AuthKey is required but not checked, just pass in a dummy variable + // to avoid having to track authkey, which is randomly cycled var url = new HttpUri(_settings.BaseUrl) - .CombinePath("/torrents.php") + .CombinePath("/ajax.php") .AddQueryParam("action", "download") .AddQueryParam("id", torrentId); @@ -72,5 +327,45 @@ namespace NzbDrone.Core.Indexers.Definitions return url.FullUri; } + + private string GetInfoUrl(string groupId, int torrentId) + { + var url = new HttpUri(_settings.BaseUrl) + .CombinePath("/torrents.php") + .AddQueryParam("id", groupId) + .AddQueryParam("torrentid", torrentId); + + return url.FullUri; + } + } + + public class OrpheusSettingsValidator : AbstractValidator<OrpheusSettings> + { + public OrpheusSettingsValidator() + { + RuleFor(c => c.Apikey).NotEmpty(); + } + } + + public class OrpheusSettings : NoAuthTorrentBaseSettings + { + private static readonly OrpheusSettingsValidator Validator = new OrpheusSettingsValidator(); + + public OrpheusSettings() + { + Apikey = ""; + UseFreeleechToken = false; + } + + [FieldDefinition(2, Label = "API Key", HelpText = "API Key from the Site (Found in Settings => Access Settings)", Privacy = PrivacyLevel.ApiKey)] + public string Apikey { get; set; } + + [FieldDefinition(3, Label = "Use Freeleech Tokens", HelpText = "Use freeleech tokens when available", Type = FieldType.Checkbox)] + public bool UseFreeleechToken { get; set; } + + public override NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs b/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs index 9fe615e10..6fe62739e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs @@ -27,8 +27,6 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "Redacted"; public override string[] IndexerUrls => new string[] { "https://redacted.ch/" }; public override string Description => "REDActed (Aka.PassTheHeadPhones) is one of the most well-known music trackers."; - public override string Language => "en-US"; - public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerCapabilities Capabilities => SetCapabilities(); @@ -82,10 +80,26 @@ namespace NzbDrone.Core.Indexers.Definitions return caps; } - protected override async Task Test(List<ValidationFailure> failures) + public override async Task<byte[]> Download(Uri link) { - ((RedactedRequestGenerator)GetRequestGenerator()).FetchPasskey(); - await base.Test(failures); + var request = new HttpRequestBuilder(link.AbsoluteUri) + .SetHeader("Authorization", Settings.Apikey) + .Build(); + + var downloadBytes = Array.Empty<byte>(); + + try + { + var response = await _httpClient.ExecuteProxiedAsync(request, Definition); + downloadBytes = response.ResponseData; + } + catch (Exception) + { + _indexerStatusService.RecordFailure(Definition.Id); + _logger.Error("Download failed"); + } + + return downloadBytes; } } @@ -138,24 +152,6 @@ namespace NzbDrone.Core.Indexers.Definitions return pageableRequests; } - public void FetchPasskey() - { - // GET on index for the passkey - var request = RequestBuilder().Resource("ajax.php?action=index").Build(); - var indexResponse = HttpClient.Execute(request); - var index = Json.Deserialize<GazelleAuthResponse>(indexResponse.Content); - if (index == null || - string.IsNullOrWhiteSpace(index.Status) || - index.Status != "success" || - string.IsNullOrWhiteSpace(index.Response.Passkey)) - { - throw new Exception("Failed to authenticate with Redacted."); - } - - // Set passkey on settings so it can be used to generate the download URL - Settings.Passkey = index.Response.Passkey; - } - private IEnumerable<IndexerRequest> GetRequest(string searchParameters) { var req = RequestBuilder() @@ -311,11 +307,9 @@ namespace NzbDrone.Core.Indexers.Definitions // AuthKey is required but not checked, just pass in a dummy variable // to avoid having to track authkey, which is randomly cycled var url = new HttpUri(_settings.BaseUrl) - .CombinePath("/torrents.php") + .CombinePath("/ajax.php") .AddQueryParam("action", "download") .AddQueryParam("id", torrentId) - .AddQueryParam("authkey", "prowlarr") - .AddQueryParam("torrent_pass", _settings.Passkey) .AddQueryParam("usetoken", (_settings.UseFreeleechToken && canUseToken) ? 1 : 0); return url.FullUri; @@ -347,7 +341,6 @@ namespace NzbDrone.Core.Indexers.Definitions public RedactedSettings() { Apikey = ""; - Passkey = ""; UseFreeleechToken = false; } @@ -357,8 +350,6 @@ namespace NzbDrone.Core.Indexers.Definitions [FieldDefinition(3, Label = "Use Freeleech Tokens", HelpText = "Use freeleech tokens when available", Type = FieldType.Checkbox)] public bool UseFreeleechToken { get; set; } - public string Passkey { get; set; } - public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); From 9ff0b9062699cebc44e53231dd9ab9e9742d11c2 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 13 Nov 2022 13:18:44 -0600 Subject: [PATCH 0647/2320] Convert Notifiarr Payload to JSON, Standardize with Webhook (#1194) * Convert Notifiarr Payload to JSON, Standardize with Webhook * fixup! --- .../Notifications/Notifiarr/Notifiarr.cs | 44 +++++++------ .../Notifications/Notifiarr/NotifiarrProxy.cs | 64 +++++-------------- .../Notifications/Webhook/Webhook.cs | 34 ++-------- .../Notifications/Webhook/WebhookBase.cs | 51 +++++++++++++++ .../Notifications/Webhook/WebhookPayload.cs | 1 + 5 files changed, 97 insertions(+), 97 deletions(-) create mode 100644 src/NzbDrone.Core/Notifications/Webhook/WebhookBase.cs diff --git a/src/NzbDrone.Core/Notifications/Notifiarr/Notifiarr.cs b/src/NzbDrone.Core/Notifications/Notifiarr/Notifiarr.cs index 255567784..2f3c651fc 100644 --- a/src/NzbDrone.Core/Notifications/Notifiarr/Notifiarr.cs +++ b/src/NzbDrone.Core/Notifications/Notifiarr/Notifiarr.cs @@ -1,15 +1,18 @@ using System.Collections.Generic; -using System.Collections.Specialized; using FluentValidation.Results; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Notifications.Webhook; +using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Notifiarr { - public class Notifiarr : NotificationBase<NotifiarrSettings> + public class Notifiarr : WebhookBase<NotifiarrSettings> { private readonly INotifiarrProxy _proxy; - public Notifiarr(INotifiarrProxy proxy) + public Notifiarr(INotifiarrProxy proxy, IConfigFileProvider configFileProvider) + : base(configFileProvider) { _proxy = proxy; } @@ -18,36 +21,35 @@ namespace NzbDrone.Core.Notifications.Notifiarr public override string Name => "Notifiarr"; public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck) { - var variables = new StringDictionary(); - - variables.Add("Prowlarr_EventType", "HealthIssue"); - variables.Add("Prowlarr_Health_Issue_Level", healthCheck.Type.ToString() ?? string.Empty); - variables.Add("Prowlarr_Health_Issue_Message", healthCheck.Message); - variables.Add("Prowlarr_Health_Issue_Type", healthCheck.Source.Name); - variables.Add("Prowlarr_Health_Issue_Wiki", healthCheck.WikiUrl.ToString() ?? string.Empty); - - _proxy.SendNotification(variables, Settings); + _proxy.SendNotification(BuildHealthPayload(healthCheck), Settings); } public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { - var variables = new StringDictionary(); - - variables.Add("Prowlarr_EventType", "ApplicationUpdate"); - variables.Add("Prowlarr_Update_Message", updateMessage.Message); - variables.Add("Prowlarr_Update_NewVersion", updateMessage.NewVersion.ToString()); - variables.Add("Prowlarr_Update_PreviousVersion", updateMessage.PreviousVersion.ToString()); - - _proxy.SendNotification(variables, Settings); + _proxy.SendNotification(BuildApplicationUploadPayload(updateMessage), Settings); } public override ValidationResult Test() { var failures = new List<ValidationFailure>(); - failures.AddIfNotNull(_proxy.Test(Settings)); + failures.AddIfNotNull(SendWebhookTest()); return new ValidationResult(failures); } + + private ValidationFailure SendWebhookTest() + { + try + { + _proxy.SendNotification(BuildTestPayload(), Settings); + } + catch (NotifiarrException ex) + { + return new NzbDroneValidationFailure("APIKey", ex.Message); + } + + return null; + } } } diff --git a/src/NzbDrone.Core/Notifications/Notifiarr/NotifiarrProxy.cs b/src/NzbDrone.Core/Notifications/Notifiarr/NotifiarrProxy.cs index 67728f88b..6b0bf6375 100644 --- a/src/NzbDrone.Core/Notifications/Notifiarr/NotifiarrProxy.cs +++ b/src/NzbDrone.Core/Notifications/Notifiarr/NotifiarrProxy.cs @@ -1,74 +1,45 @@ -using System; -using System.Collections.Specialized; -using FluentValidation.Results; +using System.Net.Http; using NLog; -using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; +using NzbDrone.Common.Serializer; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Notifications.Webhook; namespace NzbDrone.Core.Notifications.Notifiarr { public interface INotifiarrProxy { - void SendNotification(StringDictionary message, NotifiarrSettings settings); - ValidationFailure Test(NotifiarrSettings settings); + void SendNotification(WebhookPayload payload, NotifiarrSettings settings); } public class NotifiarrProxy : INotifiarrProxy { private const string URL = "https://notifiarr.com"; private readonly IHttpClient _httpClient; - private readonly IConfigFileProvider _configFileProvider; - private readonly Logger _logger; - public NotifiarrProxy(IHttpClient httpClient, IConfigFileProvider configFileProvider, Logger logger) + public NotifiarrProxy(IHttpClient httpClient) { _httpClient = httpClient; - _configFileProvider = configFileProvider; - _logger = logger; } - public void SendNotification(StringDictionary message, NotifiarrSettings settings) + public void SendNotification(WebhookPayload payload, NotifiarrSettings settings) { - ProcessNotification(message, settings); + ProcessNotification(payload, settings); } - public ValidationFailure Test(NotifiarrSettings settings) + private void ProcessNotification(WebhookPayload payload, NotifiarrSettings settings) { try { - var variables = new StringDictionary(); - variables.Add("Prowlarr_EventType", "Test"); + var request = new HttpRequestBuilder(URL + "/api/v1/notification/prowlarr") + .Accept(HttpAccept.Json) + .SetHeader("X-API-Key", settings.APIKey) + .Build(); - SendNotification(variables, settings); - return null; - } - catch (NotifiarrException ex) - { - return new ValidationFailure("APIKey", ex.Message); - } - catch (Exception ex) - { - _logger.Error(ex, ex.Message); - return new ValidationFailure("", "Unable to send test notification. Check the log for more details."); - } - } + request.Method = HttpMethod.Post; - private void ProcessNotification(StringDictionary message, NotifiarrSettings settings) - { - try - { - var instanceName = _configFileProvider.InstanceName; - var requestBuilder = new HttpRequestBuilder(URL + "/api/v1/notification/prowlarr").Post(); - requestBuilder.AddFormParameter("instanceName", instanceName).Build(); - requestBuilder.SetHeader("X-API-Key", settings.APIKey); - - foreach (string key in message.Keys) - { - requestBuilder.AddFormParameter(key, message[key]); - } - - var request = requestBuilder.Build(); + request.Headers.ContentType = "application/json"; + request.SetContent(payload.ToJson()); _httpClient.Post(request); } @@ -78,25 +49,20 @@ namespace NzbDrone.Core.Notifications.Notifiarr switch ((int)responseCode) { case 401: - _logger.Error("Unauthorized", "HTTP 401 - API key is invalid"); throw new NotifiarrException("API key is invalid"); case 400: - _logger.Error("Invalid Request", "HTTP 400 - Unable to send notification. Ensure Prowlarr Integration is enabled & assigned a channel on Notifiarr"); throw new NotifiarrException("Unable to send notification. Ensure Prowlarr Integration is enabled & assigned a channel on Notifiarr"); case 502: case 503: case 504: - _logger.Error("Service Unavailable", "Unable to send notification. Service Unavailable"); throw new NotifiarrException("Unable to send notification. Service Unavailable", ex); case 520: case 521: case 522: case 523: case 524: - _logger.Error(ex, "Cloudflare Related HTTP Error - Unable to send notification"); throw new NotifiarrException("Cloudflare Related HTTP Error - Unable to send notification", ex); default: - _logger.Error(ex, "Unknown HTTP Error - Unable to send notification"); throw new NotifiarrException("Unknown HTTP Error - Unable to send notification", ex); } } diff --git a/src/NzbDrone.Core/Notifications/Webhook/Webhook.cs b/src/NzbDrone.Core/Notifications/Webhook/Webhook.cs index 16c5e9983..fa09bc5f5 100755 --- a/src/NzbDrone.Core/Notifications/Webhook/Webhook.cs +++ b/src/NzbDrone.Core/Notifications/Webhook/Webhook.cs @@ -1,15 +1,17 @@ using System.Collections.Generic; using FluentValidation.Results; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Configuration; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Webhook { - public class Webhook : NotificationBase<WebhookSettings> + public class Webhook : WebhookBase<WebhookSettings> { private readonly IWebhookProxy _proxy; - public Webhook(IWebhookProxy proxy) + public Webhook(IWebhookProxy proxy, IConfigFileProvider configFileProvider) + : base(configFileProvider) { _proxy = proxy; } @@ -18,29 +20,12 @@ namespace NzbDrone.Core.Notifications.Webhook public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck) { - var payload = new WebhookHealthPayload - { - EventType = WebhookEventType.Health, - Level = healthCheck.Type, - Message = healthCheck.Message, - Type = healthCheck.Source.Name, - WikiUrl = healthCheck.WikiUrl?.ToString() - }; - - _proxy.SendWebhook(payload, Settings); + _proxy.SendWebhook(BuildHealthPayload(healthCheck), Settings); } public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { - var payload = new WebhookApplicationUpdatePayload - { - EventType = WebhookEventType.ApplicationUpdate, - Message = updateMessage.Message, - PreviousVersion = updateMessage.PreviousVersion.ToString(), - NewVersion = updateMessage.NewVersion.ToString() - }; - - _proxy.SendWebhook(payload, Settings); + _proxy.SendWebhook(BuildApplicationUploadPayload(updateMessage), Settings); } public override string Name => "Webhook"; @@ -58,12 +43,7 @@ namespace NzbDrone.Core.Notifications.Webhook { try { - var payload = new WebhookHealthPayload - { - EventType = WebhookEventType.Test - }; - - _proxy.SendWebhook(payload, Settings); + _proxy.SendWebhook(BuildTestPayload(), Settings); } catch (WebhookException ex) { diff --git a/src/NzbDrone.Core/Notifications/Webhook/WebhookBase.cs b/src/NzbDrone.Core/Notifications/Webhook/WebhookBase.cs new file mode 100644 index 000000000..f3f2f2f39 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Webhook/WebhookBase.cs @@ -0,0 +1,51 @@ +using NzbDrone.Core.Configuration; +using NzbDrone.Core.ThingiProvider; + +namespace NzbDrone.Core.Notifications.Webhook +{ + public abstract class WebhookBase<TSettings> : NotificationBase<TSettings> + where TSettings : IProviderConfig, new() + { + private readonly IConfigFileProvider _configFileProvider; + + protected WebhookBase(IConfigFileProvider configFileProvider) + : base() + { + _configFileProvider = configFileProvider; + } + + protected WebhookHealthPayload BuildHealthPayload(HealthCheck.HealthCheck healthCheck) + { + return new WebhookHealthPayload + { + EventType = WebhookEventType.Health, + InstanceName = _configFileProvider.InstanceName, + Level = healthCheck.Type, + Message = healthCheck.Message, + Type = healthCheck.Source.Name, + WikiUrl = healthCheck.WikiUrl?.ToString() + }; + } + + protected WebhookApplicationUpdatePayload BuildApplicationUploadPayload(ApplicationUpdateMessage updateMessage) + { + return new WebhookApplicationUpdatePayload + { + EventType = WebhookEventType.ApplicationUpdate, + InstanceName = _configFileProvider.InstanceName, + Message = updateMessage.Message, + PreviousVersion = updateMessage.PreviousVersion.ToString(), + NewVersion = updateMessage.NewVersion.ToString() + }; + } + + protected WebhookPayload BuildTestPayload() + { + return new WebhookPayload + { + EventType = WebhookEventType.Test, + InstanceName = _configFileProvider.InstanceName + }; + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Webhook/WebhookPayload.cs b/src/NzbDrone.Core/Notifications/Webhook/WebhookPayload.cs index 4b63a748e..05d51c7c1 100755 --- a/src/NzbDrone.Core/Notifications/Webhook/WebhookPayload.cs +++ b/src/NzbDrone.Core/Notifications/Webhook/WebhookPayload.cs @@ -3,5 +3,6 @@ namespace NzbDrone.Core.Notifications.Webhook public class WebhookPayload { public WebhookEventType EventType { get; set; } + public string InstanceName { get; set; } } } From 25596fc2e828138737194c5c03d009af98c85f70 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 19 Nov 2022 12:33:06 -0600 Subject: [PATCH 0648/2320] Fixed: Orpheus migration fails on Postgres --- .../Migration/022_orpheus_apiFixture.cs | 58 +++++++++++++++++++ .../Prowlarr.Core.Test.csproj | 3 - .../Datastore/Migration/008_redacted_api.cs | 26 ++++++--- .../Datastore/Migration/022_orpheus_api.cs | 24 +++++--- 4 files changed, 92 insertions(+), 19 deletions(-) create mode 100644 src/NzbDrone.Core.Test/Datastore/Migration/022_orpheus_apiFixture.cs diff --git a/src/NzbDrone.Core.Test/Datastore/Migration/022_orpheus_apiFixture.cs b/src/NzbDrone.Core.Test/Datastore/Migration/022_orpheus_apiFixture.cs new file mode 100644 index 000000000..656e2a992 --- /dev/null +++ b/src/NzbDrone.Core.Test/Datastore/Migration/022_orpheus_apiFixture.cs @@ -0,0 +1,58 @@ +using System; +using System.Linq; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Datastore.Migration; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.Datastore.Migration +{ + [TestFixture] + public class orpheus_apiFixture : MigrationTest<orpheus_api> + { + [Test] + public void should_convert_and_disable_orpheus_instance() + { + var db = WithMigrationTestDb(c => + { + c.Insert.IntoTable("Indexers").Row(new + { + Enable = true, + Name = "Orpheus", + Priority = 25, + Added = DateTime.UtcNow, + Implementation = "Orpheus", + Settings = new GazelleIndexerSettings021 + { + Username = "some name", + Password = "some pass" + }.ToJson(), + ConfigContract = "GazelleSettings" + }); + }); + + var items = db.Query<IndexerDefinition022>("SELECT \"Id\", \"Enable\", \"ConfigContract\", \"Settings\" FROM \"Indexers\""); + + items.Should().HaveCount(1); + items.First().ConfigContract.Should().Be("OrpheusSettings"); + items.First().Enable.Should().Be(false); + items.First().Settings.Should().NotContain("username"); + items.First().Settings.Should().NotContain("password"); + } + } + + public class IndexerDefinition022 + { + public int Id { get; set; } + public bool Enable { get; set; } + public string ConfigContract { get; set; } + public string Settings { get; set; } + } + + public class GazelleIndexerSettings021 + { + public string Username { get; set; } + public string Password { get; set; } + } +} diff --git a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj index 109a8badb..6d48fa0a6 100644 --- a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj @@ -21,7 +21,4 @@ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> </ItemGroup> - <ItemGroup> - <Folder Include="Datastore\Migration\" /> - </ItemGroup> </Project> diff --git a/src/NzbDrone.Core/Datastore/Migration/008_redacted_api.cs b/src/NzbDrone.Core/Datastore/Migration/008_redacted_api.cs index 796e74d13..4524af9e6 100644 --- a/src/NzbDrone.Core/Datastore/Migration/008_redacted_api.cs +++ b/src/NzbDrone.Core/Datastore/Migration/008_redacted_api.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Data; using FluentMigrator; using Newtonsoft.Json.Linq; @@ -21,6 +22,8 @@ namespace NzbDrone.Core.Datastore.Migration cmd.Transaction = tran; cmd.CommandText = "SELECT \"Id\", \"Settings\" FROM \"Indexers\" WHERE \"Implementation\" = 'Redacted'"; + var updatedIndexers = new List<Indexer008>(); + using (var reader = cmd.ExecuteReader()) { while (reader.Read()) @@ -45,19 +48,26 @@ namespace NzbDrone.Core.Datastore.Migration // write new json back to db, switch to new ConfigContract, and disable the indexer settings = jsonObject.ToJson(); - using (var updateCmd = conn.CreateCommand()) + + updatedIndexers.Add(new Indexer008 { - updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE \"Indexers\" SET \"Settings\" = ?, \"ConfigContract\" = ?, \"Enable\" = 0 WHERE \"Id\" = ?"; - updateCmd.AddParameter(settings); - updateCmd.AddParameter("RedactedSettings"); - updateCmd.AddParameter(id); - updateCmd.ExecuteNonQuery(); - } + Id = id, + Settings = settings, + ConfigContract = "RedactedSettings", + Enable = false + }); } } } } } + + public class Indexer008 + { + public int Id { get; set; } + public string Settings { get; set; } + public string ConfigContract { get; set; } + public bool Enable { get; set; } + } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/022_orpheus_api.cs b/src/NzbDrone.Core/Datastore/Migration/022_orpheus_api.cs index 3907af367..a35a51d58 100644 --- a/src/NzbDrone.Core/Datastore/Migration/022_orpheus_api.cs +++ b/src/NzbDrone.Core/Datastore/Migration/022_orpheus_api.cs @@ -1,8 +1,12 @@ +using System; +using System.Collections.Generic; using System.Data; +using Dapper; using FluentMigrator; using Newtonsoft.Json.Linq; using NzbDrone.Common.Serializer; using NzbDrone.Core.Datastore.Migration.Framework; +using static NzbDrone.Core.Datastore.Migration.redacted_api; namespace NzbDrone.Core.Datastore.Migration { @@ -21,6 +25,8 @@ namespace NzbDrone.Core.Datastore.Migration cmd.Transaction = tran; cmd.CommandText = "SELECT \"Id\", \"Settings\" FROM \"Indexers\" WHERE \"Implementation\" = 'Orpheus'"; + var updatedIndexers = new List<Indexer008>(); + using (var reader = cmd.ExecuteReader()) { while (reader.Read()) @@ -45,18 +51,20 @@ namespace NzbDrone.Core.Datastore.Migration // write new json back to db, switch to new ConfigContract, and disable the indexer settings = jsonObject.ToJson(); - using (var updateCmd = conn.CreateCommand()) + + updatedIndexers.Add(new Indexer008 { - updateCmd.Transaction = tran; - updateCmd.CommandText = "UPDATE \"Indexers\" SET \"Settings\" = ?, \"ConfigContract\" = ?, \"Enable\" = 0 WHERE \"Id\" = ?"; - updateCmd.AddParameter(settings); - updateCmd.AddParameter("OrpheusSettings"); - updateCmd.AddParameter(id); - updateCmd.ExecuteNonQuery(); - } + Id = id, + Settings = settings, + ConfigContract = "OrpheusSettings", + Enable = false + }); } } } + + var updateSql = "UPDATE \"Indexers\" SET \"Settings\" = @Settings, \"ConfigContract\" = @ConfigContract, \"Enable\" = @Enable WHERE \"Id\" = @Id"; + conn.Execute(updateSql, updatedIndexers, transaction: tran); } } } From c7e5cc6462b5f77f1d1bbe259fad6ebbd1530111 Mon Sep 17 00:00:00 2001 From: Rumplin <35449956+rumplin@users.noreply.github.com> Date: Wed, 23 Nov 2022 02:56:48 +0100 Subject: [PATCH 0649/2320] Removed suspicious URL in the default definitions (#1208) * Removed suspicious URL in the default definitions Revert "Removed suspicious URL in the default definitions" This reverts commit e26853f9aa919cd413b0f8b914ac426f220b9475. * Update Torznab.cs Removed suspicious URL from the code. Looks like the site that was originally there doesn't exist anymore and it's hosting malware (HD4Free.xyz). Co-authored-by: admin <stanislav.ivanov@performit.ie> --- src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs index 47d9584ff..27e5ee39a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs @@ -89,7 +89,6 @@ namespace NzbDrone.Core.Indexers.Torznab get { yield return GetDefinition("AnimeTosho", GetSettings("https://feed.animetosho.org")); - yield return GetDefinition("HD4Free.xyz", GetSettings("http://hd4free.xyz")); yield return GetDefinition("Generic Torznab", GetSettings("")); } } From 817d61de913569fb40da4de8fd27acf3d4192635 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 16 Nov 2022 15:19:45 -0600 Subject: [PATCH 0650/2320] Fixed: (SpeedApp) Migrate Legacy URL without slash --- src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs index 95ae6a773..5d557582c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs @@ -10,6 +10,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Name => "SpeedApp.io"; public override string[] IndexerUrls => new string[] { "https://speedapp.io/" }; + public override string[] LegacyUrls => new string[] { "https://speedapp.io" }; public override string Description => "SpeedApp is a ROMANIAN Private Torrent Tracker for MOVIES / TV / GENERAL"; From b33e45d2667559e8c08b968b78bd2177851aabb9 Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Wed, 23 Nov 2022 01:57:09 +0000 Subject: [PATCH 0651/2320] Translated using Weblate (Slovak) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 23.0% (107 of 464 strings) Translated using Weblate (Norwegian Bokmål) Currently translated at 23.9% (111 of 464 strings) Translated using Weblate (Catalan) Currently translated at 75.6% (351 of 464 strings) Translated using Weblate (Arabic) Currently translated at 73.0% (339 of 464 strings) Translated using Weblate (Vietnamese) Currently translated at 73.0% (339 of 464 strings) Translated using Weblate (Turkish) Currently translated at 72.8% (338 of 464 strings) Translated using Weblate (Thai) Currently translated at 73.0% (339 of 464 strings) Translated using Weblate (Swedish) Currently translated at 88.1% (409 of 464 strings) Translated using Weblate (Russian) Currently translated at 77.5% (360 of 464 strings) Translated using Weblate (Romanian) Currently translated at 73.2% (340 of 464 strings) Translated using Weblate (Portuguese) Currently translated at 80.8% (375 of 464 strings) Translated using Weblate (Polish) Currently translated at 75.6% (351 of 464 strings) Translated using Weblate (Dutch) Currently translated at 88.7% (412 of 464 strings) Translated using Weblate (Korean) Currently translated at 73.0% (339 of 464 strings) Translated using Weblate (Japanese) Currently translated at 73.0% (339 of 464 strings) Translated using Weblate (Italian) Currently translated at 98.0% (455 of 464 strings) Translated using Weblate (Icelandic) Currently translated at 73.0% (339 of 464 strings) Translated using Weblate (Hindi) Currently translated at 73.0% (339 of 464 strings) Translated using Weblate (Hebrew) Currently translated at 74.5% (346 of 464 strings) Translated using Weblate (French) Currently translated at 96.7% (449 of 464 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (464 of 464 strings) Translated using Weblate (Spanish) Currently translated at 79.3% (368 of 464 strings) Translated using Weblate (Greek) Currently translated at 72.8% (338 of 464 strings) Translated using Weblate (German) Currently translated at 100.0% (464 of 464 strings) Translated using Weblate (German) Currently translated at 100.0% (464 of 464 strings) Translated using Weblate (Danish) Currently translated at 72.8% (338 of 464 strings) Translated using Weblate (Czech) Currently translated at 73.0% (339 of 464 strings) Translated using Weblate (Czech) Currently translated at 73.0% (339 of 464 strings) Translated using Weblate (Bulgarian) Currently translated at 68.3% (317 of 464 strings) Translated using Weblate (German) Currently translated at 100.0% (464 of 464 strings) Translated using Weblate (German) Currently translated at 100.0% (464 of 464 strings) Translated using Weblate (German) Currently translated at 99.3% (461 of 464 strings) Co-authored-by: Anonymous <noreply@weblate.org> Co-authored-by: Don-Chris <Chr_Sch@t-online.de> Co-authored-by: Tordai, Ralph <ralph_t@posteo.de> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Zalhera <tobias.bechen@gmail.com> Co-authored-by: marapavelka <mara.pavelka@gmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ar/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/bg/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ca/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/cs/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/da/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/el/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/he/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/is/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/it/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ja/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ko/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nb_NO/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pl/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ro/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ru/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sk/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sv/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/th/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/vi/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/ar.json | 9 +++- src/NzbDrone.Core/Localization/Core/bg.json | 9 +++- src/NzbDrone.Core/Localization/Core/ca.json | 46 ++++++++++++++++- src/NzbDrone.Core/Localization/Core/cs.json | 13 +++-- src/NzbDrone.Core/Localization/Core/da.json | 9 +++- src/NzbDrone.Core/Localization/Core/de.json | 8 +-- src/NzbDrone.Core/Localization/Core/el.json | 9 +++- src/NzbDrone.Core/Localization/Core/es.json | 11 +++- src/NzbDrone.Core/Localization/Core/fi.json | 4 +- src/NzbDrone.Core/Localization/Core/fr.json | 9 +++- src/NzbDrone.Core/Localization/Core/he.json | 10 +++- src/NzbDrone.Core/Localization/Core/hi.json | 9 +++- src/NzbDrone.Core/Localization/Core/is.json | 9 +++- src/NzbDrone.Core/Localization/Core/it.json | 10 +++- src/NzbDrone.Core/Localization/Core/ja.json | 9 +++- src/NzbDrone.Core/Localization/Core/ko.json | 9 +++- .../Localization/Core/nb_NO.json | 3 +- src/NzbDrone.Core/Localization/Core/nl.json | 10 +++- src/NzbDrone.Core/Localization/Core/pl.json | 14 ++++- src/NzbDrone.Core/Localization/Core/pt.json | 13 ++++- src/NzbDrone.Core/Localization/Core/ro.json | 10 +++- src/NzbDrone.Core/Localization/Core/ru.json | 10 +++- src/NzbDrone.Core/Localization/Core/sk.json | 51 ++++++++++++++++++- src/NzbDrone.Core/Localization/Core/sv.json | 10 +++- src/NzbDrone.Core/Localization/Core/th.json | 9 +++- src/NzbDrone.Core/Localization/Core/tr.json | 9 +++- src/NzbDrone.Core/Localization/Core/vi.json | 9 +++- 27 files changed, 300 insertions(+), 31 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/ar.json b/src/NzbDrone.Core/Localization/Core/ar.json index b5aa9f620..d2c15c604 100644 --- a/src/NzbDrone.Core/Localization/Core/ar.json +++ b/src/NzbDrone.Core/Localization/Core/ar.json @@ -331,5 +331,12 @@ "UnableToLoadIndexers": "تعذر تحميل المفهرسات", "Yes": "نعم", "GrabReleases": "انتزاع الإصدار", - "No": "لا" + "No": "لا", + "Ended": "انتهى", + "LastDuration": "المدة الماضية", + "ApplicationLongTermStatusCheckAllClientMessage": "جميع المفهرسات غير متوفرة بسبب الفشل لأكثر من 6 ساعات", + "ApplicationLongTermStatusCheckSingleClientMessage": "المفهرسات غير متاحة بسبب الإخفاقات لأكثر من 6 ساعات: {0}", + "LastExecution": "آخر تنفيذ", + "NextExecution": "التنفيذ القادم", + "Queued": "في قائمة الانتظار" } diff --git a/src/NzbDrone.Core/Localization/Core/bg.json b/src/NzbDrone.Core/Localization/Core/bg.json index c078b4e50..39d4ee075 100644 --- a/src/NzbDrone.Core/Localization/Core/bg.json +++ b/src/NzbDrone.Core/Localization/Core/bg.json @@ -331,5 +331,12 @@ "UnableToLoadIndexers": "Индексаторите не могат да се заредят", "Yes": "Да", "ConnectionLostMessage": "Whisparr е загубил връзката си с бекенда и ще трябва да се презареди, за да възстанови функционалността.", - "MappedDrivesRunningAsService": "Картографираните мрежови устройства не са налични, когато се изпълняват като услуга на Windows. Моля, вижте често задаваните въпроси за повече информация" + "MappedDrivesRunningAsService": "Картографираните мрежови устройства не са налични, когато се изпълняват като услуга на Windows. Моля, вижте често задаваните въпроси за повече информация", + "ApplicationLongTermStatusCheckSingleClientMessage": "Индексатори не са налични поради неуспехи за повече от 6 часа: {0}", + "Ended": "Приключи", + "LastExecution": "Последно изпълнение", + "ApplicationLongTermStatusCheckAllClientMessage": "Всички индексатори са недостъпни поради грешки за повече от 6 часа", + "LastDuration": "lastDuration", + "NextExecution": "Следващо изпълнение", + "Queued": "На опашка" } diff --git a/src/NzbDrone.Core/Localization/Core/ca.json b/src/NzbDrone.Core/Localization/Core/ca.json index fe9a56c72..e662b474b 100644 --- a/src/NzbDrone.Core/Localization/Core/ca.json +++ b/src/NzbDrone.Core/Localization/Core/ca.json @@ -305,5 +305,49 @@ "URLBase": "Base URL", "Usenet": "Usenet", "View": "Visualitza", - "Yesterday": "Ahir" + "Yesterday": "Ahir", + "ApplicationStatusCheckSingleClientMessage": "Llistes no disponibles a causa d'errors: {0}", + "AnalyticsEnabledHelpText": "Envieu informació anònima d'ús i errors als servidors de Radarr. Això inclou informació sobre el vostre navegador, quines pàgines Radarr WebUI feu servir, informes d'errors, així com el sistema operatiu i la versió del temps d'execució. Utilitzarem aquesta informació per prioritzar les funcions i les correccions d'errors.", + "ApplyTagsHelpTexts1": "Com aplicar etiquetes a les pel·lícules seleccionades", + "ApplyTagsHelpTexts2": "Afegeix: afegeix les etiquetes a la llista d'etiquetes existent", + "ConnectionLostAutomaticMessage": "Radarr intentarà connectar-se automàticament, o podeu fer clic a recarregar.", + "ConnectionLostMessage": "Radarr ha perdut la connexió amb el backend i s'haurà de tornar a carregar per restaurar la funcionalitat.", + "HistoryCleanupDaysHelpTextWarning": "Els fitxers de la paperera de reciclatge més antics que el nombre de dies seleccionat es netejaran automàticament", + "UnableToAddANewAppProfilePleaseTryAgain": "No es pot afegir un perfil de qualitat nou, torneu-ho a provar.", + "BackupFolderHelpText": "Els camins relatius estaran sota el directori AppData del Lidarr", + "AllIndexersHiddenDueToFilter": "Totes les pel·lícules estan ocultes a causa del filtre aplicat.", + "EnableRss": "Activa RSS", + "Grabs": "Captura", + "EnableAutomaticSearchHelpText": "S'utilitzarà quan es realitzin cerques automàtiques mitjançant la interfície d'usuari o per Radarr", + "UnableToAddANewApplicationPleaseTryAgain": "No es pot afegir una notificació nova, torneu-ho a provar.", + "Application": "Aplicacions", + "Applications": "Aplicacions", + "ApplicationStatusCheckAllClientMessage": "Totes les llistes no estan disponibles a causa d'errors", + "AuthenticationMethodHelpText": "Requereix nom d'usuari i contrasenya per accedir al radar", + "ApplicationLongTermStatusCheckAllClientMessage": "Tots els indexadors no estan disponibles a causa d'errors durant més de 6 hores", + "ApplicationLongTermStatusCheckSingleClientMessage": "Els indexadors no estan disponibles a causa d'errors durant més de 6 hores: {0}", + "BindAddressHelpText": "Adreça IPv4 vàlida o '*' per a totes les interfícies", + "BranchUpdate": "Branca que s'utilitza per actualitzar Radarr", + "Connect": "Notificacions", + "DeleteApplicationMessageText": "Esteu segur que voleu suprimir la notificació '{0}'?", + "DeleteIndexerProxyMessageText": "Esteu segur que voleu suprimir la llista '{0}'?", + "Encoding": "Codificació", + "ForMoreInformationOnTheIndividualDownloadClients": "Per obtenir més informació sobre els clients de baixada individuals, feu clic als botons de més informació.", + "GeneralSettingsSummary": "Port, SSL, nom d'usuari/contrasenya, servidor intermediari, analítiques i actualitzacions", + "GrabReleases": "Captura novetat", + "HistoryCleanupDaysHelpText": "Establiu a 0 per desactivar la neteja automàtica", + "Notification": "Notificacions", + "Notifications": "Notificacions", + "PrioritySettings": "Prioritat", + "ReleaseBranchCheckOfficialBranchMessage": "La branca {0} no és una branca de llançament de Radarr vàlida, no rebreu actualitzacions", + "TagsHelpText": "S'aplica a pel·lícules amb almenys una etiqueta coincident", + "Torrent": "Torrent", + "UnableToAddANewIndexerProxyPleaseTryAgain": "No es pot afegir un indexador nou, torneu-ho a provar.", + "UpdateMechanismHelpText": "Utilitzeu l'actualitzador integrat de Prowlarr o un script", + "UserAgentProvidedByTheAppThatCalledTheAPI": "Agent d'usuari proporcionat per l'aplicació per fer peticions a l'API", + "IndexerProxyStatusCheckAllClientMessage": "Tots els indexadors no estan disponibles a causa d'errors", + "IndexerProxyStatusCheckSingleClientMessage": "Els indexadors no estan disponibles a causa d'errors: {0}", + "LaunchBrowserHelpText": " Obriu un navegador web i navegueu a la pàgina d'inici de Radarr a l'inici de l'aplicació.", + "Link": "Enllaços", + "UILanguageHelpText": "Idioma que utilitzarà Radarr per a la interfície d'usuari" } diff --git a/src/NzbDrone.Core/Localization/Core/cs.json b/src/NzbDrone.Core/Localization/Core/cs.json index 773932d12..95dbdf1f0 100644 --- a/src/NzbDrone.Core/Localization/Core/cs.json +++ b/src/NzbDrone.Core/Localization/Core/cs.json @@ -17,7 +17,7 @@ "Settings": "Nastavení", "StartTypingOrSelectAPathBelow": "Začněte psát nebo vyberte cestu níže", "Usenet": "Usenet", - "AddDownloadClient": "Přidat staženého klienta", + "AddDownloadClient": "Přidat klienta pro stahování", "Backups": "Zálohy", "CancelPendingTask": "Opravdu chcete zrušit tento nevyřízený úkol?", "MovieIndexScrollBottom": "Rejstřík filmů: Posun dolů", @@ -116,7 +116,7 @@ "System": "Systém", "Enabled": "Povoleno", "IgnoredAddresses": "Ignorované adresy", - "AcceptConfirmationModal": "Přijměte potvrzení Modal", + "AcceptConfirmationModal": "Přijměte potvrzovací modální okno", "Actions": "Akce", "Added": "Přidané", "AddIndexer": "Přidat indexátor", @@ -331,5 +331,12 @@ "No": "Ne", "UnableToLoadIndexers": "Nelze načíst indexery", "Yes": "Ano", - "GrabReleases": "Uchopte uvolnění" + "GrabReleases": "Uchopte uvolnění", + "ApplicationLongTermStatusCheckSingleClientMessage": "Indexery nedostupné z důvodu selhání po dobu delší než 6 hodin: {0}", + "ApplicationLongTermStatusCheckAllClientMessage": "Všechny indexery nejsou k dispozici z důvodu selhání po dobu delší než 6 hodin", + "Ended": "Skončil", + "LastDuration": "lastDuration", + "LastExecution": "Poslední poprava", + "NextExecution": "Další spuštění", + "Queued": "Ve frontě" } diff --git a/src/NzbDrone.Core/Localization/Core/da.json b/src/NzbDrone.Core/Localization/Core/da.json index affc9dc4d..d5b57727f 100644 --- a/src/NzbDrone.Core/Localization/Core/da.json +++ b/src/NzbDrone.Core/Localization/Core/da.json @@ -334,5 +334,12 @@ "No": "Ingen", "NetCore": ".NET Core", "UnableToLoadIndexers": "Kan ikke indlæse indeksatorer", - "Yes": "Ja" + "Yes": "Ja", + "ApplicationLongTermStatusCheckSingleClientMessage": "Indeksatorer er ikke tilgængelige på grund af fejl i mere end 6 timer: {0}", + "ApplicationLongTermStatusCheckAllClientMessage": "Alle indeksatorer er ikke tilgængelige på grund af fejl i mere end 6 timer", + "Ended": "Afsluttet", + "LastDuration": "lastDuration", + "LastExecution": "Sidste henrettelse", + "NextExecution": "Næste udførelse", + "Queued": "I kø" } diff --git a/src/NzbDrone.Core/Localization/Core/de.json b/src/NzbDrone.Core/Localization/Core/de.json index 2205cc382..bff789674 100644 --- a/src/NzbDrone.Core/Localization/Core/de.json +++ b/src/NzbDrone.Core/Localization/Core/de.json @@ -317,7 +317,7 @@ "IndexerRss": "Indexer RSS", "IndexerQuery": "Indexer Anfrage", "IndexerHealthCheckNoIndexers": "Keine Indexer aktiviert, Prowlarr wird keine Suchergebnisse zurückgeben", - "IndexerAuth": "Indexer Auth", + "IndexerAuth": "Indexer Authentifizierung", "EnableIndexer": "Indexer aktivieren", "IndexerObsoleteCheckMessage": "Indexer sind nicht mehr verfügbar oder wurden aktualiiert: {0}. Bitte enfernen und (oder) neu zu Prowlarr hinzufügen", "DevelopmentSettings": "Entwicklungseinstellungen", @@ -445,7 +445,7 @@ "LastDuration": "Letzte Dauer", "LastExecution": "Letzte Ausführung", "MinimumSeeders": "Mindest-Seeder", - "MinimumSeedersHelpText": "Mindest-Seeder sind benötigt von der App für den Indexer um zu holen", + "MinimumSeedersHelpText": "Minimale Anzahl an Seedern die von der Anwendung benötigt werden um den Indexer zu holen", "NextExecution": "Nächste Ausführung", "Parameters": "Parameter", "Queued": "In der Warteschlange", @@ -460,5 +460,7 @@ "AddSyncProfile": "Synchronisationsprofil hinzufügen", "BookSearchTypes": "Buch-Suchtypen", "IndexerDetails": "Indexer-Details", - "IndexerName": "Indexer-Name" + "IndexerName": "Indexer-Name", + "ApplicationLongTermStatusCheckAllClientMessage": "Alle Anwendungen sind nicht verfügbar, da es zu Störungen für mehr als 6 Stunden kam", + "ApplicationLongTermStatusCheckSingleClientMessage": "Anwendungen nicht verfügbar, da es zu Störungen für mehr als 6 Stunden kam: {0}" } diff --git a/src/NzbDrone.Core/Localization/Core/el.json b/src/NzbDrone.Core/Localization/Core/el.json index f8392c395..297559edf 100644 --- a/src/NzbDrone.Core/Localization/Core/el.json +++ b/src/NzbDrone.Core/Localization/Core/el.json @@ -334,5 +334,12 @@ "MappedDrivesRunningAsService": "Οι αντιστοιχισμένες μονάδες δίσκου δικτύου δεν είναι διαθέσιμες κατά την εκτέλεση ως υπηρεσία Windows. Ανατρέξτε στις Συχνές Ερωτήσεις για περισσότερες πληροφορίες", "No": "Οχι", "UnableToLoadIndexers": "Δεν είναι δυνατή η φόρτωση του ευρετηρίου", - "Yes": "Ναί" + "Yes": "Ναί", + "Ended": "Έληξε", + "LastDuration": "τελευταία Διάρκεια", + "LastExecution": "Τελευταία εκτέλεση", + "ApplicationLongTermStatusCheckAllClientMessage": "Όλοι οι δείκτες δεν είναι διαθέσιμοι λόγω αστοχιών για περισσότερο από 6 ώρες", + "ApplicationLongTermStatusCheckSingleClientMessage": "Τα ευρετήρια δεν είναι διαθέσιμα λόγω αστοχιών για περισσότερο από 6 ώρες: {0}", + "NextExecution": "Επόμενη εκτέλεση", + "Queued": "Σε ουρά" } diff --git a/src/NzbDrone.Core/Localization/Core/es.json b/src/NzbDrone.Core/Localization/Core/es.json index fae62c915..ad47007ad 100644 --- a/src/NzbDrone.Core/Localization/Core/es.json +++ b/src/NzbDrone.Core/Localization/Core/es.json @@ -364,5 +364,14 @@ "UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent proporcionado por la aplicación llamó a la API", "InstanceName": "Nombre de Instancia", "InstanceNameHelpText": "Nombre de instancia en pestaña y para nombre de aplicación en Syslog", - "Database": "Base de Datos" + "Database": "Base de Datos", + "Duration": "Duración", + "LastDuration": "Duración", + "LastExecution": "Última ejecución", + "Queued": "En Cola", + "ApplicationLongTermStatusCheckAllClientMessage": "Ningún indexer está disponible por errores durando más de 6 horas", + "ApplicationLongTermStatusCheckSingleClientMessage": "Indexers no disponible por errores durando más de 6 horas: {0}", + "Ended": "Terminó", + "NextExecution": "Siguiente ejecución", + "Started": "Iniciado" } diff --git a/src/NzbDrone.Core/Localization/Core/fi.json b/src/NzbDrone.Core/Localization/Core/fi.json index 48e3ac115..c630bd1dc 100644 --- a/src/NzbDrone.Core/Localization/Core/fi.json +++ b/src/NzbDrone.Core/Localization/Core/fi.json @@ -460,5 +460,7 @@ "NextExecution": "Seuraava suoritus", "Parameters": "Parametrit", "Queued": "Jonossa", - "Started": "Alkoi" + "Started": "Alkoi", + "ApplicationLongTermStatusCheckAllClientMessage": "Mikään tietolähde ei ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi.", + "ApplicationLongTermStatusCheckSingleClientMessage": "Tietolähteet eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi: {0}" } diff --git a/src/NzbDrone.Core/Localization/Core/fr.json b/src/NzbDrone.Core/Localization/Core/fr.json index aa2704977..b074c9eb0 100644 --- a/src/NzbDrone.Core/Localization/Core/fr.json +++ b/src/NzbDrone.Core/Localization/Core/fr.json @@ -444,5 +444,12 @@ "Duration": "Durée", "LastDuration": "Dernière durée", "InstanceName": "Nom de l'instance", - "InstanceNameHelpText": "Nom de l'instance dans l'onglet du navigateur et pour le nom d'application dans Syslog" + "InstanceNameHelpText": "Nom de l'instance dans l'onglet du navigateur et pour le nom d'application dans Syslog", + "ApplicationLongTermStatusCheckSingleClientMessage": "Indexeurs indisponibles en raison de pannes pendant plus de 6 heures : {0}", + "ApplicationLongTermStatusCheckAllClientMessage": "Tous les indexeurs sont indisponibles en raison d'échecs de plus de 6 heures", + "Ended": "Terminé", + "LastExecution": "Dernière exécution", + "NextExecution": "Prochaine exécution", + "Queued": "En file d'attente", + "Started": "Démarré" } diff --git a/src/NzbDrone.Core/Localization/Core/he.json b/src/NzbDrone.Core/Localization/Core/he.json index b7cbaed95..5f23f2cc3 100644 --- a/src/NzbDrone.Core/Localization/Core/he.json +++ b/src/NzbDrone.Core/Localization/Core/he.json @@ -337,5 +337,13 @@ "NotificationTriggersHelpText": "בחר איזה אירועים יפעילו את ההתראה הזאת", "OnApplicationUpdate": "כשהאפליקציה מעדכנת גרסא", "OnApplicationUpdateHelpText": "כשהאפליקציה מעדכנת גרסא", - "Database": "מסד נתונים" + "Database": "מסד נתונים", + "ApplicationLongTermStatusCheckSingleClientMessage": "אינדקסים לא זמינים עקב כשלים במשך יותר משש שעות: {0}", + "Duration": "אורך", + "Queued": "בתור", + "ApplicationLongTermStatusCheckAllClientMessage": "כל האינדקסים אינם זמינים עקב כשלים במשך יותר מ -6 שעות", + "Ended": "הסתיים", + "LastDuration": "lastDuration", + "LastExecution": "ביצוע אחרון", + "NextExecution": "הביצוע הבא" } diff --git a/src/NzbDrone.Core/Localization/Core/hi.json b/src/NzbDrone.Core/Localization/Core/hi.json index 2a8e8b547..554d50091 100644 --- a/src/NzbDrone.Core/Localization/Core/hi.json +++ b/src/NzbDrone.Core/Localization/Core/hi.json @@ -331,5 +331,12 @@ "Link": "लिंक", "MappedDrivesRunningAsService": "विंडोज सर्विस के रूप में चलने पर मैप्ड नेटवर्क ड्राइव उपलब्ध नहीं हैं। अधिक जानकारी के लिए कृपया FAQ देखें", "No": "नहीं", - "UnableToLoadIndexers": "अनुक्रमणिका लोड करने में असमर्थ" + "UnableToLoadIndexers": "अनुक्रमणिका लोड करने में असमर्थ", + "ApplicationLongTermStatusCheckAllClientMessage": "6 घंटे से अधिक समय तक विफलताओं के कारण सभी सूचकांक अनुपलब्ध हैं", + "ApplicationLongTermStatusCheckSingleClientMessage": "6 घंटे से अधिक समय तक विफलताओं के कारण सूचकांक उपलब्ध नहीं: {0}", + "Ended": "समाप्त", + "NextExecution": "अगला निष्पादन", + "LastDuration": "lastDuration", + "LastExecution": "अंतिम निष्पादन", + "Queued": "कतारबद्ध" } diff --git a/src/NzbDrone.Core/Localization/Core/is.json b/src/NzbDrone.Core/Localization/Core/is.json index e40299d16..20144e433 100644 --- a/src/NzbDrone.Core/Localization/Core/is.json +++ b/src/NzbDrone.Core/Localization/Core/is.json @@ -331,5 +331,12 @@ "No": "Nei", "UnableToLoadIndexers": "Ekki er hægt að hlaða Indexers", "Yes": "Já", - "ConnectionLostMessage": "Whisparr hefur misst tenginguna við bakendann og þarf að endurhlaða hann til að endurheimta virkni." + "ConnectionLostMessage": "Whisparr hefur misst tenginguna við bakendann og þarf að endurhlaða hann til að endurheimta virkni.", + "LastExecution": "Síðasta aftaka", + "ApplicationLongTermStatusCheckAllClientMessage": "Allir verðtryggingaraðilar eru ekki tiltækir vegna bilana í meira en 6 klukkustundir", + "ApplicationLongTermStatusCheckSingleClientMessage": "Vísitölufólk er ekki tiltækt vegna bilana í meira en 6 klukkustundir: {0}", + "LastDuration": "lastDuration", + "Queued": "Í biðröð", + "Ended": "Lauk", + "NextExecution": "Næsta framkvæmd" } diff --git a/src/NzbDrone.Core/Localization/Core/it.json b/src/NzbDrone.Core/Localization/Core/it.json index 4ff18e2b9..6f2f29758 100644 --- a/src/NzbDrone.Core/Localization/Core/it.json +++ b/src/NzbDrone.Core/Localization/Core/it.json @@ -449,5 +449,13 @@ "MinimumSeeders": "Seeder Minimi", "InstanceName": "Nome Istanza", "InstanceNameHelpText": "Nome dell'istanza nella scheda e per il nome dell'applicazione Syslog", - "ThemeHelpText": "Cambia il tema dell'interfaccia di Prowlarr, ispirato da {0}" + "ThemeHelpText": "Cambia il tema dell'interfaccia di Prowlarr, ispirato da {0}", + "LastDuration": "Ultima Durata", + "LastExecution": "Ultima esecuzione", + "Queued": "Messo in coda", + "ApplicationLongTermStatusCheckAllClientMessage": "Nessun Indicizzatore è disponibile da più di 6 ore a causa di errori", + "ApplicationLongTermStatusCheckSingleClientMessage": "Alcuni Indicizzatori non sono disponibili da più di 6 ore a causa di errori: {0}", + "Duration": "Durata", + "Ended": "Finito", + "NextExecution": "Prossima esecuzione" } diff --git a/src/NzbDrone.Core/Localization/Core/ja.json b/src/NzbDrone.Core/Localization/Core/ja.json index 1de5c2d9c..f0dd08307 100644 --- a/src/NzbDrone.Core/Localization/Core/ja.json +++ b/src/NzbDrone.Core/Localization/Core/ja.json @@ -331,5 +331,12 @@ "No": "番号", "UnableToLoadIndexers": "インデクサーを読み込めません", "Yes": "はい", - "ConnectionLostMessage": "Whisparrはバックエンドへの接続を失ったため、機能を復元するには再ロードする必要があります。" + "ConnectionLostMessage": "Whisparrはバックエンドへの接続を失ったため、機能を復元するには再ロードする必要があります。", + "LastDuration": "lastDuration", + "LastExecution": "最後の実行", + "ApplicationLongTermStatusCheckAllClientMessage": "6時間以上の障害のため、すべてのインデクサーが使用できなくなります", + "ApplicationLongTermStatusCheckSingleClientMessage": "6時間以上の障害のため、インデクサーを使用できません:{0}", + "Ended": "終了しました", + "NextExecution": "次の実行", + "Queued": "キューに入れられました" } diff --git a/src/NzbDrone.Core/Localization/Core/ko.json b/src/NzbDrone.Core/Localization/Core/ko.json index d5cc1fea2..f6ac40847 100644 --- a/src/NzbDrone.Core/Localization/Core/ko.json +++ b/src/NzbDrone.Core/Localization/Core/ko.json @@ -331,5 +331,12 @@ "UnableToLoadIndexers": "인덱서를로드 할 수 없습니다.", "UpdateCheckStartupNotWritableMessage": "'{1}'사용자가 '{0}'시작 폴더에 쓸 수 없기 때문에 업데이트를 설치할 수 없습니다.", "Yes": "예", - "GrabReleases": "그랩 릴리스" + "GrabReleases": "그랩 릴리스", + "NextExecution": "다음 실행", + "ApplicationLongTermStatusCheckSingleClientMessage": "6 시간 이상 오류로 인해 인덱서를 사용할 수 없음 : {0}", + "ApplicationLongTermStatusCheckAllClientMessage": "6 시간 이상 오류로 인해 모든 인덱서를 사용할 수 없습니다.", + "Ended": "종료", + "LastDuration": "lastDuration", + "LastExecution": "마지막 실행", + "Queued": "대기 중" } diff --git a/src/NzbDrone.Core/Localization/Core/nb_NO.json b/src/NzbDrone.Core/Localization/Core/nb_NO.json index 45a645f61..77b81385b 100644 --- a/src/NzbDrone.Core/Localization/Core/nb_NO.json +++ b/src/NzbDrone.Core/Localization/Core/nb_NO.json @@ -109,5 +109,6 @@ "Updates": "Oppdater", "URLBase": "URL Base", "Details": "detaljer", - "Info": "Info" + "Info": "Info", + "Queued": "Kø" } diff --git a/src/NzbDrone.Core/Localization/Core/nl.json b/src/NzbDrone.Core/Localization/Core/nl.json index 430e9dc9f..1bcb6bad9 100644 --- a/src/NzbDrone.Core/Localization/Core/nl.json +++ b/src/NzbDrone.Core/Localization/Core/nl.json @@ -409,5 +409,13 @@ "Yes": "Ja", "OnApplicationUpdateHelpText": "Bij applicatie update", "Database": "Databasis", - "OnApplicationUpdate": "Bij applicatie update" + "OnApplicationUpdate": "Bij applicatie update", + "Duration": "Duur", + "Ended": "Beëindigd", + "NextExecution": "Volgende uitvoering", + "ApplicationLongTermStatusCheckAllClientMessage": "Alle indexeerders zijn niet beschikbaar vanwege storingen gedurende meer dan 6 uur", + "ApplicationLongTermStatusCheckSingleClientMessage": "Indexeerders zijn niet beschikbaar vanwege storingen gedurende meer dan 6 uur: {0}", + "LastDuration": "Laatste Looptijd", + "LastExecution": "Laatste Uitvoering", + "Queued": "Afwachtend" } diff --git a/src/NzbDrone.Core/Localization/Core/pl.json b/src/NzbDrone.Core/Localization/Core/pl.json index 47ce22d19..bd8c0d738 100644 --- a/src/NzbDrone.Core/Localization/Core/pl.json +++ b/src/NzbDrone.Core/Localization/Core/pl.json @@ -338,5 +338,17 @@ "OnApplicationUpdate": "Przy aktualizacji aplikacji", "OnApplicationUpdateHelpText": "Przy aktualizacji aplikacji", "Database": "Baza danych", - "NotificationTriggersHelpText": "Wybierz zdarzenia, które mają uruchamiać to powiadomienie" + "NotificationTriggersHelpText": "Wybierz zdarzenia, które mają uruchamiać to powiadomienie", + "ApplicationLongTermStatusCheckSingleClientMessage": "Indeksatory niedostępne z powodu błędów przez ponad 6 godzin: {0}", + "Duration": "Czas trwania", + "Ended": "Zakończone", + "LastDuration": "Ostatni czas trwania", + "LastExecution": "Ostatnia egzekucja", + "NextExecution": "Następne wykonanie", + "Queued": "W kolejce", + "Started": "Rozpoczęto", + "Encoding": "Kodowanie", + "Application": "Aplikacje", + "Applications": "Aplikacje", + "ApplicationLongTermStatusCheckAllClientMessage": "Wszystkie indeksatory są niedostępne z powodu awarii przez ponad 6 godzin" } diff --git a/src/NzbDrone.Core/Localization/Core/pt.json b/src/NzbDrone.Core/Localization/Core/pt.json index d1cd7f057..6c86f3e5f 100644 --- a/src/NzbDrone.Core/Localization/Core/pt.json +++ b/src/NzbDrone.Core/Localization/Core/pt.json @@ -404,5 +404,16 @@ "InstanceName": "Nome da Instancia", "InstanceNameHelpText": "Nome da instância na aba e nome da aplicação para Syslog", "UnableToLoadIndexerProxies": "Incapaz de ler o indexador de proxies", - "UnableToLoadApplicationList": "Não foi possível carregar a lista de aplicações" + "UnableToLoadApplicationList": "Não foi possível carregar a lista de aplicações", + "ApplicationLongTermStatusCheckAllClientMessage": "Todos os indexadores estão indisponíveis devido a erros á mais de 6 horas", + "ApplicationLongTermStatusCheckSingleClientMessage": "Indexadores indisponíveis devido a erros à mais de 6 horas: {0}", + "Duration": "Duração", + "Ended": "Terminado", + "LastDuration": "Última Duração", + "LastExecution": "Execução mais recente", + "Notification": "Notificações", + "Notifications": "Notificações", + "Started": "Começado", + "NextExecution": "Próxima execução", + "Queued": "Em fila" } diff --git a/src/NzbDrone.Core/Localization/Core/ro.json b/src/NzbDrone.Core/Localization/Core/ro.json index 2e0489443..8056fe414 100644 --- a/src/NzbDrone.Core/Localization/Core/ro.json +++ b/src/NzbDrone.Core/Localization/Core/ro.json @@ -376,5 +376,13 @@ "FullSync": "Sincronizare completă", "IndexerObsoleteCheckMessage": "Indexatorii sunt învechiți sau nu au fost actualizați: {0}. Vă rugăm să-i ștergeți și (sau) să-i adăugați din nou în Prowlarr", "IndexerProxies": "Proxiuri indexatoare", - "IndexerVipCheckExpiringClientMessage": "Beneficiile VIP pentru indexator expiră în curând: {0}" + "IndexerVipCheckExpiringClientMessage": "Beneficiile VIP pentru indexator expiră în curând: {0}", + "ApplicationLongTermStatusCheckAllClientMessage": "Toți indexatorii nu sunt disponibili din cauza unor eșecuri de mai mult de 6 ore", + "ApplicationLongTermStatusCheckSingleClientMessage": "Indexatori indisponibili din cauza unor eșecuri de mai mult de 6 ore: {0}", + "LastDuration": "lastDuration", + "LastExecution": "Ultima executare", + "Queued": "În așteptare", + "Application": "Aplicații", + "Applications": "Aplicații", + "NextExecution": "Următoarea execuție" } diff --git a/src/NzbDrone.Core/Localization/Core/ru.json b/src/NzbDrone.Core/Localization/Core/ru.json index e20b8d0d5..89e655cc3 100644 --- a/src/NzbDrone.Core/Localization/Core/ru.json +++ b/src/NzbDrone.Core/Localization/Core/ru.json @@ -351,5 +351,13 @@ "InstanceName": "Имя экземпляра", "InstanceNameHelpText": "Имя экземпляра на вкладке и для имени приложения системного журнала", "Started": "Запущено", - "Database": "База данных" + "Database": "База данных", + "Duration": "Длительность", + "ApplicationLongTermStatusCheckSingleClientMessage": "Все индексаторы недоступны из-за ошибок за последние 6 часов: {0}", + "Ended": "Закончился", + "LastExecution": "Последнее выполнение", + "NextExecution": "Следующее выполнение", + "Queued": "В очереди", + "ApplicationLongTermStatusCheckAllClientMessage": "Все индексаторы недоступны из-за ошибок за последние 6 часов", + "LastDuration": "Последняя длительность" } diff --git a/src/NzbDrone.Core/Localization/Core/sk.json b/src/NzbDrone.Core/Localization/Core/sk.json index 9dcf3e5e4..c6bf3a7a4 100644 --- a/src/NzbDrone.Core/Localization/Core/sk.json +++ b/src/NzbDrone.Core/Localization/Core/sk.json @@ -56,5 +56,54 @@ "CloseCurrentModal": "Zatvoriť aktuálne okno", "Columns": "Stĺpce", "Component": "Komponent", - "ConnectionLost": "Spojenie prerušené" + "ConnectionLost": "Spojenie prerušené", + "Files": "Súbor", + "Filter": "Filter", + "Filters": "Filtre", + "Connections": "Spojenia", + "Custom": "Vlastné", + "Delete": "Vymazať", + "Notification": "Notifikácie", + "Notifications": "Notifikácie", + "Refresh": "Obnoviť", + "Scheduled": "Naplánované", + "Settings": "Nastavenia", + "Torrent": "Torrent", + "Torrents": "Torrenty", + "Updates": "Aktualizovať", + "URLBase": "Základ URL", + "Usenet": "Usenet", + "Username": "Používateľské meno", + "Language": "jazyk", + "Enabled": "Povoliť", + "Encoding": "Kódovanie", + "Queue": "Fronta", + "Search": "Hľadať", + "Host": "Hostiteľ", + "Hostname": "Názov hostiteľa", + "Info": "Info", + "UpdateMechanismHelpText": "Použiť vstavaný Prowlarr aktualizátor alebo skript", + "Events": "Udalosť", + "Grabs": "Grab", + "Indexers": "Indexery", + "Password": "Heslo", + "Peers": "Peeri", + "Port": "Port", + "Title": "Názov", + "UI": "UI", + "Application": "Aplikácie", + "Protocol": "Protokol", + "Reload": "Obnoviť", + "Applications": "Aplikácie", + "Seeders": "Seederi", + "Connect": "Notifikácie", + "Details": "podrobnosti", + "Disabled": "zakázané", + "DownloadClient": "Klient na sťahovanie", + "DownloadClients": "Klient na sťahovanie", + "Enable": "Povoliť", + "Indexer": "Indexer", + "New": "Nový", + "Queued": "Fronta", + "RSS": "RSS" } diff --git a/src/NzbDrone.Core/Localization/Core/sv.json b/src/NzbDrone.Core/Localization/Core/sv.json index 662ba3a92..8a35dd019 100644 --- a/src/NzbDrone.Core/Localization/Core/sv.json +++ b/src/NzbDrone.Core/Localization/Core/sv.json @@ -405,5 +405,13 @@ "Application": "Applikationer", "Link": "Länkar", "MappedDrivesRunningAsService": "Mappade nätverksenheter är inte tillgängliga när de körs som en Windows-tjänst. Se FAQ för mer information", - "No": "Nej" + "No": "Nej", + "ApplicationLongTermStatusCheckAllClientMessage": "Alla indexerare är inte tillgängliga på grund av fel i mer än 6 timmar", + "ApplicationLongTermStatusCheckSingleClientMessage": "Indexatorer är inte tillgängliga på grund av misslyckanden i mer än sex timmar: {0}", + "Duration": "Tid", + "Ended": "Avslutad", + "LastDuration": "lastDuration", + "LastExecution": "Senaste avrättningen", + "NextExecution": "Nästa utförande", + "Queued": "Köad" } diff --git a/src/NzbDrone.Core/Localization/Core/th.json b/src/NzbDrone.Core/Localization/Core/th.json index 21cbf51ac..cc5cf6006 100644 --- a/src/NzbDrone.Core/Localization/Core/th.json +++ b/src/NzbDrone.Core/Localization/Core/th.json @@ -331,5 +331,12 @@ "No": "ไม่", "Link": "ลิงค์", "UnableToLoadIndexers": "ไม่สามารถโหลด Indexers", - "Yes": "ใช่" + "Yes": "ใช่", + "ApplicationLongTermStatusCheckAllClientMessage": "ตัวจัดทำดัชนีทั้งหมดไม่สามารถใช้งานได้เนื่องจากความล้มเหลวเป็นเวลานานกว่า 6 ชั่วโมง", + "ApplicationLongTermStatusCheckSingleClientMessage": "ดัชนีไม่พร้อมใช้งานเนื่องจากความล้มเหลวเป็นเวลานานกว่า 6 ชั่วโมง: {0}", + "Ended": "สิ้นสุดแล้ว", + "LastDuration": "lastDuration", + "LastExecution": "การดำเนินการล่าสุด", + "NextExecution": "การดำเนินการถัดไป", + "Queued": "อยู่ในคิว" } diff --git a/src/NzbDrone.Core/Localization/Core/tr.json b/src/NzbDrone.Core/Localization/Core/tr.json index efaa4e0e6..72878e8a0 100644 --- a/src/NzbDrone.Core/Localization/Core/tr.json +++ b/src/NzbDrone.Core/Localization/Core/tr.json @@ -334,5 +334,12 @@ "UnableToLoadIndexers": "Dizinleyiciler yüklenemiyor", "Yes": "Evet", "Link": "Bağlantılar", - "MappedDrivesRunningAsService": "Eşlenen ağ sürücüleri, bir Windows Hizmeti olarak çalışırken kullanılamaz. Daha fazla bilgi için lütfen SSS bölümüne bakın" + "MappedDrivesRunningAsService": "Eşlenen ağ sürücüleri, bir Windows Hizmeti olarak çalışırken kullanılamaz. Daha fazla bilgi için lütfen SSS bölümüne bakın", + "Ended": "Bitti", + "LastDuration": "lastDuration", + "LastExecution": "Son Yürütme", + "NextExecution": "Sonraki Yürütme", + "Queued": "Sıraya alındı", + "ApplicationLongTermStatusCheckAllClientMessage": "6 saatten uzun süren arızalar nedeniyle tüm dizinleyiciler kullanılamıyor", + "ApplicationLongTermStatusCheckSingleClientMessage": "6 saatten uzun süredir yaşanan arızalar nedeniyle dizinleyiciler kullanılamıyor: {0}" } diff --git a/src/NzbDrone.Core/Localization/Core/vi.json b/src/NzbDrone.Core/Localization/Core/vi.json index d2621cdf7..cb674b0ab 100644 --- a/src/NzbDrone.Core/Localization/Core/vi.json +++ b/src/NzbDrone.Core/Localization/Core/vi.json @@ -331,5 +331,12 @@ "MappedDrivesRunningAsService": "Các ổ đĩa mạng được ánh xạ không khả dụng khi chạy dưới dạng Dịch vụ Windows. Vui lòng xem Câu hỏi thường gặp để biết thêm thông tin", "UnableToLoadIndexers": "Không thể tải Trình chỉ mục", "Yes": "Đúng", - "NetCore": ".NET Core" + "NetCore": ".NET Core", + "Ended": "Đã kết thúc", + "ApplicationLongTermStatusCheckAllClientMessage": "Tất cả các trình lập chỉ mục không khả dụng do lỗi trong hơn 6 giờ", + "ApplicationLongTermStatusCheckSingleClientMessage": "Trình lập chỉ mục không khả dụng do lỗi trong hơn 6 giờ: {0}", + "LastDuration": "lastDuration", + "LastExecution": "Lần thực hiện cuối cùng", + "NextExecution": "Thực hiện tiếp theo", + "Queued": "Đã xếp hàng" } From a352c053abeb5e79c5ca0d8a6032d39b58c6be7f Mon Sep 17 00:00:00 2001 From: Mark McDowall <mark@mcdowall.ca> Date: Sun, 20 Nov 2022 19:09:29 -0800 Subject: [PATCH 0652/2320] Fixed: Publish ApplicationStartingEvent during startup (cherry picked from commit 5400bce1295bdc4198d2cfe0b9258bbb7ccf0852) Fixes #1199 --- src/NzbDrone.Host/Startup.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/NzbDrone.Host/Startup.cs b/src/NzbDrone.Host/Startup.cs index 44db1e7c7..b8461c581 100644 --- a/src/NzbDrone.Host/Startup.cs +++ b/src/NzbDrone.Host/Startup.cs @@ -19,6 +19,8 @@ using NzbDrone.Common.Serializer; using NzbDrone.Core.Configuration; using NzbDrone.Core.Datastore; using NzbDrone.Core.Instrumentation; +using NzbDrone.Core.Lifecycle; +using NzbDrone.Core.Messaging.Events; using NzbDrone.Host.AccessControl; using NzbDrone.Http.Authentication; using NzbDrone.SignalR; @@ -215,6 +217,7 @@ namespace NzbDrone.Host IConfigFileProvider configFileProvider, IRuntimeInfo runtimeInfo, IFirewallAdapter firewallAdapter, + IEventAggregator eventAggregator, ProwlarrErrorPipeline errorHandler) { initializeLogger.Initialize(); @@ -236,6 +239,8 @@ namespace NzbDrone.Host Console.CancelKeyPress += (sender, eventArgs) => NLog.LogManager.Configuration = null; } + eventAggregator.PublishEvent(new ApplicationStartingEvent()); + if (OsInfo.IsWindows && runtimeInfo.IsAdmin) { firewallAdapter.MakeAccessible(); From 9b46ab73e4592d3ad620ec772132fbb1a866c7fa Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 29 Nov 2022 19:42:35 -0600 Subject: [PATCH 0653/2320] Fixed: (Orpheus) Parse date from epoch or date time string --- .../Files/Indexers/Orpheus/recentfeed.json | 2578 +++++++++++++++++ .../OrpheusTests/OrpheusFixture.cs | 68 + .../Indexers/Definitions/Orpheus.cs | 2 +- 3 files changed, 2647 insertions(+), 1 deletion(-) create mode 100644 src/NzbDrone.Core.Test/Files/Indexers/Orpheus/recentfeed.json create mode 100644 src/NzbDrone.Core.Test/IndexerTests/OrpheusTests/OrpheusFixture.cs diff --git a/src/NzbDrone.Core.Test/Files/Indexers/Orpheus/recentfeed.json b/src/NzbDrone.Core.Test/Files/Indexers/Orpheus/recentfeed.json new file mode 100644 index 000000000..9b2c9ef10 --- /dev/null +++ b/src/NzbDrone.Core.Test/Files/Indexers/Orpheus/recentfeed.json @@ -0,0 +1,2578 @@ +{ + "status": "success", + "response": { + "currentPage": 1, + "pages": 1, + "results": [ + { + "groupId": "466", + "groupName": "Abbey Road", + "artist": "The Beatles", + "cover": "https:\/\/i.ibb.co\/G7db15G\/thebeatles-abbeyroad-3hs8.jpg", + "tags": [ + "rock", + "pop", + "pop.rock", + "classic.rock", + "psychedelic.rock", + "psychedelic", + "blues", + "british", + "hard.rock", + "progressive.rock", + "britpop", + "rock.and.roll", + "uk", + "acoustic", + "folk", + "folk.rock", + "art.pop", + "progressive.pop", + "psychedelic.pop" + ], + "bookmarked": false, + "vanityHouse": false, + "groupYear": 1969, + "releaseType": "Album", + "groupTime": "2022-08-08 02:07:39", + "maxSize": 2987944720, + "totalSnatched": 1043, + "totalSeeders": 381, + "totalLeechers": 0, + "torrents": [ + { + "torrentId": 101883, + "editionId": 1, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": false, + "remasterYear": 0, + "remasterRecordLabel": "", + "remasterCatalogueNumber": "", + "remasterTitle": "", + "media": "Vinyl", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 18, + "time": "2016-11-30 22:05:03", + "size": 979581415, + "snatches": 35, + "seeders": 13, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 908633, + "editionId": 1, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": false, + "remasterYear": 0, + "remasterRecordLabel": "", + "remasterCatalogueNumber": "", + "remasterTitle": "", + "media": "Vinyl", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 24, + "time": "2018-11-07 10:12:56", + "size": 1822196345, + "snatches": 25, + "seeders": 9, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 115009, + "editionId": 1, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": false, + "remasterYear": 0, + "remasterRecordLabel": "", + "remasterCatalogueNumber": "", + "remasterTitle": "", + "media": "Vinyl", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 18, + "time": "2016-12-01 22:00:48", + "size": 275416192, + "snatches": 25, + "seeders": 8, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1551233, + "editionId": 1, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": false, + "remasterYear": 0, + "remasterRecordLabel": "", + "remasterCatalogueNumber": "", + "remasterTitle": "", + "media": "Vinyl", + "format": "MP3", + "encoding": "320", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 18, + "time": "2021-02-10 00:36:33", + "size": 113625975, + "snatches": 0, + "seeders": 0, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 115017, + "editionId": 1, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": false, + "remasterYear": 0, + "remasterRecordLabel": "", + "remasterCatalogueNumber": "", + "remasterTitle": "", + "media": "Vinyl", + "format": "MP3", + "encoding": "V0 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 18, + "time": "2016-12-01 22:01:45", + "size": 90114600, + "snatches": 15, + "seeders": 3, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 917246, + "editionId": 2, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1969, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "PCS 7088", + "remasterTitle": "Original UK 2-1", + "media": "Vinyl", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 19, + "time": "2018-11-10 02:07:08", + "size": 1001105251, + "snatches": 21, + "seeders": 8, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1166633, + "editionId": 2, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1969, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "PCS 7088", + "remasterTitle": "Original UK 2-1", + "media": "Vinyl", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 19, + "time": "2019-07-11 20:27:41", + "size": 283602860, + "snatches": 6, + "seeders": 2, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1166636, + "editionId": 2, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1969, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "PCS 7088", + "remasterTitle": "Original UK 2-1", + "media": "Vinyl", + "format": "MP3", + "encoding": "320", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 19, + "time": "2019-07-11 20:28:21", + "size": 113887054, + "snatches": 0, + "seeders": 0, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1166635, + "editionId": 2, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1969, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "PCS 7088", + "remasterTitle": "Original UK 2-1", + "media": "Vinyl", + "format": "MP3", + "encoding": "V0 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 19, + "time": "2019-07-11 20:27:57", + "size": 91220267, + "snatches": 1, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1166637, + "editionId": 2, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1969, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "PCS 7088", + "remasterTitle": "Original UK 2-1", + "media": "Vinyl", + "format": "MP3", + "encoding": "V2 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 19, + "time": "2019-07-11 20:28:36", + "size": 69116433, + "snatches": 0, + "seeders": 0, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 11893, + "editionId": 3, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1976, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "EAS-80560", + "remasterTitle": "Japanese Reissue", + "media": "Vinyl", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 18, + "time": "2016-11-25 20:13:37", + "size": 283317904, + "snatches": 5, + "seeders": 3, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 102022, + "editionId": 4, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1978, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "EALF-97001", + "remasterTitle": "Japanese Reissue", + "media": "Vinyl", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 18, + "time": "2016-11-30 22:45:47", + "size": 1019989421, + "snatches": 5, + "seeders": 4, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 512140, + "editionId": 5, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1979, + "remasterRecordLabel": "Mobile Fidelity Sound Lab", + "remasterCatalogueNumber": "MFSL 1-023", + "remasterTitle": "US Remaster", + "media": "Vinyl", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 30, + "time": "2016-12-23 19:55:17", + "size": 1004236446, + "snatches": 14, + "seeders": 7, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 59456, + "editionId": 5, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1979, + "remasterRecordLabel": "Mobile Fidelity Sound Lab", + "remasterCatalogueNumber": "MFSL 1-023", + "remasterTitle": "US Remaster", + "media": "Vinyl", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 20, + "time": "2016-11-27 10:39:37", + "size": 306275667, + "snatches": 4, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 471855, + "editionId": 6, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1982, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "EAS-50042", + "remasterTitle": "Japanese Reissue", + "media": "Vinyl", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 22, + "time": "2016-12-18 17:40:56", + "size": 1799924820, + "snatches": 11, + "seeders": 4, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 6449, + "editionId": 7, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1983, + "remasterRecordLabel": "EMI-Odeon", + "remasterCatalogueNumber": "CP35-3016", + "remasterTitle": "Original Japanese Release, De-emphasized", + "media": "CD", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": true, + "logScore": 100, + "hasCue": true, + "scene": false, + "vanityHouse": false, + "fileCount": 19, + "time": "2016-11-25 15:11:09", + "size": 257891749, + "snatches": 62, + "seeders": 29, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 155722, + "editionId": 7, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1983, + "remasterRecordLabel": "EMI-Odeon", + "remasterCatalogueNumber": "CP35-3016", + "remasterTitle": "Original Japanese Release, De-emphasized", + "media": "CD", + "format": "MP3", + "encoding": "320", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 19, + "time": "2016-12-04 05:08:51", + "size": 113984473, + "snatches": 0, + "seeders": 0, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 155711, + "editionId": 7, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1983, + "remasterRecordLabel": "EMI-Odeon", + "remasterCatalogueNumber": "CP35-3016", + "remasterTitle": "Original Japanese Release, De-emphasized", + "media": "CD", + "format": "MP3", + "encoding": "V0 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 19, + "time": "2016-12-04 05:08:06", + "size": 89040480, + "snatches": 2, + "seeders": 0, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 200881, + "editionId": 8, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1983, + "remasterRecordLabel": "EMI-Odeon", + "remasterCatalogueNumber": "CP35-3016", + "remasterTitle": "Original Japanese Release, Pre-emphasized", + "media": "CD", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": true, + "logScore": 90, + "hasCue": true, + "scene": false, + "vanityHouse": false, + "fileCount": 19, + "time": "2016-12-06 11:28:55", + "size": 291865783, + "snatches": 5, + "seeders": 3, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1021067, + "editionId": 9, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1986, + "remasterRecordLabel": "Capitol Records", + "remasterCatalogueNumber": "SJ-383", + "remasterTitle": "(24 bit \/ 192khz)", + "media": "Vinyl", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 24, + "time": "2018-12-25 14:12:57", + "size": 1609437638, + "snatches": 15, + "seeders": 6, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1165406, + "editionId": 9, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1986, + "remasterRecordLabel": "Capitol Records", + "remasterCatalogueNumber": "SJ-383", + "remasterTitle": "(24 bit \/ 192khz)", + "media": "Vinyl", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 24, + "time": "2019-07-11 14:03:55", + "size": 330970394, + "snatches": 4, + "seeders": 0, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1165408, + "editionId": 9, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1986, + "remasterRecordLabel": "Capitol Records", + "remasterCatalogueNumber": "SJ-383", + "remasterTitle": "(24 bit \/ 192khz)", + "media": "Vinyl", + "format": "MP3", + "encoding": "320", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 24, + "time": "2019-07-11 14:04:37", + "size": 156847914, + "snatches": 1, + "seeders": 0, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1165407, + "editionId": 9, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1986, + "remasterRecordLabel": "Capitol Records", + "remasterCatalogueNumber": "SJ-383", + "remasterTitle": "(24 bit \/ 192khz)", + "media": "Vinyl", + "format": "MP3", + "encoding": "V0 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 24, + "time": "2019-07-11 14:04:13", + "size": 134282794, + "snatches": 1, + "seeders": 0, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1165409, + "editionId": 9, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1986, + "remasterRecordLabel": "Capitol Records", + "remasterCatalogueNumber": "SJ-383", + "remasterTitle": "(24 bit \/ 192khz)", + "media": "Vinyl", + "format": "MP3", + "encoding": "V2 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 24, + "time": "2019-07-11 14:04:55", + "size": 112771754, + "snatches": 1, + "seeders": 0, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1705686, + "editionId": 10, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1986, + "remasterRecordLabel": "Capitol Records", + "remasterCatalogueNumber": "SJ-383", + "remasterTitle": "U.S.", + "media": "Vinyl", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 20, + "time": "2021-10-28 15:21:07", + "size": 927034006, + "snatches": 1, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 737762, + "editionId": 11, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1987, + "remasterRecordLabel": "Parlophone", + "remasterCatalogueNumber": "CDP 7 46446 2", + "remasterTitle": "Italy Reissue, Remastered", + "media": "CD", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": true, + "logScore": 100, + "hasCue": true, + "scene": false, + "vanityHouse": false, + "fileCount": 28, + "time": "2017-02-18 20:26:21", + "size": 284778602, + "snatches": 25, + "seeders": 9, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 908623, + "editionId": 12, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1987, + "remasterRecordLabel": "Odeon", + "remasterCatalogueNumber": "CP32-5332", + "remasterTitle": "Japan", + "media": "CD", + "format": "MP3", + "encoding": "320", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 21, + "time": "2018-11-07 10:09:10", + "size": 114090426, + "snatches": 2, + "seeders": 2, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 908624, + "editionId": 12, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1987, + "remasterRecordLabel": "Odeon", + "remasterCatalogueNumber": "CP32-5332", + "remasterTitle": "Japan", + "media": "CD", + "format": "MP3", + "encoding": "V0 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 21, + "time": "2018-11-07 10:09:11", + "size": 89508051, + "snatches": 0, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 908625, + "editionId": 12, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1987, + "remasterRecordLabel": "Odeon", + "remasterCatalogueNumber": "CP32-5332", + "remasterTitle": "Japan", + "media": "CD", + "format": "MP3", + "encoding": "V2 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 21, + "time": "2018-11-07 10:09:11", + "size": 67599678, + "snatches": 1, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 849104, + "editionId": 13, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1988, + "remasterRecordLabel": "Capitol Records", + "remasterCatalogueNumber": "C1-46446", + "remasterTitle": "", + "media": "Vinyl", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 28, + "time": "2017-05-09 11:06:56", + "size": 1055178274, + "snatches": 4, + "seeders": 3, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 912595, + "editionId": 14, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2009, + "remasterRecordLabel": "Apple Records \/ Parlophone Records \/ EMI Music Canada", + "remasterCatalogueNumber": "0946 3 82468 2 4", + "remasterTitle": "Stereo \/ Enhanced CD", + "media": "CD", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": true, + "logScore": 100, + "hasCue": true, + "scene": false, + "vanityHouse": false, + "fileCount": 35, + "time": "2018-11-08 14:51:40", + "size": 338886144, + "snatches": 101, + "seeders": 40, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1886932, + "editionId": 14, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2009, + "remasterRecordLabel": "Apple Records \/ Parlophone Records \/ EMI Music Canada", + "remasterCatalogueNumber": "0946 3 82468 2 4", + "remasterTitle": "Stereo \/ Enhanced CD", + "media": "CD", + "format": "MP3", + "encoding": "320", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 34, + "time": "2022-07-09 12:42:13", + "size": 155829879, + "snatches": 0, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1886931, + "editionId": 14, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2009, + "remasterRecordLabel": "Apple Records \/ Parlophone Records \/ EMI Music Canada", + "remasterCatalogueNumber": "0946 3 82468 2 4", + "remasterTitle": "Stereo \/ Enhanced CD", + "media": "CD", + "format": "MP3", + "encoding": "V0 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 34, + "time": "2022-07-09 12:41:58", + "size": 135083377, + "snatches": 0, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 64244, + "editionId": 15, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2009, + "remasterRecordLabel": "Apple Records, Parlophone", + "remasterCatalogueNumber": "0946 3 82468 2 4", + "remasterTitle": "Worldwide Remaster", + "media": "CD", + "format": "MP3", + "encoding": "320", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 19, + "time": "2016-11-27 16:59:12", + "size": 114178240, + "snatches": 2, + "seeders": 2, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 64235, + "editionId": 15, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2009, + "remasterRecordLabel": "Apple Records, Parlophone", + "remasterCatalogueNumber": "0946 3 82468 2 4", + "remasterTitle": "Worldwide Remaster", + "media": "CD", + "format": "MP3", + "encoding": "V0 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 19, + "time": "2016-11-27 16:58:39", + "size": 93431738, + "snatches": 22, + "seeders": 6, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 64252, + "editionId": 15, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2009, + "remasterRecordLabel": "Apple Records, Parlophone", + "remasterCatalogueNumber": "0946 3 82468 2 4", + "remasterTitle": "Worldwide Remaster", + "media": "CD", + "format": "MP3", + "encoding": "V2 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 19, + "time": "2016-11-27 16:59:34", + "size": 68130983, + "snatches": 1, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1212382, + "editionId": 16, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Universal Music Group", + "remasterCatalogueNumber": "0602577915079", + "remasterTitle": "2 CD Anniversary Edition", + "media": "CD", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": true, + "logScore": 100, + "hasCue": true, + "scene": false, + "vanityHouse": false, + "fileCount": 39, + "time": "2019-09-27 21:10:05", + "size": 597512250, + "snatches": 33, + "seeders": 10, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1212713, + "editionId": 17, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Universal Music Group International", + "remasterCatalogueNumber": "0602577921117", + "remasterTitle": "2.0 Mix", + "media": "BD", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 18, + "time": "2019-09-28 19:28:41", + "size": 1054069308, + "snatches": 78, + "seeders": 28, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1902445, + "editionId": 17, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Universal Music Group International", + "remasterCatalogueNumber": "0602577921117", + "remasterTitle": "2.0 Mix", + "media": "BD", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 18, + "time": "2022-08-08 02:06:25", + "size": 310360156, + "snatches": 0, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1902447, + "editionId": 17, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Universal Music Group International", + "remasterCatalogueNumber": "0602577921117", + "remasterTitle": "2.0 Mix", + "media": "BD", + "format": "MP3", + "encoding": "320", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 18, + "time": "2022-08-08 02:07:18", + "size": 114179993, + "snatches": 0, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1902446, + "editionId": 17, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Universal Music Group International", + "remasterCatalogueNumber": "0602577921117", + "remasterTitle": "2.0 Mix", + "media": "BD", + "format": "MP3", + "encoding": "V0 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 18, + "time": "2022-08-08 02:06:45", + "size": 94390992, + "snatches": 0, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1902448, + "editionId": 17, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Universal Music Group International", + "remasterCatalogueNumber": "0602577921117", + "remasterTitle": "2.0 Mix", + "media": "BD", + "format": "MP3", + "encoding": "V2 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 18, + "time": "2022-08-08 02:07:39", + "size": 68296866, + "snatches": 0, + "seeders": 0, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1216526, + "editionId": 18, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "0602577921124", + "remasterTitle": "50th Anniversary Super Deluxe Edition", + "media": "CD", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": true, + "logScore": 100, + "hasCue": true, + "scene": false, + "vanityHouse": false, + "fileCount": 70, + "time": "2019-10-04 22:47:53", + "size": 932233618, + "snatches": 122, + "seeders": 50, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1371515, + "editionId": 18, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "0602577921124", + "remasterTitle": "50th Anniversary Super Deluxe Edition", + "media": "CD", + "format": "MP3", + "encoding": "320", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 67, + "time": "2020-06-12 08:44:53", + "size": 458131494, + "snatches": 1, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1371514, + "editionId": 18, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "0602577921124", + "remasterTitle": "50th Anniversary Super Deluxe Edition", + "media": "CD", + "format": "MP3", + "encoding": "V0 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 67, + "time": "2020-06-12 08:43:15", + "size": 392721712, + "snatches": 0, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1371516, + "editionId": 18, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "0602577921124", + "remasterTitle": "50th Anniversary Super Deluxe Edition", + "media": "CD", + "format": "MP3", + "encoding": "V2 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 67, + "time": "2020-06-12 08:45:39", + "size": 320943449, + "snatches": 0, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1520881, + "editionId": 19, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Universal Music Group International", + "remasterCatalogueNumber": "0602577921117", + "remasterTitle": "7.1 Multichannel", + "media": "BD", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 18, + "time": "2020-12-26 14:33:19", + "size": 1480251699, + "snatches": 15, + "seeders": 10, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1887318, + "editionId": 20, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Universal Music Group International", + "remasterCatalogueNumber": "0602577921117", + "remasterTitle": "Multichannel", + "media": "BD", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 19, + "time": "2022-07-10 11:08:46", + "size": 2575519965, + "snatches": 4, + "seeders": 4, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1212665, + "editionId": 21, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "B0030710-01", + "remasterTitle": "Remastered", + "media": "Vinyl", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 27, + "time": "2019-09-28 16:41:36", + "size": 1072439516, + "snatches": 26, + "seeders": 6, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1483504, + "editionId": 21, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "B0030710-01", + "remasterTitle": "Remastered", + "media": "Vinyl", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 27, + "time": "2020-11-11 03:58:25", + "size": 294191860, + "snatches": 1, + "seeders": 0, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1605909, + "editionId": 21, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "B0030710-01", + "remasterTitle": "Remastered", + "media": "Vinyl", + "format": "MP3", + "encoding": "320", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 26, + "time": "2021-05-10 09:26:37", + "size": 124408658, + "snatches": 0, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1605908, + "editionId": 21, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "B0030710-01", + "remasterTitle": "Remastered", + "media": "Vinyl", + "format": "MP3", + "encoding": "V0 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 26, + "time": "2021-05-10 09:25:48", + "size": 100361236, + "snatches": 0, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1897946, + "editionId": 22, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Apple Records, Universal Music Group International", + "remasterCatalogueNumber": "0602577915123", + "remasterTitle": "Remastered", + "media": "Vinyl", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 23, + "time": "2022-07-30 08:34:26", + "size": 2082970544, + "snatches": 1, + "seeders": 0, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1212011, + "editionId": 23, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "", + "remasterTitle": "Super Deluxe Edition 3 CD", + "media": "WEB", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 44, + "time": "2019-09-27 02:56:24", + "size": 2987944720, + "snatches": 173, + "seeders": 49, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1216707, + "editionId": 23, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "", + "remasterTitle": "Super Deluxe Edition 3 CD", + "media": "WEB", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 46, + "time": "2019-10-05 14:47:38", + "size": 830933669, + "snatches": 61, + "seeders": 27, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1212241, + "editionId": 23, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "", + "remasterTitle": "Super Deluxe Edition 3 CD", + "media": "WEB", + "format": "MP3", + "encoding": "320", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 41, + "time": "2019-09-27 11:19:23", + "size": 340943769, + "snatches": 21, + "seeders": 2, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1211892, + "editionId": 23, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 2019, + "remasterRecordLabel": "Apple Records", + "remasterCatalogueNumber": "", + "remasterTitle": "Super Deluxe Edition 3 CD", + "media": "WEB", + "format": "MP3", + "encoding": "V0 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 43, + "time": "2019-09-26 19:57:43", + "size": 278707465, + "snatches": 90, + "seeders": 18, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + } + ] + }, + { + "groupId": "705434", + "groupName": "Abbey Road", + "artist": "The Beatles Complete On Ukulele", + "cover": "https:\/\/f4.bcbits.com\/img\/a3593733374_16.jpg", + "tags": [ + "2010s" + ], + "bookmarked": false, + "vanityHouse": false, + "groupYear": 2012, + "releaseType": "Anthology", + "groupTime": "2021-02-09 18:49:48", + "maxSize": 266108551, + "totalSnatched": 10, + "totalSeeders": 4, + "totalLeechers": 0, + "torrents": [ + { + "torrentId": 1551001, + "editionId": 1, + "artists": [ + { + "id": 635426, + "aliasid": 672289, + "name": "The Beatles Complete On Ukulele" + } + ], + "remastered": true, + "remasterYear": 2020, + "remasterRecordLabel": "", + "remasterCatalogueNumber": "", + "remasterTitle": "", + "media": "WEB", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 18, + "time": "2021-02-09 18:49:48", + "size": 266108551, + "snatches": 10, + "seeders": 4, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + } + ] + }, + { + "groupId": "542461", + "groupName": "After Abbey Road: Celebrating the 50th Anniversary of The Beatles' Classic", + "artist": "Mike Westbrook", + "cover": "https:\/\/funkyimg.com\/i\/2Xohc.jpg", + "tags": [ + "jazz" + ], + "bookmarked": false, + "vanityHouse": false, + "groupYear": 2019, + "releaseType": "Live album", + "groupTime": "2019-09-30 04:32:51", + "maxSize": 1160543783, + "totalSnatched": 11, + "totalSeeders": 5, + "totalLeechers": 0, + "torrents": [ + { + "torrentId": 1213141, + "editionId": 1, + "artists": [ + { + "id": 44961, + "aliasid": 44975, + "name": "Mike Westbrook" + } + ], + "remastered": false, + "remasterYear": 0, + "remasterRecordLabel": "", + "remasterCatalogueNumber": "", + "remasterTitle": "", + "media": "WEB", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 19, + "time": "2019-09-30 04:31:17", + "size": 1160543783, + "snatches": 6, + "seeders": 3, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 1213142, + "editionId": 1, + "artists": [ + { + "id": 44961, + "aliasid": 44975, + "name": "Mike Westbrook" + } + ], + "remastered": false, + "remasterYear": 0, + "remasterRecordLabel": "", + "remasterCatalogueNumber": "", + "remasterTitle": "", + "media": "WEB", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 18, + "time": "2019-09-30 04:32:51", + "size": 652493373, + "snatches": 5, + "seeders": 2, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + } + ] + }, + { + "groupId": "438621", + "groupName": "Bob Baldwin Presents Abbey Road and The Beatles", + "artist": "Bob Baldwin", + "cover": "https:\/\/images-na.ssl-images-amazon.com\/images\/I\/51JgI6blmwL.jpg", + "tags": [ + "jazz" + ], + "bookmarked": false, + "vanityHouse": false, + "groupYear": 2018, + "releaseType": "Album", + "groupTime": "2018-11-22 15:24:40", + "maxSize": 781045802, + "totalSnatched": 3, + "totalSeeders": 2, + "totalLeechers": 0, + "torrents": [ + { + "torrentId": 962463, + "editionId": 1, + "artists": [ + { + "id": 315060, + "aliasid": 318321, + "name": "Bob Baldwin" + } + ], + "remastered": false, + "remasterYear": 0, + "remasterRecordLabel": "", + "remasterCatalogueNumber": "", + "remasterTitle": "", + "media": "WEB", + "format": "FLAC", + "encoding": "24bit Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 13, + "time": "2018-11-22 15:24:40", + "size": 781045802, + "snatches": 3, + "seeders": 2, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + } + ] + }, + { + "groupId": "287801", + "groupName": "Mark Lewisohn - The Beatles: Recording Sessions; The Official Abbey Road Studio Session Notes", + "torrentId": 639730, + "tags": [ + "abbey.road", + "beatles", + "recording", + "music.history", + "pdf" + ], + "category": "E-Books", + "fileCount": 1, + "groupTime": "2017-01-15 23:26:56", + "size": 74441014, + "snatches": 4, + "seeders": 2, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "groupId": "127647", + "groupName": "Abbey Road Now! (Mojo Presents The Beatles' 1969 Classic Re-Recorded!)", + "artist": "The Beatles performed by Various Artists", + "cover": "https:\/\/i.imgur.com\/NBAH02w.jpg", + "tags": [ + "alternative.rock", + "pop", + "pop.rock", + "rock" + ], + "bookmarked": false, + "vanityHouse": false, + "groupYear": 2009, + "releaseType": "Compilation", + "groupTime": "2016-12-22 07:51:18", + "maxSize": 372296409, + "totalSnatched": 9, + "totalSeeders": 4, + "totalLeechers": 0, + "torrents": [ + { + "torrentId": 245444, + "editionId": 1, + "artists": [ + { + "id": 115923, + "aliasid": 115972, + "name": "Blue Roses" + }, + { + "id": 33172, + "aliasid": 33172, + "name": "Broken Records" + }, + { + "id": 16625, + "aliasid": 16625, + "name": "Charlie Dore" + }, + { + "id": 25495, + "aliasid": 25495, + "name": "Cornershop" + }, + { + "id": 115921, + "aliasid": 115970, + "name": "Glenn Tilbrook" + }, + { + "id": 1779, + "aliasid": 1779, + "name": "Gomez" + }, + { + "id": 30198, + "aliasid": 30198, + "name": "Jeffrey Lewis" + }, + { + "id": 106942, + "aliasid": 106987, + "name": "Karima Francis" + }, + { + "id": 115919, + "aliasid": 115968, + "name": "Leisure Society" + }, + { + "id": 81975, + "aliasid": 82000, + "name": "Let's Wrestle" + }, + { + "id": 115924, + "aliasid": 115973, + "name": "Loose Salute" + }, + { + "id": 115920, + "aliasid": 115969, + "name": "Martin John Henry" + }, + { + "id": 115922, + "aliasid": 115971, + "name": "Nine Below Zero" + }, + { + "id": 28979, + "aliasid": 28979, + "name": "Noah and the Whale" + }, + { + "id": 14837, + "aliasid": 14837, + "name": "Robyn Hitchcock" + }, + { + "id": 1715, + "aliasid": 1715, + "name": "The Invisible" + }, + { + "id": 39983, + "aliasid": 39990, + "name": "The Low Anthem" + } + ], + "remastered": false, + "remasterYear": 0, + "remasterRecordLabel": "", + "remasterCatalogueNumber": "", + "remasterTitle": "", + "media": "CD", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": true, + "logScore": 100, + "hasCue": true, + "scene": false, + "vanityHouse": false, + "fileCount": 26, + "time": "2016-12-08 00:49:14", + "size": 372296409, + "snatches": 7, + "seeders": 3, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + }, + { + "torrentId": 500231, + "editionId": 1, + "artists": [ + { + "id": 115923, + "aliasid": 115972, + "name": "Blue Roses" + }, + { + "id": 33172, + "aliasid": 33172, + "name": "Broken Records" + }, + { + "id": 16625, + "aliasid": 16625, + "name": "Charlie Dore" + }, + { + "id": 25495, + "aliasid": 25495, + "name": "Cornershop" + }, + { + "id": 115921, + "aliasid": 115970, + "name": "Glenn Tilbrook" + }, + { + "id": 1779, + "aliasid": 1779, + "name": "Gomez" + }, + { + "id": 30198, + "aliasid": 30198, + "name": "Jeffrey Lewis" + }, + { + "id": 106942, + "aliasid": 106987, + "name": "Karima Francis" + }, + { + "id": 115919, + "aliasid": 115968, + "name": "Leisure Society" + }, + { + "id": 81975, + "aliasid": 82000, + "name": "Let's Wrestle" + }, + { + "id": 115924, + "aliasid": 115973, + "name": "Loose Salute" + }, + { + "id": 115920, + "aliasid": 115969, + "name": "Martin John Henry" + }, + { + "id": 115922, + "aliasid": 115971, + "name": "Nine Below Zero" + }, + { + "id": 28979, + "aliasid": 28979, + "name": "Noah and the Whale" + }, + { + "id": 14837, + "aliasid": 14837, + "name": "Robyn Hitchcock" + }, + { + "id": 1715, + "aliasid": 1715, + "name": "The Invisible" + }, + { + "id": 39983, + "aliasid": 39990, + "name": "The Low Anthem" + } + ], + "remastered": false, + "remasterYear": 0, + "remasterRecordLabel": "", + "remasterCatalogueNumber": "", + "remasterTitle": "", + "media": "CD", + "format": "MP3", + "encoding": "V0 (VBR)", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 25, + "time": "2016-12-22 07:51:18", + "size": 160605741, + "snatches": 2, + "seeders": 1, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + } + ] + }, + { + "groupId": "33646", + "groupName": "The Alternate Abbey Road", + "artist": "The Beatles", + "cover": "https:\/\/i.imgur.com\/mWQE7H8.jpg", + "tags": [ + "rock" + ], + "bookmarked": false, + "vanityHouse": false, + "groupYear": 1997, + "releaseType": "Bootleg", + "groupTime": "2016-11-26 23:30:22", + "maxSize": 370460438, + "totalSnatched": 4, + "totalSeeders": 2, + "totalLeechers": 0, + "torrents": [ + { + "torrentId": 49915, + "editionId": 1, + "artists": [ + { + "id": 14, + "aliasid": 14, + "name": "The Beatles" + } + ], + "remastered": true, + "remasterYear": 1997, + "remasterRecordLabel": "", + "remasterCatalogueNumber": "", + "remasterTitle": "Fake Edition", + "media": "CD", + "format": "FLAC", + "encoding": "Lossless", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 25, + "time": "2016-11-26 23:30:22", + "size": 370460438, + "snatches": 4, + "seeders": 2, + "leechers": 0, + "isFreeleech": false, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": true, + "hasSnatched": false + } + ] + } + ] + }, + "info": { + "source": "Orpheus", + "version": 2 + } +} \ No newline at end of file diff --git a/src/NzbDrone.Core.Test/IndexerTests/OrpheusTests/OrpheusFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/OrpheusTests/OrpheusFixture.cs new file mode 100644 index 000000000..b8d007c90 --- /dev/null +++ b/src/NzbDrone.Core.Test/IndexerTests/OrpheusTests/OrpheusFixture.cs @@ -0,0 +1,68 @@ +using System; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Common.Http; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Indexers.Definitions; +using NzbDrone.Core.Indexers.Gazelle; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.IndexerTests.OrpheusTests +{ + [TestFixture] + public class OrpheusFixture : CoreTest<Orpheus> + { + [SetUp] + public void Setup() + { + Subject.Definition = new IndexerDefinition() + { + Name = "Orpheus", + Settings = new OrpheusSettings() { Apikey = "somekey" } + }; + } + + [Test] + public async Task should_parse_recent_feed_from_GazelleGames() + { + var recentFeed = ReadAllText(@"Files/Indexers/Orpheus/recentfeed.json"); + + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader { { "Content-Type", "application/json" } }, new CookieCollection(), recentFeed))); + + var releases = (await Subject.Fetch(new BasicSearchCriteria { Categories = new int[] { 2000 } })).Releases; + + releases.Should().HaveCount(65); + releases.First().Should().BeOfType<GazelleInfo>(); + + var torrentInfo = releases.First() as GazelleInfo; + + torrentInfo.Title.Should().Be("The Beatles - Abbey Road (1969) [MP3 V2 (VBR)] [BD]"); + torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent); + torrentInfo.DownloadUrl.Should().Be("https://orpheus.network/ajax.php?action=download&id=1902448"); + torrentInfo.InfoUrl.Should().Be("https://orpheus.network/torrents.php?id=466&torrentid=1902448"); + torrentInfo.CommentUrl.Should().BeNullOrEmpty(); + torrentInfo.Indexer.Should().Be(Subject.Definition.Name); + torrentInfo.PublishDate.Should().Be(DateTime.Parse("2022-08-07 21:07:39").ToUniversalTime()); + torrentInfo.Size.Should().Be(68296866); + torrentInfo.InfoHash.Should().Be(null); + torrentInfo.MagnetUrl.Should().Be(null); + torrentInfo.Peers.Should().Be(0); + torrentInfo.Seeders.Should().Be(0); + torrentInfo.ImdbId.Should().Be(0); + torrentInfo.TmdbId.Should().Be(0); + torrentInfo.TvdbId.Should().Be(0); + torrentInfo.Languages.Should().HaveCount(0); + torrentInfo.Subs.Should().HaveCount(0); + torrentInfo.DownloadVolumeFactor.Should().Be(1); + torrentInfo.UploadVolumeFactor.Should().Be(1); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs index b52287137..62d0db71b 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs @@ -281,7 +281,7 @@ namespace NzbDrone.Core.Indexers.Definitions InfoUrl = infoUrl, Seeders = int.Parse(result.Seeders), Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders), - PublishDate = DateTimeOffset.FromUnixTimeSeconds(ParseUtil.CoerceLong(result.GroupTime)).UtcDateTime, + PublishDate = long.TryParse(result.GroupTime, out var num) ? DateTimeOffset.FromUnixTimeSeconds(num).UtcDateTime : DateTimeUtil.FromFuzzyTime((string)result.GroupTime), Freeleech = result.IsFreeLeech || result.IsPersonalFreeLeech, Files = result.FileCount, Grabs = result.Snatches, From 1cce39b404290cd1564a3e19ee8ab54ba9a1834a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 29 Nov 2022 20:15:23 -0600 Subject: [PATCH 0654/2320] Fix Orpheus Tests --- .../IndexerTests/OrpheusTests/OrpheusFixture.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core.Test/IndexerTests/OrpheusTests/OrpheusFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/OrpheusTests/OrpheusFixture.cs index b8d007c90..5c007cec0 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/OrpheusTests/OrpheusFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/OrpheusTests/OrpheusFixture.cs @@ -50,7 +50,7 @@ namespace NzbDrone.Core.Test.IndexerTests.OrpheusTests torrentInfo.InfoUrl.Should().Be("https://orpheus.network/torrents.php?id=466&torrentid=1902448"); torrentInfo.CommentUrl.Should().BeNullOrEmpty(); torrentInfo.Indexer.Should().Be(Subject.Definition.Name); - torrentInfo.PublishDate.Should().Be(DateTime.Parse("2022-08-07 21:07:39").ToUniversalTime()); + torrentInfo.PublishDate.Should().Be(DateTime.Parse("2022-08-08 2:07:39")); torrentInfo.Size.Should().Be(68296866); torrentInfo.InfoHash.Should().Be(null); torrentInfo.MagnetUrl.Should().Be(null); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs index 62d0db71b..07351a876 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs @@ -281,7 +281,7 @@ namespace NzbDrone.Core.Indexers.Definitions InfoUrl = infoUrl, Seeders = int.Parse(result.Seeders), Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders), - PublishDate = long.TryParse(result.GroupTime, out var num) ? DateTimeOffset.FromUnixTimeSeconds(num).UtcDateTime : DateTimeUtil.FromFuzzyTime((string)result.GroupTime), + PublishDate = long.TryParse(result.GroupTime, out var num) ? DateTimeOffset.FromUnixTimeSeconds(num).UtcDateTime : DateTimeUtil.FromFuzzyTime(result.GroupTime), Freeleech = result.IsFreeLeech || result.IsPersonalFreeLeech, Files = result.FileCount, Grabs = result.Snatches, From cd3e99ad874d0c766bb0e7c66541b05dfeb9efb3 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Thu, 1 Dec 2022 21:30:27 -0600 Subject: [PATCH 0655/2320] Fixed: Indexer Error handling improvements (#1172) * Fixed: Indexer Error handling improvements * fixup! Fixed: Indexer Error handling improvements --- src/NzbDrone.Core/Indexers/HttpIndexerBase.cs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index 7ab4417a4..14961ca8b 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -210,7 +210,7 @@ namespace NzbDrone.Core.Indexers } if (webException.Message.Contains("502") || webException.Message.Contains("503") || - webException.Message.Contains("timed out")) + webException.Message.Contains("504") || webException.Message.Contains("timed out")) { _logger.Warn("{0} server is currently unavailable. {1} {2}", this, url, webException.Message); } @@ -223,16 +223,10 @@ namespace NzbDrone.Core.Indexers { result.Queries.Add(new IndexerQueryResult { Response = ex.Response }); - if (ex.RetryAfter != TimeSpan.Zero) - { - _indexerStatusService.RecordFailure(Definition.Id, ex.RetryAfter); - } - else - { - _indexerStatusService.RecordFailure(Definition.Id, TimeSpan.FromHours(1)); - } + var retryTime = ex.RetryAfter != TimeSpan.Zero ? ex.RetryAfter : TimeSpan.FromHours(1); - _logger.Warn("Request Limit reached for {0}", this); + _indexerStatusService.RecordFailure(Definition.Id, retryTime); + _logger.Warn("Request Limit reached for {0}. Disabled for {1}", this, retryTime); } catch (HttpException ex) { From c69843931e871badc294f07d8f70b194e6aae5ed Mon Sep 17 00:00:00 2001 From: Zak Saunders <thezak48@users.noreply.github.com> Date: Tue, 6 Dec 2022 07:22:52 +0000 Subject: [PATCH 0656/2320] New: Auto theme option to match OS theme Co-authored-by: Qstick <qstick@gmail.com> --- frontend/src/Styles/Themes/index.js | 4 ++++ src/NzbDrone.Core/Configuration/ConfigFileProvider.cs | 2 +- src/NzbDrone.Core/Localization/Core/en.json | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/src/Styles/Themes/index.js b/frontend/src/Styles/Themes/index.js index 02068cc4c..d93c5dd8c 100644 --- a/frontend/src/Styles/Themes/index.js +++ b/frontend/src/Styles/Themes/index.js @@ -1,7 +1,11 @@ import * as dark from './dark'; import * as light from './light'; +const defaultDark = window.matchMedia('(prefers-color-scheme: dark)').matches; +const auto = defaultDark ? { ...dark } : { ...light }; + export default { + auto, light, dark }; diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index 6b55b6ece..ac5955069 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -206,7 +206,7 @@ namespace NzbDrone.Core.Configuration public string PostgresMainDb => _postgresOptions?.MainDb ?? GetValue("PostgresMainDb", "prowlarr-main", persist: false); public string PostgresLogDb => _postgresOptions?.LogDb ?? GetValue("PostgresLogDb", "prowlarr-log", persist: false); public int PostgresPort => (_postgresOptions?.Port ?? 0) != 0 ? _postgresOptions.Port : GetValueInt("PostgresPort", 5432, persist: false); - public string Theme => GetValue("Theme", "light", persist: false); + public string Theme => GetValue("Theme", "auto", persist: false); public bool LogSql => GetValueBoolean("LogSql", false, persist: false); public int LogRotate => GetValueInt("LogRotate", 50, persist: false); public bool FilterSentryEvents => GetValueBoolean("FilterSentryEvents", true, persist: false); diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 79ea9e092..d39180ffc 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -404,7 +404,7 @@ "TestAllApps": "Test All Apps", "TestAllClients": "Test All Clients", "TestAllIndexers": "Test All Indexers", - "ThemeHelpText": "Change Prowlarr UI theme, inspired by {0}", + "ThemeHelpText": "Change Application UI Theme, 'Auto' Theme will use your OS Theme to set Light or Dark mode. Inspired by {0}", "Time": "Time", "Title": "Title", "Today": "Today", From f172d17eccc1e72660b1ea10a3ea5c7f3c41610c Mon Sep 17 00:00:00 2001 From: Mark McDowall <mark@mcdowall.ca> Date: Sun, 4 Dec 2022 22:08:56 -0800 Subject: [PATCH 0657/2320] Fixed: Improve Bind Address validation and help text --- .../IsValidIPAddressFixture.cs | 25 +++++++++++++++++++ .../Extensions/StringExtensions.cs | 21 ++++++++++++++++ src/NzbDrone.Core/Localization/Core/en.json | 2 +- src/NzbDrone.Core/Validation/IpValidation.cs | 22 +++------------- .../Config/HostConfigController.cs | 4 +-- 5 files changed, 52 insertions(+), 22 deletions(-) create mode 100644 src/NzbDrone.Common.Test/ExtensionTests/StringExtensionTests/IsValidIPAddressFixture.cs diff --git a/src/NzbDrone.Common.Test/ExtensionTests/StringExtensionTests/IsValidIPAddressFixture.cs b/src/NzbDrone.Common.Test/ExtensionTests/StringExtensionTests/IsValidIPAddressFixture.cs new file mode 100644 index 000000000..0e2ac3d63 --- /dev/null +++ b/src/NzbDrone.Common.Test/ExtensionTests/StringExtensionTests/IsValidIPAddressFixture.cs @@ -0,0 +1,25 @@ +using System.Globalization; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Common.Extensions; + +namespace NzbDrone.Common.Test.ExtensionTests.StringExtensionTests +{ + [TestFixture] + public class IsValidIPAddressFixture + { + [TestCase("192.168.0.1")] + [TestCase("::1")] + [TestCase("2001:db8:4006:812::200e")] + public void should_validate_ip_address(string input) + { + input.IsValidIpAddress().Should().BeTrue(); + } + + [TestCase("sonarr.tv")] + public void should_not_parse_non_ip_address(string input) + { + input.IsValidIpAddress().Should().BeFalse(); + } + } +} diff --git a/src/NzbDrone.Common/Extensions/StringExtensions.cs b/src/NzbDrone.Common/Extensions/StringExtensions.cs index 28725f269..5e5c069d5 100644 --- a/src/NzbDrone.Common/Extensions/StringExtensions.cs +++ b/src/NzbDrone.Common/Extensions/StringExtensions.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; +using System.Net.Sockets; using System.Text; using System.Text.RegularExpressions; @@ -231,5 +232,25 @@ namespace NzbDrone.Common.Extensions .Replace("'", "%27") .Replace("%7E", "~"); } + + public static bool IsValidIpAddress(this string value) + { + if (!IPAddress.TryParse(value, out var parsedAddress)) + { + return false; + } + + if (parsedAddress.Equals(IPAddress.Parse("255.255.255.255"))) + { + return false; + } + + if (parsedAddress.IsIPv6Multicast) + { + return false; + } + + return parsedAddress.AddressFamily == AddressFamily.InterNetwork || parsedAddress.AddressFamily == AddressFamily.InterNetworkV6; + } } } diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index d39180ffc..56cb6cc95 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -54,7 +54,7 @@ "Backups": "Backups", "BeforeUpdate": "Before update", "BindAddress": "Bind Address", - "BindAddressHelpText": "Valid IP4 address or '*' for all interfaces", + "BindAddressHelpText": "Valid IP address, localhost or '*' for all interfaces", "BookSearch": "Book Search", "BookSearchTypes": "Book Search Types", "Branch": "Branch", diff --git a/src/NzbDrone.Core/Validation/IpValidation.cs b/src/NzbDrone.Core/Validation/IpValidation.cs index 7037ae1ea..eb5863caa 100644 --- a/src/NzbDrone.Core/Validation/IpValidation.cs +++ b/src/NzbDrone.Core/Validation/IpValidation.cs @@ -1,30 +1,14 @@ -using System.Net; -using System.Net.Sockets; using FluentValidation; using FluentValidation.Validators; +using NzbDrone.Common.Extensions; namespace NzbDrone.Core.Validation { public static class IpValidation { - public static IRuleBuilderOptions<T, string> ValidIp4Address<T>(this IRuleBuilder<T, string> ruleBuilder) + public static IRuleBuilderOptions<T, string> ValidIpAddress<T>(this IRuleBuilder<T, string> ruleBuilder) { - return ruleBuilder.Must(x => - { - IPAddress parsedAddress; - - if (!IPAddress.TryParse(x, out parsedAddress)) - { - return false; - } - - if (parsedAddress.Equals(IPAddress.Parse("255.255.255.255"))) - { - return false; - } - - return parsedAddress.AddressFamily == AddressFamily.InterNetwork; - }).WithMessage("Must contain wildcard (*) or a valid IPv4 Address"); + return ruleBuilder.Must(x => x.IsValidIpAddress()).WithMessage("Must contain wildcard (*) or a valid IP Address"); } public static IRuleBuilderOptions<T, string> NotListenAllIp4Address<T>(this IRuleBuilder<T, string> ruleBuilder) diff --git a/src/Prowlarr.Api.V1/Config/HostConfigController.cs b/src/Prowlarr.Api.V1/Config/HostConfigController.cs index b55163f67..ff890043a 100644 --- a/src/Prowlarr.Api.V1/Config/HostConfigController.cs +++ b/src/Prowlarr.Api.V1/Config/HostConfigController.cs @@ -33,9 +33,9 @@ namespace Prowlarr.Api.V1.Config _userService = userService; SharedValidator.RuleFor(c => c.BindAddress) - .ValidIp4Address() + .ValidIpAddress() .NotListenAllIp4Address() - .When(c => c.BindAddress != "*"); + .When(c => c.BindAddress != "*" && c.BindAddress != "localhost"); SharedValidator.RuleFor(c => c.Port).ValidPort(); From 2af7fac15ee354266f1e2e52764b866c877558b2 Mon Sep 17 00:00:00 2001 From: Mark McDowall <mark@mcdowall.ca> Date: Mon, 5 Dec 2022 00:57:21 -0800 Subject: [PATCH 0658/2320] New: IPv6 support for connections/indexers/download clients --- src/NzbDrone.Common.Test/Http/HttpUriFixture.cs | 3 ++- src/NzbDrone.Common/Extensions/StringExtensions.cs | 5 +++++ src/NzbDrone.Common/Http/HttpUri.cs | 6 ++++-- src/NzbDrone.Core/Validation/RuleBuilderExtensions.cs | 10 ++++++++-- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Common.Test/Http/HttpUriFixture.cs b/src/NzbDrone.Common.Test/Http/HttpUriFixture.cs index 3627b04dc..d25d07bfe 100644 --- a/src/NzbDrone.Common.Test/Http/HttpUriFixture.cs +++ b/src/NzbDrone.Common.Test/Http/HttpUriFixture.cs @@ -1,4 +1,4 @@ -using FluentAssertions; +using FluentAssertions; using NUnit.Framework; using NzbDrone.Common.Http; using NzbDrone.Test.Common; @@ -10,6 +10,7 @@ namespace NzbDrone.Common.Test.Http [TestCase("abc://my_host.com:8080/root/api/")] [TestCase("abc://my_host.com:8080//root/api/")] [TestCase("abc://my_host.com:8080/root//api/")] + [TestCase("abc://[::1]:8080/root//api/")] public void should_parse(string uri) { var newUri = new HttpUri(uri); diff --git a/src/NzbDrone.Common/Extensions/StringExtensions.cs b/src/NzbDrone.Common/Extensions/StringExtensions.cs index 5e5c069d5..8144b6a92 100644 --- a/src/NzbDrone.Common/Extensions/StringExtensions.cs +++ b/src/NzbDrone.Common/Extensions/StringExtensions.cs @@ -252,5 +252,10 @@ namespace NzbDrone.Common.Extensions return parsedAddress.AddressFamily == AddressFamily.InterNetwork || parsedAddress.AddressFamily == AddressFamily.InterNetworkV6; } + + public static string ToUrlHost(this string input) + { + return input.Contains(":") ? $"[{input}]" : input; + } } } diff --git a/src/NzbDrone.Common/Http/HttpUri.cs b/src/NzbDrone.Common/Http/HttpUri.cs index a636071d9..ecd4abf70 100644 --- a/src/NzbDrone.Common/Http/HttpUri.cs +++ b/src/NzbDrone.Common/Http/HttpUri.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Common.Http { public class HttpUri : IEquatable<HttpUri> { - private static readonly Regex RegexUri = new Regex(@"^(?:(?<scheme>[a-z]+):)?(?://(?<host>[-_A-Z0-9.]+)(?::(?<port>[0-9]{1,5}))?)?(?<path>(?:(?:(?<=^)|/+)[^/?#\r\n]+)+/*|/+)?(?:\?(?<query>[^#\r\n]*))?(?:\#(?<fragment>.*))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex RegexUri = new Regex(@"^(?:(?<scheme>[a-z]+):)?(?://(?<host>[-_A-Z0-9.]+|\[[[A-F0-9:]+\])(?::(?<port>[0-9]{1,5}))?)?(?<path>(?:(?:(?<=^)|/+)[^/?#\r\n]+)+/*|/+)?(?:\?(?<query>[^#\r\n]*))?(?:\#(?<fragment>.*))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase); private readonly string _uri; public string FullUri => _uri; @@ -70,6 +70,8 @@ namespace NzbDrone.Common.Http private void Parse() { + var parseSuccess = Uri.TryCreate(_uri, UriKind.RelativeOrAbsolute, out var uri); + var match = RegexUri.Match(_uri); var scheme = match.Groups["scheme"]; @@ -79,7 +81,7 @@ namespace NzbDrone.Common.Http var query = match.Groups["query"]; var fragment = match.Groups["fragment"]; - if (!match.Success || (scheme.Success && !host.Success && path.Success)) + if (!parseSuccess || (scheme.Success && !host.Success && path.Success)) { throw new ArgumentException("Uri didn't match expected pattern: " + _uri); } diff --git a/src/NzbDrone.Core/Validation/RuleBuilderExtensions.cs b/src/NzbDrone.Core/Validation/RuleBuilderExtensions.cs index 3c577d95c..d58979e7a 100644 --- a/src/NzbDrone.Core/Validation/RuleBuilderExtensions.cs +++ b/src/NzbDrone.Core/Validation/RuleBuilderExtensions.cs @@ -1,11 +1,15 @@ +using System; using System.Text.RegularExpressions; using FluentValidation; using FluentValidation.Validators; +using NzbDrone.Common.Extensions; namespace NzbDrone.Core.Validation { public static class RuleBuilderExtensions { + private static readonly Regex HostRegex = new Regex("^[-_a-z0-9.]+$", RegexOptions.IgnoreCase | RegexOptions.Compiled); + public static IRuleBuilderOptions<T, int> ValidId<T>(this IRuleBuilder<T, int> ruleBuilder) { return ruleBuilder.SetValidator(new GreaterThanValidator(0)); @@ -24,13 +28,15 @@ namespace NzbDrone.Core.Validation public static IRuleBuilderOptions<T, string> ValidHost<T>(this IRuleBuilder<T, string> ruleBuilder) { ruleBuilder.SetValidator(new NotEmptyValidator(null)); - return ruleBuilder.SetValidator(new RegularExpressionValidator("^[-_a-z0-9.]+$", RegexOptions.IgnoreCase)).WithMessage("must be valid Host without http://"); + + return ruleBuilder.Must(x => HostRegex.IsMatch(x) || x.IsValidIpAddress()).WithMessage("must be valid Host without http://"); } public static IRuleBuilderOptions<T, string> ValidRootUrl<T>(this IRuleBuilder<T, string> ruleBuilder) { ruleBuilder.SetValidator(new NotEmptyValidator(null)); - return ruleBuilder.SetValidator(new RegularExpressionValidator("^https?://[-_a-z0-9.]+", RegexOptions.IgnoreCase)).WithMessage("must be valid URL that starts with http(s)://"); + + return ruleBuilder.Must(x => x.IsValidUrl() && x.StartsWith("http", StringComparison.InvariantCultureIgnoreCase)).WithMessage("must be valid URL that starts with http(s)://"); } public static IRuleBuilderOptions<T, string> ValidUrlBase<T>(this IRuleBuilder<T, string> ruleBuilder, string example = "/sonarr") From 1c125733b2100bd841c1eb0cc3ca37618dad5ce0 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 7 Dec 2022 21:16:40 -0600 Subject: [PATCH 0659/2320] New: Improve IPAddress.IsLocal method Co-Authored-By: ta264 <ta264@users.noreply.github.com> --- .../Extensions/IpAddressExtensions.cs | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/NzbDrone.Common/Extensions/IpAddressExtensions.cs b/src/NzbDrone.Common/Extensions/IpAddressExtensions.cs index 4a7cc9a44..7feb431c4 100644 --- a/src/NzbDrone.Common/Extensions/IpAddressExtensions.cs +++ b/src/NzbDrone.Common/Extensions/IpAddressExtensions.cs @@ -7,34 +7,50 @@ namespace NzbDrone.Common.Extensions { public static bool IsLocalAddress(this IPAddress ipAddress) { - if (ipAddress.IsIPv6LinkLocal) + // Map back to IPv4 if mapped to IPv6, for example "::ffff:1.2.3.4" to "1.2.3.4". + if (ipAddress.IsIPv4MappedToIPv6) { - return true; + ipAddress = ipAddress.MapToIPv4(); } + // Checks loopback ranges for both IPv4 and IPv6. if (IPAddress.IsLoopback(ipAddress)) { return true; } + // IPv4 if (ipAddress.AddressFamily == AddressFamily.InterNetwork) { - byte[] bytes = ipAddress.GetAddressBytes(); - switch (bytes[0]) - { - case 10: - case 127: - return true; - case 172: - return bytes[1] < 32 && bytes[1] >= 16; - case 192: - return bytes[1] == 168; - default: - return false; - } + return IsLocalIPv4(ipAddress.GetAddressBytes()); + } + + // IPv6 + if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6) + { + return ipAddress.IsIPv6LinkLocal || + ipAddress.IsIPv6UniqueLocal || + ipAddress.IsIPv6SiteLocal; } return false; } + + private static bool IsLocalIPv4(byte[] ipv4Bytes) + { + // Link local (no IP assigned by DHCP): 169.254.0.0 to 169.254.255.255 (169.254.0.0/16) + bool IsLinkLocal() => ipv4Bytes[0] == 169 && ipv4Bytes[1] == 254; + + // Class A private range: 10.0.0.0 – 10.255.255.255 (10.0.0.0/8) + bool IsClassA() => ipv4Bytes[0] == 10; + + // Class B private range: 172.16.0.0 – 172.31.255.255 (172.16.0.0/12) + bool IsClassB() => ipv4Bytes[0] == 172 && ipv4Bytes[1] >= 16 && ipv4Bytes[1] <= 31; + + // Class C private range: 192.168.0.0 – 192.168.255.255 (192.168.0.0/16) + bool IsClassC() => ipv4Bytes[0] == 192 && ipv4Bytes[1] == 168; + + return IsLinkLocal() || IsClassA() || IsClassC() || IsClassB(); + } } } From ffb3f83324bbc762d92d8dff2a377283bfc08f77 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 7 Dec 2022 21:18:17 -0600 Subject: [PATCH 0660/2320] Simplify X-Forwarded-For handling This happens in asp.net middleware now Co-Authored-By: ta264 <ta264@users.noreply.github.com> --- .../Extensions/RequestExtensions.cs | 34 +------------------ 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/src/Prowlarr.Http/Extensions/RequestExtensions.cs b/src/Prowlarr.Http/Extensions/RequestExtensions.cs index f620f9be0..e46cfd7fe 100644 --- a/src/Prowlarr.Http/Extensions/RequestExtensions.cs +++ b/src/Prowlarr.Http/Extensions/RequestExtensions.cs @@ -126,39 +126,7 @@ namespace Prowlarr.Http.Extensions remoteIP = remoteIP.MapToIPv4(); } - var remoteAddress = remoteIP.ToString(); - - // Only check if forwarded by a local network reverse proxy - if (remoteIP.IsLocalAddress()) - { - var realIPHeader = request.Headers["X-Real-IP"]; - if (realIPHeader.Any()) - { - return realIPHeader.First().ToString(); - } - - var forwardedForHeader = request.Headers["X-Forwarded-For"]; - if (forwardedForHeader.Any()) - { - // Get the first address that was forwarded by a local IP to prevent remote clients faking another proxy - foreach (var forwardedForAddress in forwardedForHeader.SelectMany(v => v.Split(',')).Select(v => v.Trim()).Reverse()) - { - if (!IPAddress.TryParse(forwardedForAddress, out remoteIP)) - { - return remoteAddress; - } - - if (!remoteIP.IsLocalAddress()) - { - return forwardedForAddress; - } - - remoteAddress = forwardedForAddress; - } - } - } - - return remoteAddress; + return remoteIP.ToString(); } public static string GetHostName(this HttpRequest request) From 5d2fefde8f1ab044e7834dd8bcc536036364e9e8 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Wed, 30 Nov 2022 22:09:18 -0600 Subject: [PATCH 0661/2320] Fixed: Correct Attribute compare for Id validation --- src/Prowlarr.Http/REST/RestController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Prowlarr.Http/REST/RestController.cs b/src/Prowlarr.Http/REST/RestController.cs index 7992f6f6f..30f19110a 100644 --- a/src/Prowlarr.Http/REST/RestController.cs +++ b/src/Prowlarr.Http/REST/RestController.cs @@ -62,7 +62,7 @@ namespace Prowlarr.Http.REST } var attributes = descriptor.MethodInfo.CustomAttributes; - if (attributes.Any(x => VALIDATE_ID_ATTRIBUTES.Contains(x.GetType())) && !skipValidate) + if (attributes.Any(x => VALIDATE_ID_ATTRIBUTES.Contains(x.AttributeType)) && !skipValidate) { if (context.ActionArguments.TryGetValue("id", out var idObj)) { From df13537e29e55681c18c7c2e7e82dc1460b18493 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 8 Dec 2022 17:48:33 -0600 Subject: [PATCH 0662/2320] Fixed: Use route Id for PUT requests if not passed in body --- src/Prowlarr.Http/REST/RestController.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Prowlarr.Http/REST/RestController.cs b/src/Prowlarr.Http/REST/RestController.cs index 30f19110a..6475d4b43 100644 --- a/src/Prowlarr.Http/REST/RestController.cs +++ b/src/Prowlarr.Http/REST/RestController.cs @@ -57,6 +57,12 @@ namespace Prowlarr.Http.REST foreach (var resource in resourceArgs) { + // Map route Id to body resource if not set in request + if (Request.Method == "PUT" && resource.Id == 0 && context.RouteData.Values.TryGetValue("id", out var routeId)) + { + resource.Id = Convert.ToInt32(routeId); + } + ValidateResource(resource, skipValidate, skipShared); } } From 3ff3452e2d1dea1845f1fd41ae98b74f3f6b02ec Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Thu, 8 Dec 2022 17:50:18 -0600 Subject: [PATCH 0663/2320] Handling for Obsolete API Endpoints --- src/Prowlarr.Http/REST/RestController.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Prowlarr.Http/REST/RestController.cs b/src/Prowlarr.Http/REST/RestController.cs index 6475d4b43..3c2bbd527 100644 --- a/src/Prowlarr.Http/REST/RestController.cs +++ b/src/Prowlarr.Http/REST/RestController.cs @@ -6,6 +6,8 @@ using FluentValidation.Results; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Filters; +using NLog; +using NzbDrone.Common.Instrumentation; using NzbDrone.Core.Datastore; using NzbDrone.Http.REST.Attributes; using Prowlarr.Http.Validation; @@ -16,7 +18,9 @@ namespace Prowlarr.Http.REST where TResource : RestResource, new() { private static readonly List<Type> VALIDATE_ID_ATTRIBUTES = new List<Type> { typeof(RestPutByIdAttribute), typeof(RestDeleteByIdAttribute) }; + private static readonly Type DEPRECATED_ATTRIBUTE = typeof(ObsoleteAttribute); + private readonly Logger _logger; protected ResourceValidator<TResource> PostValidator { get; private set; } protected ResourceValidator<TResource> PutValidator { get; private set; } protected ResourceValidator<TResource> SharedValidator { get; private set; } @@ -31,6 +35,8 @@ namespace Prowlarr.Http.REST protected RestController() { + _logger = NzbDroneLogger.GetLogger(this); + PostValidator = new ResourceValidator<TResource>(); PutValidator = new ResourceValidator<TResource>(); SharedValidator = new ResourceValidator<TResource>(); @@ -76,6 +82,13 @@ namespace Prowlarr.Http.REST } } + var controllerAttributes = descriptor.ControllerTypeInfo.CustomAttributes; + if (controllerAttributes.Any(x => x.AttributeType == DEPRECATED_ATTRIBUTE) || attributes.Any(x => x.AttributeType == DEPRECATED_ATTRIBUTE)) + { + _logger.Warn("API call made to deprecated endpoint from {0}", Request.Headers.UserAgent.ToString()); + Response.Headers.Add("Deprecation", "true"); + } + base.OnActionExecuting(context); } From b371f2d9136470db9a44be033567c9947645cac0 Mon Sep 17 00:00:00 2001 From: Erik Persson <erikp9@kth.se> Date: Tue, 6 Dec 2022 22:15:46 +0100 Subject: [PATCH 0664/2320] New: Added setting to not include animebytes synonyms --- .../Indexers/Definitions/AnimeBytes.cs | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs index 005242e83..a6b12642e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs @@ -228,34 +228,34 @@ namespace NzbDrone.Core.Indexers.Definitions if (syn.StringArray != null) { - if (syn.StringArray.Count >= 1) + if (_settings.AddJapaneseTitle && syn.StringArray.Count >= 1) { synonyms.Add(syn.StringArray[0]); } - if (syn.StringArray.Count >= 2) + if (_settings.AddRomajiTitle && syn.StringArray.Count >= 2) { synonyms.Add(syn.StringArray[1]); } - if (syn.StringArray.Count == 3) + if (_settings.AddAlternativeTitle && syn.StringArray.Count == 3) { synonyms.AddRange(syn.StringArray[2].Split(',').Select(t => t.Trim())); } } else { - if (syn.StringMap.ContainsKey("0")) + if (_settings.AddJapaneseTitle && syn.StringMap.ContainsKey("0")) { synonyms.Add(syn.StringMap["0"]); } - if (syn.StringMap.ContainsKey("1")) + if (_settings.AddRomajiTitle && syn.StringMap.ContainsKey("1")) { synonyms.Add(syn.StringMap["1"]); } - if (syn.StringMap.ContainsKey("2")) + if (_settings.AddAlternativeTitle && syn.StringMap.ContainsKey("2")) { synonyms.AddRange(syn.StringMap["2"].Split(',').Select(t => t.Trim())); } @@ -543,6 +543,9 @@ namespace NzbDrone.Core.Indexers.Definitions Username = ""; EnableSonarrCompatibility = true; UseFilenameForSingleEpisodes = false; + AddJapaneseTitle = true; + AddRomajiTitle = true; + AddAlternativeTitle = true; } [FieldDefinition(2, Label = "Passkey", HelpText = "Site Passkey", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] @@ -557,6 +560,15 @@ namespace NzbDrone.Core.Indexers.Definitions [FieldDefinition(5, Label = "Use Filenames for Single Episodes", Type = FieldType.Checkbox, HelpText = "Makes Prowlarr replace AnimeBytes release names with the actual filename, this currently only works for single episode releases")] public bool UseFilenameForSingleEpisodes { get; set; } + [FieldDefinition(6, Label = "Add Japanese title as a synonym", Type = FieldType.Checkbox, HelpText = "Makes Prowlarr add Japanese titles as synonyms, i.e kanji/hiragana/katakana.")] + public bool AddJapaneseTitle { get; set; } + + [FieldDefinition(7, Label = "Add Romaji title as a synonym", Type = FieldType.Checkbox, HelpText = "Makes Prowlarr add Romaji title as a synonym, i.e \"Shingeki no Kyojin\" with Attack on Titan")] + public bool AddRomajiTitle { get; set; } + + [FieldDefinition(8, Label = "Add alternative title as a synonym", Type = FieldType.Checkbox, HelpText = "Makes Prowlarr add alternative title as a synonym, i.e \"AoT\" with Attack on Titan, but also \"Attack on Titan Season 4\" Instead of \"Attack on Titan: The Final Season\"")] + public bool AddAlternativeTitle { get; set; } + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); From 470779ead2767647fe874b629401dd8f12ee41fa Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 11 Dec 2022 12:46:58 -0600 Subject: [PATCH 0665/2320] Bump version to 0.4.11 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1664dbd8e..88827d156 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: testsFolder: './_tests' yarnCacheFolder: $(Pipeline.Workspace)/.yarn nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages - majorVersion: '0.4.10' + majorVersion: '0.4.11' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From 6c97f1b6eec3183301410a57be5f1980b3551e9d Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sun, 11 Dec 2022 00:09:53 +0000 Subject: [PATCH 0666/2320] Translated using Weblate (Italian) Currently translated at 100.0% (464 of 464 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (464 of 464 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (464 of 464 strings) Translated using Weblate (German) Currently translated at 100.0% (464 of 464 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (464 of 464 strings) Translated using Weblate (Dutch) Currently translated at 89.6% (416 of 464 strings) Translated using Weblate (Dutch) Currently translated at 89.6% (416 of 464 strings) Co-authored-by: Csaba <csab0825@gmail.com> Co-authored-by: Mipiaceanutella <remix-polity-0l@icloud.com> Co-authored-by: Oskari Lavinto <olavinto@protonmail.com> Co-authored-by: Robin Flikkema <robin@robinflikkema.nl> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: kamperzoid <nick@kamper.be> Co-authored-by: reloxx <reloxx@interia.pl> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/it/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/de.json | 4 ++-- src/NzbDrone.Core/Localization/Core/fi.json | 14 +++++++------- src/NzbDrone.Core/Localization/Core/hu.json | 4 ++-- src/NzbDrone.Core/Localization/Core/it.json | 15 ++++++++++----- src/NzbDrone.Core/Localization/Core/nl.json | 8 +++++--- 5 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/de.json b/src/NzbDrone.Core/Localization/Core/de.json index bff789674..9f5e58d5c 100644 --- a/src/NzbDrone.Core/Localization/Core/de.json +++ b/src/NzbDrone.Core/Localization/Core/de.json @@ -141,7 +141,7 @@ "BackupRetentionHelpText": "Automatische Backups, die älter als die Aufbewahrungsfrist sind, werden automatisch gelöscht", "Backups": "Backups", "BindAddress": "Adresse binden", - "BindAddressHelpText": "Gültige IPv4 Adresse oder \"*\" für alle Netzwerke", + "BindAddressHelpText": "Gültige IP-Adresse, \"localhost\" oder \"*\" für alle Netzwerke", "Branch": "Git-Branch", "BypassProxyForLocalAddresses": "Proxy für lokale Adressen umgehen", "CertificateValidation": "Zertifikat Validierung", @@ -435,7 +435,7 @@ "InstanceName": "Instanzname", "InstanceNameHelpText": "Instanzname im Browser-Tab und für Syslog-Anwendungsname", "SyncProfiles": "Sync-Profile", - "ThemeHelpText": "Prowlarr UI Theme ändern, inspiriert von {0}", + "ThemeHelpText": "Ändere das UI-Theme der Anwendung. Das 'Auto'-Theme verwendet dein Betriebssystem-Theme, um den hellen oder dunklen Modus einzustellen. Inspiriert von {0}", "Duration": "Dauer", "EditSyncProfile": "Synchronisationsprofil bearbeiten", "ElapsedTime": "Vergangene Zeit", diff --git a/src/NzbDrone.Core/Localization/Core/fi.json b/src/NzbDrone.Core/Localization/Core/fi.json index c630bd1dc..d7eb2c195 100644 --- a/src/NzbDrone.Core/Localization/Core/fi.json +++ b/src/NzbDrone.Core/Localization/Core/fi.json @@ -74,7 +74,7 @@ "ApplyTags": "Tunnistetoimenpide", "Authentication": "Todennus", "AuthenticationMethodHelpText": "Vaadi käyttäjätunnus ja salasana.", - "BindAddressHelpText": "Toimiva IPv4-osoite tai '*' (tähti) kaikille yhteyksille.", + "BindAddressHelpText": "Toimiva IP-osoite, localhost tai '*' (tähti) kaikille yhteyksille.", "Close": "Sulje", "DeleteNotification": "Poista kytkentä", "Docker": "Docker", @@ -100,7 +100,7 @@ "Protocol": "Protokolla", "ProxyCheckBadRequestMessage": "Välityspalvelintesti epäonnistui. Tilakoodi: {0}", "ProxyCheckFailedToTestMessage": "Välityspalvelintesti epäonnistui: {0}", - "ProxyCheckResolveIpMessage": "Määritetyn välityspalvelimen '{0}' IP-osoitteen selvitys epäonnistui", + "ProxyCheckResolveIpMessage": "Määritetyn välityspalvelimen '{0}' IP-osoitteen selvitys epäonnistui.", "ProxyPasswordHelpText": "Käyttäjätunnus ja salasana tulee syöttää vain tarvittaessa. Muussa tapauksessa jätä kentät tyhjiksi.", "ProxyType": "Välityspalvelimen tyyppi", "ProxyUsernameHelpText": "Käyttäjätunnus ja salasana tulee syöttää vain tarvittaessa. Muussa tapauksessa jätä kentät tyhjiksi.", @@ -121,7 +121,7 @@ "Security": "Suojaus", "SuggestTranslationChange": "Ehdota käännösmuutosta", "System": "Järjestelmä", - "SystemTimeCheckMessage": "Järjestelmän aika on heittä yli vuorokauden verran. Ajoitetut tehtävät eivät luultavasti toimi oikein ennen ajan korjausta.", + "SystemTimeCheckMessage": "Järjestelmän aika on pielessä yli vuorokauden. Ajoitetut tehtävät eivät luultavasti toimi oikein ennen sen korjausta.", "TagCannotBeDeletedWhileInUse": "Tunnistetta ei voi poistaa, koska se on käytössä", "TagIsNotUsedAndCanBeDeleted": "Tunnistetta ei ole määritetty millekään kohteelle, joten sen voi poistaa.", "TagsSettingsSummary": "Täältä näet kaikki tunnisteet käyttökohteineen ja voit poistaa sellaiset tunnisteet, joita ei ole määritetty millekään kohteelle.", @@ -333,7 +333,7 @@ "ProwlarrSupportsAnyIndexer": "Prowlarr tukee Newznab- ja Torznab-yhteensopivien tietolähteiden ohella myös useita muita lähteitä vaihtoehdoilla \"Yleinen Newznab\" (Usenetille) ja 'Yleinen Torznab' (torrenteille).", "SettingsIndexerLogging": "Tehostettu tietolähteiden valvonta", "AddIndexerProxy": "Lisää tiedonhaun välityspalvelin", - "UISettingsSummary": "Päiväyksen ja kielen sekä heikentyneen värinäön asetukset", + "UISettingsSummary": "Kalenterin, päiväyksen ja kellonajan sekä kielen ja heikentyneelle värinäölle sopivan tilan asetukset.", "SettingsIndexerLoggingHelpText": "Kirjaa tarkempia tietoja tietolähteiden toiminnasta, mukaanlukien vastaukset", "IndexerTagsHelpText": "Tunnisteiden avulla voit määrittää tiedonhaun välityspalvelimet, mihin sovelluksiin tietolähteet synkronoidaan tai yksikertaisesti järjestellä tietolähteitäsi.", "UnableToLoadAppProfiles": "Sovellusprofiilien lataus epäonnistui", @@ -449,7 +449,7 @@ "EditSyncProfile": "Muokkaa synkronointiprofiilia", "InstanceName": "Instanssin nimi", "InstanceNameHelpText": "Instanssin nimi välilehdellä ja järjestelmälokissa", - "ThemeHelpText": "Vaihda Prowlarin käyttöliittymän teemaa, jota on inspiroinut {0}", + "ThemeHelpText": "Vaihda sovelluksen käyttöliittymän ulkoasua. \"Automaattinen\" vaihtaa vaalean ja tumman tilan käyttöjärjestelmäsi teemaa vastaavaksi. Innoittanut {0}.", "Duration": "Kesto", "ElapsedTime": "Kulunut aika", "EnabledRedirected": "Kulunut, uudelleenohjattu", @@ -461,6 +461,6 @@ "Parameters": "Parametrit", "Queued": "Jonossa", "Started": "Alkoi", - "ApplicationLongTermStatusCheckAllClientMessage": "Mikään tietolähde ei ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi.", - "ApplicationLongTermStatusCheckSingleClientMessage": "Tietolähteet eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi: {0}" + "ApplicationLongTermStatusCheckAllClientMessage": "Sovellukset eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi.", + "ApplicationLongTermStatusCheckSingleClientMessage": "Sovellukset eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi: {0}" } diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index ad3c70d77..fc175aaf4 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -54,7 +54,7 @@ "BranchUpdateMechanism": "A külső frissítési mechanizmus által használt ágazat", "BranchUpdate": "Ágazattípus a Prowlarr frissítéseihez", "Branch": "Ágazat", - "BindAddressHelpText": "Érvényes IP4-cím, vagy „*” minden interfészhez", + "BindAddressHelpText": "Érvényes IP-cím, localhost, vagy „*” minden interfészhez", "BindAddress": "Kapcsolási Cím", "BeforeUpdate": "Alkalmazásfrissítés előtt", "Backups": "Biztonsági Mentés", @@ -449,7 +449,7 @@ "MinimumSeedersHelpText": "Az alkalmazás által megkövetelt minimális Seeder az indexer számára", "InstanceName": "Példány Neve", "InstanceNameHelpText": "Példánynév a böngésző lapon és a syslog alkalmazás neve", - "ThemeHelpText": "Prowlarr felhasználói felület témájának módosítása, ihlette {0}", + "ThemeHelpText": "Változtasd meg az alkalmazás felhasználói felület témáját. Az „Auto” téma az operációs rendszer témáját használja a Világos vagy Sötét mód beállításához. Ihlette: {0}", "Duration": "Időtartam", "ElapsedTime": "Eltelt idő", "EnabledRedirected": "Engedélyezve, átirányítva", diff --git a/src/NzbDrone.Core/Localization/Core/it.json b/src/NzbDrone.Core/Localization/Core/it.json index 6f2f29758..3d3c48870 100644 --- a/src/NzbDrone.Core/Localization/Core/it.json +++ b/src/NzbDrone.Core/Localization/Core/it.json @@ -93,7 +93,7 @@ "Cancel": "Annulla", "BypassProxyForLocalAddresses": "Evita il Proxy per gli Indirizzi Locali", "Branch": "Ramo", - "BindAddressHelpText": "Indirizzo IPv4 valido o '*' per tutte le interfacce", + "BindAddressHelpText": "Indirizzo IP valido, localhost o '*' per tutte le interfacce", "BindAddress": "Indirizzo di Bind", "Backups": "I Backup", "BackupRetentionHelpText": "I backup automatici più vecchi del periodo di conservazione verranno eliminati automaticamente", @@ -153,7 +153,7 @@ "BranchUpdateMechanism": "Ramo utilizzato dal sistema di aggiornamento esterno", "BranchUpdate": "Ramo da usare per aggiornare Prowlarr", "ApplyTagsHelpTexts2": "Aggiungi: Aggiunge le etichette alla lista esistente di etichette", - "ApplyTagsHelpTexts1": "Come applicare etichette agli Indicizzatori selezionati", + "ApplyTagsHelpTexts1": "Come applicare etichette agli indicizzatori selezionati", "AddingTag": "Aggiungi etichetta", "Password": "Password", "OnHealthIssueHelpText": "Quando c'è un problema", @@ -441,7 +441,7 @@ "SettingsSqlLoggingHelpText": "Scrivi a log tutte le query SQL di Prowlarr", "SyncLevelAddRemove": "Solo aggiunte e rimozioni: Quando gli indicizzatori vengono aggiunti o rimossi da Prowlarr, verrà aggiornata questa applicazione remota.", "SyncLevelFull": "Sincronizzazione completa: Manterrà gli indicizzatori di questa app completamente sincronizzati. Le modifiche apportate agli indicizzatori in Prowlarr sono poi sincronizzate con questa applicazione. Qualsiasi cambiamento fatto agli indicizzatori da remoto all'interno di questa applicazione sarà sovrascritto da Prowlarr alla prossima sincronizzazione.", - "MinimumSeedersHelpText": "Seeder minimi richiesti dall'Applicazione per far si che l'indicizzatore li prenda", + "MinimumSeedersHelpText": "Seeder minimi richiesti dall'Applicazione per far sì che l'indicizzatore li prenda", "SyncProfile": "Profilo Sincronizzazione", "SyncProfiles": "Profili Sincronizzazione", "AddSyncProfile": "Aggiungi Profilo di Sincronizzazione", @@ -449,7 +449,7 @@ "MinimumSeeders": "Seeder Minimi", "InstanceName": "Nome Istanza", "InstanceNameHelpText": "Nome dell'istanza nella scheda e per il nome dell'applicazione Syslog", - "ThemeHelpText": "Cambia il tema dell'interfaccia di Prowlarr, ispirato da {0}", + "ThemeHelpText": "Cambia il Tema dell'interfaccia dell’applicazione, il Tema 'Auto' userà il suo Tema di Sistema per impostare la modalità Chiara o Scura. Ispirato da {0}", "LastDuration": "Ultima Durata", "LastExecution": "Ultima esecuzione", "Queued": "Messo in coda", @@ -457,5 +457,10 @@ "ApplicationLongTermStatusCheckSingleClientMessage": "Alcuni Indicizzatori non sono disponibili da più di 6 ore a causa di errori: {0}", "Duration": "Durata", "Ended": "Finito", - "NextExecution": "Prossima esecuzione" + "NextExecution": "Prossima esecuzione", + "GrabTitle": "Ottieni il Titolo", + "Parameters": "Parametri", + "ElapsedTime": "Tempo trascorso", + "EnabledRedirected": "Abilitato, Reindirizzato", + "Started": "Iniziato" } diff --git a/src/NzbDrone.Core/Localization/Core/nl.json b/src/NzbDrone.Core/Localization/Core/nl.json index 1bcb6bad9..bb9c4a586 100644 --- a/src/NzbDrone.Core/Localization/Core/nl.json +++ b/src/NzbDrone.Core/Localization/Core/nl.json @@ -299,11 +299,11 @@ "MovieIndexScrollBottom": "Film Index: Scroll naar onder", "IndexerLongTermStatusCheckSingleClientMessage": "Indexeerders zijn niet beschikbaar vanwege storingen gedurende meer dan 6 uur: {0}", "IndexerLongTermStatusCheckAllClientMessage": "Alle indexeerders zijn niet beschikbaar vanwege storingen gedurende meer dan 6 uur", - "ClearHistoryMessageText": "Weet je zeker dat je alle geschiedenis van Prowlarr wilt verwijderen", + "ClearHistoryMessageText": "Weet je zeker dat je alle geschiedenis van Prowlarr wilt verwijderen?", "ClearHistory": "Geschiedenis verwijderen", "ApplicationStatusCheckSingleClientMessage": "Applicaties onbeschikbaar door fouten", "ApplicationStatusCheckAllClientMessage": "Alle applicaties onbeschikbaar door fouten", - "AllIndexersHiddenDueToFilter": "Alle indexeerders zijn verborgen door actieve filter", + "AllIndexersHiddenDueToFilter": "Alle indexeerders zijn verborgen door actieve filter.", "AddToDownloadClient": "Release toevoegen aan download client", "AddNewIndexer": "Voeg nieuwe Indexeerder Toe", "AddedToDownloadClient": "Release toegevoegd aan client", @@ -417,5 +417,7 @@ "ApplicationLongTermStatusCheckSingleClientMessage": "Indexeerders zijn niet beschikbaar vanwege storingen gedurende meer dan 6 uur: {0}", "LastDuration": "Laatste Looptijd", "LastExecution": "Laatste Uitvoering", - "Queued": "Afwachtend" + "Queued": "Afwachtend", + "Categories": "Categorieën", + "AddSyncProfile": "Synchronisatieprofiel toevoegen" } From a110412665b6154cd84d576c65d0dad48dfdfed4 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 17 Dec 2022 10:27:14 -0600 Subject: [PATCH 0667/2320] Fixed: Stats failing of all indexer events are failures Fixes #1231 --- .../IndexerStatisticsServiceFixture.cs | 55 +++++++++++++++++++ .../IndexerStats/IndexerStatisticsService.cs | 7 ++- 2 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 src/NzbDrone.Core.Test/IndexerStatsTests/IndexerStatisticsServiceFixture.cs diff --git a/src/NzbDrone.Core.Test/IndexerStatsTests/IndexerStatisticsServiceFixture.cs b/src/NzbDrone.Core.Test/IndexerStatsTests/IndexerStatisticsServiceFixture.cs new file mode 100644 index 000000000..c0ec172b4 --- /dev/null +++ b/src/NzbDrone.Core.Test/IndexerStatsTests/IndexerStatisticsServiceFixture.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using FizzWare.NBuilder; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Core.History; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.IndexerStats; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.IndexerStatsTests +{ + public class IndexerStatisticsServiceFixture : CoreTest<IndexerStatisticsService> + { + private IndexerDefinition _indexer; + + [SetUp] + public void Setup() + { + _indexer = Builder<IndexerDefinition>.CreateNew().With(x => x.Id = 5).Build(); + + Mocker.GetMock<IIndexerFactory>() + .Setup(o => o.All()) + .Returns(new List<IndexerDefinition> { _indexer }); + } + + [Test] + public void should_pull_stats_if_all_events_are_failures() + { + var history = new List<History.History> + { + new History.History + { + Date = DateTime.UtcNow.AddHours(-1), + EventType = HistoryEventType.IndexerRss, + Successful = false, + Id = 8, + IndexerId = 5, + Data = new Dictionary<string, string> { { "source", "prowlarr" } } + } + }; + + Mocker.GetMock<IHistoryService>() + .Setup(o => o.Between(It.IsAny<DateTime>(), It.IsAny<DateTime>())) + .Returns<DateTime, DateTime>((s, f) => history); + + var statistics = Subject.IndexerStatistics(DateTime.UtcNow.AddMonths(-1), DateTime.UtcNow); + + statistics.IndexerStatistics.Count.Should().Be(1); + statistics.IndexerStatistics.First().AverageResponseTime.Should().Be(0); + } + } +} diff --git a/src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs b/src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs index 02bbbb143..42cd79cad 100644 --- a/src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs +++ b/src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs @@ -56,9 +56,10 @@ namespace NzbDrone.Core.IndexerStats .ToArray(); int temp = 0; - indexerStats.AverageResponseTime = (int)sortedEvents.Where(h => int.TryParse(h.Data.GetValueOrDefault("elapsedTime"), out temp)) - .Select(h => temp) - .Average(); + var elapsedTimeEvents = sortedEvents.Where(h => int.TryParse(h.Data.GetValueOrDefault("elapsedTime"), out temp)) + .Select(h => temp); + + indexerStats.AverageResponseTime = elapsedTimeEvents.Count() > 0 ? (int)elapsedTimeEvents.Average() : 0; foreach (var historyEvent in sortedEvents) { From 0d918a0aa9329edda7d1c0fa8e41604843f570a0 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Fri, 9 Dec 2022 19:03:13 -0600 Subject: [PATCH 0668/2320] New: Define multiple mapped categories for Download Clients Fixes #170 --- .../src/Components/Form/FormInputGroup.js | 4 + .../NewznabCategorySelectInputConnector.js | 2 +- frontend/src/Helpers/Props/inputTypes.js | 2 + .../Categories/AddCategoryModal.js | 27 +++ .../Categories/AddCategoryModalConnector.js | 50 +++++ .../Categories/AddCategoryModalContent.css | 5 + .../Categories/AddCategoryModalContent.js | 111 ++++++++++++ .../AddCategoryModalContentConnector.js | 78 ++++++++ .../DownloadClients/Categories/Category.css | 32 ++++ .../DownloadClients/Categories/Category.js | 111 ++++++++++++ .../EditDownloadClientModalContent.js | 76 +++++++- ...EditDownloadClientModalContentConnector.js | 28 ++- .../Settings/downloadClientCategories.js | 171 ++++++++++++++++++ .../Store/Actions/Settings/downloadClients.js | 29 ++- frontend/src/Store/Actions/settingsActions.js | 5 + .../023_download_client_categories.cs | 15 ++ src/NzbDrone.Core/Datastore/TableMapping.cs | 4 +- .../Download/Clients/Aria2/Aria2.cs | 2 + .../Clients/Blackhole/TorrentBlackhole.cs | 2 + .../Clients/Blackhole/UsenetBlackhole.cs | 1 + .../Download/Clients/Deluge/Deluge.cs | 49 +++-- .../Download/Clients/Deluge/DelugeProxy.cs | 6 +- .../Download/Clients/Deluge/DelugeSettings.cs | 2 +- .../DownloadStationSettings.cs | 8 +- .../DownloadStation/TorrentDownloadStation.cs | 7 +- .../DownloadStation/UsenetDownloadStation.cs | 7 +- .../Download/Clients/Flood/Flood.cs | 12 +- .../Download/Clients/Hadouken/Hadouken.cs | 5 +- .../Clients/Hadouken/HadoukenProxy.cs | 14 +- .../Clients/Hadouken/HadoukenSettings.cs | 2 +- .../Download/Clients/NzbVortex/NzbVortex.cs | 22 ++- .../Clients/NzbVortex/NzbVortexProxy.cs | 6 +- .../Clients/NzbVortex/NzbVortexSettings.cs | 2 +- .../Download/Clients/Nzbget/Nzbget.cs | 17 +- .../Download/Clients/Nzbget/NzbgetSettings.cs | 2 +- .../Download/Clients/Pneumatic/Pneumatic.cs | 1 + .../Clients/QBittorrent/QBittorrent.cs | 37 ++-- .../QBittorrent/QBittorrentProxySelector.cs | 4 +- .../Clients/QBittorrent/QBittorrentProxyV1.cs | 12 +- .../Clients/QBittorrent/QBittorrentProxyV2.cs | 12 +- .../QBittorrent/QBittorrentSettings.cs | 2 +- .../Download/Clients/Sabnzbd/Sabnzbd.cs | 31 ++-- .../Clients/Sabnzbd/SabnzbdSettings.cs | 2 +- .../Clients/Transmission/Transmission.cs | 1 + .../Transmission/TransmissionSettings.cs | 2 +- .../Download/Clients/Vuze/Vuze.cs | 1 + .../Download/Clients/rTorrent/RTorrent.cs | 5 +- .../Clients/rTorrent/RTorrentSettings.cs | 2 +- .../Download/Clients/uTorrent/UTorrent.cs | 45 +---- .../Clients/uTorrent/UTorrentSettings.cs | 2 +- .../Download/DownloadClientBase.cs | 60 ++++++ .../Download/DownloadClientCategory.cs | 14 ++ .../Download/DownloadClientDefinition.cs | 10 +- .../Download/DownloadClientFactory.cs | 1 + src/NzbDrone.Core/Download/IDownloadClient.cs | 2 + src/NzbDrone.Core/Localization/Core/en.json | 4 + .../DownloadClient/DownloadClientResource.cs | 6 + 57 files changed, 1020 insertions(+), 152 deletions(-) create mode 100644 frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModal.js create mode 100644 frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModalConnector.js create mode 100644 frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModalContent.css create mode 100644 frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModalContent.js create mode 100644 frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModalContentConnector.js create mode 100644 frontend/src/Settings/DownloadClients/DownloadClients/Categories/Category.css create mode 100644 frontend/src/Settings/DownloadClients/DownloadClients/Categories/Category.js create mode 100644 frontend/src/Store/Actions/Settings/downloadClientCategories.js create mode 100644 src/NzbDrone.Core/Datastore/Migration/023_download_client_categories.cs create mode 100644 src/NzbDrone.Core/Download/DownloadClientCategory.cs diff --git a/frontend/src/Components/Form/FormInputGroup.js b/frontend/src/Components/Form/FormInputGroup.js index 7bc031c9e..8e39cd36a 100644 --- a/frontend/src/Components/Form/FormInputGroup.js +++ b/frontend/src/Components/Form/FormInputGroup.js @@ -16,6 +16,7 @@ import FormInputHelpText from './FormInputHelpText'; import IndexerFlagsSelectInputConnector from './IndexerFlagsSelectInputConnector'; import InfoInput from './InfoInput'; import KeyValueListInput from './KeyValueListInput'; +import NewznabCategorySelectInputConnector from './NewznabCategorySelectInputConnector'; import NumberInput from './NumberInput'; import OAuthInputConnector from './OAuthInputConnector'; import PasswordInput from './PasswordInput'; @@ -68,6 +69,9 @@ function getComponent(type) { case inputTypes.PATH: return PathInputConnector; + case inputTypes.CATEGORY_SELECT: + return NewznabCategorySelectInputConnector; + case inputTypes.INDEXER_FLAGS_SELECT: return IndexerFlagsSelectInputConnector; diff --git a/frontend/src/Components/Form/NewznabCategorySelectInputConnector.js b/frontend/src/Components/Form/NewznabCategorySelectInputConnector.js index d9cd3d178..e63e2cae7 100644 --- a/frontend/src/Components/Form/NewznabCategorySelectInputConnector.js +++ b/frontend/src/Components/Form/NewznabCategorySelectInputConnector.js @@ -31,7 +31,7 @@ function createMapStateToProps() { }); return { - value, + value: value || [], values }; } diff --git a/frontend/src/Helpers/Props/inputTypes.js b/frontend/src/Helpers/Props/inputTypes.js index 4af772636..7a11bb0c7 100644 --- a/frontend/src/Helpers/Props/inputTypes.js +++ b/frontend/src/Helpers/Props/inputTypes.js @@ -8,6 +8,7 @@ export const DEVICE = 'device'; export const KEY_VALUE_LIST = 'keyValueList'; export const INFO = 'info'; export const MOVIE_MONITORED_SELECT = 'movieMonitoredSelect'; +export const CATEGORY_SELECT = 'newznabCategorySelect'; export const NUMBER = 'number'; export const OAUTH = 'oauth'; export const PASSWORD = 'password'; @@ -32,6 +33,7 @@ export const all = [ KEY_VALUE_LIST, INFO, MOVIE_MONITORED_SELECT, + CATEGORY_SELECT, NUMBER, OAUTH, PASSWORD, diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModal.js b/frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModal.js new file mode 100644 index 000000000..798077c4f --- /dev/null +++ b/frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModal.js @@ -0,0 +1,27 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import Modal from 'Components/Modal/Modal'; +import { sizes } from 'Helpers/Props'; +import AddCategoryModalContentConnector from './AddCategoryModalContentConnector'; + +function AddCategoryModal({ isOpen, onModalClose, ...otherProps }) { + return ( + <Modal + size={sizes.MEDIUM} + isOpen={isOpen} + onModalClose={onModalClose} + > + <AddCategoryModalContentConnector + {...otherProps} + onModalClose={onModalClose} + /> + </Modal> + ); +} + +AddCategoryModal.propTypes = { + isOpen: PropTypes.bool.isRequired, + onModalClose: PropTypes.func.isRequired +}; + +export default AddCategoryModal; diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModalConnector.js b/frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModalConnector.js new file mode 100644 index 000000000..069dc0312 --- /dev/null +++ b/frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModalConnector.js @@ -0,0 +1,50 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { clearPendingChanges } from 'Store/Actions/baseActions'; +import AddCategoryModal from './AddCategoryModal'; + +function createMapDispatchToProps(dispatch, props) { + const section = 'settings.downloadClientCategories'; + + return { + dispatchClearPendingChanges() { + dispatch(clearPendingChanges({ section })); + } + }; +} + +class AddCategoryModalConnector extends Component { + + // + // Listeners + + onModalClose = () => { + this.props.dispatchClearPendingChanges(); + this.props.onModalClose(); + }; + + // + // Render + + render() { + const { + dispatchClearPendingChanges, + ...otherProps + } = this.props; + + return ( + <AddCategoryModal + {...otherProps} + onModalClose={this.onModalClose} + /> + ); + } +} + +AddCategoryModalConnector.propTypes = { + onModalClose: PropTypes.func.isRequired, + dispatchClearPendingChanges: PropTypes.func.isRequired +}; + +export default connect(null, createMapDispatchToProps)(AddCategoryModalConnector); diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModalContent.css b/frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModalContent.css new file mode 100644 index 000000000..a2b6014df --- /dev/null +++ b/frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModalContent.css @@ -0,0 +1,5 @@ +.deleteButton { + composes: button from '~Components/Link/Button.css'; + + margin-right: auto; +} diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModalContent.js b/frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModalContent.js new file mode 100644 index 000000000..71c51849c --- /dev/null +++ b/frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModalContent.js @@ -0,0 +1,111 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import Form from 'Components/Form/Form'; +import FormGroup from 'Components/Form/FormGroup'; +import FormInputGroup from 'Components/Form/FormInputGroup'; +import FormLabel from 'Components/Form/FormLabel'; +import Button from 'Components/Link/Button'; +import SpinnerErrorButton from 'Components/Link/SpinnerErrorButton'; +import ModalBody from 'Components/Modal/ModalBody'; +import ModalContent from 'Components/Modal/ModalContent'; +import ModalFooter from 'Components/Modal/ModalFooter'; +import ModalHeader from 'Components/Modal/ModalHeader'; +import { inputTypes, kinds } from 'Helpers/Props'; +import translate from 'Utilities/String/translate'; +import styles from './AddCategoryModalContent.css'; + +function AddCategoryModalContent(props) { + const { + advancedSettings, + item, + onInputChange, + onFieldChange, + onCancelPress, + onSavePress, + onDeleteSpecificationPress, + ...otherProps + } = props; + + const { + id, + clientCategory, + categories + } = item; + + return ( + <ModalContent onModalClose={onCancelPress}> + <ModalHeader> + {`${id ? 'Edit' : 'Add'} Category`} + </ModalHeader> + + <ModalBody> + <Form + {...otherProps} + > + <FormGroup> + <FormLabel> + {translate('DownloadClientCategory')} + </FormLabel> + + <FormInputGroup + type={inputTypes.TEXT} + name="clientCategory" + {...clientCategory} + onChange={onInputChange} + /> + </FormGroup> + + <FormGroup> + <FormLabel> + {translate('MappedCategories')} + </FormLabel> + + <FormInputGroup + type={inputTypes.CATEGORY_SELECT} + name="categories" + {...categories} + onChange={onInputChange} + /> + </FormGroup> + </Form> + </ModalBody> + <ModalFooter> + { + id && + <Button + className={styles.deleteButton} + kind={kinds.DANGER} + onPress={onDeleteSpecificationPress} + > + {translate('Delete')} + </Button> + } + + <Button + onPress={onCancelPress} + > + {translate('Cancel')} + </Button> + + <SpinnerErrorButton + isSpinning={false} + onPress={onSavePress} + > + {translate('Save')} + </SpinnerErrorButton> + </ModalFooter> + </ModalContent> + ); +} + +AddCategoryModalContent.propTypes = { + advancedSettings: PropTypes.bool.isRequired, + item: PropTypes.object.isRequired, + onInputChange: PropTypes.func.isRequired, + onFieldChange: PropTypes.func.isRequired, + onCancelPress: PropTypes.func.isRequired, + onSavePress: PropTypes.func.isRequired, + onDeleteSpecificationPress: PropTypes.func +}; + +export default AddCategoryModalContent; diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModalContentConnector.js b/frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModalContentConnector.js new file mode 100644 index 000000000..a585e5707 --- /dev/null +++ b/frontend/src/Settings/DownloadClients/DownloadClients/Categories/AddCategoryModalContentConnector.js @@ -0,0 +1,78 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import { clearDownloadClientCategoryPending, saveDownloadClientCategory, setDownloadClientCategoryFieldValue, setDownloadClientCategoryValue } from 'Store/Actions/settingsActions'; +import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector'; +import AddCategoryModalContent from './AddCategoryModalContent'; + +function createMapStateToProps() { + return createSelector( + (state) => state.settings.advancedSettings, + createProviderSettingsSelector('downloadClientCategories'), + (advancedSettings, specification) => { + return { + advancedSettings, + ...specification + }; + } + ); +} + +const mapDispatchToProps = { + setDownloadClientCategoryValue, + setDownloadClientCategoryFieldValue, + saveDownloadClientCategory, + clearDownloadClientCategoryPending +}; + +class AddCategoryModalContentConnector extends Component { + + // + // Listeners + + onInputChange = ({ name, value }) => { + this.props.setDownloadClientCategoryValue({ name, value }); + }; + + onFieldChange = ({ name, value }) => { + this.props.setDownloadClientCategoryFieldValue({ name, value }); + }; + + onCancelPress = () => { + this.props.clearDownloadClientCategoryPending(); + this.props.onModalClose(); + }; + + onSavePress = () => { + this.props.saveDownloadClientCategory({ id: this.props.id }); + this.props.onModalClose(); + }; + + // + // Render + + render() { + return ( + <AddCategoryModalContent + {...this.props} + onCancelPress={this.onCancelPress} + onSavePress={this.onSavePress} + onInputChange={this.onInputChange} + onFieldChange={this.onFieldChange} + /> + ); + } +} + +AddCategoryModalContentConnector.propTypes = { + id: PropTypes.number, + item: PropTypes.object.isRequired, + setDownloadClientCategoryValue: PropTypes.func.isRequired, + setDownloadClientCategoryFieldValue: PropTypes.func.isRequired, + clearDownloadClientCategoryPending: PropTypes.func.isRequired, + saveDownloadClientCategory: PropTypes.func.isRequired, + onModalClose: PropTypes.func.isRequired +}; + +export default connect(createMapStateToProps, mapDispatchToProps)(AddCategoryModalContentConnector); diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/Categories/Category.css b/frontend/src/Settings/DownloadClients/DownloadClients/Categories/Category.css new file mode 100644 index 000000000..52ce0edd4 --- /dev/null +++ b/frontend/src/Settings/DownloadClients/DownloadClients/Categories/Category.css @@ -0,0 +1,32 @@ +.customFormat { + composes: card from '~Components/Card.css'; + + width: 300px; +} + +.nameContainer { + display: flex; + justify-content: space-between; +} + +.name { + @add-mixin truncate; + + margin-bottom: 5px; + font-weight: 300; + font-size: 20px; +} + +.labels { + display: flex; + flex-wrap: wrap; + margin-top: 5px; + pointer-events: all; +} + +.tooltipLabel { + composes: label from '~Components/Label.css'; + + margin: 0; + border: none; +} diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/Categories/Category.js b/frontend/src/Settings/DownloadClients/DownloadClients/Categories/Category.js new file mode 100644 index 000000000..6e0a25a2d --- /dev/null +++ b/frontend/src/Settings/DownloadClients/DownloadClients/Categories/Category.js @@ -0,0 +1,111 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import Card from 'Components/Card'; +import Label from 'Components/Label'; +import ConfirmModal from 'Components/Modal/ConfirmModal'; +import { kinds } from 'Helpers/Props'; +import translate from 'Utilities/String/translate'; +import AddCategoryModalConnector from './AddCategoryModalConnector'; +import styles from './Category.css'; + +class Category extends Component { + + // + // Lifecycle + + constructor(props, context) { + super(props, context); + + this.state = { + isEditSpecificationModalOpen: false, + isDeleteSpecificationModalOpen: false + }; + } + + // + // Listeners + + onEditSpecificationPress = () => { + this.setState({ isEditSpecificationModalOpen: true }); + }; + + onEditSpecificationModalClose = () => { + this.setState({ isEditSpecificationModalOpen: false }); + }; + + onDeleteSpecificationPress = () => { + this.setState({ + isEditSpecificationModalOpen: false, + isDeleteSpecificationModalOpen: true + }); + }; + + onDeleteSpecificationModalClose = () => { + this.setState({ isDeleteSpecificationModalOpen: false }); + }; + + onConfirmDeleteSpecification = () => { + this.props.onConfirmDeleteSpecification(this.props.id); + }; + + // + // Lifecycle + + render() { + const { + id, + clientCategory, + categories + } = this.props; + + return ( + <Card + className={styles.customFormat} + overlayContent={true} + onPress={this.onEditSpecificationPress} + > + <div className={styles.nameContainer}> + <div className={styles.name}> + {clientCategory} + </div> + </div> + + <Label kind={kinds.PRIMARY}> + {`${categories.length} ${categories.length > 1 ? translate('Categories') : translate('Category')}`} + </Label> + + <AddCategoryModalConnector + id={id} + isOpen={this.state.isEditSpecificationModalOpen} + onModalClose={this.onEditSpecificationModalClose} + onDeleteSpecificationPress={this.onDeleteSpecificationPress} + /> + + <ConfirmModal + isOpen={this.state.isDeleteSpecificationModalOpen} + kind={kinds.DANGER} + title={translate('DeleteClientCategory')} + message={ + <div> + <div> + {translate('AreYouSureYouWantToDeleteCategory', [name])} + </div> + </div> + } + confirmLabel={translate('Delete')} + onConfirm={this.onConfirmDeleteSpecification} + onCancel={this.onDeleteSpecificationModalClose} + /> + </Card> + ); + } +} + +Category.propTypes = { + id: PropTypes.number.isRequired, + categories: PropTypes.arrayOf(PropTypes.number).isRequired, + clientCategory: PropTypes.string.isRequired, + onConfirmDeleteSpecification: PropTypes.func.isRequired +}; + +export default Category; diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContent.js b/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContent.js index 8aba1b678..2e63c2b5f 100644 --- a/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContent.js +++ b/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContent.js @@ -1,11 +1,14 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import Alert from 'Components/Alert'; +import Card from 'Components/Card'; +import FieldSet from 'Components/FieldSet'; import Form from 'Components/Form/Form'; import FormGroup from 'Components/Form/FormGroup'; import FormInputGroup from 'Components/Form/FormInputGroup'; import FormLabel from 'Components/Form/FormLabel'; import ProviderFieldFormGroup from 'Components/Form/ProviderFieldFormGroup'; +import Icon from 'Components/Icon'; import Button from 'Components/Link/Button'; import SpinnerErrorButton from 'Components/Link/SpinnerErrorButton'; import LoadingIndicator from 'Components/Loading/LoadingIndicator'; @@ -13,12 +16,33 @@ import ModalBody from 'Components/Modal/ModalBody'; import ModalContent from 'Components/Modal/ModalContent'; import ModalFooter from 'Components/Modal/ModalFooter'; import ModalHeader from 'Components/Modal/ModalHeader'; -import { inputTypes, kinds } from 'Helpers/Props'; +import { icons, inputTypes, kinds } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; +import AddCategoryModalConnector from './Categories/AddCategoryModalConnector'; +import Category from './Categories/Category'; import styles from './EditDownloadClientModalContent.css'; class EditDownloadClientModalContent extends Component { + // + // Lifecycle + + constructor(props, context) { + super(props, context); + + this.state = { + isAddCategoryModalOpen: false + }; + } + + onAddCategoryPress = () => { + this.setState({ isAddCategoryModalOpen: true }); + }; + + onAddCategoryModalClose = () => { + this.setState({ isAddCategoryModalOpen: false }); + }; + // // Render @@ -27,6 +51,7 @@ class EditDownloadClientModalContent extends Component { advancedSettings, isFetching, error, + categories, isSaving, isTesting, saveError, @@ -37,19 +62,27 @@ class EditDownloadClientModalContent extends Component { onSavePress, onTestPress, onDeleteDownloadClientPress, + onConfirmDeleteCategory, ...otherProps } = this.props; + const { + isAddCategoryModalOpen + } = this.state; + const { id, implementationName, name, enable, priority, + supportsCategories, fields, message } = item; + console.log(supportsCategories); + return ( <ModalContent onModalClose={onModalClose}> <ModalHeader> @@ -136,6 +169,43 @@ class EditDownloadClientModalContent extends Component { /> </FormGroup> + { + supportsCategories.value ? + <FieldSet legend={translate('MappedCategories')}> + <div className={styles.customFormats}> + { + categories.map((tag) => { + return ( + <Category + key={tag.id} + {...tag} + onConfirmDeleteSpecification={onConfirmDeleteCategory} + /> + ); + }) + } + + <Card + className={styles.addCategory} + onPress={this.onAddCategoryPress} + > + <div className={styles.center}> + <Icon + name={icons.ADD} + size={25} + /> + </div> + </Card> + </div> + </FieldSet> : + null + } + + <AddCategoryModalConnector + isOpen={isAddCategoryModalOpen} + onModalClose={this.onAddCategoryModalClose} + /> + </Form> } </ModalBody> @@ -185,13 +255,15 @@ EditDownloadClientModalContent.propTypes = { isSaving: PropTypes.bool.isRequired, saveError: PropTypes.object, isTesting: PropTypes.bool.isRequired, + categories: PropTypes.arrayOf(PropTypes.object), item: PropTypes.object.isRequired, onInputChange: PropTypes.func.isRequired, onFieldChange: PropTypes.func.isRequired, onModalClose: PropTypes.func.isRequired, onSavePress: PropTypes.func.isRequired, onTestPress: PropTypes.func.isRequired, - onDeleteDownloadClientPress: PropTypes.func + onDeleteDownloadClientPress: PropTypes.func, + onConfirmDeleteCategory: PropTypes.func.isRequired }; export default EditDownloadClientModalContent; diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContentConnector.js b/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContentConnector.js index f2d4ad6ff..d02d99ca3 100644 --- a/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContentConnector.js +++ b/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContentConnector.js @@ -2,7 +2,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { saveDownloadClient, setDownloadClientFieldValue, setDownloadClientValue, testDownloadClient } from 'Store/Actions/settingsActions'; +import { deleteDownloadClientCategory, fetchDownloadClientCategories, saveDownloadClient, setDownloadClientFieldValue, setDownloadClientValue, testDownloadClient } from 'Store/Actions/settingsActions'; import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector'; import EditDownloadClientModalContent from './EditDownloadClientModalContent'; @@ -10,10 +10,12 @@ function createMapStateToProps() { return createSelector( (state) => state.settings.advancedSettings, createProviderSettingsSelector('downloadClients'), - (advancedSettings, downloadClient) => { + (state) => state.settings.downloadClientCategories, + (advancedSettings, downloadClient, categories) => { return { advancedSettings, - ...downloadClient + ...downloadClient, + categories: categories.items }; } ); @@ -23,7 +25,9 @@ const mapDispatchToProps = { setDownloadClientValue, setDownloadClientFieldValue, saveDownloadClient, - testDownloadClient + testDownloadClient, + fetchDownloadClientCategories, + deleteDownloadClientCategory }; class EditDownloadClientModalContentConnector extends Component { @@ -31,6 +35,14 @@ class EditDownloadClientModalContentConnector extends Component { // // Lifecycle + componentDidMount() { + const { + id, + tagsFromId + } = this.props; + this.props.fetchDownloadClientCategories({ id: tagsFromId || id }); + } + componentDidUpdate(prevProps, prevState) { if (prevProps.isSaving && !this.props.isSaving && !this.props.saveError) { this.props.onModalClose(); @@ -56,6 +68,10 @@ class EditDownloadClientModalContentConnector extends Component { this.props.testDownloadClient({ id: this.props.id }); }; + onConfirmDeleteCategory = (id) => { + this.props.deleteDownloadClientCategory({ id }); + }; + // // Render @@ -67,6 +83,7 @@ class EditDownloadClientModalContentConnector extends Component { onTestPress={this.onTestPress} onInputChange={this.onInputChange} onFieldChange={this.onFieldChange} + onConfirmDeleteCategory={this.onConfirmDeleteCategory} /> ); } @@ -74,10 +91,13 @@ class EditDownloadClientModalContentConnector extends Component { EditDownloadClientModalContentConnector.propTypes = { id: PropTypes.number, + tagsFromId: PropTypes.number, isFetching: PropTypes.bool.isRequired, isSaving: PropTypes.bool.isRequired, saveError: PropTypes.object, item: PropTypes.object.isRequired, + fetchDownloadClientCategories: PropTypes.func.isRequired, + deleteDownloadClientCategory: PropTypes.func.isRequired, setDownloadClientValue: PropTypes.func.isRequired, setDownloadClientFieldValue: PropTypes.func.isRequired, saveDownloadClient: PropTypes.func.isRequired, diff --git a/frontend/src/Store/Actions/Settings/downloadClientCategories.js b/frontend/src/Store/Actions/Settings/downloadClientCategories.js new file mode 100644 index 000000000..a57dc1858 --- /dev/null +++ b/frontend/src/Store/Actions/Settings/downloadClientCategories.js @@ -0,0 +1,171 @@ +import { createAction } from 'redux-actions'; +import { batchActions } from 'redux-batched-actions'; +import createClearReducer from 'Store/Actions/Creators/Reducers/createClearReducer'; +import createSetProviderFieldValueReducer from 'Store/Actions/Creators/Reducers/createSetProviderFieldValueReducer'; +import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer'; +import { createThunk } from 'Store/thunks'; +import getNextId from 'Utilities/State/getNextId'; +import getProviderState from 'Utilities/State/getProviderState'; +import getSectionState from 'Utilities/State/getSectionState'; +import selectProviderSchema from 'Utilities/State/selectProviderSchema'; +import { removeItem, set, update, updateItem } from '../baseActions'; + +// +// Variables + +const section = 'settings.downloadClientCategories'; + +// +// Actions Types + +export const FETCH_DOWNLOAD_CLIENT_CATEGORIES = 'settings/downloadClientCategories/fetchDownloadClientCategories'; +export const FETCH_DOWNLOAD_CLIENT_CATEGORY_SCHEMA = 'settings/downloadClientCategories/fetchDownloadClientCategorySchema'; +export const SELECT_DOWNLOAD_CLIENT_CATEGORY_SCHEMA = 'settings/downloadClientCategories/selectDownloadClientCategorySchema'; +export const SET_DOWNLOAD_CLIENT_CATEGORY_VALUE = 'settings/downloadClientCategories/setDownloadClientCategoryValue'; +export const SET_DOWNLOAD_CLIENT_CATEGORY_FIELD_VALUE = 'settings/downloadClientCategories/setDownloadClientCategoryFieldValue'; +export const SAVE_DOWNLOAD_CLIENT_CATEGORY = 'settings/downloadClientCategories/saveDownloadClientCategory'; +export const DELETE_DOWNLOAD_CLIENT_CATEGORY = 'settings/downloadClientCategories/deleteDownloadClientCategory'; +export const DELETE_ALL_DOWNLOAD_CLIENT_CATEGORY = 'settings/downloadClientCategories/deleteAllDownloadClientCategory'; +export const CLEAR_DOWNLOAD_CLIENT_CATEGORIES = 'settings/downloadClientCategories/clearDownloadClientCategories'; +export const CLEAR_DOWNLOAD_CLIENT_CATEGORY_PENDING = 'settings/downloadClientCategories/clearDownloadClientCategoryPending'; +// +// Action Creators + +export const fetchDownloadClientCategories = createThunk(FETCH_DOWNLOAD_CLIENT_CATEGORIES); +export const fetchDownloadClientCategorySchema = createThunk(FETCH_DOWNLOAD_CLIENT_CATEGORY_SCHEMA); +export const selectDownloadClientCategorySchema = createAction(SELECT_DOWNLOAD_CLIENT_CATEGORY_SCHEMA); + +export const saveDownloadClientCategory = createThunk(SAVE_DOWNLOAD_CLIENT_CATEGORY); +export const deleteDownloadClientCategory = createThunk(DELETE_DOWNLOAD_CLIENT_CATEGORY); +export const deleteAllDownloadClientCategory = createThunk(DELETE_ALL_DOWNLOAD_CLIENT_CATEGORY); + +export const setDownloadClientCategoryValue = createAction(SET_DOWNLOAD_CLIENT_CATEGORY_VALUE, (payload) => { + return { + section, + ...payload + }; +}); + +export const setDownloadClientCategoryFieldValue = createAction(SET_DOWNLOAD_CLIENT_CATEGORY_FIELD_VALUE, (payload) => { + return { + section, + ...payload + }; +}); + +export const clearDownloadClientCategory = createAction(CLEAR_DOWNLOAD_CLIENT_CATEGORIES); + +export const clearDownloadClientCategoryPending = createThunk(CLEAR_DOWNLOAD_CLIENT_CATEGORY_PENDING); + +// +// Details + +export default { + + // + // State + + defaultState: { + isPopulated: false, + error: null, + isSchemaFetching: false, + isSchemaPopulated: false, + schemaError: null, + schema: [], + selectedSchema: {}, + isSaving: false, + saveError: null, + items: [], + pendingChanges: {} + }, + + // + // Action Handlers + + actionHandlers: { + [FETCH_DOWNLOAD_CLIENT_CATEGORIES]: (getState, payload, dispatch) => { + let tags = []; + if (payload.id) { + const cfState = getSectionState(getState(), 'settings.downloadClients', true); + const cf = cfState.items[cfState.itemMap[payload.id]]; + tags = cf.categories.map((tag, i) => { + return { + id: i + 1, + ...tag + }; + }); + } + + dispatch(batchActions([ + update({ section, data: tags }), + set({ + section, + isPopulated: true + }) + ])); + }, + + [SAVE_DOWNLOAD_CLIENT_CATEGORY]: (getState, payload, dispatch) => { + const { + id, + ...otherPayload + } = payload; + + const saveData = getProviderState({ id, ...otherPayload }, getState, section, false); + + console.log(saveData); + + // we have to set id since not actually posting to server yet + if (!saveData.id) { + saveData.id = getNextId(getState().settings.downloadClientCategories.items); + } + + dispatch(batchActions([ + updateItem({ section, ...saveData }), + set({ + section, + pendingChanges: {} + }) + ])); + }, + + [DELETE_DOWNLOAD_CLIENT_CATEGORY]: (getState, payload, dispatch) => { + const id = payload.id; + return dispatch(removeItem({ section, id })); + }, + + [DELETE_ALL_DOWNLOAD_CLIENT_CATEGORY]: (getState, payload, dispatch) => { + return dispatch(set({ + section, + items: [] + })); + }, + + [CLEAR_DOWNLOAD_CLIENT_CATEGORY_PENDING]: (getState, payload, dispatch) => { + return dispatch(set({ + section, + pendingChanges: {} + })); + } + }, + + // + // Reducers + + reducers: { + [SET_DOWNLOAD_CLIENT_CATEGORY_VALUE]: createSetSettingValueReducer(section), + [SET_DOWNLOAD_CLIENT_CATEGORY_FIELD_VALUE]: createSetProviderFieldValueReducer(section), + + [SELECT_DOWNLOAD_CLIENT_CATEGORY_SCHEMA]: (state, { payload }) => { + return selectProviderSchema(state, section, payload, (selectedSchema) => { + return selectedSchema; + }); + }, + + [CLEAR_DOWNLOAD_CLIENT_CATEGORIES]: createClearReducer(section, { + isPopulated: false, + error: null, + items: [] + }) + } +}; diff --git a/frontend/src/Store/Actions/Settings/downloadClients.js b/frontend/src/Store/Actions/Settings/downloadClients.js index c18b4db76..7e9292f24 100644 --- a/frontend/src/Store/Actions/Settings/downloadClients.js +++ b/frontend/src/Store/Actions/Settings/downloadClients.js @@ -9,6 +9,7 @@ import createSetProviderFieldValueReducer from 'Store/Actions/Creators/Reducers/ import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer'; import { createThunk } from 'Store/thunks'; import selectProviderSchema from 'Utilities/State/selectProviderSchema'; +import { set } from '../baseActions'; // // Variables @@ -90,10 +91,34 @@ export default { [FETCH_DOWNLOAD_CLIENTS]: createFetchHandler(section, '/downloadclient'), [FETCH_DOWNLOAD_CLIENT_SCHEMA]: createFetchSchemaHandler(section, '/downloadclient/schema'), - [SAVE_DOWNLOAD_CLIENT]: createSaveProviderHandler(section, '/downloadclient'), + [SAVE_DOWNLOAD_CLIENT]: (getState, payload, dispatch) => { + // move the format tags in as a pending change + const state = getState(); + const pendingChanges = state.settings.downloadClients.pendingChanges; + pendingChanges.categories = state.settings.downloadClientCategories.items; + dispatch(set({ + section, + pendingChanges + })); + + createSaveProviderHandler(section, '/downloadclient')(getState, payload, dispatch); + }, + [CANCEL_SAVE_DOWNLOAD_CLIENT]: createCancelSaveProviderHandler(section), [DELETE_DOWNLOAD_CLIENT]: createRemoveItemHandler(section, '/downloadclient'), - [TEST_DOWNLOAD_CLIENT]: createTestProviderHandler(section, '/downloadclient'), + + [TEST_DOWNLOAD_CLIENT]: (getState, payload, dispatch) => { + const state = getState(); + const pendingChanges = state.settings.downloadClients.pendingChanges; + pendingChanges.categories = state.settings.downloadClientCategories.items; + dispatch(set({ + section, + pendingChanges + })); + + createTestProviderHandler(section, '/downloadclient')(getState, payload, dispatch); + }, + [CANCEL_TEST_DOWNLOAD_CLIENT]: createCancelTestProviderHandler(section), [TEST_ALL_DOWNLOAD_CLIENTS]: createTestAllProvidersHandler(section, '/downloadclient') }, diff --git a/frontend/src/Store/Actions/settingsActions.js b/frontend/src/Store/Actions/settingsActions.js index 6aa4ad6be..77baa5785 100644 --- a/frontend/src/Store/Actions/settingsActions.js +++ b/frontend/src/Store/Actions/settingsActions.js @@ -4,6 +4,7 @@ import createHandleActions from './Creators/createHandleActions'; import applications from './Settings/applications'; import appProfiles from './Settings/appProfiles'; import development from './Settings/development'; +import downloadClientCategories from './Settings/downloadClientCategories'; import downloadClients from './Settings/downloadClients'; import general from './Settings/general'; import indexerCategories from './Settings/indexerCategories'; @@ -11,6 +12,7 @@ import indexerProxies from './Settings/indexerProxies'; import notifications from './Settings/notifications'; import ui from './Settings/ui'; +export * from './Settings/downloadClientCategories'; export * from './Settings/downloadClients'; export * from './Settings/general'; export * from './Settings/indexerCategories'; @@ -32,6 +34,7 @@ export const section = 'settings'; export const defaultState = { advancedSettings: false, + downloadClientCategories: downloadClientCategories.defaultState, downloadClients: downloadClients.defaultState, general: general.defaultState, indexerCategories: indexerCategories.defaultState, @@ -61,6 +64,7 @@ export const toggleAdvancedSettings = createAction(TOGGLE_ADVANCED_SETTINGS); // Action Handlers export const actionHandlers = handleThunks({ + ...downloadClientCategories.actionHandlers, ...downloadClients.actionHandlers, ...general.actionHandlers, ...indexerCategories.actionHandlers, @@ -81,6 +85,7 @@ export const reducers = createHandleActions({ return Object.assign({}, state, { advancedSettings: !state.advancedSettings }); }, + ...downloadClientCategories.reducers, ...downloadClients.reducers, ...general.reducers, ...indexerCategories.reducers, diff --git a/src/NzbDrone.Core/Datastore/Migration/023_download_client_categories.cs b/src/NzbDrone.Core/Datastore/Migration/023_download_client_categories.cs new file mode 100644 index 000000000..4b27c8661 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/023_download_client_categories.cs @@ -0,0 +1,15 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(023)] + public class download_client_categories : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Alter.Table("DownloadClients") + .AddColumn("Categories").AsString().WithDefaultValue("[]"); + } + } +} diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index 566dba21e..b26c016e6 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -60,7 +60,8 @@ namespace NzbDrone.Core.Datastore Mapper.Entity<DownloadClientDefinition>("DownloadClients").RegisterModel() .Ignore(x => x.ImplementationName) - .Ignore(i => i.Protocol) + .Ignore(d => d.SupportsCategories) + .Ignore(d => d.Protocol) .Ignore(d => d.Tags); Mapper.Entity<NotificationDefinition>("Notifications").RegisterModel() @@ -115,6 +116,7 @@ namespace NzbDrone.Core.Datastore SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<string>>()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<ReleaseInfo>()); SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<HashSet<int>>()); + SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<DownloadClientCategory>>()); SqlMapper.AddTypeHandler(new OsPathConverter()); SqlMapper.RemoveTypeMap(typeof(Guid)); SqlMapper.RemoveTypeMap(typeof(Guid?)); diff --git a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2.cs b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2.cs index 7eac71b7f..902985371 100644 --- a/src/NzbDrone.Core/Download/Clients/Aria2/Aria2.cs +++ b/src/NzbDrone.Core/Download/Clients/Aria2/Aria2.cs @@ -18,6 +18,8 @@ namespace NzbDrone.Core.Download.Clients.Aria2 public override string Name => "Aria2"; + public override bool SupportsCategories => false; + public Aria2(IAria2Proxy proxy, ITorrentFileInfoReader torrentFileInfoReader, IHttpClient httpClient, diff --git a/src/NzbDrone.Core/Download/Clients/Blackhole/TorrentBlackhole.cs b/src/NzbDrone.Core/Download/Clients/Blackhole/TorrentBlackhole.cs index 3315d43e9..5f6dd7a9d 100644 --- a/src/NzbDrone.Core/Download/Clients/Blackhole/TorrentBlackhole.cs +++ b/src/NzbDrone.Core/Download/Clients/Blackhole/TorrentBlackhole.cs @@ -74,6 +74,8 @@ namespace NzbDrone.Core.Download.Clients.Blackhole public override string Name => "Torrent Blackhole"; + public override bool SupportsCategories => false; + protected override void Test(List<ValidationFailure> failures) { failures.AddIfNotNull(TestFolder(Settings.TorrentFolder, "TorrentFolder")); diff --git a/src/NzbDrone.Core/Download/Clients/Blackhole/UsenetBlackhole.cs b/src/NzbDrone.Core/Download/Clients/Blackhole/UsenetBlackhole.cs index 7f0dd9c0b..0f0364e61 100644 --- a/src/NzbDrone.Core/Download/Clients/Blackhole/UsenetBlackhole.cs +++ b/src/NzbDrone.Core/Download/Clients/Blackhole/UsenetBlackhole.cs @@ -45,6 +45,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole } public override string Name => "Usenet Blackhole"; + public override bool SupportsCategories => false; protected override void Test(List<ValidationFailure> failures) { diff --git a/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs b/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs index 82fb83402..9ea829e6a 100644 --- a/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs +++ b/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Net; +using System.Text.RegularExpressions; using FluentValidation.Results; using NLog; using NzbDrone.Common.Disk; @@ -38,9 +39,10 @@ namespace NzbDrone.Core.Download.Clients.Deluge } // _proxy.SetTorrentSeedingConfiguration(actualHash, remoteMovie.SeedConfiguration, Settings); - if (Settings.Category.IsNotNullOrWhiteSpace()) + var category = GetCategoryForRelease(release) ?? Settings.Category; + if (category.IsNotNullOrWhiteSpace()) { - _proxy.SetTorrentLabel(actualHash, Settings.Category, Settings); + _proxy.SetTorrentLabel(actualHash, category, Settings); } if (Settings.Priority == (int)DelugePriority.First) @@ -61,9 +63,10 @@ namespace NzbDrone.Core.Download.Clients.Deluge } // _proxy.SetTorrentSeedingConfiguration(actualHash, release.SeedConfiguration, Settings); - if (Settings.Category.IsNotNullOrWhiteSpace()) + var category = GetCategoryForRelease(release) ?? Settings.Category; + if (category.IsNotNullOrWhiteSpace()) { - _proxy.SetTorrentLabel(actualHash, Settings.Category, Settings); + _proxy.SetTorrentLabel(actualHash, category, Settings); } if (Settings.Priority == (int)DelugePriority.First) @@ -75,6 +78,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge } public override string Name => "Deluge"; + public override bool SupportsCategories => true; protected override void Test(List<ValidationFailure> failures) { @@ -139,7 +143,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge private ValidationFailure TestCategory() { - if (Settings.Category.IsNullOrWhiteSpace()) + if (Categories.Count == 0) { return null; } @@ -156,23 +160,42 @@ namespace NzbDrone.Core.Download.Clients.Deluge var labels = _proxy.GetAvailableLabels(Settings); - if (Settings.Category.IsNotNullOrWhiteSpace() && !labels.Contains(Settings.Category)) - { - _proxy.AddLabel(Settings.Category, Settings); - labels = _proxy.GetAvailableLabels(Settings); + var categories = Categories.Select(c => c.ClientCategory).ToList(); + categories.Add(Settings.Category); - if (!labels.Contains(Settings.Category)) + foreach (var category in categories) + { + if (category.IsNotNullOrWhiteSpace() && !labels.Contains(category)) { - return new NzbDroneValidationFailure("Category", "Configuration of label failed") + _proxy.AddLabel(category, Settings); + labels = _proxy.GetAvailableLabels(Settings); + + if (!labels.Contains(category)) { - DetailedDescription = "Prowlarr was unable to add the label to Deluge." - }; + return new NzbDroneValidationFailure("Category", "Configuration of label failed") + { + DetailedDescription = "Prowlarr was unable to add the label to Deluge." + }; + } } } return null; } + protected override void ValidateCategories(List<ValidationFailure> failures) + { + base.ValidateCategories(failures); + + foreach (var label in Categories) + { + if (!Regex.IsMatch(label.ClientCategory, "^[-a-z0-9]*$")) + { + failures.AddIfNotNull(new ValidationFailure(string.Empty, "Mapped Categories allowed characters a-z, 0-9 and -")); + } + } + } + private ValidationFailure TestGetTorrents() { try diff --git a/src/NzbDrone.Core/Download/Clients/Deluge/DelugeProxy.cs b/src/NzbDrone.Core/Download/Clients/Deluge/DelugeProxy.cs index 5248e6f20..6396052c3 100644 --- a/src/NzbDrone.Core/Download/Clients/Deluge/DelugeProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/Deluge/DelugeProxy.cs @@ -19,7 +19,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge string[] GetAvailablePlugins(DelugeSettings settings); string[] GetEnabledPlugins(DelugeSettings settings); string[] GetAvailableLabels(DelugeSettings settings); - DelugeLabel GetLabelOptions(DelugeSettings settings); + DelugeLabel GetLabelOptions(DelugeSettings settings, string label); void SetTorrentLabel(string hash, string label, DelugeSettings settings); void SetTorrentConfiguration(string hash, string key, object value, DelugeSettings settings); void SetTorrentSeedingConfiguration(string hash, TorrentSeedConfiguration seedConfiguration, DelugeSettings settings); @@ -158,9 +158,9 @@ namespace NzbDrone.Core.Download.Clients.Deluge return response; } - public DelugeLabel GetLabelOptions(DelugeSettings settings) + public DelugeLabel GetLabelOptions(DelugeSettings settings, string label) { - var response = ProcessRequest<DelugeLabel>(settings, "label.get_options", settings.Category); + var response = ProcessRequest<DelugeLabel>(settings, "label.get_options", label); return response; } diff --git a/src/NzbDrone.Core/Download/Clients/Deluge/DelugeSettings.cs b/src/NzbDrone.Core/Download/Clients/Deluge/DelugeSettings.cs index d9b7edc3e..bf463eb81 100644 --- a/src/NzbDrone.Core/Download/Clients/Deluge/DelugeSettings.cs +++ b/src/NzbDrone.Core/Download/Clients/Deluge/DelugeSettings.cs @@ -43,7 +43,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge [FieldDefinition(4, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] public string Password { get; set; } - [FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional")] + [FieldDefinition(5, Label = "Default Category", Type = FieldType.Textbox, HelpText = "Default fallback Category if no mapped category exists for a release. Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional")] public string Category { get; set; } [FieldDefinition(6, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(DelugePriority), HelpText = "Priority to use when grabbing items")] diff --git a/src/NzbDrone.Core/Download/Clients/DownloadStation/DownloadStationSettings.cs b/src/NzbDrone.Core/Download/Clients/DownloadStation/DownloadStationSettings.cs index 497fd2fa8..bc3e8ca1c 100644 --- a/src/NzbDrone.Core/Download/Clients/DownloadStation/DownloadStationSettings.cs +++ b/src/NzbDrone.Core/Download/Clients/DownloadStation/DownloadStationSettings.cs @@ -18,9 +18,9 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation .When(c => c.TvDirectory.IsNotNullOrWhiteSpace()) .WithMessage("Cannot start with /"); - RuleFor(c => c.TvCategory).Matches(@"^\.?[-a-z]*$", RegexOptions.IgnoreCase).WithMessage("Allowed characters a-z and -"); + RuleFor(c => c.Category).Matches(@"^\.?[-a-z]*$", RegexOptions.IgnoreCase).WithMessage("Allowed characters a-z and -"); - RuleFor(c => c.TvCategory).Empty() + RuleFor(c => c.Category).Empty() .When(c => c.TvDirectory.IsNotNullOrWhiteSpace()) .WithMessage("Cannot use Category and Directory"); } @@ -45,8 +45,8 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation [FieldDefinition(4, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] public string Password { get; set; } - [FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional. Creates a [category] subdirectory in the output directory.")] - public string TvCategory { get; set; } + [FieldDefinition(5, Label = "Default Category", Type = FieldType.Textbox, HelpText = "Default fallback category if no mapped category exists for a release. Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional. Creates a [category] subdirectory in the output directory.")] + public string Category { get; set; } [FieldDefinition(6, Label = "Directory", Type = FieldType.Textbox, HelpText = "Optional shared folder to put downloads into, leave blank to use the default Download Station location")] public string TvDirectory { get; set; } diff --git a/src/NzbDrone.Core/Download/Clients/DownloadStation/TorrentDownloadStation.cs b/src/NzbDrone.Core/Download/Clients/DownloadStation/TorrentDownloadStation.cs index dc759e9e5..5d3d0729e 100644 --- a/src/NzbDrone.Core/Download/Clients/DownloadStation/TorrentDownloadStation.cs +++ b/src/NzbDrone.Core/Download/Clients/DownloadStation/TorrentDownloadStation.cs @@ -44,6 +44,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation } public override string Name => "Download Station"; + public override bool SupportsCategories => false; public override ProviderMessage Message => new ProviderMessage("Prowlarr is unable to connect to Download Station if 2-Factor Authentication is enabled on your DSM account", ProviderMessageType.Warning); @@ -198,7 +199,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation if (downloadDir != null) { var sharedFolder = downloadDir.Split('\\', '/')[0]; - var fieldName = Settings.TvDirectory.IsNotNullOrWhiteSpace() ? nameof(Settings.TvDirectory) : nameof(Settings.TvCategory); + var fieldName = Settings.TvDirectory.IsNotNullOrWhiteSpace() ? nameof(Settings.TvDirectory) : nameof(Settings.Category); var folderInfo = _fileStationProxy.GetInfoFileOrDirectory($"/{downloadDir}", Settings); @@ -311,11 +312,11 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation { return Settings.TvDirectory.TrimStart('/'); } - else if (Settings.TvCategory.IsNotNullOrWhiteSpace()) + else if (Settings.Category.IsNotNullOrWhiteSpace()) { var destDir = GetDefaultDir(); - return $"{destDir.TrimEnd('/')}/{Settings.TvCategory}"; + return $"{destDir.TrimEnd('/')}/{Settings.Category}"; } return null; diff --git a/src/NzbDrone.Core/Download/Clients/DownloadStation/UsenetDownloadStation.cs b/src/NzbDrone.Core/Download/Clients/DownloadStation/UsenetDownloadStation.cs index c5c51433d..2cf42704b 100644 --- a/src/NzbDrone.Core/Download/Clients/DownloadStation/UsenetDownloadStation.cs +++ b/src/NzbDrone.Core/Download/Clients/DownloadStation/UsenetDownloadStation.cs @@ -42,6 +42,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation } public override string Name => "Download Station"; + public override bool SupportsCategories => false; public override ProviderMessage Message => new ProviderMessage("Prowlarr is unable to connect to Download Station if 2-Factor Authentication is enabled on your DSM account", ProviderMessageType.Warning); @@ -101,7 +102,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation if (downloadDir != null) { var sharedFolder = downloadDir.Split('\\', '/')[0]; - var fieldName = Settings.TvDirectory.IsNotNullOrWhiteSpace() ? nameof(Settings.TvDirectory) : nameof(Settings.TvCategory); + var fieldName = Settings.TvDirectory.IsNotNullOrWhiteSpace() ? nameof(Settings.TvDirectory) : nameof(Settings.Category); var folderInfo = _fileStationProxy.GetInfoFileOrDirectory($"/{downloadDir}", Settings); @@ -272,11 +273,11 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation { return Settings.TvDirectory.TrimStart('/'); } - else if (Settings.TvCategory.IsNotNullOrWhiteSpace()) + else if (Settings.Category.IsNotNullOrWhiteSpace()) { var destDir = GetDefaultDir(); - return $"{destDir.TrimEnd('/')}/{Settings.TvCategory}"; + return $"{destDir.TrimEnd('/')}/{Settings.Category}"; } return null; diff --git a/src/NzbDrone.Core/Download/Clients/Flood/Flood.cs b/src/NzbDrone.Core/Download/Clients/Flood/Flood.cs index 8698500ea..f292eaf53 100644 --- a/src/NzbDrone.Core/Download/Clients/Flood/Flood.cs +++ b/src/NzbDrone.Core/Download/Clients/Flood/Flood.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Download.Clients.Flood _proxy = proxy; } - private static IEnumerable<string> HandleTags(ReleaseInfo release, FloodSettings settings) + private static IEnumerable<string> HandleTags(ReleaseInfo release, FloodSettings settings, string mappedCategory) { var result = new HashSet<string>(); @@ -36,6 +36,11 @@ namespace NzbDrone.Core.Download.Clients.Flood result.UnionWith(settings.Tags); } + if (mappedCategory != null) + { + result.Add(mappedCategory); + } + if (settings.AdditionalTags.Any()) { foreach (var additionalTag in settings.AdditionalTags) @@ -55,18 +60,19 @@ namespace NzbDrone.Core.Download.Clients.Flood } public override string Name => "Flood"; + public override bool SupportsCategories => true; public override ProviderMessage Message => new ProviderMessage("Prowlarr is unable to remove torrents that have finished seeding when using Flood", ProviderMessageType.Warning); protected override string AddFromTorrentFile(ReleaseInfo release, string hash, string filename, byte[] fileContent) { - _proxy.AddTorrentByFile(Convert.ToBase64String(fileContent), HandleTags(release, Settings), Settings); + _proxy.AddTorrentByFile(Convert.ToBase64String(fileContent), HandleTags(release, Settings, GetCategoryForRelease(release)), Settings); return hash; } protected override string AddFromMagnetLink(ReleaseInfo release, string hash, string magnetLink) { - _proxy.AddTorrentByUrl(magnetLink, HandleTags(release, Settings), Settings); + _proxy.AddTorrentByUrl(magnetLink, HandleTags(release, Settings, GetCategoryForRelease(release)), Settings); return hash; } diff --git a/src/NzbDrone.Core/Download/Clients/Hadouken/Hadouken.cs b/src/NzbDrone.Core/Download/Clients/Hadouken/Hadouken.cs index bfe9bdebf..a5ca2e4fc 100644 --- a/src/NzbDrone.Core/Download/Clients/Hadouken/Hadouken.cs +++ b/src/NzbDrone.Core/Download/Clients/Hadouken/Hadouken.cs @@ -27,6 +27,7 @@ namespace NzbDrone.Core.Download.Clients.Hadouken } public override string Name => "Hadouken"; + public override bool SupportsCategories => true; protected override void Test(List<ValidationFailure> failures) { @@ -41,14 +42,14 @@ namespace NzbDrone.Core.Download.Clients.Hadouken protected override string AddFromMagnetLink(ReleaseInfo release, string hash, string magnetLink) { - _proxy.AddTorrentUri(Settings, magnetLink); + _proxy.AddTorrentUri(Settings, magnetLink, GetCategoryForRelease(release) ?? Settings.Category); return hash.ToUpper(); } protected override string AddFromTorrentFile(ReleaseInfo release, string hash, string filename, byte[] fileContent) { - return _proxy.AddTorrentFile(Settings, fileContent).ToUpper(); + return _proxy.AddTorrentFile(Settings, fileContent, GetCategoryForRelease(release) ?? Settings.Category).ToUpper(); } private ValidationFailure TestConnection() diff --git a/src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenProxy.cs b/src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenProxy.cs index b695ef1da..a9704432a 100644 --- a/src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenProxy.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Net; using NLog; @@ -13,8 +13,8 @@ namespace NzbDrone.Core.Download.Clients.Hadouken HadoukenSystemInfo GetSystemInfo(HadoukenSettings settings); HadoukenTorrent[] GetTorrents(HadoukenSettings settings); IReadOnlyDictionary<string, object> GetConfig(HadoukenSettings settings); - string AddTorrentFile(HadoukenSettings settings, byte[] fileContent); - void AddTorrentUri(HadoukenSettings settings, string torrentUrl); + string AddTorrentFile(HadoukenSettings settings, byte[] fileContent, string label); + void AddTorrentUri(HadoukenSettings settings, string torrentUrl, string label); void RemoveTorrent(HadoukenSettings settings, string downloadId); void RemoveTorrentAndData(HadoukenSettings settings, string downloadId); } @@ -47,14 +47,14 @@ namespace NzbDrone.Core.Download.Clients.Hadouken return ProcessRequest<IReadOnlyDictionary<string, object>>(settings, "webui.getSettings"); } - public string AddTorrentFile(HadoukenSettings settings, byte[] fileContent) + public string AddTorrentFile(HadoukenSettings settings, byte[] fileContent, string label) { - return ProcessRequest<string>(settings, "webui.addTorrent", "file", Convert.ToBase64String(fileContent), new { label = settings.Category }); + return ProcessRequest<string>(settings, "webui.addTorrent", "file", Convert.ToBase64String(fileContent), new { label }); } - public void AddTorrentUri(HadoukenSettings settings, string torrentUrl) + public void AddTorrentUri(HadoukenSettings settings, string torrentUrl, string label) { - ProcessRequest<string>(settings, "webui.addTorrent", "url", torrentUrl, new { label = settings.Category }); + ProcessRequest<string>(settings, "webui.addTorrent", "url", torrentUrl, new { label }); } public void RemoveTorrent(HadoukenSettings settings, string downloadId) diff --git a/src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenSettings.cs b/src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenSettings.cs index df8ecfe38..c8e6f7763 100644 --- a/src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenSettings.cs +++ b/src/NzbDrone.Core/Download/Clients/Hadouken/HadoukenSettings.cs @@ -51,7 +51,7 @@ namespace NzbDrone.Core.Download.Clients.Hadouken [FieldDefinition(5, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] public string Password { get; set; } - [FieldDefinition(6, Label = "Category", Type = FieldType.Textbox)] + [FieldDefinition(6, Label = "Default Category", Type = FieldType.Textbox, HelpText = "Default fallback category if no mapped category exists for a release.")] public string Category { get; set; } public NzbDroneValidationResult Validate() diff --git a/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortex.cs b/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortex.cs index f2d68823d..e1088780d 100644 --- a/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortex.cs +++ b/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortex.cs @@ -29,8 +29,9 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex protected override string AddFromNzbFile(ReleaseInfo release, string filename, byte[] fileContents) { var priority = Settings.Priority; + var category = GetCategoryForRelease(release) ?? Settings.Category; - var response = _proxy.DownloadNzb(fileContents, filename, priority, Settings); + var response = _proxy.DownloadNzb(fileContents, filename, priority, Settings, category); if (response == null) { @@ -41,6 +42,7 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex } public override string Name => "NZBVortex"; + public override bool SupportsCategories => true; protected List<NzbVortexGroup> GetGroups() { @@ -111,19 +113,27 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex private ValidationFailure TestCategory() { - var group = GetGroups().FirstOrDefault(c => c.GroupName == Settings.Category); + var groups = GetGroups(); - if (group == null) + foreach (var category in Categories) { - if (Settings.Category.IsNotNullOrWhiteSpace()) + if (!category.ClientCategory.IsNullOrWhiteSpace() && !groups.Any(v => v.GroupName == category.ClientCategory)) { - return new NzbDroneValidationFailure("Category", "Group does not exist") + return new NzbDroneValidationFailure(string.Empty, "Group does not exist") { - DetailedDescription = "The Group you entered doesn't exist in NzbVortex. Go to NzbVortex to create it." + DetailedDescription = "A mapped category you entered doesn't exist in NzbVortex. Go to NzbVortex to create it." }; } } + if (!Settings.Category.IsNullOrWhiteSpace() && !groups.Any(v => v.GroupName == Settings.Category)) + { + return new NzbDroneValidationFailure("Category", "Category does not exist") + { + DetailedDescription = "The category you entered doesn't exist in NzbVortex. Go to NzbVortex to create it." + }; + } + return null; } diff --git a/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortexProxy.cs b/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortexProxy.cs index aeb2d7ac5..11bbf6213 100644 --- a/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortexProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortexProxy.cs @@ -13,7 +13,7 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex { public interface INzbVortexProxy { - string DownloadNzb(byte[] nzbData, string filename, int priority, NzbVortexSettings settings); + string DownloadNzb(byte[] nzbData, string filename, int priority, NzbVortexSettings settings, string group); void Remove(int id, bool deleteData, NzbVortexSettings settings); NzbVortexVersionResponse GetVersion(NzbVortexSettings settings); NzbVortexApiVersionResponse GetApiVersion(NzbVortexSettings settings); @@ -37,7 +37,7 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex _authSessionIdCache = cacheManager.GetCache<string>(GetType(), "authCache"); } - public string DownloadNzb(byte[] nzbData, string filename, int priority, NzbVortexSettings settings) + public string DownloadNzb(byte[] nzbData, string filename, int priority, NzbVortexSettings settings, string group) { var requestBuilder = BuildRequest(settings).Resource("nzb/add") .Post() @@ -45,7 +45,7 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex if (settings.Category.IsNotNullOrWhiteSpace()) { - requestBuilder.AddQueryParam("groupname", settings.Category); + requestBuilder.AddQueryParam("groupname", group); } requestBuilder.AddFormUpload("name", filename, nzbData, "application/x-nzb"); diff --git a/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortexSettings.cs b/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortexSettings.cs index c6b03f0e7..2dae1ac49 100644 --- a/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortexSettings.cs +++ b/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortexSettings.cs @@ -47,7 +47,7 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex [FieldDefinition(3, Label = "API Key", Type = FieldType.Textbox, Privacy = PrivacyLevel.ApiKey)] public string ApiKey { get; set; } - [FieldDefinition(4, Label = "Group", Type = FieldType.Textbox, HelpText = "Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional")] + [FieldDefinition(4, Label = "Default Category", Type = FieldType.Textbox, HelpText = "Default fallback category if no mapped category exists for a release. Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional")] public string Category { get; set; } [FieldDefinition(5, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(NzbVortexPriority), HelpText = "Priority to use when grabbing items")] diff --git a/src/NzbDrone.Core/Download/Clients/Nzbget/Nzbget.cs b/src/NzbDrone.Core/Download/Clients/Nzbget/Nzbget.cs index ecdbcf1cd..0aa160cda 100644 --- a/src/NzbDrone.Core/Download/Clients/Nzbget/Nzbget.cs +++ b/src/NzbDrone.Core/Download/Clients/Nzbget/Nzbget.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget protected override string AddFromNzbFile(ReleaseInfo release, string filename, byte[] fileContent) { - var category = Settings.Category; + var category = GetCategoryForRelease(release) ?? Settings.Category; var priority = Settings.Priority; @@ -50,7 +50,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget protected override string AddFromLink(ReleaseInfo release) { - var category = Settings.Category; + var category = GetCategoryForRelease(release) ?? Settings.Category; var priority = Settings.Priority; @@ -66,6 +66,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget } public override string Name => "NZBGet"; + public override bool SupportsCategories => true; protected IEnumerable<NzbgetCategory> GetCategories(Dictionary<string, string> config) { @@ -139,6 +140,18 @@ namespace NzbDrone.Core.Download.Clients.Nzbget var config = _proxy.GetConfig(Settings); var categories = GetCategories(config); + foreach (var category in Categories) + { + if (!category.ClientCategory.IsNullOrWhiteSpace() && !categories.Any(v => v.Name == category.ClientCategory)) + { + return new NzbDroneValidationFailure(string.Empty, "Category does not exist") + { + InfoLink = _proxy.GetBaseUrl(Settings), + DetailedDescription = "A mapped category you entered doesn't exist in NZBGet. Go to NZBGet to create it." + }; + } + } + if (!Settings.Category.IsNullOrWhiteSpace() && !categories.Any(v => v.Name == Settings.Category)) { return new NzbDroneValidationFailure("Category", "Category does not exist") diff --git a/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetSettings.cs b/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetSettings.cs index 21ba2167b..0e1cbc912 100644 --- a/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetSettings.cs +++ b/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetSettings.cs @@ -53,7 +53,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget [FieldDefinition(5, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] public string Password { get; set; } - [FieldDefinition(6, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional")] + [FieldDefinition(6, Label = "Default Category", Type = FieldType.Textbox, HelpText = "Default fallback category if no mapped category exists for a release. Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional")] public string Category { get; set; } [FieldDefinition(7, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority), HelpText = "Priority for items added from Prowlarr")] diff --git a/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs b/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs index 1d9a4963d..1e98734f7 100644 --- a/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs +++ b/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs @@ -23,6 +23,7 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic } public override string Name => "Pneumatic"; + public override bool SupportsCategories => false; public override DownloadProtocol Protocol => DownloadProtocol.Usenet; diff --git a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs index 70d17228b..95dd9e30b 100644 --- a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs @@ -52,8 +52,9 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent //var addHasSetShareLimits = setShareLimits && ProxyApiVersion >= new Version(2, 8, 1); var itemToTop = Settings.Priority == (int)QBittorrentPriority.First; var forceStart = (QBittorrentState)Settings.InitialState == QBittorrentState.ForceStart; + var category = GetCategoryForRelease(release) ?? Settings.Category; - Proxy.AddTorrentFromUrl(magnetLink, null, Settings); + Proxy.AddTorrentFromUrl(magnetLink, null, Settings, category); if (itemToTop || forceStart) { @@ -100,8 +101,9 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent //var addHasSetShareLimits = setShareLimits && ProxyApiVersion >= new Version(2, 8, 1); var itemToTop = Settings.Priority == (int)QBittorrentPriority.First; var forceStart = (QBittorrentState)Settings.InitialState == QBittorrentState.ForceStart; + var category = GetCategoryForRelease(release) ?? Settings.Category; - Proxy.AddTorrentFromFile(filename, fileContent, null, Settings); + Proxy.AddTorrentFromFile(filename, fileContent, null, Settings, category); if (itemToTop || forceStart) { @@ -167,6 +169,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent } public override string Name => "qBittorrent"; + public override bool SupportsCategories => true; protected override void Test(List<ValidationFailure> failures) { @@ -197,7 +200,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent else if (version < Version.Parse("1.6")) { // API version 6 introduced support for labels - if (Settings.Category.IsNotNullOrWhiteSpace()) + if (Settings.Category.IsNotNullOrWhiteSpace() || Categories.Count > 0) { return new NzbDroneValidationFailure("Category", "Category is not supported") { @@ -205,15 +208,6 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent }; } } - else if (Settings.Category.IsNullOrWhiteSpace()) - { - // warn if labels are supported, but category is not provided - return new NzbDroneValidationFailure("Category", "Category is recommended") - { - IsWarning = true, - DetailedDescription = "Prowlarr will not attempt to import completed downloads without a category." - }; - } } catch (DownloadClientAuthenticationException ex) { @@ -251,7 +245,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent private ValidationFailure TestCategory() { - if (Settings.Category.IsNullOrWhiteSpace()) + if (Settings.Category.IsNullOrWhiteSpace() && Categories.Count == 0) { return null; } @@ -265,6 +259,23 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent Dictionary<string, QBittorrentLabel> labels = Proxy.GetLabels(Settings); + foreach (var category in Categories) + { + if (category.ClientCategory.IsNotNullOrWhiteSpace() && !labels.ContainsKey(category.ClientCategory)) + { + Proxy.AddLabel(category.ClientCategory, Settings); + labels = Proxy.GetLabels(Settings); + + if (!labels.ContainsKey(category.ClientCategory)) + { + return new NzbDroneValidationFailure(string.Empty, "Configuration of label failed") + { + DetailedDescription = "Prowlarr was unable to add the label to qBittorrent." + }; + } + } + } + if (Settings.Category.IsNotNullOrWhiteSpace() && !labels.ContainsKey(Settings.Category)) { Proxy.AddLabel(Settings.Category, Settings); diff --git a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxySelector.cs b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxySelector.cs index 158db804e..2460b3239 100644 --- a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxySelector.cs +++ b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxySelector.cs @@ -18,8 +18,8 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent QBittorrentTorrentProperties GetTorrentProperties(string hash, QBittorrentSettings settings); List<QBittorrentTorrentFile> GetTorrentFiles(string hash, QBittorrentSettings settings); - void AddTorrentFromUrl(string torrentUrl, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings); - void AddTorrentFromFile(string fileName, byte[] fileContent, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings); + void AddTorrentFromUrl(string torrentUrl, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings, string category); + void AddTorrentFromFile(string fileName, byte[] fileContent, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings, string category); void RemoveTorrent(string hash, bool removeData, QBittorrentSettings settings); void SetTorrentLabel(string hash, string label, QBittorrentSettings settings); diff --git a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxyV1.cs b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxyV1.cs index e8b1c2e14..8bf6c1878 100644 --- a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxyV1.cs +++ b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxyV1.cs @@ -113,15 +113,15 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent return response; } - public void AddTorrentFromUrl(string torrentUrl, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings) + public void AddTorrentFromUrl(string torrentUrl, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings, string category) { var request = BuildRequest(settings).Resource("/command/download") .Post() .AddFormParameter("urls", torrentUrl); - if (settings.Category.IsNotNullOrWhiteSpace()) + if (category.IsNotNullOrWhiteSpace()) { - request.AddFormParameter("category", settings.Category); + request.AddFormParameter("category", category); } // Note: ForceStart is handled by separate api call @@ -143,15 +143,15 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent } } - public void AddTorrentFromFile(string fileName, byte[] fileContent, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings) + public void AddTorrentFromFile(string fileName, byte[] fileContent, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings, string category) { var request = BuildRequest(settings).Resource("/command/upload") .Post() .AddFormUpload("torrents", fileName, fileContent); - if (settings.Category.IsNotNullOrWhiteSpace()) + if (category.IsNotNullOrWhiteSpace()) { - request.AddFormParameter("category", settings.Category); + request.AddFormParameter("category", category); } // Note: ForceStart is handled by separate api call diff --git a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxyV2.cs b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxyV2.cs index ed5165e67..c1d789e2d 100644 --- a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxyV2.cs +++ b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentProxyV2.cs @@ -119,14 +119,14 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent return response; } - public void AddTorrentFromUrl(string torrentUrl, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings) + public void AddTorrentFromUrl(string torrentUrl, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings, string category) { var request = BuildRequest(settings).Resource("/api/v2/torrents/add") .Post() .AddFormParameter("urls", torrentUrl); - if (settings.Category.IsNotNullOrWhiteSpace()) + if (category.IsNotNullOrWhiteSpace()) { - request.AddFormParameter("category", settings.Category); + request.AddFormParameter("category", category); } // Note: ForceStart is handled by separate api call @@ -153,15 +153,15 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent } } - public void AddTorrentFromFile(string fileName, byte[] fileContent, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings) + public void AddTorrentFromFile(string fileName, byte[] fileContent, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings, string category) { var request = BuildRequest(settings).Resource("/api/v2/torrents/add") .Post() .AddFormUpload("torrents", fileName, fileContent); - if (settings.Category.IsNotNullOrWhiteSpace()) + if (category.IsNotNullOrWhiteSpace()) { - request.AddFormParameter("category", settings.Category); + request.AddFormParameter("category", category); } // Note: ForceStart is handled by separate api call diff --git a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentSettings.cs b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentSettings.cs index a18d14c34..d0c46c0c5 100644 --- a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentSettings.cs +++ b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrentSettings.cs @@ -47,7 +47,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent [FieldDefinition(5, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] public string Password { get; set; } - [FieldDefinition(6, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional")] + [FieldDefinition(6, Label = "Default Category", Type = FieldType.Textbox, HelpText = "Default fallback category if no mapped category exists for a release. Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional")] public string Category { get; set; } [FieldDefinition(7, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(QBittorrentPriority), HelpText = "Priority to use when grabbing items")] diff --git a/src/NzbDrone.Core/Download/Clients/Sabnzbd/Sabnzbd.cs b/src/NzbDrone.Core/Download/Clients/Sabnzbd/Sabnzbd.cs index ff3f23136..584e392b2 100644 --- a/src/NzbDrone.Core/Download/Clients/Sabnzbd/Sabnzbd.cs +++ b/src/NzbDrone.Core/Download/Clients/Sabnzbd/Sabnzbd.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd protected override string AddFromNzbFile(ReleaseInfo release, string filename, byte[] fileContent) { - var category = Settings.Category; + var category = GetCategoryForRelease(release) ?? Settings.Category; var priority = Settings.Priority; var response = _proxy.DownloadNzb(fileContent, filename, category, priority, Settings); @@ -48,7 +48,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd protected override string AddFromLink(ReleaseInfo release) { - var category = Settings.Category; + var category = GetCategoryForRelease(release) ?? Settings.Category; var priority = Settings.Priority; var response = _proxy.DownloadNzbByUrl(release.DownloadUrl, category, priority, Settings); @@ -62,6 +62,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd } public override string Name => "SABnzbd"; + public override bool SupportsCategories => true; protected IEnumerable<SabnzbdCategory> GetCategories(SabnzbdConfig config) { @@ -260,29 +261,27 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd private ValidationFailure TestCategory() { var config = _proxy.GetConfig(Settings); - var category = GetCategories(config).FirstOrDefault((SabnzbdCategory v) => v.Name == Settings.Category); + var categories = GetCategories(config); - if (category != null) + foreach (var category in Categories) { - if (category.Dir.EndsWith("*")) + if (!category.ClientCategory.IsNullOrWhiteSpace() && !categories.Any(v => v.Name == category.ClientCategory)) { - return new NzbDroneValidationFailure("Category", "Enable Job folders") + return new NzbDroneValidationFailure(string.Empty, "Category does not exist") { - InfoLink = _proxy.GetBaseUrl(Settings, "config/categories/"), - DetailedDescription = "Prowlarr prefers each download to have a separate folder. With * appended to the Folder/Path SABnzbd will not create these job folders. Go to SABnzbd to fix it." + InfoLink = _proxy.GetBaseUrl(Settings), + DetailedDescription = "A mapped category you entered doesn't exist in Sabnzbd. Go to Sabnzbd to create it." }; } } - else + + if (!Settings.Category.IsNullOrWhiteSpace() && !categories.Any(v => v.Name == Settings.Category)) { - if (!Settings.Category.IsNullOrWhiteSpace()) + return new NzbDroneValidationFailure("Category", "Category does not exist") { - return new NzbDroneValidationFailure("Category", "Category does not exist") - { - InfoLink = _proxy.GetBaseUrl(Settings, "config/categories/"), - DetailedDescription = "The category you entered doesn't exist in SABnzbd. Go to SABnzbd to create it." - }; - } + InfoLink = _proxy.GetBaseUrl(Settings), + DetailedDescription = "The category you entered doesn't exist in Sabnzbd. Go to Sabnzbd to create it." + }; } if (config.Misc.enable_tv_sorting && ContainsCategory(config.Misc.tv_categories, Settings.Category)) diff --git a/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdSettings.cs b/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdSettings.cs index 024f55a81..37df94bd5 100644 --- a/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdSettings.cs +++ b/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdSettings.cs @@ -65,7 +65,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd [FieldDefinition(6, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] public string Password { get; set; } - [FieldDefinition(7, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional")] + [FieldDefinition(7, Label = "Default Category", Type = FieldType.Textbox, HelpText = "Default fallback category if no mapped category exists for a release. Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional")] public string Category { get; set; } [FieldDefinition(8, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(SabnzbdPriority), HelpText = "Priority to use when grabbing items")] diff --git a/src/NzbDrone.Core/Download/Clients/Transmission/Transmission.cs b/src/NzbDrone.Core/Download/Clients/Transmission/Transmission.cs index a6f8ec3a1..fac544a20 100644 --- a/src/NzbDrone.Core/Download/Clients/Transmission/Transmission.cs +++ b/src/NzbDrone.Core/Download/Clients/Transmission/Transmission.cs @@ -38,5 +38,6 @@ namespace NzbDrone.Core.Download.Clients.Transmission } public override string Name => "Transmission"; + public override bool SupportsCategories => false; } } diff --git a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionSettings.cs b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionSettings.cs index 0759cf1ea..4d2682ee6 100644 --- a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionSettings.cs +++ b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionSettings.cs @@ -53,7 +53,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission [FieldDefinition(5, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] public string Password { get; set; } - [FieldDefinition(6, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional. Creates a [category] subdirectory in the output directory.")] + [FieldDefinition(6, Label = "Default Category", Type = FieldType.Textbox, HelpText = "Default fallback category if no mapped category exists for a release. Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional. Creates a [category] subdirectory in the output directory.")] public string Category { get; set; } [FieldDefinition(7, Label = "Directory", Type = FieldType.Textbox, Advanced = true, HelpText = "Optional location to put downloads in, leave blank to use the default Transmission location")] diff --git a/src/NzbDrone.Core/Download/Clients/Vuze/Vuze.cs b/src/NzbDrone.Core/Download/Clients/Vuze/Vuze.cs index d52b3eb46..bd1f4c37b 100644 --- a/src/NzbDrone.Core/Download/Clients/Vuze/Vuze.cs +++ b/src/NzbDrone.Core/Download/Clients/Vuze/Vuze.cs @@ -58,5 +58,6 @@ namespace NzbDrone.Core.Download.Clients.Vuze } public override string Name => "Vuze"; + public override bool SupportsCategories => false; } } diff --git a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs index 091ac1242..9f7505cfd 100644 --- a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs @@ -38,7 +38,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent { var priority = (RTorrentPriority)Settings.Priority; - _proxy.AddTorrentFromUrl(magnetLink, Settings.Category, priority, Settings.Directory, Settings); + _proxy.AddTorrentFromUrl(magnetLink, GetCategoryForRelease(release) ?? Settings.Category, priority, Settings.Directory, Settings); var tries = 10; var retryDelay = 500; @@ -58,7 +58,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent { var priority = (RTorrentPriority)Settings.Priority; - _proxy.AddTorrentFromFile(filename, fileContent, Settings.Category, priority, Settings.Directory, Settings); + _proxy.AddTorrentFromFile(filename, fileContent, GetCategoryForRelease(release) ?? Settings.Category, priority, Settings.Directory, Settings); var tries = 10; var retryDelay = 500; @@ -73,6 +73,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent } public override string Name => "rTorrent"; + public override bool SupportsCategories => true; public override ProviderMessage Message => new ProviderMessage("Prowlarr is unable to remove torrents that have finished seeding when using rTorrent", ProviderMessageType.Warning); diff --git a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentSettings.cs b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentSettings.cs index 73fbd43bf..e2ab37fe2 100644 --- a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentSettings.cs +++ b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrentSettings.cs @@ -48,7 +48,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent [FieldDefinition(5, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] public string Password { get; set; } - [FieldDefinition(6, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional.")] + [FieldDefinition(6, Label = "Default Category", Type = FieldType.Textbox, HelpText = "Default fallback category if no mapped category exists for a release. Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional.")] public string Category { get; set; } [FieldDefinition(7, Label = "Directory", Type = FieldType.Textbox, Advanced = true, HelpText = "Optional location to put downloads in, leave blank to use the default rTorrent location")] diff --git a/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrent.cs b/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrent.cs index 47951fe70..9b92312d5 100644 --- a/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrent.cs @@ -38,9 +38,10 @@ namespace NzbDrone.Core.Download.Clients.UTorrent _proxy.AddTorrentFromUrl(magnetLink, Settings); //_proxy.SetTorrentSeedingConfiguration(hash, release.SeedConfiguration, Settings); - if (Settings.Category.IsNotNullOrWhiteSpace()) + var category = GetCategoryForRelease(release) ?? Settings.Category; + if (GetCategoryForRelease(release).IsNotNullOrWhiteSpace()) { - _proxy.SetTorrentLabel(hash, Settings.Category, Settings); + _proxy.SetTorrentLabel(hash, category, Settings); } if (Settings.Priority == (int)UTorrentPriority.First) @@ -58,9 +59,10 @@ namespace NzbDrone.Core.Download.Clients.UTorrent _proxy.AddTorrentFromFile(filename, fileContent, Settings); //_proxy.SetTorrentSeedingConfiguration(hash, release.SeedConfiguration, Settings); - if (Settings.Category.IsNotNullOrWhiteSpace()) + var category = GetCategoryForRelease(release) ?? Settings.Category; + if (category.IsNotNullOrWhiteSpace()) { - _proxy.SetTorrentLabel(hash, Settings.Category, Settings); + _proxy.SetTorrentLabel(hash, category, Settings); } if (Settings.Priority == (int)UTorrentPriority.First) @@ -74,40 +76,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent } public override string Name => "uTorrent"; - - private List<UTorrentTorrent> GetTorrents() - { - List<UTorrentTorrent> torrents; - - var cacheKey = string.Format("{0}:{1}:{2}", Settings.Host, Settings.Port, Settings.Category); - var cache = _torrentCache.Find(cacheKey); - - var response = _proxy.GetTorrents(cache == null ? null : cache.CacheID, Settings); - - if (cache != null && response.Torrents == null) - { - var removedAndUpdated = new HashSet<string>(response.TorrentsChanged.Select(v => v.Hash).Concat(response.TorrentsRemoved)); - - torrents = cache.Torrents - .Where(v => !removedAndUpdated.Contains(v.Hash)) - .Concat(response.TorrentsChanged) - .ToList(); - } - else - { - torrents = response.Torrents; - } - - cache = new UTorrentTorrentCache - { - CacheID = response.CacheNumber, - Torrents = torrents - }; - - _torrentCache.Set(cacheKey, cache, TimeSpan.FromMinutes(15)); - - return torrents; - } + public override bool SupportsCategories => true; protected override void Test(List<ValidationFailure> failures) { diff --git a/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrentSettings.cs b/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrentSettings.cs index 19388bf5d..d3b72c04d 100644 --- a/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrentSettings.cs +++ b/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrentSettings.cs @@ -46,7 +46,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent [FieldDefinition(5, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] public string Password { get; set; } - [FieldDefinition(6, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional")] + [FieldDefinition(6, Label = "Default Category", Type = FieldType.Textbox, HelpText = "Default fallback category if no mapped category exists for a release. Adding a category specific to Prowlarr avoids conflicts with unrelated downloads, but it's optional")] public string Category { get; set; } [FieldDefinition(7, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(UTorrentPriority), HelpText = "Priority to use when grabbing items")] diff --git a/src/NzbDrone.Core/Download/DownloadClientBase.cs b/src/NzbDrone.Core/Download/DownloadClientBase.cs index 395cd491b..9b3741587 100644 --- a/src/NzbDrone.Core/Download/DownloadClientBase.cs +++ b/src/NzbDrone.Core/Download/DownloadClientBase.cs @@ -1,14 +1,17 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using FluentValidation.Results; using NLog; using NzbDrone.Common.Disk; +using NzbDrone.Common.Extensions; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; +using Org.BouncyCastle.Crypto.Tls; namespace NzbDrone.Core.Download { @@ -50,6 +53,9 @@ namespace NzbDrone.Core.Download return GetType().Name; } + protected List<DownloadClientCategory> Categories => ((DownloadClientDefinition)Definition).Categories; + public abstract bool SupportsCategories { get; } + public abstract DownloadProtocol Protocol { get; @@ -57,12 +63,54 @@ namespace NzbDrone.Core.Download public abstract Task<string> Download(ReleaseInfo release, bool redirect, IIndexer indexer); + protected string GetCategoryForRelease(ReleaseInfo release) + { + var categories = ((DownloadClientDefinition)Definition).Categories; + if (categories.Count == 0) + { + return null; + } + + // Check for direct mapping + var category = categories.FirstOrDefault(x => x.Categories.Intersect(release.Categories.Select(c => c.Id)).Any())?.ClientCategory; + + // Check for parent mapping + if (category == null) + { + foreach (var cat in categories) + { + var mappedCat = NewznabStandardCategory.AllCats.Where(x => cat.Categories.Contains(x.Id)); + var subCats = mappedCat.SelectMany(x => x.SubCategories); + + if (subCats.Intersect(release.Categories).Any()) + { + category = cat.ClientCategory; + break; + } + } + } + + return category; + } + + protected virtual void ValidateCategories(List<ValidationFailure> failures) + { + foreach (var category in ((DownloadClientDefinition)Definition).Categories) + { + if (category.ClientCategory.IsNullOrWhiteSpace()) + { + failures.AddIfNotNull(new ValidationFailure(string.Empty, "Category can not be empty")); + } + } + } + public ValidationResult Test() { var failures = new List<ValidationFailure>(); try { + ValidateCategories(failures); Test(failures); } catch (Exception ex) @@ -97,5 +145,17 @@ namespace NzbDrone.Core.Download return null; } + + private bool HasConcreteImplementation(string methodName) + { + var method = GetType().GetMethod(methodName); + + if (method == null) + { + throw new MissingMethodException(GetType().Name, Name); + } + + return !method.DeclaringType.IsAbstract; + } } } diff --git a/src/NzbDrone.Core/Download/DownloadClientCategory.cs b/src/NzbDrone.Core/Download/DownloadClientCategory.cs new file mode 100644 index 000000000..b99e6fa4f --- /dev/null +++ b/src/NzbDrone.Core/Download/DownloadClientCategory.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NzbDrone.Core.Download +{ + public class DownloadClientCategory + { + public string ClientCategory { get; set; } + public List<int> Categories { get; set; } + } +} diff --git a/src/NzbDrone.Core/Download/DownloadClientDefinition.cs b/src/NzbDrone.Core/Download/DownloadClientDefinition.cs index 1c0dfa927..ed2add70d 100644 --- a/src/NzbDrone.Core/Download/DownloadClientDefinition.cs +++ b/src/NzbDrone.Core/Download/DownloadClientDefinition.cs @@ -1,10 +1,18 @@ -using NzbDrone.Core.Indexers; +using System.Collections.Generic; +using NzbDrone.Core.Indexers; using NzbDrone.Core.ThingiProvider; namespace NzbDrone.Core.Download { public class DownloadClientDefinition : ProviderDefinition { + public DownloadClientDefinition() + { + Categories = new List<DownloadClientCategory>(); + } + + public List<DownloadClientCategory> Categories { get; set; } + public bool SupportsCategories { get; set; } public DownloadProtocol Protocol { get; set; } public int Priority { get; set; } = 1; } diff --git a/src/NzbDrone.Core/Download/DownloadClientFactory.cs b/src/NzbDrone.Core/Download/DownloadClientFactory.cs index d69374794..f5cd9f005 100644 --- a/src/NzbDrone.Core/Download/DownloadClientFactory.cs +++ b/src/NzbDrone.Core/Download/DownloadClientFactory.cs @@ -40,6 +40,7 @@ namespace NzbDrone.Core.Download base.SetProviderCharacteristics(provider, definition); definition.Protocol = provider.Protocol; + definition.SupportsCategories = provider.SupportsCategories; } public List<IDownloadClient> DownloadHandlingEnabled(bool filterBlockedClients = true) diff --git a/src/NzbDrone.Core/Download/IDownloadClient.cs b/src/NzbDrone.Core/Download/IDownloadClient.cs index 0b6d0664f..6c7bcf862 100644 --- a/src/NzbDrone.Core/Download/IDownloadClient.cs +++ b/src/NzbDrone.Core/Download/IDownloadClient.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Threading.Tasks; using NzbDrone.Core.Indexers; using NzbDrone.Core.Parser.Model; @@ -7,6 +8,7 @@ namespace NzbDrone.Core.Download { public interface IDownloadClient : IProvider { + bool SupportsCategories { get; } DownloadProtocol Protocol { get; } Task<string> Download(ReleaseInfo release, bool redirect, IIndexer indexer); } diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 56cb6cc95..5a2bf2838 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -39,6 +39,7 @@ "AppProfileSelectHelpText": "App profiles are used to control RSS, Automatic Search and Interactive Search settings on application sync", "Apps": "Apps", "AppSettingsSummary": "Applications and settings to configure how Prowlarr interacts with your PVR programs", + "AreYouSureYouWantToDeleteCategory": "Are you sure you want to delete mapped category?", "AreYouSureYouWantToResetYourAPIKey": "Are you sure you want to reset your API Key?", "AudioSearch": "Audio Search", "Auth": "Auth", @@ -97,6 +98,7 @@ "DeleteAppProfile": "Delete App Profile", "DeleteBackup": "Delete Backup", "DeleteBackupMessageText": "Are you sure you want to delete the backup '{0}'?", + "DeleteClientCategory": "Delete Download Client Category", "DeleteDownloadClient": "Delete Download Client", "DeleteDownloadClientMessageText": "Are you sure you want to delete the download client '{0}'?", "DeleteIndexerProxy": "Delete Indexer Proxy", @@ -113,6 +115,7 @@ "Docker": "Docker", "Donations": "Donations", "DownloadClient": "Download Client", + "DownloadClientCategory": "Download Client Category", "DownloadClients": "Download Clients", "DownloadClientSettings": "Download Client Settings", "DownloadClientsSettingsSummary": "Download clients configuration for integration into Prowlarr UI search", @@ -226,6 +229,7 @@ "Logs": "Logs", "MaintenanceRelease": "Maintenance Release: bug fixes and other improvements. See Github Commit History for more details", "Manual": "Manual", + "MappedCategories": "Mapped Categories", "MappedDrivesRunningAsService": "Mapped network drives are not available when running as a Windows Service. Please see the FAQ for more information", "MassEditor": "Mass Editor", "Mechanism": "Mechanism", diff --git a/src/Prowlarr.Api.V1/DownloadClient/DownloadClientResource.cs b/src/Prowlarr.Api.V1/DownloadClient/DownloadClientResource.cs index 63de27da2..7376d6fe4 100644 --- a/src/Prowlarr.Api.V1/DownloadClient/DownloadClientResource.cs +++ b/src/Prowlarr.Api.V1/DownloadClient/DownloadClientResource.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using NzbDrone.Core.Download; using NzbDrone.Core.Indexers; @@ -8,6 +9,8 @@ namespace Prowlarr.Api.V1.DownloadClient public bool Enable { get; set; } public DownloadProtocol Protocol { get; set; } public int Priority { get; set; } + public List<DownloadClientCategory> Categories { get; set; } + public bool SupportsCategories { get; set; } } public class DownloadClientResourceMapper : ProviderResourceMapper<DownloadClientResource, DownloadClientDefinition> @@ -24,6 +27,8 @@ namespace Prowlarr.Api.V1.DownloadClient resource.Enable = definition.Enable; resource.Protocol = definition.Protocol; resource.Priority = definition.Priority; + resource.Categories = definition.Categories; + resource.SupportsCategories = definition.SupportsCategories; return resource; } @@ -40,6 +45,7 @@ namespace Prowlarr.Api.V1.DownloadClient definition.Enable = resource.Enable; definition.Protocol = resource.Protocol; definition.Priority = resource.Priority; + definition.Categories = resource.Categories; return definition; } From 4e3f460a244263011e72669b98e60f23d2537f45 Mon Sep 17 00:00:00 2001 From: Bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 11 Dec 2022 14:03:49 -0600 Subject: [PATCH 0669/2320] Fixed: (Avistaz Family) Correct Age Parsing Co-authored-by: Qstick <qstick@gmail.com> --- .../IndexerTests/AvistazTests/AvistazFixture.cs | 2 +- .../IndexerTests/AvistazTests/ExoticazFixture.cs | 2 +- .../IndexerTests/AvistazTests/PrivateHDFixture.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/AvistazFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/AvistazFixture.cs index 290944b46..347a88033 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/AvistazFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/AvistazFixture.cs @@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AvistazTests torrentInfo.InfoUrl.Should().Be("https://avistaz.to/torrent/187240-japan-sinks-people-of-hope-2021-s01e05-720p-nf-web-dl-ddp20-x264-seikel"); torrentInfo.CommentUrl.Should().BeNullOrEmpty(); torrentInfo.Indexer.Should().Be(Subject.Definition.Name); - torrentInfo.PublishDate.Should().Be(DateTime.Parse("2021-11-14 23:26:21")); + torrentInfo.PublishDate.Should().Be(DateTime.Parse("2021-11-15 04:26:21")); torrentInfo.Size.Should().Be(935127615); torrentInfo.InfoHash.Should().Be("a879261d4e6e792402f92401141a21de70d51bf2"); torrentInfo.MagnetUrl.Should().Be(null); diff --git a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/ExoticazFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/ExoticazFixture.cs index ea4b7f98c..85f7ef287 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/ExoticazFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/ExoticazFixture.cs @@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AvistazTests torrentInfo.InfoUrl.Should().Be("https://exoticaz.to/torrent/64040-ssis-419-my-first-experience-is-yua-mikami-from-the-day-i-lost-my-virginity-i-was-devoted-to-sex"); torrentInfo.CommentUrl.Should().BeNullOrEmpty(); torrentInfo.Indexer.Should().Be(Subject.Definition.Name); - torrentInfo.PublishDate.Should().Be(DateTime.Parse("2022-06-11 11:04:50")); + torrentInfo.PublishDate.Should().Be(DateTime.Parse("2022-06-11 16:04:50")); torrentInfo.Size.Should().Be(7085405541); torrentInfo.InfoHash.Should().Be("asdjfiasdf54asd7f4a2sdf544asdf"); torrentInfo.MagnetUrl.Should().Be(null); diff --git a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/PrivateHDFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/PrivateHDFixture.cs index e259a928c..5f316cecd 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/PrivateHDFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/AvistazTests/PrivateHDFixture.cs @@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AvistazTests torrentInfo.InfoUrl.Should().Be("https://privatehd.to/torrent/78506-godzilla-2014-2160p-uhd-bluray-remux-hdr-hevc-atmos-triton"); torrentInfo.CommentUrl.Should().BeNullOrEmpty(); torrentInfo.Indexer.Should().Be(Subject.Definition.Name); - torrentInfo.PublishDate.Should().Be(DateTime.Parse("2021-03-21 00:24:49")); + torrentInfo.PublishDate.Should().Be(DateTime.Parse("2021-03-21 05:24:49")); torrentInfo.Size.Should().Be(69914591044); torrentInfo.InfoHash.Should().Be("a879261d4e6e792402f92401141a21de70d51bf2"); torrentInfo.MagnetUrl.Should().Be(null); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs index 068be1881..7c8ea9252 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazApi.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz public AvistazIdInfo MovieTvinfo { get; set; } [JsonProperty(PropertyName = "created_at")] - public DateTime CreatedAt { get; set; } + public string CreatedAt { get; set; } [JsonProperty(PropertyName = "file_name")] public string FileName { get; set; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs index 183a8ef03..4bb24fdfd 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazParser.cs @@ -61,7 +61,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz InfoUrl = details, Guid = details, Categories = cats, - PublishDate = row.CreatedAt, + PublishDate = DateTime.Parse(row.CreatedAt + "-05:00").ToUniversalTime(), // Avistaz does not specify a timezone & returns server time Size = row.FileSize, Files = row.FileCount, Grabs = row.Completed, From 38ba810ae811f060ae0351ce8b7e77ec003b4272 Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Sat, 17 Dec 2022 20:17:16 +0000 Subject: [PATCH 0670/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index e6bdc2f83..4a93c7e02 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -4823,6 +4823,24 @@ }, "additionalProperties": false }, + "DownloadClientCategory": { + "type": "object", + "properties": { + "clientCategory": { + "type": "string", + "nullable": true + }, + "categories": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + } + }, + "additionalProperties": false + }, "DownloadClientConfigResource": { "type": "object", "properties": { @@ -4895,6 +4913,16 @@ "priority": { "type": "integer", "format": "int32" + }, + "categories": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DownloadClientCategory" + }, + "nullable": true + }, + "supportsCategories": { + "type": "boolean" } }, "additionalProperties": false From 320161e0513c1e52c78b6d0fed2f59b7541b8a19 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 17 Dec 2022 19:26:03 -0600 Subject: [PATCH 0671/2320] New: Smarter Newznab category mapping --- .../Files/Indexers/Newznab/newznab_caps.xml | 1 + .../NewznabCapabilitiesProviderFixture.cs | 14 +++++++ .../Indexers/Definitions/Newznab/Newznab.cs | 2 +- .../Newznab/NewznabCapabilitiesProvider.cs | 39 ++++++++++++------- .../Newznab/NewznabRequestGenerator.cs | 10 +++-- .../Definitions/Newznab/NewznabRssParser.cs | 19 +++++---- .../Indexers/Definitions/Torznab/Torznab.cs | 2 +- .../Definitions/Torznab/TorznabRssParser.cs | 21 ++++++---- 8 files changed, 73 insertions(+), 35 deletions(-) diff --git a/src/NzbDrone.Core.Test/Files/Indexers/Newznab/newznab_caps.xml b/src/NzbDrone.Core.Test/Files/Indexers/Newznab/newznab_caps.xml index f340341ca..b8e05ab35 100644 --- a/src/NzbDrone.Core.Test/Files/Indexers/Newznab/newznab_caps.xml +++ b/src/NzbDrone.Core.Test/Files/Indexers/Newznab/newznab_caps.xml @@ -18,6 +18,7 @@ <subcat id="5030" name="SD"/> <subcat id="5060" name="Sport"/> <subcat id="5010" name="WEB-DL"/> + <subcat id="5999" name="Other"/> </category> <category id="7000" name="Other"> <subcat id="7010" name="Misc"/> diff --git a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs index a5a7c7c14..d6b2e12f2 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Net; using System.Threading.Tasks; using System.Xml; @@ -70,6 +71,19 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests caps.LimitsMax.Value.Should().Be(60); } + [Test] + public void should_map_different_categories() + { + GivenCapsResponse(_caps); + + var caps = Subject.GetCapabilities(_settings, _definition); + + var bookCats = caps.Categories.MapTorznabCapsToTrackers(new int[] { NewznabStandardCategory.Books.Id }); + + bookCats.Count.Should().Be(2); + bookCats.Should().Contain("8000"); + } + [Test] public void should_use_default_pagesize_if_missing() { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs index 9660c9391..e299f1474 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs @@ -42,7 +42,7 @@ namespace NzbDrone.Core.Indexers.Newznab public override IParseIndexerResponse GetParser() { - return new NewznabRssParser(Settings); + return new NewznabRssParser(Settings, Definition, _capabilitiesProvider); } public string[] GetBaseUrlFromSettings() diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs index 155ec309a..75fa06176 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Xml; using System.Xml.Linq; @@ -221,27 +222,37 @@ namespace NzbDrone.Core.Indexers.Newznab { foreach (var xmlCategory in xmlCategories.Elements("category")) { - var cat = new IndexerCategory + var parentName = xmlCategory.Attribute("name").Value; + var parentId = int.Parse(xmlCategory.Attribute("id").Value); + var mappedCat = NewznabStandardCategory.AllCats.FirstOrDefault(x => x.Name.ToLower() == parentName.ToLower()); + + if (mappedCat == null) { - Id = int.Parse(xmlCategory.Attribute("id").Value), - Name = xmlCategory.Attribute("name").Value, - Description = xmlCategory.Attribute("description") != null ? xmlCategory.Attribute("description").Value : string.Empty - }; + mappedCat = NewznabStandardCategory.AllCats.FirstOrDefault(x => x.Id == parentId); + } foreach (var xmlSubcat in xmlCategory.Elements("subcat")) { - var subCat = new IndexerCategory - { - Id = int.Parse(xmlSubcat.Attribute("id").Value), - Name = xmlSubcat.Attribute("name").Value, - Description = xmlSubcat.Attribute("description") != null ? xmlSubcat.Attribute("description").Value : string.Empty - }; + var subName = xmlSubcat.Attribute("name").Value; + var subId = int.Parse(xmlSubcat.Attribute("id").Value); + var mappingName = $"{parentName}/{subName}"; + var mappedSubCat = NewznabStandardCategory.AllCats.FirstOrDefault(x => x.Name.ToLower() == mappingName.ToLower()); - cat.SubCategories.Add(subCat); - capabilities.Categories.AddCategoryMapping(subCat.Name, subCat); + if (mappedSubCat == null) + { + mappedSubCat = NewznabStandardCategory.AllCats.FirstOrDefault(x => x.Id == subId); + } + + if (mappedSubCat != null) + { + capabilities.Categories.AddCategoryMapping(subId, mappedSubCat, mappingName); + } } - capabilities.Categories.AddCategoryMapping(cat.Name, cat); + if (mappedCat != null) + { + capabilities.Categories.AddCategoryMapping(parentId, mappedCat, parentName); + } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs index 4ca28f18e..1d674d8ef 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRequestGenerator.cs @@ -68,6 +68,7 @@ namespace NzbDrone.Core.Indexers.Newznab } pageableRequests.Add(GetPagedRequests(searchCriteria, + capabilities, parameters)); return pageableRequests; @@ -109,6 +110,7 @@ namespace NzbDrone.Core.Indexers.Newznab } pageableRequests.Add(GetPagedRequests(searchCriteria, + capabilities, parameters)); return pageableRequests; @@ -175,6 +177,7 @@ namespace NzbDrone.Core.Indexers.Newznab } pageableRequests.Add(GetPagedRequests(searchCriteria, + capabilities, parameters)); return pageableRequests; @@ -216,6 +219,7 @@ namespace NzbDrone.Core.Indexers.Newznab } pageableRequests.Add(GetPagedRequests(searchCriteria, + capabilities, parameters)); return pageableRequests; @@ -233,15 +237,15 @@ namespace NzbDrone.Core.Indexers.Newznab parameters.Add("q", NewsnabifyTitle(searchCriteria.SearchTerm)); } - pageableRequests.Add(GetPagedRequests(searchCriteria, parameters)); + pageableRequests.Add(GetPagedRequests(searchCriteria, capabilities, parameters)); return pageableRequests; } - private IEnumerable<IndexerRequest> GetPagedRequests(SearchCriteriaBase searchCriteria, NameValueCollection parameters) + private IEnumerable<IndexerRequest> GetPagedRequests(SearchCriteriaBase searchCriteria, IndexerCapabilities capabilities, NameValueCollection parameters) { var baseUrl = string.Format("{0}{1}?t={2}&extended=1", Settings.BaseUrl.TrimEnd('/'), Settings.ApiPath.TrimEnd('/'), searchCriteria.SearchType); - var categories = searchCriteria.Categories; + var categories = capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories); if (categories != null && categories.Any()) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs index 851951356..665b2c75d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs @@ -5,6 +5,7 @@ using System.Xml.Linq; using NzbDrone.Common.Extensions; using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.ThingiProvider; namespace NzbDrone.Core.Indexers.Newznab { @@ -13,12 +14,16 @@ namespace NzbDrone.Core.Indexers.Newznab public const string ns = "{http://www.newznab.com/DTD/2010/feeds/attributes/}"; private readonly NewznabSettings _settings; + private readonly ProviderDefinition _definition; + private readonly INewznabCapabilitiesProvider _capabilitiesProvider; - public NewznabRssParser(NewznabSettings settings) + public NewznabRssParser(NewznabSettings settings, ProviderDefinition definition, INewznabCapabilitiesProvider capabilitiesProvider) { PreferredEnclosureMimeTypes = UsenetEnclosureMimeTypes; UseEnclosureUrl = true; _settings = settings; + _definition = definition; + _capabilitiesProvider = capabilitiesProvider; } public static void CheckError(XDocument xdoc, IndexerResponse indexerResponse) @@ -118,19 +123,17 @@ namespace NzbDrone.Core.Indexers.Newznab protected override ICollection<IndexerCategory> GetCategory(XElement item) { + var capabilities = _capabilitiesProvider.GetCapabilities(_settings, _definition); var cats = TryGetMultipleNewznabAttributes(item, "category"); var results = new List<IndexerCategory>(); foreach (var cat in cats) { - if (int.TryParse(cat, out var intCategory)) - { - var indexerCat = _settings.Categories?.FirstOrDefault(c => c.Id == intCategory) ?? null; + var indexerCat = capabilities.Categories.MapTrackerCatToNewznab(cat); - if (indexerCat != null) - { - results.Add(indexerCat); - } + if (indexerCat != null) + { + results.AddRange(indexerCat); } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs index 27e5ee39a..a4515cfe7 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs @@ -41,7 +41,7 @@ namespace NzbDrone.Core.Indexers.Torznab public override IParseIndexerResponse GetParser() { - return new TorznabRssParser(Settings); + return new TorznabRssParser(Settings, Definition, _capabilitiesProvider); } public string[] GetBaseUrlFromSettings() diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs index a7bc3c9af..46fa0e92a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs @@ -4,7 +4,9 @@ using System.Linq; using System.Xml.Linq; using NzbDrone.Common.Extensions; using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Newznab; using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.ThingiProvider; namespace NzbDrone.Core.Indexers.Torznab { @@ -13,10 +15,15 @@ namespace NzbDrone.Core.Indexers.Torznab public const string ns = "{http://torznab.com/schemas/2015/feed}"; private readonly TorznabSettings _settings; - public TorznabRssParser(TorznabSettings settings) + private readonly ProviderDefinition _definition; + private readonly INewznabCapabilitiesProvider _capabilitiesProvider; + + public TorznabRssParser(TorznabSettings settings, ProviderDefinition definition, INewznabCapabilitiesProvider capabilitiesProvider) { UseEnclosureUrl = true; _settings = settings; + _definition = definition; + _capabilitiesProvider = capabilitiesProvider; } protected override bool PreProcess(IndexerResponse indexerResponse) @@ -157,19 +164,17 @@ namespace NzbDrone.Core.Indexers.Torznab protected override ICollection<IndexerCategory> GetCategory(XElement item) { + var capabilities = _capabilitiesProvider.GetCapabilities(_settings, _definition); var cats = TryGetMultipleNewznabAttributes(item, "category"); var results = new List<IndexerCategory>(); foreach (var cat in cats) { - if (int.TryParse(cat, out var intCategory)) - { - var indexerCat = _settings.Categories?.FirstOrDefault(c => c.Id == intCategory) ?? null; + var indexerCat = capabilities.Categories.MapTrackerCatToNewznab(cat); - if (indexerCat != null) - { - results.Add(indexerCat); - } + if (indexerCat != null) + { + results.AddRange(indexerCat); } } From 9efd0b391e487750bdfd6b8b910a02c7eec3b076 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 17 Dec 2022 20:01:50 -0600 Subject: [PATCH 0672/2320] fixup! --- .../NewznabCapabilitiesProviderFixture.cs | 13 ++++++++ .../Newznab/NewznabCapabilitiesProvider.cs | 30 ++++++++++++++++--- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs index d6b2e12f2..085188d5a 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs @@ -84,6 +84,19 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests bookCats.Should().Contain("8000"); } + [Test] + public void should_map_by_name_when_available() + { + GivenCapsResponse(_caps); + + var caps = Subject.GetCapabilities(_settings, _definition); + + var bookCats = caps.Categories.MapTrackerCatToNewznab("5999"); + + bookCats.Count.Should().Be(2); + bookCats.First().Id.Should().Be(5050); + } + [Test] public void should_use_default_pagesize_if_missing() { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs index 75fa06176..1d3952bf2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs @@ -224,28 +224,50 @@ namespace NzbDrone.Core.Indexers.Newznab { var parentName = xmlCategory.Attribute("name").Value; var parentId = int.Parse(xmlCategory.Attribute("id").Value); - var mappedCat = NewznabStandardCategory.AllCats.FirstOrDefault(x => x.Name.ToLower() == parentName.ToLower()); + + var mappedCat = NewznabStandardCategory.ParentCats.FirstOrDefault(x => parentName.ToLower().Contains(x.Name.ToLower())); if (mappedCat == null) { - mappedCat = NewznabStandardCategory.AllCats.FirstOrDefault(x => x.Id == parentId); + // Try by parent id if name fails + mappedCat = NewznabStandardCategory.ParentCats.FirstOrDefault(x => x.Id == parentId); + } + + if (mappedCat == null) + { + // Fallback to Other + mappedCat = NewznabStandardCategory.Other; } foreach (var xmlSubcat in xmlCategory.Elements("subcat")) { var subName = xmlSubcat.Attribute("name").Value; var subId = int.Parse(xmlSubcat.Attribute("id").Value); - var mappingName = $"{parentName}/{subName}"; + + var mappingName = $"{mappedCat.Name}/{subName}"; var mappedSubCat = NewznabStandardCategory.AllCats.FirstOrDefault(x => x.Name.ToLower() == mappingName.ToLower()); if (mappedSubCat == null) { + // Try by child id if name fails mappedSubCat = NewznabStandardCategory.AllCats.FirstOrDefault(x => x.Id == subId); } + if (mappedSubCat == null && mappedCat.Id != NewznabStandardCategory.Other.Id) + { + // Try by Parent/Other if parent is not other + mappedSubCat = NewznabStandardCategory.AllCats.FirstOrDefault(x => x.Name.ToLower() == $"{mappedCat.Name.ToLower()}/other"); + } + + if (mappedSubCat == null) + { + // Fallback to Misc Other + mappedSubCat = NewznabStandardCategory.OtherMisc; + } + if (mappedSubCat != null) { - capabilities.Categories.AddCategoryMapping(subId, mappedSubCat, mappingName); + capabilities.Categories.AddCategoryMapping(subId, mappedSubCat, $"{parentName}/{subName}"); } } From 364a5564ae169f64fc55a41a40847fbdb5724c01 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 11 Dec 2022 13:39:16 -0600 Subject: [PATCH 0673/2320] update-no-results-msg --- src/NzbDrone.Core/Indexers/HttpIndexerBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index 14961ca8b..24044a858 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -448,7 +448,7 @@ namespace NzbDrone.Core.Indexers if (releases.Releases.Empty()) { - return new ValidationFailure(string.Empty, "Query successful, but no results were returned from your indexer. This may be an issue with the indexer or your indexer category settings."); + return new ValidationFailure(string.Empty, "Query successful, but no results were returned from your indexer. This may be an issue with the indexer, your indexer category settings, or other indexer settings such as search freeleech only etc."); } } catch (IndexerAuthException ex) From fa923e658fb65661a08364e78956b9b31d2b9ab0 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 17 Dec 2022 23:14:56 -0600 Subject: [PATCH 0674/2320] Fixed: (Nyaa) Torrent Age in UI incorrect Fixes #144 --- src/NzbDrone.Core/Parser/DateTimeUtil.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Parser/DateTimeUtil.cs b/src/NzbDrone.Core/Parser/DateTimeUtil.cs index 3e05f60a7..1c1278645 100644 --- a/src/NzbDrone.Core/Parser/DateTimeUtil.cs +++ b/src/NzbDrone.Core/Parser/DateTimeUtil.cs @@ -109,7 +109,7 @@ namespace NzbDrone.Core.Parser if (DateTimeRoutines.TryParseDateOrTime( str, dtFormat, out DateTimeRoutines.ParsedDateTime dt)) { - return dt.DateTime; + return dt.DateTime.ToUniversalTime(); } throw new InvalidDateException($"FromFuzzyTime parsing failed for string {str}"); From 9227efdb6577c3cdf4d3744f50ef9a1273c4d05c Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sat, 17 Dec 2022 23:34:08 -0600 Subject: [PATCH 0675/2320] New: (FileList) Freeleech Only option Fixes #1147 --- .../Definitions/FileList/FileListRequestGenerator.cs | 5 +++++ .../Indexers/Definitions/FileList/FileListSettings.cs | 3 +++ .../Indexers/Settings/CookieTorrentBaseSettings.cs | 4 ++-- .../Indexers/Settings/NoAuthTorrentBaseSettings.cs | 4 ++-- .../Indexers/Settings/UserPassTorrentBaseSettings.cs | 4 ++-- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListRequestGenerator.cs index 226903005..803b7be39 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListRequestGenerator.cs @@ -109,6 +109,11 @@ namespace NzbDrone.Core.Indexers.FileList var baseUrl = string.Format("{0}/api.php?action={1}&category={2}&username={3}&passkey={4}{5}", Settings.BaseUrl.TrimEnd('/'), searchType, categoriesQuery, Settings.Username.Trim(), Settings.Passkey.Trim(), parameters); + if (Settings.FreeleechOnly) + { + baseUrl += "&freeleech=1"; + } + yield return new IndexerRequest(baseUrl, HttpAccept.Json); } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListSettings.cs index ec8e9c4bd..89934c9ea 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListSettings.cs @@ -29,6 +29,9 @@ namespace NzbDrone.Core.Indexers.FileList [FieldDefinition(3, Label = "Passkey", HelpText = "Site Passkey (This is the alphanumeric string in the tracker url shown in your download client)", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] public string Passkey { get; set; } + [FieldDefinition(4, Label = "Freeleech Only", HelpText = "Search Freeleech torrents only", Type = FieldType.Checkbox)] + public bool FreeleechOnly { get; set; } + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs index 1ea233525..b337c5339 100644 --- a/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs @@ -27,10 +27,10 @@ namespace NzbDrone.Core.Indexers.Settings [FieldDefinition(2, Label = "Cookie", HelpText = "Site Cookie", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] public string Cookie { get; set; } - [FieldDefinition(3)] + [FieldDefinition(10)] public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - [FieldDefinition(4)] + [FieldDefinition(11)] public IndexerTorrentBaseSettings TorrentBaseSettings { get; set; } = new IndexerTorrentBaseSettings(); public virtual NzbDroneValidationResult Validate() diff --git a/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs index 9aff60db1..c2922551a 100644 --- a/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs @@ -15,10 +15,10 @@ namespace NzbDrone.Core.Indexers.Settings [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] public string BaseUrl { get; set; } - [FieldDefinition(2)] + [FieldDefinition(10)] public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - [FieldDefinition(3)] + [FieldDefinition(11)] public IndexerTorrentBaseSettings TorrentBaseSettings { get; set; } = new IndexerTorrentBaseSettings(); public virtual NzbDroneValidationResult Validate() diff --git a/src/NzbDrone.Core/Indexers/Settings/UserPassTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/Settings/UserPassTorrentBaseSettings.cs index 7b03f66ee..07ef1f193 100644 --- a/src/NzbDrone.Core/Indexers/Settings/UserPassTorrentBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/Settings/UserPassTorrentBaseSettings.cs @@ -32,10 +32,10 @@ namespace NzbDrone.Core.Indexers.Settings [FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)] public string Password { get; set; } - [FieldDefinition(4)] + [FieldDefinition(10)] public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings(); - [FieldDefinition(5)] + [FieldDefinition(11)] public IndexerTorrentBaseSettings TorrentBaseSettings { get; set; } = new IndexerTorrentBaseSettings(); public NzbDroneValidationResult Validate() From a8234c9ce06500c4832bb8c309bcbdb956145dc0 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Dec 2022 00:02:59 -0600 Subject: [PATCH 0676/2320] Fixed: Refresh applicable healthchecks on bulk deletes --- .../HealthCheck/Checks/IndexerCheck.cs | 1 + .../Checks/IndexerLongTermStatusCheck.cs | 1 + .../HealthCheck/Checks/IndexerStatusCheck.cs | 1 + .../HealthCheck/Checks/IndexerVIPCheck.cs | 1 + .../HealthCheck/Checks/IndexerVIPExpiredCheck.cs | 1 + .../HealthCheck/Checks/NoDefinitionCheck.cs | 1 + .../Checks/OutdatedDefinitionCheck.cs | 1 + src/NzbDrone.Core/Indexers/IndexerFactory.cs | 14 +------------- .../Events/ProviderBulkDeletedEvent.cs | 16 ++++++++++++++++ .../ThingiProvider/IProviderFactory.cs | 1 + .../ThingiProvider/ProviderFactory.cs | 7 +++++++ .../Indexers/IndexerEditorController.cs | 16 ++++++++-------- 12 files changed, 40 insertions(+), 21 deletions(-) create mode 100644 src/NzbDrone.Core/ThingiProvider/Events/ProviderBulkDeletedEvent.cs diff --git a/src/NzbDrone.Core/HealthCheck/Checks/IndexerCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/IndexerCheck.cs index f25db9b15..c8781a06a 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/IndexerCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/IndexerCheck.cs @@ -8,6 +8,7 @@ namespace NzbDrone.Core.HealthCheck.Checks [CheckOn(typeof(ProviderAddedEvent<IIndexer>))] [CheckOn(typeof(ProviderUpdatedEvent<IIndexer>))] [CheckOn(typeof(ProviderDeletedEvent<IIndexer>))] + [CheckOn(typeof(ProviderBulkDeletedEvent<IIndexer>))] [CheckOn(typeof(ProviderStatusChangedEvent<IIndexer>))] public class IndexerCheck : HealthCheckBase { diff --git a/src/NzbDrone.Core/HealthCheck/Checks/IndexerLongTermStatusCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/IndexerLongTermStatusCheck.cs index 9ba7ffd1c..792fe7bd9 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/IndexerLongTermStatusCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/IndexerLongTermStatusCheck.cs @@ -9,6 +9,7 @@ namespace NzbDrone.Core.HealthCheck.Checks { [CheckOn(typeof(ProviderUpdatedEvent<IIndexer>))] [CheckOn(typeof(ProviderDeletedEvent<IIndexer>))] + [CheckOn(typeof(ProviderBulkDeletedEvent<IIndexer>))] [CheckOn(typeof(ProviderStatusChangedEvent<IIndexer>))] public class IndexerLongTermStatusCheck : HealthCheckBase { diff --git a/src/NzbDrone.Core/HealthCheck/Checks/IndexerStatusCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/IndexerStatusCheck.cs index f7d6ee541..fae67980b 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/IndexerStatusCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/IndexerStatusCheck.cs @@ -9,6 +9,7 @@ namespace NzbDrone.Core.HealthCheck.Checks { [CheckOn(typeof(ProviderUpdatedEvent<IIndexer>))] [CheckOn(typeof(ProviderDeletedEvent<IIndexer>))] + [CheckOn(typeof(ProviderBulkDeletedEvent<IIndexer>))] [CheckOn(typeof(ProviderStatusChangedEvent<IIndexer>))] public class IndexerStatusCheck : HealthCheckBase { diff --git a/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPCheck.cs index eff84cc67..4265b5963 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPCheck.cs @@ -11,6 +11,7 @@ namespace NzbDrone.Core.HealthCheck.Checks [CheckOn(typeof(ProviderAddedEvent<IIndexer>))] [CheckOn(typeof(ProviderUpdatedEvent<IIndexer>))] [CheckOn(typeof(ProviderDeletedEvent<IIndexer>))] + [CheckOn(typeof(ProviderBulkDeletedEvent<IIndexer>))] public class IndexerVIPCheck : HealthCheckBase { private readonly IIndexerFactory _indexerFactory; diff --git a/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPExpiredCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPExpiredCheck.cs index 5170897c4..8b0dd06e7 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPExpiredCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/IndexerVIPExpiredCheck.cs @@ -11,6 +11,7 @@ namespace NzbDrone.Core.HealthCheck.Checks [CheckOn(typeof(ProviderAddedEvent<IIndexer>))] [CheckOn(typeof(ProviderUpdatedEvent<IIndexer>))] [CheckOn(typeof(ProviderDeletedEvent<IIndexer>))] + [CheckOn(typeof(ProviderBulkDeletedEvent<IIndexer>))] public class IndexerVIPExpiredCheck : HealthCheckBase { private readonly IIndexerFactory _indexerFactory; diff --git a/src/NzbDrone.Core/HealthCheck/Checks/NoDefinitionCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/NoDefinitionCheck.cs index 24c49c41d..7849b9426 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/NoDefinitionCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/NoDefinitionCheck.cs @@ -9,6 +9,7 @@ using NzbDrone.Core.ThingiProvider.Events; namespace NzbDrone.Core.HealthCheck.Checks { [CheckOn(typeof(ProviderDeletedEvent<IIndexer>))] + [CheckOn(typeof(ProviderBulkDeletedEvent<IIndexer>))] public class NoDefinitionCheck : HealthCheckBase { private readonly IIndexerDefinitionUpdateService _indexerDefinitionUpdateService; diff --git a/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs index c45c37db6..2fcd67f18 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/OutdatedDefinitionCheck.cs @@ -9,6 +9,7 @@ using NzbDrone.Core.ThingiProvider.Events; namespace NzbDrone.Core.HealthCheck.Checks { [CheckOn(typeof(ProviderDeletedEvent<IIndexer>))] + [CheckOn(typeof(ProviderBulkDeletedEvent<IIndexer>))] public class OutdatedDefinitionCheck : HealthCheckBase { private readonly IIndexerDefinitionUpdateService _indexerDefinitionUpdateService; diff --git a/src/NzbDrone.Core/Indexers/IndexerFactory.cs b/src/NzbDrone.Core/Indexers/IndexerFactory.cs index 022b203b4..a1fa5c659 100644 --- a/src/NzbDrone.Core/Indexers/IndexerFactory.cs +++ b/src/NzbDrone.Core/Indexers/IndexerFactory.cs @@ -10,6 +10,7 @@ using NzbDrone.Core.Indexers.Newznab; using NzbDrone.Core.IndexerVersions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.ThingiProvider.Events; namespace NzbDrone.Core.Indexers { @@ -17,7 +18,6 @@ namespace NzbDrone.Core.Indexers { List<IIndexer> Enabled(bool filterBlockedIndexers = true); List<IIndexer> AllProviders(bool filterBlockedIndexers = true); - void DeleteIndexers(List<int> indexerIds); } public class IndexerFactory : ProviderFactory<IIndexer, IndexerDefinition>, IIndexerFactory @@ -256,18 +256,6 @@ namespace NzbDrone.Core.Indexers } } - public void DeleteIndexers(List<int> indexerIds) - { - var indexersToDelete = _providerRepository.Get(indexerIds).ToList(); - - _providerRepository.DeleteMany(indexerIds); - - foreach (var indexer in indexersToDelete) - { - _logger.Info("Deleted indexer {0}", indexer.Name); - } - } - public override ValidationResult Test(IndexerDefinition definition) { var result = base.Test(definition); diff --git a/src/NzbDrone.Core/ThingiProvider/Events/ProviderBulkDeletedEvent.cs b/src/NzbDrone.Core/ThingiProvider/Events/ProviderBulkDeletedEvent.cs new file mode 100644 index 000000000..c40ee5554 --- /dev/null +++ b/src/NzbDrone.Core/ThingiProvider/Events/ProviderBulkDeletedEvent.cs @@ -0,0 +1,16 @@ +using System.Collections; +using System.Collections.Generic; +using NzbDrone.Common.Messaging; + +namespace NzbDrone.Core.ThingiProvider.Events +{ + public class ProviderBulkDeletedEvent<TProvider> : IEvent + { + public IEnumerable<int> ProviderIds { get; private set; } + + public ProviderBulkDeletedEvent(IEnumerable<int> ids) + { + ProviderIds = ids; + } + } +} diff --git a/src/NzbDrone.Core/ThingiProvider/IProviderFactory.cs b/src/NzbDrone.Core/ThingiProvider/IProviderFactory.cs index 12e249c4b..73b6d5e67 100644 --- a/src/NzbDrone.Core/ThingiProvider/IProviderFactory.cs +++ b/src/NzbDrone.Core/ThingiProvider/IProviderFactory.cs @@ -14,6 +14,7 @@ namespace NzbDrone.Core.ThingiProvider void Update(TProviderDefinition definition); void Update(IEnumerable<TProviderDefinition> definitions); void Delete(int id); + void Delete(IEnumerable<int> ids); IEnumerable<TProviderDefinition> GetDefaultDefinitions(); IEnumerable<TProviderDefinition> GetPresetDefinitions(TProviderDefinition providerDefinition); void SetProviderCharacteristics(TProviderDefinition definition); diff --git a/src/NzbDrone.Core/ThingiProvider/ProviderFactory.cs b/src/NzbDrone.Core/ThingiProvider/ProviderFactory.cs index 47c10e9f8..049fe02a9 100644 --- a/src/NzbDrone.Core/ThingiProvider/ProviderFactory.cs +++ b/src/NzbDrone.Core/ThingiProvider/ProviderFactory.cs @@ -121,6 +121,13 @@ namespace NzbDrone.Core.ThingiProvider _eventAggregator.PublishEvent(new ProviderDeletedEvent<TProvider>(id)); } + public void Delete(IEnumerable<int> ids) + { + _providerRepository.DeleteMany(ids); + + _eventAggregator.PublishEvent(new ProviderBulkDeletedEvent<TProvider>(ids)); + } + public TProvider GetInstance(TProviderDefinition definition) { var type = GetImplementation(definition); diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerEditorController.cs b/src/Prowlarr.Api.V1/Indexers/IndexerEditorController.cs index bde7f5282..38bc7c281 100644 --- a/src/Prowlarr.Api.V1/Indexers/IndexerEditorController.cs +++ b/src/Prowlarr.Api.V1/Indexers/IndexerEditorController.cs @@ -11,13 +11,13 @@ namespace Prowlarr.Api.V1.Indexers [V1ApiController("indexer/editor")] public class IndexerEditorController : Controller { - private readonly IIndexerFactory _indexerService; + private readonly IIndexerFactory _indexerFactory; private readonly IManageCommandQueue _commandQueueManager; private readonly IndexerResourceMapper _resourceMapper; - public IndexerEditorController(IIndexerFactory indexerService, IManageCommandQueue commandQueueManager, IndexerResourceMapper resourceMapper) + public IndexerEditorController(IIndexerFactory indexerFactory, IManageCommandQueue commandQueueManager, IndexerResourceMapper resourceMapper) { - _indexerService = indexerService; + _indexerFactory = indexerFactory; _commandQueueManager = commandQueueManager; _resourceMapper = resourceMapper; } @@ -25,7 +25,7 @@ namespace Prowlarr.Api.V1.Indexers [HttpPut] public IActionResult SaveAll(IndexerEditorResource resource) { - var indexersToUpdate = _indexerService.AllProviders(false).Select(x => (IndexerDefinition)x.Definition).Where(d => resource.IndexerIds.Contains(d.Id)); + var indexersToUpdate = _indexerFactory.AllProviders(false).Select(x => (IndexerDefinition)x.Definition).Where(d => resource.IndexerIds.Contains(d.Id)); foreach (var indexer in indexersToUpdate) { @@ -59,13 +59,13 @@ namespace Prowlarr.Api.V1.Indexers } } - _indexerService.Update(indexersToUpdate); + _indexerFactory.Update(indexersToUpdate); - var indexers = _indexerService.All(); + var indexers = _indexerFactory.All(); foreach (var definition in indexers) { - _indexerService.SetProviderCharacteristics(definition); + _indexerFactory.SetProviderCharacteristics(definition); } return Accepted(_resourceMapper.ToResource(indexers)); @@ -74,7 +74,7 @@ namespace Prowlarr.Api.V1.Indexers [HttpDelete] public object DeleteIndexers([FromBody] IndexerEditorResource resource) { - _indexerService.DeleteIndexers(resource.IndexerIds); + _indexerFactory.Delete(resource.IndexerIds); return new { }; } From 9dde041c99c92e4c6e200d66cd927da38bdd0869 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Dec 2022 00:13:44 -0600 Subject: [PATCH 0677/2320] New: Search by description on add indexer modal Fixes #1000 --- frontend/src/Indexer/Add/AddIndexerModalContent.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Indexer/Add/AddIndexerModalContent.js b/frontend/src/Indexer/Add/AddIndexerModalContent.js index 236e0d747..f334af39e 100644 --- a/frontend/src/Indexer/Add/AddIndexerModalContent.js +++ b/frontend/src/Indexer/Add/AddIndexerModalContent.js @@ -123,7 +123,7 @@ class AddIndexerModalContent extends Component { const filteredIndexers = indexers.filter((indexer) => { const { filter, filterProtocols, filterLanguages, filterPrivacyLevels } = this.state; - if (!indexer.name.toLowerCase().includes(filter.toLocaleLowerCase())) { + if (!indexer.name.toLowerCase().includes(filter.toLocaleLowerCase()) && !indexer.description.toLowerCase().includes(filter.toLocaleLowerCase())) { return false; } From 4d137886bc906a97e3477ad992c745e4e087657d Mon Sep 17 00:00:00 2001 From: Weblate <noreply@weblate.org> Date: Sun, 18 Dec 2022 03:31:41 +0000 Subject: [PATCH 0678/2320] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (468 of 468 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (464 of 464 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (464 of 464 strings) Translated using Weblate (Dutch) Currently translated at 89.6% (416 of 464 strings) Translated using Weblate (German) Currently translated at 100.0% (464 of 464 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (464 of 464 strings) Co-authored-by: Csaba <csab0825@gmail.com> Co-authored-by: Havok Dan <havokdan@yahoo.com.br> Co-authored-by: Oskari Lavinto <olavinto@protonmail.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: benniblot <ben2004engler@gmail.com> Co-authored-by: mhng98 <mark.groenewegen@hotmail.com> Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/de.json | 2 +- src/NzbDrone.Core/Localization/Core/fi.json | 2 +- src/NzbDrone.Core/Localization/Core/hu.json | 2 +- src/NzbDrone.Core/Localization/Core/nl.json | 3 ++- src/NzbDrone.Core/Localization/Core/pt_BR.json | 10 +++++++--- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/de.json b/src/NzbDrone.Core/Localization/Core/de.json index 9f5e58d5c..bc04ce3f9 100644 --- a/src/NzbDrone.Core/Localization/Core/de.json +++ b/src/NzbDrone.Core/Localization/Core/de.json @@ -141,7 +141,7 @@ "BackupRetentionHelpText": "Automatische Backups, die älter als die Aufbewahrungsfrist sind, werden automatisch gelöscht", "Backups": "Backups", "BindAddress": "Adresse binden", - "BindAddressHelpText": "Gültige IP-Adresse, \"localhost\" oder \"*\" für alle Netzwerke", + "BindAddressHelpText": "Gültige IP Adresse oder \"*\" für alle Netzwerke", "Branch": "Git-Branch", "BypassProxyForLocalAddresses": "Proxy für lokale Adressen umgehen", "CertificateValidation": "Zertifikat Validierung", diff --git a/src/NzbDrone.Core/Localization/Core/fi.json b/src/NzbDrone.Core/Localization/Core/fi.json index d7eb2c195..eb0ee3a7b 100644 --- a/src/NzbDrone.Core/Localization/Core/fi.json +++ b/src/NzbDrone.Core/Localization/Core/fi.json @@ -35,7 +35,7 @@ "Fixed": "Korjattu", "FocusSearchBox": "Kohdista hakukenttä", "ForMoreInformationOnTheIndividualDownloadClients": "Lue lisää lataustyökalusta painamalla 'Lisätietoja'.", - "HideAdvanced": "Piilota lisäasetukset", + "HideAdvanced": "Piilota edistyneet", "History": "Historia", "MIA": "Puuttuu", "New": "Uusi", diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index fc175aaf4..07d68aabb 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -54,7 +54,7 @@ "BranchUpdateMechanism": "A külső frissítési mechanizmus által használt ágazat", "BranchUpdate": "Ágazattípus a Prowlarr frissítéseihez", "Branch": "Ágazat", - "BindAddressHelpText": "Érvényes IP-cím, localhost, vagy „*” minden interfészhez", + "BindAddressHelpText": "Érvényes IP-cím, localhost vagy '*' minden interfészhez", "BindAddress": "Kapcsolási Cím", "BeforeUpdate": "Alkalmazásfrissítés előtt", "Backups": "Biztonsági Mentés", diff --git a/src/NzbDrone.Core/Localization/Core/nl.json b/src/NzbDrone.Core/Localization/Core/nl.json index bb9c4a586..fbc2832f9 100644 --- a/src/NzbDrone.Core/Localization/Core/nl.json +++ b/src/NzbDrone.Core/Localization/Core/nl.json @@ -419,5 +419,6 @@ "LastExecution": "Laatste Uitvoering", "Queued": "Afwachtend", "Categories": "Categorieën", - "AddSyncProfile": "Synchronisatieprofiel toevoegen" + "AddSyncProfile": "Synchronisatieprofiel toevoegen", + "AudioSearch": "auditief zoeken" } diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index 7a00c054b..6c4c228bb 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -79,7 +79,7 @@ "Backups": "Backups", "BeforeUpdate": "Antes da atualização", "BindAddress": "Endereço de vínculo", - "BindAddressHelpText": "Endereço IP4 válido ou \"*\" para todas as interfaces", + "BindAddressHelpText": "Endereço IP válido, localhost ou '*' para todas as interfaces", "Branch": "Ramificação", "BranchUpdate": "Ramificação para atualização do Prowlarr", "BypassProxyForLocalAddresses": "Ignorar proxy para endereços locais", @@ -447,7 +447,7 @@ "AddSyncProfile": "Adicionar Perfil de Sincronização", "MinimumSeeders": "Mínimo de Seeders", "MinimumSeedersHelpText": "Semeadores mínimos exigidos pelo aplicativo para o indexador baixar", - "ThemeHelpText": "Altere o tema da IU do Prowlarr, inspirado em {0}", + "ThemeHelpText": "Alterar o tema da interface do usuário do aplicativo, o tema 'Auto' usará o tema do sistema operacional para definir o modo Claro ou Escuro. Inspirado por {0}", "InstanceName": "Nome da instância", "InstanceNameHelpText": "Nome da instância na guia e para o nome do aplicativo Syslog", "Duration": "Duração", @@ -462,5 +462,9 @@ "NextExecution": "Próxima Execução", "Started": "Iniciado", "ApplicationLongTermStatusCheckAllClientMessage": "Todos os aplicativos estão indisponíveis devido a falhas por mais de 6 horas", - "ApplicationLongTermStatusCheckSingleClientMessage": "Aplicativos indisponíveis devido a falhas por mais de 6 horas: {0}" + "ApplicationLongTermStatusCheckSingleClientMessage": "Aplicativos indisponíveis devido a falhas por mais de 6 horas: {0}", + "AreYouSureYouWantToDeleteCategory": "Tem certeza de que deseja excluir a categoria mapeada?", + "DeleteClientCategory": "Excluir Categoria de Cliente de Download", + "DownloadClientCategory": "Categoria de Download do Cliente", + "MappedCategories": "Categorias Mapeadas" } From 0fa5127c83daa70641c3e9c90f3a5a3682b2eb73 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Dec 2022 12:56:03 -0600 Subject: [PATCH 0679/2320] Cleanup dev logging in UI --- .../DownloadClients/EditDownloadClientModalContent.js | 2 -- frontend/src/Settings/UI/UISettingsConnector.js | 2 -- frontend/src/Store/Actions/Settings/downloadClientCategories.js | 2 -- frontend/src/Store/Actions/releaseActions.js | 2 -- 4 files changed, 8 deletions(-) diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContent.js b/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContent.js index 2e63c2b5f..28554a31c 100644 --- a/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContent.js +++ b/frontend/src/Settings/DownloadClients/DownloadClients/EditDownloadClientModalContent.js @@ -81,8 +81,6 @@ class EditDownloadClientModalContent extends Component { message } = item; - console.log(supportsCategories); - return ( <ModalContent onModalClose={onModalClose}> <ModalHeader> diff --git a/frontend/src/Settings/UI/UISettingsConnector.js b/frontend/src/Settings/UI/UISettingsConnector.js index 98af9dfce..b4ee1d1fe 100644 --- a/frontend/src/Settings/UI/UISettingsConnector.js +++ b/frontend/src/Settings/UI/UISettingsConnector.js @@ -14,8 +14,6 @@ function createLanguagesSelector() { return createSelector( (state) => state.localization, (localization) => { - console.log(localization); - const items = localization.items; if (!items) { diff --git a/frontend/src/Store/Actions/Settings/downloadClientCategories.js b/frontend/src/Store/Actions/Settings/downloadClientCategories.js index a57dc1858..b9fb04404 100644 --- a/frontend/src/Store/Actions/Settings/downloadClientCategories.js +++ b/frontend/src/Store/Actions/Settings/downloadClientCategories.js @@ -113,8 +113,6 @@ export default { const saveData = getProviderState({ id, ...otherPayload }, getState, section, false); - console.log(saveData); - // we have to set id since not actually posting to server yet if (!saveData.id) { saveData.id = getNextId(getState().settings.downloadClientCategories.items); diff --git a/frontend/src/Store/Actions/releaseActions.js b/frontend/src/Store/Actions/releaseActions.js index 7256f9d8d..5e3b172a2 100644 --- a/frontend/src/Store/Actions/releaseActions.js +++ b/frontend/src/Store/Actions/releaseActions.js @@ -310,8 +310,6 @@ export const actionHandlers = handleThunks({ isGrabbing: true })); - console.log(payload); - const promise = createAjaxRequest({ url: '/search/bulk', method: 'POST', From b5aa85a5489cc86d3c9e2208029642710cab9666 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Dec 2022 18:12:18 -0600 Subject: [PATCH 0680/2320] New: (Nebulance) Convert to API --- .../Indexers/Definitions/Nebulance.cs | 246 +++++++++--------- 1 file changed, 125 insertions(+), 121 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs index 7613c74f6..fa43a5fcd 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs @@ -1,23 +1,19 @@ using System; using System.Collections.Generic; -using System.Collections.Specialized; using System.Globalization; -using System.Net.Http; using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using AngleSharp.Html.Parser; -using FluentValidation; +using Newtonsoft.Json; using NLog; +using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { @@ -25,7 +21,6 @@ namespace NzbDrone.Core.Indexers.Definitions { public override string Name => "Nebulance"; public override string[] IndexerUrls => new string[] { "https://nebulance.io/" }; - private string LoginUrl => Settings.BaseUrl + "login.php"; public override string Description => "Nebulance (NBL) is a ratioless Private Torrent Tracker for TV"; public override string Language => "en-US"; public override Encoding Encoding => Encoding.UTF8; @@ -48,53 +43,13 @@ namespace NzbDrone.Core.Indexers.Definitions return new NebulanceParser(Settings, Capabilities.Categories); } - protected override async Task DoLogin() - { - var requestBuilder = new HttpRequestBuilder(LoginUrl) - { - LogResponseContent = true - }; - - requestBuilder.Method = HttpMethod.Post; - requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); - - var cookies = Cookies; - - Cookies = null; - var authLoginRequest = requestBuilder - .AddFormParameter("username", Settings.Username) - .AddFormParameter("password", Settings.Password) - .AddFormParameter("twofa", Settings.TwoFactorAuth) - .AddFormParameter("keeplogged", "on") - .AddFormParameter("login", "Login") - .SetHeader("Content-Type", "multipart/form-data") - .Build(); - - var response = await ExecuteAuth(authLoginRequest); - - cookies = response.GetCookies(); - UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); - - _logger.Debug("Nebulance authentication succeeded."); - } - - protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) - { - if (!httpResponse.Content.Contains("logout.php")) - { - return true; - } - - return false; - } - private IndexerCapabilities SetCapabilities() { var caps = new IndexerCapabilities { TvSearchParams = new List<TvSearchParam> { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId } }; @@ -115,30 +70,16 @@ namespace NzbDrone.Core.Indexers.Definitions { } - private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories) + private IEnumerable<IndexerRequest> GetPagedRequests(NebulanceQuery parameters, int? results, int? offset) { - var searchUrl = string.Format("{0}/torrents.php", Settings.BaseUrl.TrimEnd('/')); + var apiUrl = Settings.BaseUrl + "api.php"; - var searchTerm = term; + var builder = new JsonRpcRequestBuilder(apiUrl) + .Call("getTorrents", Settings.ApiKey, parameters, results ?? 100, offset ?? 0); - if (!string.IsNullOrWhiteSpace(searchTerm)) - { - searchTerm = Regex.Replace(searchTerm, @"[-._]", " "); - } + builder.SuppressHttpError = true; - var qc = new NameValueCollection - { - { "action", "basic" }, - { "order_by", "time" }, - { "order_way", "desc" }, - { "searchtext", searchTerm } - }; - - searchUrl = searchUrl + "?" + qc.GetQueryString(); - - var request = new IndexerRequest(searchUrl, HttpAccept.Html); - - yield return request; + yield return new IndexerRequest(builder.Build()); } public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) @@ -159,7 +100,27 @@ namespace NzbDrone.Core.Indexers.Definitions { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories)); + var queryParams = new NebulanceQuery + { + Age = ">0" + }; + + if (searchCriteria.SanitizedTvSearchString.IsNotNullOrWhiteSpace()) + { + queryParams.Name = "%" + searchCriteria.SanitizedTvSearchString + "%"; + } + + if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace() && int.TryParse(searchCriteria.ImdbId, out var intImdb)) + { + queryParams.Imdb = intImdb; + + if (searchCriteria.EpisodeSearchString.IsNotNullOrWhiteSpace()) + { + queryParams.Name = "%" + searchCriteria.EpisodeSearchString + "%"; + } + } + + pageableRequests.Add(GetPagedRequests(queryParams, searchCriteria.Limit, searchCriteria.Offset)); return pageableRequests; } @@ -175,7 +136,17 @@ namespace NzbDrone.Core.Indexers.Definitions { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + var queryParams = new NebulanceQuery + { + Age = ">0" + }; + + if (searchCriteria.SanitizedSearchTerm.IsNotNullOrWhiteSpace()) + { + queryParams.Name = "%" + searchCriteria.SanitizedSearchTerm + "%"; + } + + pageableRequests.Add(GetPagedRequests(queryParams, searchCriteria.Limit, searchCriteria.Offset)); return pageableRequests; } @@ -199,60 +170,38 @@ namespace NzbDrone.Core.Indexers.Definitions { var torrentInfos = new List<ReleaseInfo>(); - var parser = new HtmlParser(); - var document = parser.ParseDocument(indexerResponse.Content); - var rows = document.QuerySelectorAll(".torrent_table > tbody > tr[class^='torrent row']"); + JsonRpcResponse<NebulanceTorrents> jsonResponse = new HttpResponse<JsonRpcResponse<NebulanceTorrents>>(indexerResponse.HttpResponse).Resource; + + if (jsonResponse.Error != null || jsonResponse.Result == null) + { + throw new IndexerException(indexerResponse, "Indexer API call returned an error [{0}]", jsonResponse.Error); + } + + if (jsonResponse.Result.Items.Count == 0) + { + return torrentInfos; + } + + var rows = jsonResponse.Result.Items; foreach (var row in rows) { - var 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 - { - if (title.Length > 5 && title.Substring(title.Length - 5).Contains(".")) - { - title = title.Remove(title.LastIndexOf(".", StringComparison.Ordinal)); - } - } - - var posterStr = row.QuerySelector("img")?.GetAttribute("src"); - Uri.TryCreate(posterStr, UriKind.Absolute, out var poster); - - var details = _settings.BaseUrl + row.QuerySelector("a[data-src]").GetAttribute("href"); - var link = _settings.BaseUrl + row.QuerySelector("a[href*='action=download']").GetAttribute("href"); - - var qColSize = row.QuerySelector("td:nth-child(3)"); - var size = ParseUtil.GetBytes(qColSize.Children[0].TextContent); - var files = ParseUtil.CoerceInt(qColSize.Children[1].TextContent.Split(':')[1].Trim()); - - var qPublishdate = row.QuerySelector("td:nth-child(4) span"); - var publishDateStr = qPublishdate.GetAttribute("title"); - var publishDate = !string.IsNullOrEmpty(publishDateStr) && publishDateStr.Contains(",") - ? DateTime.ParseExact(publishDateStr, "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture) - : DateTime.ParseExact(qPublishdate.TextContent.Trim(), "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture); - - var grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(5)").TextContent); - var seeds = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(6)").TextContent); - var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(7)").TextContent); + var details = _settings.BaseUrl + "torrents.php?id=" + row.TorrentId; var release = new TorrentInfo { - Title = title, + Title = row.ReleaseTitle, Guid = details, InfoUrl = details, - PosterUrl = poster?.AbsoluteUri ?? null, - DownloadUrl = link, - Categories = new List<IndexerCategory> { TvCategoryFromQualityParser.ParseTvShowQuality(title) }, - Size = size, - Files = files, - PublishDate = publishDate, - Grabs = grabs, - Seeders = seeds, - Peers = seeds + leechers, + PosterUrl = row.Banner, + DownloadUrl = row.Download, + Categories = new List<IndexerCategory> { TvCategoryFromQualityParser.ParseTvShowQuality(row.ReleaseTitle) }, + Size = ParseUtil.CoerceLong(row.Size), + Files = row.FileList.Length, + PublishDate = DateTime.Parse(row.PublishDateUtc, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal), + Grabs = ParseUtil.CoerceInt(row.Snatch), + Seeders = ParseUtil.CoerceInt(row.Seed), + Peers = ParseUtil.CoerceInt(row.Seed) + ParseUtil.CoerceInt(row.Leech), MinimumRatio = 0, // ratioless MinimumSeedTime = 86400, // 24 hours DownloadVolumeFactor = 0, // ratioless tracker @@ -268,14 +217,69 @@ namespace NzbDrone.Core.Indexers.Definitions public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } } - public class NebulanceSettings : UserPassTorrentBaseSettings + public class NebulanceSettings : NoAuthTorrentBaseSettings { public NebulanceSettings() { - TwoFactorAuth = ""; + ApiKey = ""; } - [FieldDefinition(4, Label = "Two Factor Auth", HelpText = "Two-Factor Auth")] - public string TwoFactorAuth { get; set; } + [FieldDefinition(4, Label = "API Key", HelpText = "API Key from User Settings > Api Keys. Key must have List and Download permissions")] + public string ApiKey { get; set; } + } + + public class NebulanceQuery + { + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string Id { get; set; } + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string Time { get; set; } + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string Age { get; set; } + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int Tvmaze { get; set; } + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int Imdb { get; set; } + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string Hash { get; set; } + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string[] Tags { get; set; } + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string Name { get; set; } + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string Category { get; set; } + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string Series { get; set; } + + public NebulanceQuery Clone() + { + return MemberwiseClone() as NebulanceQuery; + } + } + + public class NebulanceTorrent + { + [JsonProperty(PropertyName = "rls_name")] + public string ReleaseTitle { get; set; } + public string Title { get; set; } + public string Size { get; set; } + public string Seed { get; set; } + public string Leech { get; set; } + public string Snatch { get; set; } + public string Download { get; set; } + [JsonProperty(PropertyName = "file_list")] + public string[] FileList { get; set; } + [JsonProperty(PropertyName = "series_banner")] + public string Banner { get; set; } + [JsonProperty(PropertyName = "group_id")] + public string TorrentId { get; set; } + [JsonProperty(PropertyName = "rls_utc")] + public string PublishDateUtc { get; set; } + } + + public class NebulanceTorrents + { + public List<NebulanceTorrent> Items { get; set; } + public int Results { get; set; } } } From 3f9cb2c6eaa9ab3d25b9abe30d2c6da80c2a535f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Dec 2022 20:29:23 -0600 Subject: [PATCH 0681/2320] Fixed: String compare in arr Indexer equality --- src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs | 2 +- src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs | 2 +- src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs | 2 +- src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs | 2 +- src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs b/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs index b2be57c33..2171e1ba9 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Applications.Lidarr var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; - var apiPathCompare = apiPath == otherApiPath; + var apiPathCompare = apiPath.Equals(otherApiPath); var minimumSeeders = Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); var otherMinimumSeeders = other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); diff --git a/src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs b/src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs index 52065160e..25f11b1c0 100644 --- a/src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Applications.Radarr var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; - var apiPathCompare = apiPath == otherApiPath; + var apiPathCompare = apiPath.Equals(otherApiPath); var minimumSeeders = Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); var otherMinimumSeeders = other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); diff --git a/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs b/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs index ef108cba5..e4683ae01 100644 --- a/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Readarr/ReadarrIndexer.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Applications.Readarr var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; - var apiPathCompare = apiPath == otherApiPath; + var apiPathCompare = apiPath.Equals(otherApiPath); var minimumSeeders = Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); var otherMinimumSeeders = other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); diff --git a/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs b/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs index 15adc891d..a2fd4b944 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs @@ -34,7 +34,7 @@ namespace NzbDrone.Core.Applications.Sonarr var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; - var apiPathCompare = apiPath == otherApiPath; + var apiPathCompare = apiPath.Equals(otherApiPath); var minimumSeeders = Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); var otherMinimumSeeders = other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); diff --git a/src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs b/src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs index fc4d33f9a..b1d720360 100644 --- a/src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Whisparr/WhisparrIndexer.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Applications.Whisparr var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; - var apiPathCompare = apiPath == otherApiPath; + var apiPathCompare = apiPath.Equals(otherApiPath); var minimumSeeders = Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); var otherMinimumSeeders = other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value); From 50616f5c9e95de450dc520b6a49f7af81bd68b38 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Dec 2022 20:46:43 -0600 Subject: [PATCH 0682/2320] Fixed: Don't mess with options we don't set on full sync --- src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs | 8 +++++++- src/NzbDrone.Core/Applications/Radarr/Radarr.cs | 8 +++++++- src/NzbDrone.Core/Applications/Readarr/Readarr.cs | 8 +++++++- src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs | 7 ++++++- src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs | 8 +++++++- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs index 8ff099786..ec5421931 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs @@ -7,6 +7,7 @@ using Newtonsoft.Json.Linq; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Applications.Whisparr; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers; @@ -126,6 +127,8 @@ namespace NzbDrone.Core.Applications.Lidarr { if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) { + lidarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => !lidarrIndexer.Fields.Any(s => s.Name == f.Name))); + // Update the indexer if it still has categories that match _lidarrV1Proxy.UpdateIndexer(lidarrIndexer, Settings); } @@ -159,6 +162,7 @@ namespace NzbDrone.Core.Applications.Lidarr { var cacheKey = $"{Settings.BaseUrl}"; var schemas = _schemaCache.Get(cacheKey, () => _lidarrV1Proxy.GetIndexerSchema(Settings), TimeSpan.FromDays(7)); + var syncFields = new string[] { "baseUrl", "apiPath", "apiKey", "categories", "minimumSeeders", "seedCriteria.seedRatio", "seedCriteria.seedTime", "seedCriteria.discographySeedTime" }; var newznab = schemas.Where(i => i.Implementation == "Newznab").First(); var torznab = schemas.Where(i => i.Implementation == "Torznab").First(); @@ -175,9 +179,11 @@ namespace NzbDrone.Core.Applications.Lidarr Priority = indexer.Priority, Implementation = indexer.Protocol == DownloadProtocol.Usenet ? "Newznab" : "Torznab", ConfigContract = schema.ConfigContract, - Fields = schema.Fields, + Fields = new List<LidarrField>() }; + lidarrIndexer.Fields.AddRange(schema.Fields.Where(x => syncFields.Contains(x.Name))); + lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/"; lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/api"; lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey; diff --git a/src/NzbDrone.Core/Applications/Radarr/Radarr.cs b/src/NzbDrone.Core/Applications/Radarr/Radarr.cs index 13e4ffe8a..7faaeb663 100644 --- a/src/NzbDrone.Core/Applications/Radarr/Radarr.cs +++ b/src/NzbDrone.Core/Applications/Radarr/Radarr.cs @@ -7,6 +7,7 @@ using Newtonsoft.Json.Linq; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Applications.Whisparr; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers; @@ -126,6 +127,8 @@ namespace NzbDrone.Core.Applications.Radarr { if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) { + radarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => !radarrIndexer.Fields.Any(s => s.Name == f.Name))); + // Update the indexer if it still has categories that match _radarrV3Proxy.UpdateIndexer(radarrIndexer, Settings); } @@ -159,6 +162,7 @@ namespace NzbDrone.Core.Applications.Radarr { var cacheKey = $"{Settings.BaseUrl}"; var schemas = _schemaCache.Get(cacheKey, () => _radarrV3Proxy.GetIndexerSchema(Settings), TimeSpan.FromDays(7)); + var syncFields = new string[] { "baseUrl", "apiPath", "apiKey", "categories", "minimumSeeders", "seedCriteria.seedRatio", "seedCriteria.seedTime" }; var newznab = schemas.Where(i => i.Implementation == "Newznab").First(); var torznab = schemas.Where(i => i.Implementation == "Torznab").First(); @@ -175,9 +179,11 @@ namespace NzbDrone.Core.Applications.Radarr Priority = indexer.Priority, Implementation = indexer.Protocol == DownloadProtocol.Usenet ? "Newznab" : "Torznab", ConfigContract = schema.ConfigContract, - Fields = schema.Fields, + Fields = new List<RadarrField>() }; + radarrIndexer.Fields.AddRange(schema.Fields.Where(x => syncFields.Contains(x.Name))); + radarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/"; radarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/api"; radarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey; diff --git a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs index 40cc9cc35..ca0fa7f6b 100644 --- a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs +++ b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs @@ -7,6 +7,7 @@ using Newtonsoft.Json.Linq; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Applications.Whisparr; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers; @@ -126,6 +127,8 @@ namespace NzbDrone.Core.Applications.Readarr { if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) { + readarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => !readarrIndexer.Fields.Any(s => s.Name == f.Name))); + // Update the indexer if it still has categories that match _readarrV1Proxy.UpdateIndexer(readarrIndexer, Settings); } @@ -159,6 +162,7 @@ namespace NzbDrone.Core.Applications.Readarr { var cacheKey = $"{Settings.BaseUrl}"; var schemas = _schemaCache.Get(cacheKey, () => _readarrV1Proxy.GetIndexerSchema(Settings), TimeSpan.FromDays(7)); + var syncFields = new string[] { "baseUrl", "apiPath", "apiKey", "categories", "minimumSeeders", "seedCriteria.seedRatio", "seedCriteria.seedTime", "seedCriteria.discographySeedTime" }; var newznab = schemas.Where(i => i.Implementation == "Newznab").First(); var torznab = schemas.Where(i => i.Implementation == "Torznab").First(); @@ -175,9 +179,11 @@ namespace NzbDrone.Core.Applications.Readarr Priority = indexer.Priority, Implementation = indexer.Protocol == DownloadProtocol.Usenet ? "Newznab" : "Torznab", ConfigContract = schema.ConfigContract, - Fields = schema.Fields, + Fields = new List<ReadarrField>() }; + readarrIndexer.Fields.AddRange(schema.Fields.Where(x => syncFields.Contains(x.Name))); + readarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/"; readarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/api"; readarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey; diff --git a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs index 4b62bdad7..1ee7e5f8b 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs @@ -127,6 +127,8 @@ namespace NzbDrone.Core.Applications.Sonarr if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexer.Capabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any()) { // Update the indexer if it still has categories that match + sonarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => !sonarrIndexer.Fields.Any(s => s.Name == f.Name))); + _sonarrV3Proxy.UpdateIndexer(sonarrIndexer, Settings); } else @@ -159,6 +161,7 @@ namespace NzbDrone.Core.Applications.Sonarr { var cacheKey = $"{Settings.BaseUrl}"; var schemas = _schemaCache.Get(cacheKey, () => _sonarrV3Proxy.GetIndexerSchema(Settings), TimeSpan.FromDays(7)); + var syncFields = new string[] { "baseUrl", "apiPath", "apiKey", "categories", "animeCategories", "minimumSeeders", "seedCriteria.seedRatio", "seedCriteria.seedTime", "seedCriteria.seasonPackSeedTime" }; var newznab = schemas.Where(i => i.Implementation == "Newznab").First(); var torznab = schemas.Where(i => i.Implementation == "Torznab").First(); @@ -175,9 +178,11 @@ namespace NzbDrone.Core.Applications.Sonarr Priority = indexer.Priority, Implementation = indexer.Protocol == DownloadProtocol.Usenet ? "Newznab" : "Torznab", ConfigContract = schema.ConfigContract, - Fields = schema.Fields, + Fields = new List<SonarrField>() }; + sonarrIndexer.Fields.AddRange(schema.Fields.Where(x => syncFields.Contains(x.Name))); + sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/"; sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/api"; sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey; diff --git a/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs b/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs index ff6a5966a..cc2ad5d61 100644 --- a/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs +++ b/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs @@ -7,6 +7,7 @@ using Newtonsoft.Json.Linq; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Applications.Sonarr; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers; @@ -126,6 +127,8 @@ namespace NzbDrone.Core.Applications.Whisparr { if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) { + whisparrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => !whisparrIndexer.Fields.Any(s => s.Name == f.Name))); + // Update the indexer if it still has categories that match _whisparrV3Proxy.UpdateIndexer(whisparrIndexer, Settings); } @@ -159,6 +162,7 @@ namespace NzbDrone.Core.Applications.Whisparr { var cacheKey = $"{Settings.BaseUrl}"; var schemas = _schemaCache.Get(cacheKey, () => _whisparrV3Proxy.GetIndexerSchema(Settings), TimeSpan.FromDays(7)); + var syncFields = new string[] { "baseUrl", "apiPath", "apiKey", "categories", "minimumSeeders", "seedCriteria.seedRatio", "seedCriteria.seedTime" }; var newznab = schemas.Where(i => i.Implementation == "Newznab").First(); var torznab = schemas.Where(i => i.Implementation == "Torznab").First(); @@ -175,9 +179,11 @@ namespace NzbDrone.Core.Applications.Whisparr Priority = indexer.Priority, Implementation = indexer.Protocol == DownloadProtocol.Usenet ? "Newznab" : "Torznab", ConfigContract = schema.ConfigContract, - Fields = schema.Fields, + Fields = new List<WhisparrField>() }; + whisparrIndexer.Fields.AddRange(schema.Fields.Where(x => syncFields.Contains(x.Name))); + whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/"; whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/api"; whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey; From ac89cd636fd25531b6b37c9334bcab838227ce57 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Dec 2022 20:51:35 -0600 Subject: [PATCH 0683/2320] New: Separate setting for Pack Seed Time --- src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs | 2 +- src/NzbDrone.Core/Applications/Readarr/Readarr.cs | 2 +- src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs | 2 +- src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs | 3 +++ 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs index ec5421931..f05e0e40c 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs @@ -197,7 +197,7 @@ namespace NzbDrone.Core.Applications.Lidarr if (lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime") != null) { - lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; + lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.PackSeedTime ?? ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; } } diff --git a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs index ca0fa7f6b..0a00524a9 100644 --- a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs +++ b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs @@ -197,7 +197,7 @@ namespace NzbDrone.Core.Applications.Readarr if (readarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime") != null) { - readarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; + readarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.discographySeedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.PackSeedTime ?? ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; } } diff --git a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs index 1ee7e5f8b..032606f00 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs @@ -194,7 +194,7 @@ namespace NzbDrone.Core.Applications.Sonarr sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value = indexer.AppProfile.Value.MinimumSeeders; sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedRatio").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedRatio; sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; - sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seasonPackSeedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; + sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "seedCriteria.seasonPackSeedTime").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.PackSeedTime ?? ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.SeedTime; } return sonarrIndexer; diff --git a/src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs index 622c59e37..cdcd43c03 100644 --- a/src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs @@ -43,5 +43,8 @@ namespace NzbDrone.Core.Indexers [FieldDefinition(2, Type = FieldType.Number, Label = "Seed Time", HelpText = "The time a torrent should be seeded before stopping, empty is app's default", Unit = "minutes", Advanced = true)] public int? SeedTime { get; set; } + + [FieldDefinition(3, Type = FieldType.Number, Label = "Pack Seed Time", HelpText = "The time a pack (season or discography) torrent should be seeded before stopping, empty is app's default", Unit = "minutes", Advanced = true)] + public int? PackSeedTime { get; set; } } } From d959e81efbc2915d2e4d61cfd0b46f24acc39c7e Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Dec 2022 21:19:03 -0600 Subject: [PATCH 0684/2320] Modify Nab tests to pass for additional parameters Fixes #1236 --- src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs | 4 ++-- src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs index e299f1474..db65d782a 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs @@ -181,13 +181,13 @@ namespace NzbDrone.Core.Indexers.Newznab } if (capabilities.MovieSearchParams != null && - new[] { MovieSearchParam.Q, MovieSearchParam.ImdbId }.Any(v => capabilities.MovieSearchParams.Contains(v))) + new[] { MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId, MovieSearchParam.TraktId }.Any(v => capabilities.MovieSearchParams.Contains(v))) { return null; } if (capabilities.TvSearchParams != null && - new[] { TvSearchParam.Q, TvSearchParam.TvdbId, TvSearchParam.TmdbId, TvSearchParam.RId }.Any(v => capabilities.TvSearchParams.Contains(v)) && + new[] { TvSearchParam.Q, TvSearchParam.TvdbId, TvSearchParam.ImdbId, TvSearchParam.TmdbId, TvSearchParam.RId }.Any(v => capabilities.TvSearchParams.Contains(v)) && new[] { TvSearchParam.Season, TvSearchParam.Ep }.All(v => capabilities.TvSearchParams.Contains(v))) { return null; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs index a4515cfe7..57d08c52d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs @@ -157,13 +157,13 @@ namespace NzbDrone.Core.Indexers.Torznab } if (capabilities.MovieSearchParams != null && - new[] { MovieSearchParam.Q, MovieSearchParam.ImdbId }.Any(v => capabilities.MovieSearchParams.Contains(v))) + new[] { MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId, MovieSearchParam.TraktId }.Any(v => capabilities.MovieSearchParams.Contains(v))) { return null; } if (capabilities.TvSearchParams != null && - new[] { TvSearchParam.Q, TvSearchParam.TvdbId, TvSearchParam.RId }.Any(v => capabilities.TvSearchParams.Contains(v)) && + new[] { TvSearchParam.Q, TvSearchParam.TvdbId, TvSearchParam.ImdbId, TvSearchParam.TmdbId, TvSearchParam.RId }.Any(v => capabilities.TvSearchParams.Contains(v)) && new[] { TvSearchParam.Season, TvSearchParam.Ep }.All(v => capabilities.TvSearchParams.Contains(v))) { return null; From a635820b483246b868b4790e02105f8667a764a0 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Dec 2022 21:33:30 -0600 Subject: [PATCH 0685/2320] New: Sync Indexers button on index page Fixes #92 --- frontend/src/Indexer/Index/IndexerIndex.js | 12 ++++++++++++ frontend/src/Indexer/Index/IndexerIndexConnector.js | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/frontend/src/Indexer/Index/IndexerIndex.js b/frontend/src/Indexer/Index/IndexerIndex.js index e8057147c..6d9d79072 100644 --- a/frontend/src/Indexer/Index/IndexerIndex.js +++ b/frontend/src/Indexer/Index/IndexerIndex.js @@ -272,6 +272,7 @@ class IndexerIndex extends Component { saveError, isDeleting, isTestingAll, + isSyncingIndexers, deleteError, onScroll, onSortSelect, @@ -309,6 +310,15 @@ class IndexerIndex extends Component { onPress={this.onAddIndexerPress} /> + <PageToolbarSeparator /> + + <PageToolbarButton + label={translate('SyncAppIndexers')} + iconName={icons.REFRESH} + isSpinning={isSyncingIndexers} + onPress={this.props.onAppIndexerSyncPress} + /> + <PageToolbarButton label={translate('TestAllIndexers')} iconName={icons.TEST} @@ -493,10 +503,12 @@ IndexerIndex.propTypes = { saveError: PropTypes.object, isDeleting: PropTypes.bool.isRequired, isTestingAll: PropTypes.bool.isRequired, + isSyncingIndexers: PropTypes.bool.isRequired, deleteError: PropTypes.object, onSortSelect: PropTypes.func.isRequired, onFilterSelect: PropTypes.func.isRequired, onTestAllPress: PropTypes.func.isRequired, + onAppIndexerSyncPress: PropTypes.func.isRequired, onScroll: PropTypes.func.isRequired, onSaveSelected: PropTypes.func.isRequired }; diff --git a/frontend/src/Indexer/Index/IndexerIndexConnector.js b/frontend/src/Indexer/Index/IndexerIndexConnector.js index e31041c66..a177a628e 100644 --- a/frontend/src/Indexer/Index/IndexerIndexConnector.js +++ b/frontend/src/Indexer/Index/IndexerIndexConnector.js @@ -2,10 +2,13 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; +import * as commandNames from 'Commands/commandNames'; import withScrollPosition from 'Components/withScrollPosition'; +import { executeCommand } from 'Store/Actions/commandActions'; import { testAllIndexers } from 'Store/Actions/indexerActions'; import { saveIndexerEditor, setMovieFilter, setMovieSort, setMovieTableOption } from 'Store/Actions/indexerIndexActions'; import scrollPositions from 'Store/scrollPositions'; +import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector'; import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector'; import createIndexerClientSideCollectionItemsSelector from 'Store/Selectors/createIndexerClientSideCollectionItemsSelector'; import IndexerIndex from './IndexerIndex'; @@ -13,13 +16,16 @@ import IndexerIndex from './IndexerIndex'; function createMapStateToProps() { return createSelector( createIndexerClientSideCollectionItemsSelector('indexerIndex'), + createCommandExecutingSelector(commandNames.APP_INDEXER_SYNC), createDimensionsSelector(), ( indexers, + isSyncingIndexers, dimensionsState ) => { return { ...indexers, + isSyncingIndexers, isSmallScreen: dimensionsState.isSmallScreen }; } @@ -46,6 +52,12 @@ function createMapDispatchToProps(dispatch, props) { onTestAllPress() { dispatch(testAllIndexers()); + }, + + onAppIndexerSyncPress() { + dispatch(executeCommand({ + name: commandNames.APP_INDEXER_SYNC + })); } }; } From dfe132cda24b2b532955bccf7853cb4bbe90de64 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Dec 2022 21:46:14 -0600 Subject: [PATCH 0686/2320] Fixed: Retain direct Indexer properties not affiliated with Prowlarr Fixes #1165 --- src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs | 5 ++++- src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs | 1 + src/NzbDrone.Core/Applications/Radarr/Radarr.cs | 5 ++++- src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs | 1 + src/NzbDrone.Core/Applications/Readarr/Readarr.cs | 1 - src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs | 7 ++++++- src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs | 2 ++ src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs | 1 - 8 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs index f05e0e40c..cafdeaf60 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs @@ -7,7 +7,6 @@ using Newtonsoft.Json.Linq; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; -using NzbDrone.Core.Applications.Whisparr; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers; @@ -127,8 +126,12 @@ namespace NzbDrone.Core.Applications.Lidarr { if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) { + // Retain user fields not-affiliated with Prowlarr lidarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => !lidarrIndexer.Fields.Any(s => s.Name == f.Name))); + // Retain user settings not-affiliated with Prowlarr + lidarrIndexer.DownloadClientId = remoteIndexer.DownloadClientId; + // Update the indexer if it still has categories that match _lidarrV1Proxy.UpdateIndexer(lidarrIndexer, Settings); } diff --git a/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs b/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs index 2171e1ba9..7ac02fd45 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/LidarrIndexer.cs @@ -17,6 +17,7 @@ namespace NzbDrone.Core.Applications.Lidarr public string Implementation { get; set; } public string ConfigContract { get; set; } public string InfoLink { get; set; } + public int? DownloadClientId { get; set; } public HashSet<int> Tags { get; set; } public List<LidarrField> Fields { get; set; } diff --git a/src/NzbDrone.Core/Applications/Radarr/Radarr.cs b/src/NzbDrone.Core/Applications/Radarr/Radarr.cs index 7faaeb663..f55cb83eb 100644 --- a/src/NzbDrone.Core/Applications/Radarr/Radarr.cs +++ b/src/NzbDrone.Core/Applications/Radarr/Radarr.cs @@ -7,7 +7,6 @@ using Newtonsoft.Json.Linq; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; -using NzbDrone.Core.Applications.Whisparr; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers; @@ -127,8 +126,12 @@ namespace NzbDrone.Core.Applications.Radarr { if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) { + // Retain user fields not-affiliated with Prowlarr radarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => !radarrIndexer.Fields.Any(s => s.Name == f.Name))); + // Retain user settings not-affiliated with Prowlarr + radarrIndexer.DownloadClientId = remoteIndexer.DownloadClientId; + // Update the indexer if it still has categories that match _radarrV3Proxy.UpdateIndexer(radarrIndexer, Settings); } diff --git a/src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs b/src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs index 25f11b1c0..38082724e 100644 --- a/src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Radarr/RadarrIndexer.cs @@ -17,6 +17,7 @@ namespace NzbDrone.Core.Applications.Radarr public string Implementation { get; set; } public string ConfigContract { get; set; } public string InfoLink { get; set; } + public int? DownloadClientId { get; set; } public HashSet<int> Tags { get; set; } public List<RadarrField> Fields { get; set; } diff --git a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs index 0a00524a9..324d6c9ab 100644 --- a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs +++ b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs @@ -7,7 +7,6 @@ using Newtonsoft.Json.Linq; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; -using NzbDrone.Core.Applications.Whisparr; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers; diff --git a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs index 032606f00..3584a8734 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs @@ -126,9 +126,14 @@ namespace NzbDrone.Core.Applications.Sonarr { if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexer.Capabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any()) { - // Update the indexer if it still has categories that match + // Retain user fields not-affiliated with Prowlarr sonarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => !sonarrIndexer.Fields.Any(s => s.Name == f.Name))); + // Retain user settings not-affiliated with Prowlarr + sonarrIndexer.DownloadClientId = remoteIndexer.DownloadClientId; + sonarrIndexer.SeasonSearchMaximumSingleEpisodeAge = remoteIndexer.SeasonSearchMaximumSingleEpisodeAge; + + // Update the indexer if it still has categories that match _sonarrV3Proxy.UpdateIndexer(sonarrIndexer, Settings); } else diff --git a/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs b/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs index a2fd4b944..e3dffaed0 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/SonarrIndexer.cs @@ -17,6 +17,8 @@ namespace NzbDrone.Core.Applications.Sonarr public string Implementation { get; set; } public string ConfigContract { get; set; } public string InfoLink { get; set; } + public int? DownloadClientId { get; set; } + public int? SeasonSearchMaximumSingleEpisodeAge { get; set; } public HashSet<int> Tags { get; set; } public List<SonarrField> Fields { get; set; } diff --git a/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs b/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs index cc2ad5d61..11464ed2e 100644 --- a/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs +++ b/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs @@ -7,7 +7,6 @@ using Newtonsoft.Json.Linq; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; -using NzbDrone.Core.Applications.Sonarr; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers; From 57dcd861a9dc5178e6975d3ef1d534c1accb79a0 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Sun, 18 Dec 2022 23:20:46 -0600 Subject: [PATCH 0687/2320] Fixed: Validation for nested settings not running Prevents #1243 --- .../Definitions/Cardigann/CardigannSettings.cs | 15 +-------------- .../Definitions/Headphones/HeadphonesSettings.cs | 1 + .../Definitions/Newznab/NewznabSettings.cs | 1 + .../Definitions/Torznab/TorznabSettings.cs | 2 ++ src/NzbDrone.Core/Indexers/IndexerBaseSettings.cs | 5 +++++ .../Settings/CookieTorrentBaseSettings.cs | 2 ++ .../Settings/NoAuthTorrentBaseSettings.cs | 5 +++++ .../Settings/UserPassTorrentBaseSettings.cs | 2 ++ 8 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannSettings.cs index 9b1ef4e15..9a75ffd28 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannSettings.cs @@ -1,22 +1,14 @@ using System.Collections.Generic; using FluentValidation; +using FluentValidation.Results; using NzbDrone.Core.Annotations; using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Cardigann { - public class CardigannSettingsValidator : AbstractValidator<CardigannSettings> - { - public CardigannSettingsValidator() - { - } - } - public class CardigannSettings : NoAuthTorrentBaseSettings { - private static readonly CardigannSettingsValidator Validator = new CardigannSettingsValidator(); - public CardigannSettings() { ExtraFieldData = new Dictionary<string, object>(); @@ -26,10 +18,5 @@ namespace NzbDrone.Core.Indexers.Cardigann public string DefinitionFile { get; set; } public Dictionary<string, object> ExtraFieldData { get; set; } - - public override NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Headphones/HeadphonesSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Headphones/HeadphonesSettings.cs index f24062086..0f854f715 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Headphones/HeadphonesSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Headphones/HeadphonesSettings.cs @@ -10,6 +10,7 @@ namespace NzbDrone.Core.Indexers.Headphones { RuleFor(c => c.Username).NotEmpty(); RuleFor(c => c.Password).NotEmpty(); + RuleFor(x => x.BaseSettings).SetValidator(new IndexerCommonSettingsValidator()); } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabSettings.cs index 7dc8c4d84..ceab10935 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabSettings.cs @@ -35,6 +35,7 @@ namespace NzbDrone.Core.Indexers.Newznab public NewznabSettingsValidator() { + RuleFor(x => x.BaseSettings).SetValidator(new IndexerCommonSettingsValidator()); RuleFor(c => c.BaseUrl).ValidRootUrl(); RuleFor(c => c.ApiPath).ValidUrlBase("/api"); RuleFor(c => c.ApiKey).NotEmpty().When(ShouldHaveApiKey); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabSettings.cs index c1ea89cc9..4f4547fd6 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabSettings.cs @@ -29,6 +29,8 @@ namespace NzbDrone.Core.Indexers.Torznab public TorznabSettingsValidator() { + RuleFor(x => x.BaseSettings).SetValidator(new IndexerCommonSettingsValidator()); + RuleFor(x => x.TorrentBaseSettings).SetValidator(new IndexerTorrentSettingsValidator()); RuleFor(c => c.BaseUrl).ValidRootUrl(); RuleFor(c => c.ApiPath).ValidUrlBase("/api"); RuleFor(c => c.ApiKey).NotEmpty().When(ShouldHaveApiKey); diff --git a/src/NzbDrone.Core/Indexers/IndexerBaseSettings.cs b/src/NzbDrone.Core/Indexers/IndexerBaseSettings.cs index c3e3019bd..600d4d7d9 100644 --- a/src/NzbDrone.Core/Indexers/IndexerBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/IndexerBaseSettings.cs @@ -1,5 +1,7 @@ using FluentValidation; using NzbDrone.Core.Annotations; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers { @@ -7,6 +9,9 @@ namespace NzbDrone.Core.Indexers { public IndexerCommonSettingsValidator() { + RuleFor(c => c.QueryLimit).GreaterThan(0).When(c => c.QueryLimit.HasValue).WithMessage("Should be greater than zero"); + + RuleFor(c => c.GrabLimit).GreaterThan(0).When(c => c.GrabLimit.HasValue).WithMessage("Should be greater than zero"); } } diff --git a/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs index b337c5339..81cef47ba 100644 --- a/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/Settings/CookieTorrentBaseSettings.cs @@ -11,6 +11,8 @@ namespace NzbDrone.Core.Indexers.Settings public CookieBaseSettingsValidator() { RuleFor(c => c.Cookie).NotEmpty(); + RuleFor(x => x.BaseSettings).SetValidator(new IndexerCommonSettingsValidator()); + RuleFor(x => x.TorrentBaseSettings).SetValidator(new IndexerTorrentSettingsValidator()); } } diff --git a/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs index c2922551a..b9fd2688f 100644 --- a/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs @@ -6,6 +6,11 @@ namespace NzbDrone.Core.Indexers.Settings { public class NoAuthSettingsValidator : AbstractValidator<NoAuthTorrentBaseSettings> { + public NoAuthSettingsValidator() + { + RuleFor(x => x.BaseSettings).SetValidator(new IndexerCommonSettingsValidator()); + RuleFor(x => x.TorrentBaseSettings).SetValidator(new IndexerTorrentSettingsValidator()); + } } public class NoAuthTorrentBaseSettings : ITorrentIndexerSettings diff --git a/src/NzbDrone.Core/Indexers/Settings/UserPassTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/Settings/UserPassTorrentBaseSettings.cs index 07ef1f193..e8c7f2709 100644 --- a/src/NzbDrone.Core/Indexers/Settings/UserPassTorrentBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/Settings/UserPassTorrentBaseSettings.cs @@ -12,6 +12,8 @@ namespace NzbDrone.Core.Indexers.Settings { RuleFor(c => c.Username).NotEmpty(); RuleFor(c => c.Password).NotEmpty(); + RuleFor(x => x.BaseSettings).SetValidator(new IndexerCommonSettingsValidator()); + RuleFor(x => x.TorrentBaseSettings).SetValidator(new IndexerTorrentSettingsValidator()); } } From 810b3612aadb0fc63c2de80af1517bd9df375c20 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 20 Dec 2022 12:34:56 -0600 Subject: [PATCH 0688/2320] Fixed: Mapping of Year, Genre, other from search string --- frontend/src/History/HistoryRow.js | 45 +++++++++++++ src/NzbDrone.Core/History/HistoryService.cs | 11 ++++ .../IndexerSearch/NewznabRequest.cs | 65 +++++++++++++++++-- 3 files changed, 116 insertions(+), 5 deletions(-) diff --git a/frontend/src/History/HistoryRow.js b/frontend/src/History/HistoryRow.js index 0ebe3deb4..7cc08fc1b 100644 --- a/frontend/src/History/HistoryRow.js +++ b/frontend/src/History/HistoryRow.js @@ -226,6 +226,42 @@ class HistoryRow extends Component { null } + { + data.label ? + <HistoryRowParameter + title='Label' + value={data.label} + /> : + null + } + + { + data.track ? + <HistoryRowParameter + title='Track' + value={data.track} + /> : + null + } + + { + data.year ? + <HistoryRowParameter + title='Year' + value={data.year} + /> : + null + } + + { + data.genre ? + <HistoryRowParameter + title='Genre' + value={data.genre} + /> : + null + } + { data.author ? <HistoryRowParameter @@ -243,6 +279,15 @@ class HistoryRow extends Component { /> : null } + + { + data.publisher ? + <HistoryRowParameter + title='Publisher' + value={data.publisher} + /> : + null + } </TableRowCell> ); } diff --git a/src/NzbDrone.Core/History/HistoryService.cs b/src/NzbDrone.Core/History/HistoryService.cs index a06636d42..cd3ba6b3d 100644 --- a/src/NzbDrone.Core/History/HistoryService.cs +++ b/src/NzbDrone.Core/History/HistoryService.cs @@ -130,6 +130,8 @@ namespace NzbDrone.Core.History history.Data.Add("ImdbId", ((MovieSearchCriteria)message.Query).FullImdbId ?? string.Empty); history.Data.Add("TmdbId", ((MovieSearchCriteria)message.Query).TmdbId?.ToString() ?? string.Empty); history.Data.Add("TraktId", ((MovieSearchCriteria)message.Query).TraktId?.ToString() ?? string.Empty); + history.Data.Add("Year", ((MovieSearchCriteria)message.Query).Year?.ToString() ?? string.Empty); + history.Data.Add("Genre", ((MovieSearchCriteria)message.Query).Genre ?? string.Empty); } if (message.Query is TvSearchCriteria) @@ -142,18 +144,27 @@ namespace NzbDrone.Core.History history.Data.Add("TvMazeId", ((TvSearchCriteria)message.Query).TvMazeId?.ToString() ?? string.Empty); history.Data.Add("Season", ((TvSearchCriteria)message.Query).Season?.ToString() ?? string.Empty); history.Data.Add("Episode", ((TvSearchCriteria)message.Query).Episode ?? string.Empty); + history.Data.Add("Year", ((TvSearchCriteria)message.Query).Year?.ToString() ?? string.Empty); + history.Data.Add("Genre", ((TvSearchCriteria)message.Query).Genre ?? string.Empty); } if (message.Query is MusicSearchCriteria) { history.Data.Add("Artist", ((MusicSearchCriteria)message.Query).Artist ?? string.Empty); history.Data.Add("Album", ((MusicSearchCriteria)message.Query).Album ?? string.Empty); + history.Data.Add("Track", ((MusicSearchCriteria)message.Query).Track ?? string.Empty); + history.Data.Add("Label", ((MusicSearchCriteria)message.Query).Label ?? string.Empty); + history.Data.Add("Year", ((MusicSearchCriteria)message.Query).Year?.ToString() ?? string.Empty); + history.Data.Add("Genre", ((MusicSearchCriteria)message.Query).Genre ?? string.Empty); } if (message.Query is BookSearchCriteria) { history.Data.Add("Author", ((BookSearchCriteria)message.Query).Author ?? string.Empty); history.Data.Add("BookTitle", ((BookSearchCriteria)message.Query).Title ?? string.Empty); + history.Data.Add("Publisher", ((BookSearchCriteria)message.Query).Publisher ?? string.Empty); + history.Data.Add("Year", ((BookSearchCriteria)message.Query).Year?.ToString() ?? string.Empty); + history.Data.Add("Genre", ((BookSearchCriteria)message.Query).Genre ?? string.Empty); } history.Data.Add("ElapsedTime", message.QueryResult.Response?.ElapsedTime.ToString() ?? string.Empty); diff --git a/src/NzbDrone.Core/IndexerSearch/NewznabRequest.cs b/src/NzbDrone.Core/IndexerSearch/NewznabRequest.cs index b8ba22e76..5d5e82fb3 100644 --- a/src/NzbDrone.Core/IndexerSearch/NewznabRequest.cs +++ b/src/NzbDrone.Core/IndexerSearch/NewznabRequest.cs @@ -4,10 +4,10 @@ namespace NzbDrone.Core.IndexerSearch { public class NewznabRequest { - private static readonly Regex TvRegex = new Regex(@"\{((?:imdbid\:)(?<imdbid>[^{]+)|(?:tvdbid\:)(?<tvdbid>[^{]+)|(?:tmdbid\:)(?<tmdbid>[^{]+)|(?:doubanid\:)(?<doubanid>[^{]+)|(?:season\:)(?<season>[^{]+)|(?:episode\:)(?<episode>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); - private static readonly Regex MovieRegex = new Regex(@"\{((?:imdbid\:)(?<imdbid>[^{]+)|(?:doubanid\:)(?<doubanid>[^{]+)|(?:tmdbid\:)(?<tmdbid>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); - private static readonly Regex MusicRegex = new Regex(@"\{((?:artist\:)(?<artist>[^{]+)|(?:album\:)(?<album>[^{]+)|(?:track\:)(?<track>[^{]+)|(?:label\:)(?<label>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); - private static readonly Regex BookRegex = new Regex(@"\{((?:author\:)(?<author>[^{]+)|(?:publisher\:)(?<publisher>[^{]+)|(?:title\:)(?<title>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex TvRegex = new Regex(@"\{((?:imdbid\:)(?<imdbid>[^{]+)|(?:rid\:)(?<rid>[^{]+)|(?:tvdbid\:)(?<tvdbid>[^{]+)|(?:tmdbid\:)(?<tmdbid>[^{]+)|(?:doubanid\:)(?<doubanid>[^{]+)|(?:season\:)(?<season>[^{]+)|(?:episode\:)(?<episode>[^{]+)|(?:year\:)(?<year>[^{]+)|(?:genre\:)(?<genre>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex MovieRegex = new Regex(@"\{((?:imdbid\:)(?<imdbid>[^{]+)|(?:doubanid\:)(?<doubanid>[^{]+)|(?:tmdbid\:)(?<tmdbid>[^{]+)|(?:traktid\:)(?<traktid>[^{]+)|(?:year\:)(?<year>[^{]+)|(?:genre\:)(?<genre>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex MusicRegex = new Regex(@"\{((?:artist\:)(?<artist>[^{]+)|(?:album\:)(?<album>[^{]+)|(?:track\:)(?<track>[^{]+)|(?:label\:)(?<label>[^{]+)|(?:year\:)(?<year>[^{]+)|(?:genre\:)(?<genre>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex BookRegex = new Regex(@"\{((?:author\:)(?<author>[^{]+)|(?:publisher\:)(?<publisher>[^{]+)|(?:title\:)(?<title>[^{]+)|(?:year\:)(?<year>[^{]+)|(?:genre\:)(?<genre>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); public string t { get; set; } public string q { get; set; } @@ -61,6 +61,11 @@ namespace NzbDrone.Core.IndexerSearch doubanid = int.TryParse(match.Groups["doubanid"].Value, out var tmdb) ? tmdb : null; } + if (match.Groups["rid"].Success) + { + rid = int.TryParse(match.Groups["rid"].Value, out var rId) ? rId : null; + } + if (match.Groups["season"].Success) { season = int.TryParse(match.Groups["season"].Value, out var seasonParsed) ? seasonParsed : null; @@ -71,11 +76,26 @@ namespace NzbDrone.Core.IndexerSearch imdbid = match.Groups["imdbid"].Value; } + if (match.Groups["traktid"].Success) + { + traktid = int.TryParse(match.Groups["traktid"].Value, out var trackId) ? trackId : null; + } + if (match.Groups["episode"].Success) { ep = match.Groups["episode"].Value; } + if (match.Groups["year"].Success) + { + year = int.TryParse(match.Groups["year"].Value, out var parsedYear) ? parsedYear : null; + } + + if (match.Groups["genre"].Success) + { + genre = match.Groups["genre"].Value; + } + q = q.Replace(match.Value, ""); } } @@ -93,7 +113,7 @@ namespace NzbDrone.Core.IndexerSearch if (match.Groups["doubanid"].Success) { - doubanid = int.TryParse(match.Groups["doubanid"].Value, out var tmdb) ? tmdb : null; + doubanid = int.TryParse(match.Groups["doubanid"].Value, out var doubanId) ? doubanId : null; } if (match.Groups["imdbid"].Success) @@ -101,6 +121,21 @@ namespace NzbDrone.Core.IndexerSearch imdbid = match.Groups["imdbid"].Value; } + if (match.Groups["traktid"].Success) + { + traktid = int.TryParse(match.Groups["traktid"].Value, out var trackId) ? trackId : null; + } + + if (match.Groups["year"].Success) + { + year = int.TryParse(match.Groups["year"].Value, out var parsedYear) ? parsedYear : null; + } + + if (match.Groups["genre"].Success) + { + genre = match.Groups["genre"].Value; + } + q = q.Replace(match.Value, "").Trim(); } } @@ -131,6 +166,16 @@ namespace NzbDrone.Core.IndexerSearch label = match.Groups["label"].Value; } + if (match.Groups["year"].Success) + { + year = int.TryParse(match.Groups["year"].Value, out var parsedYear) ? parsedYear : null; + } + + if (match.Groups["genre"].Success) + { + genre = match.Groups["genre"].Value; + } + q = q.Replace(match.Value, "").Trim(); } } @@ -156,6 +201,16 @@ namespace NzbDrone.Core.IndexerSearch publisher = match.Groups["publisher"].Value; } + if (match.Groups["year"].Success) + { + year = int.TryParse(match.Groups["year"].Value, out var parsedYear) ? parsedYear : null; + } + + if (match.Groups["genre"].Success) + { + genre = match.Groups["genre"].Value; + } + q = q.Replace(match.Value, "").Trim(); } } From 6bb8c09fcfbca2115b29147333aa78daab7ee69e Mon Sep 17 00:00:00 2001 From: Bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Mon, 28 Nov 2022 19:18:58 -0600 Subject: [PATCH 0689/2320] Log Skipped Application-Indexer Syncs at trace for support --- src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarian.cs | 2 ++ src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs | 2 ++ src/NzbDrone.Core/Applications/Mylar/Mylar.cs | 2 ++ src/NzbDrone.Core/Applications/Radarr/Radarr.cs | 2 ++ src/NzbDrone.Core/Applications/Readarr/Readarr.cs | 2 ++ src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs | 2 ++ src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs | 2 ++ 7 files changed, 14 insertions(+) diff --git a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarian.cs b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarian.cs index 763735d51..26ba2392f 100644 --- a/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarian.cs +++ b/src/NzbDrone.Core/Applications/LazyLibrarian/LazyLibrarian.cs @@ -74,6 +74,8 @@ namespace NzbDrone.Core.Applications.LazyLibrarian var remoteIndexer = _lazyLibrarianV1Proxy.AddIndexer(lazyLibrarianIndexer, Settings); _appIndexerMapService.Insert(new AppIndexerMap { AppId = Definition.Id, IndexerId = indexer.Id, RemoteIndexerName = $"{remoteIndexer.Type},{remoteIndexer.Name}" }); } + + _logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id); } public override void RemoveIndexer(int indexerId) diff --git a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs index cafdeaf60..457d05063 100644 --- a/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs +++ b/src/NzbDrone.Core/Applications/Lidarr/Lidarr.cs @@ -91,6 +91,8 @@ namespace NzbDrone.Core.Applications.Lidarr var remoteIndexer = _lidarrV1Proxy.AddIndexer(lidarrIndexer, Settings); _appIndexerMapService.Insert(new AppIndexerMap { AppId = Definition.Id, IndexerId = indexer.Id, RemoteIndexerId = remoteIndexer.Id }); } + + _logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id); } public override void RemoveIndexer(int indexerId) diff --git a/src/NzbDrone.Core/Applications/Mylar/Mylar.cs b/src/NzbDrone.Core/Applications/Mylar/Mylar.cs index 195c3e555..69c92b949 100644 --- a/src/NzbDrone.Core/Applications/Mylar/Mylar.cs +++ b/src/NzbDrone.Core/Applications/Mylar/Mylar.cs @@ -75,6 +75,8 @@ namespace NzbDrone.Core.Applications.Mylar var remoteIndexer = _mylarV3Proxy.AddIndexer(mylarIndexer, Settings); _appIndexerMapService.Insert(new AppIndexerMap { AppId = Definition.Id, IndexerId = indexer.Id, RemoteIndexerName = $"{remoteIndexer.Type},{remoteIndexer.Name}" }); } + + _logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id); } public override void RemoveIndexer(int indexerId) diff --git a/src/NzbDrone.Core/Applications/Radarr/Radarr.cs b/src/NzbDrone.Core/Applications/Radarr/Radarr.cs index f55cb83eb..22bf80fb9 100644 --- a/src/NzbDrone.Core/Applications/Radarr/Radarr.cs +++ b/src/NzbDrone.Core/Applications/Radarr/Radarr.cs @@ -91,6 +91,8 @@ namespace NzbDrone.Core.Applications.Radarr var remoteIndexer = _radarrV3Proxy.AddIndexer(radarrIndexer, Settings); _appIndexerMapService.Insert(new AppIndexerMap { AppId = Definition.Id, IndexerId = indexer.Id, RemoteIndexerId = remoteIndexer.Id }); } + + _logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id); } public override void RemoveIndexer(int indexerId) diff --git a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs index 324d6c9ab..8b00f2b07 100644 --- a/src/NzbDrone.Core/Applications/Readarr/Readarr.cs +++ b/src/NzbDrone.Core/Applications/Readarr/Readarr.cs @@ -91,6 +91,8 @@ namespace NzbDrone.Core.Applications.Readarr var remoteIndexer = _readarrV1Proxy.AddIndexer(readarrIndexer, Settings); _appIndexerMapService.Insert(new AppIndexerMap { AppId = Definition.Id, IndexerId = indexer.Id, RemoteIndexerId = remoteIndexer.Id }); } + + _logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id); } public override void RemoveIndexer(int indexerId) diff --git a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs index 3584a8734..c1b73fd55 100644 --- a/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs +++ b/src/NzbDrone.Core/Applications/Sonarr/Sonarr.cs @@ -91,6 +91,8 @@ namespace NzbDrone.Core.Applications.Sonarr var remoteIndexer = _sonarrV3Proxy.AddIndexer(sonarrIndexer, Settings); _appIndexerMapService.Insert(new AppIndexerMap { AppId = Definition.Id, IndexerId = indexer.Id, RemoteIndexerId = remoteIndexer.Id }); } + + _logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id); } public override void RemoveIndexer(int indexerId) diff --git a/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs b/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs index 11464ed2e..447dc561d 100644 --- a/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs +++ b/src/NzbDrone.Core/Applications/Whisparr/Whisparr.cs @@ -91,6 +91,8 @@ namespace NzbDrone.Core.Applications.Whisparr var remoteIndexer = _whisparrV3Proxy.AddIndexer(radarrIndexer, Settings); _appIndexerMapService.Insert(new AppIndexerMap { AppId = Definition.Id, IndexerId = indexer.Id, RemoteIndexerId = remoteIndexer.Id }); } + + _logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id); } public override void RemoveIndexer(int indexerId) From 3b266133948bf965abd71d448ae0675231b40c99 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 20 Dec 2022 13:38:01 -0600 Subject: [PATCH 0690/2320] Fixed: (Pornolab) Update Categories Co-Authored-By: ilike2burnthing <59480337+ilike2burnthing@users.noreply.github.com> --- src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs b/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs index 8293a42c0..4ff626743 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PornoLab.cs @@ -108,9 +108,9 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1111, NewznabStandardCategory.XXXPack, "Паки полных фильмов / Full Length Movies Packs"); caps.Categories.AddCategoryMapping(508, NewznabStandardCategory.XXX, "Классические фильмы / Classic"); caps.Categories.AddCategoryMapping(555, NewznabStandardCategory.XXX, "Фильмы с сюжетом / Feature & Vignettes"); - caps.Categories.AddCategoryMapping(1673, NewznabStandardCategory.XXX, "Гонзо-фильмы 2011-2021 / Gonzo 2011-2021"); + caps.Categories.AddCategoryMapping(1673, NewznabStandardCategory.XXX, "Гонзо-фильмы 2011-2023 / Gonzo 2011-2023"); caps.Categories.AddCategoryMapping(1112, NewznabStandardCategory.XXX, "Фильмы без сюжета 1991-2010 / All Sex & Amateur 1991-2010"); - caps.Categories.AddCategoryMapping(1718, NewznabStandardCategory.XXX, "Фильмы без сюжета 2011-2021 / All Sex & Amateur 2011-2021"); + caps.Categories.AddCategoryMapping(1718, NewznabStandardCategory.XXX, "Фильмы без сюжета 2011-2023 / All Sex & Amateur 2011-2023"); caps.Categories.AddCategoryMapping(553, NewznabStandardCategory.XXX, "Лесбо-фильмы / All Girl & Solo"); caps.Categories.AddCategoryMapping(1143, NewznabStandardCategory.XXX, "Этнические фильмы / Ethnic-Themed"); caps.Categories.AddCategoryMapping(1646, NewznabStandardCategory.XXX, "Видео для телефонов и КПК / Pocket РС & Phone Video"); @@ -125,8 +125,8 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1675, NewznabStandardCategory.XXXPack, "Паки русских порнороликов / Russian Clips Packs"); caps.Categories.AddCategoryMapping(36, NewznabStandardCategory.XXX, "Сайтрипы с русскими актрисами 1991-2015 / Russian SiteRip's 1991-2015"); caps.Categories.AddCategoryMapping(1830, NewznabStandardCategory.XXX, "Сайтрипы с русскими актрисами 1991-2015 (HD Video) / Russian SiteRip's 1991-2015 (HD Video)"); - caps.Categories.AddCategoryMapping(1803, NewznabStandardCategory.XXX, "Сайтрипы с русскими актрисами 2016-2021 / Russian SiteRip's 2016-2021"); - caps.Categories.AddCategoryMapping(1831, NewznabStandardCategory.XXX, "Сайтрипы с русскими актрисами 2016-2021 (HD Video) / Russian SiteRip's 2016-2021 (HD Video)"); + caps.Categories.AddCategoryMapping(1803, NewznabStandardCategory.XXX, "Сайтрипы с русскими актрисами 2016-2023 / Russian SiteRip's 2016-2023"); + caps.Categories.AddCategoryMapping(1831, NewznabStandardCategory.XXX, "Сайтрипы с русскими актрисами 2016-2023 (HD Video) / Russian SiteRip's 2016-2023 (HD Video)"); caps.Categories.AddCategoryMapping(1741, NewznabStandardCategory.XXX, "Русские Порноролики Разное / Russian Clips (various)"); caps.Categories.AddCategoryMapping(1676, NewznabStandardCategory.XXX, "Русское любительское видео / Russian Amateur Video"); @@ -145,6 +145,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1842, NewznabStandardCategory.XXX, "Сайтрипы 2020 (HD Video) / SiteRip's 2020 (HD Video)"); caps.Categories.AddCategoryMapping(1846, NewznabStandardCategory.XXX, "Сайтрипы 2021 (HD Video) / SiteRip's 2021 (HD Video)"); caps.Categories.AddCategoryMapping(1857, NewznabStandardCategory.XXX, "Сайтрипы 2022 (HD Video) / SiteRip's 2022 (HD Video)"); + caps.Categories.AddCategoryMapping(1861, NewznabStandardCategory.XXX, "Сайтрипы 2023 (HD Video) / SiteRip's 2023 (HD Video)"); caps.Categories.AddCategoryMapping(1451, NewznabStandardCategory.XXX, "Сайтрипы 1991-2010 / SiteRip's 1991-2010"); caps.Categories.AddCategoryMapping(1788, NewznabStandardCategory.XXX, "Сайтрипы 2011-2012 / SiteRip's 2011-2012"); @@ -158,6 +159,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1843, NewznabStandardCategory.XXX, "Сайтрипы 2020 / SiteRip's 2020"); caps.Categories.AddCategoryMapping(1847, NewznabStandardCategory.XXX, "Сайтрипы 2021 / SiteRip's 2021"); caps.Categories.AddCategoryMapping(1856, NewznabStandardCategory.XXX, "Сайтрипы 2022 / SiteRip's 2022"); + caps.Categories.AddCategoryMapping(1862, NewznabStandardCategory.XXX, "Сайтрипы 2023 / SiteRip's 2023"); caps.Categories.AddCategoryMapping(1707, NewznabStandardCategory.XXX, "Сцены из фильмов / Movie Scenes"); caps.Categories.AddCategoryMapping(284, NewznabStandardCategory.XXX, "Порноролики Разное / Clips (various)"); @@ -166,7 +168,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1801, NewznabStandardCategory.XXXPack, "Паки японских фильмов и сайтрипов / Full Length Japanese Movies Packs & SiteRip's Packs"); caps.Categories.AddCategoryMapping(1719, NewznabStandardCategory.XXX, "Японские фильмы и сайтрипы (DVD и HD Video) / Japanese Movies & SiteRip's (DVD & HD Video)"); caps.Categories.AddCategoryMapping(997, NewznabStandardCategory.XXX, "Японские фильмы и сайтрипы 1991-2014 / Japanese Movies & SiteRip's 1991-2014"); - caps.Categories.AddCategoryMapping(1818, NewznabStandardCategory.XXX, "Японские фильмы и сайтрипы 2015-2019 / Japanese Movies & SiteRip's 2015-2019"); + caps.Categories.AddCategoryMapping(1818, NewznabStandardCategory.XXX, "Японские фильмы и сайтрипы 2015-2023 / Japanese Movies & SiteRip's 2015-2023"); caps.Categories.AddCategoryMapping(1671, NewznabStandardCategory.XXX, "Эротические студии (видео) / Erotic Video Library"); caps.Categories.AddCategoryMapping(1726, NewznabStandardCategory.XXX, "Met-Art & MetModels"); @@ -205,6 +207,7 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(1734, NewznabStandardCategory.XXX, "Фистинг и дилдо / Fisting & Dildo"); caps.Categories.AddCategoryMapping(1791, NewznabStandardCategory.XXX, "Беременные / Pregnant"); caps.Categories.AddCategoryMapping(509, NewznabStandardCategory.XXX, "Буккаке / Bukkake"); + caps.Categories.AddCategoryMapping(1859, NewznabStandardCategory.XXX, "Гэнг-бэнг / GangBang"); caps.Categories.AddCategoryMapping(1685, NewznabStandardCategory.XXX, "Мочеиспускание / Peeing"); caps.Categories.AddCategoryMapping(1762, NewznabStandardCategory.XXX, "Фетиш / Fetish"); From 45dbcc6b89ced7788f0f3ae2c43fc35073a168ca Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 20 Dec 2022 09:13:44 -0600 Subject: [PATCH 0691/2320] Bump version to 1.0.0 --- azure-pipelines.yml | 2 +- .../UpdateTests/UpdatePackageProviderFixture.cs | 1 - src/NzbDrone.Core/Configuration/ConfigFileProvider.cs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 88827d156..489b7909a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: testsFolder: './_tests' yarnCacheFolder: $(Pipeline.Workspace)/.yarn nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages - majorVersion: '0.4.11' + majorVersion: '1.0.0' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' diff --git a/src/NzbDrone.Core.Test/UpdateTests/UpdatePackageProviderFixture.cs b/src/NzbDrone.Core.Test/UpdateTests/UpdatePackageProviderFixture.cs index 441d79efe..8c496a35f 100644 --- a/src/NzbDrone.Core.Test/UpdateTests/UpdatePackageProviderFixture.cs +++ b/src/NzbDrone.Core.Test/UpdateTests/UpdatePackageProviderFixture.cs @@ -25,7 +25,6 @@ namespace NzbDrone.Core.Test.UpdateTests } [Test] - [Ignore("TODO No Updates On Server")] public void finds_update_when_version_lower() { UseRealHttp(); diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index ac5955069..ac8a13a4e 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -196,7 +196,7 @@ namespace NzbDrone.Core.Configuration public bool AnalyticsEnabled => GetValueBoolean("AnalyticsEnabled", true, persist: false); // TODO: Change back to "master" for the first stable release. - public string Branch => GetValue("Branch", "develop").ToLowerInvariant(); + public string Branch => GetValue("Branch", "master").ToLowerInvariant(); public string LogLevel => GetValue("LogLevel", "info").ToLowerInvariant(); public string ConsoleLogLevel => GetValue("ConsoleLogLevel", string.Empty, persist: false); From 1cbb9b1724c0a8815fc126b634974d7a602bf36f Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 20 Dec 2022 09:26:22 -0600 Subject: [PATCH 0692/2320] Bump dotnet to 6.0.12 --- azure-pipelines.yml | 2 +- package.json | 2 +- src/Directory.Build.props | 2 +- src/NzbDrone.Common/Prowlarr.Common.csproj | 6 +++--- src/NzbDrone.Host/Prowlarr.Host.csproj | 2 +- .../Prowlarr.Integration.Test.csproj | 2 +- yarn.lock | 8 ++++---- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 489b7909a..f9aaacc20 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,7 +15,7 @@ variables: buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' sentryOrg: 'servarr' sentryUrl: 'https://sentry.servarr.com' - dotnetVersion: '6.0.301' + dotnetVersion: '6.0.404' innoVersion: '6.2.0' nodeVersion: '16.x' windowsImage: 'windows-2022' diff --git a/package.json b/package.json index 0d351012b..0a77911bf 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "@fortawesome/free-regular-svg-icons": "6.1.1", "@fortawesome/free-solid-svg-icons": "6.1.1", "@fortawesome/react-fontawesome": "0.1.18", - "@microsoft/signalr": "6.0.6", + "@microsoft/signalr": "6.0.11", "@sentry/browser": "6.19.2", "@sentry/integrations": "6.19.2", "chart.js": "3.7.1", diff --git a/src/Directory.Build.props b/src/Directory.Build.props index c226ec800..df60a8196 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -94,7 +94,7 @@ <!-- Standard testing packages --> <ItemGroup Condition="'$(TestProject)'=='true'"> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" /> <PackageReference Include="NUnit" Version="3.13.3" /> <PackageReference Include="NUnit3TestAdapter" Version="4.2.1" /> <PackageReference Include="NunitXml.TestLogger" Version="3.0.117" /> diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index 90c255d24..ff0c30158 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -5,8 +5,8 @@ </PropertyGroup> <ItemGroup> <PackageReference Include="DryIoc.dll" Version="5.2.2" /> - <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" /> - <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> + <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" /> + <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="NLog" Version="5.0.1" /> <PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" /> @@ -15,7 +15,7 @@ <PackageReference Include="SharpZipLib" Version="1.3.3" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> - <PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" /> + <PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.1" /> <PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" /> <PackageReference Include="System.Runtime.Loader" Version="4.3.0" /> <PackageReference Include="System.ServiceProcess.ServiceController" Version="6.0.0" /> diff --git a/src/NzbDrone.Host/Prowlarr.Host.csproj b/src/NzbDrone.Host/Prowlarr.Host.csproj index 04faad891..660f10f29 100644 --- a/src/NzbDrone.Host/Prowlarr.Host.csproj +++ b/src/NzbDrone.Host/Prowlarr.Host.csproj @@ -6,7 +6,7 @@ <ItemGroup> <PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" /> - <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> + <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.1" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.4.0" /> <PackageReference Include="DryIoc.dll" Version="5.2.2" /> <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="6.1.0" /> diff --git a/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj b/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj index 47586e916..ee8982c7f 100644 --- a/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj +++ b/src/NzbDrone.Integration.Test/Prowlarr.Integration.Test.csproj @@ -4,7 +4,7 @@ <OutputType>Library</OutputType> </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.6" /> + <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.12" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" /> diff --git a/yarn.lock b/yarn.lock index de6dc72ca..6e5e43e09 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1150,10 +1150,10 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@microsoft/signalr@6.0.6": - version "6.0.6" - resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-6.0.6.tgz#6ba53623a64df64a80126694db4e37146647d3fe" - integrity sha512-3dTLtgwEXUeE9R/3NZQslh1B2WbppeHVXdnpvSZc7Yz+tP5Yiw3KCVUHwKUVnYmd9/2v3DaI/pvCdihrss49zA== +"@microsoft/signalr@6.0.11": + version "6.0.11" + resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-6.0.11.tgz#f8e762e4516a27850836251a15528041b3c877f9" + integrity sha512-5flnqEgl+7AK3+NCcavmzC4AKRt1bqa/T3zd8acyQRf/VyUe2nsFgSdaXQKZx4z3v8OIe1aQloRDvDEI4JjpAg== dependencies: abort-controller "^3.0.0" eventsource "^1.0.7" From 31f0e8212e7b14da1ab717bbf11c0050e1bf6342 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 20 Dec 2022 09:37:46 -0600 Subject: [PATCH 0693/2320] Update UI Dev Dependencies --- frontend/src/Components/Form/TagInputInput.js | 1 - package.json | 62 +- yarn.lock | 3655 +++++++---------- 3 files changed, 1449 insertions(+), 2269 deletions(-) diff --git a/frontend/src/Components/Form/TagInputInput.js b/frontend/src/Components/Form/TagInputInput.js index e28eb3c40..3d474e4a1 100644 --- a/frontend/src/Components/Form/TagInputInput.js +++ b/frontend/src/Components/Form/TagInputInput.js @@ -36,7 +36,6 @@ class TagInputInput extends Component { <div ref={forwardedRef} className={className} - component="div" onMouseDown={this.onMouseDown} > { diff --git a/package.json b/package.json index 0a77911bf..cc44605de 100644 --- a/package.json +++ b/package.json @@ -78,54 +78,54 @@ "reselect": "4.0.0" }, "devDependencies": { - "@babel/core": "7.18.2", - "@babel/eslint-parser": "7.18.2", - "@babel/plugin-proposal-class-properties": "7.17.12", - "@babel/plugin-proposal-decorators": "7.18.2", - "@babel/plugin-proposal-export-default-from": "7.17.12", - "@babel/plugin-proposal-export-namespace-from": "7.17.12", - "@babel/plugin-proposal-function-sent": "7.18.2", - "@babel/plugin-proposal-nullish-coalescing-operator": "7.17.12", - "@babel/plugin-proposal-numeric-separator": "7.16.7", - "@babel/plugin-proposal-optional-chaining": "7.17.12", - "@babel/plugin-proposal-throw-expressions": "7.16.7", + "@babel/core": "7.20.5", + "@babel/eslint-parser": "7.19.1", + "@babel/plugin-proposal-class-properties": "7.18.6", + "@babel/plugin-proposal-decorators": "7.20.5", + "@babel/plugin-proposal-export-default-from": "7.18.10", + "@babel/plugin-proposal-export-namespace-from": "7.18.9", + "@babel/plugin-proposal-function-sent": "7.18.6", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.18.6", + "@babel/plugin-proposal-numeric-separator": "7.18.6", + "@babel/plugin-proposal-optional-chaining": "7.18.9", + "@babel/plugin-proposal-throw-expressions": "7.18.6", "@babel/plugin-syntax-dynamic-import": "7.8.3", - "@babel/preset-env": "7.18.2", - "@babel/preset-react": "7.17.12", - "autoprefixer": "10.4.7", - "babel-loader": "8.2.5", + "@babel/preset-env": "7.20.2", + "@babel/preset-react": "7.18.6", + "autoprefixer": "10.4.13", + "babel-loader": "9.1.0", "babel-plugin-inline-classnames": "2.0.1", "babel-plugin-transform-react-remove-prop-types": "0.4.24", - "core-js": "3.22.8", - "css-loader": "6.7.1", - "eslint": "8.17.0", + "core-js": "3.26.1", + "css-loader": "6.7.3", + "eslint": "8.30.0", "eslint-plugin-filenames": "1.3.2", "eslint-plugin-import": "2.26.0", - "eslint-plugin-react": "7.30.0", - "eslint-plugin-simple-import-sort": "7.0.0", + "eslint-plugin-react": "7.31.11", + "eslint-plugin-simple-import-sort": "8.0.0", "esprint": "3.6.0", "file-loader": "6.2.0", - "filemanager-webpack-plugin": "6.1.7", + "filemanager-webpack-plugin": "8.0.0", "html-webpack-plugin": "5.5.0", - "loader-utils": "^3.0.0", - "mini-css-extract-plugin": "2.6.0", - "postcss": "8.4.14", + "loader-utils": "^3.2.1", + "mini-css-extract-plugin": "2.7.2", + "postcss": "8.4.20", "postcss-color-function": "4.1.0", - "postcss-loader": "6.2.1", - "postcss-mixins": "9.0.2", - "postcss-nested": "5.0.6", - "postcss-simple-vars": "6.0.3", + "postcss-loader": "7.0.2", + "postcss-mixins": "9.0.4", + "postcss-nested": "6.0.0", + "postcss-simple-vars": "7.0.1", "postcss-url": "10.1.3", "require-nocache": "1.0.0", "rimraf": "3.0.2", "run-sequence": "2.2.1", "streamqueue": "1.1.2", "style-loader": "3.3.1", - "stylelint": "14.8.5", + "stylelint": "14.16.0", "stylelint-order": "5.0.0", "url-loader": "4.1.1", - "webpack": "5.73.0", - "webpack-cli": "4.9.2", + "webpack": "5.75.0", + "webpack-cli": "5.0.1", "webpack-livereload-plugin": "3.0.2" } } diff --git a/yarn.lock b/yarn.lock index 6e5e43e09..94b36b118 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,448 +10,452 @@ "@jridgewell/gen-mapping" "^0.1.0" "@jridgewell/trace-mapping" "^0.3.9" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== dependencies: - "@babel/highlight" "^7.16.7" + "@babel/highlight" "^7.18.6" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.17.10": - version "7.17.10" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.10.tgz#711dc726a492dfc8be8220028b1b92482362baab" - integrity sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw== +"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.0", "@babel/compat-data@^7.20.1": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.5.tgz#86f172690b093373a933223b4745deeb6049e733" + integrity sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g== -"@babel/core@7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.2.tgz#87b2fcd7cce9becaa7f5acebdc4f09f3dd19d876" - integrity sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ== +"@babel/core@7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.5.tgz#45e2114dc6cd4ab167f81daf7820e8fa1250d113" + integrity sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ== dependencies: "@ampproject/remapping" "^2.1.0" - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.18.2" - "@babel/helper-compilation-targets" "^7.18.2" - "@babel/helper-module-transforms" "^7.18.0" - "@babel/helpers" "^7.18.2" - "@babel/parser" "^7.18.0" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.18.2" - "@babel/types" "^7.18.2" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.20.5" + "@babel/helper-compilation-targets" "^7.20.0" + "@babel/helper-module-transforms" "^7.20.2" + "@babel/helpers" "^7.20.5" + "@babel/parser" "^7.20.5" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.20.5" + "@babel/types" "^7.20.5" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.1" semver "^6.3.0" -"@babel/eslint-parser@7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.18.2.tgz#e14dee36c010edfb0153cf900c2b0815e82e3245" - integrity sha512-oFQYkE8SuH14+uR51JVAmdqwKYXGRjEXx7s+WiagVjqQ+HPE+nnwyF2qlVG8evUsUHmPcA+6YXMEDbIhEyQc5A== +"@babel/eslint-parser@7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz#4f68f6b0825489e00a24b41b6a1ae35414ecd2f4" + integrity sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ== dependencies: - eslint-scope "^5.1.1" + "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" eslint-visitor-keys "^2.1.0" semver "^6.3.0" -"@babel/generator@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.2.tgz#33873d6f89b21efe2da63fe554460f3df1c5880d" - integrity sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw== +"@babel/generator@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.5.tgz#cb25abee3178adf58d6814b68517c62bdbfdda95" + integrity sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA== dependencies: - "@babel/types" "^7.18.2" - "@jridgewell/gen-mapping" "^0.3.0" + "@babel/types" "^7.20.5" + "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" -"@babel/helper-annotate-as-pure@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" - integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== +"@babel/helper-annotate-as-pure@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" + integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.18.6" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz#38d138561ea207f0f69eb1626a418e4f7e6a580b" - integrity sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA== +"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz#acd4edfd7a566d1d51ea975dff38fd52906981bb" + integrity sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw== dependencies: - "@babel/helper-explode-assignable-expression" "^7.16.7" - "@babel/types" "^7.16.7" + "@babel/helper-explode-assignable-expression" "^7.18.6" + "@babel/types" "^7.18.9" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.17.10", "@babel/helper-compilation-targets@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz#67a85a10cbd5fc7f1457fec2e7f45441dc6c754b" - integrity sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ== +"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.20.0": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz#6bf5374d424e1b3922822f1d9bdaa43b1a139d0a" + integrity sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ== dependencies: - "@babel/compat-data" "^7.17.10" - "@babel/helper-validator-option" "^7.16.7" - browserslist "^4.20.2" + "@babel/compat-data" "^7.20.0" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.21.3" semver "^6.3.0" -"@babel/helper-create-class-features-plugin@^7.17.12", "@babel/helper-create-class-features-plugin@^7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.0.tgz#fac430912606331cb075ea8d82f9a4c145a4da19" - integrity sha512-Kh8zTGR9de3J63e5nS0rQUdRs/kbtwoeQQ0sriS0lItjC96u8XXZN6lKpuyWd2coKSU13py/y+LTmThLuVX0Pg== +"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.5.tgz#327154eedfb12e977baa4ecc72e5806720a85a06" + integrity sha512-3RCdA/EmEaikrhayahwToF0fpweU/8o2p8vhc1c/1kftHOdTKuC65kik/TLc+qfbS8JKw4qqJbne4ovICDhmww== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.17.9" - "@babel/helper-member-expression-to-functions" "^7.17.7" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-replace-supers" "^7.19.1" + "@babel/helper-split-export-declaration" "^7.18.6" -"@babel/helper-create-regexp-features-plugin@^7.16.7", "@babel/helper-create-regexp-features-plugin@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.12.tgz#bb37ca467f9694bbe55b884ae7a5cc1e0084e4fd" - integrity sha512-b2aZrV4zvutr9AIa6/gA3wsZKRwTKYoDxYiFKcESS3Ug2GTXzwBEvMuuFLhCQpEnRXs1zng4ISAXSUxxKBIcxw== +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz#5ea79b59962a09ec2acf20a963a01ab4d076ccca" + integrity sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - regexpu-core "^5.0.1" + "@babel/helper-annotate-as-pure" "^7.18.6" + regexpu-core "^5.2.1" -"@babel/helper-define-polyfill-provider@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz#52411b445bdb2e676869e5a74960d2d3826d2665" - integrity sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA== +"@babel/helper-define-polyfill-provider@^0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz#8612e55be5d51f0cd1f36b4a5a83924e89884b7a" + integrity sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww== dependencies: - "@babel/helper-compilation-targets" "^7.13.0" - "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/traverse" "^7.13.0" + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-plugin-utils" "^7.16.7" debug "^4.1.1" lodash.debounce "^4.0.8" resolve "^1.14.2" semver "^6.1.2" -"@babel/helper-environment-visitor@^7.16.7", "@babel/helper-environment-visitor@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz#8a6d2dedb53f6bf248e31b4baf38739ee4a637bd" - integrity sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ== +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== -"@babel/helper-explode-assignable-expression@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz#12a6d8522fdd834f194e868af6354e8650242b7a" - integrity sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ== +"@babel/helper-explode-assignable-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096" + integrity sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.18.6" -"@babel/helper-function-name@^7.16.7", "@babel/helper-function-name@^7.17.9": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz#136fcd54bc1da82fcb47565cf16fd8e444b1ff12" - integrity sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg== +"@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c" + integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w== dependencies: - "@babel/template" "^7.16.7" - "@babel/types" "^7.17.0" + "@babel/template" "^7.18.10" + "@babel/types" "^7.19.0" -"@babel/helper-hoist-variables@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" - integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.18.6" -"@babel/helper-member-expression-to-functions@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz#a34013b57d8542a8c4ff8ba3f747c02452a4d8c4" - integrity sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw== +"@babel/helper-member-expression-to-functions@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815" + integrity sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg== dependencies: - "@babel/types" "^7.17.0" + "@babel/types" "^7.18.9" -"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" - integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== +"@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.18.6" -"@babel/helper-module-transforms@^7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz#baf05dec7a5875fb9235bd34ca18bad4e21221cd" - integrity sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA== +"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.19.6", "@babel/helper-module-transforms@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz#ac53da669501edd37e658602a21ba14c08748712" + integrity sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA== dependencies: - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-simple-access" "^7.17.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/helper-validator-identifier" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.18.0" - "@babel/types" "^7.18.0" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.20.2" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.19.1" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.20.1" + "@babel/types" "^7.20.2" -"@babel/helper-optimise-call-expression@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" - integrity sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w== +"@babel/helper-optimise-call-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" + integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.18.6" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.17.12", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz#86c2347da5acbf5583ba0a10aed4c9bf9da9cf96" - integrity sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA== +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629" + integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== -"@babel/helper-remap-async-to-generator@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz#29ffaade68a367e2ed09c90901986918d25e57e3" - integrity sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw== +"@babel/helper-remap-async-to-generator@^7.18.6", "@babel/helper-remap-async-to-generator@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519" + integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-wrap-function" "^7.16.8" - "@babel/types" "^7.16.8" + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-wrap-function" "^7.18.9" + "@babel/types" "^7.18.9" -"@babel/helper-replace-supers@^7.16.7", "@babel/helper-replace-supers@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.18.2.tgz#41fdfcc9abaf900e18ba6e5931816d9062a7b2e0" - integrity sha512-XzAIyxx+vFnrOxiQrToSUOzUOn0e1J2Li40ntddek1Y69AXUTXoDJ40/D5RdjFu7s7qHiaeoTiempZcbuVXh2Q== +"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz#e1592a9b4b368aa6bdb8784a711e0bcbf0612b78" + integrity sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw== dependencies: - "@babel/helper-environment-visitor" "^7.18.2" - "@babel/helper-member-expression-to-functions" "^7.17.7" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/traverse" "^7.18.2" - "@babel/types" "^7.18.2" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/traverse" "^7.19.1" + "@babel/types" "^7.19.0" -"@babel/helper-simple-access@^7.17.7", "@babel/helper-simple-access@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz#4dc473c2169ac3a1c9f4a51cfcd091d1c36fcff9" - integrity sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ== +"@babel/helper-simple-access@^7.19.4", "@babel/helper-simple-access@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz#0ab452687fe0c2cfb1e2b9e0015de07fc2d62dd9" + integrity sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA== dependencies: - "@babel/types" "^7.18.2" + "@babel/types" "^7.20.2" -"@babel/helper-skip-transparent-expression-wrappers@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" - integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== +"@babel/helper-skip-transparent-expression-wrappers@^7.18.9": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz#fbe4c52f60518cab8140d77101f0e63a8a230684" + integrity sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg== dependencies: - "@babel/types" "^7.16.0" + "@babel/types" "^7.20.0" -"@babel/helper-split-export-declaration@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" - integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.18.6" -"@babel/helper-validator-identifier@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" - integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== +"@babel/helper-string-parser@^7.19.4": + version "7.19.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" + integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== -"@babel/helper-validator-option@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" - integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== +"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== -"@babel/helper-wrap-function@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz#58afda087c4cd235de92f7ceedebca2c41274200" - integrity sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw== +"@babel/helper-validator-option@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + +"@babel/helper-wrap-function@^7.18.6", "@babel/helper-wrap-function@^7.18.9": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz#75e2d84d499a0ab3b31c33bcfe59d6b8a45f62e3" + integrity sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q== dependencies: - "@babel/helper-function-name" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.16.8" - "@babel/types" "^7.16.8" + "@babel/helper-function-name" "^7.19.0" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.20.5" + "@babel/types" "^7.20.5" -"@babel/helpers@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.2.tgz#970d74f0deadc3f5a938bfa250738eb4ac889384" - integrity sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg== +"@babel/helpers@^7.20.5": + version "7.20.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.20.6.tgz#e64778046b70e04779dfbdf924e7ebb45992c763" + integrity sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w== dependencies: - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.18.2" - "@babel/types" "^7.18.2" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.20.5" + "@babel/types" "^7.20.5" -"@babel/highlight@^7.16.7": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.12.tgz#257de56ee5afbd20451ac0a75686b6b404257351" - integrity sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg== +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== dependencies: - "@babel/helper-validator-identifier" "^7.16.7" + "@babel/helper-validator-identifier" "^7.18.6" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.16.7", "@babel/parser@^7.18.0": - version "7.18.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.4.tgz#6774231779dd700e0af29f6ad8d479582d7ce5ef" - integrity sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow== +"@babel/parser@^7.18.10", "@babel/parser@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.5.tgz#7f3c7335fe417665d929f34ae5dceae4c04015e8" + integrity sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA== -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.17.12.tgz#1dca338caaefca368639c9ffb095afbd4d420b1e" - integrity sha512-xCJQXl4EeQ3J9C4yOmpTrtVGmzpm2iSzyxbkZHw7UCnZBftHpF/hpII80uWVyVrc40ytIClHjgWGTG1g/yB+aw== +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2" + integrity sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.17.12.tgz#0d498ec8f0374b1e2eb54b9cb2c4c78714c77753" - integrity sha512-/vt0hpIw0x4b6BLKUkwlvEoiGZYYLNZ96CzyHYPbtG2jZGz6LBe7/V+drYrc/d+ovrF9NBi0pmtvmNb/FsWtRQ== +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz#a11af19aa373d68d561f08e0a57242350ed0ec50" + integrity sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" - "@babel/plugin-proposal-optional-chaining" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + "@babel/plugin-proposal-optional-chaining" "^7.18.9" -"@babel/plugin-proposal-async-generator-functions@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.17.12.tgz#094a417e31ce7e692d84bab06c8e2a607cbeef03" - integrity sha512-RWVvqD1ooLKP6IqWTA5GyFVX2isGEgC5iFxKzfYOIy/QEFdxYyCybBDtIGjipHpb9bDWHzcqGqFakf+mVmBTdQ== +"@babel/plugin-proposal-async-generator-functions@^7.20.1": + version "7.20.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.1.tgz#352f02baa5d69f4e7529bdac39aaa02d41146af9" + integrity sha512-Gh5rchzSwE4kC+o/6T8waD0WHEQIsDmjltY8WnWRXHUdH8axZhuH86Ov9M72YhJfDrZseQwuuWaaIT/TmePp3g== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-remap-async-to-generator" "^7.16.8" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-remap-async-to-generator" "^7.18.9" "@babel/plugin-syntax-async-generators" "^7.8.4" -"@babel/plugin-proposal-class-properties@7.17.12", "@babel/plugin-proposal-class-properties@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.17.12.tgz#84f65c0cc247d46f40a6da99aadd6438315d80a4" - integrity sha512-U0mI9q8pW5Q9EaTHFPwSVusPMV/DV9Mm8p7csqROFLtIE9rBF5piLqyrBGigftALrBcsBGu4m38JneAe7ZDLXw== +"@babel/plugin-proposal-class-properties@7.18.6", "@babel/plugin-proposal-class-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" + integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== dependencies: - "@babel/helper-create-class-features-plugin" "^7.17.12" - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-proposal-class-static-block@^7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.0.tgz#7d02253156e3c3793bdb9f2faac3a1c05f0ba710" - integrity sha512-t+8LsRMMDE74c6sV7KShIw13sqbqd58tlqNrsWoWBTIMw7SVQ0cZ905wLNS/FBCy/3PyooRHLFFlfrUNyyz5lA== +"@babel/plugin-proposal-class-static-block@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz#8aa81d403ab72d3962fc06c26e222dacfc9b9020" + integrity sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw== dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.0" - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-class-static-block" "^7.14.5" -"@babel/plugin-proposal-decorators@7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.18.2.tgz#dbe4086d2d42db489399783c3aa9272e9700afd4" - integrity sha512-kbDISufFOxeczi0v4NQP3p5kIeW6izn/6klfWBrIIdGZZe4UpHR+QU03FAoWjGGd9SUXAwbw2pup1kaL4OQsJQ== +"@babel/plugin-proposal-decorators@7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.20.5.tgz#28ba1a0e5044664a512967a19407d7fc26925394" + integrity sha512-Lac7PpRJXcC3s9cKsBfl+uc+DYXU5FD06BrTFunQO6QIQT+DwyzDPURAowI3bcvD1dZF/ank1Z5rstUJn3Hn4Q== dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.0" - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-replace-supers" "^7.18.2" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/plugin-syntax-decorators" "^7.17.12" - charcodes "^0.2.0" + "@babel/helper-create-class-features-plugin" "^7.20.5" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-replace-supers" "^7.19.1" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/plugin-syntax-decorators" "^7.19.0" -"@babel/plugin-proposal-dynamic-import@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz#c19c897eaa46b27634a00fee9fb7d829158704b2" - integrity sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg== +"@babel/plugin-proposal-dynamic-import@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz#72bcf8d408799f547d759298c3c27c7e7faa4d94" + integrity sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-dynamic-import" "^7.8.3" -"@babel/plugin-proposal-export-default-from@7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.17.12.tgz#df785e638618d8ffa14e08c78c44d9695d083b73" - integrity sha512-LpsTRw725eBAXXKUOnJJct+SEaOzwR78zahcLuripD2+dKc2Sj+8Q2DzA+GC/jOpOu/KlDXuxrzG214o1zTauQ== +"@babel/plugin-proposal-export-default-from@7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.18.10.tgz#091f4794dbce4027c03cf4ebc64d3fb96b75c206" + integrity sha512-5H2N3R2aQFxkV4PIBUR/i7PUSwgTZjouJKzI8eKswfIjT0PhvzkPn0t0wIS5zn6maQuvtT0t1oHtMUz61LOuow== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/plugin-syntax-export-default-from" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-export-default-from" "^7.18.6" -"@babel/plugin-proposal-export-namespace-from@7.17.12", "@babel/plugin-proposal-export-namespace-from@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.17.12.tgz#b22864ccd662db9606edb2287ea5fd1709f05378" - integrity sha512-j7Ye5EWdwoXOpRmo5QmRyHPsDIe6+u70ZYZrd7uz+ebPYFKfRcLcNu3Ro0vOlJ5zuv8rU7xa+GttNiRzX56snQ== +"@babel/plugin-proposal-export-namespace-from@7.18.9", "@babel/plugin-proposal-export-namespace-from@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz#5f7313ab348cdb19d590145f9247540e94761203" + integrity sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.9" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" -"@babel/plugin-proposal-function-sent@7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-function-sent/-/plugin-proposal-function-sent-7.18.2.tgz#460a3c6ceac16da8e50a93b6068fd99265e56c75" - integrity sha512-JKAqbpAh6/ZA9satxaP02oL9lmyF1XxzItEONAPHd+jhZtzxBu5sR4L2LhnzjUwR3uJzExaiuHLGuUMNMt/t5A== +"@babel/plugin-proposal-function-sent@7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-function-sent/-/plugin-proposal-function-sent-7.18.6.tgz#60854442f9024869e731116b4f7f98ee8cb072de" + integrity sha512-UdaOKPOLPt0O+Xu26tnw6oAZMLXhk+yMrXOzn6kAzTHBnWHJsoN1hlrgxFAQ+FRLS0ql1oYIQ2phvoFzmN3GMw== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-wrap-function" "^7.16.8" - "@babel/plugin-syntax-function-sent" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-wrap-function" "^7.18.6" + "@babel/plugin-syntax-function-sent" "^7.18.6" -"@babel/plugin-proposal-json-strings@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.17.12.tgz#f4642951792437233216d8c1af370bb0fbff4664" - integrity sha512-rKJ+rKBoXwLnIn7n6o6fulViHMrOThz99ybH+hKHcOZbnN14VuMnH9fo2eHE69C8pO4uX1Q7t2HYYIDmv8VYkg== +"@babel/plugin-proposal-json-strings@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz#7e8788c1811c393aff762817e7dbf1ebd0c05f0b" + integrity sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-json-strings" "^7.8.3" -"@babel/plugin-proposal-logical-assignment-operators@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.17.12.tgz#c64a1bcb2b0a6d0ed2ff674fd120f90ee4b88a23" - integrity sha512-EqFo2s1Z5yy+JeJu7SFfbIUtToJTVlC61/C7WLKDntSw4Sz6JNAIfL7zQ74VvirxpjB5kz/kIx0gCcb+5OEo2Q== +"@babel/plugin-proposal-logical-assignment-operators@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz#8148cbb350483bf6220af06fa6db3690e14b2e23" + integrity sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.9" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-proposal-nullish-coalescing-operator@7.17.12", "@babel/plugin-proposal-nullish-coalescing-operator@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.17.12.tgz#1e93079bbc2cbc756f6db6a1925157c4a92b94be" - integrity sha512-ws/g3FSGVzv+VH86+QvgtuJL/kR67xaEIF2x0iPqdDfYW6ra6JF3lKVBkWynRLcNtIC1oCTfDRVxmm2mKzy+ag== +"@babel/plugin-proposal-nullish-coalescing-operator@7.18.6", "@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1" + integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" -"@babel/plugin-proposal-numeric-separator@7.16.7", "@babel/plugin-proposal-numeric-separator@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz#d6b69f4af63fb38b6ca2558442a7fb191236eba9" - integrity sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw== +"@babel/plugin-proposal-numeric-separator@7.18.6", "@babel/plugin-proposal-numeric-separator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75" + integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.0.tgz#79f2390c892ba2a68ec112eb0d895cfbd11155e8" - integrity sha512-nbTv371eTrFabDfHLElkn9oyf9VG+VKK6WMzhY2o4eHKaG19BToD9947zzGMO6I/Irstx9d8CwX6njPNIAR/yw== +"@babel/plugin-proposal-object-rest-spread@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.2.tgz#a556f59d555f06961df1e572bb5eca864c84022d" + integrity sha512-Ks6uej9WFK+fvIMesSqbAto5dD8Dz4VuuFvGJFKgIGSkJuRGcrwGECPA1fDgQK3/DbExBJpEkTeYeB8geIFCSQ== dependencies: - "@babel/compat-data" "^7.17.10" - "@babel/helper-compilation-targets" "^7.17.10" - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/compat-data" "^7.20.1" + "@babel/helper-compilation-targets" "^7.20.0" + "@babel/helper-plugin-utils" "^7.20.2" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.17.12" + "@babel/plugin-transform-parameters" "^7.20.1" -"@babel/plugin-proposal-optional-catch-binding@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz#c623a430674ffc4ab732fd0a0ae7722b67cb74cf" - integrity sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA== +"@babel/plugin-proposal-optional-catch-binding@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz#f9400d0e6a3ea93ba9ef70b09e72dd6da638a2cb" + integrity sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-proposal-optional-chaining@7.17.12", "@babel/plugin-proposal-optional-chaining@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.17.12.tgz#f96949e9bacace3a9066323a5cf90cfb9de67174" - integrity sha512-7wigcOs/Z4YWlK7xxjkvaIw84vGhDv/P1dFGQap0nHkc8gFKY/r+hXc8Qzf5k1gY7CvGIcHqAnOagVKJJ1wVOQ== +"@babel/plugin-proposal-optional-chaining@7.18.9", "@babel/plugin-proposal-optional-chaining@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz#e8e8fe0723f2563960e4bf5e9690933691915993" + integrity sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -"@babel/plugin-proposal-private-methods@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.17.12.tgz#c2ca3a80beb7539289938da005ad525a038a819c" - integrity sha512-SllXoxo19HmxhDWm3luPz+cPhtoTSKLJE9PXshsfrOzBqs60QP0r8OaJItrPhAj0d7mZMnNF0Y1UUggCDgMz1A== +"@babel/plugin-proposal-private-methods@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea" + integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.17.12" - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-proposal-private-property-in-object@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.17.12.tgz#b02efb7f106d544667d91ae97405a9fd8c93952d" - integrity sha512-/6BtVi57CJfrtDNKfK5b66ydK2J5pXUKBKSPD2G1whamMuEnZWgoOIfO8Vf9F/DoD4izBLD/Au4NMQfruzzykg== +"@babel/plugin-proposal-private-property-in-object@^7.18.6": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz#309c7668f2263f1c711aa399b5a9a6291eef6135" + integrity sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-create-class-features-plugin" "^7.17.12" - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-create-class-features-plugin" "^7.20.5" + "@babel/helper-plugin-utils" "^7.20.2" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" -"@babel/plugin-proposal-throw-expressions@7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-throw-expressions/-/plugin-proposal-throw-expressions-7.16.7.tgz#d3512286f634a06f7271abecce752e1655b9ab03" - integrity sha512-BbjL/uDt7c+OKA7k2YbZIPtOb6qmrzXPybjqrGreP8wMMzTPKjjiK+moqgpElsIXv1XHmlk9PQWdOHD5sL93KA== +"@babel/plugin-proposal-throw-expressions@7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-throw-expressions/-/plugin-proposal-throw-expressions-7.18.6.tgz#f05eb10f417d34857e4ebf3a2a152e77bd59ff9f" + integrity sha512-WHOrJyhGoGrdtW480L79cF7Iq/gZDZ/z6OqK7mVyFR5I37dTpog/wNgb6hmaM3HYZtULEJl++7VaMWkNZsOcHg== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-throw-expressions" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-throw-expressions" "^7.18.6" -"@babel/plugin-proposal-unicode-property-regex@^7.17.12", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.17.12.tgz#3dbd7a67bd7f94c8238b394da112d86aaf32ad4d" - integrity sha512-Wb9qLjXf3ZazqXA7IvI7ozqRIXIGPtSo+L5coFmEkhTQK18ao4UDDD0zdTGAarmbLj2urpRwrc6893cu5Bfh0A== +"@babel/plugin-proposal-unicode-property-regex@^7.18.6", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e" + integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.17.12" - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -474,12 +478,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-decorators@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.12.tgz#02e8f678602f0af8222235271efea945cfdb018a" - integrity sha512-D1Hz0qtGTza8K2xGyEdVNCYLdVHukAcbQr4K3/s6r/esadyEriZovpJimQOpu8ju4/jV8dW/1xdaE0UpDroidw== +"@babel/plugin-syntax-decorators@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz#5f13d1d8fce96951bea01a10424463c9a5b3a599" + integrity sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.19.0" "@babel/plugin-syntax-dynamic-import@7.8.3", "@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" @@ -488,12 +492,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-export-default-from@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.16.7.tgz#fa89cf13b60de2c3f79acdc2b52a21174c6de060" - integrity sha512-4C3E4NsrLOgftKaTYTULhHsuQrGv3FHrBzOMDiS7UYKIpgGBkAdawg4h+EI8zPeK9M0fiIIh72hIwsI24K7MbA== +"@babel/plugin-syntax-export-default-from@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.18.6.tgz#8df076711a4818c4ce4f23e61d622b0ba2ff84bc" + integrity sha512-Kr//z3ujSVNx6E9z9ih5xXXMqK07VVTuqPmqGe6Mss/zW5XPeLZeSDZoP9ab/hT4wPKqAgjl2PnhPrcpk8Seew== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-export-namespace-from@^7.8.3": version "7.8.3" @@ -502,19 +506,19 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-function-sent@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-function-sent/-/plugin-syntax-function-sent-7.16.7.tgz#46ff4ac849881dbeaa5c5ab60cd1041ffc606095" - integrity sha512-W2fOJmlqHJ0kalyP8kAA0Jx5Hn87OX5qZwjtII3uqi+VpIdLTJLAHH8d4qIt5eqflLALFf6ehVT6+mnFJ2d7AA== +"@babel/plugin-syntax-function-sent@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-function-sent/-/plugin-syntax-function-sent-7.18.6.tgz#ce2e8e9979f8a26246bba81534e605c6d1369e5e" + integrity sha512-f3OJHIlFIkg+cP1Hfo2SInLhsg0pz2Ikmgo7jMdIIKC+3jVXQlHB0bgSapOWxeWI0SU28qIWmfn5ZKu1yPJHkg== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-syntax-import-assertions@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.17.12.tgz#58096a92b11b2e4e54b24c6a0cc0e5e607abcedd" - integrity sha512-n/loy2zkq9ZEM8tEOwON9wTQSTNDTDEz6NujPtJGLU7qObzT1N4c4YZZf8E6ATB2AjNQg/Ib2AIpO03EZaCehw== +"@babel/plugin-syntax-import-assertions@^7.20.0": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz#bb50e0d4bea0957235390641209394e87bdb9cc4" + integrity sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.19.0" "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" @@ -523,12 +527,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.17.12.tgz#834035b45061983a491f60096f61a2e7c5674a47" - integrity sha512-spyY3E3AURfxh/RHtjx5j6hs8am5NbUBGfcZ2vB3uShSpZdQyXSf5rR5Mk76vbtlAZOelyVQ71Fg0x9SG4fsog== +"@babel/plugin-syntax-jsx@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" + integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" @@ -579,12 +583,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-throw-expressions@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-throw-expressions/-/plugin-syntax-throw-expressions-7.16.7.tgz#5fd64f4d58d653499cc1077bb58594e18da5a514" - integrity sha512-6Kw78ssLHIADvVsqLOLLxuxH4SG55A2tqn0Og2tQQq6X/06HBWLClg6quL+oTfyeVEsPnFYTSECkajseotTnbA== +"@babel/plugin-syntax-throw-expressions@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-throw-expressions/-/plugin-syntax-throw-expressions-7.18.6.tgz#50889d493f7ef9631d79bae6b30f58fa8c06449f" + integrity sha512-rp1CqEZXGv1z1YZ3qYffBH3rhnOxrTwQG8fh2yqulTurwv9zu3Gthfd+niZBLSOi1rY6146TgF+JmVeDXaX4TQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-top-level-await@^7.14.5": version "7.14.5" @@ -593,323 +597,321 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-arrow-functions@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.17.12.tgz#dddd783b473b1b1537ef46423e3944ff24898c45" - integrity sha512-PHln3CNi/49V+mza4xMwrg+WGYevSF1oaiXaC2EQfdp4HWlSjRsrDXWJiQBKpP7749u6vQ9mcry2uuFOv5CXvA== +"@babel/plugin-transform-arrow-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz#19063fcf8771ec7b31d742339dac62433d0611fe" + integrity sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-async-to-generator@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.17.12.tgz#dbe5511e6b01eee1496c944e35cdfe3f58050832" - integrity sha512-J8dbrWIOO3orDzir57NRsjg4uxucvhby0L/KZuGsWDj0g7twWK3g7JhJhOrXtuXiw8MeiSdJ3E0OW9H8LYEzLQ== +"@babel/plugin-transform-async-to-generator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz#ccda3d1ab9d5ced5265fdb13f1882d5476c71615" + integrity sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag== dependencies: - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-remap-async-to-generator" "^7.16.8" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-remap-async-to-generator" "^7.18.6" -"@babel/plugin-transform-block-scoped-functions@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz#4d0d57d9632ef6062cdf354bb717102ee042a620" - integrity sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg== +"@babel/plugin-transform-block-scoped-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz#9187bf4ba302635b9d70d986ad70f038726216a8" + integrity sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-block-scoping@^7.17.12": - version "7.18.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.4.tgz#7988627b3e9186a13e4d7735dc9c34a056613fb9" - integrity sha512-+Hq10ye+jlvLEogSOtq4mKvtk7qwcUQ1f0Mrueai866C82f844Yom2cttfJdMdqRLTxWpsbfbkIkOIfovyUQXw== +"@babel/plugin-transform-block-scoping@^7.20.2": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.5.tgz#401215f9dc13dc5262940e2e527c9536b3d7f237" + integrity sha512-WvpEIW9Cbj9ApF3yJCjIEEf1EiNJLtXagOrL5LNWEZOo3jv8pmPoYTSNJQvqej8OavVlgOoOPw6/htGZro6IkA== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.20.2" -"@babel/plugin-transform-classes@^7.17.12": - version "7.18.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.4.tgz#51310b812a090b846c784e47087fa6457baef814" - integrity sha512-e42NSG2mlKWgxKUAD9EJJSkZxR67+wZqzNxLSpc51T8tRU5SLFHsPmgYR5yr7sdgX4u+iHA1C5VafJ6AyImV3A== +"@babel/plugin-transform-classes@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.2.tgz#c0033cf1916ccf78202d04be4281d161f6709bb2" + integrity sha512-9rbPp0lCVVoagvtEyQKSo5L8oo0nQS/iif+lwlAz29MccX2642vWDlSZK+2T2buxbopotId2ld7zZAzRfz9j1g== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-environment-visitor" "^7.18.2" - "@babel/helper-function-name" "^7.17.9" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-replace-supers" "^7.18.2" - "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-compilation-targets" "^7.20.0" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-replace-supers" "^7.19.1" + "@babel/helper-split-export-declaration" "^7.18.6" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.17.12.tgz#bca616a83679698f3258e892ed422546e531387f" - integrity sha512-a7XINeplB5cQUWMg1E/GI1tFz3LfK021IjV1rj1ypE+R7jHm+pIHmHl25VNkZxtx9uuYp7ThGk8fur1HHG7PgQ== +"@babel/plugin-transform-computed-properties@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz#2357a8224d402dad623caf6259b611e56aec746e" + integrity sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.9" -"@babel/plugin-transform-destructuring@^7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.0.tgz#dc4f92587e291b4daa78aa20cc2d7a63aa11e858" - integrity sha512-Mo69klS79z6KEfrLg/1WkmVnB8javh75HX4pi2btjvlIoasuxilEyjtsQW6XPrubNd7AQy0MMaNIaQE4e7+PQw== +"@babel/plugin-transform-destructuring@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.2.tgz#c23741cfa44ddd35f5e53896e88c75331b8b2792" + integrity sha512-mENM+ZHrvEgxLTBXUiQ621rRXZes3KWUv6NdQlrnr1TkWVw+hUjQBZuP2X32qKlrlG2BzgR95gkuCRSkJl8vIw== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.20.2" -"@babel/plugin-transform-dotall-regex@^7.16.7", "@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz#6b2d67686fab15fb6a7fd4bd895d5982cfc81241" - integrity sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ== +"@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz#b286b3e7aae6c7b861e45bed0a2fafd6b1a4fef8" + integrity sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-duplicate-keys@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.17.12.tgz#a09aa709a3310013f8e48e0e23bc7ace0f21477c" - integrity sha512-EA5eYFUG6xeerdabina/xIoB95jJ17mAkR8ivx6ZSu9frKShBjpOGZPn511MTDTkiCO+zXnzNczvUM69YSf3Zw== +"@babel/plugin-transform-duplicate-keys@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz#687f15ee3cdad6d85191eb2a372c4528eaa0ae0e" + integrity sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.9" -"@babel/plugin-transform-exponentiation-operator@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz#efa9862ef97e9e9e5f653f6ddc7b665e8536fe9b" - integrity sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA== +"@babel/plugin-transform-exponentiation-operator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz#421c705f4521888c65e91fdd1af951bfefd4dacd" + integrity sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-for-of@^7.18.1": - version "7.18.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.1.tgz#ed14b657e162b72afbbb2b4cdad277bf2bb32036" - integrity sha512-+TTB5XwvJ5hZbO8xvl2H4XaMDOAK57zF4miuC9qQJgysPNEAZZ9Z69rdF5LJkozGdZrjBIUAIyKUWRMmebI7vg== +"@babel/plugin-transform-for-of@^7.18.8": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz#6ef8a50b244eb6a0bdbad0c7c61877e4e30097c1" + integrity sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-function-name@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz#5ab34375c64d61d083d7d2f05c38d90b97ec65cf" - integrity sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA== +"@babel/plugin-transform-function-name@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz#cc354f8234e62968946c61a46d6365440fc764e0" + integrity sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ== dependencies: - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" -"@babel/plugin-transform-literals@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.17.12.tgz#97131fbc6bbb261487105b4b3edbf9ebf9c830ae" - integrity sha512-8iRkvaTjJciWycPIZ9k9duu663FT7VrBdNqNgxnVXEFwOIp55JWcZd23VBRySYbnS3PwQ3rGiabJBBBGj5APmQ== +"@babel/plugin-transform-literals@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz#72796fdbef80e56fba3c6a699d54f0de557444bc" + integrity sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.9" -"@babel/plugin-transform-member-expression-literals@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz#6e5dcf906ef8a098e630149d14c867dd28f92384" - integrity sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw== +"@babel/plugin-transform-member-expression-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz#ac9fdc1a118620ac49b7e7a5d2dc177a1bfee88e" + integrity sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-modules-amd@^7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.0.tgz#7ef1002e67e36da3155edc8bf1ac9398064c02ed" - integrity sha512-h8FjOlYmdZwl7Xm2Ug4iX2j7Qy63NANI+NQVWQzv6r25fqgg7k2dZl03p95kvqNclglHs4FZ+isv4p1uXMA+QA== +"@babel/plugin-transform-modules-amd@^7.19.6": + version "7.19.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz#aca391801ae55d19c4d8d2ebfeaa33df5f2a2cbd" + integrity sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg== dependencies: - "@babel/helper-module-transforms" "^7.18.0" - "@babel/helper-plugin-utils" "^7.17.12" - babel-plugin-dynamic-import-node "^2.3.3" + "@babel/helper-module-transforms" "^7.19.6" + "@babel/helper-plugin-utils" "^7.19.0" -"@babel/plugin-transform-modules-commonjs@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.2.tgz#1aa8efa2e2a6e818b6a7f2235fceaf09bdb31e9e" - integrity sha512-f5A865gFPAJAEE0K7F/+nm5CmAE3y8AWlMBG9unu5j9+tk50UQVK0QS8RNxSp7MJf0wh97uYyLWt3Zvu71zyOQ== +"@babel/plugin-transform-modules-commonjs@^7.19.6": + version "7.19.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz#25b32feef24df8038fc1ec56038917eacb0b730c" + integrity sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ== dependencies: - "@babel/helper-module-transforms" "^7.18.0" - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-simple-access" "^7.18.2" - babel-plugin-dynamic-import-node "^2.3.3" + "@babel/helper-module-transforms" "^7.19.6" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-simple-access" "^7.19.4" -"@babel/plugin-transform-modules-systemjs@^7.18.0": - version "7.18.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.4.tgz#3d6fd9868c735cce8f38d6ae3a407fb7e61e6d46" - integrity sha512-lH2UaQaHVOAeYrUUuZ8i38o76J/FnO8vu21OE+tD1MyP9lxdZoSfz+pDbWkq46GogUrdrMz3tiz/FYGB+bVThg== +"@babel/plugin-transform-modules-systemjs@^7.19.6": + version "7.19.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz#59e2a84064b5736a4471b1aa7b13d4431d327e0d" + integrity sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ== dependencies: - "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-module-transforms" "^7.18.0" - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-validator-identifier" "^7.16.7" - babel-plugin-dynamic-import-node "^2.3.3" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-module-transforms" "^7.19.6" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-validator-identifier" "^7.19.1" -"@babel/plugin-transform-modules-umd@^7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.0.tgz#56aac64a2c2a1922341129a4597d1fd5c3ff020f" - integrity sha512-d/zZ8I3BWli1tmROLxXLc9A6YXvGK8egMxHp+E/rRwMh1Kip0AP77VwZae3snEJ33iiWwvNv2+UIIhfalqhzZA== +"@babel/plugin-transform-modules-umd@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz#81d3832d6034b75b54e62821ba58f28ed0aab4b9" + integrity sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ== dependencies: - "@babel/helper-module-transforms" "^7.18.0" - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-named-capturing-groups-regex@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.17.12.tgz#9c4a5a5966e0434d515f2675c227fd8cc8606931" - integrity sha512-vWoWFM5CKaTeHrdUJ/3SIOTRV+MBVGybOC9mhJkaprGNt5demMymDW24yC74avb915/mIRe3TgNb/d8idvnCRA== +"@babel/plugin-transform-named-capturing-groups-regex@^7.19.1": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz#626298dd62ea51d452c3be58b285d23195ba69a8" + integrity sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.17.12" - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-create-regexp-features-plugin" "^7.20.5" + "@babel/helper-plugin-utils" "^7.20.2" -"@babel/plugin-transform-new-target@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.17.12.tgz#10842cd605a620944e81ea6060e9e65c265742e3" - integrity sha512-CaOtzk2fDYisbjAD4Sd1MTKGVIpRtx9bWLyj24Y/k6p4s4gQ3CqDGJauFJxt8M/LEx003d0i3klVqnN73qvK3w== +"@babel/plugin-transform-new-target@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz#d128f376ae200477f37c4ddfcc722a8a1b3246a8" + integrity sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-object-super@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz#ac359cf8d32cf4354d27a46867999490b6c32a94" - integrity sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw== +"@babel/plugin-transform-object-super@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz#fb3c6ccdd15939b6ff7939944b51971ddc35912c" + integrity sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.6" -"@babel/plugin-transform-parameters@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.17.12.tgz#eb467cd9586ff5ff115a9880d6fdbd4a846b7766" - integrity sha512-6qW4rWo1cyCdq1FkYri7AHpauchbGLXpdwnYsfxFb+KtddHENfsY5JZb35xUwkK5opOLcJ3BNd2l7PhRYGlwIA== +"@babel/plugin-transform-parameters@^7.20.1": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.5.tgz#f8f9186c681d10c3de7620c916156d893c8a019e" + integrity sha512-h7plkOmcndIUWXZFLgpbrh2+fXAi47zcUX7IrOQuZdLD0I0KvjJ6cvo3BEcAOsDOcZhVKGJqv07mkSqK0y2isQ== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.20.2" -"@babel/plugin-transform-property-literals@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz#2dadac85155436f22c696c4827730e0fe1057a55" - integrity sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw== +"@babel/plugin-transform-property-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz#e22498903a483448e94e032e9bbb9c5ccbfc93a3" + integrity sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-react-display-name@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz#7b6d40d232f4c0f550ea348593db3b21e2404340" - integrity sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg== +"@babel/plugin-transform-react-display-name@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz#8b1125f919ef36ebdfff061d664e266c666b9415" + integrity sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-react-jsx-development@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz#43a00724a3ed2557ed3f276a01a929e6686ac7b8" - integrity sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A== +"@babel/plugin-transform-react-jsx-development@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz#dbe5c972811e49c7405b630e4d0d2e1380c0ddc5" + integrity sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA== dependencies: - "@babel/plugin-transform-react-jsx" "^7.16.7" + "@babel/plugin-transform-react-jsx" "^7.18.6" -"@babel/plugin-transform-react-jsx@^7.16.7", "@babel/plugin-transform-react-jsx@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.12.tgz#2aa20022709cd6a3f40b45d60603d5f269586dba" - integrity sha512-Lcaw8bxd1DKht3thfD4A12dqo1X16he1Lm8rIv8sTwjAYNInRS1qHa9aJoqvzpscItXvftKDCfaEQzwoVyXpEQ== +"@babel/plugin-transform-react-jsx@^7.18.6": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz#b3cbb7c3a00b92ec8ae1027910e331ba5c500eb9" + integrity sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/plugin-syntax-jsx" "^7.17.12" - "@babel/types" "^7.17.12" + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/plugin-syntax-jsx" "^7.18.6" + "@babel/types" "^7.19.0" -"@babel/plugin-transform-react-pure-annotations@^7.16.7": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.0.tgz#ef82c8e310913f3522462c9ac967d395092f1954" - integrity sha512-6+0IK6ouvqDn9bmEG7mEyF/pwlJXVj5lwydybpyyH3D0A7Hftk+NCTdYjnLNZksn261xaOV5ksmp20pQEmc2RQ== +"@babel/plugin-transform-react-pure-annotations@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz#561af267f19f3e5d59291f9950fd7b9663d0d844" + integrity sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-regenerator@^7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.0.tgz#44274d655eb3f1af3f3a574ba819d3f48caf99d5" - integrity sha512-C8YdRw9uzx25HSIzwA7EM7YP0FhCe5wNvJbZzjVNHHPGVcDJ3Aie+qGYYdS1oVQgn+B3eAIJbWFLrJ4Jipv7nw== +"@babel/plugin-transform-regenerator@^7.18.6": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz#57cda588c7ffb7f4f8483cc83bdcea02a907f04d" + integrity sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - regenerator-transform "^0.15.0" + "@babel/helper-plugin-utils" "^7.20.2" + regenerator-transform "^0.15.1" -"@babel/plugin-transform-reserved-words@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.17.12.tgz#7dbd349f3cdffba751e817cf40ca1386732f652f" - integrity sha512-1KYqwbJV3Co03NIi14uEHW8P50Md6KqFgt0FfpHdK6oyAHQVTosgPuPSiWud1HX0oYJ1hGRRlk0fP87jFpqXZA== +"@babel/plugin-transform-reserved-words@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz#b1abd8ebf8edaa5f7fe6bbb8d2133d23b6a6f76a" + integrity sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-shorthand-properties@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz#e8549ae4afcf8382f711794c0c7b6b934c5fbd2a" - integrity sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg== +"@babel/plugin-transform-shorthand-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz#6d6df7983d67b195289be24909e3f12a8f664dc9" + integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-spread@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.17.12.tgz#c112cad3064299f03ea32afed1d659223935d1f5" - integrity sha512-9pgmuQAtFi3lpNUstvG9nGfk9DkrdmWNp9KeKPFmuZCpEnxRzYlS8JgwPjYj+1AWDOSvoGN0H30p1cBOmT/Svg== +"@babel/plugin-transform-spread@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz#dd60b4620c2fec806d60cfaae364ec2188d593b6" + integrity sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" -"@babel/plugin-transform-sticky-regex@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz#c84741d4f4a38072b9a1e2e3fd56d359552e8660" - integrity sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw== +"@babel/plugin-transform-sticky-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz#c6706eb2b1524028e317720339583ad0f444adcc" + integrity sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-template-literals@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.2.tgz#31ed6915721864847c48b656281d0098ea1add28" - integrity sha512-/cmuBVw9sZBGZVOMkpAEaVLwm4JmK2GZ1dFKOGGpMzEHWFmyZZ59lUU0PdRr8YNYeQdNzTDwuxP2X2gzydTc9g== +"@babel/plugin-transform-template-literals@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz#04ec6f10acdaa81846689d63fae117dd9c243a5e" + integrity sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.9" -"@babel/plugin-transform-typeof-symbol@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.17.12.tgz#0f12f57ac35e98b35b4ed34829948d42bd0e6889" - integrity sha512-Q8y+Jp7ZdtSPXCThB6zjQ74N3lj0f6TDh1Hnf5B+sYlzQ8i5Pjp8gW0My79iekSpT4WnI06blqP6DT0OmaXXmw== +"@babel/plugin-transform-typeof-symbol@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz#c8cea68263e45addcd6afc9091429f80925762c0" + integrity sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.9" -"@babel/plugin-transform-unicode-escapes@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz#da8717de7b3287a2c6d659750c964f302b31ece3" - integrity sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q== +"@babel/plugin-transform-unicode-escapes@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz#1ecfb0eda83d09bbcb77c09970c2dd55832aa246" + integrity sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.9" -"@babel/plugin-transform-unicode-regex@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz#0f7aa4a501198976e25e82702574c34cfebe9ef2" - integrity sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q== +"@babel/plugin-transform-unicode-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz#194317225d8c201bbae103364ffe9e2cea36cdca" + integrity sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/preset-env@7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.18.2.tgz#f47d3000a098617926e674c945d95a28cb90977a" - integrity sha512-PfpdxotV6afmXMU47S08F9ZKIm2bJIQ0YbAAtDfIENX7G1NUAXigLREh69CWDjtgUy7dYn7bsMzkgdtAlmS68Q== +"@babel/preset-env@7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.20.2.tgz#9b1642aa47bb9f43a86f9630011780dab7f86506" + integrity sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg== dependencies: - "@babel/compat-data" "^7.17.10" - "@babel/helper-compilation-targets" "^7.18.2" - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.17.12" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.17.12" - "@babel/plugin-proposal-async-generator-functions" "^7.17.12" - "@babel/plugin-proposal-class-properties" "^7.17.12" - "@babel/plugin-proposal-class-static-block" "^7.18.0" - "@babel/plugin-proposal-dynamic-import" "^7.16.7" - "@babel/plugin-proposal-export-namespace-from" "^7.17.12" - "@babel/plugin-proposal-json-strings" "^7.17.12" - "@babel/plugin-proposal-logical-assignment-operators" "^7.17.12" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.17.12" - "@babel/plugin-proposal-numeric-separator" "^7.16.7" - "@babel/plugin-proposal-object-rest-spread" "^7.18.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.16.7" - "@babel/plugin-proposal-optional-chaining" "^7.17.12" - "@babel/plugin-proposal-private-methods" "^7.17.12" - "@babel/plugin-proposal-private-property-in-object" "^7.17.12" - "@babel/plugin-proposal-unicode-property-regex" "^7.17.12" + "@babel/compat-data" "^7.20.1" + "@babel/helper-compilation-targets" "^7.20.0" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9" + "@babel/plugin-proposal-async-generator-functions" "^7.20.1" + "@babel/plugin-proposal-class-properties" "^7.18.6" + "@babel/plugin-proposal-class-static-block" "^7.18.6" + "@babel/plugin-proposal-dynamic-import" "^7.18.6" + "@babel/plugin-proposal-export-namespace-from" "^7.18.9" + "@babel/plugin-proposal-json-strings" "^7.18.6" + "@babel/plugin-proposal-logical-assignment-operators" "^7.18.9" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6" + "@babel/plugin-proposal-numeric-separator" "^7.18.6" + "@babel/plugin-proposal-object-rest-spread" "^7.20.2" + "@babel/plugin-proposal-optional-catch-binding" "^7.18.6" + "@babel/plugin-proposal-optional-chaining" "^7.18.9" + "@babel/plugin-proposal-private-methods" "^7.18.6" + "@babel/plugin-proposal-private-property-in-object" "^7.18.6" + "@babel/plugin-proposal-unicode-property-regex" "^7.18.6" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-class-properties" "^7.12.13" "@babel/plugin-syntax-class-static-block" "^7.14.5" "@babel/plugin-syntax-dynamic-import" "^7.8.3" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-import-assertions" "^7.17.12" + "@babel/plugin-syntax-import-assertions" "^7.20.0" "@babel/plugin-syntax-json-strings" "^7.8.3" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" @@ -919,44 +921,44 @@ "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-transform-arrow-functions" "^7.17.12" - "@babel/plugin-transform-async-to-generator" "^7.17.12" - "@babel/plugin-transform-block-scoped-functions" "^7.16.7" - "@babel/plugin-transform-block-scoping" "^7.17.12" - "@babel/plugin-transform-classes" "^7.17.12" - "@babel/plugin-transform-computed-properties" "^7.17.12" - "@babel/plugin-transform-destructuring" "^7.18.0" - "@babel/plugin-transform-dotall-regex" "^7.16.7" - "@babel/plugin-transform-duplicate-keys" "^7.17.12" - "@babel/plugin-transform-exponentiation-operator" "^7.16.7" - "@babel/plugin-transform-for-of" "^7.18.1" - "@babel/plugin-transform-function-name" "^7.16.7" - "@babel/plugin-transform-literals" "^7.17.12" - "@babel/plugin-transform-member-expression-literals" "^7.16.7" - "@babel/plugin-transform-modules-amd" "^7.18.0" - "@babel/plugin-transform-modules-commonjs" "^7.18.2" - "@babel/plugin-transform-modules-systemjs" "^7.18.0" - "@babel/plugin-transform-modules-umd" "^7.18.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.17.12" - "@babel/plugin-transform-new-target" "^7.17.12" - "@babel/plugin-transform-object-super" "^7.16.7" - "@babel/plugin-transform-parameters" "^7.17.12" - "@babel/plugin-transform-property-literals" "^7.16.7" - "@babel/plugin-transform-regenerator" "^7.18.0" - "@babel/plugin-transform-reserved-words" "^7.17.12" - "@babel/plugin-transform-shorthand-properties" "^7.16.7" - "@babel/plugin-transform-spread" "^7.17.12" - "@babel/plugin-transform-sticky-regex" "^7.16.7" - "@babel/plugin-transform-template-literals" "^7.18.2" - "@babel/plugin-transform-typeof-symbol" "^7.17.12" - "@babel/plugin-transform-unicode-escapes" "^7.16.7" - "@babel/plugin-transform-unicode-regex" "^7.16.7" + "@babel/plugin-transform-arrow-functions" "^7.18.6" + "@babel/plugin-transform-async-to-generator" "^7.18.6" + "@babel/plugin-transform-block-scoped-functions" "^7.18.6" + "@babel/plugin-transform-block-scoping" "^7.20.2" + "@babel/plugin-transform-classes" "^7.20.2" + "@babel/plugin-transform-computed-properties" "^7.18.9" + "@babel/plugin-transform-destructuring" "^7.20.2" + "@babel/plugin-transform-dotall-regex" "^7.18.6" + "@babel/plugin-transform-duplicate-keys" "^7.18.9" + "@babel/plugin-transform-exponentiation-operator" "^7.18.6" + "@babel/plugin-transform-for-of" "^7.18.8" + "@babel/plugin-transform-function-name" "^7.18.9" + "@babel/plugin-transform-literals" "^7.18.9" + "@babel/plugin-transform-member-expression-literals" "^7.18.6" + "@babel/plugin-transform-modules-amd" "^7.19.6" + "@babel/plugin-transform-modules-commonjs" "^7.19.6" + "@babel/plugin-transform-modules-systemjs" "^7.19.6" + "@babel/plugin-transform-modules-umd" "^7.18.6" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.19.1" + "@babel/plugin-transform-new-target" "^7.18.6" + "@babel/plugin-transform-object-super" "^7.18.6" + "@babel/plugin-transform-parameters" "^7.20.1" + "@babel/plugin-transform-property-literals" "^7.18.6" + "@babel/plugin-transform-regenerator" "^7.18.6" + "@babel/plugin-transform-reserved-words" "^7.18.6" + "@babel/plugin-transform-shorthand-properties" "^7.18.6" + "@babel/plugin-transform-spread" "^7.19.0" + "@babel/plugin-transform-sticky-regex" "^7.18.6" + "@babel/plugin-transform-template-literals" "^7.18.9" + "@babel/plugin-transform-typeof-symbol" "^7.18.9" + "@babel/plugin-transform-unicode-escapes" "^7.18.10" + "@babel/plugin-transform-unicode-regex" "^7.18.6" "@babel/preset-modules" "^0.1.5" - "@babel/types" "^7.18.2" - babel-plugin-polyfill-corejs2 "^0.3.0" - babel-plugin-polyfill-corejs3 "^0.5.0" - babel-plugin-polyfill-regenerator "^0.3.0" - core-js-compat "^3.22.1" + "@babel/types" "^7.20.2" + babel-plugin-polyfill-corejs2 "^0.3.3" + babel-plugin-polyfill-corejs3 "^0.6.0" + babel-plugin-polyfill-regenerator "^0.4.1" + core-js-compat "^3.25.1" semver "^6.3.0" "@babel/preset-modules@^0.1.5": @@ -970,56 +972,57 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-react@7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.17.12.tgz#62adbd2d1870c0de3893095757ed5b00b492ab3d" - integrity sha512-h5U+rwreXtZaRBEQhW1hOJLMq8XNJBQ/9oymXiCXTuT/0uOwpbT0gUt+sXeOqoXBgNuUKI7TaObVwoEyWkpFgA== +"@babel/preset-react@7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.18.6.tgz#979f76d6277048dc19094c217b507f3ad517dd2d" + integrity sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-transform-react-display-name" "^7.16.7" - "@babel/plugin-transform-react-jsx" "^7.17.12" - "@babel/plugin-transform-react-jsx-development" "^7.16.7" - "@babel/plugin-transform-react-pure-annotations" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-transform-react-display-name" "^7.18.6" + "@babel/plugin-transform-react-jsx" "^7.18.6" + "@babel/plugin-transform-react-jsx-development" "^7.18.6" + "@babel/plugin-transform-react-pure-annotations" "^7.18.6" "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": - version "7.18.3" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.3.tgz#c7b654b57f6f63cf7f8b418ac9ca04408c4579f4" - integrity sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug== + version "7.20.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.6.tgz#facf4879bfed9b5326326273a64220f099b0fce3" + integrity sha512-Q+8MqP7TiHMWzSfwiJwXCjyf4GYA4Dgw3emg/7xmwsdLJOZUp+nMqcOwOzzYheuM1rhDu8FSj2l0aoMygEuXuA== dependencies: - regenerator-runtime "^0.13.4" + regenerator-runtime "^0.13.11" -"@babel/template@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" - integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== +"@babel/template@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" + integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/parser" "^7.16.7" - "@babel/types" "^7.16.7" + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.10" + "@babel/types" "^7.18.10" -"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.18.0", "@babel/traverse@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.2.tgz#b77a52604b5cc836a9e1e08dca01cba67a12d2e8" - integrity sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA== +"@babel/traverse@^7.19.1", "@babel/traverse@^7.20.1", "@babel/traverse@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.5.tgz#78eb244bea8270fdda1ef9af22a5d5e5b7e57133" + integrity sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ== dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.18.2" - "@babel/helper-environment-visitor" "^7.18.2" - "@babel/helper-function-name" "^7.17.9" - "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.18.0" - "@babel/types" "^7.18.2" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.20.5" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.20.5" + "@babel/types" "^7.20.5" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.17.12", "@babel/types@^7.18.0", "@babel/types@^7.18.2", "@babel/types@^7.4.4": - version "7.18.4" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.4.tgz#27eae9b9fd18e9dccc3f9d6ad051336f307be354" - integrity sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw== +"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.4.4": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.5.tgz#e206ae370b5393d94dfd1d04cd687cace53efa84" + integrity sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg== dependencies: - "@babel/helper-validator-identifier" "^7.16.7" + "@babel/helper-string-parser" "^7.19.4" + "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" "@cnakazawa/watch@^1.0.3": @@ -1030,20 +1033,25 @@ exec-sh "^0.3.2" minimist "^1.2.0" +"@csstools/selector-specificity@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz#1bfafe4b7ed0f3e4105837e056e0a89b108ebe36" + integrity sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg== + "@discoveryjs/json-ext@^0.5.0": version "0.5.7" resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@eslint/eslintrc@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" - integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw== +"@eslint/eslintrc@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.0.tgz#8ec64e0df3e7a1971ee1ff5158da87389f167a63" + integrity sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.3.2" - globals "^13.15.0" + espree "^9.4.0" + globals "^13.19.0" ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" @@ -1088,14 +1096,19 @@ dependencies: prop-types "^15.8.1" -"@humanwhocodes/config-array@^0.9.2": - version "0.9.5" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" - integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== +"@humanwhocodes/config-array@^0.11.8": + version "0.11.8" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" + integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== dependencies: "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" - minimatch "^3.0.4" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== "@humanwhocodes/object-schema@^1.2.1": version "1.2.1" @@ -1110,24 +1123,24 @@ "@jridgewell/set-array" "^1.0.0" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/gen-mapping@^0.3.0": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz#cf92a983c83466b8c0ce9124fadeaf09f7c66ea9" - integrity sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg== +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== dependencies: - "@jridgewell/set-array" "^1.0.0" + "@jridgewell/set-array" "^1.0.1" "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/resolve-uri@^3.0.3": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe" - integrity sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA== +"@jridgewell/resolve-uri@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== -"@jridgewell/set-array@^1.0.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea" - integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ== +"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== "@jridgewell/source-map@^0.3.2": version "0.3.2" @@ -1137,18 +1150,18 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.13" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c" - integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w== +"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/trace-mapping@^0.3.7", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.13" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea" - integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w== +"@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.17" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" + integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" "@microsoft/signalr@6.0.11": version "6.0.11" @@ -1161,13 +1174,12 @@ node-fetch "^2.6.7" ws "^7.4.5" -"@mrmlnc/readdir-enhanced@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" - integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== +"@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": + version "5.1.1-v1" + resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" + integrity sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg== dependencies: - call-me-maybe "^1.0.1" - glob-to-regexp "^0.3.0" + eslint-scope "5.1.1" "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -1182,12 +1194,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.stat@^1.1.2": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" - integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== - -"@nodelib/fs.walk@^1.2.3": +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -1272,7 +1279,7 @@ "@sentry/types" "6.19.2" tslib "^1.9.3" -"@types/archiver@^5.1.1": +"@types/archiver@^5.3.1": version "5.3.1" resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-5.3.1.tgz#02991e940a03dd1a32678fead4b4ca03d0e387ca" integrity sha512-wKYZaSXaDvTZuInAWjCeGG7BEAgTWG2zZW0/f7IYFcoHB2X2d9lkVFnrOlXl3W6NrvO6Ml3FLLu8Uksyymcpnw== @@ -1287,39 +1294,35 @@ "@types/node" "*" "@types/eslint-scope@^3.7.3": - version "3.7.3" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224" - integrity sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g== + version "3.7.4" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" + integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== dependencies: "@types/eslint" "*" "@types/estree" "*" "@types/eslint@*": - version "8.4.2" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.2.tgz#48f2ac58ab9c631cb68845c3d956b28f79fad575" - integrity sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA== + version "8.4.10" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.10.tgz#19731b9685c19ed1552da7052b6f668ed7eb64bb" + integrity sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw== dependencies: "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*", "@types/estree@^0.0.51": +"@types/estree@*": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" + integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== + +"@types/estree@^0.0.51": version "0.0.51" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== -"@types/express-serve-static-core@^4.17.9": - version "4.17.28" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz#c47def9f34ec81dc6328d0b1b5303d1ec98d86b8" - integrity sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig== - dependencies: - "@types/node" "*" - "@types/qs" "*" - "@types/range-parser" "*" - -"@types/glob@*", "@types/glob@^7.1.1": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" - integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== +"@types/glob@*": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-8.0.0.tgz#321607e9cbaec54f687a0792b2d1d370739455d2" + integrity sha512-l6NQsDDyQUVeoTynNpC9uRvCUint/gSUXQA2euwmTuWGvPY5LSDUu6tkCtJB2SvGQlJQzLaKqcGZP4//7EDveA== dependencies: "@types/minimatch" "*" "@types/node" "*" @@ -1337,7 +1340,7 @@ resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== -"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": +"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== @@ -1347,15 +1350,10 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== -"@types/lodash@^4.14.159": - version "4.14.182" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2" - integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q== - "@types/minimatch@*": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" - integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" + integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== "@types/minimist@^1.2.0": version "1.2.2" @@ -1363,14 +1361,14 @@ integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== "@types/node@*": - version "17.0.39" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.39.tgz#3652d82e2a16b4ea679d5ea3143b816c91b7e113" - integrity sha512-JDU3YLlnPK3WDao6/DlXLOgSNpG13ct+CwIO17V8q0/9fWJyeMJJ/VyZ1lv8kDprihvZMydzVwf0tQOqGiY2Nw== + version "18.11.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.17.tgz#5c009e1d9c38f4a2a9d45c0b0c493fe6cdb4bcb5" + integrity sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng== "@types/node@^12.12.54": - version "12.20.54" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.54.tgz#38a3dff8c2a939553f2cdb85dcddc68be46c3c68" - integrity sha512-CFMnEPkSXWALI73t1oIWyb8QOmVrp6RruAqIx349sd+1ImaFwzlKcz55mwrx/yLyOyz1gkq/UKuNOigt27PXqg== + version "12.20.55" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -1387,16 +1385,6 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== -"@types/qs@*": - version "6.9.7" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" - integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== - -"@types/range-parser@*": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" - integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== - "@types/react-redux@^7.1.16": version "7.1.24" resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.24.tgz#6caaff1603aba17b27d20f8ad073e4c077e975c0" @@ -1408,9 +1396,9 @@ redux "^4.0.0" "@types/react@*": - version "18.0.11" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.11.tgz#94c9b62020caff17d117374d724de853ec711d21" - integrity sha512-JxSwm54IgMW4XTR+zFF5QpNx4JITmFbB4WHR2J0vg9RpjNeyqEMlODXsD2e64br6GX70TL0UYjZJETpyyC1WdA== + version "18.0.26" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.26.tgz#8ad59fc01fef8eaf5c74f4ea392621749f0b7917" + integrity sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -1549,22 +1537,20 @@ "@webassemblyjs/ast" "1.11.1" "@xtuc/long" "4.2.2" -"@webpack-cli/configtest@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.1.1.tgz#9f53b1b7946a6efc2a749095a4f450e2932e8356" - integrity sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg== +"@webpack-cli/configtest@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.0.1.tgz#a69720f6c9bad6aef54a8fa6ba9c3533e7ef4c7f" + integrity sha512-njsdJXJSiS2iNbQVS0eT8A/KPnmyH4pv1APj2K0d1wrZcBLw+yppxOy4CGqa0OxDJkzfL/XELDhD8rocnIwB5A== -"@webpack-cli/info@^1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.4.1.tgz#2360ea1710cbbb97ff156a3f0f24556e0fc1ebea" - integrity sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA== - dependencies: - envinfo "^7.7.3" +"@webpack-cli/info@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.1.tgz#eed745799c910d20081e06e5177c2b2569f166c0" + integrity sha512-fE1UEWTwsAxRhrJNikE7v4EotYflkEhBL7EbajfkPlf6E37/2QshOy/D48Mw8G5XMFlQtS6YV42vtbG9zBpIQA== -"@webpack-cli/serve@^1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.1.tgz#0de2875ac31b46b6c5bb1ae0a7d7f0ba5678dffe" - integrity sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw== +"@webpack-cli/serve@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.1.tgz#34bdc31727a1889198855913db2f270ace6d7bf8" + integrity sha512-0G7tNyS+yW8TdgHwZKlDWYXFA6OJQnoLCQvYKkQP0Q2X205PSQ6RNUj0M+1OB/9gRQaUZ/ccYfaxd0nhaWKfjw== "@xtuc/ieee754@^1.2.0": version "1.2.0" @@ -1601,10 +1587,10 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1: - version "8.7.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" - integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== +acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.0: + version "8.8.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73" + integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA== add-px-to-style@1.0.0: version "1.0.0" @@ -1649,9 +1635,9 @@ ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5: uri-js "^4.2.2" ajv@^8.0.0, ajv@^8.0.1, ajv@^8.8.0: - version "8.11.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" - integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== + version "8.11.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.2.tgz#aecb20b50607acf2569b6382167b65a96008bb78" + integrity sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -1714,9 +1700,9 @@ ansi-wrap@0.1.0: integrity sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw== anymatch@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" @@ -1737,7 +1723,7 @@ archiver-utils@^2.1.0: normalize-path "^3.0.0" readable-stream "^2.0.0" -archiver@^5.3.0: +archiver@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.1.tgz#21e92811d6f09ecfce649fbefefe8c79e57cbbb6" integrity sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w== @@ -1763,12 +1749,7 @@ arr-diff@^1.0.1: arr-flatten "^1.0.1" array-slice "^0.2.3" -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA== - -arr-flatten@^1.0.1, arr-flatten@^1.1.0: +arr-flatten@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== @@ -1778,20 +1759,15 @@ arr-union@^2.0.1: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-2.1.0.tgz#20f9eab5ec70f5c7d215b1077b1c39161d292c7d" integrity sha512-t5db90jq+qdgk8aFnxEkjqta0B/GHrM1pxzuuZz2zWsOXc5nKu3t+76s/PQBA8FTcM/ipspIH9jWG4OxCBc2eA== -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== - -array-includes@^3.1.4, array-includes@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.5.tgz#2c320010db8d31031fd2a5f6b3bbd4b1aad31bdb" - integrity sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ== +array-includes@^3.1.4, array-includes@^3.1.5, array-includes@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" + integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== dependencies: call-bind "^1.0.2" define-properties "^1.1.4" - es-abstract "^1.19.5" - get-intrinsic "^1.1.1" + es-abstract "^1.20.4" + get-intrinsic "^1.1.3" is-string "^1.0.7" array-slice@^0.2.3: @@ -1799,69 +1775,53 @@ array-slice@^0.2.3: resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" integrity sha512-rlVfZW/1Ph2SNySXwR9QYkChp8EkOEiTMO5Vwx60usw04i4nWemkm9RXmQqgkQFaLHsqLuADvjp6IfgL9l2M8Q== -array-union@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng== - dependencies: - array-uniq "^1.0.1" - array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ== - array.prototype.flat@^1.2.5: - version "1.3.0" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz#0b0c1567bf57b38b56b4c97b8aa72ab45e4adc7b" - integrity sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw== + version "1.3.1" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" + integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz#a7e8ed4225f4788a70cd910abcf0791e76a5534f" - integrity sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg== +array.prototype.flatmap@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" + integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" es-shim-unscopables "^1.0.0" +array.prototype.tosorted@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz#ccf44738aa2b5ac56578ffda97c03fd3e23dd532" + integrity sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + get-intrinsic "^1.1.3" + arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== -arrify@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" - integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== - astral-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== -async@^2.6.2: +async@^2.6.4: version "2.6.4" resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== @@ -1869,72 +1829,58 @@ async@^2.6.2: lodash "^4.17.14" async@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9" - integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g== + version "3.2.4" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" + integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== -atob@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -autoprefixer@10.4.7: - version "10.4.7" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.7.tgz#1db8d195f41a52ca5069b7593be167618edbbedf" - integrity sha512-ypHju4Y2Oav95SipEcCcI5J7CGPuvz8oat7sUtYj3ClK44bldfvtvcxK6IEK++7rqB7YchDGzweZIBG+SD0ZAA== +autoprefixer@10.4.13: + version "10.4.13" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.13.tgz#b5136b59930209a321e9fa3dca2e7c4d223e83a8" + integrity sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg== dependencies: - browserslist "^4.20.3" - caniuse-lite "^1.0.30001335" + browserslist "^4.21.4" + caniuse-lite "^1.0.30001426" fraction.js "^4.2.0" normalize-range "^0.1.2" picocolors "^1.0.0" postcss-value-parser "^4.2.0" -babel-loader@8.2.5: - version "8.2.5" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.5.tgz#d45f585e654d5a5d90f5350a779d7647c5ed512e" - integrity sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ== +babel-loader@9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-9.1.0.tgz#839e9ae88aea930864ef9ec0f356dfca96ecf238" + integrity sha512-Antt61KJPinUMwHwIIz9T5zfMgevnfZkEVWYDWlG888fgdvRRGD0JTuf/fFozQnfT+uq64sk1bmdHDy/mOEWnA== dependencies: - find-cache-dir "^3.3.1" - loader-utils "^2.0.0" - make-dir "^3.1.0" - schema-utils "^2.6.5" - -babel-plugin-dynamic-import-node@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" - integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== - dependencies: - object.assign "^4.1.0" + find-cache-dir "^3.3.2" + schema-utils "^4.0.0" babel-plugin-inline-classnames@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/babel-plugin-inline-classnames/-/babel-plugin-inline-classnames-2.0.1.tgz#d871490af06781a42f231a1e090bc4133594f168" integrity sha512-Pq/jJ6hTiGiqcMmy2d4CyJcfBDeUHOdQl1t1MDWNaSKR2RxDmShSAx4Zqz6NDmFaiinaRqF8eQoTVgSRGU+McQ== -babel-plugin-polyfill-corejs2@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz#440f1b70ccfaabc6b676d196239b138f8a2cfba5" - integrity sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w== +babel-plugin-polyfill-corejs2@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz#5d1bd3836d0a19e1b84bbf2d9640ccb6f951c122" + integrity sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q== dependencies: - "@babel/compat-data" "^7.13.11" - "@babel/helper-define-polyfill-provider" "^0.3.1" + "@babel/compat-data" "^7.17.7" + "@babel/helper-define-polyfill-provider" "^0.3.3" semver "^6.1.1" -babel-plugin-polyfill-corejs3@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz#aabe4b2fa04a6e038b688c5e55d44e78cd3a5f72" - integrity sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ== +babel-plugin-polyfill-corejs3@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz#56ad88237137eade485a71b52f72dbed57c6230a" + integrity sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA== dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.1" - core-js-compat "^3.21.0" + "@babel/helper-define-polyfill-provider" "^0.3.3" + core-js-compat "^3.25.1" -babel-plugin-polyfill-regenerator@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz#2c0678ea47c75c8cc2fbb1852278d8fb68233990" - integrity sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A== +babel-plugin-polyfill-regenerator@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz#390f91c38d90473592ed43351e801a9d3e0fd747" + integrity sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw== dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.1" + "@babel/helper-define-polyfill-provider" "^0.3.3" babel-plugin-transform-react-remove-prop-types@0.4.24: version "0.4.24" @@ -1969,19 +1915,6 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -2019,21 +1952,12 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" + balanced-match "^1.0.0" braces@^3.0.2: version "3.0.2" @@ -2042,16 +1966,15 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.14.5, browserslist@^4.20.2, browserslist@^4.20.3: - version "4.20.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.3.tgz#eb7572f49ec430e054f56d52ff0ebe9be915f8bf" - integrity sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg== +browserslist@^4.14.5, browserslist@^4.21.3, browserslist@^4.21.4: + version "4.21.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987" + integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw== dependencies: - caniuse-lite "^1.0.30001332" - electron-to-chromium "^1.4.118" - escalade "^3.1.1" - node-releases "^2.0.3" - picocolors "^1.0.0" + caniuse-lite "^1.0.30001400" + electron-to-chromium "^1.4.251" + node-releases "^2.0.6" + update-browserslist-db "^1.0.9" bser@2.1.1: version "2.1.1" @@ -2083,21 +2006,6 @@ bytes@1: resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" integrity sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ== -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -2106,11 +2014,6 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" -call-me-maybe@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" - integrity sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw== - callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -2143,10 +2046,10 @@ camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -caniuse-lite@^1.0.30001332, caniuse-lite@^1.0.30001335: - version "1.0.30001346" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001346.tgz#e895551b46b9cc9cc9de852facd42f04839a8fbe" - integrity sha512-q6ibZUO2t88QCIPayP/euuDREq+aMAxFE5S70PkrLh0iTDj/zEhgvJRKC2+CvXY6EWc6oQwUR48lL5vCW6jiXQ== +caniuse-lite@^1.0.30001400, caniuse-lite@^1.0.30001426: + version "1.0.30001439" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz#ab7371faeb4adff4b74dad1718a6fd122e45d9cb" + integrity sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A== capture-exit@^2.0.0: version "2.0.0" @@ -2183,11 +2086,6 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -charcodes@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/charcodes/-/charcodes-0.2.0.tgz#5208d327e6cc05f99eb80ffc814707572d1f14e4" - integrity sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ== - chart.js@3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.7.1.tgz#0516f690c6a8680c6c707e31a4c1807a6f400ada" @@ -2198,25 +2096,15 @@ chrome-trace-event@^1.0.2: resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - classnames@2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== clean-css@^5.2.2: - version "5.3.0" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.0.tgz#ad3d8238d5f3549e83d5f87205189494bc7cbb59" - integrity sha512-YYuuxv4H/iNb1Z/5IbMRoxgrzjWGhOEFfd+groZ5dMCVkpENiMZmwspdrzBo9286JjM1gZJPAyL7ZIdzuvu2AQ== + version "5.3.1" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.1.tgz#d0610b0b90d125196a2894d35366f734e5d7aa32" + integrity sha512-lCr8OHhiWCTw4v8POJovCoh4T7I9U11yVsPjMWWnnMmp9ZowCxyad1Pathle/9HjaDp+fdQKjO9fQydE6RHTZg== dependencies: source-map "~0.6.0" @@ -2234,13 +2122,13 @@ clipboard@2.0.10: select "^1.1.2" tiny-emitter "^2.0.0" -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== dependencies: string-width "^4.2.0" - strip-ansi "^6.0.0" + strip-ansi "^6.0.1" wrap-ansi "^7.0.0" clone-deep@^4.0.1: @@ -2252,30 +2140,15 @@ clone-deep@^4.0.1: kind-of "^6.0.2" shallow-clone "^3.0.0" -clone-regexp@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-2.2.0.tgz#7d65e00885cd8796405c35a737e7a86b7429e36f" - integrity sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q== - dependencies: - is-regexp "^2.0.0" - clone@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== clsx@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" - integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw== - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" + version "1.2.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" + integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== color-convert@^1.3.0, color-convert@^1.9.0: version "1.9.3" @@ -2322,41 +2195,36 @@ color@^0.11.0: color-convert "^1.3.0" color-string "^0.3.0" -colord@^2.9.2: - version "2.9.2" - resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1" - integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ== +colord@^2.9.3: + version "2.9.3" + resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" + integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== colorette@^2.0.14: - version "2.0.17" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.17.tgz#5dd4c0d15e2984b7433cb4a9f2ead45063b80c47" - integrity sha512-hJo+3Bkn0NCHybn9Tu35fIeoOKGOk5OCC32y4Hz2It+qlCO2Q3DeQ1hRn/tDDMQKRYUEzqsl7jbF6dYKjlE60g== + version "2.0.19" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" + integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== commander@^2.20.0, commander@^2.20.3: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^7.0.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - commander@^8.3.0: version "8.3.0" resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== +commander@^9.4.1: + version "9.4.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.1.tgz#d1dd8f2ce6faf93147295c0df13c7c21141cfbdd" + integrity sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw== + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== -component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - compress-commons@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.1.tgz#df2a09a7ed17447642bad10a85cc9a19e5c42a7d" @@ -2389,29 +2257,21 @@ continuable-cache@^0.3.1: integrity sha512-TF30kpKhTH8AGCG3dut0rdd/19B7Z+qCnrMoBLpyQu/2drZdNrrpcjPEoJeSVsQM+8KmWG5O56oPDjSSUsuTyA== convert-source-map@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + version "1.9.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +core-js-compat@^3.25.1: + version "3.26.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.26.1.tgz#0e710b09ebf689d719545ac36e49041850f943df" + integrity sha512-622/KzTudvXCDLRw70iHW4KKs1aGpcRcowGWyYJr2DEBfRrd6hNJybxSWJFuZYD4ma86xhrwDDHxmDaIq4EA8A== dependencies: - safe-buffer "~5.1.1" + browserslist "^4.21.4" -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== - -core-js-compat@^3.21.0, core-js-compat@^3.22.1: - version "3.22.8" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.22.8.tgz#46fa34ce1ddf742acd7f95f575f66bbb21e05d62" - integrity sha512-pQnwg4xtuvc2Bs/5zYQPaEYYSuTxsF7LBWF0SvnVhthZo/Qe+rJpcEekrdNK5DWwDJ0gv0oI9NNX5Mppdy0ctg== - dependencies: - browserslist "^4.20.3" - semver "7.0.0" - -core-js@3.22.8: - version "3.22.8" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.22.8.tgz#23f860b1fe60797cc4f704d76c93fea8a2f60631" - integrity sha512-UoGQ/cfzGYIuiq6Z7vWL1HfkE9U9IZ4Ub+0XSiJTCzvbZzgPA69oDF2f+lgJ6dFFLEdjW5O6svvoKzXX23xFkA== +core-js@3.26.1: + version "3.26.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.26.1.tgz#7a9816dabd9ee846c1c0fe0e8fcad68f3709134e" + integrity sha512-21491RRQVzUn0GGM9Z1Jrpr6PNPxPi+Za8OM9q4tksTSnlbXXGKK1nXNg/QvwFYettXvSX6zWKCtHHfjN4puyA== core-js@^2.4.0: version "2.6.12" @@ -2423,10 +2283,10 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" - integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== +cosmiconfig@^7.0.0, cosmiconfig@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" + integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== dependencies: "@types/parse-json" "^4.0.0" import-fresh "^3.2.1" @@ -2434,31 +2294,6 @@ cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: path-type "^4.0.0" yaml "^1.10.0" -cp-file@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-7.0.0.tgz#b9454cfd07fe3b974ab9ea0e5f29655791a9b8cd" - integrity sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw== - dependencies: - graceful-fs "^4.1.2" - make-dir "^3.0.0" - nested-error-stacks "^2.0.0" - p-event "^4.1.0" - -cpy@^8.1.2: - version "8.1.2" - resolved "https://registry.yarnpkg.com/cpy/-/cpy-8.1.2.tgz#e339ea54797ad23f8e3919a5cffd37bfc3f25935" - integrity sha512-dmC4mUesv0OYH2kNFEidtf/skUwv4zePmGeepjyyJ0qTo5+8KhA1o99oIAwVVLzQMAeDJml74d6wPPKb6EZUTg== - dependencies: - arrify "^2.0.1" - cp-file "^7.0.0" - globby "^9.2.0" - has-glob "^1.0.0" - junk "^3.1.0" - nested-error-stacks "^2.1.0" - p-all "^2.1.0" - p-filter "^2.1.0" - p-map "^3.0.0" - crc-32@^1.2.0: version "1.2.2" resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" @@ -2499,24 +2334,24 @@ css-color-function@~1.3.3: debug "^3.1.0" rgb "~0.1.0" -css-functions-list@^3.0.1: +css-functions-list@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.1.0.tgz#cf5b09f835ad91a00e5959bcfc627cd498e1321b" integrity sha512-/9lCvYZaUbBGvYUgYGFJ4dcYiyqdhSjG7IPVluoV8A1ILjkF7ilmhp1OGUz8n+nmBcu0RNrQAzgD8B6FJbrt2w== -css-loader@6.7.1: - version "6.7.1" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.1.tgz#e98106f154f6e1baf3fc3bc455cb9981c1d5fd2e" - integrity sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw== +css-loader@6.7.3: + version "6.7.3" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.3.tgz#1e8799f3ccc5874fdd55461af51137fcc5befbcd" + integrity sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ== dependencies: icss-utils "^5.1.0" - postcss "^8.4.7" + postcss "^8.4.19" postcss-modules-extract-imports "^3.0.0" postcss-modules-local-by-default "^4.0.0" postcss-modules-scope "^3.0.0" postcss-modules-values "^4.0.0" postcss-value-parser "^4.2.0" - semver "^7.3.5" + semver "^7.3.8" css-select@^4.1.3: version "4.3.0" @@ -2540,23 +2375,23 @@ cssesc@^3.0.0: integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== csstype@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2" - integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA== + version "3.1.1" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9" + integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== cuint@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b" integrity sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw== -debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: +debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@^3.1.0, debug@^3.1.1, debug@^3.2.7: +debug@^3.1.0, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== @@ -2571,9 +2406,9 @@ debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: ms "2.1.2" decamelize-keys@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" - integrity sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg== + version "1.1.1" + resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.1.tgz#04a2d523b2f18d80d0158a43b895d56dff8d19d8" + integrity sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg== dependencies: decamelize "^1.1.0" map-obj "^1.0.0" @@ -2583,11 +2418,6 @@ decamelize@^1.1.0, decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og== - deep-equal@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" @@ -2613,29 +2443,7 @@ define-properties@^1.1.3, define-properties@^1.1.4: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA== - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA== - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -del@^6.0.0: +del@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/del/-/del-6.1.1.tgz#3b70314f1ec0aa325c6b14eb36b95786671edb7a" integrity sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg== @@ -2664,13 +2472,6 @@ detect-node-es@^1.1.0: resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== -dir-glob@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" - integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== - dependencies: - path-type "^3.0.0" - dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -2767,10 +2568,10 @@ dot-case@^3.0.4: no-case "^3.0.4" tslib "^2.0.3" -electron-to-chromium@^1.4.118: - version "1.4.146" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.146.tgz#fd20970c3def2f9e6b32ac13a2e7a6b64e1b0c48" - integrity sha512-4eWebzDLd+hYLm4csbyMU2EbBnqhwl8Oe9eF/7CBDPWcRxFmqzx4izxvHH+lofQxzieg8UbB8ZuzNTxeukzfTg== +electron-to-chromium@^1.4.251: + version "1.4.284" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592" + integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA== element-class@0.2.2: version "0.2.2" @@ -2794,10 +2595,10 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -enhanced-resolve@^5.9.3: - version "5.9.3" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz#44a342c012cbc473254af5cc6ae20ebd0aae5d88" - integrity sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow== +enhanced-resolve@^5.10.0: + version "5.12.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz#300e1c90228f5b570c4d35babf263f6da7155634" + integrity sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -2826,33 +2627,35 @@ error@^7.0.0: dependencies: string-template "~0.2.1" -es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5: - version "1.20.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814" - integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA== +es-abstract@^1.19.0, es-abstract@^1.20.4: + version "1.20.5" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.5.tgz#e6dc99177be37cacda5988e692c3fa8b218e95d2" + integrity sha512-7h8MM2EQhsCA7pU/Nv78qOXFpD8Rhqd12gYiSJVkrH9+e8VuA8JlPJK/hQjjlLv6pJvx/z1iRFKzYb0XT/RuAQ== dependencies: call-bind "^1.0.2" es-to-primitive "^1.2.1" function-bind "^1.1.1" function.prototype.name "^1.1.5" - get-intrinsic "^1.1.1" + get-intrinsic "^1.1.3" get-symbol-description "^1.0.0" + gopd "^1.0.1" has "^1.0.3" has-property-descriptors "^1.0.0" has-symbols "^1.0.3" internal-slot "^1.0.3" - is-callable "^1.2.4" + is-callable "^1.2.7" is-negative-zero "^2.0.2" is-regex "^1.1.4" is-shared-array-buffer "^1.0.2" is-string "^1.0.7" is-weakref "^1.0.2" - object-inspect "^1.12.0" + object-inspect "^1.12.2" object-keys "^1.1.1" - object.assign "^4.1.2" + object.assign "^4.1.4" regexp.prototype.flags "^1.4.3" - string.prototype.trimend "^1.0.5" - string.prototype.trimstart "^1.0.5" + safe-regex-test "^1.0.0" + string.prototype.trimend "^1.0.6" + string.prototype.trimstart "^1.0.6" unbox-primitive "^1.0.2" es-module-lexer@^0.9.0: @@ -2912,12 +2715,11 @@ eslint-import-resolver-node@^0.3.6: resolve "^1.20.0" eslint-module-utils@^2.7.3: - version "2.7.3" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" - integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== + version "2.7.4" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974" + integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA== dependencies: debug "^3.2.7" - find-up "^2.1.0" eslint-plugin-filenames@1.3.2: version "1.3.2" @@ -2948,32 +2750,33 @@ eslint-plugin-import@2.26.0: resolve "^1.22.0" tsconfig-paths "^3.14.1" -eslint-plugin-react@7.30.0: - version "7.30.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.30.0.tgz#8e7b1b2934b8426ac067a0febade1b13bd7064e3" - integrity sha512-RgwH7hjW48BleKsYyHK5vUAvxtE9SMPDKmcPRQgtRCYaZA0XQPt5FSkrU3nhz5ifzMZcA8opwmRJ2cmOO8tr5A== +eslint-plugin-react@7.31.11: + version "7.31.11" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz#011521d2b16dcf95795df688a4770b4eaab364c8" + integrity sha512-TTvq5JsT5v56wPa9OYHzsrOlHzKZKjV+aLgS+55NJP/cuzdiQPC7PfYoUjMoxlffKtvijpk7vA/jmuqRb9nohw== dependencies: - array-includes "^3.1.5" - array.prototype.flatmap "^1.3.0" + array-includes "^3.1.6" + array.prototype.flatmap "^1.3.1" + array.prototype.tosorted "^1.1.1" doctrine "^2.1.0" estraverse "^5.3.0" jsx-ast-utils "^2.4.1 || ^3.0.0" minimatch "^3.1.2" - object.entries "^1.1.5" - object.fromentries "^2.0.5" - object.hasown "^1.1.1" - object.values "^1.1.5" + object.entries "^1.1.6" + object.fromentries "^2.0.6" + object.hasown "^1.1.2" + object.values "^1.1.6" prop-types "^15.8.1" resolve "^2.0.0-next.3" semver "^6.3.0" - string.prototype.matchall "^4.0.7" + string.prototype.matchall "^4.0.8" -eslint-plugin-simple-import-sort@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-7.0.0.tgz#a1dad262f46d2184a90095a60c66fef74727f0f8" - integrity sha512-U3vEDB5zhYPNfxT5TYR7u01dboFZp+HNpnGhkDB2g/2E4wZ/g1Q9Ton8UwCLfRV9yAKyYqDh62oHOamvkFxsvw== +eslint-plugin-simple-import-sort@8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-8.0.0.tgz#9d9a2372b0606e999ea841b10458a370a6ccc160" + integrity sha512-bXgJQ+lqhtQBCuWY/FUWdB27j4+lqcvXv5rUARkzbeWLwea+S5eBZEQrhnO+WgX3ZoJHVj0cn943iyXwByHHQw== -eslint-scope@5.1.1, eslint-scope@^5.1.1: +eslint-scope@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -3006,13 +2809,15 @@ eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@8.17.0: - version "8.17.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.17.0.tgz#1cfc4b6b6912f77d24b874ca1506b0fe09328c21" - integrity sha512-gq0m0BTJfci60Fz4nczYxNAlED+sMcihltndR8t9t1evnU/azx53x3t2UHXC/uRjcbvRw/XctpaNygSTcQD+Iw== +eslint@8.30.0: + version "8.30.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.30.0.tgz#83a506125d089eef7c5b5910eeea824273a33f50" + integrity sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ== dependencies: - "@eslint/eslintrc" "^1.3.0" - "@humanwhocodes/config-array" "^0.9.2" + "@eslint/eslintrc" "^1.4.0" + "@humanwhocodes/config-array" "^0.11.8" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -3022,18 +2827,21 @@ eslint@8.17.0: eslint-scope "^7.1.1" eslint-utils "^3.0.0" eslint-visitor-keys "^3.3.0" - espree "^9.3.2" + espree "^9.4.0" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^6.0.1" - globals "^13.15.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + grapheme-splitter "^1.0.4" ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-sdsl "^4.1.4" js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" @@ -3045,14 +2853,13 @@ eslint@8.17.0: strip-ansi "^6.0.1" strip-json-comments "^3.1.0" text-table "^0.2.0" - v8-compile-cache "^2.0.3" -espree@^9.3.2: - version "9.3.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596" - integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA== +espree@^9.4.0: + version "9.4.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd" + integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg== dependencies: - acorn "^8.7.1" + acorn "^8.8.0" acorn-jsx "^5.3.2" eslint-visitor-keys "^3.3.0" @@ -3108,11 +2915,9 @@ events@^3.2.0: integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== eventsource@^1.0.7: - version "1.1.1" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.1.tgz#4544a35a57d7120fba4fa4c86cb4023b2c09df2f" - integrity sha512-qV5ZC0h7jYIAOhArFJgSfdyz6rALJyb270714o7ZtNnw2WSJ+eexhKtE0O8LYPRsHZHf2osHKZBxGPvm3kPkCA== - dependencies: - original "^1.0.0" + version "1.1.2" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.2.tgz#bc75ae1c60209e7cb1541231980460343eaea7c2" + integrity sha512-xAH3zWhgO2/3KIniEKYPr8plNSzlGINOUqYj0m0u7AB81iRw8b/3E73W6AuU+6klLbaSFmZnaETQ2lXPfAydrA== exec-sh@^0.3.2, exec-sh@^0.3.4: version "0.3.6" @@ -3134,41 +2939,6 @@ execa@^4.0.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -execall@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/execall/-/execall-2.0.0.tgz#16a06b5fe5099df7d00be5d9c06eecded1663b45" - integrity sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow== - dependencies: - clone-regexp "^2.1.0" - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA== - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - extend-shallow@^1.1.2: version "1.1.4" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-1.1.4.tgz#19d6bf94dfc09d76ba711f39b872d21ff4dd9071" @@ -3176,35 +2946,6 @@ extend-shallow@^1.1.2: dependencies: kind-of "^1.1.0" -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug== - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - eyes@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" @@ -3225,22 +2966,10 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^2.2.6: - version "2.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" - integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== - dependencies: - "@mrmlnc/readdir-enhanced" "^2.2.1" - "@nodelib/fs.stat" "^1.1.2" - glob-parent "^3.1.0" - is-glob "^4.0.0" - merge2 "^1.2.3" - micromatch "^3.1.10" - -fast-glob@^3.2.11, fast-glob@^3.2.9: - version "3.2.11" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" - integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== +fast-glob@^3.2.11, fast-glob@^3.2.12, fast-glob@^3.2.9: + version "3.2.12" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" + integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -3258,15 +2987,15 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== -fastest-levenshtein@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2" - integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow== +fastest-levenshtein@^1.0.12, fastest-levenshtein@^1.0.16: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + version "1.14.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.14.0.tgz#107f69d7295b11e0fccc264e1fc6389f623731ce" + integrity sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg== dependencies: reusify "^1.0.4" @@ -3278,9 +3007,9 @@ faye-websocket@~0.10.0: websocket-driver ">=0.5.1" fb-watchman@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" - integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== dependencies: bser "2.1.1" @@ -3306,34 +3035,25 @@ file-loader@6.2.0: loader-utils "^2.0.0" schema-utils "^3.0.0" -filemanager-webpack-plugin@6.1.7: - version "6.1.7" - resolved "https://registry.yarnpkg.com/filemanager-webpack-plugin/-/filemanager-webpack-plugin-6.1.7.tgz#2365c4b1aaeeb7aa093f842c9e7ad951a03e0ccf" - integrity sha512-0hhPpmod5t0xy1hBSA9gXi0WlOHL3+x56IBt0b/VMhvbZ5/z6jakXvNOTuVmn4wOZwAORvAeH5qQ5Qs6NdPyiw== +filemanager-webpack-plugin@8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/filemanager-webpack-plugin/-/filemanager-webpack-plugin-8.0.0.tgz#d9a6683122504a9a47ac1fb8551f241dbb8d017d" + integrity sha512-TYwu62wgq2O2c3K80Sfj8vEys/tP5wdgYoySHgUwWoc2hPbQY3Mq3ahcAW634JvHCTcSV7IAfRxMI3wTXRt2Vw== dependencies: - "@types/archiver" "^5.1.1" - archiver "^5.3.0" - cpy "^8.1.2" - del "^6.0.0" - fs-extra "^10.0.0" - is-glob "^4.0.1" - schema-utils "^3.1.1" + "@types/archiver" "^5.3.1" + archiver "^5.3.1" + del "^6.1.1" + fast-glob "^3.2.12" + fs-extra "^10.1.0" + is-glob "^4.0.3" + normalize-path "^3.0.0" + schema-utils "^4.0.0" filesize@6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.3.0.tgz#dff53cfb3f104c9e422f346d53be8dbcc971bf11" integrity sha512-ytx0ruGpDHKWVoiui6+BY/QMNngtDQ/pJaFwfBpQif0J63+E8DLdFyqS3NkKQn7vIruUEpoGD9JUJSg7Kp+I0g== -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ== - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -3341,7 +3061,7 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -find-cache-dir@^3.3.1: +find-cache-dir@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== @@ -3350,13 +3070,6 @@ find-cache-dir@^3.3.1: make-dir "^3.0.2" pkg-dir "^4.1.0" -find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== - dependencies: - locate-path "^2.0.0" - find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" @@ -3365,6 +3078,14 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" @@ -3374,9 +3095,9 @@ flat-cache@^3.0.4: rimraf "^3.0.2" flatted@^3.1.0: - version "3.2.5" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" - integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== focus-lock@^0.8.1: version "0.8.1" @@ -3385,29 +3106,17 @@ focus-lock@^0.8.1: dependencies: tslib "^1.9.3" -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== - fraction.js@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA== - dependencies: - map-cache "^0.2.2" - fs-constants@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== -fs-extra@^10.0.0: +fs-extra@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== @@ -3436,11 +3145,6 @@ function.prototype.name@^1.1.5: es-abstract "^1.19.0" functions-have-names "^1.2.2" -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== - functions-have-names@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" @@ -3456,25 +3160,20 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" + integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== dependencies: function-bind "^1.1.1" has "^1.0.3" - has-symbols "^1.0.1" + has-symbols "^1.0.3" get-node-dimensions@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/get-node-dimensions/-/get-node-dimensions-1.2.1.tgz#fb7b4bb57060fb4247dd51c9d690dfbec56b0823" integrity sha512-2MSPMu7S1iOTL+BOa6K1S62hB2zUAYNF/lV0gSVlOaacd087lc6nR1H1r0e3B1CerTo+RceOmi1iJW+vp21xcQ== -get-stdin@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" - integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== - get-stream@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" @@ -3482,11 +3181,6 @@ get-stream@^5.0.0: dependencies: pump "^3.0.0" -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -3495,19 +3189,6 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== - -glob-parent@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA== - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -3515,18 +3196,13 @@ glob-parent@^5.1.2: dependencies: is-glob "^4.0.1" -glob-parent@^6.0.1: +glob-parent@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== dependencies: is-glob "^4.0.3" -glob-to-regexp@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" - integrity sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig== - glob-to-regexp@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" @@ -3565,10 +3241,10 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.15.0: - version "13.15.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.15.0.tgz#38113218c907d2f7e98658af246cef8b77e90bac" - integrity sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog== +globals@^13.19.0: + version "13.19.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.19.0.tgz#7a42de8e6ad4f7242fbcca27ea5b23aca367b5c8" + integrity sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ== dependencies: type-fest "^0.20.2" @@ -3584,20 +3260,6 @@ globby@^11.0.1, globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -globby@^9.2.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d" - integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg== - dependencies: - "@types/glob" "^7.1.1" - array-union "^1.0.2" - dir-glob "^2.2.2" - fast-glob "^2.2.6" - glob "^7.1.3" - ignore "^4.0.3" - pify "^4.0.1" - slash "^2.0.0" - globjoin@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" @@ -3610,11 +3272,23 @@ good-listener@^1.2.2: dependencies: delegate "^3.1.2" +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + gud@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" @@ -3647,13 +3321,6 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-glob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-glob/-/has-glob-1.0.0.tgz#9aaa9eedbffb1ba3990a7b0010fb678ee0081207" - integrity sha512-D+8A457fBShSEI3tFCj65PAbT++5sKiFtdCdOam0gnfBgw9D277OERk+HM9qYJXmdVLZ/znez10SqHN0BBQ50g== - dependencies: - is-glob "^3.0.0" - has-property-descriptors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" @@ -3661,7 +3328,7 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" -has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: +has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== @@ -3673,37 +3340,6 @@ has-tostringtag@^1.0.0: dependencies: has-symbols "^1.0.2" -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q== - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw== - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ== - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ== - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" @@ -3787,9 +3423,9 @@ htmlparser2@^6.1.0: entities "^2.0.0" http-parser-js@>=0.5.1: - version "0.5.6" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.6.tgz#2e02406ab2df8af8a7abfba62e0da01c62b95afd" - integrity sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA== + version "0.5.8" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" + integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== https-browserify@1.0.0: version "1.0.0" @@ -3801,11 +3437,6 @@ human-signals@^1.1.1: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - icss-utils@^5.0.0, icss-utils@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" @@ -3816,15 +3447,10 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^4.0.3: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== +ignore@^5.2.0, ignore@^5.2.1: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== immediate@~3.0.5: version "3.0.6" @@ -3886,18 +3512,18 @@ ini@^1.3.5: integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + version "1.0.4" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.4.tgz#8551e7baf74a7a6ba5f749cfb16aa60722f0d6f3" + integrity sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ== dependencies: - get-intrinsic "^1.1.0" + get-intrinsic "^1.1.3" has "^1.0.3" side-channel "^1.0.4" -interpret@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" - integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== +interpret@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" + integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== invariant@^2.2.4: version "2.2.4" @@ -3906,20 +3532,6 @@ invariant@^2.2.4: dependencies: loose-envify "^1.0.0" -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A== - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - is-arguments@^1.0.4: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -3948,37 +3560,18 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-callable@^1.1.4, is-callable@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" - integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== - -is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.8.1: - version "2.9.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" - integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== +is-core-module@^2.5.0, is-core-module@^2.8.1, is-core-module@^2.9.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" + integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== dependencies: has "^1.0.3" -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg== - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - is-date-object@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" @@ -3986,37 +3579,7 @@ is-date-object@^1.0.1: dependencies: has-tostringtag "^1.0.0" -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw== - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^2.1.0, is-extglob@^2.1.1: +is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== @@ -4026,13 +3589,6 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-glob@^3.0.0, is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw== - dependencies: - is-extglob "^2.1.0" - is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -4052,13 +3608,6 @@ is-number-object@^1.0.4: dependencies: has-tostringtag "^1.0.0" -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg== - dependencies: - kind-of "^3.0.2" - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -4069,7 +3618,7 @@ is-path-cwd@^2.2.0: resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== -is-path-inside@^3.0.2: +is-path-inside@^3.0.2, is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== @@ -4079,7 +3628,7 @@ is-plain-obj@^1.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== -is-plain-object@^2.0.3, is-plain-object@^2.0.4: +is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== @@ -4099,11 +3648,6 @@ is-regex@^1.0.4, is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-regexp@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-2.1.0.tgz#cd734a56864e23b956bf4e7c66c396a4c0b22c2d" - integrity sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA== - is-shared-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" @@ -4137,17 +3681,12 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== -isarray@1.0.0, isarray@~1.0.0: +isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== @@ -4157,14 +3696,7 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA== - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: +isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== @@ -4180,13 +3712,11 @@ isstream@^0.1.2: integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== jayson@^3.6.6: - version "3.6.6" - resolved "https://registry.yarnpkg.com/jayson/-/jayson-3.6.6.tgz#189984f624e398f831bd2be8e8c80eb3abf764a1" - integrity sha512-f71uvrAWTtrwoww6MKcl9phQTC+56AopLyEenWvKVAIMz+q0oVGj6tenLZ7Z6UiPBkJtKLj4kt0tACllFQruGQ== + version "3.7.0" + resolved "https://registry.yarnpkg.com/jayson/-/jayson-3.7.0.tgz#b735b12d06d348639ae8230d7a1e2916cb078f25" + integrity sha512-tfy39KJMrrXJ+mFcMpxwBvFDetS8LAID93+rycFglIQM4kl3uNR3W4lBLE/FFhsoUCEox5Dt2adVpDm/XtebbQ== dependencies: "@types/connect" "^3.4.33" - "@types/express-serve-static-core" "^4.17.9" - "@types/lodash" "^4.14.159" "@types/node" "^12.12.54" "@types/ws" "^7.4.4" JSONStream "^1.3.5" @@ -4219,6 +3749,11 @@ jquery@3.6.0: resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470" integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw== +js-sdsl@^4.1.4: + version "4.2.0" + resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.2.0.tgz#278e98b7bea589b8baaf048c20aeb19eb7ad09d0" + integrity sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -4274,9 +3809,9 @@ json5@^1.0.1: minimist "^1.2.0" json5@^2.1.2, json5@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" - integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + version "2.2.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.2.tgz#64471c5bdcc564c18f7c1d4df2e2297f2457c5ab" + integrity sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ== jsonfile@^6.0.1: version "6.1.0" @@ -4293,17 +3828,12 @@ jsonparse@^1.2.0: integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== "jsx-ast-utils@^2.4.1 || ^3.0.0": - version "3.3.0" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.0.tgz#e624f259143b9062c92b6413ff92a164c80d3ccb" - integrity sha512-XzO9luP6L0xkxwhIJMTJQpZo/eeN60K08jHdexfD569AGxeNug6UketeHXEhROoM8aR7EcUoOQmIhcJQjcuq8Q== + version "3.3.3" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea" + integrity sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw== dependencies: - array-includes "^3.1.4" - object.assign "^4.1.2" - -junk@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1" - integrity sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ== + array-includes "^3.1.5" + object.assign "^4.1.3" just-curry-it@^3.1.0: version "3.2.1" @@ -4315,26 +3845,7 @@ kind-of@^1.1.0: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44" integrity sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g== -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw== - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: +kind-of@^6.0.2, kind-of@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== @@ -4344,10 +3855,10 @@ klona@^2.0.5: resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== -known-css-properties@^0.25.0: - version "0.25.0" - resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.25.0.tgz#6ebc4d4b412f602e5cfbeb4086bd544e34c0a776" - integrity sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA== +known-css-properties@^0.26.0: + version "0.26.0" + resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.26.0.tgz#008295115abddc045a9f4ed7e2a84dc8b3a77649" + integrity sha512-5FZRzrZzNTBruuurWpvZnvP9pum+fe0HcK8z/ooo+U+Hmp4vtbyp1/QDsqmufirXy4egGzbaH/y2uCZf+6W5Kg== lazystream@^1.0.0: version "1.0.1" @@ -4392,18 +3903,18 @@ loader-runner@^4.2.0: integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== loader-utils@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" - integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A== + version "2.0.4" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" + integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== dependencies: big.js "^5.2.2" emojis-list "^3.0.0" json5 "^2.1.2" -loader-utils@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-3.2.0.tgz#bcecc51a7898bee7473d4bc6b845b23af8304d4f" - integrity sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ== +loader-utils@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-3.2.1.tgz#4fb104b599daafd82ef3e1a41fb9265f87e1f576" + integrity sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw== localforage@^1.8.1: version "1.10.0" @@ -4412,14 +3923,6 @@ localforage@^1.8.1: dependencies: lie "3.1.1" -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - locate-path@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" @@ -4427,6 +3930,13 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lodash.camelcase@4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" @@ -4518,7 +4028,7 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0, make-dir@~3.1.0: +make-dir@^3.0.2, make-dir@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== @@ -4532,11 +4042,6 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== - map-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" @@ -4547,13 +4052,6 @@ map-obj@^4.0.0: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w== - dependencies: - object-visit "^1.0.0" - mathml-tag-names@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" @@ -4582,30 +4080,11 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: +merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromatch@^3.1.10: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" @@ -4649,20 +4128,27 @@ mini-create-react-context@^0.4.0: "@babel/runtime" "^7.12.1" tiny-warning "^1.0.3" -mini-css-extract-plugin@2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.0.tgz#578aebc7fc14d32c0ad304c2c34f08af44673f5e" - integrity sha512-ndG8nxCEnAemsg4FSgS+yNyHKgkTB4nPKqCOgh65j3/30qqC5RaSQQXMm++Y6sb6E1zRSxPkztj9fqxhS1Eo6w== +mini-css-extract-plugin@2.7.2: + version "2.7.2" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz#e049d3ea7d3e4e773aad585c6cb329ce0c7b72d7" + integrity sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw== dependencies: schema-utils "^4.0.0" -minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" +minimatch@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.2.tgz#0939d7d6f0898acbd1508abe534d1929368a8fff" + integrity sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg== + dependencies: + brace-expansion "^2.0.1" + minimatch@~3.0.4: version "3.0.8" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.8.tgz#5e6a59bd11e2ab0de1cfb843eb2d82e546c321c1" @@ -4680,19 +4166,11 @@ minimist-options@4.1.0: kind-of "^6.0.3" minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" - integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + version "1.2.7" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" + integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp@^0.5.5: +mkdirp@^0.5.6: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== @@ -4734,23 +4212,6 @@ nanoid@^3.3.4: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -4761,11 +4222,6 @@ neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz#26c8a3cee6cc05fbcf1e333cd2fc3e003326c0b5" - integrity sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw== - no-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" @@ -4786,10 +4242,10 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-releases@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666" - integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q== +node-releases@^2.0.6: + version "2.0.8" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.8.tgz#0f349cdc8fcfa39a92ac0be9bc48b7706292b9ae" + integrity sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A== normalize-package-data@^2.5.0: version "2.5.0" @@ -4826,7 +4282,7 @@ normalize.css@8.0.1: resolved "https://registry.yarnpkg.com/normalize.css/-/normalize.css-8.0.1.tgz#9b98a208738b9cc2634caacbc42d131c97487bf3" integrity sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg== -npm-run-path@^4.0.0, npm-run-path@^4.0.1: +npm-run-path@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== @@ -4850,16 +4306,7 @@ object-assign@^4.1.0, object-assign@^4.1.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ== - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-inspect@^1.12.0, object-inspect@^1.9.0: +object-inspect@^1.12.2, object-inspect@^1.9.0: version "1.12.2" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== @@ -4877,64 +4324,50 @@ object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA== +object.assign@^4.1.3, object.assign@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== dependencies: - isobject "^3.0.0" - -object.assign@^4.1.0, object.assign@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" object-keys "^1.1.1" -object.entries@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" - integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== +object.entries@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.6.tgz#9737d0e5b8291edd340a3e3264bb8a3b00d5fa23" + integrity sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" + define-properties "^1.1.4" + es-abstract "^1.20.4" -object.fromentries@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" - integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== +object.fromentries@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73" + integrity sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" + define-properties "^1.1.4" + es-abstract "^1.20.4" -object.hasown@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.1.tgz#ad1eecc60d03f49460600430d97f23882cf592a3" - integrity sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A== +object.hasown@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.2.tgz#f919e21fad4eb38a57bc6345b3afd496515c3f92" + integrity sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw== dependencies: define-properties "^1.1.4" - es-abstract "^1.19.5" + es-abstract "^1.20.4" -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ== - dependencies: - isobject "^3.0.1" - -object.values@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" - integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== +object.values@^1.1.5, object.values@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" + integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" + define-properties "^1.1.4" + es-abstract "^1.20.4" once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" @@ -4943,7 +4376,7 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -onetime@^5.1.0, onetime@^5.1.2: +onetime@^5.1.0: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== @@ -4962,46 +4395,6 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" -original@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" - integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== - dependencies: - url-parse "^1.4.3" - -p-all@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-all/-/p-all-2.1.0.tgz#91419be56b7dee8fe4c5db875d55e0da084244a0" - integrity sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA== - dependencies: - p-map "^2.0.0" - -p-event@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5" - integrity sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ== - dependencies: - p-timeout "^3.1.0" - -p-filter@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-filter/-/p-filter-2.1.0.tgz#1b1472562ae7a0f742f0f3d3d3718ea66ff9c09c" - integrity sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw== - dependencies: - p-map "^2.0.0" - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -5009,12 +4402,12 @@ p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg== +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: - p-limit "^1.1.0" + yocto-queue "^0.1.0" p-locate@^4.1.0: version "4.1.0" @@ -5023,17 +4416,12 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" -p-map@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" - integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== - -p-map@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" - integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== dependencies: - aggregate-error "^3.0.0" + p-limit "^3.0.2" p-map@^4.0.0: version "4.0.0" @@ -5042,18 +4430,6 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" -p-timeout@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" - integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== - dependencies: - p-finally "^1.0.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== - p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -5097,21 +4473,6 @@ pascal-case@^3.1.2: no-case "^3.0.4" tslib "^2.0.3" -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== - -path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q== - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== - path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -5127,7 +4488,7 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.6, path-parse@^1.0.7: +path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== @@ -5139,13 +4500,6 @@ path-to-regexp@^1.7.0: dependencies: isarray "0.0.1" -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -5166,16 +4520,6 @@ picomatch@^2.0.4, picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - pkg-dir@^4.1.0, pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" @@ -5200,18 +4544,13 @@ popper.js@^1.14.4: integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== portfinder@^1.0.17: - version "1.0.28" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" - integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA== + version "1.0.32" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.32.tgz#2fe1b9e58389712429dc2bea5beb2146146c7f81" + integrity sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg== dependencies: - async "^2.6.2" - debug "^3.1.1" - mkdirp "^0.5.5" - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== + async "^2.6.4" + debug "^3.2.7" + mkdirp "^0.5.6" postcss-color-function@4.1.0: version "4.1.0" @@ -5230,14 +4569,14 @@ postcss-js@^4.0.0: dependencies: camelcase-css "^2.0.1" -postcss-loader@6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-6.2.1.tgz#0895f7346b1702103d30fdc66e4d494a93c008ef" - integrity sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q== +postcss-loader@7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-7.0.2.tgz#b53ff44a26fba3688eee92a048c7f2d4802e23bb" + integrity sha512-fUJzV/QH7NXUAqV8dWJ9Lg4aTkDCezpTS5HgJ2DvqznexTbSTxgi/dTECvTZ15BwKTtk8G/bqI/QTu2HPd3ZCg== dependencies: cosmiconfig "^7.0.0" klona "^2.0.5" - semver "^7.3.5" + semver "^7.3.8" postcss-media-query-parser@^0.2.3: version "0.2.3" @@ -5249,14 +4588,14 @@ postcss-message-helpers@^2.0.0: resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" integrity sha512-tPLZzVAiIJp46TBbpXtrUAKqedXSyW5xDEo1sikrfEfnTs+49SBZR/xDdqCiJvSSbtr615xDsaMF3RrxS2jZlA== -postcss-mixins@9.0.2: - version "9.0.2" - resolved "https://registry.yarnpkg.com/postcss-mixins/-/postcss-mixins-9.0.2.tgz#098969dafd1b9a98e2973fde024bef9d2563f604" - integrity sha512-LaFjXcR+7LRji+Sc6DRn1mUw43+Y9Lyh5JjFTQDedlIi4W6REAesRXRJLlms5424vb0zerBfCVZzS2ZHRxGZOA== +postcss-mixins@9.0.4: + version "9.0.4" + resolved "https://registry.yarnpkg.com/postcss-mixins/-/postcss-mixins-9.0.4.tgz#75cd3cdb619a7e08c4c51ebb094db5f6d65b3831" + integrity sha512-XVq5jwQJDRu5M1XGkdpgASqLk37OqkH4JCFDXl/Dn7janOJjCTEKL+36cnRVy7bMtoBzALfO7bV7nTIsFnUWLA== dependencies: fast-glob "^3.2.11" postcss-js "^4.0.0" - postcss-simple-vars "^6.0.3" + postcss-simple-vars "^7.0.0" sugarss "^4.0.1" postcss-modules-extract-imports@^3.0.0: @@ -5287,12 +4626,12 @@ postcss-modules-values@^4.0.0: dependencies: icss-utils "^5.0.0" -postcss-nested@5.0.6: - version "5.0.6" - resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-5.0.6.tgz#466343f7fc8d3d46af3e7dba3fcd47d052a945bc" - integrity sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA== +postcss-nested@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.0.0.tgz#1572f1984736578f360cffc7eb7dca69e30d1735" + integrity sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w== dependencies: - postcss-selector-parser "^6.0.6" + postcss-selector-parser "^6.0.10" postcss-resolve-nested-selector@^0.1.1: version "0.1.1" @@ -5304,18 +4643,18 @@ postcss-safe-parser@^6.0.0: resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz#bb4c29894171a94bc5c996b9a30317ef402adaa1" integrity sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ== -postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.6: - version "6.0.10" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d" - integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== +postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: + version "6.0.11" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz#2e41dc39b7ad74046e1615185185cd0b17d0c8dc" + integrity sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g== dependencies: cssesc "^3.0.0" util-deprecate "^1.0.2" -postcss-simple-vars@6.0.3, postcss-simple-vars@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/postcss-simple-vars/-/postcss-simple-vars-6.0.3.tgz#e66516c7fe980da3498f4a8ad400b9c53861806c" - integrity sha512-fkNn4Zio8vN4vIig9IFdb8lVlxWnYR769RgvxCM6YWlFKie/nQaOcaMMMFz/s4gsfHW4/5bJW+i57zD67mQU7g== +postcss-simple-vars@7.0.1, postcss-simple-vars@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-simple-vars/-/postcss-simple-vars-7.0.1.tgz#836b3097a54dcd13dbd3c36a5dbdd512fad2954c" + integrity sha512-5GLLXaS8qmzHMOjVxqkk1TZPf1jMqesiI7qLhnlyERalG0sMbHIbJqrcnrpmZdKCLglHnRHoEBB61RtGTsj++A== postcss-sorting@^7.0.1: version "7.0.1" @@ -5342,10 +4681,10 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@8.4.14, postcss@^8.3.11, postcss@^8.4.14, postcss@^8.4.7: - version "8.4.14" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf" - integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig== +postcss@8.4.20, postcss@^8.3.11, postcss@^8.4.19: + version "8.4.20" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.20.tgz#64c52f509644cecad8567e949f4081d98349dc56" + integrity sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g== dependencies: nanoid "^3.3.4" picocolors "^1.0.0" @@ -5393,9 +4732,9 @@ prop-types@15.8.1, prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.5.4, react-is "^16.13.1" psl@^1.1.33: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== pump@^3.0.0: version "3.0.0" @@ -5410,13 +4749,20 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@6.10.3, qs@^6.4.0: +qs@6.10.3: version "6.10.3" resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== dependencies: side-channel "^1.0.4" +qs@^6.4.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + querystringify@^2.1.1: version "2.2.0" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" @@ -5541,7 +4887,7 @@ react-dnd@14.0.4: react-document-title@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/react-document-title/-/react-document-title-2.0.3.tgz#bbf922a0d71412fc948245e4283b2412df70f2b9" - integrity sha1-u/kioNcUEvyUgkXkKDskEt9w8rk= + integrity sha512-T5y+quDAybtD7JhvVyc2BDW3a9xj6MoW6/VZU6OJkbASqwEMo5G4nB0RqFJCEHOqjQMcQI+wGRPDhUADnaHlQw== dependencies: prop-types "^15.5.6" react-side-effect "^1.0.2" @@ -5593,7 +4939,7 @@ react-lifecycles-compat@^3.0.4: react-measure@1.4.7: version "1.4.7" resolved "https://registry.yarnpkg.com/react-measure/-/react-measure-1.4.7.tgz#a1d2ca0dcfef04978b7ac263a765dcb6a0936fdb" - integrity sha1-odLKDc/vBJeLesJjp2XctqCTb9s= + integrity sha512-eHW1uXJOWkiXXqNPPDHlM9ZdUX5L84p0QKpxN5dEogkXvDe/UzovP4gKFLfPW6+mQlbOsmZNdFc/HTNxtZ9kHg== dependencies: get-node-dimensions "^1.2.0" prop-types "^15.5.4" @@ -5663,7 +5009,7 @@ react-side-effect@^1.0.2: react-themeable@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/react-themeable/-/react-themeable-1.1.0.tgz#7d4466dd9b2b5fa75058727825e9f152ba379a0e" - integrity sha1-fURm3ZsrX6dQWHJ4JenxUro3mg4= + integrity sha512-kl5tQ8K+r9IdQXZd8WLa+xxYN04lLnJXRVhHfdgwsUJr/SlKJxIejoc9z9obEkx1mdqbTw1ry43fxEUwyD9u7w== dependencies: object-assign "^3.0.0" @@ -5730,18 +5076,18 @@ readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: util-deprecate "^1.0.1" readdir-glob@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.1.tgz#f0e10bb7bf7bfa7e0add8baffdc54c3f7dbee6c4" - integrity sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA== + version "1.1.2" + resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.2.tgz#b185789b8e6a43491635b6953295c5c5e3fd224c" + integrity sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA== dependencies: - minimatch "^3.0.4" + minimatch "^5.1.0" -rechoir@^0.7.0: - version "0.7.1" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686" - integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg== +rechoir@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" + integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== dependencies: - resolve "^1.9.0" + resolve "^1.20.0" redent@^3.0.0: version "3.0.0" @@ -5775,7 +5121,7 @@ redux-batched-actions@0.5.0: redux-localstorage@0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/redux-localstorage/-/redux-localstorage-0.4.1.tgz#faf6d719c581397294d811473ffcedee065c933c" - integrity sha1-+vbXGcWBOXKU2BFHP/zt7gZckzw= + integrity sha512-dUha0YoH+BSZ2q15pakB+JWeqiuXUf3Ir4rObOpNrZ96HEdciGAjkL10k3KGdLI7qvQw/c096asw/SQ6TPjU/A== redux-thunk@2.3.0: version "2.3.0" @@ -5796,10 +5142,10 @@ redux@^4.0.0, redux@^4.1.1: dependencies: "@babel/runtime" "^7.9.2" -regenerate-unicode-properties@^10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz#7f442732aa7934a3740c779bb9b3340dccc1fb56" - integrity sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw== +regenerate-unicode-properties@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" + integrity sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ== dependencies: regenerate "^1.4.2" @@ -5813,27 +5159,19 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== -regenerator-runtime@^0.13.4: - version "0.13.9" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== +regenerator-runtime@^0.13.11: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== -regenerator-transform@^0.15.0: - version "0.15.0" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537" - integrity sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg== +regenerator-transform@^0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz#f6c4e99fc1b4591f780db2586328e4d9a9d8dc56" + integrity sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg== dependencies: "@babel/runtime" "^7.8.4" -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3: +regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== @@ -5847,34 +5185,34 @@ regexpp@^3.2.0: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== -regexpu-core@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.0.1.tgz#c531122a7840de743dcf9c83e923b5560323ced3" - integrity sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw== +regexpu-core@^5.2.1: + version "5.2.2" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.2.2.tgz#3e4e5d12103b64748711c3aad69934d7718e75fc" + integrity sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw== dependencies: regenerate "^1.4.2" - regenerate-unicode-properties "^10.0.1" - regjsgen "^0.6.0" - regjsparser "^0.8.2" + regenerate-unicode-properties "^10.1.0" + regjsgen "^0.7.1" + regjsparser "^0.9.1" unicode-match-property-ecmascript "^2.0.0" - unicode-match-property-value-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.1.0" -regjsgen@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.6.0.tgz#83414c5354afd7d6627b16af5f10f41c4e71808d" - integrity sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA== +regjsgen@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.7.1.tgz#ee5ef30e18d3f09b7c369b76e7c2373ed25546f6" + integrity sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA== -regjsparser@^0.8.2: - version "0.8.4" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.8.4.tgz#8a14285ffcc5de78c5b95d62bbf413b6bc132d5f" - integrity sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA== +regjsparser@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" + integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== dependencies: jsesc "~0.5.0" relateurl@^0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" - integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= + integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog== renderkid@^3.0.0: version "3.0.0" @@ -5887,20 +5225,10 @@ renderkid@^3.0.0: lodash "^4.17.21" strip-ansi "^6.0.1" -repeat-element@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" - integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== require-from-string@^2.0.2: version "2.0.2" @@ -5910,12 +5238,12 @@ require-from-string@^2.0.2: require-nocache@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/require-nocache/-/require-nocache-1.0.0.tgz#a665d0b60a07e8249875790a4d350219d3c85fa3" - integrity sha1-pmXQtgoH6CSYdXkKTTUCGdPIX6M= + integrity sha512-nemgZOwvrnGtMH6DQ7n17RQNrQ779BBUiPJTeqrdXNE4ytaoX+HTflXvNlyKooJoFbNUJEtZmm9FlbmjxUXDgA== requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== reselect@4.0.0: version "4.0.0" @@ -5949,32 +5277,23 @@ resolve-pathname@^3.0.0: resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - -resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.9.0: - version "1.22.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" - integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== +resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== dependencies: - is-core-module "^2.8.1" + is-core-module "^2.9.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" resolve@^2.0.0-next.3: - version "2.0.0-next.3" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.3.tgz#d41016293d4a8586a39ca5d9b5f15cbea1f55e46" - integrity sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q== + version "2.0.0-next.4" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" + integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" reusify@^1.0.4: version "1.0.4" @@ -5984,7 +5303,7 @@ reusify@^1.0.4: rgb@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/rgb/-/rgb-0.1.0.tgz#be27b291e8feffeac1bd99729721bfa40fc037b5" - integrity sha1-vieykej+/+rBvZlylyG/pA/AN7U= + integrity sha512-F49dXX73a92N09uQkfCp2QjwXpmJcn9/i9PvjmwsSIXUGqRLCf/yx5Q9gRxuLQTq248kakqQuc8GX/U/CxSqlA== rimraf@3.0.2, rimraf@^3.0.2: version "3.0.2" @@ -6027,14 +5346,16 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: safe-json-parse@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" - integrity sha1-PnZyPjjf3aE8mx0poeB//uSzC1c= + integrity sha512-o0JmTu17WGUaUOHa1l0FPGXKBfijbxK6qoHzlkihsDXxzBHvJcA7zgviKR92Xs841rX9pK16unfphLq0/KqX7A== -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== dependencies: - ret "~0.1.10" + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" sane@^5.0.1: version "5.0.1" @@ -6069,15 +5390,6 @@ schema-utils@>1.0.0, schema-utils@^4.0.0: ajv-formats "^2.1.1" ajv-keywords "^5.0.0" -schema-utils@^2.6.5: - version "2.7.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" - integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== - dependencies: - "@types/json-schema" "^7.0.5" - ajv "^6.12.4" - ajv-keywords "^3.5.2" - schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" @@ -6095,32 +5407,27 @@ seamless-immutable@^7.1.3: section-iterator@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/section-iterator/-/section-iterator-2.0.0.tgz#bf444d7afeeb94ad43c39ad2fb26151627ccba2a" - integrity sha1-v0RNev7rlK1Dw5rS+yYVFifMuio= + integrity sha512-xvTNwcbeDayXotnV32zLb3duQsP+4XosHpb/F+tu6VzEZFmIjzPdNk6/O+QOOx5XTh08KL2ufdXeCO33p380pQ== select@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" - integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= + integrity sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA== "semver@2 || 3 || 4 || 5": version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== - semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.4, semver@^7.3.5: - version "7.3.7" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" - integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== +semver@^7.3.4, semver@^7.3.8: + version "7.3.8" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" + integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== dependencies: lru-cache "^6.0.0" @@ -6131,16 +5438,6 @@ serialize-javascript@^6.0.0: dependencies: randombytes "^2.1.0" -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" @@ -6179,16 +5476,11 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: +signal-exit@^3.0.2, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -6203,52 +5495,11 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== -source-map-resolve@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" @@ -6257,16 +5508,6 @@ source-map-support@~0.5.20: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-url@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" - integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== - -source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -6294,29 +5535,9 @@ spdx-expression-parse@^3.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.11" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" - integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== - -specificity@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/specificity/-/specificity-0.4.1.tgz#aab5e645012db08ba182e151165738d00887b019" - integrity sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg== - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" + version "3.0.12" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz#69077835abe2710b65f03969898b6637b505a779" + integrity sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA== streamqueue@1.1.2: version "1.1.2" @@ -6329,7 +5550,7 @@ streamqueue@1.1.2: string-template@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" - integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0= + integrity sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw== string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" @@ -6340,42 +5561,42 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string.prototype.matchall@^4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d" - integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg== +string.prototype.matchall@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz#3bf85722021816dcd1bf38bb714915887ca79fd3" + integrity sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - get-intrinsic "^1.1.1" + define-properties "^1.1.4" + es-abstract "^1.20.4" + get-intrinsic "^1.1.3" has-symbols "^1.0.3" internal-slot "^1.0.3" - regexp.prototype.flags "^1.4.1" + regexp.prototype.flags "^1.4.3" side-channel "^1.0.4" -string.prototype.trimend@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0" - integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== +string.prototype.trimend@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" + integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== dependencies: call-bind "^1.0.2" define-properties "^1.1.4" - es-abstract "^1.19.5" + es-abstract "^1.20.4" -string.prototype.trimstart@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef" - integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== +string.prototype.trimstart@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" + integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== dependencies: call-bind "^1.0.2" define-properties "^1.1.4" - es-abstract "^1.19.5" + es-abstract "^1.20.4" string_decoder@0.10: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== string_decoder@^1.1.1: version "1.3.0" @@ -6394,7 +5615,7 @@ string_decoder@~1.1.1: strip-ansi@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== dependencies: ansi-regex "^2.0.0" @@ -6408,7 +5629,7 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== strip-final-newline@^2.0.0: version "2.0.0" @@ -6435,7 +5656,7 @@ style-loader@3.3.1: style-search@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" - integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI= + integrity sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg== stylelint-order@5.0.0: version "5.0.0" @@ -6445,51 +5666,49 @@ stylelint-order@5.0.0: postcss "^8.3.11" postcss-sorting "^7.0.1" -stylelint@14.8.5: - version "14.8.5" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.8.5.tgz#0fcbf5b6821283b5a249dde36d70f1158da0a2a3" - integrity sha512-e3t4H/hlWlspkcNUrkhf44RU3OpPTA7uBOoREGBzSwdEF+2g/+gbZq7WEpMP7BpopcSe/uLaTvDuL+URL7cdnQ== +stylelint@14.16.0: + version "14.16.0" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.16.0.tgz#8e1a424f4b9852e59089f95de306734d70e5048b" + integrity sha512-X6uTi9DcxjzLV8ZUAjit1vsRtSwcls0nl07c9rqOPzvpA8IvTX/xWEkBRowS0ffevRrqkHa/ThDEu86u73FQDg== dependencies: + "@csstools/selector-specificity" "^2.0.2" balanced-match "^2.0.0" - colord "^2.9.2" - cosmiconfig "^7.0.1" - css-functions-list "^3.0.1" + colord "^2.9.3" + cosmiconfig "^7.1.0" + css-functions-list "^3.1.0" debug "^4.3.4" - execall "^2.0.0" - fast-glob "^3.2.11" - fastest-levenshtein "^1.0.12" + fast-glob "^3.2.12" + fastest-levenshtein "^1.0.16" file-entry-cache "^6.0.1" - get-stdin "^8.0.0" global-modules "^2.0.0" globby "^11.1.0" globjoin "^0.1.4" html-tags "^3.2.0" - ignore "^5.2.0" + ignore "^5.2.1" import-lazy "^4.0.0" imurmurhash "^0.1.4" is-plain-object "^5.0.0" - known-css-properties "^0.25.0" + known-css-properties "^0.26.0" mathml-tag-names "^2.1.3" meow "^9.0.0" micromatch "^4.0.5" normalize-path "^3.0.0" picocolors "^1.0.0" - postcss "^8.4.14" + postcss "^8.4.19" postcss-media-query-parser "^0.2.3" postcss-resolve-nested-selector "^0.1.1" postcss-safe-parser "^6.0.0" - postcss-selector-parser "^6.0.10" + postcss-selector-parser "^6.0.11" postcss-value-parser "^4.2.0" resolve-from "^5.0.0" - specificity "^0.4.1" string-width "^4.2.3" strip-ansi "^6.0.1" style-search "^0.1.0" - supports-hyperlinks "^2.2.0" + supports-hyperlinks "^2.3.0" svg-tags "^1.0.0" - table "^6.8.0" + table "^6.8.1" v8-compile-cache "^2.3.0" - write-file-atomic "^4.0.1" + write-file-atomic "^4.0.2" sugarss@^4.0.1: version "4.0.1" @@ -6499,7 +5718,7 @@ sugarss@^4.0.1: supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== supports-color@^5.3.0, supports-color@^5.4.0: version "5.5.0" @@ -6522,10 +5741,10 @@ supports-color@^8.0.0: dependencies: has-flag "^4.0.0" -supports-hyperlinks@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" - integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== +supports-hyperlinks@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" + integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== dependencies: has-flag "^4.0.0" supports-color "^7.0.0" @@ -6538,12 +5757,12 @@ supports-preserve-symlinks-flag@^1.0.0: svg-tags@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" - integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= + integrity sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA== -table@^6.8.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca" - integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA== +table@^6.8.1: + version "6.8.1" + resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" + integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA== dependencies: ajv "^8.0.1" lodash.truncate "^4.4.2" @@ -6568,20 +5787,20 @@ tar-stream@^2.2.0: readable-stream "^3.1.1" terser-webpack-plugin@^5.1.3: - version "5.3.3" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz#8033db876dd5875487213e87c627bca323e5ed90" - integrity sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ== + version "5.3.6" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz#5590aec31aa3c6f771ce1b1acca60639eab3195c" + integrity sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ== dependencies: - "@jridgewell/trace-mapping" "^0.3.7" + "@jridgewell/trace-mapping" "^0.3.14" jest-worker "^27.4.5" schema-utils "^3.1.1" serialize-javascript "^6.0.0" - terser "^5.7.2" + terser "^5.14.1" -terser@^5.10.0, terser@^5.7.2: - version "5.14.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.0.tgz#eefeec9af5153f55798180ee2617f390bdd285e2" - integrity sha512-JC6qfIEkPBd9j1SMO3Pfn+A6w2kQV54tv+ABQLgZr7dA3k/DL/OBoYSWxzVpZev3J+bUHXfr55L8Mox7AaNo6g== +terser@^5.10.0, terser@^5.14.1: + version "5.16.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.1.tgz#5af3bc3d0f24241c7fb2024199d5c461a1075880" + integrity sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw== dependencies: "@jridgewell/source-map" "^0.3.2" acorn "^8.5.0" @@ -6591,17 +5810,17 @@ terser@^5.10.0, terser@^5.7.2: text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== "through@>=2.2.7 <3": version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== time-stamp@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" - integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= + integrity sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw== tiny-emitter@^2.0.0: version "2.1.0" @@ -6609,9 +5828,9 @@ tiny-emitter@^2.0.0: integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== tiny-invariant@^1.0.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" - integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg== + version "1.3.1" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" + integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== tiny-lr@^1.1.1: version "1.1.1" @@ -6638,34 +5857,19 @@ tmpl@1.0.5: to-camel-case@1.0.0, to-camel-case@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/to-camel-case/-/to-camel-case-1.0.0.tgz#1a56054b2f9d696298ce66a60897322b6f423e46" - integrity sha1-GlYFSy+daWKYzmamCJcyK29CPkY= + integrity sha512-nD8pQi5H34kyu1QDMFjzEIYqk0xa9Alt6ZfrdEMuHCFOfTLhDG5pgTu/aAM9Wt9lXILwlXmWP43b8sav0GNE8Q== dependencies: to-space-case "^1.0.0" to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== to-no-case@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a" - integrity sha1-xyKQcWTvaxeBMsjmmTAhLRtKoWo= - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" + integrity sha512-Z3g735FxuZY8rodxV4gH7LxClE4H0hTIyHNIHdk+vpQxjLm0cwnKXq/OFVZ76SOQmto7txVcwSCwkU5kqp+FKg== to-regex-range@^5.0.1: version "5.0.1" @@ -6674,36 +5878,27 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - to-space-case@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/to-space-case/-/to-space-case-1.0.0.tgz#b052daafb1b2b29dc770cea0163e5ec0ebc9fc17" - integrity sha1-sFLar7Gysp3HcM6gFj5ewOvJ/Bc= + integrity sha512-rLdvwXZ39VOn1IxGL3V6ZstoTbwLRckQmn/U8ZDLuWwIXNpuZDhQ3AiRUlhTbOXFVE9C+dR51wM0CBDhk31VcA== dependencies: to-no-case "^1.0.0" "tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" - integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== + version "4.1.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.2.tgz#e53e84b85f24e0b65dd526f46628db6c85f6b874" + integrity sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ== dependencies: psl "^1.1.33" punycode "^2.1.1" - universalify "^0.1.2" + universalify "^0.2.0" + url-parse "^1.5.3" tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== trim-newlines@^3.0.0: version "3.0.1" @@ -6726,9 +5921,9 @@ tslib@^1.9.3: integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tslib@^2.0.0, tslib@^2.0.3: - version "2.4.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + version "2.4.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" + integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" @@ -6785,43 +5980,33 @@ unicode-match-property-ecmascript@^2.0.0: unicode-canonical-property-names-ecmascript "^2.0.0" unicode-property-aliases-ecmascript "^2.0.0" -unicode-match-property-value-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" - integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== +unicode-match-property-value-ecmascript@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" + integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== unicode-property-aliases-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" - integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" + integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - -universalify@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== universalify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= +update-browserslist-db@^1.0.9: + version "1.0.10" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" + integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ== dependencies: - has-value "^0.3.1" - isobject "^3.0.0" + escalade "^3.1.1" + picocolors "^1.0.0" uri-js@^4.2.2: version "4.4.1" @@ -6830,11 +6015,6 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - url-loader@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-4.1.1.tgz#28505e905cae158cf07c92ca622d7f237e70a4e2" @@ -6844,7 +6024,7 @@ url-loader@4.1.1: mime-types "^2.1.27" schema-utils "^3.0.0" -url-parse@^1.4.3: +url-parse@^1.5.3: version "1.5.10" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== @@ -6867,27 +6047,22 @@ use-sidecar@^1.0.1: detect-node-es "^1.1.0" tslib "^2.0.0" -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== utila@~0.4: version "0.4.0" resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" - integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= + integrity sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA== uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -v8-compile-cache@^2.0.3, v8-compile-cache@^2.3.0: +v8-compile-cache@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== @@ -6919,7 +6094,7 @@ warning@^4.0.2, warning@^4.0.3: dependencies: loose-envify "^1.0.0" -watchpack@^2.3.1: +watchpack@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== @@ -6930,24 +6105,25 @@ watchpack@^2.3.1: webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== -webpack-cli@4.9.2: - version "4.9.2" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.2.tgz#77c1adaea020c3f9e2db8aad8ea78d235c83659d" - integrity sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ== +webpack-cli@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.0.1.tgz#95fc0495ac4065e9423a722dec9175560b6f2d9a" + integrity sha512-S3KVAyfwUqr0Mo/ur3NzIp6jnerNpo7GUO6so51mxLi1spqsA17YcMXy0WOIJtBSnj748lthxC6XLbNKh/ZC+A== dependencies: "@discoveryjs/json-ext" "^0.5.0" - "@webpack-cli/configtest" "^1.1.1" - "@webpack-cli/info" "^1.4.1" - "@webpack-cli/serve" "^1.6.1" + "@webpack-cli/configtest" "^2.0.1" + "@webpack-cli/info" "^2.0.1" + "@webpack-cli/serve" "^2.0.1" colorette "^2.0.14" - commander "^7.0.0" - execa "^5.0.0" + commander "^9.4.1" + cross-spawn "^7.0.3" + envinfo "^7.7.3" fastest-levenshtein "^1.0.12" import-local "^3.0.2" - interpret "^2.2.0" - rechoir "^0.7.0" + interpret "^3.1.1" + rechoir "^0.8.0" webpack-merge "^5.7.3" webpack-livereload-plugin@3.0.2: @@ -6973,21 +6149,21 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@5.73.0: - version "5.73.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.73.0.tgz#bbd17738f8a53ee5760ea2f59dce7f3431d35d38" - integrity sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA== +webpack@5.75.0: + version "5.75.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.75.0.tgz#1e440468647b2505860e94c9ff3e44d5b582c152" + integrity sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^0.0.51" "@webassemblyjs/ast" "1.11.1" "@webassemblyjs/wasm-edit" "1.11.1" "@webassemblyjs/wasm-parser" "1.11.1" - acorn "^8.4.1" + acorn "^8.7.1" acorn-import-assertions "^1.7.6" browserslist "^4.14.5" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.9.3" + enhanced-resolve "^5.10.0" es-module-lexer "^0.9.0" eslint-scope "5.1.1" events "^3.2.0" @@ -7000,7 +6176,7 @@ webpack@5.73.0: schema-utils "^3.1.0" tapable "^2.1.1" terser-webpack-plugin "^5.1.3" - watchpack "^2.3.1" + watchpack "^2.4.0" webpack-sources "^3.2.3" websocket-driver@>=0.5.1: @@ -7020,7 +6196,7 @@ websocket-extensions@>=0.1.1: whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== dependencies: tr46 "~0.0.3" webidl-conversions "^3.0.0" @@ -7072,20 +6248,20 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -write-file-atomic@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.1.tgz#9faa33a964c1c85ff6f849b80b42a88c2c537c8f" - integrity sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ== +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== dependencies: imurmurhash "^0.1.4" signal-exit "^3.0.7" ws@^7.4.5: - version "7.5.8" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.8.tgz#ac2729881ab9e7cbaf8787fe3469a48c5c7f636a" - integrity sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw== + version "7.5.9" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" + integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== xxhashjs@~0.2.2: version "0.2.2" @@ -7114,23 +6290,28 @@ yargs-parser@^20.2.3: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-parser@^21.0.0: - version "21.0.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35" - integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== yargs@^17.3.1: - version "17.5.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" - integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== + version "17.6.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.6.2.tgz#2e23f2944e976339a1ee00f18c77fedee8332541" + integrity sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw== dependencies: - cliui "^7.0.2" + cliui "^8.0.1" escalade "^3.1.1" get-caller-file "^2.0.5" require-directory "^2.1.1" string-width "^4.2.3" y18n "^5.0.5" - yargs-parser "^21.0.0" + yargs-parser "^21.1.1" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== zip-stream@^4.1.0: version "4.1.0" From 2a2e859420b221395e45ac8199962b808c9cdb48 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 20 Dec 2022 10:20:39 -0600 Subject: [PATCH 0694/2320] Update UI Dependencies --- frontend/src/Utilities/Number/formatBytes.js | 2 +- package.json | 42 +-- yarn.lock | 320 +++++++++---------- 3 files changed, 176 insertions(+), 188 deletions(-) diff --git a/frontend/src/Utilities/Number/formatBytes.js b/frontend/src/Utilities/Number/formatBytes.js index 1ff1b5a97..2fb3eebe6 100644 --- a/frontend/src/Utilities/Number/formatBytes.js +++ b/frontend/src/Utilities/Number/formatBytes.js @@ -1,4 +1,4 @@ -import filesize from 'filesize'; +import { filesize } from 'filesize'; function formatBytes(input) { const size = Number(input); diff --git a/package.json b/package.json index cc44605de..3ed9997aa 100644 --- a/package.json +++ b/package.json @@ -25,57 +25,57 @@ "not chrome < 60" ], "dependencies": { - "@fortawesome/fontawesome-free": "6.1.1", - "@fortawesome/fontawesome-svg-core": "6.1.1", - "@fortawesome/free-regular-svg-icons": "6.1.1", - "@fortawesome/free-solid-svg-icons": "6.1.1", - "@fortawesome/react-fontawesome": "0.1.18", + "@fortawesome/fontawesome-free": "6.2.1", + "@fortawesome/fontawesome-svg-core": "6.2.1", + "@fortawesome/free-regular-svg-icons": "6.2.1", + "@fortawesome/free-solid-svg-icons": "6.2.1", + "@fortawesome/react-fontawesome": "0.2.0", "@microsoft/signalr": "6.0.11", - "@sentry/browser": "6.19.2", - "@sentry/integrations": "6.19.2", - "chart.js": "3.7.1", - "classnames": "2.3.1", - "clipboard": "2.0.10", - "connected-react-router": "6.9.1", + "@sentry/browser": "7.28.0", + "@sentry/integrations": "7.28.0", + "chart.js": "4.1.1", + "classnames": "2.3.2", + "clipboard": "2.0.11", + "connected-react-router": "6.9.3", "element-class": "0.2.2", - "filesize": "6.3.0", + "filesize": "10.0.6", "history": "4.10.1", "https-browserify": "1.0.0", "jdu": "1.0.0", - "jquery": "3.6.0", + "jquery": "3.6.2", "lodash": "4.17.21", "mobile-detect": "1.4.5", - "moment": "2.29.2", + "moment": "2.29.4", "mousetrap": "1.6.5", "normalize.css": "8.0.1", "prop-types": "15.8.1", - "qs": "6.10.3", + "qs": "6.11.0", "react": "17.0.2", "react-addons-shallow-compare": "15.6.3", "react-async-script": "1.2.0", "react-autosuggest": "10.1.0", - "react-custom-scrollbars-2": "4.4.0", + "react-custom-scrollbars-2": "4.5.0", "react-dnd": "14.0.4", "react-dnd-html5-backend": "14.0.2", "react-dnd-multi-backend": "6.0.2", "react-dnd-touch-backend": "14.1.1", "react-document-title": "2.0.3", "react-dom": "17.0.2", - "react-focus-lock": "2.5.0", + "react-focus-lock": "2.9.2", "react-google-recaptcha": "2.1.0", "react-lazyload": "3.2.0", "react-measure": "1.4.7", "react-popper": "1.3.7", - "react-redux": "7.2.4", + "react-redux": "8.0.5", "react-router": "5.2.0", "react-router-dom": "5.2.0", "react-virtualized": "9.21.1", - "redux": "4.1.0", + "redux": "4.2.0", "redux-actions": "2.6.5", "redux-batched-actions": "0.5.0", "redux-localstorage": "0.4.1", - "redux-thunk": "2.3.0", - "reselect": "4.0.0" + "redux-thunk": "2.4.2", + "reselect": "4.1.7" }, "devDependencies": { "@babel/core": "7.20.5", diff --git a/yarn.lock b/yarn.lock index 94b36b118..5162372bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1058,41 +1058,41 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@fortawesome/fontawesome-common-types@6.1.1": - version "6.1.1" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.1.tgz#7dc996042d21fc1ae850e3173b5c67b0549f9105" - integrity sha512-wVn5WJPirFTnzN6tR95abCx+ocH+3IFLXAgyavnf9hUmN0CfWoDjPT/BAWsUVwSlYYVBeCLJxaqi7ZGe4uSjBA== +"@fortawesome/fontawesome-common-types@6.2.1": + version "6.2.1" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.1.tgz#411e02a820744d3f7e0d8d9df9d82b471beaa073" + integrity sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ== -"@fortawesome/fontawesome-free@6.1.1": - version "6.1.1" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.1.1.tgz#bf5d45611ab74890be386712a0e5d998c65ee2a1" - integrity sha512-J/3yg2AIXc9wznaVqpHVX3Wa5jwKovVF0AMYSnbmcXTiL3PpRPfF58pzWucCwEiCJBp+hCNRLWClTomD8SseKg== +"@fortawesome/fontawesome-free@6.2.1": + version "6.2.1" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.2.1.tgz#344baf6ff9eaad7a73cff067d8c56bfc11ae5304" + integrity sha512-viouXhegu/TjkvYQoiRZK3aax69dGXxgEjpvZW81wIJdxm5Fnvp3VVIP4VHKqX4SvFw6qpmkILkD4RJWAdrt7A== -"@fortawesome/fontawesome-svg-core@6.1.1": - version "6.1.1" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.1.1.tgz#3424ec6182515951816be9b11665d67efdce5b5f" - integrity sha512-NCg0w2YIp81f4V6cMGD9iomfsIj7GWrqmsa0ZsPh59G7PKiGN1KymZNxmF00ssuAlo/VZmpK6xazsGOwzKYUMg== +"@fortawesome/fontawesome-svg-core@6.2.1": + version "6.2.1" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.1.tgz#e87e905e444b5e7b715af09b64d27b53d4c8f9d9" + integrity sha512-HELwwbCz6C1XEcjzyT1Jugmz2NNklMrSPjZOWMlc+ZsHIVk+XOvOXLGGQtFBwSyqfJDNgRq4xBCwWOaZ/d9DEA== dependencies: - "@fortawesome/fontawesome-common-types" "6.1.1" + "@fortawesome/fontawesome-common-types" "6.2.1" -"@fortawesome/free-regular-svg-icons@6.1.1": - version "6.1.1" - resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.1.1.tgz#3f2f58262a839edf0643cbacee7a8a8230061c98" - integrity sha512-xXiW7hcpgwmWtndKPOzG+43fPH7ZjxOaoeyooptSztGmJxCAflHZxXNK0GcT0uEsR4jTGQAfGklDZE5NHoBhKg== +"@fortawesome/free-regular-svg-icons@6.2.1": + version "6.2.1" + resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.2.1.tgz#650e56d937755a8341f2eef258ecb6f95458820f" + integrity sha512-wiqcNDNom75x+pe88FclpKz7aOSqS2lOivZeicMV5KRwOAeypxEYWAK/0v+7r+LrEY30+qzh8r2XDaEHvoLsMA== dependencies: - "@fortawesome/fontawesome-common-types" "6.1.1" + "@fortawesome/fontawesome-common-types" "6.2.1" -"@fortawesome/free-solid-svg-icons@6.1.1": - version "6.1.1" - resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.1.1.tgz#3369e673f8fe8be2fba30b1ec274d47490a830a6" - integrity sha512-0/5exxavOhI/D4Ovm2r3vxNojGZioPwmFrKg0ZUH69Q68uFhFPs6+dhAToh6VEQBntxPRYPuT5Cg1tpNa9JUPg== +"@fortawesome/free-solid-svg-icons@6.2.1": + version "6.2.1" + resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.1.tgz#2290ea5adcf1537cbd0c43de6feb38af02141d27" + integrity sha512-oKuqrP5jbfEPJWTij4sM+/RvgX+RMFwx3QZCZcK9PrBDgxC35zuc7AOFsyMjMd/PIFPeB2JxyqDr5zs/DZFPPw== dependencies: - "@fortawesome/fontawesome-common-types" "6.1.1" + "@fortawesome/fontawesome-common-types" "6.2.1" -"@fortawesome/react-fontawesome@0.1.18": - version "0.1.18" - resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.18.tgz#dae37f718a24e14d7a99a5496c873d69af3fbd73" - integrity sha512-RwLIB4TZw0M9gvy5u+TusAA0afbwM4JQIimNH/j3ygd6aIvYPQLqXMhC9ErY26J23rDPyDZldIfPq/HpTTJ/tQ== +"@fortawesome/react-fontawesome@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz#d90dd8a9211830b4e3c08e94b63a0ba7291ddcf4" + integrity sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw== dependencies: prop-types "^15.8.1" @@ -1163,6 +1163,11 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@kurkle/color@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@kurkle/color/-/color-0.3.1.tgz#ef72bc8022ccf77cdd2715097f062ee591ec145c" + integrity sha512-hW0GwZj06z/ZFUW2Espl7toVDjghJN+EKqyXzPSV8NV89d5BYp5rRMBJoc+aUN0x5OXDMeRQHazejr2Xmqj2tw== + "@microsoft/signalr@6.0.11": version "6.0.11" resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-6.0.11.tgz#f8e762e4516a27850836251a15528041b3c877f9" @@ -1217,66 +1222,56 @@ resolved "https://registry.yarnpkg.com/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz#a3031eb54129f2c66b2753f8404266ec7bf67f0a" integrity sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg== -"@sentry/browser@6.19.2": - version "6.19.2" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.19.2.tgz#c0f6df07584f3b36fa037067aea20b2c8c2095a3" - integrity sha512-5VC44p5Vu2eJhVT39nLAJFgha5MjHDYCyZRR1ieeZt3a++otojPGBBAKNAtrEMGV+A2Z9AoneD6ZnDVlyb3GKg== +"@sentry/browser@7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.28.0.tgz#652971bc33e609426fd5690a7e68314287e85403" + integrity sha512-UMsFwNOEpdX3pHdpJ9klSK2FbwG0n9FlrPSb2KMuuW/OA62Yq2YStShoyJ35ix3cwHnhF6/F+lXxJ/WfMvX6DQ== dependencies: - "@sentry/core" "6.19.2" - "@sentry/types" "6.19.2" - "@sentry/utils" "6.19.2" + "@sentry/core" "7.28.0" + "@sentry/replay" "7.28.0" + "@sentry/types" "7.28.0" + "@sentry/utils" "7.28.0" tslib "^1.9.3" -"@sentry/core@6.19.2": - version "6.19.2" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.19.2.tgz#dd35ba6ca41a2dd011c43f732bcdadbb52c06376" - integrity sha512-yu1R3ewBT4udmB4v7sc4biQZ0Z0rfB9+TzB5ZKoCftbe6kqXjFMMaFRYNUF9HicVldKAsBktgkWw3+yfqGkw/A== +"@sentry/core@7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.28.0.tgz#4e2bda6febecf9ac2109e569c2ef8be7e983469a" + integrity sha512-9wY6mRzoyZ8TEW7X1jpciD0DSqqYPaggiJyykxaVbjwmJc7GjJpY94XHmSeKNUV4w7ddMhdsznhBmGNN6CFMfQ== dependencies: - "@sentry/hub" "6.19.2" - "@sentry/minimal" "6.19.2" - "@sentry/types" "6.19.2" - "@sentry/utils" "6.19.2" + "@sentry/types" "7.28.0" + "@sentry/utils" "7.28.0" tslib "^1.9.3" -"@sentry/hub@6.19.2": - version "6.19.2" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.19.2.tgz#0e9f9c507e55d8396002f644b43ef27cc9ff1289" - integrity sha512-W7KCgNBgdBIMagOxy5J5KQPe+maYxSqfE8a5ncQ3R8BcZDQEKnkW/1FplNbfRLZqA/tL/ndKb7pTPqVtzsbARw== +"@sentry/integrations@7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.28.0.tgz#3a985f1a690a3e29561ed2ec5d323561f8f5d7dd" + integrity sha512-OS51DRs1lvI/pQaxcpsxOxhbDKB3ZxTZglVjoCr7pZQm7pb6gzQF2oaYT+W1hMgK0h/mEgyR9XWDOAZCa2aMBg== dependencies: - "@sentry/types" "6.19.2" - "@sentry/utils" "6.19.2" - tslib "^1.9.3" - -"@sentry/integrations@6.19.2": - version "6.19.2" - resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-6.19.2.tgz#d5abcab94ae23ada097eb454c269e9ab573e14bb" - integrity sha512-RjkZXPrtrM+lJVEa4OpZ9CYjJdkpPoWslEQzLMvbaRpURpHFqmABGtXRAnJRYKmy6h7/9q9sABcDgCD4OZw11g== - dependencies: - "@sentry/types" "6.19.2" - "@sentry/utils" "6.19.2" + "@sentry/types" "7.28.0" + "@sentry/utils" "7.28.0" localforage "^1.8.1" tslib "^1.9.3" -"@sentry/minimal@6.19.2": - version "6.19.2" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.19.2.tgz#e748541e4adbc7e80a3b6ccaf01b631c17fc44b4" - integrity sha512-ClwxKm77iDHET7kpzv1JvzDx1er5DoNu+EUjst0kQzARIrXvu9xuZuE2/CnBWycQWqw8o3HoGoKz65uIhsUCzQ== +"@sentry/replay@7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.28.0.tgz#b82a60bc96a0db80fd7f95275180b3aaae64a885" + integrity sha512-AuAREwMqZQhrGTxd69zY3uRPnfcrIRxL4wMefopzkjPx9Zboxkp2rsUJlrC0JLmReNML0ec7ZybZx94LunbE7Q== dependencies: - "@sentry/hub" "6.19.2" - "@sentry/types" "6.19.2" - tslib "^1.9.3" + "@sentry/core" "7.28.0" + "@sentry/types" "7.28.0" + "@sentry/utils" "7.28.0" -"@sentry/types@6.19.2": - version "6.19.2" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.19.2.tgz#0219c9da21ed975951108b8541913b1966464435" - integrity sha512-XO5qmVBdTs+7PdCz7fAwn1afWxSnRE2KLBFg5/vOdKosPSSHsSHUURSkxiEZc2QsR+JpRB4AeQ26AkIRX38qTg== +"@sentry/types@7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.28.0.tgz#26318a71b4e121e7df7b54c48ddba6c7cfcfa70b" + integrity sha512-F6tZldpvC3Lt8FPgJ6wRTcE7P9txIpHSBjyYz9wqFlVJx4IhBmrn6vZU1LvANUaK1jZZF2PW5tFRrVEnydfpqg== -"@sentry/utils@6.19.2": - version "6.19.2" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.19.2.tgz#995efb896c5159369509f4896c27a2d2ea9191f2" - integrity sha512-2DQQ2OJaxjtyxGq5FmMlqb6hptsqMs2xoBiVRMkTS/rvyTrk1oQdKZ8ePwjtgX3nJ728ni3IXIyXV+vfGp4EBw== +"@sentry/utils@7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.28.0.tgz#6860e7c5689819568295f725117a54e06bb2214a" + integrity sha512-ag1RotlFSJnwUi/MYWY5iQ8aLcwrCBlD/qlGB43PvB3XGDl3e7E/pUy2bdblP7Q2uCKLVUBcudyaSgtvNqu9wA== dependencies: - "@sentry/types" "6.19.2" + "@sentry/types" "7.28.0" tslib "^1.9.3" "@types/archiver@^5.3.1": @@ -1327,7 +1322,7 @@ "@types/minimatch" "*" "@types/node" "*" -"@types/hoist-non-react-statics@^3.3.0": +"@types/hoist-non-react-statics@^3.3.1": version "3.3.1" resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== @@ -1385,16 +1380,6 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== -"@types/react-redux@^7.1.16": - version "7.1.24" - resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.24.tgz#6caaff1603aba17b27d20f8ad073e4c077e975c0" - integrity sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ== - dependencies: - "@types/hoist-non-react-statics" "^3.3.0" - "@types/react" "*" - hoist-non-react-statics "^3.3.0" - redux "^4.0.0" - "@types/react@*": version "18.0.26" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.26.tgz#8ad59fc01fef8eaf5c74f4ea392621749f0b7917" @@ -1409,6 +1394,11 @@ resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== +"@types/use-sync-external-store@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43" + integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA== + "@types/ws@^7.4.4": version "7.4.7" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" @@ -2086,20 +2076,22 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chart.js@3.7.1: - version "3.7.1" - resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.7.1.tgz#0516f690c6a8680c6c707e31a4c1807a6f400ada" - integrity sha512-8knRegQLFnPQAheZV8MjxIXc5gQEfDFD897BJgv/klO/vtIyFFmgMXrNfgrXpbTr/XbTturxRgxIXx/Y+ASJBA== +chart.js@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-4.1.1.tgz#9bd96ddaa444205ec55dd103f713f65530e9a2df" + integrity sha512-P0pCosNXp+LR8zO/QTkZKT6Hb7p0DPFtypEeVOf+6x06hX13NIb75R0DXUA4Ksx/+48chDQKtCCmRCviQRTqsA== + dependencies: + "@kurkle/color" "^0.3.0" chrome-trace-event@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== -classnames@2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" - integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== +classnames@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" + integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw== clean-css@^5.2.2: version "5.3.1" @@ -2113,10 +2105,10 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -clipboard@2.0.10: - version "2.0.10" - resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.10.tgz#e61f6f7139ac5044c58c0484dcac9fb2a918bfd6" - integrity sha512-cz3m2YVwFz95qSEbCDi2fzLN/epEN9zXBvfgAoGkvGOJZATMl9gtTDVOtBYkx2ODUJl2kvmud7n32sV2BpYR4g== +clipboard@2.0.11: + version "2.0.11" + resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.11.tgz#62180360b97dd668b6b3a84ec226975762a70be5" + integrity sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw== dependencies: good-listener "^1.2.2" select "^1.1.2" @@ -2240,15 +2232,15 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -connected-react-router@6.9.1: - version "6.9.1" - resolved "https://registry.yarnpkg.com/connected-react-router/-/connected-react-router-6.9.1.tgz#d842eebaa15b9920e2e45fc03d74e41110e94e4c" - integrity sha512-BbtB6t0iqAwGwygDenJl9zmlk7vpKWIRSycULmkAOn2RUaF6+bqETprl0qcIqQmY5CTqSwKanaxkLXYWiffAfQ== +connected-react-router@6.9.3: + version "6.9.3" + resolved "https://registry.yarnpkg.com/connected-react-router/-/connected-react-router-6.9.3.tgz#72300aca9f9d6f38e1f4a2901572faa02adec972" + integrity sha512-4ThxysOiv/R2Dc4Cke1eJwjKwH1Y51VDwlOrOfs1LjpdYOVvCNjNkZDayo7+sx42EeGJPQUNchWkjAIJdXGIOQ== dependencies: lodash.isequalwith "^4.4.0" prop-types "^15.7.2" optionalDependencies: - immutable "^3.8.1 || ^4.0.0-rc.1" + immutable "^3.8.1 || ^4.0.0" seamless-immutable "^7.1.3" continuable-cache@^0.3.1: @@ -3049,10 +3041,10 @@ filemanager-webpack-plugin@8.0.0: normalize-path "^3.0.0" schema-utils "^4.0.0" -filesize@6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.3.0.tgz#dff53cfb3f104c9e422f346d53be8dbcc971bf11" - integrity sha512-ytx0ruGpDHKWVoiui6+BY/QMNngtDQ/pJaFwfBpQif0J63+E8DLdFyqS3NkKQn7vIruUEpoGD9JUJSg7Kp+I0g== +filesize@10.0.6: + version "10.0.6" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-10.0.6.tgz#5f4cd2721664cd925db3a7a5a87bbfd6ab5ebb1a" + integrity sha512-rzpOZ4C9vMFDqOa6dNpog92CoLYjD79dnjLk2TYDDtImRIyLTOzqojCb05Opd1WuiWjs+fshhCgTd8cl7y5t+g== fill-range@^7.0.1: version "7.0.1" @@ -3099,12 +3091,12 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== -focus-lock@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.8.1.tgz#bb36968abf77a2063fa173cb6c47b12ac8599d33" - integrity sha512-/LFZOIo82WDsyyv7h7oc0MJF9ACOvDRdx9rWPZ2pgMfNWu/z8hQDBtOchuB/0BVLmuFOZjV02YwUVzNsWx/EzA== +focus-lock@^0.11.2: + version "0.11.4" + resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.11.4.tgz#fbf84894d7c384f25a2c7cf5d97c848131d97f6f" + integrity sha512-LzZWJcOBIcHslQ46N3SUu/760iLPSrUtp8omM4gh9du438V2CQdks8TcOu1yvmu2C68nVOBnl1WFiKGPbQ8L6g== dependencies: - tslib "^1.9.3" + tslib "^2.0.3" fraction.js@^4.2.0: version "4.2.0" @@ -3457,7 +3449,7 @@ immediate@~3.0.5: resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== -"immutable@^3.8.1 || ^4.0.0-rc.1": +"immutable@^3.8.1 || ^4.0.0": version "4.1.0" resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.1.0.tgz#f795787f0db780183307b9eb2091fcac1f6fafef" integrity sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ== @@ -3744,10 +3736,10 @@ jest-worker@^27.4.5, jest-worker@^27.4.6: merge-stream "^2.0.0" supports-color "^8.0.0" -jquery@3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470" - integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw== +jquery@3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.2.tgz#8302bbc9160646f507bdf59d136a478b312783c4" + integrity sha512-/e7ulNIEEYk1Z/l4X0vpxGt+B/dNsV8ghOPAWZaJs8pkGvsSC0tm33aMGylXcj/U7y4IcvwtMXPMyBFZn/gK9A== js-sdsl@^4.1.4: version "4.2.0" @@ -4182,10 +4174,10 @@ mobile-detect@1.4.5: resolved "https://registry.yarnpkg.com/mobile-detect/-/mobile-detect-1.4.5.tgz#da393c3c413ca1a9bcdd9ced653c38281c0fb6ad" integrity sha512-yc0LhH6tItlvfLBugVUEtgawwFU2sIe+cSdmRJJCTMZ5GEJyLxNyC/NIOAOGk67Fa8GNpOttO3Xz/1bHpXFD/g== -moment@2.29.2: - version "2.29.2" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.2.tgz#00910c60b20843bcba52d37d58c628b47b1f20e4" - integrity sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg== +moment@2.29.4: + version "2.29.4" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" + integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== mousetrap@1.6.5: version "1.6.5" @@ -4749,14 +4741,7 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@6.10.3: - version "6.10.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" - integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== - dependencies: - side-channel "^1.0.4" - -qs@^6.4.0: +qs@6.11.0, qs@^6.4.0: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== @@ -4826,17 +4811,17 @@ react-autosuggest@10.1.0: section-iterator "^2.0.0" shallow-equal "^1.2.1" -react-clientside-effect@^1.2.2: +react-clientside-effect@^1.2.6: version "1.2.6" resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz#29f9b14e944a376b03fb650eed2a754dd128ea3a" integrity sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg== dependencies: "@babel/runtime" "^7.12.13" -react-custom-scrollbars-2@4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/react-custom-scrollbars-2/-/react-custom-scrollbars-2-4.4.0.tgz#6cc237abc18f5ab32b5392b336e6f072c2b4cfc1" - integrity sha512-I+oxZ9rfHfvYm85jdH2lQqpzwNr/ZAdYB8htm6R/hwRGoIEK31jq+YE6MmFwBzuO7C5zcAtH5HN9vwZxnW61NQ== +react-custom-scrollbars-2@4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/react-custom-scrollbars-2/-/react-custom-scrollbars-2-4.5.0.tgz#cff18e7368bce9d570aea0be780045eda392c745" + integrity sha512-/z0nWAeXfMDr4+OXReTpYd1Atq9kkn4oI3qxq3iMXGQx1EEfwETSqB8HTAvg1X7dEqcCachbny1DRNGlqX5bDQ== dependencies: dom-css "^2.0.0" prop-types "^15.5.10" @@ -4901,17 +4886,17 @@ react-dom@17.0.2: object-assign "^4.1.1" scheduler "^0.20.2" -react-focus-lock@2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.5.0.tgz#12e3a3940e897c26e2c2a0408cd25ea3c99b3709" - integrity sha512-XLxj6uTXgz0US8TmqNU2jMfnXwZG0mH2r/afQqvPEaX6nyEll5LHVcEXk2XDUQ34RVeLPkO/xK5x6c/qiuSq/A== +react-focus-lock@2.9.2: + version "2.9.2" + resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.9.2.tgz#a57dfd7c493e5a030d87f161c96ffd082bd920f2" + integrity sha512-5JfrsOKyA5Zn3h958mk7bAcfphr24jPoMoznJ8vaJF6fUrPQ8zrtEd3ILLOK8P5jvGxdMd96OxWNjDzATfR2qw== dependencies: "@babel/runtime" "^7.0.0" - focus-lock "^0.8.1" + focus-lock "^0.11.2" prop-types "^15.6.2" - react-clientside-effect "^1.2.2" - use-callback-ref "^1.2.1" - use-sidecar "^1.0.1" + react-clientside-effect "^1.2.6" + use-callback-ref "^1.3.0" + use-sidecar "^1.1.2" react-google-recaptcha@2.1.0: version "2.1.0" @@ -4926,6 +4911,11 @@ react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + react-lazyload@3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/react-lazyload/-/react-lazyload-3.2.0.tgz#497bd06a6dbd7015e3376e1137a67dc47d2dd021" @@ -4958,17 +4948,17 @@ react-popper@1.3.7: typed-styles "^0.0.7" warning "^4.0.2" -react-redux@7.2.4: - version "7.2.4" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.4.tgz#1ebb474032b72d806de2e0519cd07761e222e225" - integrity sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA== +react-redux@8.0.5: + version "8.0.5" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.5.tgz#e5fb8331993a019b8aaf2e167a93d10af469c7bd" + integrity sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw== dependencies: "@babel/runtime" "^7.12.1" - "@types/react-redux" "^7.1.16" + "@types/hoist-non-react-statics" "^3.3.1" + "@types/use-sync-external-store" "^0.0.3" hoist-non-react-statics "^3.3.2" - loose-envify "^1.4.0" - prop-types "^15.7.2" - react-is "^16.13.1" + react-is "^18.0.0" + use-sync-external-store "^1.0.0" react-router-dom@5.2.0: version "5.2.0" @@ -5123,19 +5113,12 @@ redux-localstorage@0.4.1: resolved "https://registry.yarnpkg.com/redux-localstorage/-/redux-localstorage-0.4.1.tgz#faf6d719c581397294d811473ffcedee065c933c" integrity sha512-dUha0YoH+BSZ2q15pakB+JWeqiuXUf3Ir4rObOpNrZ96HEdciGAjkL10k3KGdLI7qvQw/c096asw/SQ6TPjU/A== -redux-thunk@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622" - integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw== +redux-thunk@2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.2.tgz#b9d05d11994b99f7a91ea223e8b04cf0afa5ef3b" + integrity sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q== -redux@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.0.tgz#eb049679f2f523c379f1aff345c8612f294c88d4" - integrity sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g== - dependencies: - "@babel/runtime" "^7.9.2" - -redux@^4.0.0, redux@^4.1.1: +redux@4.2.0, redux@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.0.tgz#46f10d6e29b6666df758780437651eeb2b969f13" integrity sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA== @@ -5245,10 +5228,10 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== -reselect@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7" - integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA== +reselect@4.1.7: + version "4.1.7" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.7.tgz#56480d9ff3d3188970ee2b76527bd94a95567a42" + integrity sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A== resize-observer-polyfill@^1.4.1: version "1.5.1" @@ -6032,14 +6015,14 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" -use-callback-ref@^1.2.1: +use-callback-ref@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.0.tgz#772199899b9c9a50526fedc4993fc7fa1f7e32d5" integrity sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w== dependencies: tslib "^2.0.0" -use-sidecar@^1.0.1: +use-sidecar@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2" integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw== @@ -6047,6 +6030,11 @@ use-sidecar@^1.0.1: detect-node-es "^1.1.0" tslib "^2.0.0" +use-sync-external-store@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" + integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== + util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" From c7eb08a0f024cbed8531d46eaf1029b267d52837 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 20 Dec 2022 12:00:24 -0600 Subject: [PATCH 0695/2320] New: Auth Required Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com> --- frontend/src/Components/Page/Page.js | 7 + frontend/src/Components/Page/PageConnector.js | 6 +- .../FirstRun/AuthenticationRequiredModal.js | 34 ++++ .../AuthenticationRequiredModalContent.css | 5 + .../AuthenticationRequiredModalContent.js | 164 ++++++++++++++++++ ...enticationRequiredModalContentConnector.js | 86 +++++++++ .../src/Settings/General/SecuritySettings.js | 41 ++++- .../AutomationTest.cs | 2 +- .../Instrumentation/Sentry/SentryCleanser.cs | 31 +++- .../Instrumentation/Sentry/SentryTarget.cs | 14 +- src/NzbDrone.Common/Prowlarr.Common.csproj | 10 +- .../Prowlarr.Core.Test.csproj | 2 +- .../AuthenticationRequiredType.cs | 8 + .../Authentication/AuthenticationType.cs | 5 +- src/NzbDrone.Core/Authentication/User.cs | 4 +- .../Authentication/UserService.cs | 71 +++++++- .../Configuration/ConfigFileProvider.cs | 3 + .../Migration/024_add_salt_to_users.cs | 16 ++ src/NzbDrone.Core/Prowlarr.Core.csproj | 9 +- src/NzbDrone.Host/Prowlarr.Host.csproj | 4 +- src/NzbDrone.Host/Startup.cs | 3 +- src/NzbDrone.Test.Common/NzbDroneRunner.cs | 8 +- .../Prowlarr.Test.Common.csproj | 2 +- src/NzbDrone.Update/Prowlarr.Update.csproj | 4 +- src/NzbDrone.Windows/Prowlarr.Windows.csproj | 2 +- .../Config/HostConfigResource.cs | 2 + src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj | 2 +- .../ApiKeyAuthenticationHandler.cs | 1 + .../AuthenticationBuilderExtensions.cs | 6 + ...leDenyAnonymousAuthorizationRequirement.cs | 8 + .../Authentication/UiAuthorizationHandler.cs | 45 +++++ .../UiAuthorizationPolicyProvider.cs | 5 +- src/Prowlarr.Http/Prowlarr.Http.csproj | 2 +- 33 files changed, 555 insertions(+), 57 deletions(-) create mode 100644 frontend/src/FirstRun/AuthenticationRequiredModal.js create mode 100644 frontend/src/FirstRun/AuthenticationRequiredModalContent.css create mode 100644 frontend/src/FirstRun/AuthenticationRequiredModalContent.js create mode 100644 frontend/src/FirstRun/AuthenticationRequiredModalContentConnector.js create mode 100644 src/NzbDrone.Core/Authentication/AuthenticationRequiredType.cs create mode 100644 src/NzbDrone.Core/Datastore/Migration/024_add_salt_to_users.cs create mode 100644 src/Prowlarr.Http/Authentication/BypassableDenyAnonymousAuthorizationRequirement.cs create mode 100644 src/Prowlarr.Http/Authentication/UiAuthorizationHandler.cs diff --git a/frontend/src/Components/Page/Page.js b/frontend/src/Components/Page/Page.js index dce638e4a..aa23f4d88 100644 --- a/frontend/src/Components/Page/Page.js +++ b/frontend/src/Components/Page/Page.js @@ -4,6 +4,7 @@ import AppUpdatedModalConnector from 'App/AppUpdatedModalConnector'; import ColorImpairedContext from 'App/ColorImpairedContext'; import ConnectionLostModalConnector from 'App/ConnectionLostModalConnector'; import SignalRConnector from 'Components/SignalRConnector'; +import AuthenticationRequiredModal from 'FirstRun/AuthenticationRequiredModal'; import locationShape from 'Helpers/Props/Shapes/locationShape'; import PageHeader from './Header/PageHeader'; import PageSidebar from './Sidebar/PageSidebar'; @@ -75,6 +76,7 @@ class Page extends Component { isSmallScreen, isSidebarVisible, enableColorImpairedMode, + authenticationEnabled, onSidebarToggle, onSidebarVisibleChange } = this.props; @@ -109,6 +111,10 @@ class Page extends Component { isOpen={this.state.isConnectionLostModalOpen} onModalClose={this.onConnectionLostModalClose} /> + + <AuthenticationRequiredModal + isOpen={!authenticationEnabled} + /> </div> </ColorImpairedContext.Provider> ); @@ -124,6 +130,7 @@ Page.propTypes = { isUpdated: PropTypes.bool.isRequired, isDisconnected: PropTypes.bool.isRequired, enableColorImpairedMode: PropTypes.bool.isRequired, + authenticationEnabled: PropTypes.bool.isRequired, onResize: PropTypes.func.isRequired, onSidebarToggle: PropTypes.func.isRequired, onSidebarVisibleChange: PropTypes.func.isRequired diff --git a/frontend/src/Components/Page/PageConnector.js b/frontend/src/Components/Page/PageConnector.js index 647fdcf7b..5ac032c0f 100644 --- a/frontend/src/Components/Page/PageConnector.js +++ b/frontend/src/Components/Page/PageConnector.js @@ -11,6 +11,7 @@ import { fetchAppProfiles, fetchGeneralSettings, fetchIndexerCategories, fetchUI import { fetchStatus } from 'Store/Actions/systemActions'; import { fetchTags } from 'Store/Actions/tagActions'; import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector'; +import createSystemStatusSelector from 'Store/Selectors/createSystemStatusSelector'; import ErrorPage from './ErrorPage'; import LoadingPage from './LoadingPage'; import Page from './Page'; @@ -133,18 +134,21 @@ function createMapStateToProps() { selectErrors, selectAppProps, createDimensionsSelector(), + createSystemStatusSelector(), ( enableColorImpairedMode, isPopulated, errors, app, - dimensions + dimensions, + systemStatus ) => { return { ...app, ...errors, isPopulated, isSmallScreen: dimensions.isSmallScreen, + authenticationEnabled: systemStatus.authentication !== 'none', enableColorImpairedMode }; } diff --git a/frontend/src/FirstRun/AuthenticationRequiredModal.js b/frontend/src/FirstRun/AuthenticationRequiredModal.js new file mode 100644 index 000000000..caa855cb7 --- /dev/null +++ b/frontend/src/FirstRun/AuthenticationRequiredModal.js @@ -0,0 +1,34 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import Modal from 'Components/Modal/Modal'; +import { sizes } from 'Helpers/Props'; +import AuthenticationRequiredModalContentConnector from './AuthenticationRequiredModalContentConnector'; + +function onModalClose() { + // No-op +} + +function AuthenticationRequiredModal(props) { + const { + isOpen + } = props; + + return ( + <Modal + size={sizes.MEDIUM} + isOpen={isOpen} + closeOnBackgroundClick={false} + onModalClose={onModalClose} + > + <AuthenticationRequiredModalContentConnector + onModalClose={onModalClose} + /> + </Modal> + ); +} + +AuthenticationRequiredModal.propTypes = { + isOpen: PropTypes.bool.isRequired +}; + +export default AuthenticationRequiredModal; diff --git a/frontend/src/FirstRun/AuthenticationRequiredModalContent.css b/frontend/src/FirstRun/AuthenticationRequiredModalContent.css new file mode 100644 index 000000000..bbc6704e6 --- /dev/null +++ b/frontend/src/FirstRun/AuthenticationRequiredModalContent.css @@ -0,0 +1,5 @@ +.authRequiredAlert { + composes: alert from '~Components/Alert.css'; + + margin-bottom: 20px; +} diff --git a/frontend/src/FirstRun/AuthenticationRequiredModalContent.js b/frontend/src/FirstRun/AuthenticationRequiredModalContent.js new file mode 100644 index 000000000..193bdf950 --- /dev/null +++ b/frontend/src/FirstRun/AuthenticationRequiredModalContent.js @@ -0,0 +1,164 @@ +import PropTypes from 'prop-types'; +import React, { useEffect, useRef } from 'react'; +import Alert from 'Components/Alert'; +import FormGroup from 'Components/Form/FormGroup'; +import FormInputGroup from 'Components/Form/FormInputGroup'; +import FormLabel from 'Components/Form/FormLabel'; +import SpinnerButton from 'Components/Link/SpinnerButton'; +import LoadingIndicator from 'Components/Loading/LoadingIndicator'; +import ModalBody from 'Components/Modal/ModalBody'; +import ModalContent from 'Components/Modal/ModalContent'; +import ModalFooter from 'Components/Modal/ModalFooter'; +import ModalHeader from 'Components/Modal/ModalHeader'; +import { inputTypes, kinds } from 'Helpers/Props'; +import { authenticationMethodOptions, authenticationRequiredOptions, authenticationRequiredWarning } from 'Settings/General/SecuritySettings'; +import styles from './AuthenticationRequiredModalContent.css'; + +function onModalClose() { + // No-op +} + +function AuthenticationRequiredModalContent(props) { + const { + isPopulated, + error, + isSaving, + settings, + onInputChange, + onSavePress, + dispatchFetchStatus + } = props; + + const { + authenticationMethod, + authenticationRequired, + username, + password + } = settings; + + const authenticationEnabled = authenticationMethod && authenticationMethod.value !== 'none'; + + const didMount = useRef(false); + + useEffect(() => { + if (!isSaving && didMount.current) { + dispatchFetchStatus(); + } + + didMount.current = true; + }, [isSaving, dispatchFetchStatus]); + + return ( + <ModalContent + showCloseButton={false} + onModalClose={onModalClose} + > + <ModalHeader> + Authentication Required + </ModalHeader> + + <ModalBody> + <Alert + className={styles.authRequiredAlert} + kind={kinds.WARNING} + > + {authenticationRequiredWarning} + </Alert> + + { + isPopulated && !error ? + <div> + <FormGroup> + <FormLabel>Authentication</FormLabel> + + <FormInputGroup + type={inputTypes.SELECT} + name="authenticationMethod" + values={authenticationMethodOptions} + helpText="Require Username and Password to access Sonarr" + onChange={onInputChange} + {...authenticationMethod} + /> + </FormGroup> + + { + authenticationEnabled ? + <FormGroup> + <FormLabel>Authentication Required</FormLabel> + + <FormInputGroup + type={inputTypes.SELECT} + name="authenticationRequired" + values={authenticationRequiredOptions} + helpText="Change which requests authentication is required for. Do not change unless you understand the risks." + onChange={onInputChange} + {...authenticationRequired} + /> + </FormGroup> : + null + } + + { + authenticationEnabled ? + <FormGroup> + <FormLabel>Username</FormLabel> + + <FormInputGroup + type={inputTypes.TEXT} + name="username" + onChange={onInputChange} + {...username} + /> + </FormGroup> : + null + } + + { + authenticationEnabled ? + <FormGroup> + <FormLabel>Password</FormLabel> + + <FormInputGroup + type={inputTypes.PASSWORD} + name="password" + onChange={onInputChange} + {...password} + /> + </FormGroup> : + null + } + </div> : + null + } + + { + !isPopulated && !error ? <LoadingIndicator /> : null + } + </ModalBody> + + <ModalFooter> + <SpinnerButton + kind={kinds.PRIMARY} + isSpinning={isSaving} + isDisabled={!authenticationEnabled} + onPress={onSavePress} + > + Save + </SpinnerButton> + </ModalFooter> + </ModalContent> + ); +} + +AuthenticationRequiredModalContent.propTypes = { + isPopulated: PropTypes.bool.isRequired, + error: PropTypes.object, + isSaving: PropTypes.bool.isRequired, + saveError: PropTypes.object, + settings: PropTypes.object.isRequired, + onInputChange: PropTypes.func.isRequired, + onSavePress: PropTypes.func.isRequired, + dispatchFetchStatus: PropTypes.func.isRequired +}; + +export default AuthenticationRequiredModalContent; diff --git a/frontend/src/FirstRun/AuthenticationRequiredModalContentConnector.js b/frontend/src/FirstRun/AuthenticationRequiredModalContentConnector.js new file mode 100644 index 000000000..6653a9d34 --- /dev/null +++ b/frontend/src/FirstRun/AuthenticationRequiredModalContentConnector.js @@ -0,0 +1,86 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import { clearPendingChanges } from 'Store/Actions/baseActions'; +import { fetchGeneralSettings, saveGeneralSettings, setGeneralSettingsValue } from 'Store/Actions/settingsActions'; +import { fetchStatus } from 'Store/Actions/systemActions'; +import createSettingsSectionSelector from 'Store/Selectors/createSettingsSectionSelector'; +import AuthenticationRequiredModalContent from './AuthenticationRequiredModalContent'; + +const SECTION = 'general'; + +function createMapStateToProps() { + return createSelector( + createSettingsSectionSelector(SECTION), + (sectionSettings) => { + return { + ...sectionSettings + }; + } + ); +} + +const mapDispatchToProps = { + dispatchClearPendingChanges: clearPendingChanges, + dispatchSetGeneralSettingsValue: setGeneralSettingsValue, + dispatchSaveGeneralSettings: saveGeneralSettings, + dispatchFetchGeneralSettings: fetchGeneralSettings, + dispatchFetchStatus: fetchStatus +}; + +class AuthenticationRequiredModalContentConnector extends Component { + + // + // Lifecycle + + componentDidMount() { + this.props.dispatchFetchGeneralSettings(); + } + + componentWillUnmount() { + this.props.dispatchClearPendingChanges({ section: `settings.${SECTION}` }); + } + + // + // Listeners + + onInputChange = ({ name, value }) => { + this.props.dispatchSetGeneralSettingsValue({ name, value }); + }; + + onSavePress = () => { + this.props.dispatchSaveGeneralSettings(); + }; + + // + // Render + + render() { + const { + dispatchClearPendingChanges, + dispatchFetchGeneralSettings, + dispatchSetGeneralSettingsValue, + dispatchSaveGeneralSettings, + ...otherProps + } = this.props; + + return ( + <AuthenticationRequiredModalContent + {...otherProps} + onInputChange={this.onInputChange} + onSavePress={this.onSavePress} + /> + ); + } +} + +AuthenticationRequiredModalContentConnector.propTypes = { + dispatchClearPendingChanges: PropTypes.func.isRequired, + dispatchFetchGeneralSettings: PropTypes.func.isRequired, + dispatchSetGeneralSettingsValue: PropTypes.func.isRequired, + dispatchSaveGeneralSettings: PropTypes.func.isRequired, + dispatchFetchStatus: PropTypes.func.isRequired +}; + +export default connect(createMapStateToProps, mapDispatchToProps)(AuthenticationRequiredModalContentConnector); diff --git a/frontend/src/Settings/General/SecuritySettings.js b/frontend/src/Settings/General/SecuritySettings.js index d2589b6b1..d161667ba 100644 --- a/frontend/src/Settings/General/SecuritySettings.js +++ b/frontend/src/Settings/General/SecuritySettings.js @@ -11,12 +11,20 @@ import ConfirmModal from 'Components/Modal/ConfirmModal'; import { icons, inputTypes, kinds } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; -const authenticationMethodOptions = [ - { key: 'none', value: 'None' }, +export const authenticationRequiredWarning = 'To prevent remote access without authentication, Sonarr now requires authentication to be enabled. You can optionally disable authentication from local addresses.'; + +export const authenticationMethodOptions = [ + { key: 'none', value: 'None', isDisabled: true }, + { key: 'external', value: 'External', isHidden: true }, { key: 'basic', value: 'Basic (Browser Popup)' }, { key: 'forms', value: 'Forms (Login Page)' } ]; +export const authenticationRequiredOptions = [ + { key: 'enabled', value: 'Enabled' }, + { key: 'disabledForLocalAddresses', value: 'Disabled for Local Addresses' } +]; + const certificateValidationOptions = [ { key: 'enabled', value: 'Enabled' }, { key: 'disabledForLocalAddresses', value: 'Disabled for Local Addresses' }, @@ -68,6 +76,7 @@ class SecuritySettings extends Component { const { authenticationMethod, + authenticationRequired, username, password, apiKey, @@ -86,13 +95,31 @@ class SecuritySettings extends Component { name="authenticationMethod" values={authenticationMethodOptions} helpText={translate('AuthenticationMethodHelpText')} + helpTextWarning={authenticationRequiredWarning} onChange={onInputChange} {...authenticationMethod} /> </FormGroup> { - authenticationEnabled && + authenticationEnabled ? + <FormGroup> + <FormLabel>Authentication Required</FormLabel> + + <FormInputGroup + type={inputTypes.SELECT} + name="authenticationRequired" + values={authenticationRequiredOptions} + helpText="Change which requests authentication is required for. Do not change unless you understand the risks." + onChange={onInputChange} + {...authenticationRequired} + /> + </FormGroup> : + null + } + + { + authenticationEnabled ? <FormGroup> <FormLabel>{translate('Username')}</FormLabel> @@ -102,11 +129,12 @@ class SecuritySettings extends Component { onChange={onInputChange} {...username} /> - </FormGroup> + </FormGroup> : + null } { - authenticationEnabled && + authenticationEnabled ? <FormGroup> <FormLabel>{translate('Password')}</FormLabel> @@ -116,7 +144,8 @@ class SecuritySettings extends Component { onChange={onInputChange} {...password} /> - </FormGroup> + </FormGroup> : + null } <FormGroup> diff --git a/src/NzbDrone.Automation.Test/AutomationTest.cs b/src/NzbDrone.Automation.Test/AutomationTest.cs index 840346de8..247f52633 100644 --- a/src/NzbDrone.Automation.Test/AutomationTest.cs +++ b/src/NzbDrone.Automation.Test/AutomationTest.cs @@ -46,7 +46,7 @@ namespace NzbDrone.Automation.Test _runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), null); _runner.KillAll(); - _runner.Start(); + _runner.Start(true); driver.Url = "http://localhost:9696"; diff --git a/src/NzbDrone.Common/Instrumentation/Sentry/SentryCleanser.cs b/src/NzbDrone.Common/Instrumentation/Sentry/SentryCleanser.cs index 217ee5d72..a56e57376 100644 --- a/src/NzbDrone.Common/Instrumentation/Sentry/SentryCleanser.cs +++ b/src/NzbDrone.Common/Instrumentation/Sentry/SentryCleanser.cs @@ -11,26 +11,41 @@ namespace NzbDrone.Common.Instrumentation.Sentry { try { - sentryEvent.Message = CleanseLogMessage.Cleanse(sentryEvent.Message.Message); + if (sentryEvent.Message is not null) + { + sentryEvent.Message.Formatted = CleanseLogMessage.Cleanse(sentryEvent.Message.Formatted); + sentryEvent.Message.Message = CleanseLogMessage.Cleanse(sentryEvent.Message.Message); + sentryEvent.Message.Params = sentryEvent.Message.Params?.Select(x => CleanseLogMessage.Cleanse(x switch + { + string str => str, + _ => x.ToString() + })).ToList(); + } - if (sentryEvent.Fingerprint != null) + if (sentryEvent.Fingerprint.Any()) { var fingerprint = sentryEvent.Fingerprint.Select(x => CleanseLogMessage.Cleanse(x)).ToList(); sentryEvent.SetFingerprint(fingerprint); } - if (sentryEvent.Extra != null) + if (sentryEvent.Extra.Any()) { - var extras = sentryEvent.Extra.ToDictionary(x => x.Key, y => (object)CleanseLogMessage.Cleanse((string)y.Value)); + var extras = sentryEvent.Extra.ToDictionary(x => x.Key, y => (object)CleanseLogMessage.Cleanse(y.Value as string)); sentryEvent.SetExtras(extras); } - foreach (var exception in sentryEvent.SentryExceptions) + if (sentryEvent.SentryExceptions is not null) { - exception.Value = CleanseLogMessage.Cleanse(exception.Value); - foreach (var frame in exception.Stacktrace.Frames) + foreach (var exception in sentryEvent.SentryExceptions) { - frame.FileName = ShortenPath(frame.FileName); + exception.Value = CleanseLogMessage.Cleanse(exception.Value); + if (exception.Stacktrace is not null) + { + foreach (var frame in exception.Stacktrace.Frames) + { + frame.FileName = ShortenPath(frame.FileName); + } + } } } } diff --git a/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs b/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs index 8832b6251..2ba30e338 100644 --- a/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs +++ b/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs @@ -42,10 +42,7 @@ namespace NzbDrone.Common.Instrumentation.Sentry "UnauthorizedAccessException", // Filter out people stuck in boot loops - "CorruptDatabaseException", - - // This also filters some people in boot loops - "TinyIoCResolutionException" + "CorruptDatabaseException" }; public static readonly List<string> FilteredExceptionMessages = new List<string> @@ -102,9 +99,6 @@ namespace NzbDrone.Common.Instrumentation.Sentry o.Dsn = dsn; o.AttachStacktrace = true; o.MaxBreadcrumbs = 200; - o.SendDefaultPii = false; - o.Debug = false; - o.DiagnosticLevel = SentryLevel.Debug; o.Release = BuildInfo.Release; o.BeforeSend = x => SentryCleanser.CleanseEvent(x); o.BeforeBreadcrumb = x => SentryCleanser.CleanseBreadcrumb(x); @@ -210,7 +204,11 @@ namespace NzbDrone.Common.Instrumentation.Sentry if (ex != null) { fingerPrint.Add(ex.GetType().FullName); - fingerPrint.Add(ex.TargetSite.ToString()); + if (ex.TargetSite != null) + { + fingerPrint.Add(ex.TargetSite.ToString()); + } + if (ex.InnerException != null) { fingerPrint.Add(ex.InnerException.GetType().FullName); diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index ff0c30158..66ea583ee 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -4,13 +4,13 @@ <DefineConstants Condition="'$(RuntimeIdentifier)' == 'linux-musl-x64' or '$(RuntimeIdentifier)' == 'linux-musl-arm64'">ISMUSL</DefineConstants> </PropertyGroup> <ItemGroup> - <PackageReference Include="DryIoc.dll" Version="5.2.2" /> + <PackageReference Include="DryIoc.dll" Version="5.3.1" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.1" /> - <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> - <PackageReference Include="NLog" Version="5.0.1" /> - <PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" /> - <PackageReference Include="Sentry" Version="3.21.0" /> + <PackageReference Include="Newtonsoft.Json" Version="13.0.2" /> + <PackageReference Include="NLog" Version="5.1.0" /> + <PackageReference Include="NLog.Extensions.Logging" Version="5.2.0" /> + <PackageReference Include="Sentry" Version="3.24.1" /> <PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" /> <PackageReference Include="SharpZipLib" Version="1.3.3" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" /> diff --git a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj index 6d48fa0a6..47a54f144 100644 --- a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj @@ -6,7 +6,7 @@ <PackageReference Include="Dapper" Version="2.0.123" /> <PackageReference Include="NBuilder" Version="6.1.0" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> - <PackageReference Include="YamlDotNet" Version="12.0.1" /> + <PackageReference Include="YamlDotNet" Version="12.3.1" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" /> diff --git a/src/NzbDrone.Core/Authentication/AuthenticationRequiredType.cs b/src/NzbDrone.Core/Authentication/AuthenticationRequiredType.cs new file mode 100644 index 000000000..dc3c2c770 --- /dev/null +++ b/src/NzbDrone.Core/Authentication/AuthenticationRequiredType.cs @@ -0,0 +1,8 @@ +namespace NzbDrone.Core.Authentication +{ + public enum AuthenticationRequiredType + { + Enabled = 0, + DisabledForLocalAddresses = 1 + } +} diff --git a/src/NzbDrone.Core/Authentication/AuthenticationType.cs b/src/NzbDrone.Core/Authentication/AuthenticationType.cs index 9f21b07a7..ca408774b 100644 --- a/src/NzbDrone.Core/Authentication/AuthenticationType.cs +++ b/src/NzbDrone.Core/Authentication/AuthenticationType.cs @@ -1,9 +1,10 @@ -namespace NzbDrone.Core.Authentication +namespace NzbDrone.Core.Authentication { public enum AuthenticationType { None = 0, Basic = 1, - Forms = 2 + Forms = 2, + External = 3 } } diff --git a/src/NzbDrone.Core/Authentication/User.cs b/src/NzbDrone.Core/Authentication/User.cs index 794d4824a..63c67bd5f 100644 --- a/src/NzbDrone.Core/Authentication/User.cs +++ b/src/NzbDrone.Core/Authentication/User.cs @@ -1,4 +1,4 @@ -using System; +using System; using NzbDrone.Core.Datastore; namespace NzbDrone.Core.Authentication @@ -8,5 +8,7 @@ namespace NzbDrone.Core.Authentication public Guid Identifier { get; set; } public string Username { get; set; } public string Password { get; set; } + public string Salt { get; set; } + public int Iterations { get; set; } } } diff --git a/src/NzbDrone.Core/Authentication/UserService.cs b/src/NzbDrone.Core/Authentication/UserService.cs index 73f70aa5b..9b4553788 100644 --- a/src/NzbDrone.Core/Authentication/UserService.cs +++ b/src/NzbDrone.Core/Authentication/UserService.cs @@ -1,4 +1,6 @@ using System; +using System.Security.Cryptography; +using Microsoft.AspNetCore.Cryptography.KeyDerivation; using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; @@ -21,6 +23,10 @@ namespace NzbDrone.Core.Authentication private readonly IAppFolderInfo _appFolderInfo; private readonly IDiskProvider _diskProvider; + private static readonly int ITERATIONS = 10000; + private static readonly int SALT_SIZE = 128 / 8; + private static readonly int NUMBER_OF_BYTES = 256 / 8; + public UserService(IUserRepository repo, IAppFolderInfo appFolderInfo, IDiskProvider diskProvider) { _repo = repo; @@ -30,12 +36,15 @@ namespace NzbDrone.Core.Authentication public User Add(string username, string password) { - return _repo.Insert(new User + var user = new User { Identifier = Guid.NewGuid(), - Username = username.ToLowerInvariant(), - Password = password.SHA256Hash() - }); + Username = username.ToLowerInvariant() + }; + + SetUserHashedPassword(user, password); + + return _repo.Insert(user); } public User Update(User user) @@ -54,7 +63,7 @@ namespace NzbDrone.Core.Authentication if (user.Password != password) { - user.Password = password.SHA256Hash(); + SetUserHashedPassword(user, password); } user.Username = username.ToLowerInvariant(); @@ -81,7 +90,20 @@ namespace NzbDrone.Core.Authentication return null; } - if (user.Password == password.SHA256Hash()) + if (user.Salt.IsNullOrWhiteSpace()) + { + // If password matches stored SHA256 hash, update to salted hash and verify. + if (user.Password == password.SHA256Hash()) + { + SetUserHashedPassword(user, password); + + return Update(user); + } + + return null; + } + + if (VerifyHashedPassword(user, password)) { return user; } @@ -93,5 +115,42 @@ namespace NzbDrone.Core.Authentication { return _repo.FindUser(identifier); } + + private User SetUserHashedPassword(User user, string password) + { + var salt = GenerateSalt(); + + user.Iterations = ITERATIONS; + user.Salt = Convert.ToBase64String(salt); + user.Password = GetHashedPassword(password, salt, ITERATIONS); + + return user; + } + + private byte[] GenerateSalt() + { + var salt = new byte[SALT_SIZE]; + RandomNumberGenerator.Create().GetBytes(salt); + + return salt; + } + + private string GetHashedPassword(string password, byte[] salt, int iterations) + { + return Convert.ToBase64String(KeyDerivation.Pbkdf2( + password: password, + salt: salt, + prf: KeyDerivationPrf.HMACSHA512, + iterationCount: iterations, + numBytesRequested: NUMBER_OF_BYTES)); + } + + private bool VerifyHashedPassword(User user, string password) + { + var salt = Convert.FromBase64String(user.Salt); + var hashedPassword = GetHashedPassword(password, salt, user.Iterations); + + return user.Password == hashedPassword; + } } } diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index ac8a13a4e..6ccc49cc7 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -32,6 +32,7 @@ namespace NzbDrone.Core.Configuration bool EnableSsl { get; } bool LaunchBrowser { get; } AuthenticationType AuthenticationMethod { get; } + AuthenticationRequiredType AuthenticationRequired { get; } bool AnalyticsEnabled { get; } string LogLevel { get; } string ConsoleLogLevel { get; } @@ -193,6 +194,8 @@ namespace NzbDrone.Core.Configuration } } + public AuthenticationRequiredType AuthenticationRequired => GetValueEnum("AuthenticationRequired", AuthenticationRequiredType.Enabled); + public bool AnalyticsEnabled => GetValueBoolean("AnalyticsEnabled", true, persist: false); // TODO: Change back to "master" for the first stable release. diff --git a/src/NzbDrone.Core/Datastore/Migration/024_add_salt_to_users.cs b/src/NzbDrone.Core/Datastore/Migration/024_add_salt_to_users.cs new file mode 100644 index 000000000..e5bb6b083 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/024_add_salt_to_users.cs @@ -0,0 +1,16 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(024)] + public class add_salt_to_users : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Alter.Table("Users") + .AddColumn("Salt").AsString().Nullable() + .AddColumn("Iterations").AsInt32().Nullable(); + } + } +} diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index fae8e0d2e..7dc2b8187 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -6,7 +6,8 @@ <PackageReference Include="AngleSharp.Xml" Version="0.17.0" /> <PackageReference Include="Dapper" Version="2.0.123" /> <PackageReference Include="FluentMigrator.Runner" Version="3.3.2" /> - <PackageReference Include="MailKit" Version="3.4.1" /> + <PackageReference Include="MailKit" Version="3.4.3" /> + <PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="6.0.12" /> <PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" /> <PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" /> <PackageReference Include="Npgsql" Version="5.0.11" /> @@ -15,13 +16,13 @@ <PackageReference Include="FluentMigrator.Runner.SQLite" Version="3.3.2" /> <PackageReference Include="FluentMigrator.Runner.Postgres" Version="3.3.2" /> <PackageReference Include="FluentValidation" Version="8.6.2" /> - <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> - <PackageReference Include="NLog" Version="5.0.1" /> + <PackageReference Include="Newtonsoft.Json" Version="13.0.2" /> + <PackageReference Include="NLog" Version="5.1.0" /> <PackageReference Include="TinyTwitter" Version="1.1.2" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> <PackageReference Include="System.Text.Json" Version="6.0.5" /> <PackageReference Include="MonoTorrent" Version="2.0.5" /> - <PackageReference Include="YamlDotNet" Version="12.0.1" /> + <PackageReference Include="YamlDotNet" Version="12.3.1" /> <PackageReference Include="AngleSharp" Version="0.17.1" /> </ItemGroup> <ItemGroup> diff --git a/src/NzbDrone.Host/Prowlarr.Host.csproj b/src/NzbDrone.Host/Prowlarr.Host.csproj index 660f10f29..7aa32bf91 100644 --- a/src/NzbDrone.Host/Prowlarr.Host.csproj +++ b/src/NzbDrone.Host/Prowlarr.Host.csproj @@ -4,11 +4,11 @@ <OutputType>Library</OutputType> </PropertyGroup> <ItemGroup> - <PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" /> + <PackageReference Include="NLog.Extensions.Logging" Version="5.2.0" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.1" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.4.0" /> - <PackageReference Include="DryIoc.dll" Version="5.2.2" /> + <PackageReference Include="DryIoc.dll" Version="5.3.1" /> <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="6.1.0" /> </ItemGroup> <ItemGroup> diff --git a/src/NzbDrone.Host/Startup.cs b/src/NzbDrone.Host/Startup.cs index b8461c581..f70d90be0 100644 --- a/src/NzbDrone.Host/Startup.cs +++ b/src/NzbDrone.Host/Startup.cs @@ -22,7 +22,6 @@ using NzbDrone.Core.Instrumentation; using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Messaging.Events; using NzbDrone.Host.AccessControl; -using NzbDrone.Http.Authentication; using NzbDrone.SignalR; using Prowlarr.Api.V1.System; using Prowlarr.Http; @@ -172,6 +171,8 @@ namespace NzbDrone.Host .PersistKeysToFileSystem(new DirectoryInfo(Configuration["dataProtectionFolder"])); services.AddSingleton<IAuthorizationPolicyProvider, UiAuthorizationPolicyProvider>(); + services.AddSingleton<IAuthorizationHandler, UiAuthorizationHandler>(); + services.AddAuthorization(options => { options.AddPolicy("SignalR", policy => diff --git a/src/NzbDrone.Test.Common/NzbDroneRunner.cs b/src/NzbDrone.Test.Common/NzbDroneRunner.cs index b4c97847c..e4c66b937 100644 --- a/src/NzbDrone.Test.Common/NzbDroneRunner.cs +++ b/src/NzbDrone.Test.Common/NzbDroneRunner.cs @@ -37,12 +37,12 @@ namespace NzbDrone.Test.Common Port = port; } - public void Start() + public void Start(bool enableAuth = false) { AppData = Path.Combine(TestContext.CurrentContext.TestDirectory, "_intg_" + TestBase.GetUID()); Directory.CreateDirectory(AppData); - GenerateConfigFile(); + GenerateConfigFile(enableAuth); string consoleExe; if (OsInfo.IsWindows) @@ -167,7 +167,7 @@ namespace NzbDrone.Test.Common } } - private void GenerateConfigFile() + private void GenerateConfigFile(bool enableAuth) { var configFile = Path.Combine(AppData, "config.xml"); @@ -180,6 +180,8 @@ namespace NzbDrone.Test.Common new XElement(nameof(ConfigFileProvider.ApiKey), apiKey), new XElement(nameof(ConfigFileProvider.LogLevel), "trace"), new XElement(nameof(ConfigFileProvider.AnalyticsEnabled), false), + new XElement(nameof(ConfigFileProvider.AuthenticationMethod), enableAuth ? "Forms" : "None"), + new XElement(nameof(ConfigFileProvider.AuthenticationRequired), "DisabledForLocalAddresses"), new XElement(nameof(ConfigFileProvider.Port), Port))); var data = xDoc.ToString(); diff --git a/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj b/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj index 1ca89ee02..1f680a255 100644 --- a/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj +++ b/src/NzbDrone.Test.Common/Prowlarr.Test.Common.csproj @@ -6,7 +6,7 @@ <PackageReference Include="FluentAssertions" Version="5.10.3" /> <PackageReference Include="FluentValidation" Version="8.6.2" /> <PackageReference Include="Moq" Version="4.17.2" /> - <PackageReference Include="NLog" Version="5.0.1" /> + <PackageReference Include="NLog" Version="5.1.0" /> <PackageReference Include="NUnit" Version="3.13.3" /> <PackageReference Include="RestSharp" Version="106.15.0" /> <PackageReference Include="RestSharp.Serializers.SystemTextJson" Version="106.15.0" /> diff --git a/src/NzbDrone.Update/Prowlarr.Update.csproj b/src/NzbDrone.Update/Prowlarr.Update.csproj index 7af53f202..d34e071f0 100644 --- a/src/NzbDrone.Update/Prowlarr.Update.csproj +++ b/src/NzbDrone.Update/Prowlarr.Update.csproj @@ -4,9 +4,9 @@ <TargetFrameworks>net6.0</TargetFrameworks> </PropertyGroup> <ItemGroup> - <PackageReference Include="DryIoc.dll" Version="5.2.2" /> + <PackageReference Include="DryIoc.dll" Version="5.3.1" /> <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="6.1.0" /> - <PackageReference Include="NLog" Version="5.0.1" /> + <PackageReference Include="NLog" Version="5.1.0" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Common\Prowlarr.Common.csproj" /> diff --git a/src/NzbDrone.Windows/Prowlarr.Windows.csproj b/src/NzbDrone.Windows/Prowlarr.Windows.csproj index 1661cd01f..f690fcf0f 100644 --- a/src/NzbDrone.Windows/Prowlarr.Windows.csproj +++ b/src/NzbDrone.Windows/Prowlarr.Windows.csproj @@ -4,7 +4,7 @@ <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> </PropertyGroup> <ItemGroup> - <PackageReference Include="NLog" Version="5.0.1" /> + <PackageReference Include="NLog" Version="5.1.0" /> <PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" /> </ItemGroup> <ItemGroup> diff --git a/src/Prowlarr.Api.V1/Config/HostConfigResource.cs b/src/Prowlarr.Api.V1/Config/HostConfigResource.cs index 820552533..38d132615 100644 --- a/src/Prowlarr.Api.V1/Config/HostConfigResource.cs +++ b/src/Prowlarr.Api.V1/Config/HostConfigResource.cs @@ -15,6 +15,7 @@ namespace Prowlarr.Api.V1.Config public bool EnableSsl { get; set; } public bool LaunchBrowser { get; set; } public AuthenticationType AuthenticationMethod { get; set; } + public AuthenticationRequiredType AuthenticationRequired { get; set; } public bool AnalyticsEnabled { get; set; } public string Username { get; set; } public string Password { get; set; } @@ -57,6 +58,7 @@ namespace Prowlarr.Api.V1.Config EnableSsl = model.EnableSsl, LaunchBrowser = model.LaunchBrowser, AuthenticationMethod = model.AuthenticationMethod, + AuthenticationRequired = model.AuthenticationRequired, AnalyticsEnabled = model.AnalyticsEnabled, //Username diff --git a/src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj b/src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj index 5fa5c9af6..fb87b706f 100644 --- a/src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj +++ b/src/Prowlarr.Api.V1/Prowlarr.Api.V1.csproj @@ -4,7 +4,7 @@ </PropertyGroup> <ItemGroup> <PackageReference Include="FluentValidation" Version="8.6.2" /> - <PackageReference Include="NLog" Version="5.0.1" /> + <PackageReference Include="NLog" Version="5.1.0" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Core\Prowlarr.Core.csproj" /> diff --git a/src/Prowlarr.Http/Authentication/ApiKeyAuthenticationHandler.cs b/src/Prowlarr.Http/Authentication/ApiKeyAuthenticationHandler.cs index 3eed8c06c..eda470c4c 100644 --- a/src/Prowlarr.Http/Authentication/ApiKeyAuthenticationHandler.cs +++ b/src/Prowlarr.Http/Authentication/ApiKeyAuthenticationHandler.cs @@ -13,6 +13,7 @@ namespace Prowlarr.Http.Authentication public class ApiKeyAuthenticationOptions : AuthenticationSchemeOptions { public const string DefaultScheme = "API Key"; + public string Scheme => DefaultScheme; public string AuthenticationType = DefaultScheme; diff --git a/src/Prowlarr.Http/Authentication/AuthenticationBuilderExtensions.cs b/src/Prowlarr.Http/Authentication/AuthenticationBuilderExtensions.cs index e672a87e5..cdc024e05 100644 --- a/src/Prowlarr.Http/Authentication/AuthenticationBuilderExtensions.cs +++ b/src/Prowlarr.Http/Authentication/AuthenticationBuilderExtensions.cs @@ -22,10 +22,16 @@ namespace Prowlarr.Http.Authentication return authenticationBuilder.AddScheme<AuthenticationSchemeOptions, NoAuthenticationHandler>(name, options => { }); } + public static AuthenticationBuilder AddExternal(this AuthenticationBuilder authenticationBuilder, string name) + { + return authenticationBuilder.AddScheme<AuthenticationSchemeOptions, NoAuthenticationHandler>(name, options => { }); + } + public static AuthenticationBuilder AddAppAuthentication(this IServiceCollection services) { return services.AddAuthentication() .AddNone(AuthenticationType.None.ToString()) + .AddExternal(AuthenticationType.External.ToString()) .AddBasic(AuthenticationType.Basic.ToString()) .AddCookie(AuthenticationType.Forms.ToString(), options => { diff --git a/src/Prowlarr.Http/Authentication/BypassableDenyAnonymousAuthorizationRequirement.cs b/src/Prowlarr.Http/Authentication/BypassableDenyAnonymousAuthorizationRequirement.cs new file mode 100644 index 000000000..1853acea6 --- /dev/null +++ b/src/Prowlarr.Http/Authentication/BypassableDenyAnonymousAuthorizationRequirement.cs @@ -0,0 +1,8 @@ +using Microsoft.AspNetCore.Authorization.Infrastructure; + +namespace Prowlarr.Http.Authentication +{ + public class BypassableDenyAnonymousAuthorizationRequirement : DenyAnonymousAuthorizationRequirement + { + } +} diff --git a/src/Prowlarr.Http/Authentication/UiAuthorizationHandler.cs b/src/Prowlarr.Http/Authentication/UiAuthorizationHandler.cs new file mode 100644 index 000000000..738364748 --- /dev/null +++ b/src/Prowlarr.Http/Authentication/UiAuthorizationHandler.cs @@ -0,0 +1,45 @@ +using System.Net; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Authentication; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Configuration.Events; +using NzbDrone.Core.Messaging.Events; +using Prowlarr.Http.Extensions; + +namespace Prowlarr.Http.Authentication +{ + public class UiAuthorizationHandler : AuthorizationHandler<BypassableDenyAnonymousAuthorizationRequirement>, IAuthorizationRequirement, IHandle<ConfigSavedEvent> + { + private readonly IConfigFileProvider _configService; + private static AuthenticationRequiredType _authenticationRequired; + + public UiAuthorizationHandler(IConfigFileProvider configService) + { + _configService = configService; + _authenticationRequired = configService.AuthenticationRequired; + } + + protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, BypassableDenyAnonymousAuthorizationRequirement requirement) + { + if (_authenticationRequired == AuthenticationRequiredType.DisabledForLocalAddresses) + { + if (context.Resource is HttpContext httpContext && + IPAddress.TryParse(httpContext.GetRemoteIP(), out var ipAddress) && + ipAddress.IsLocalAddress()) + { + context.Succeed(requirement); + } + } + + return Task.CompletedTask; + } + + public void Handle(ConfigSavedEvent message) + { + _authenticationRequired = _configService.AuthenticationRequired; + } + } +} diff --git a/src/Prowlarr.Http/Authentication/UiAuthorizationPolicyProvider.cs b/src/Prowlarr.Http/Authentication/UiAuthorizationPolicyProvider.cs index a5295a99f..2c1cc208b 100644 --- a/src/Prowlarr.Http/Authentication/UiAuthorizationPolicyProvider.cs +++ b/src/Prowlarr.Http/Authentication/UiAuthorizationPolicyProvider.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Options; using NzbDrone.Core.Configuration; -namespace NzbDrone.Http.Authentication +namespace Prowlarr.Http.Authentication { public class UiAuthorizationPolicyProvider : IAuthorizationPolicyProvider { @@ -29,7 +29,8 @@ namespace NzbDrone.Http.Authentication if (policyName.Equals(POLICY_NAME, StringComparison.OrdinalIgnoreCase)) { var policy = new AuthorizationPolicyBuilder(_config.AuthenticationMethod.ToString()) - .RequireAuthenticatedUser(); + .AddRequirements(new BypassableDenyAnonymousAuthorizationRequirement()); + return Task.FromResult(policy.Build()); } diff --git a/src/Prowlarr.Http/Prowlarr.Http.csproj b/src/Prowlarr.Http/Prowlarr.Http.csproj index 75751a276..8cfc4f4b2 100644 --- a/src/Prowlarr.Http/Prowlarr.Http.csproj +++ b/src/Prowlarr.Http/Prowlarr.Http.csproj @@ -5,7 +5,7 @@ <ItemGroup> <PackageReference Include="FluentValidation" Version="8.6.2" /> <PackageReference Include="ImpromptuInterface" Version="7.0.1" /> - <PackageReference Include="NLog" Version="5.0.1" /> + <PackageReference Include="NLog" Version="5.1.0" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NzbDrone.Core\Prowlarr.Core.csproj" /> From c94beb68140bcc2020446642cc55b0df856b14ad Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 20 Dec 2022 14:58:58 -0600 Subject: [PATCH 0696/2320] Fixed: Translations for Auth Settings --- .../AuthenticationRequiredModalContent.js | 17 +++++++++-------- .../src/Settings/General/SecuritySettings.js | 6 +++--- src/NzbDrone.Core/Localization/Core/en.json | 3 +++ 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/frontend/src/FirstRun/AuthenticationRequiredModalContent.js b/frontend/src/FirstRun/AuthenticationRequiredModalContent.js index 193bdf950..920c59a31 100644 --- a/frontend/src/FirstRun/AuthenticationRequiredModalContent.js +++ b/frontend/src/FirstRun/AuthenticationRequiredModalContent.js @@ -12,6 +12,7 @@ import ModalFooter from 'Components/Modal/ModalFooter'; import ModalHeader from 'Components/Modal/ModalHeader'; import { inputTypes, kinds } from 'Helpers/Props'; import { authenticationMethodOptions, authenticationRequiredOptions, authenticationRequiredWarning } from 'Settings/General/SecuritySettings'; +import translate from 'Utilities/String/translate'; import styles from './AuthenticationRequiredModalContent.css'; function onModalClose() { @@ -54,7 +55,7 @@ function AuthenticationRequiredModalContent(props) { onModalClose={onModalClose} > <ModalHeader> - Authentication Required + {translate('AuthenticationRequired')} </ModalHeader> <ModalBody> @@ -69,13 +70,13 @@ function AuthenticationRequiredModalContent(props) { isPopulated && !error ? <div> <FormGroup> - <FormLabel>Authentication</FormLabel> + <FormLabel>{translate('Authentication')}</FormLabel> <FormInputGroup type={inputTypes.SELECT} name="authenticationMethod" values={authenticationMethodOptions} - helpText="Require Username and Password to access Sonarr" + helpText={translate('AuthenticationMethodHelpText')} onChange={onInputChange} {...authenticationMethod} /> @@ -84,13 +85,13 @@ function AuthenticationRequiredModalContent(props) { { authenticationEnabled ? <FormGroup> - <FormLabel>Authentication Required</FormLabel> + <FormLabel>{translate('AuthenticationRequired')}</FormLabel> <FormInputGroup type={inputTypes.SELECT} name="authenticationRequired" values={authenticationRequiredOptions} - helpText="Change which requests authentication is required for. Do not change unless you understand the risks." + helpText={translate('AuthenticationRequiredHelpText')} onChange={onInputChange} {...authenticationRequired} /> @@ -101,7 +102,7 @@ function AuthenticationRequiredModalContent(props) { { authenticationEnabled ? <FormGroup> - <FormLabel>Username</FormLabel> + <FormLabel>{translate('Username')}</FormLabel> <FormInputGroup type={inputTypes.TEXT} @@ -116,7 +117,7 @@ function AuthenticationRequiredModalContent(props) { { authenticationEnabled ? <FormGroup> - <FormLabel>Password</FormLabel> + <FormLabel>{translate('Password')}</FormLabel> <FormInputGroup type={inputTypes.PASSWORD} @@ -143,7 +144,7 @@ function AuthenticationRequiredModalContent(props) { isDisabled={!authenticationEnabled} onPress={onSavePress} > - Save + {translate('Save')} </SpinnerButton> </ModalFooter> </ModalContent> diff --git a/frontend/src/Settings/General/SecuritySettings.js b/frontend/src/Settings/General/SecuritySettings.js index d161667ba..4b382800c 100644 --- a/frontend/src/Settings/General/SecuritySettings.js +++ b/frontend/src/Settings/General/SecuritySettings.js @@ -11,7 +11,7 @@ import ConfirmModal from 'Components/Modal/ConfirmModal'; import { icons, inputTypes, kinds } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; -export const authenticationRequiredWarning = 'To prevent remote access without authentication, Sonarr now requires authentication to be enabled. You can optionally disable authentication from local addresses.'; +export const authenticationRequiredWarning = translate('AuthenticationRequiredWarning'); export const authenticationMethodOptions = [ { key: 'none', value: 'None', isDisabled: true }, @@ -104,13 +104,13 @@ class SecuritySettings extends Component { { authenticationEnabled ? <FormGroup> - <FormLabel>Authentication Required</FormLabel> + <FormLabel>{translate('AuthenticationRequired')}</FormLabel> <FormInputGroup type={inputTypes.SELECT} name="authenticationRequired" values={authenticationRequiredOptions} - helpText="Change which requests authentication is required for. Do not change unless you understand the risks." + helpText={translate('AuthenticationRequiredHelpText')} onChange={onInputChange} {...authenticationRequired} /> diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 5a2bf2838..44df1df07 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -45,6 +45,9 @@ "Auth": "Auth", "Authentication": "Authentication", "AuthenticationMethodHelpText": "Require Username and Password to access Prowlarr", + "AuthenticationRequired": "Authentication Required", + "AuthenticationRequiredHelpText": "Change which requests authentication is required for. Do not change unless you understand the risks.", + "AuthenticationRequiredWarning": "To prevent remote access without authentication, Prowlarr now requires authentication to be enabled. You can optionally disable authentication from local addresses.", "Automatic": "Automatic", "AutomaticSearch": "Automatic Search", "Backup": "Backup", From 8afaa3386da2e5d5e698271e1038a7f891ce95a1 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 20 Dec 2022 15:12:07 -0600 Subject: [PATCH 0697/2320] Fixed: (PrivateHD) Remove Audio category Fixes #1246 --- src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs b/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs index dc8feb1d2..55505681e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/PrivateHD.cs @@ -40,10 +40,6 @@ namespace NzbDrone.Core.Indexers.Definitions MovieSearchParams = new List<MovieSearchParam> { MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId, MovieSearchParam.Genre - }, - MusicSearchParams = new List<MusicSearchParam> - { - MusicSearchParam.Q } }; @@ -55,7 +51,6 @@ namespace NzbDrone.Core.Indexers.Definitions caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVUHD); caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVHD); caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVSD); - caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio); return caps; } From d285cbb0211472201254faa9e7ecf81eabafdc44 Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 20 Dec 2022 15:20:06 -0600 Subject: [PATCH 0698/2320] (SecretCinema) Avoid double HtmlDecode #1238 --- src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs b/src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs index afa3927a4..75381c628 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs @@ -119,7 +119,7 @@ namespace NzbDrone.Core.Indexers.Definitions var release = new GazelleInfo() { Guid = string.Format("SecretCinema-{0}", id), - Title = WebUtility.HtmlDecode(title), + Title = title, Container = torrent.Encoding, Files = torrent.FileCount, Grabs = torrent.Snatches, From e9764820c012e9cfe5c823ea87c1277f54878b4a Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 20 Dec 2022 16:24:34 -0600 Subject: [PATCH 0699/2320] Fixed: (SecretCinema) Title not being decoded Fixes #1238 --- .../Indexers/SecretCinema/recentfeed.json | 144 ++++++++++++++++++ .../OrpheusTests/OrpheusFixture.cs | 2 +- .../SecretCinemaTests/SecretCinemaFixture.cs | 68 +++++++++ .../Indexers/Definitions/SecretCinema.cs | 17 +-- 4 files changed, 219 insertions(+), 12 deletions(-) create mode 100644 src/NzbDrone.Core.Test/Files/Indexers/SecretCinema/recentfeed.json create mode 100644 src/NzbDrone.Core.Test/IndexerTests/SecretCinemaTests/SecretCinemaFixture.cs diff --git a/src/NzbDrone.Core.Test/Files/Indexers/SecretCinema/recentfeed.json b/src/NzbDrone.Core.Test/Files/Indexers/SecretCinema/recentfeed.json new file mode 100644 index 000000000..268d37913 --- /dev/null +++ b/src/NzbDrone.Core.Test/Files/Indexers/SecretCinema/recentfeed.json @@ -0,0 +1,144 @@ +{ + "status": "success", + "response": { + "currentPage": 1, + "pages": 1, + "results": [ + { + "groupId": 2497, + "groupName": "Singin' in the Rain", + "artist": "Gene Kelly & Stanley Donen", + "cover": "https:\/\/www.themoviedb.org\/t\/p\/original\/g2AaJDC2vSRcqHSDH29642xmQd.jpg", + "tags": [ "comedy", "musical", "romance" ], + "bookmarked": false, + "vanityHouse": false, + "groupYear": 1952, + "releaseType": null, + "groupTime": "1671129449", + "maxSize": 57473058680, + "totalSnatched": 25, + "totalSeeders": 9, + "totalLeechers": 0, + "torrents": [ + { + "torrentId": 3599, + "editionId": 1, + "artists": [ + { + "id": 126, + "name": "Gene Kelly", + "aliasid": 127 + }, + { + "id": 125, + "name": "Stanley Donen", + "aliasid": 126 + } + ], + "remastered": false, + "remasterYear": 0, + "remasterCatalogueNumber": "", + "remasterTitle": "", + "media": "1080p", + "encoding": "", + "format": "", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 1, + "time": "2017-09-10 11:47:27", + "size": 24724893991, + "snatches": 14, + "seeders": 1, + "leechers": 0, + "isFreeleech": true, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": false, + "hasSnatched": false + }, + { + "torrentId": 45068, + "editionId": 2, + "artists": [ + { + "id": 126, + "name": "Gene Kelly", + "aliasid": 127 + }, + { + "id": 125, + "name": "Stanley Donen", + "aliasid": 126 + } + ], + "remastered": false, + "remasterYear": 0, + "remasterCatalogueNumber": "", + "remasterTitle": "", + "media": "2160p", + "encoding": "", + "format": "", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 1, + "time": "2022-12-15 19:37:29", + "size": 57473058680, + "snatches": 6, + "seeders": 8, + "leechers": 0, + "isFreeleech": true, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": false, + "hasSnatched": false + }, + { + "torrentId": 2726, + "editionId": 3, + "artists": [ + { + "id": 126, + "name": "Gene Kelly", + "aliasid": 127 + }, + { + "id": 125, + "name": "Stanley Donen", + "aliasid": 126 + } + ], + "remastered": false, + "remasterYear": 0, + "remasterCatalogueNumber": "", + "remasterTitle": "", + "media": "DVD-R", + "encoding": "", + "format": "", + "hasLog": false, + "logScore": 0, + "hasCue": false, + "scene": false, + "vanityHouse": false, + "fileCount": 37, + "time": "2017-08-26 14:58:58", + "size": 10350032896, + "snatches": 5, + "seeders": 0, + "leechers": 0, + "isFreeleech": true, + "isNeutralLeech": false, + "isPersonalFreeleech": false, + "canUseToken": false, + "hasSnatched": false + } + ] + } + ] + } +} \ No newline at end of file diff --git a/src/NzbDrone.Core.Test/IndexerTests/OrpheusTests/OrpheusFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/OrpheusTests/OrpheusFixture.cs index 5c007cec0..03f012795 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/OrpheusTests/OrpheusFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/OrpheusTests/OrpheusFixture.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Test.IndexerTests.OrpheusTests } [Test] - public async Task should_parse_recent_feed_from_GazelleGames() + public async Task should_parse_recent_feed_from_Orpheus() { var recentFeed = ReadAllText(@"Files/Indexers/Orpheus/recentfeed.json"); diff --git a/src/NzbDrone.Core.Test/IndexerTests/SecretCinemaTests/SecretCinemaFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/SecretCinemaTests/SecretCinemaFixture.cs new file mode 100644 index 000000000..5da0a9864 --- /dev/null +++ b/src/NzbDrone.Core.Test/IndexerTests/SecretCinemaTests/SecretCinemaFixture.cs @@ -0,0 +1,68 @@ +using System; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Common.Http; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Indexers.Definitions; +using NzbDrone.Core.Indexers.Gazelle; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.IndexerTests.SecretCinemaTests +{ + [TestFixture] + public class SecretCinemaFixture : CoreTest<SecretCinema> + { + [SetUp] + public void Setup() + { + Subject.Definition = new IndexerDefinition() + { + Name = "SecretCinema", + Settings = new GazelleSettings() { Username = "somekey", Password = "somekey" } + }; + } + + [Test] + public async Task should_parse_recent_feed_from_SecretCinema() + { + var recentFeed = ReadAllText(@"Files/Indexers/SecretCinema/recentfeed.json"); + + Mocker.GetMock<IIndexerHttpClient>() + .Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition)) + .Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader { { "Content-Type", "application/json" } }, new CookieCollection(), recentFeed))); + + var releases = (await Subject.Fetch(new BasicSearchCriteria { Categories = new int[] { 2000 } })).Releases; + + releases.Should().HaveCount(3); + releases.First().Should().BeOfType<GazelleInfo>(); + + var torrentInfo = releases.First() as GazelleInfo; + + torrentInfo.Title.Should().Be("Singin' in the Rain (1952) 2160p"); + torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent); + torrentInfo.DownloadUrl.Should().Be("https://secret-cinema.pw/torrents.php?action=download&useToken=0&id=45068"); + torrentInfo.InfoUrl.Should().Be("https://secret-cinema.pw/torrents.php?id=2497&torrentid=45068"); + torrentInfo.CommentUrl.Should().BeNullOrEmpty(); + torrentInfo.Indexer.Should().Be(Subject.Definition.Name); + torrentInfo.PublishDate.Should().Be(DateTime.Parse("2022-12-15 19:37:29")); + torrentInfo.Size.Should().Be(57473058680); + torrentInfo.InfoHash.Should().Be(null); + torrentInfo.MagnetUrl.Should().Be(null); + torrentInfo.Peers.Should().Be(8); + torrentInfo.Seeders.Should().Be(8); + torrentInfo.ImdbId.Should().Be(0); + torrentInfo.TmdbId.Should().Be(0); + torrentInfo.TvdbId.Should().Be(0); + torrentInfo.Languages.Should().HaveCount(0); + torrentInfo.Subs.Should().HaveCount(0); + torrentInfo.DownloadVolumeFactor.Should().Be(0); + torrentInfo.UploadVolumeFactor.Should().Be(1); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs b/src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs index 75381c628..b39826d02 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SecretCinema.cs @@ -2,24 +2,16 @@ using System; using System.Collections.Generic; using System.Linq; using System.Net; -using System.Text; using System.Text.RegularExpressions; -using System.Threading.Tasks; -using FluentValidation; -using FluentValidation.Results; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; -using NzbDrone.Common.Serializer; -using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Gazelle; -using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions { @@ -113,7 +105,6 @@ namespace NzbDrone.Core.Indexers.Definitions // in SC movies, artist=director and GroupName=title var artist = WebUtility.HtmlDecode(result.Artist); - var album = WebUtility.HtmlDecode(result.GroupName); var title = WebUtility.HtmlDecode(result.GroupName); var release = new GazelleInfo() @@ -131,6 +122,8 @@ namespace NzbDrone.Core.Indexers.Definitions Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders), PublishDate = torrent.Time.ToUniversalTime(), Scene = torrent.Scene, + DownloadVolumeFactor = torrent.IsFreeLeech || torrent.IsNeutralLeech || torrent.IsPersonalFreeLeech ? 0 : 1, + UploadVolumeFactor = torrent.IsNeutralLeech ? 0 : 1 }; var category = torrent.Category; @@ -147,7 +140,7 @@ namespace NzbDrone.Core.Indexers.Definitions { // Remove director from title // SC API returns no more useful information than this - release.Title = $"{result.GroupName} ({result.GroupYear}) {torrent.Media}"; + release.Title = $"{title} ({result.GroupYear}) {torrent.Media}"; // Replace media formats with standards release.Title = Regex.Replace(release.Title, "BDMV", "COMPLETE BLURAY", RegexOptions.IgnoreCase); @@ -156,7 +149,7 @@ namespace NzbDrone.Core.Indexers.Definitions else { // SC API currently doesn't return anything but title. - release.Title = $"{result.Artist} - {result.GroupName} ({result.GroupYear}) [{torrent.Format} {torrent.Encoding}] [{torrent.Media}]"; + release.Title = $"{artist} - {title} ({result.GroupYear}) [{torrent.Format} {torrent.Encoding}] [{torrent.Media}]"; } if (torrent.HasCue) @@ -184,6 +177,8 @@ namespace NzbDrone.Core.Indexers.Definitions Files = result.FileCount, Grabs = result.Snatches, PublishDate = DateTimeOffset.FromUnixTimeSeconds(ParseUtil.CoerceLong(result.GroupTime)).UtcDateTime, + DownloadVolumeFactor = result.IsFreeLeech || result.IsNeutralLeech || result.IsPersonalFreeLeech ? 0 : 1, + UploadVolumeFactor = result.IsNeutralLeech ? 0 : 1 }; var category = result.Category; From 0199a37a0ce38f5d995b8fbd4819b0c2a20f81b9 Mon Sep 17 00:00:00 2001 From: Servarr <development@lidarr.audio> Date: Tue, 20 Dec 2022 22:29:45 +0000 Subject: [PATCH 0700/2320] Automated API Docs update --- src/Prowlarr.Api.V1/openapi.json | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Prowlarr.Api.V1/openapi.json b/src/Prowlarr.Api.V1/openapi.json index 4a93c7e02..fc8ae0348 100644 --- a/src/Prowlarr.Api.V1/openapi.json +++ b/src/Prowlarr.Api.V1/openapi.json @@ -4548,11 +4548,19 @@ ], "type": "string" }, + "AuthenticationRequiredType": { + "enum": [ + "enabled", + "disabledForLocalAddresses" + ], + "type": "string" + }, "AuthenticationType": { "enum": [ "none", "basic", - "forms" + "forms", + "external" ], "type": "string" }, @@ -5145,6 +5153,9 @@ "authenticationMethod": { "$ref": "#/components/schemas/AuthenticationType" }, + "authenticationRequired": { + "$ref": "#/components/schemas/AuthenticationRequiredType" + }, "analyticsEnabled": { "type": "boolean" }, From 30f53c20edc65d3847995e02750b7ed604514fcd Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 20 Dec 2022 17:59:50 -0600 Subject: [PATCH 0701/2320] New: Convert MoreThanTV to API Fixes #1235 --- src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs | 4 +--- src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs | 8 +++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs b/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs index 0ede86e38..29f434c3c 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/MoreThanTV.cs @@ -9,20 +9,18 @@ using System.Web; using AngleSharp.Dom; using AngleSharp.Html.Dom; using AngleSharp.Html.Parser; -using FluentValidation; using NLog; using NzbDrone.Common.Http; -using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions; +[Obsolete("Converted to Torznab")] public class MoreThanTV : TorrentIndexerBase<CookieTorrentBaseSettings> { public override string Name => "MoreThanTV"; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs index 57d08c52d..d54716855 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs @@ -88,8 +88,9 @@ namespace NzbDrone.Core.Indexers.Torznab { get { - yield return GetDefinition("AnimeTosho", GetSettings("https://feed.animetosho.org")); - yield return GetDefinition("Generic Torznab", GetSettings("")); + yield return GetDefinition("AnimeTosho", "", GetSettings("https://feed.animetosho.org")); + yield return GetDefinition("MoreThanTV", "Private torrent tracker for TV / MOVIES", GetSettings("https://www.morethantv.me")); + yield return GetDefinition("Generic Torznab", "A Newznab-like api for torrents.", GetSettings("")); } } @@ -99,12 +100,13 @@ namespace NzbDrone.Core.Indexers.Torznab _capabilitiesProvider = capabilitiesProvider; } - private IndexerDefinition GetDefinition(string name, TorznabSettings settings) + private IndexerDefinition GetDefinition(string name, string description, TorznabSettings settings) { return new IndexerDefinition { Enable = true, Name = name, + Description = description, Implementation = GetType().Name, Settings = settings, Protocol = DownloadProtocol.Usenet, From ad95d73e9dc407bb7814dc81000dbc306ebdf1fa Mon Sep 17 00:00:00 2001 From: Qstick <qstick@gmail.com> Date: Tue, 20 Dec 2022 20:50:30 -0600 Subject: [PATCH 0702/2320] Fixed: Category parsing for some not-so-great Torznab feeds MoreThanTv --- .../Indexers/Torznab/torznab_morethantv.xml | 55 +++++++++++++++++++ .../TorznabTests/TorznabFixture.cs | 36 ++++++++++++ .../Definitions/Newznab/NewznabRssParser.cs | 6 ++ .../Definitions/Torznab/TorznabRssParser.cs | 10 +++- 4 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 src/NzbDrone.Core.Test/Files/Indexers/Torznab/torznab_morethantv.xml diff --git a/src/NzbDrone.Core.Test/Files/Indexers/Torznab/torznab_morethantv.xml b/src/NzbDrone.Core.Test/Files/Indexers/Torznab/torznab_morethantv.xml new file mode 100644 index 000000000..2722c7aee --- /dev/null +++ b/src/NzbDrone.Core.Test/Files/Indexers/Torznab/torznab_morethantv.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rss version="2.0" xmlns:torznab="http://torznab.com/schemas/2015/feed"> + <channel> + <item> + <title>Out of the Past 1947 720p BluRay FLAC2.0 x264-CtrlHD.mkv + https://www.morethantv.me/torrents.php?id=(removed)&torrentid=836164 + https://www.morethantv.me/torrents.php?action=download&id=(removed)&authkey=(removed)&torrent_pass=(removed) + https://www.morethantv.me/torrents.php?id=(removed)&torrentid=836164 + Tue, 20 Dec 2022 21:32:17 +0000 + 5412993028 + 1 + 2 + 2000 + 2040 + A private eye escapes his past to run a gas station in a small town, but his past catches up with him. Now he must return to the big city world of danger, corruption, double crosses, and duplicitous dames. + + + + + + + + + + + + + + + Out of the Past 1947 1080p USA Blu-ray AVC DTS-HD MA 2.0-PCH + https://www.morethantv.me/torrents.php?id=(removed)&torrentid=836165 + https://www.morethantv.me/torrents.php?action=download&id=(removed)&authkey=(removed)&torrent_pass=(removed) + https://www.morethantv.me/torrents.php?id=(removed)&torrentid=836165 + Tue, 20 Dec 2022 21:47:40 +0000 + 30524085127 + 78 + 0 + 2000 + 2040 + A private eye escapes his past to run a gas station in a small town, but his past catches up with him. Now he must return to the big city world of danger, corruption, double crosses, and duplicitous dames. + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs index 2c96236fc..9018763a7 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs @@ -34,6 +34,10 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests }; _caps = new IndexerCapabilities(); + + _caps.Categories.AddCategoryMapping(2000, NewznabStandardCategory.Movies, "Movies"); + _caps.Categories.AddCategoryMapping(2040, NewznabStandardCategory.MoviesHD, "Movies/HD"); + Mocker.GetMock() .Setup(v => v.GetCapabilities(It.IsAny(), It.IsAny())) .Returns(_caps); @@ -129,6 +133,38 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests releaseInfo.Peers.Should().BeNull(); } + [Test] + public async Task should_parse_recent_feed_from_torznab_morethantv() + { + var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_morethantv.xml"); + + Mocker.GetMock() + .Setup(o => o.ExecuteProxiedAsync(It.Is(v => v.Method == HttpMethod.Get), Subject.Definition)) + .Returns((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed))); + + var releases = (await Subject.Fetch(new MovieSearchCriteria())).Releases; + + releases.Should().HaveCount(2); + + releases.First().Should().BeOfType(); + var releaseInfo = releases.First() as TorrentInfo; + + releaseInfo.Title.Should().Be("Out of the Past 1947 720p BluRay FLAC2.0 x264-CtrlHD.mkv"); + releaseInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent); + releaseInfo.DownloadUrl.Should().Be("https://www.morethantv.me/torrents.php?action=download&id=(removed)&authkey=(removed)&torrent_pass=(removed)"); + releaseInfo.InfoUrl.Should().Be("https://www.morethantv.me/torrents.php?id=(removed)&torrentid=836164"); + releaseInfo.CommentUrl.Should().Be("https://www.morethantv.me/torrents.php?id=(removed)&torrentid=836164"); + releaseInfo.Indexer.Should().Be(Subject.Definition.Name); + releaseInfo.PublishDate.Should().Be(DateTime.Parse("Tue, 20 Dec 2022 21:32:17 +0000").ToUniversalTime()); + releaseInfo.Size.Should().Be(5412993028); + releaseInfo.TvdbId.Should().Be(0); + releaseInfo.TvRageId.Should().Be(0); + releaseInfo.InfoHash.Should().Be("(removed)"); + releaseInfo.Seeders.Should().Be(3); + releaseInfo.Peers.Should().Be(3); + releaseInfo.Categories.Count().Should().Be(4); + } + [Test] public void should_use_pagesize_reported_by_caps() { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs index 665b2c75d..5f8eb652e 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs @@ -127,6 +127,12 @@ namespace NzbDrone.Core.Indexers.Newznab var cats = TryGetMultipleNewznabAttributes(item, "category"); var results = new List(); + // Try to find elements for some indexers that suck at following the rules. + if (results.Count == 0) + { + cats = item.Elements("category").Select(e => e.Value).ToList(); + } + foreach (var cat in cats) { var indexerCat = capabilities.Categories.MapTrackerCatToNewznab(cat); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs index 46fa0e92a..0e2dc6cb1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs @@ -165,9 +165,15 @@ namespace NzbDrone.Core.Indexers.Torznab protected override ICollection GetCategory(XElement item) { var capabilities = _capabilitiesProvider.GetCapabilities(_settings, _definition); - var cats = TryGetMultipleNewznabAttributes(item, "category"); + var cats = TryGetMultipleTorznabAttributes(item, "category"); var results = new List(); + // Try to find elements for some indexers that suck at following the rules. + if (results.Count == 0) + { + cats = item.Elements("category").Select(e => e.Value).ToList(); + } + foreach (var cat in cats) { var indexerCat = capabilities.Categories.MapTrackerCatToNewznab(cat); @@ -265,7 +271,7 @@ namespace NzbDrone.Core.Indexers.Torznab return defaultValue; } - protected List TryGetMultipleNewznabAttributes(XElement item, string key) + protected List TryGetMultipleTorznabAttributes(XElement item, string key) { var attrElements = item.Elements(ns + "attr").Where(e => e.Attribute("name").Value.Equals(key, StringComparison.OrdinalIgnoreCase)); var results = new List(); From c35f1212fbf9ae56d2ddccd7916bcf3487c8e3b5 Mon Sep 17 00:00:00 2001 From: Qstick Date: Tue, 20 Dec 2022 21:57:17 -0600 Subject: [PATCH 0703/2320] New: (Indexer) Torrent Bytes --- .../Indexers/Definitions/TorrentBytes.cs | 330 ++++++++++++++++++ 1 file changed, 330 insertions(+) create mode 100644 src/NzbDrone.Core/Indexers/Definitions/TorrentBytes.cs diff --git a/src/NzbDrone.Core/Indexers/Definitions/TorrentBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/TorrentBytes.cs new file mode 100644 index 000000000..3107041e1 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/TorrentBytes.cs @@ -0,0 +1,330 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Globalization; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using AngleSharp.Html.Parser; +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; + +namespace NzbDrone.Core.Indexers.Definitions +{ + public class TorrentBytes : TorrentIndexerBase + { + public override string Name => "Torrent Bytes"; + public override string[] IndexerUrls => new string[] { "https://www.torrentbytes.net/" }; + private string LoginUrl => Settings.BaseUrl + "takelogin.php"; + public override string Description => "A decade of TorrentBytes"; + public override string Language => "en-US"; + public override Encoding Encoding => Encoding.GetEncoding("iso-8859-1"); + public override DownloadProtocol Protocol => DownloadProtocol.Torrent; + public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + public override IndexerCapabilities Capabilities => SetCapabilities(); + + public TorrentBytes(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) + { + } + + public override IIndexerRequestGenerator GetRequestGenerator() + { + return new TorrentBytesRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; + } + + public override IParseIndexerResponse GetParser() + { + return new TorrentBytesParser(Settings, Capabilities.Categories); + } + + protected override async Task DoLogin() + { + var requestBuilder = new HttpRequestBuilder(LoginUrl) + { + LogResponseContent = true, + AllowAutoRedirect = true + }; + + requestBuilder.Method = HttpMethod.Post; + requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); + + var cookies = Cookies; + + Cookies = null; + var authLoginRequest = requestBuilder + .AddFormParameter("username", Settings.Username) + .AddFormParameter("password", Settings.Password) + .AddFormParameter("returnto", "/") + .AddFormParameter("login", "Log in!") + .SetHeader("Content-Type", "multipart/form-data") + .Build(); + + var headers = new NameValueCollection + { + { "Referer", LoginUrl } + }; + + authLoginRequest.Headers.Add(headers); + + var response = await ExecuteAuth(authLoginRequest); + + if (CheckIfLoginNeeded(response)) + { + var parser = new HtmlParser(); + var dom = parser.ParseDocument(response.Content); + var errorMessage = dom.QuerySelector("td.embedded").TextContent.Trim(); + + throw new IndexerAuthException(errorMessage); + } + + cookies = response.GetCookies(); + UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); + + _logger.Debug("TorrentBytes authentication succeeded."); + } + + protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) + { + if (!httpResponse.Content.Contains("my.php")) + { + return true; + } + + return false; + } + + private IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities + { + TvSearchParams = new List + { + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId + }, + MovieSearchParams = new List + { + MovieSearchParam.Q, MovieSearchParam.ImdbId + }, + MusicSearchParams = new List + { + MusicSearchParam.Q + } + }; + + caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.TVAnime, "Anime"); + caps.Categories.AddCategoryMapping(52, NewznabStandardCategory.PCMac, "Apple/All"); + caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.PC, "Apps/misc"); + caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.PC, "Apps/PC"); + caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.TVForeign, "Foreign Titles"); + caps.Categories.AddCategoryMapping(50, NewznabStandardCategory.Console, "Games/Consoles"); + caps.Categories.AddCategoryMapping(42, NewznabStandardCategory.PCGames, "Games/Pack"); + caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.PCGames, "Games/PC"); + caps.Categories.AddCategoryMapping(51, NewznabStandardCategory.PC, "Linux/All"); + caps.Categories.AddCategoryMapping(31, NewznabStandardCategory.OtherMisc, "Misc"); + caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.MoviesDVD, "Movies/DVD-R"); + caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.MoviesBluRay, "Movies/Full Blu-ray"); + caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.MoviesHD, "Movies/HD"); + caps.Categories.AddCategoryMapping(40, NewznabStandardCategory.Movies, "Movies/Pack"); + caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.MoviesSD, "Movies/SD"); + caps.Categories.AddCategoryMapping(49, NewznabStandardCategory.MoviesUHD, "Movies/UHD"); + caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.Audio, "Music/DVDR"); + caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.AudioLossless, "Music/Flac"); + caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.AudioMP3, "Music/MP3"); + caps.Categories.AddCategoryMapping(43, NewznabStandardCategory.Audio, "Music/Pack"); + caps.Categories.AddCategoryMapping(34, NewznabStandardCategory.AudioVideo, "Music/Videos"); + caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.MoviesBluRay, "NonScene/BRrip"); + caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.MoviesHD, "NonScene/x264"); + caps.Categories.AddCategoryMapping(44, NewznabStandardCategory.MoviesSD, "NonScene/Xvid"); + caps.Categories.AddCategoryMapping(37, NewznabStandardCategory.TVHD, "TV/BRrip"); + caps.Categories.AddCategoryMapping(38, NewznabStandardCategory.TVHD, "TV/HD"); + caps.Categories.AddCategoryMapping(41, NewznabStandardCategory.TV, "TV/Pack"); + caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.TVSD, "TV/SD"); + caps.Categories.AddCategoryMapping(32, NewznabStandardCategory.TVUHD, "TV/UHD"); + caps.Categories.AddCategoryMapping(39, NewznabStandardCategory.XXXx264, "XXX/HD"); + caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.XXXImageSet, "XXX/IMGSET"); + caps.Categories.AddCategoryMapping(21, NewznabStandardCategory.XXXPack, "XXX/Pack"); + caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.XXXXviD, "XXX/SD"); + caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.XXX, "XXX/Web"); + + return caps; + } + } + + public class TorrentBytesRequestGenerator : IIndexerRequestGenerator + { + public UserPassTorrentBaseSettings Settings { get; set; } + public IndexerCapabilities Capabilities { get; set; } + + public TorrentBytesRequestGenerator() + { + } + + private IEnumerable GetPagedRequests(string term, int[] categories, string imdbId = null) + { + var searchUrl = string.Format("{0}/browse.php", Settings.BaseUrl.TrimEnd('/')); + + var qc = new NameValueCollection + { + { "incldead", "1" } + }; + + if (imdbId.IsNotNullOrWhiteSpace()) + { + qc.Add("search", imdbId); + qc.Add("sc", "2"); // search in description + } + else + { + qc.Add("search", term); + qc.Add("sc", "1"); // search in title + } + + foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories)) + { + qc.Add("c" + cat, "1"); + } + + searchUrl = searchUrl + "?" + qc.GetQueryString(); + + var request = new IndexerRequest(searchUrl, HttpAccept.Html); + + yield return request; + } + + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories)); + + return pageableRequests; + } + + public Func> GetCookies { get; set; } + public Action, DateTime?> CookiesUpdater { get; set; } + } + + public class TorrentBytesParser : IParseIndexerResponse + { + private readonly UserPassTorrentBaseSettings _settings; + private readonly IndexerCapabilitiesCategories _categories; + + public TorrentBytesParser(UserPassTorrentBaseSettings settings, IndexerCapabilitiesCategories categories) + { + _settings = settings; + _categories = categories; + } + + public IList ParseResponse(IndexerResponse indexerResponse) + { + var torrentInfos = new List(); + + var parser = new HtmlParser(); + var doc = parser.ParseDocument(indexerResponse.Content); + var rows = doc.QuerySelectorAll("table > tbody:has(tr > td.colhead) > tr:not(:has(td.colhead))"); + foreach (var row in rows) + { + var release = new TorrentInfo(); + var link = row.QuerySelector("td:nth-of-type(2) a:nth-of-type(2)"); + release.Guid = _settings.BaseUrl + link.GetAttribute("href"); + release.InfoUrl = release.Guid; + release.Title = link.GetAttribute("title"); + + // There isn't a title attribute if the release name isn't truncated. + if (string.IsNullOrWhiteSpace(release.Title)) + { + release.Title = link.FirstChild.TextContent.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 + var qCat = row.QuerySelector("td:nth-of-type(1) a"); + if (qCat != null) + { + var cat = qCat.GetAttribute("href").Substring(15); + release.Categories = _categories.MapTrackerCatToNewznab(cat); + } + + var qLink = row.QuerySelector("td:nth-of-type(2) a"); + release.DownloadUrl = _settings.BaseUrl + qLink.GetAttribute("href"); + + var added = row.QuerySelector("td:nth-of-type(5)").TextContent.Trim(); + release.PublishDate = DateTime.ParseExact(added, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture); + + var sizeStr = row.QuerySelector("td:nth-of-type(7)").TextContent.Trim(); + release.Size = ParseUtil.GetBytes(sizeStr); + release.Seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(9)").TextContent.Trim()); + release.Peers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(10)").TextContent.Trim()) + + release.Seeders; + + var files = row.QuerySelector("td:nth-child(3)").TextContent; + release.Files = ParseUtil.CoerceInt(files); + + var grabs = row.QuerySelector("td:nth-child(8)").TextContent; + if (grabs != "----") + { + release.Grabs = ParseUtil.CoerceInt(grabs); + } + + release.DownloadVolumeFactor = row.QuerySelector("font[color=\"green\"]:contains(\"F\"):contains(\"L\")") != null ? 0 : 1; + release.UploadVolumeFactor = 1; + + torrentInfos.Add(release); + } + + return torrentInfos.ToArray(); + } + + public Action, DateTime?> CookiesUpdater { get; set; } + } +} From 05a7465a076fe610025d250e6462b148fd803906 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Wed, 21 Dec 2022 08:04:13 -0600 Subject: [PATCH 0704/2320] Fixed: (MTV) Torznab Api Path #1235 --- src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs index d54716855..842e4686d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs @@ -89,7 +89,7 @@ namespace NzbDrone.Core.Indexers.Torznab get { yield return GetDefinition("AnimeTosho", "", GetSettings("https://feed.animetosho.org")); - yield return GetDefinition("MoreThanTV", "Private torrent tracker for TV / MOVIES", GetSettings("https://www.morethantv.me")); + yield return GetDefinition("MoreThanTV", "Private torrent tracker for TV / MOVIES", GetSettings("https://www.morethantv.me", apiPath: @"/api/torznab")); yield return GetDefinition("Generic Torznab", "A Newznab-like api for torrents.", GetSettings("")); } } From a5a4f62f2577afd540b5616d2ace7432698cc5cb Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 20 Dec 2022 11:09:56 +0000 Subject: [PATCH 0705/2320] Translated using Weblate (Bengali) Currently translated at 0.8% (4 of 468 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (468 of 468 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (468 of 468 strings) Co-authored-by: Csaba Co-authored-by: Oskari Lavinto Co-authored-by: saambd Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/bn/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/ Translation: Servarr/Prowlarr --- src/NzbDrone.Core/Localization/Core/bn.json | 7 ++++++- src/NzbDrone.Core/Localization/Core/fi.json | 6 +++++- src/NzbDrone.Core/Localization/Core/hu.json | 6 +++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/bn.json b/src/NzbDrone.Core/Localization/Core/bn.json index 0967ef424..9e5c642f5 100644 --- a/src/NzbDrone.Core/Localization/Core/bn.json +++ b/src/NzbDrone.Core/Localization/Core/bn.json @@ -1 +1,6 @@ -{} +{ + "About": "সম্পর্কিত", + "Actions": "ক্রিয়াকাণ্ড", + "Add": "যোগ করুন", + "AcceptConfirmationModal": "নিশ্চিতকরণ মডেল গ্রহণ করুন" +} diff --git a/src/NzbDrone.Core/Localization/Core/fi.json b/src/NzbDrone.Core/Localization/Core/fi.json index eb0ee3a7b..a7c14c6fe 100644 --- a/src/NzbDrone.Core/Localization/Core/fi.json +++ b/src/NzbDrone.Core/Localization/Core/fi.json @@ -462,5 +462,9 @@ "Queued": "Jonossa", "Started": "Alkoi", "ApplicationLongTermStatusCheckAllClientMessage": "Sovellukset eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi.", - "ApplicationLongTermStatusCheckSingleClientMessage": "Sovellukset eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi: {0}" + "ApplicationLongTermStatusCheckSingleClientMessage": "Sovellukset eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi: {0}", + "AreYouSureYouWantToDeleteCategory": "Haluatko varmasti poistaa kartoitetun kategorian?", + "DeleteClientCategory": "Poista lataustyökalukategoria", + "DownloadClientCategory": "Lataustyökalukategoria", + "MappedCategories": "Kartoitetut kategoriat" } diff --git a/src/NzbDrone.Core/Localization/Core/hu.json b/src/NzbDrone.Core/Localization/Core/hu.json index 07d68aabb..f80bcf04c 100644 --- a/src/NzbDrone.Core/Localization/Core/hu.json +++ b/src/NzbDrone.Core/Localization/Core/hu.json @@ -462,5 +462,9 @@ "Started": "Elkezdődött", "NextExecution": "Következő végrehajtás", "ApplicationLongTermStatusCheckSingleClientMessage": "Az alkamazások elérhetetlenek több mint 6 órája az alábbi hiba miatt: {0}", - "ApplicationLongTermStatusCheckAllClientMessage": "Az összes alkalmazás elérhetetlen több mint 6 órája meghibásodás miatt" + "ApplicationLongTermStatusCheckAllClientMessage": "Az összes alkalmazás elérhetetlen több mint 6 órája meghibásodás miatt", + "AreYouSureYouWantToDeleteCategory": "Biztosan törölni szeretnéd a leképezett kategóriát?", + "DeleteClientCategory": "Letöltési kliens kategória törlése", + "MappedCategories": "Térképezett kategóriák", + "DownloadClientCategory": "Letöltési kliens kategória" } From 6636cbc4aea7204613f915fb51645f2a03c1ce04 Mon Sep 17 00:00:00 2001 From: Qstick Date: Thu, 22 Dec 2022 08:47:45 -0600 Subject: [PATCH 0706/2320] Fixed: (AnimeTosho) Mapping of Subcat as Parent --- .../Indexers/Torznab/torznab_animetosho_caps.xml | 15 +++++++++++++++ .../NewznabCapabilitiesProviderFixture.cs | 13 +++++++++++++ .../Newznab/NewznabCapabilitiesProvider.cs | 9 ++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/NzbDrone.Core.Test/Files/Indexers/Torznab/torznab_animetosho_caps.xml diff --git a/src/NzbDrone.Core.Test/Files/Indexers/Torznab/torznab_animetosho_caps.xml b/src/NzbDrone.Core.Test/Files/Indexers/Torznab/torznab_animetosho_caps.xml new file mode 100644 index 000000000..e8bbf2930 --- /dev/null +++ b/src/NzbDrone.Core.Test/Files/Indexers/Torznab/torznab_animetosho_caps.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs index 085188d5a..e643263f7 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/NewznabTests/NewznabCapabilitiesProviderFixture.cs @@ -84,6 +84,19 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests bookCats.Should().Contain("8000"); } + [Test] + public void should_find_sub_categories_as_main_categories() + { + GivenCapsResponse(ReadAllText("Files/Indexers/Torznab/torznab_animetosho_caps.xml")); + + var caps = Subject.GetCapabilities(_settings, _definition); + + var bookCats = caps.Categories.MapTrackerCatToNewznab("5070"); + + bookCats.Count.Should().Be(2); + bookCats.First().Id.Should().Be(5070); + } + [Test] public void should_map_by_name_when_available() { diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs index 1d3952bf2..acdecca56 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs @@ -223,9 +223,16 @@ namespace NzbDrone.Core.Indexers.Newznab foreach (var xmlCategory in xmlCategories.Elements("category")) { var parentName = xmlCategory.Attribute("name").Value; + var parentNameLower = parentName?.ToLowerInvariant(); var parentId = int.Parse(xmlCategory.Attribute("id").Value); - var mappedCat = NewznabStandardCategory.ParentCats.FirstOrDefault(x => parentName.ToLower().Contains(x.Name.ToLower())); + var mappedCat = NewznabStandardCategory.ParentCats.FirstOrDefault(x => parentNameLower.Contains(x.Name.ToLower())); + + if (mappedCat == null) + { + // Try to find name and Id in AllCats for sub cats that are mapped as parents + mappedCat = NewznabStandardCategory.AllCats.FirstOrDefault(x => x.Id == parentId && x.Name.ToLower().Contains(parentNameLower)); + } if (mappedCat == null) { From 7303cdf555de46e2cb31286b027dffb0a922048e Mon Sep 17 00:00:00 2001 From: Qstick Date: Thu, 22 Dec 2022 10:05:52 -0600 Subject: [PATCH 0707/2320] Fixed: Incorrect logic for newznab category parsing --- .../Indexers/Definitions/Newznab/NewznabRssParser.cs | 2 +- .../Indexers/Definitions/Torznab/TorznabRssParser.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs index 5f8eb652e..269b548ab 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs @@ -128,7 +128,7 @@ namespace NzbDrone.Core.Indexers.Newznab var results = new List(); // Try to find elements for some indexers that suck at following the rules. - if (results.Count == 0) + if (cats.Count == 0) { cats = item.Elements("category").Select(e => e.Value).ToList(); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs index 0e2dc6cb1..6097acb85 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs @@ -169,7 +169,7 @@ namespace NzbDrone.Core.Indexers.Torznab var results = new List(); // Try to find elements for some indexers that suck at following the rules. - if (results.Count == 0) + if (cats.Count == 0) { cats = item.Elements("category").Select(e => e.Value).ToList(); } From 2e851b058886764033a4caae913d8764d5392bcb Mon Sep 17 00:00:00 2001 From: Qstick Date: Thu, 22 Dec 2022 13:37:09 -0600 Subject: [PATCH 0708/2320] New: Mobile friendly manual search Fixes #490 --- .../src/Search/Mobile/SearchIndexOverview.css | 47 ++++ .../src/Search/Mobile/SearchIndexOverview.js | 189 ++++++++++++++++ .../Search/Mobile/SearchIndexOverviews.css | 11 + .../src/Search/Mobile/SearchIndexOverviews.js | 211 ++++++++++++++++++ .../Mobile/SearchIndexOverviewsConnector.js | 32 +++ frontend/src/Search/SearchIndex.js | 41 +--- .../Search/Table/SearchIndexItemConnector.js | 12 +- package.json | 1 + yarn.lock | 9 +- 9 files changed, 513 insertions(+), 40 deletions(-) create mode 100644 frontend/src/Search/Mobile/SearchIndexOverview.css create mode 100644 frontend/src/Search/Mobile/SearchIndexOverview.js create mode 100644 frontend/src/Search/Mobile/SearchIndexOverviews.css create mode 100644 frontend/src/Search/Mobile/SearchIndexOverviews.js create mode 100644 frontend/src/Search/Mobile/SearchIndexOverviewsConnector.js diff --git a/frontend/src/Search/Mobile/SearchIndexOverview.css b/frontend/src/Search/Mobile/SearchIndexOverview.css new file mode 100644 index 000000000..9d28a55c2 --- /dev/null +++ b/frontend/src/Search/Mobile/SearchIndexOverview.css @@ -0,0 +1,47 @@ +$hoverScale: 1.05; + +.content { + display: flex; + flex-grow: 0; + margin-left: 5px; +} + +.container { + border-radius: 4px; + background-color: var(--cardBackgroundColor); +} + +.info { + display: flex; + flex-direction: column; + flex-grow: 1; + overflow: hidden; +} + +.titleRow { + display: flex; + justify-content: space-between; + flex: 0 0 auto; + margin-bottom: 10px; + height: 38px; +} + +.indexerRow { + color: var(--disabledColor); +} + +.infoRow { + margin-bottom: 5px; +} + +.title { + width: 85%; + font-weight: 500; + font-size: 12px; +} + +.actions { + position: absolute; + right: 0; + white-space: nowrap; +} diff --git a/frontend/src/Search/Mobile/SearchIndexOverview.js b/frontend/src/Search/Mobile/SearchIndexOverview.js new file mode 100644 index 000000000..9de331e78 --- /dev/null +++ b/frontend/src/Search/Mobile/SearchIndexOverview.js @@ -0,0 +1,189 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import TextTruncate from 'react-text-truncate'; +import Label from 'Components/Label'; +import IconButton from 'Components/Link/IconButton'; +import SpinnerIconButton from 'Components/Link/SpinnerIconButton'; +import { icons, kinds } from 'Helpers/Props'; +import CategoryLabel from 'Search/Table/CategoryLabel'; +import Peers from 'Search/Table/Peers'; +import ProtocolLabel from 'Search/Table/ProtocolLabel'; +import dimensions from 'Styles/Variables/dimensions'; +import formatAge from 'Utilities/Number/formatAge'; +import formatBytes from 'Utilities/Number/formatBytes'; +import translate from 'Utilities/String/translate'; +import styles from './SearchIndexOverview.css'; + +const columnPadding = parseInt(dimensions.movieIndexColumnPadding); +const columnPaddingSmallScreen = parseInt(dimensions.movieIndexColumnPaddingSmallScreen); + +function getContentHeight(rowHeight, isSmallScreen) { + const padding = isSmallScreen ? columnPaddingSmallScreen : columnPadding; + + return rowHeight - padding; +} + +function getDownloadIcon(isGrabbing, isGrabbed, grabError) { + if (isGrabbing) { + return icons.SPINNER; + } else if (isGrabbed) { + return icons.DOWNLOADING; + } else if (grabError) { + return icons.DOWNLOADING; + } + + return icons.DOWNLOAD; +} + +function getDownloadTooltip(isGrabbing, isGrabbed, grabError) { + if (isGrabbing) { + return ''; + } else if (isGrabbed) { + return translate('AddedToDownloadClient'); + } else if (grabError) { + return grabError; + } + + return translate('AddToDownloadClient'); +} + +class SearchIndexOverview extends Component { + + // + // Listeners + + onEditSeriesPress = () => { + this.setState({ isEditSeriesModalOpen: true }); + }; + + onEditSeriesModalClose = () => { + this.setState({ isEditSeriesModalOpen: false }); + }; + + // + // Render + + render() { + const { + title, + protocol, + downloadUrl, + categories, + seeders, + leechers, + size, + age, + ageHours, + ageMinutes, + indexer, + rowHeight, + isSmallScreen, + isGrabbed, + isGrabbing, + grabError + } = this.props; + + const contentHeight = getContentHeight(rowHeight, isSmallScreen); + + return ( +
+
+
+
+
+ +
+ +
+ + + +
+
+
+ {indexer} +
+
+ + + { + protocol === 'torrent' && + + } + + + + + + +
+
+
+
+ ); + } +} + +SearchIndexOverview.propTypes = { + guid: PropTypes.string.isRequired, + categories: PropTypes.arrayOf(PropTypes.object).isRequired, + protocol: PropTypes.string.isRequired, + age: PropTypes.number.isRequired, + ageHours: PropTypes.number.isRequired, + ageMinutes: PropTypes.number.isRequired, + publishDate: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + infoUrl: PropTypes.string.isRequired, + downloadUrl: PropTypes.string.isRequired, + indexerId: PropTypes.number.isRequired, + indexer: PropTypes.string.isRequired, + size: PropTypes.number.isRequired, + files: PropTypes.number, + grabs: PropTypes.number, + seeders: PropTypes.number, + leechers: PropTypes.number, + indexerFlags: PropTypes.arrayOf(PropTypes.string).isRequired, + rowHeight: PropTypes.number.isRequired, + showRelativeDates: PropTypes.bool.isRequired, + shortDateFormat: PropTypes.string.isRequired, + longDateFormat: PropTypes.string.isRequired, + timeFormat: PropTypes.string.isRequired, + isSmallScreen: PropTypes.bool.isRequired, + onGrabPress: PropTypes.func.isRequired, + isGrabbing: PropTypes.bool.isRequired, + isGrabbed: PropTypes.bool.isRequired, + grabError: PropTypes.string +}; + +SearchIndexOverview.defaultProps = { + isGrabbing: false, + isGrabbed: false +}; + +export default SearchIndexOverview; diff --git a/frontend/src/Search/Mobile/SearchIndexOverviews.css b/frontend/src/Search/Mobile/SearchIndexOverviews.css new file mode 100644 index 000000000..f393dcbb0 --- /dev/null +++ b/frontend/src/Search/Mobile/SearchIndexOverviews.css @@ -0,0 +1,11 @@ +.grid { + flex: 1 0 auto; +} + +.container { + &:hover { + .content { + background-color: var(--tableRowHoverBackgroundColor); + } + } +} diff --git a/frontend/src/Search/Mobile/SearchIndexOverviews.js b/frontend/src/Search/Mobile/SearchIndexOverviews.js new file mode 100644 index 000000000..c8e5d1007 --- /dev/null +++ b/frontend/src/Search/Mobile/SearchIndexOverviews.js @@ -0,0 +1,211 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { Grid, WindowScroller } from 'react-virtualized'; +import Measure from 'Components/Measure'; +import SearchIndexItemConnector from 'Search/Table/SearchIndexItemConnector'; +import getIndexOfFirstCharacter from 'Utilities/Array/getIndexOfFirstCharacter'; +import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder'; +import SearchIndexOverview from './SearchIndexOverview'; +import styles from './SearchIndexOverviews.css'; + +class SearchIndexOverviews extends Component { + + // + // Lifecycle + + constructor(props, context) { + super(props, context); + + this.state = { + width: 0, + columnCount: 1, + rowHeight: 100, + scrollRestored: false + }; + + this._grid = null; + } + + componentDidUpdate(prevProps, prevState) { + const { + items, + sortKey, + jumpToCharacter, + scrollTop, + isSmallScreen + } = this.props; + + const { + width, + rowHeight, + scrollRestored + } = this.state; + + if (prevProps.sortKey !== sortKey) { + this.calculateGrid(this.state.width, isSmallScreen); + } + + if ( + this._grid && + (prevState.width !== width || + prevState.rowHeight !== rowHeight || + hasDifferentItemsOrOrder(prevProps.items, items) + ) + ) { + // recomputeGridSize also forces Grid to discard its cache of rendered cells + this._grid.recomputeGridSize(); + } + + if (this._grid && scrollTop !== 0 && !scrollRestored) { + this.setState({ scrollRestored: true }); + this._grid.scrollToPosition({ scrollTop }); + } + + if (jumpToCharacter != null && jumpToCharacter !== prevProps.jumpToCharacter) { + const index = getIndexOfFirstCharacter(items, jumpToCharacter); + + if (this._grid && index != null) { + + this._grid.scrollToCell({ + rowIndex: index, + columnIndex: 0 + }); + } + } + } + + // + // Control + + setGridRef = (ref) => { + this._grid = ref; + }; + + calculateGrid = (width = this.state.width, isSmallScreen) => { + const rowHeight = 100; + + this.setState({ + width, + rowHeight + }); + }; + + cellRenderer = ({ key, rowIndex, style }) => { + const { + items, + sortKey, + showRelativeDates, + shortDateFormat, + longDateFormat, + timeFormat, + isSmallScreen, + onGrabPress + } = this.props; + + const { + rowHeight + } = this.state; + + const release = items[rowIndex]; + + return ( +
+ +
+ ); + }; + + // + // Listeners + + onMeasure = ({ width }) => { + this.calculateGrid(width, this.props.isSmallScreen); + }; + + // + // Render + + render() { + const { + items + } = this.props; + + const { + width, + rowHeight + } = this.state; + + return ( + + + {({ height, registerChild, onChildScroll, scrollTop }) => { + if (!height) { + return
; + } + + return ( +
+ +
+ ); + } + } + + + ); + } +} + +SearchIndexOverviews.propTypes = { + items: PropTypes.arrayOf(PropTypes.object).isRequired, + sortKey: PropTypes.string, + scrollTop: PropTypes.number.isRequired, + jumpToCharacter: PropTypes.string, + scroller: PropTypes.instanceOf(Element).isRequired, + showRelativeDates: PropTypes.bool.isRequired, + shortDateFormat: PropTypes.string.isRequired, + longDateFormat: PropTypes.string.isRequired, + isSmallScreen: PropTypes.bool.isRequired, + timeFormat: PropTypes.string.isRequired, + onGrabPress: PropTypes.func.isRequired +}; + +export default SearchIndexOverviews; diff --git a/frontend/src/Search/Mobile/SearchIndexOverviewsConnector.js b/frontend/src/Search/Mobile/SearchIndexOverviewsConnector.js new file mode 100644 index 000000000..39f376e55 --- /dev/null +++ b/frontend/src/Search/Mobile/SearchIndexOverviewsConnector.js @@ -0,0 +1,32 @@ +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import { grabRelease } from 'Store/Actions/releaseActions'; +import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector'; +import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector'; +import SearchIndexOverviews from './SearchIndexOverviews'; + +function createMapStateToProps() { + return createSelector( + createUISettingsSelector(), + createDimensionsSelector(), + (uiSettings, dimensions) => { + return { + showRelativeDates: uiSettings.showRelativeDates, + shortDateFormat: uiSettings.shortDateFormat, + longDateFormat: uiSettings.longDateFormat, + timeFormat: uiSettings.timeFormat, + isSmallScreen: dimensions.isSmallScreen + }; + } + ); +} + +function createMapDispatchToProps(dispatch, props) { + return { + onGrabPress(payload) { + dispatch(grabRelease(payload)); + } + }; +} + +export default connect(createMapStateToProps, createMapDispatchToProps)(SearchIndexOverviews); diff --git a/frontend/src/Search/SearchIndex.js b/frontend/src/Search/SearchIndex.js index 5a7d9d484..884e279d2 100644 --- a/frontend/src/Search/SearchIndex.js +++ b/frontend/src/Search/SearchIndex.js @@ -11,8 +11,6 @@ import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection'; import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator'; import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper'; import { align, icons, sortDirections } from 'Helpers/Props'; -import AddIndexerModal from 'Indexer/Add/AddIndexerModal'; -import EditIndexerModalConnector from 'Indexer/Edit/EditIndexerModalConnector'; import NoIndexer from 'Indexer/NoIndexer'; import * as keyCodes from 'Utilities/Constants/keyCodes'; import getErrorMessage from 'Utilities/Object/getErrorMessage'; @@ -23,12 +21,17 @@ import selectAll from 'Utilities/Table/selectAll'; import toggleSelected from 'Utilities/Table/toggleSelected'; import SearchIndexFilterMenu from './Menus/SearchIndexFilterMenu'; import SearchIndexSortMenu from './Menus/SearchIndexSortMenu'; +import SearchIndexOverviewsConnector from './Mobile/SearchIndexOverviewsConnector'; import NoSearchResults from './NoSearchResults'; import SearchFooterConnector from './SearchFooterConnector'; import SearchIndexTableConnector from './Table/SearchIndexTableConnector'; import styles from './SearchIndex.css'; -function getViewComponent() { +function getViewComponent(isSmallScreen) { + if (isSmallScreen) { + return SearchIndexOverviewsConnector; + } + return SearchIndexTableConnector; } @@ -44,8 +47,6 @@ class SearchIndex extends Component { scroller: null, jumpBarItems: { order: [] }, jumpToCharacter: null, - isAddIndexerModalOpen: false, - isEditIndexerModalOpen: false, searchType: null, lastToggled: null, allSelected: false, @@ -177,21 +178,6 @@ class SearchIndex extends Component { // // Listeners - onAddIndexerPress = () => { - this.setState({ isAddIndexerModalOpen: true }); - }; - - onAddIndexerModalClose = ({ indexerSelected = false } = {}) => { - this.setState({ - isAddIndexerModalOpen: false, - isEditIndexerModalOpen: indexerSelected - }); - }; - - onEditIndexerModalClose = () => { - this.setState({ isEditIndexerModalOpen: false }); - }; - onJumpBarItemPress = (jumpToCharacter) => { this.setState({ jumpToCharacter }); }; @@ -253,6 +239,7 @@ class SearchIndex extends Component { onScroll, onSortSelect, onFilterSelect, + isSmallScreen, hasIndexers, ...otherProps } = this.props; @@ -260,8 +247,6 @@ class SearchIndex extends Component { const { scroller, jumpBarItems, - isAddIndexerModalOpen, - isEditIndexerModalOpen, jumpToCharacter, selectedState, allSelected, @@ -270,7 +255,7 @@ class SearchIndex extends Component { const selectedIndexerIds = this.getSelectedIds(); - const ViewComponent = getViewComponent(); + const ViewComponent = getViewComponent(isSmallScreen); const isLoaded = !!(!error && isPopulated && items.length && scroller); const hasNoIndexer = !totalItems; @@ -384,16 +369,6 @@ class SearchIndex extends Component { onSearchPress={this.onSearchPress} onBulkGrabPress={this.onBulkGrabPress} /> - - - - ); } diff --git a/frontend/src/Search/Table/SearchIndexItemConnector.js b/frontend/src/Search/Table/SearchIndexItemConnector.js index 04db22740..da1133b6d 100644 --- a/frontend/src/Search/Table/SearchIndexItemConnector.js +++ b/frontend/src/Search/Table/SearchIndexItemConnector.js @@ -18,20 +18,20 @@ function createMapStateToProps() { return createSelector( createReleaseSelector(), ( - movie + release ) => { - // If a movie is deleted this selector may fire before the parent - // selecors, which will result in an undefined movie, if that happens + // If a release is deleted this selector may fire before the parent + // selecors, which will result in an undefined release, if that happens // we want to return early here and again in the render function to avoid - // trying to show a movie that has no information available. + // trying to show a release that has no information available. - if (!movie) { + if (!release) { return {}; } return { - ...movie + ...release }; } ); diff --git a/package.json b/package.json index 3ed9997aa..57c4e0e24 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ "react-redux": "8.0.5", "react-router": "5.2.0", "react-router-dom": "5.2.0", + "react-text-truncate": "0.19.0", "react-virtualized": "9.21.1", "redux": "4.2.0", "redux-actions": "2.6.5", diff --git a/yarn.lock b/yarn.lock index 5162372bf..573ee0d51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4714,7 +4714,7 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -prop-types@15.8.1, prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@15.8.1, prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -4996,6 +4996,13 @@ react-side-effect@^1.0.2: dependencies: shallowequal "^1.0.1" +react-text-truncate@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/react-text-truncate/-/react-text-truncate-0.19.0.tgz#60bc5ecf29a03ebc256f31f90a2d8402176aac91" + integrity sha512-QxHpZABfGG0Z3WEYbRTZ+rXdZn50Zvp+sWZXgVAd7FCKAMzv/kcwctTpNmWgXDTpAoHhMjOVwmgRtX3x5yeF4w== + dependencies: + prop-types "^15.5.7" + react-themeable@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/react-themeable/-/react-themeable-1.1.0.tgz#7d4466dd9b2b5fa75058727825e9f152ba379a0e" From 94a797fc1e54e479cb222119e03f19869f8e32cc Mon Sep 17 00:00:00 2001 From: Qstick Date: Thu, 22 Dec 2022 14:32:03 -0600 Subject: [PATCH 0709/2320] New: (Nebulace) TVMaze Search Support Fixes #1252 --- .../Indexers/Definitions/Nebulance.cs | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs index fa43a5fcd..c5a598db5 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Text; +using System.Text.RegularExpressions; using Newtonsoft.Json; using NLog; using NzbDrone.Common.Extensions; @@ -49,7 +50,7 @@ namespace NzbDrone.Core.Indexers.Definitions { TvSearchParams = new List { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvMazeId } }; @@ -107,16 +108,25 @@ namespace NzbDrone.Core.Indexers.Definitions if (searchCriteria.SanitizedTvSearchString.IsNotNullOrWhiteSpace()) { - queryParams.Name = "%" + searchCriteria.SanitizedTvSearchString + "%"; + queryParams.Name = "%" + Regex.Replace(searchCriteria.SanitizedTvSearchString, @"[ -._]", "%").Trim() + "%"; } - if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace() && int.TryParse(searchCriteria.ImdbId, out var intImdb)) + if (searchCriteria.TvMazeId.HasValue) + { + queryParams.Tvmaze = searchCriteria.TvMazeId.Value; + + if (searchCriteria.EpisodeSearchString.IsNotNullOrWhiteSpace()) + { + queryParams.Name = "%" + Regex.Replace(searchCriteria.EpisodeSearchString, @"[ -._]", "%").Trim() + "%"; + } + } + else if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace() && int.TryParse(searchCriteria.ImdbId, out var intImdb)) { queryParams.Imdb = intImdb; if (searchCriteria.EpisodeSearchString.IsNotNullOrWhiteSpace()) { - queryParams.Name = "%" + searchCriteria.EpisodeSearchString + "%"; + queryParams.Name = "%" + Regex.Replace(searchCriteria.EpisodeSearchString, @"[ -._]", "%").Trim() + "%"; } } @@ -143,7 +153,7 @@ namespace NzbDrone.Core.Indexers.Definitions if (searchCriteria.SanitizedSearchTerm.IsNotNullOrWhiteSpace()) { - queryParams.Name = "%" + searchCriteria.SanitizedSearchTerm + "%"; + queryParams.Name = "%" + Regex.Replace(searchCriteria.SanitizedSearchTerm, @"[ -._]", "%").Trim() + "%"; } pageableRequests.Add(GetPagedRequests(queryParams, searchCriteria.Limit, searchCriteria.Offset)); From 2d33560d890fa4fdae58bf14cee6dcda04ecf9a7 Mon Sep 17 00:00:00 2001 From: Qstick Date: Thu, 22 Dec 2022 15:29:26 -0600 Subject: [PATCH 0710/2320] Theme tweaks --- frontend/src/Components/InfoLabel.css | 2 +- frontend/src/Components/Label.css | 2 +- frontend/src/Components/Page/Header/PageHeaderActionsMenu.css | 2 +- frontend/src/Search/Mobile/SearchIndexOverview.css | 2 +- frontend/src/Search/Table/SearchIndexHeader.css | 2 +- frontend/src/Search/Table/SearchIndexRow.css | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/src/Components/InfoLabel.css b/frontend/src/Components/InfoLabel.css index 6a2f5601b..8d0655b92 100644 --- a/frontend/src/Components/InfoLabel.css +++ b/frontend/src/Components/InfoLabel.css @@ -36,5 +36,5 @@ /** Outline **/ .outline { - background-color: var(--white); + background-color: var(--cardBackgroundColor); } diff --git a/frontend/src/Components/Label.css b/frontend/src/Components/Label.css index 84b12552b..c421e980f 100644 --- a/frontend/src/Components/Label.css +++ b/frontend/src/Components/Label.css @@ -108,5 +108,5 @@ /** Outline **/ .outline { - background-color: var(--white); + background-color: var(--cardBackgroundColor); } diff --git a/frontend/src/Components/Page/Header/PageHeaderActionsMenu.css b/frontend/src/Components/Page/Header/PageHeaderActionsMenu.css index 26a5d37da..7375d53b7 100644 --- a/frontend/src/Components/Page/Header/PageHeaderActionsMenu.css +++ b/frontend/src/Components/Page/Header/PageHeaderActionsMenu.css @@ -5,7 +5,7 @@ text-align: center; &:hover { - color: var(--toobarButtonHoverColor); + color: #515253; } } diff --git a/frontend/src/Search/Mobile/SearchIndexOverview.css b/frontend/src/Search/Mobile/SearchIndexOverview.css index 9d28a55c2..c2d9b7abd 100644 --- a/frontend/src/Search/Mobile/SearchIndexOverview.css +++ b/frontend/src/Search/Mobile/SearchIndexOverview.css @@ -37,7 +37,7 @@ $hoverScale: 1.05; .title { width: 85%; font-weight: 500; - font-size: 12px; + font-size: 14px; } .actions { diff --git a/frontend/src/Search/Table/SearchIndexHeader.css b/frontend/src/Search/Table/SearchIndexHeader.css index 669c93125..e638dedd5 100644 --- a/frontend/src/Search/Table/SearchIndexHeader.css +++ b/frontend/src/Search/Table/SearchIndexHeader.css @@ -14,7 +14,7 @@ .category { composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css'; - flex: 0 0 110px; + flex: 0 0 130px; } .age, diff --git a/frontend/src/Search/Table/SearchIndexRow.css b/frontend/src/Search/Table/SearchIndexRow.css index 8f676213c..4ad142f4d 100644 --- a/frontend/src/Search/Table/SearchIndexRow.css +++ b/frontend/src/Search/Table/SearchIndexRow.css @@ -21,7 +21,7 @@ .category { composes: cell; - flex: 0 0 110px; + flex: 0 0 130px; } .age, From 387fb0bd15d8e00bed9e0b9c122c0fa4e8388fec Mon Sep 17 00:00:00 2001 From: Qstick Date: Thu, 22 Dec 2022 18:52:38 -0600 Subject: [PATCH 0711/2320] Revert release analytics --- .../IndexerSearch/ReleaseAnalyticsService.cs | 85 ------------------- 1 file changed, 85 deletions(-) delete mode 100644 src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs deleted file mode 100644 index b058dc461..000000000 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseAnalyticsService.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using NLog; -using NzbDrone.Common.Cloud; -using NzbDrone.Common.Extensions; -using NzbDrone.Common.Http; -using NzbDrone.Common.Serializer; -using NzbDrone.Common.TPL; -using NzbDrone.Core.Analytics; -using NzbDrone.Core.Indexers.Events; -using NzbDrone.Core.Messaging.Events; -using NzbDrone.Core.Parser.Model; - -namespace NzbDrone.Core.IndexerSearch -{ - public class ReleaseAnalyticsService : IHandleAsync - { - private readonly IHttpClient _httpClient; - private readonly IHttpRequestBuilderFactory _requestBuilder; - private readonly IAnalyticsService _analyticsService; - private readonly Debouncer _debouncer; - private readonly Logger _logger; - private readonly List _pendingUpdates; - - public ReleaseAnalyticsService(IHttpClient httpClient, IProwlarrCloudRequestBuilder requestBuilder, IAnalyticsService analyticsService, Logger logger) - { - _debouncer = new Debouncer(SendReleases, TimeSpan.FromMinutes(10)); - _analyticsService = analyticsService; - _requestBuilder = requestBuilder.Releases; - _httpClient = httpClient; - _logger = logger; - - _pendingUpdates = new List(); - } - - public void HandleAsync(IndexerQueryEvent message) - { - if (_analyticsService.IsEnabled && message.QueryResult?.Releases != null) - { - lock (_pendingUpdates) - { - _pendingUpdates.AddRange(message.QueryResult.Releases.Where(r => r.Title.IsNotNullOrWhiteSpace())); - } - - _debouncer.Execute(); - } - } - - public void SendReleases() - { - lock (_pendingUpdates) - { - var pendingUpdates = _pendingUpdates.ToArray(); - _pendingUpdates.Clear(); - - var request = _requestBuilder.Create().Resource("release/push").Build(); - request.Method = HttpMethod.Post; - request.Headers.ContentType = "application/json"; - request.SuppressHttpError = true; - request.LogHttpError = false; - - var body = pendingUpdates.DistinctBy(r => r.Title).Select(x => new - { - Title = x.Title, - Categories = x.Categories?.Where(c => c.Id < 10000).Select(c => c.Id) ?? new List(), - Protocol = x.DownloadProtocol.ToString(), - Size = x.Size, - PublishDate = x.PublishDate - }); - - try - { - request.SetContent(body.ToJson()); - _httpClient.Post(request); - } - catch - { - _logger.Trace("Analytics push failed"); - } - } - } - } -} From 29e7cc06a13d9e176b81be27dc70fb809f34d5f9 Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 24 Dec 2022 15:16:00 -0600 Subject: [PATCH 0712/2320] Bump MonoTorrent to 2.0.7 Co-Authored-By: Winter <78392041+winterqt@users.noreply.github.com> --- src/NzbDrone.Core/Prowlarr.Core.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index 7dc2b8187..cdeb99ef8 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -21,7 +21,7 @@ - + From d9098b612e438786758e01d20ac17ba6b13e3b4c Mon Sep 17 00:00:00 2001 From: Bogdan Date: Tue, 27 Dec 2022 01:48:29 +0200 Subject: [PATCH 0713/2320] Fixed: (Nebulance) Changed MinimumSeedTime according to their H&R rules --- src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs index c5a598db5..3549a9e10 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs @@ -49,9 +49,9 @@ namespace NzbDrone.Core.Indexers.Definitions var caps = new IndexerCapabilities { TvSearchParams = new List - { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvMazeId - } + { + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvMazeId + } }; caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.TV); @@ -213,7 +213,7 @@ namespace NzbDrone.Core.Indexers.Definitions Seeders = ParseUtil.CoerceInt(row.Seed), Peers = ParseUtil.CoerceInt(row.Seed) + ParseUtil.CoerceInt(row.Leech), MinimumRatio = 0, // ratioless - MinimumSeedTime = 86400, // 24 hours + MinimumSeedTime = row.Category.ToLower() == "season" ? 432000 : 86400, // 120 hours for seasons and 24 hours for episodes DownloadVolumeFactor = 0, // ratioless tracker UploadVolumeFactor = 1 }; @@ -272,6 +272,8 @@ namespace NzbDrone.Core.Indexers.Definitions [JsonProperty(PropertyName = "rls_name")] public string ReleaseTitle { get; set; } public string Title { get; set; } + [JsonProperty(PropertyName = "cat")] + public string Category { get; set; } public string Size { get; set; } public string Seed { get; set; } public string Leech { get; set; } From ae8f017ca85010ae7387d3954a98fa01513205d9 Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 26 Dec 2022 20:10:07 +0000 Subject: [PATCH 0714/2320] Translated using Weblate (Ukrainian) Currently translated at 63.2% (298 of 471 strings) Translated using Weblate (Chinese (Simplified) (zh_CN)) Currently translated at 98.5% (464 of 471 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (471 of 471 strings) Translated using Weblate (Bengali) Currently translated at 0.8% (4 of 468 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (468 of 468 strings) Translated using Weblate (Finnish) Currently translated at 100.0% (468 of 468 strings) Co-authored-by: Csaba Co-authored-by: Havok Dan Co-authored-by: Oskari Lavinto Co-authored-by: Weblate Co-authored-by: andrey4korop Co-authored-by: lhquark Co-authored-by: saambd Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/bn/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/uk/ Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/ Translation: Servarr/Prowlarr --- .../Localization/Core/pt_BR.json | 5 +- src/NzbDrone.Core/Localization/Core/uk.json | 235 +++++++++++++++++- .../Localization/Core/zh_CN.json | 5 +- 3 files changed, 241 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json index 6c4c228bb..6d029a950 100644 --- a/src/NzbDrone.Core/Localization/Core/pt_BR.json +++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json @@ -466,5 +466,8 @@ "AreYouSureYouWantToDeleteCategory": "Tem certeza de que deseja excluir a categoria mapeada?", "DeleteClientCategory": "Excluir Categoria de Cliente de Download", "DownloadClientCategory": "Categoria de Download do Cliente", - "MappedCategories": "Categorias Mapeadas" + "MappedCategories": "Categorias Mapeadas", + "AuthenticationRequired": "Autenticação Requerida", + "AuthenticationRequiredHelpText": "Altera para quais solicitações a autenticação é necessária. Não mude a menos que você entenda os riscos.", + "AuthenticationRequiredWarning": "Para impedir o acesso remoto sem autenticação, o Prowlarr agora exige que a autenticação seja habilitada. Você pode, opcionalmente, desabilitar a autenticação de endereços locais." } diff --git a/src/NzbDrone.Core/Localization/Core/uk.json b/src/NzbDrone.Core/Localization/Core/uk.json index 9d0fa3331..378be1f80 100644 --- a/src/NzbDrone.Core/Localization/Core/uk.json +++ b/src/NzbDrone.Core/Localization/Core/uk.json @@ -70,5 +70,238 @@ "DeleteApplicationMessageText": "Ви впевнені, що хочете видалити клієнт завантаження '{0}'?", "DeleteTagMessageText": "Ви впевнені, що хочете видалити тег {0} ?", "DeleteIndexerProxyMessageText": "Ви впевнені, що хочете видалити тег {0} ?", - "DeleteNotificationMessageText": "Ви впевнені, що хочете видалити клієнт завантаження '{0}'?" + "DeleteNotificationMessageText": "Ви впевнені, що хочете видалити клієнт завантаження '{0}'?", + "YesCancel": "Так, скасувати", + "InstanceName": "Ім'я екземпляра", + "Interval": "Інтервал", + "PendingChangesStayReview": "Залишайтеся та переглядайте зміни", + "ShowSearch": "Показати пошук", + "SSLCertPasswordHelpText": "Пароль для файлу pfx", + "TestAll": "Перевірити все", + "Type": "Тип", + "UnableToLoadDownloadClients": "Не вдалося завантажити клієнти для завантаження", + "UnableToLoadGeneralSettings": "Не вдалося завантажити загальні налаштування", + "UnableToLoadHistory": "Не вдалося завантажити історію", + "UnableToLoadIndexers": "Не вдалося завантажити індексатори", + "UnableToLoadNotifications": "Не вдалося завантажити сповіщення", + "UnableToLoadTags": "Не вдалося завантажити теги", + "UpdateAutomaticallyHelpText": "Автоматичне завантаження та встановлення оновлень. Ви все ще зможете встановити з System: Updates", + "Uptime": "Час роботи", + "URLBase": "URL-адреса", + "DownloadClients": "Клієнти завантажувачів", + "DownloadClientSettings": "Налаштування клієнта завантажувача", + "DownloadClientStatusCheckSingleClientMessage": "Завантаження клієнтів недоступне через помилки: {0}", + "Edit": "Редагувати", + "EditIndexer": "Редагувати індексатор", + "Docker": "Docker", + "NoLeaveIt": "Ні, залиште це", + "NoLogFiles": "Немає файлів журналу", + "NoTagsHaveBeenAddedYet": "Теги ще не додано", + "NotificationTriggers": "Тригери сповіщень", + "Ok": "Гаразд", + "LastWriteTime": "Час останнього запису", + "Presets": "Предустановки", + "RestoreBackup": "Відновлення резервної копії", + "Result": "Результат", + "Retention": "Утримання", + "OAuthPopupMessage": "Ваш браузер блокує спливаючі вікна", + "Title": "Назва", + "Today": "Сьогодні", + "Tomorrow": "Завтра", + "Torrents": "Торренти", + "OnHealthIssueHelpText": "Про питання здоров'я", + "OpenBrowserOnStart": "Відкрийте браузер при запуску", + "Options": "Опції", + "PackageVersion": "Версія пакета", + "Protocol": "Протокол", + "Proxy": "Проксі", + "ProxyCheckFailedToTestMessage": "Не вдалося перевірити проксі: {0}", + "ProxyCheckResolveIpMessage": "Не вдалося визначити IP-адресу для налаштованого проксі-сервера {0}", + "ProxyType": "Тип проксі", + "ProxyUsernameHelpText": "Вам потрібно лише ввести ім’я користувача та пароль, якщо вони потрібні. В іншому випадку залиште їх порожніми.", + "Reset": "Скинути", + "RemoveFilter": "Видалити фільтр", + "RemovingTag": "Видалення мітки", + "ResetAPIKey": "Скинути ключ API", + "Restart": "Перезавантажити", + "RestartNow": "Перезавантажити зараз", + "RestartRequiredHelpTextWarning": "Щоб набуло чинності, потрібно перезапустити", + "Search": "Пошук", + "SendAnonymousUsageData": "Надсилати анонімні дані про використання", + "SetTags": "Встановити теги", + "Settings": "Налаштування", + "SettingsEnableColorImpairedModeHelpText": "Змінений стиль, щоб користувачі з вадами кольору могли краще розрізняти кольорову кодовану інформацію", + "Source": "Джерело", + "Shutdown": "Вимкнення", + "Size": "Розмір", + "Sort": "Сортування", + "UILanguage": "Мова інтерфейсу користувача", + "UISettings": "Налаштування інтерфейсу користувача", + "EnableSSL": "Увімкнути SSL", + "HomePage": "Домашня сторінка", + "Hostname": "Ім'я хоста", + "DeleteNotification": "Видалити сповіщення", + "IndexerStatusCheckSingleClientMessage": "Індексатори недоступні через помилки: {0}", + "Info": "Інформація", + "InstanceNameHelpText": "Ім’я екземпляра на вкладці та ім’я програми Syslog", + "InteractiveSearch": "Інтерактивний пошук", + "KeyboardShortcuts": "Гарячі клавіши", + "Language": "Мова", + "LastDuration": "Остання тривалість", + "Mode": "Режим", + "MoreInfo": "Більше інформації", + "Name": "Ім'я", + "NoChanges": "Жодних змін", + "NoUpdatesAreAvailable": "Немає оновлень", + "OnApplicationUpdate": "Оновлення програми", + "OnApplicationUpdateHelpText": "Оновлення програми", + "OnHealthIssue": "Про питання здоров'я", + "Password": "Пароль", + "PendingChangesDiscardChanges": "Відкинути зміни та залишити", + "Port": "Порт", + "PortNumber": "Номер порту", + "Priority": "Пріоритет", + "ProxyBypassFilterHelpText": "Використовуйте «,» як роздільник і «*». як символ підстановки для субдоменів", + "PtpOldSettingsCheckMessage": "Наведені нижче індексатори PassThePopcorn мають застарілі налаштування та їх потрібно оновити: {0}", + "Queue": "Черга", + "Queued": "У черзі", + "ReadTheWikiForMoreInformation": "Читайте Wiki для отримання додаткової інформації", + "Reload": "Перезавантажити", + "RemovedFromTaskQueue": "Видалено з черги завдань", + "Restore": "Відновлення", + "RSSIsNotSupportedWithThisIndexer": "Цей індексатор не підтримує RSS", + "Save": "Зберегти", + "SaveChanges": "Зберегти зміни", + "SaveSettings": "Зберегти зміни", + "ScriptPath": "Шлях сценарію", + "Security": "Безпека", + "SelectAll": "Вибрати все", + "SettingsLongDateFormat": "Довгий формат дати", + "SettingsShortDateFormat": "Короткий формат дати", + "SettingsShowRelativeDates": "Показати відносні дати", + "SettingsTimeFormat": "Формат часу", + "ShowAdvanced": "Показати Додатково", + "ShownClickToHide": "Показано, натисніть, щоб приховати", + "ShowSearchHelpText": "Показувати кнопку пошуку при наведенні", + "TagCannotBeDeletedWhileInUse": "Неможливо видалити під час використання", + "TestAllClients": "Перевірте всіх клієнтів", + "TestAllIndexers": "Перевірити всі індексатори", + "Time": "Час", + "UILanguageHelpTextWarning": "Потрібно перезавантажити браузер", + "UnableToAddANewIndexerPleaseTryAgain": "Не вдалося додати новий індексатор, спробуйте ще раз.", + "UnableToAddANewNotificationPleaseTryAgain": "Не вдалося додати нове сповіщення, спробуйте ще раз.", + "UnableToLoadBackups": "Не вдалося завантажити резервні копії", + "UnableToLoadUISettings": "Не вдалося завантажити налаштування інтерфейсу користувача", + "UnsavedChanges": "Незбережені зміни", + "UnselectAll": "Скасувати вибір усіх", + "UpdateCheckStartupNotWritableMessage": "Неможливо встановити оновлення, оскільки папка запуску \"{0}\" не може бути записана користувачем \"{1}\".", + "UpdateCheckStartupTranslocationMessage": "Неможливо встановити оновлення, оскільки папка запуску \"{0}\" знаходиться в папці переміщення програми.", + "UpdateCheckUINotWritableMessage": "Неможливо встановити оновлення, оскільки папка інтерфейсу користувача \"{0}\" не може бути записана користувачем \"{1}\".", + "Updates": "Оновлення", + "UrlBaseHelpText": "Для підтримки зворотного проксі-сервера значення за умовчанням порожнє", + "UseProxy": "Використовуйте проксі", + "Yesterday": "Вчора", + "Duration": "Тривалість", + "EnableAutomaticSearch": "Увімкнути автоматичний пошук", + "EnableInteractiveSearch": "Увімкнути інтерактивний пошук", + "EnableSslHelpText": " Щоб набуло чинності, потрібно перезапустити роботу від імені адміністратора", + "Ended": "Завершено", + "Error": "Помилка", + "ErrorLoadingContents": "Помилка завантаження вмісту", + "EventType": "Тип події", + "Exception": "Виняток", + "ExistingTag": "Існуючий тег", + "Failed": "Не вдалося", + "FeatureRequests": "Запити щодо функцій", + "Events": "Події", + "Fixed": "Виправлено", + "Filters": "Фільтри", + "Files": "Файли", + "Filter": "Фільтр", + "FocusSearchBox": "Перейти до вікна пошуку", + "Folder": "Папка", + "General": "Загальний", + "GeneralSettings": "Загальні налаштування", + "Health": "Здоров'я", + "HiddenClickToShow": "Приховано, натисніть, щоб показати", + "HideAdvanced": "Сховати додаткові", + "History": "Історія", + "IgnoredAddresses": "Ігноровані адреси", + "IllRestartLater": "Я перезапущу пізніше", + "IncludeHealthWarningsHelpText": "Включайте попередження про здоров’я", + "Indexer": "Індексатор", + "IndexerPriority": "Пріоритет індексатора", + "LogLevel": "Рівень журналу", + "Level": "Рівень", + "Logs": "Журнали", + "New": "Новий", + "NoChange": "Без змін", + "NextExecution": "Наступне виконання", + "NoBackupsAreAvailable": "Немає резервних копій", + "NoLinks": "Немає посилань", + "OpenThisModal": "Відкрийте цей модальний вікно", + "ProxyCheckBadRequestMessage": "Не вдалося перевірити проксі. Код стану: {0}", + "ReleaseStatus": "Статус випуску", + "Refresh": "Оновити", + "RefreshMovie": "Оновити фільм", + "System": "Система", + "TableOptions": "Параметри таблиці", + "Test": "Тест", + "Tags": "Теги", + "TagsSettingsSummary": "Перегляньте всі теги та те, як вони використовуються. Невикористані теги можна видалити", + "Tasks": "Задачі", + "Version": "Версія", + "View": "Переглянути", + "Username": "Ім'я користувача", + "Warn": "Попередити", + "Mechanism": "Механізм", + "Message": "Повідомлення", + "MIA": "MIA", + "Enabled": "Увімкнено", + "EnableInteractiveSearchHelpText": "Буде використано, коли використовується інтерактивний пошук", + "Indexers": "Індексатори", + "HealthNoIssues": "Немає проблем із вашою конфігурацією", + "IndexerFlags": "Прапори індексатора", + "IndexerLongTermStatusCheckAllClientMessage": "Усі індексатори недоступні через збої більше 6 годин", + "IndexerLongTermStatusCheckSingleClientMessage": "Індексатори недоступні через збої більше 6 годин: {0}", + "IndexerStatusCheckAllClientMessage": "Усі індексатори недоступні через збої", + "LastExecution": "Останнє виконання", + "LogFiles": "Файли журналів", + "LogLevelTraceHelpTextWarning": "Журнал трасування слід увімкнути лише тимчасово", + "Manual": "Інструкція", + "MappedDrivesRunningAsService": "Підключені мережеві диски недоступні під час роботи як служби Windows. Щоб отримати додаткову інформацію, перегляньте FAQ", + "MovieIndexScrollBottom": "Індекс фільму: прокрутка внизу", + "MovieIndexScrollTop": "Індекс фільму: прокрутка вгору", + "NotificationTriggersHelpText": "Виберіть, які події мають викликати це сповіщення", + "PageSize": "Розмір сторінки", + "PageSizeHelpText": "Кількість елементів для показу на кожній сторінці", + "PendingChangesMessage": "У вас є незбережені зміни. Ви впевнені, що бажаєте залишити цю сторінку?", + "ProxyPasswordHelpText": "Вам потрібно лише ввести ім’я користувача та пароль, якщо вони потрібні. В іншому випадку залиште їх порожніми.", + "Scheduled": "За розкладом", + "SettingsEnableColorImpairedMode": "Увімкнути режим із порушенням кольору", + "SettingsShowRelativeDatesHelpText": "Показати відносні (сьогодні/вчора/тощо) або абсолютні дати", + "TagIsNotUsedAndCanBeDeleted": "Тег не використовується і може бути видалений", + "UnableToAddANewDownloadClientPleaseTryAgain": "Не вдається додати новий клієнт для завантаження, повторіть спробу.", + "UpdateScriptPathHelpText": "Шлях до спеціального сценарію, який приймає витягнутий пакет оновлення та обробляє решту процесу оновлення", + "DeleteTag": "Видалити тег", + "Details": "Подробиці", + "Disabled": "Вимкнено", + "Discord": "Discord", + "DownloadClient": "Клієнт завантажувача", + "Donations": "Пожертви", + "DownloadClientStatusCheckAllClientMessage": "Усі клієнти завантаження недоступні через збої", + "Enable": "Увімкнути", + "Filename": "Ім'я файлу", + "Host": "Хост", + "PriorityHelpText": "Надайте пріоритет кільком клієнтам завантаження. Round-Robin використовується для клієнтів з однаковим пріоритетом.", + "SSLCertPathHelpText": "Шлях до файлу pfx", + "SSLPort": "Порт SSL", + "Started": "Розпочато", + "StartTypingOrSelectAPathBelow": "Почніть вводити текст або виберіть шлях нижче", + "StartupDirectory": "Каталог запуску", + "Status": "Статус", + "Style": "Стиль", + "SuggestTranslationChange": "Запропонуйте зміну перекладу", + "TableOptionsColumnsMessage": "Виберіть, які стовпці відображаються та в якому порядку вони відображаються", + "SystemTimeCheckMessage": "Системний час вимкнено більш ніж на 1 день. Заплановані завдання можуть не працювати належним чином, доки час не буде виправлено" } diff --git a/src/NzbDrone.Core/Localization/Core/zh_CN.json b/src/NzbDrone.Core/Localization/Core/zh_CN.json index cfc726c11..542d295e1 100644 --- a/src/NzbDrone.Core/Localization/Core/zh_CN.json +++ b/src/NzbDrone.Core/Localization/Core/zh_CN.json @@ -159,7 +159,7 @@ "BranchUpdateMechanism": "外部更新机制使用的分支", "BranchUpdate": "更新Prowlarr的分支", "Branch": "分支", - "BindAddressHelpText": "有效的 IP4 地址或以'*'代表所有地址", + "BindAddressHelpText": "有效的 IP 地址,localhost,或以'*'代表所有地址", "BindAddress": "绑定地址", "BeforeUpdate": "更新前", "Backups": "备份", @@ -462,5 +462,6 @@ "Started": "已开始", "LastDuration": "上一次用时", "ApplicationLongTermStatusCheckAllClientMessage": "由于故障超过6小时,所有程序都不可用", - "ApplicationLongTermStatusCheckSingleClientMessage": "由于故障超过6小时而无法使用的程序:{0}" + "ApplicationLongTermStatusCheckSingleClientMessage": "由于故障超过6小时而无法使用的程序:{0}", + "AuthenticationRequired": "需要认证" } From 587a73f3d6183f338ca54fe7416e009ca8e5a350 Mon Sep 17 00:00:00 2001 From: Qstick Date: Mon, 26 Dec 2022 18:17:50 -0600 Subject: [PATCH 0715/2320] Fixed: (Newznab) Parsing of Ids from non-standard feeds Fixes #1261 --- .../IndexerSearch/NewznabResults.cs | 13 +++++---- .../Definitions/Newznab/NewznabRssParser.cs | 29 +++++++++++-------- src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs | 1 + 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs index f272559ae..2a076f9c5 100644 --- a/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs +++ b/src/NzbDrone.Core/IndexerSearch/NewznabResults.cs @@ -93,12 +93,13 @@ namespace NzbDrone.Core.IndexerSearch r.Languages == null ? null : from c in r.Languages select GetNabElement("language", c, protocol), r.Subs == null ? null : from c in r.Subs select GetNabElement("subs", c, protocol), r.Genres == null ? null : GetNabElement("genre", string.Join(", ", r.Genres), protocol), - GetNabElement("rageid", r.TvRageId, protocol), - GetNabElement("tvdbid", r.TvdbId, protocol), - GetNabElement("imdb", r.ImdbId.ToString("D7"), protocol), - GetNabElement("tmdbid", r.TmdbId, protocol), - GetNabElement("traktid", r.TraktId, protocol), - GetNabElement("doubanid", r.DoubanId, protocol), + r.TvRageId == 0 ? null : GetNabElement("rageid", r.TvRageId, protocol), + r.TvdbId == 0 ? null : GetNabElement("tvdbid", r.TvdbId, protocol), + r.ImdbId == 0 ? null : GetNabElement("imdb", r.ImdbId.ToString("D7"), protocol), + r.TmdbId == 0 ? null : GetNabElement("tmdbid", r.TmdbId, protocol), + r.TraktId == 0 ? null : GetNabElement("traktid", r.TraktId, protocol), + r.TvMazeId == 0 ? null : GetNabElement("tvmazeid", r.TvMazeId, protocol), + r.DoubanId == 0 ? null : GetNabElement("doubanid", r.DoubanId, protocol), GetNabElement("seeders", t.Seeders, protocol), GetNabElement("files", r.Files, protocol), GetNabElement("grabs", r.Grabs, protocol), diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs index 269b548ab..1efd2ace2 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabRssParser.cs @@ -100,12 +100,14 @@ namespace NzbDrone.Core.Indexers.Newznab } releaseInfo = base.ProcessItem(item, releaseInfo); - releaseInfo.ImdbId = GetIntAttribute(item, "imdb"); - releaseInfo.TmdbId = GetIntAttribute(item, "tmdbid"); - releaseInfo.TvdbId = GetIntAttribute(item, "tvdbid"); - releaseInfo.TvRageId = GetIntAttribute(item, "rageid"); - releaseInfo.Grabs = GetIntAttribute(item, "grabs"); - releaseInfo.Files = GetIntAttribute(item, "files"); + releaseInfo.ImdbId = GetIntAttribute(item, new[] { "imdb", "imdbid" }); + releaseInfo.TmdbId = GetIntAttribute(item, new[] { "tmdbid", "tmdb" }); + releaseInfo.TvdbId = GetIntAttribute(item, new[] { "tvdbid", "tvdb" }); + releaseInfo.TvMazeId = GetIntAttribute(item, new[] { "tvmazeid", "tvmaze" }); + releaseInfo.TraktId = GetIntAttribute(item, new[] { "traktid", "trakt" }); + releaseInfo.TvRageId = GetIntAttribute(item, new[] { "rageid" }); + releaseInfo.Grabs = GetIntAttribute(item, new[] { "grabs" }); + releaseInfo.Files = GetIntAttribute(item, new[] { "files" }); releaseInfo.PosterUrl = GetPosterUrl(item); return releaseInfo; @@ -206,14 +208,17 @@ namespace NzbDrone.Core.Indexers.Newznab return url; } - protected virtual int GetIntAttribute(XElement item, string attribute) + protected virtual int GetIntAttribute(XElement item, string[] attributes) { - var idString = TryGetNewznabAttribute(item, attribute); - int idInt; - - if (!idString.IsNullOrWhiteSpace() && int.TryParse(idString, out idInt)) + foreach (var attr in attributes) { - return idInt; + var idString = TryGetNewznabAttribute(item, attr); + int idInt; + + if (!idString.IsNullOrWhiteSpace() && int.TryParse(idString, out idInt)) + { + return idInt; + } } return 0; diff --git a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs index f0f66fc1b..511f4f683 100644 --- a/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs +++ b/src/NzbDrone.Core/Parser/Model/ReleaseInfo.cs @@ -34,6 +34,7 @@ namespace NzbDrone.Core.Parser.Model public int ImdbId { get; set; } public int TmdbId { get; set; } public int TraktId { get; set; } + public int TvMazeId { get; set; } public int DoubanId { get; set; } public int Year { get; set; } public string Author { get; set; } From ba3a2407070459e9cd8febbe71a0d897d20b500b Mon Sep 17 00:00:00 2001 From: Bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 26 Nov 2022 10:57:06 -0600 Subject: [PATCH 0716/2320] Add TooManyRequestsException with var retryWait --- src/NzbDrone.Common/Http/TooManyRequestsException.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Common/Http/TooManyRequestsException.cs b/src/NzbDrone.Common/Http/TooManyRequestsException.cs index dcb261efa..1d86740ca 100644 --- a/src/NzbDrone.Common/Http/TooManyRequestsException.cs +++ b/src/NzbDrone.Common/Http/TooManyRequestsException.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace NzbDrone.Common.Http { @@ -25,5 +25,11 @@ namespace NzbDrone.Common.Http } } } + + public TooManyRequestsException(HttpRequest request, HttpResponse response, TimeSpan retryWait) + : base(request, response) + { + RetryAfter = retryWait; + } } } From 518c85dee2bf05ccc840c1e2f87ff696f77672af Mon Sep 17 00:00:00 2001 From: Bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 26 Nov 2022 11:01:33 -0600 Subject: [PATCH 0717/2320] Fixed: (Rarbg) Improve RateLimit Handling Fixed: (Rarbg) Increase delay to 4s to reduce Rate Limiting Fixes #1169 --- .../Indexers/Definitions/Rarbg/Rarbg.cs | 9 ++++--- .../Indexers/Definitions/Rarbg/RarbgParser.cs | 26 ++++++++++++++----- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs index 3f3befd76..123547357 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs @@ -34,7 +34,7 @@ namespace NzbDrone.Core.Indexers.Rarbg public override IndexerCapabilities Capabilities => SetCapabilities(); - public override TimeSpan RateLimit => TimeSpan.FromSeconds(2); + public override TimeSpan RateLimit => TimeSpan.FromSeconds(4); public Rarbg(IRarbgTokenProvider tokenProvider, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger) @@ -106,7 +106,8 @@ namespace NzbDrone.Core.Indexers.Rarbg { var response = await FetchIndexerResponse(request); - // try and recover from token or rate limit errors + // try and recover from token errors + // Response of 200 and rate_limt of 1 requires a 5 minute backoff. Handle in Response Parsing & do not page further if rate_limit is populated. var jsonResponse = new HttpResponse(response.HttpResponse); if (jsonResponse.Resource.error_code.HasValue) @@ -123,9 +124,9 @@ namespace NzbDrone.Core.Indexers.Rarbg request.HttpRequest.Url = request.Url.SetQuery(qs.GetQueryString()); response = await FetchIndexerResponse(request); } - else if (jsonResponse.Resource.error_code == 5 || jsonResponse.Resource.rate_limit.HasValue) + else if (jsonResponse.Resource.error_code == 5) { - _logger.Debug("Rarbg rate limit hit, retying request"); + _logger.Debug("Rarbg temp rate limit hit, retying request"); response = await FetchIndexerResponse(request); } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs index e2fcf3a7c..e837279e1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs @@ -23,20 +23,32 @@ namespace NzbDrone.Core.Indexers.Rarbg public IList ParseResponse(IndexerResponse indexerResponse) { var results = new List(); + var retryTime = TimeSpan.FromMinutes(1); + var responseCode = (int)indexerResponse.HttpResponse.StatusCode; - switch (indexerResponse.HttpResponse.StatusCode) + switch (responseCode) { - default: - if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) - { - throw new IndexerException(indexerResponse, "Indexer API call returned an unexpected StatusCode [{0}]", indexerResponse.HttpResponse.StatusCode); - } - + case (int)HttpStatusCode.TooManyRequests: + retryTime = TimeSpan.FromMinutes(2); + throw new TooManyRequestsException(indexerResponse.HttpRequest, indexerResponse.HttpResponse, retryTime); + case 520: + retryTime = TimeSpan.FromMinutes(3); + throw new TooManyRequestsException(indexerResponse.HttpRequest, indexerResponse.HttpResponse, retryTime); + case (int)HttpStatusCode.OK: + retryTime = TimeSpan.FromMinutes(5); break; + default: + throw new IndexerException(indexerResponse, "Indexer API call returned an unexpected StatusCode [{0}]", responseCode); } var jsonResponse = new HttpResponse(indexerResponse.HttpResponse); + // Handle 200 Rate Limiting + if (jsonResponse.Resource.rate_limit == 1) + { + throw new TooManyRequestsException(indexerResponse.HttpRequest, indexerResponse.HttpResponse, retryTime); + } + if (jsonResponse.Resource.error_code.HasValue) { if (jsonResponse.Resource.error_code == 20 || jsonResponse.Resource.error_code == 8 From affde5d7b73701ace1096d88297f22ec36d1b0fd Mon Sep 17 00:00:00 2001 From: Bogdan Date: Wed, 28 Dec 2022 06:16:49 +0200 Subject: [PATCH 0718/2320] Fixed: (Orpheus) Changed to use filters for categories, label and year --- .../Indexers/Definitions/Orpheus.cs | 52 +++++++++++++++++-- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs index 07351a876..ec001c5eb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using FluentValidation; using NLog; +using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; @@ -126,8 +128,29 @@ namespace NzbDrone.Core.Indexers.Definitions public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); + var parameters = new NameValueCollection(); - pageableRequests.Add(GetRequest(string.Format("&artistname={0}&groupname={1}", searchCriteria.Artist, searchCriteria.Album))); + if (searchCriteria.Artist.IsNotNullOrWhiteSpace()) + { + parameters.Add("artistname", searchCriteria.Artist); + } + + if (searchCriteria.Album.IsNotNullOrWhiteSpace()) + { + parameters.Add("groupname", searchCriteria.Album); + } + + if (searchCriteria.Label.IsNotNullOrWhiteSpace()) + { + parameters.Add("recordlabel", searchCriteria.Label); + } + + if (searchCriteria.Year.HasValue) + { + parameters.Add("year", searchCriteria.Year.ToString()); + } + + pageableRequests.Add(GetRequest(searchCriteria, parameters)); return pageableRequests; } @@ -135,8 +158,9 @@ namespace NzbDrone.Core.Indexers.Definitions public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); + var parameters = new NameValueCollection(); - pageableRequests.Add(GetRequest(searchCriteria.SanitizedSearchTerm)); + pageableRequests.Add(GetRequest(searchCriteria, parameters)); return pageableRequests; } @@ -154,16 +178,34 @@ namespace NzbDrone.Core.Indexers.Definitions public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); + var parameters = new NameValueCollection(); - pageableRequests.Add(GetRequest(searchCriteria.SanitizedSearchTerm)); + pageableRequests.Add(GetRequest(searchCriteria, parameters)); return pageableRequests; } - private IEnumerable GetRequest(string searchParameters) + private IEnumerable GetRequest(SearchCriteriaBase searchCriteria, NameValueCollection parameters) { + var term = searchCriteria.SanitizedSearchTerm.Trim(); + + parameters.Add("action", "browse"); + parameters.Add("order_by", "time"); + parameters.Add("order_way", "desc"); + parameters.Add("searchstr", term); + + var queryCats = Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories); + + if (queryCats.Count > 0) + { + foreach (var cat in queryCats) + { + parameters.Add($"filter_cat[{cat}]", "1"); + } + } + var req = RequestBuilder() - .Resource($"ajax.php?action=browse&searchstr={searchParameters}") + .Resource($"ajax.php?{parameters.GetQueryString()}") .Build(); yield return new IndexerRequest(req); From d556545e7fd050da1550d8e1ed48415caa3457d5 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Wed, 28 Dec 2022 13:44:07 +0200 Subject: [PATCH 0719/2320] Fixed: Changed torznab parser to use additional attributes --- .../Definitions/Torznab/TorznabRssParser.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs index 6097acb85..042a41979 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/TorznabRssParser.cs @@ -74,8 +74,18 @@ namespace NzbDrone.Core.Indexers.Torznab torrentInfo.DownloadVolumeFactor = downloadFactor; torrentInfo.UploadVolumeFactor = uploadFactor; + torrentInfo.ImdbId = GetIntAttribute(item, new[] { "imdb", "imdbid" }); + torrentInfo.TmdbId = GetIntAttribute(item, new[] { "tmdbid", "tmdb" }); + torrentInfo.TvdbId = GetIntAttribute(item, new[] { "tvdbid", "tvdb" }); + torrentInfo.TvMazeId = GetIntAttribute(item, new[] { "tvmazeid", "tvmaze" }); + torrentInfo.TraktId = GetIntAttribute(item, new[] { "traktid", "trakt" }); + torrentInfo.TvRageId = GetIntAttribute(item, new[] { "rageid" }); + torrentInfo.Grabs = GetIntAttribute(item, new[] { "grabs" }); + torrentInfo.Files = GetIntAttribute(item, new[] { "files" }); + torrentInfo.IndexerFlags = GetFlags(item); torrentInfo.PosterUrl = GetPosterUrl(item); + torrentInfo.InfoHash = GetInfoHash(item); } return torrentInfo; @@ -287,5 +297,21 @@ namespace NzbDrone.Core.Indexers.Torznab return results; } + + protected virtual int GetIntAttribute(XElement item, string[] attributes) + { + foreach (var attr in attributes) + { + var idString = TryGetTorznabAttribute(item, attr); + int idInt; + + if (!idString.IsNullOrWhiteSpace() && int.TryParse(idString, out idInt)) + { + return idInt; + } + } + + return 0; + } } } From 73af5c9a726f0aba18f399af011cc802622eed18 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Tue, 27 Dec 2022 19:17:38 +0200 Subject: [PATCH 0720/2320] Fixed: (Indexer) Changed FL to use internal flag --- src/NzbDrone.Core/Indexers/Definitions/FileList/FileList.cs | 3 ++- .../Indexers/Definitions/FileList/FileListApi.cs | 1 + .../Indexers/Definitions/FileList/FileListParser.cs | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileList.cs b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileList.cs index 630283e80..7d725a9ca 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileList.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileList.cs @@ -39,7 +39,7 @@ namespace NzbDrone.Core.Indexers.FileList { TvSearchParams = new List { - TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep + TvSearchParam.Q, TvSearchParam.ImdbId, TvSearchParam.Season, TvSearchParam.Ep }, MovieSearchParams = new List { @@ -55,6 +55,7 @@ namespace NzbDrone.Core.Indexers.FileList }, Flags = new List { + IndexerFlag.Internal, IndexerFlag.FreeLeech } }; diff --git a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListApi.cs b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListApi.cs index b92766e14..aa09996b9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListApi.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListApi.cs @@ -16,6 +16,7 @@ namespace NzbDrone.Core.Indexers.FileList public uint Files { get; set; } [JsonProperty(PropertyName = "imdb")] public string ImdbId { get; set; } + public bool Internal { get; set; } [JsonProperty(PropertyName = "freeleech")] public bool FreeLeech { get; set; } [JsonProperty(PropertyName = "doubleup")] diff --git a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListParser.cs b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListParser.cs index 2a4176bd2..a495d4fe9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/FileList/FileListParser.cs @@ -38,6 +38,11 @@ namespace NzbDrone.Core.Indexers.FileList var flags = new List(); + if (result.Internal) + { + flags.Add(IndexerFlag.Internal); + } + var imdbId = 0; if (result.ImdbId != null && result.ImdbId.Length > 2) { From a58380031ddd39ee9f2a5ec1de51d94a0a9ffe6f Mon Sep 17 00:00:00 2001 From: Bogdan Date: Wed, 28 Dec 2022 19:29:48 +0200 Subject: [PATCH 0721/2320] Fixed: (Indexer) Added `TvSearchParam.ImdbId` to SpeedApp --- src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs | 11 ++--------- src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs | 11 ++--------- .../Indexers/Definitions/SpeedApp/SpeedAppBase.cs | 5 +---- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs b/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs index 23027a5f1..ca92f0ddb 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs @@ -9,12 +9,9 @@ namespace NzbDrone.Core.Indexers.Definitions public class RetroFlix : SpeedAppBase { public override string Name => "RetroFlix"; - public override string[] IndexerUrls => new string[] { "https://retroflix.club/" }; public override string[] LegacyUrls => new string[] { "https://retroflix.net/" }; - public override string Description => "Private Torrent Tracker for Classic Movies / TV / General Releases"; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override TimeSpan RateLimit => TimeSpan.FromSeconds(2.1); @@ -29,15 +26,11 @@ namespace NzbDrone.Core.Indexers.Definitions { TvSearchParams = new List { - TvSearchParam.Q, - TvSearchParam.Season, - TvSearchParam.Ep, - TvSearchParam.ImdbId + TvSearchParam.Q, TvSearchParam.ImdbId, TvSearchParam.Season, TvSearchParam.Ep, }, MovieSearchParams = new List { - MovieSearchParam.Q, - MovieSearchParam.ImdbId + MovieSearchParam.Q, MovieSearchParam.ImdbId, }, MusicSearchParams = new List { diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs index 5d557582c..b4ba75ada 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs @@ -8,14 +8,10 @@ namespace NzbDrone.Core.Indexers.Definitions public class SpeedApp : SpeedAppBase { public override string Name => "SpeedApp.io"; - public override string[] IndexerUrls => new string[] { "https://speedapp.io/" }; public override string[] LegacyUrls => new string[] { "https://speedapp.io" }; - public override string Description => "SpeedApp is a ROMANIAN Private Torrent Tracker for MOVIES / TV / GENERAL"; - public override string Language => "ro-RO"; - public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public SpeedApp(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger, IIndexerRepository indexerRepository) @@ -29,14 +25,11 @@ namespace NzbDrone.Core.Indexers.Definitions { TvSearchParams = new List { - TvSearchParam.Q, - TvSearchParam.Season, - TvSearchParam.Ep, + TvSearchParam.Q, TvSearchParam.ImdbId, TvSearchParam.Season, TvSearchParam.Ep, }, MovieSearchParams = new List { - MovieSearchParam.Q, - MovieSearchParam.ImdbId, + MovieSearchParam.Q, MovieSearchParam.ImdbId, }, MusicSearchParams = new List { diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs index 1e30bb7cb..ca144bc46 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs @@ -29,11 +29,8 @@ namespace NzbDrone.Core.Indexers.Definitions public abstract class SpeedAppBase : TorrentIndexerBase { private string LoginUrl => Settings.BaseUrl + "api/login"; - public override Encoding Encoding => Encoding.UTF8; - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override IndexerCapabilities Capabilities => SetCapabilities(); private IIndexerRepository _indexerRepository; @@ -304,7 +301,7 @@ namespace NzbDrone.Core.Indexers.Definitions Description = torrent.ShortDescription, Size = torrent.Size, ImdbId = ParseUtil.GetImdbID(torrent.ImdbId).GetValueOrDefault(), - DownloadUrl = $"{_settings.BaseUrl}/api/torrent/{torrent.Id}/download", + DownloadUrl = $"{_settings.BaseUrl}api/torrent/{torrent.Id}/download", PosterUrl = torrent.Poster, InfoUrl = torrent.Url, Grabs = torrent.TimesCompleted, From c15643be399aa92e3766e1f3dd8d15cff99dfa2d Mon Sep 17 00:00:00 2001 From: Bogdan Date: Thu, 29 Dec 2022 20:24:46 +0200 Subject: [PATCH 0722/2320] Fixed: (Cardigann) Allow use of template variables in fields selector --- .../Indexers/Definitions/Cardigann/CardigannBase.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index e24d28aa6..0e3900295 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -132,20 +132,22 @@ namespace NzbDrone.Core.Indexers.Cardigann if (selector.Selector != null) { - if (dom.Matches(selector.Selector)) + var selectorSelector = ApplyGoTemplateText(selector.Selector, variables); + + if (dom.Matches(selectorSelector)) { selection = dom; } else { - selection = QuerySelector(dom, selector.Selector); + selection = QuerySelector(dom, selectorSelector); } if (selection == null) { if (required) { - throw new Exception(string.Format("Selector \"{0}\" didn't match {1}", selector.Selector, dom.ToHtmlPretty())); + throw new Exception(string.Format("Selector \"{0}\" didn't match {1}", selectorSelector, dom.ToHtmlPretty())); } return null; From 6ce9e5ceb9763aeae6525a44b160f3cf9f09c4dd Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 30 Dec 2022 18:28:55 -0600 Subject: [PATCH 0723/2320] Fixed: Release Grab not working on Mobile search --- frontend/src/Search/Mobile/SearchIndexOverview.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/frontend/src/Search/Mobile/SearchIndexOverview.js b/frontend/src/Search/Mobile/SearchIndexOverview.js index 9de331e78..6b1e0ea2a 100644 --- a/frontend/src/Search/Mobile/SearchIndexOverview.js +++ b/frontend/src/Search/Mobile/SearchIndexOverview.js @@ -52,12 +52,17 @@ class SearchIndexOverview extends Component { // // Listeners - onEditSeriesPress = () => { - this.setState({ isEditSeriesModalOpen: true }); - }; + onGrabPress = () => { + const { + guid, + indexerId, + onGrabPress + } = this.props; - onEditSeriesModalClose = () => { - this.setState({ isEditSeriesModalOpen: false }); + onGrabPress({ + guid, + indexerId + }); }; // From 4175c2577ef78bd0afc52869358cada403f8ce7f Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 31 Dec 2022 15:56:29 -0600 Subject: [PATCH 0724/2320] Fixed: Link to release page from mobile search --- .../src/Search/Mobile/SearchIndexOverview.css | 2 ++ .../src/Search/Mobile/SearchIndexOverview.js | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/frontend/src/Search/Mobile/SearchIndexOverview.css b/frontend/src/Search/Mobile/SearchIndexOverview.css index c2d9b7abd..4e184bd0a 100644 --- a/frontend/src/Search/Mobile/SearchIndexOverview.css +++ b/frontend/src/Search/Mobile/SearchIndexOverview.css @@ -35,9 +35,11 @@ $hoverScale: 1.05; } .title { + overflow: hidden; width: 85%; font-weight: 500; font-size: 14px; + overflow-wrap: break-word; } .actions { diff --git a/frontend/src/Search/Mobile/SearchIndexOverview.js b/frontend/src/Search/Mobile/SearchIndexOverview.js index 6b1e0ea2a..df9d1e3e7 100644 --- a/frontend/src/Search/Mobile/SearchIndexOverview.js +++ b/frontend/src/Search/Mobile/SearchIndexOverview.js @@ -3,6 +3,7 @@ import React, { Component } from 'react'; import TextTruncate from 'react-text-truncate'; import Label from 'Components/Label'; import IconButton from 'Components/Link/IconButton'; +import Link from 'Components/Link/Link'; import SpinnerIconButton from 'Components/Link/SpinnerIconButton'; import { icons, kinds } from 'Helpers/Props'; import CategoryLabel from 'Search/Table/CategoryLabel'; @@ -71,6 +72,7 @@ class SearchIndexOverview extends Component { render() { const { title, + infoUrl, protocol, downloadUrl, categories, @@ -96,10 +98,16 @@ class SearchIndexOverview extends Component {
- + + + +
From f386ddb80657d7d0f961f1d7ddf58e7379195aed Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 31 Dec 2022 16:17:54 -0600 Subject: [PATCH 0725/2320] Fixed: Sorting on mobile search UI --- frontend/src/Search/Mobile/SearchIndexOverviews.js | 4 +--- frontend/src/Search/Table/SearchIndexItemConnector.js | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/frontend/src/Search/Mobile/SearchIndexOverviews.js b/frontend/src/Search/Mobile/SearchIndexOverviews.js index c8e5d1007..7fadb51e0 100644 --- a/frontend/src/Search/Mobile/SearchIndexOverviews.js +++ b/frontend/src/Search/Mobile/SearchIndexOverviews.js @@ -49,7 +49,7 @@ class SearchIndexOverviews extends Component { this._grid && (prevState.width !== width || prevState.rowHeight !== rowHeight || - hasDifferentItemsOrOrder(prevProps.items, items) + hasDifferentItemsOrOrder(prevProps.items, items, 'guid') ) ) { // recomputeGridSize also forces Grid to discard its cache of rendered cells @@ -93,7 +93,6 @@ class SearchIndexOverviews extends Component { cellRenderer = ({ key, rowIndex, style }) => { const { items, - sortKey, showRelativeDates, shortDateFormat, longDateFormat, @@ -117,7 +116,6 @@ class SearchIndexOverviews extends Component { Date: Fri, 30 Dec 2022 19:51:00 +0200 Subject: [PATCH 0726/2320] Fixed: (RetroFlix) Set 5 days as MST, return 100 results and remove "[REQUESTED]" from title --- .../Indexers/Definitions/RetroFlix.cs | 1 + .../Definitions/SpeedApp/SpeedAppBase.cs | 21 ++++++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs b/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs index ca92f0ddb..50dfad186 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/RetroFlix.cs @@ -14,6 +14,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override string Description => "Private Torrent Tracker for Classic Movies / TV / General Releases"; public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override TimeSpan RateLimit => TimeSpan.FromSeconds(2.1); + protected override int MinimumSeedTime => 432000; // 120 hours public RetroFlix(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger, IIndexerRepository indexerRepository) : base(httpClient, eventAggregator, indexerStatusService, configService, logger, indexerRepository) diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs index ca144bc46..e0569bc09 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs @@ -6,6 +6,7 @@ using System.Net; using System.Net.Http; using System.Net.Mime; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; using FluentValidation; using Newtonsoft.Json; @@ -21,7 +22,6 @@ using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Definitions @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override Encoding Encoding => Encoding.UTF8; public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override IndexerCapabilities Capabilities => SetCapabilities(); - + protected virtual int MinimumSeedTime => 172800; // 48 hours private IIndexerRepository _indexerRepository; public SpeedAppBase(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger, IIndexerRepository indexerRepository) @@ -48,7 +48,7 @@ namespace NzbDrone.Core.Indexers.Definitions public override IParseIndexerResponse GetParser() { - return new SpeedAppParser(Settings, Capabilities.Categories); + return new SpeedAppParser(Settings, Capabilities.Categories, MinimumSeedTime); } protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) @@ -226,7 +226,12 @@ namespace NzbDrone.Core.Indexers.Definitions private IEnumerable GetPagedRequests(string term, int[] categories, string imdbId = null, int? season = null, string episode = null) { - var qc = new NameValueCollection(); + var qc = new NameValueCollection() + { + { "itemsPerPage", "100" }, + { "sort", "torrent.createdAt" }, + { "direction", "desc" } + }; if (imdbId.IsNotNullOrWhiteSpace()) { @@ -271,13 +276,15 @@ namespace NzbDrone.Core.Indexers.Definitions { private readonly SpeedAppSettings _settings; private readonly IndexerCapabilitiesCategories _categories; + private readonly int _minimumSeedTime; public Action, DateTime?> CookiesUpdater { get; set; } - public SpeedAppParser(SpeedAppSettings settings, IndexerCapabilitiesCategories categories) + public SpeedAppParser(SpeedAppSettings settings, IndexerCapabilitiesCategories categories, int minimumSeedTime) { _settings = settings; _categories = categories; + _minimumSeedTime = minimumSeedTime; } public IList ParseResponse(IndexerResponse indexerResponse) @@ -297,7 +304,7 @@ namespace NzbDrone.Core.Indexers.Definitions return jsonResponse.Resource.Select(torrent => new TorrentInfo { Guid = torrent.Id.ToString(), - Title = torrent.Name, + Title = Regex.Replace(torrent.Name, @"(?i:\[REQUESTED\])", "").Trim(' ', '.'), Description = torrent.ShortDescription, Size = torrent.Size, ImdbId = ParseUtil.GetImdbID(torrent.ImdbId).GetValueOrDefault(), @@ -311,7 +318,7 @@ namespace NzbDrone.Core.Indexers.Definitions Seeders = torrent.Seeders, Peers = torrent.Leechers + torrent.Seeders, MinimumRatio = 1, - MinimumSeedTime = 172800, + MinimumSeedTime = _minimumSeedTime, DownloadVolumeFactor = torrent.DownloadVolumeFactor, UploadVolumeFactor = torrent.UploadVolumeFactor, }).ToArray(); From 43f4899324a7e07846bd2219183ab3532c0a433d Mon Sep 17 00:00:00 2001 From: Bogdan Date: Wed, 28 Dec 2022 13:52:45 +0200 Subject: [PATCH 0727/2320] New: (Indexer) Torrent Libble with 2FA and pagination --- .../Indexers/Definitions/Libble.cs | 372 ++++++++++++++++++ 1 file changed, 372 insertions(+) create mode 100644 src/NzbDrone.Core/Indexers/Definitions/Libble.cs diff --git a/src/NzbDrone.Core/Indexers/Definitions/Libble.cs b/src/NzbDrone.Core/Indexers/Definitions/Libble.cs new file mode 100644 index 000000000..f95f93687 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/Definitions/Libble.cs @@ -0,0 +1,372 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using AngleSharp.Html.Parser; +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Settings; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; + +namespace NzbDrone.Core.Indexers.Definitions +{ + internal class Libble : TorrentIndexerBase + { + public override string Name => "Libble"; + public override string[] IndexerUrls => new string[] { "https://libble.me/" }; + public override string Description => "Libble is a Private Torrent Tracker for MUSIC"; + private string LoginUrl => Settings.BaseUrl + "login.php"; + public override string Language => "en-US"; + public override Encoding Encoding => Encoding.UTF8; + public override DownloadProtocol Protocol => DownloadProtocol.Torrent; + public override IndexerPrivacy Privacy => IndexerPrivacy.Private; + public override int PageSize => 50; + public override IndexerCapabilities Capabilities => SetCapabilities(); + + public Libble(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger) + : base(httpClient, eventAggregator, indexerStatusService, configService, logger) + { + } + + public override IIndexerRequestGenerator GetRequestGenerator() + { + return new LibbleRequestGenerator() { Settings = Settings, Capabilities = Capabilities }; + } + + public override IParseIndexerResponse GetParser() + { + return new LibbleParser(Settings, Capabilities.Categories); + } + + protected override async Task DoLogin() + { + var requestBuilder = new HttpRequestBuilder(LoginUrl) + { + Method = HttpMethod.Post, + AllowAutoRedirect = true + }; + + requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15); + + var cookies = Cookies; + + Cookies = null; + var authLoginRequest = requestBuilder + .AddFormParameter("username", Settings.Username) + .AddFormParameter("password", Settings.Password) + .AddFormParameter("code", Settings.TwoFactorAuthCode) + .AddFormParameter("keeplogged", "1") + .AddFormParameter("login", "Login") + .SetHeader("Content-Type", "multipart/form-data") + .Build(); + + var headers = new NameValueCollection + { + { "Referer", LoginUrl } + }; + + authLoginRequest.Headers.Add(headers); + + var response = await ExecuteAuth(authLoginRequest); + + if (CheckIfLoginNeeded(response)) + { + var parser = new HtmlParser(); + var dom = parser.ParseDocument(response.Content); + var errorMessage = dom.QuerySelector("#loginform > .warning")?.TextContent.Trim(); + + throw new IndexerAuthException($"Libble authentication failed. Error: \"{errorMessage}\""); + } + + cookies = response.GetCookies(); + UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30)); + + _logger.Debug("Libble authentication succeeded."); + } + + protected override bool CheckIfLoginNeeded(HttpResponse httpResponse) + { + return !httpResponse.Content.Contains("logout.php"); + } + + private IndexerCapabilities SetCapabilities() + { + var caps = new IndexerCapabilities + { + MusicSearchParams = new List + { + MusicSearchParam.Q, MusicSearchParam.Artist, MusicSearchParam.Album, MusicSearchParam.Label, MusicSearchParam.Year, MusicSearchParam.Genre + } + }; + + caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Audio); + caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.Audio); + caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.AudioVideo); + + return caps; + } + } + + public class LibbleRequestGenerator : IIndexerRequestGenerator + { + public LibbleSettings Settings { get; set; } + public IndexerCapabilities Capabilities { get; set; } + + public LibbleRequestGenerator() + { + } + + private IEnumerable GetPagedRequests(SearchCriteriaBase searchCriteria, NameValueCollection parameters) + { + var term = searchCriteria.SanitizedSearchTerm.Trim(); + + parameters.Add("order_by", "time"); + parameters.Add("order_way", "desc"); + parameters.Add("searchstr", term); + + var queryCats = Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories); + + if (queryCats.Count > 0) + { + foreach (var cat in queryCats) + { + parameters.Add($"filter_cat[{cat}]", "1"); + } + } + + if (searchCriteria.Offset.HasValue && searchCriteria.Limit.HasValue && searchCriteria.Offset > 0 && searchCriteria.Limit > 0) + { + var page = (int)(searchCriteria.Offset / searchCriteria.Limit) + 1; + parameters.Add("page", page.ToString()); + } + + var searchUrl = string.Format("{0}/torrents.php?{1}", Settings.BaseUrl.TrimEnd('/'), parameters.GetQueryString()); + + var request = new IndexerRequest(searchUrl, HttpAccept.Html); + + yield return request; + } + + public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + var parameters = new NameValueCollection(); + + if (searchCriteria.Artist.IsNotNullOrWhiteSpace()) + { + parameters.Add("artistname", searchCriteria.Artist); + } + + if (searchCriteria.Album.IsNotNullOrWhiteSpace()) + { + parameters.Add("groupname", searchCriteria.Album); + } + + if (searchCriteria.Label.IsNotNullOrWhiteSpace()) + { + parameters.Add("recordlabel", searchCriteria.Label); + } + + if (searchCriteria.Year.HasValue) + { + parameters.Add("year", searchCriteria.Year.ToString()); + } + + if (searchCriteria.Genre.IsNotNullOrWhiteSpace()) + { + parameters.Add("taglist", searchCriteria.Genre); + } + + pageableRequests.Add(GetPagedRequests(searchCriteria, parameters)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) + { + var pageableRequests = new IndexerPageableRequestChain(); + var parameters = new NameValueCollection(); + + pageableRequests.Add(GetPagedRequests(searchCriteria, parameters)); + + return pageableRequests; + } + + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + { + return new IndexerPageableRequestChain(); + } + + public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) + { + return new IndexerPageableRequestChain(); + } + + public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) + { + return new IndexerPageableRequestChain(); + } + + public Func> GetCookies { get; set; } + public Action, DateTime?> CookiesUpdater { get; set; } + } + + public class LibbleParser : IParseIndexerResponse + { + private readonly LibbleSettings _settings; + private readonly IndexerCapabilitiesCategories _categories; + + public LibbleParser(LibbleSettings settings, IndexerCapabilitiesCategories categories) + { + _settings = settings; + _categories = categories; + } + + public IList ParseResponse(IndexerResponse indexerResponse) + { + var torrentInfos = new List(); + + var parser = new HtmlParser(); + var doc = parser.ParseDocument(indexerResponse.Content); + var rows = doc.QuerySelectorAll("table#torrent_table > tbody > tr.group:has(strong > a[href*=\"torrents.php?id=\"])"); + + var releaseYearRegex = new Regex(@"\[(\d{4})\]$"); + + foreach (var row in rows) + { + var albumLinkNode = row.QuerySelector("strong > a[href*=\"torrents.php?id=\"]"); + var groupId = ParseUtil.GetArgumentFromQueryString(albumLinkNode.GetAttribute("href"), "id"); + + var artistsNodes = row.QuerySelectorAll("strong > a[href*=\"artist.php?id=\"]"); + + var releaseArtist = "Various Artists"; + if (artistsNodes.Count() > 0) + { + releaseArtist = artistsNodes.Select(artist => artist.TextContent.Trim()).ToList().Join(", "); + } + + var releaseAlbumName = row.QuerySelector("strong > a[href*=\"torrents.php?id=\"]")?.TextContent.Trim(); + + var title = row.QuerySelector("td:nth-child(4) > strong")?.TextContent.Trim(); + var releaseAlbumYear = releaseYearRegex.Match(title); + + var releaseDescription = row.QuerySelector("div.tags")?.TextContent.Trim(); + var releaseThumbnailUrl = row.QuerySelector(".thumbnail")?.GetAttribute("title").Trim(); + + var releaseGenres = new List(); + if (!string.IsNullOrEmpty(releaseDescription)) + { + releaseGenres = releaseGenres.Union(releaseDescription.Split(',').Select(tag => tag.Trim()).ToList()).ToList(); + } + + var cat = row.QuerySelector("td.cats_col div.cat_icon")?.GetAttribute("class").Trim(); + + var matchCategory = Regex.Match(cat, @"\bcats_(.*?)\b"); + if (matchCategory.Success) + { + cat = matchCategory.Groups[1].Value.Trim(); + } + + var category = new List + { + cat switch + { + "music" => NewznabStandardCategory.Audio, + "libblemixtapes" => NewznabStandardCategory.Audio, + "musicvideos" => NewznabStandardCategory.AudioVideo, + _ => NewznabStandardCategory.Other, + } + }; + + var releaseRows = doc.QuerySelectorAll(string.Format("table#torrent_table > tbody > tr.group_torrent.groupid_{0}:has(a[href*=\"torrents.php?id=\"])", groupId)); + + foreach (var releaseRow in releaseRows) + { + var release = new TorrentInfo(); + + var detailsNode = releaseRow.QuerySelector("a[href^=\"torrents.php?id=\"]"); + var downloadLink = _settings.BaseUrl + releaseRow.QuerySelector("a[href^=\"torrents.php?action=download&id=\"]").GetAttribute("href").Trim(); + + var releaseTags = detailsNode.FirstChild.TextContent.Trim(' ', '/'); + + release.Title = string.Format("{0} - {1} {2} {3}", releaseArtist, releaseAlbumName, releaseAlbumYear, releaseTags).Trim(); + release.Categories = category; + release.Description = releaseDescription; + release.Genres = releaseGenres; + release.PosterUrl = releaseThumbnailUrl; + + release.InfoUrl = _settings.BaseUrl + detailsNode.GetAttribute("href").Trim(); + release.DownloadUrl = downloadLink; + release.Guid = release.InfoUrl; + + release.Size = ParseUtil.GetBytes(releaseRow.QuerySelector("td:nth-child(4)").TextContent.Trim()); + release.Files = ParseUtil.CoerceInt(releaseRow.QuerySelector("td:nth-child(2)").TextContent); + release.Grabs = ParseUtil.CoerceInt(releaseRow.QuerySelector("td:nth-child(5)").TextContent); + release.Seeders = ParseUtil.CoerceInt(releaseRow.QuerySelector("td:nth-child(6)").TextContent); + release.Peers = release.Seeders + ParseUtil.CoerceInt(releaseRow.QuerySelector("td:nth-child(7)").TextContent); + + release.MinimumRatio = 1; + release.MinimumSeedTime = 259200; // 72 hours + + try + { + release.PublishDate = DateTime.ParseExact( + releaseRow.QuerySelector("td:nth-child(3) > span[title]").GetAttribute("title").Trim(), + "MMM dd yyyy, HH:mm", + CultureInfo.InvariantCulture, + DateTimeStyles.AssumeUniversal); + } + catch (Exception) + { + } + + switch (releaseRow.QuerySelector("a[href^=\"torrents.php?id=\"] strong")?.TextContent.Trim()) + { + case "Neutral!": + release.DownloadVolumeFactor = 0; + release.UploadVolumeFactor = 0; + break; + case "Freeleech!": + release.DownloadVolumeFactor = 0; + release.UploadVolumeFactor = 1; + break; + default: + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; + break; + } + + torrentInfos.Add(release); + } + } + + return torrentInfos.ToArray(); + } + + public Action, DateTime?> CookiesUpdater { get; set; } + } + + public class LibbleSettings : UserPassTorrentBaseSettings + { + public LibbleSettings() + { + TwoFactorAuthCode = ""; + } + + [FieldDefinition(4, Label = "2FA code", Type = FieldType.Textbox, HelpText = "Only fill in the 2FA code box if you have enabled 2FA on the Libble Web Site. Otherwise just leave it empty.")] + public string TwoFactorAuthCode { get; set; } + } +} From 858415b037b61fc15a1881e34f63b55711b3adeb Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 31 Dec 2022 16:36:52 -0600 Subject: [PATCH 0728/2320] Fixed: (Cardigann) Query string gets first letter removed in request handling --- .../Definitions/Cardigann/CardigannRequestGenerator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index a298c1bda..cbf777533 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -718,8 +718,8 @@ namespace NzbDrone.Core.Indexers.Cardigann { if (!requestLinkStr.Contains("?")) { - // TODO Need Encoding here if we add it back - requestLinkStr += "?" + queryCollection.GetQueryString(separator: request.Queryseparator).Substring(1); + requestLinkStr += "?"; + requestLinkStr += queryCollection.GetQueryString(_encoding, separator: request.Queryseparator); } else { From 4914fcd5dfb26b0c6181c40fbd8baa6afc7c5c5f Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 31 Dec 2022 17:03:27 -0600 Subject: [PATCH 0729/2320] Fixed: (UI) Category is None in history if only search by sub category --- frontend/src/Indexer/Index/Table/CapabilitiesLabel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Indexer/Index/Table/CapabilitiesLabel.js b/frontend/src/Indexer/Index/Table/CapabilitiesLabel.js index e1a4bb4f1..5ca237a8a 100644 --- a/frontend/src/Indexer/Index/Table/CapabilitiesLabel.js +++ b/frontend/src/Indexer/Index/Table/CapabilitiesLabel.js @@ -14,7 +14,7 @@ function CapabilitiesLabel(props) { let filteredList = categories.filter((item) => item.id < 100000); if (categoryFilter.length > 0) { - filteredList = filteredList.filter((item) => categoryFilter.includes(item.id)); + filteredList = filteredList.filter((item) => categoryFilter.includes(item.id) || (item.subCategories && item.subCategories.some((r) => categoryFilter.includes(r.id)))); } const nameList = filteredList.map((item) => item.name).sort(); From 38ab533272b1464fd9001f3f6df282d4378cd71f Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Tue, 20 Dec 2022 17:07:11 -0800 Subject: [PATCH 0730/2320] Fixed: Only log /proc/mounts exception once per process --- src/NzbDrone.Mono/Disk/ProcMountProvider.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Mono/Disk/ProcMountProvider.cs b/src/NzbDrone.Mono/Disk/ProcMountProvider.cs index f95f2a88c..5900d203c 100644 --- a/src/NzbDrone.Mono/Disk/ProcMountProvider.cs +++ b/src/NzbDrone.Mono/Disk/ProcMountProvider.cs @@ -27,6 +27,8 @@ namespace NzbDrone.Mono.Disk private static Dictionary _fileSystems; + private bool _hasLoggedProcMountFailure = false; + public ProcMountProvider(Logger logger) { _logger = logger; @@ -45,7 +47,11 @@ namespace NzbDrone.Mono.Disk } catch (Exception ex) { - _logger.Debug(ex, "Failed to retrieve mounts from {0}", PROC_MOUNTS_FILENAME); + if (!_hasLoggedProcMountFailure) + { + _logger.Debug(ex, "Failed to retrieve mounts from {0}", PROC_MOUNTS_FILENAME); + _hasLoggedProcMountFailure = true; + } } return new List(); From 5b82decc316f25aa263fb2bbe4e595a796988e0d Mon Sep 17 00:00:00 2001 From: Colin Gagnaire Date: Sat, 17 Dec 2022 03:37:21 +0100 Subject: [PATCH 0731/2320] New: Add support for native Freebox Download Client --- .../FreeboxDownloadEncoding.cs | 27 ++ .../FreeboxDownloadException.cs | 10 + .../FreeboxDownloadPriority.cs | 8 + .../FreeboxDownload/FreeboxDownloadProxy.cs | 271 ++++++++++++++++++ .../FreeboxDownloadSettings.cs | 84 ++++++ .../Responses/FreeboxDownloadConfiguration.cs | 21 ++ .../Responses/FreeboxDownloadTask.cs | 137 +++++++++ .../FreeboxDownload/Responses/FreeboxLogin.cs | 18 ++ .../Responses/FreeboxResponse.cs | 69 +++++ .../FreeboxDownload/TorrentFreeboxDownload.cs | 137 +++++++++ 10 files changed, 782 insertions(+) create mode 100644 src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadEncoding.cs create mode 100644 src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadException.cs create mode 100644 src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadPriority.cs create mode 100644 src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadProxy.cs create mode 100644 src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadSettings.cs create mode 100644 src/NzbDrone.Core/Download/Clients/FreeboxDownload/Responses/FreeboxDownloadConfiguration.cs create mode 100644 src/NzbDrone.Core/Download/Clients/FreeboxDownload/Responses/FreeboxDownloadTask.cs create mode 100644 src/NzbDrone.Core/Download/Clients/FreeboxDownload/Responses/FreeboxLogin.cs create mode 100644 src/NzbDrone.Core/Download/Clients/FreeboxDownload/Responses/FreeboxResponse.cs create mode 100644 src/NzbDrone.Core/Download/Clients/FreeboxDownload/TorrentFreeboxDownload.cs diff --git a/src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadEncoding.cs b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadEncoding.cs new file mode 100644 index 000000000..0e12570aa --- /dev/null +++ b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadEncoding.cs @@ -0,0 +1,27 @@ +namespace NzbDrone.Core.Download.Clients.FreeboxDownload +{ + public static class EncodingForBase64 + { + public static string EncodeBase64(this string text) + { + if (text == null) + { + return null; + } + + byte[] textAsBytes = System.Text.Encoding.UTF8.GetBytes(text); + return System.Convert.ToBase64String(textAsBytes); + } + + public static string DecodeBase64(this string encodedText) + { + if (encodedText == null) + { + return null; + } + + byte[] textAsBytes = System.Convert.FromBase64String(encodedText); + return System.Text.Encoding.UTF8.GetString(textAsBytes); + } + } +} diff --git a/src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadException.cs b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadException.cs new file mode 100644 index 000000000..38fcf8047 --- /dev/null +++ b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadException.cs @@ -0,0 +1,10 @@ +namespace NzbDrone.Core.Download.Clients.FreeboxDownload +{ + public class FreeboxDownloadException : DownloadClientException + { + public FreeboxDownloadException(string message) + : base(message) + { + } + } +} diff --git a/src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadPriority.cs b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadPriority.cs new file mode 100644 index 000000000..ee16d70d6 --- /dev/null +++ b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadPriority.cs @@ -0,0 +1,8 @@ +namespace NzbDrone.Core.Download.Clients.FreeboxDownload +{ + public enum FreeboxDownloadPriority + { + Last = 0, + First = 1 + } +} diff --git a/src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadProxy.cs b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadProxy.cs new file mode 100644 index 000000000..1c40a3832 --- /dev/null +++ b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadProxy.cs @@ -0,0 +1,271 @@ +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Security.Cryptography; +using NLog; +using NzbDrone.Common.Cache; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Download.Clients.FreeboxDownload.Responses; + +namespace NzbDrone.Core.Download.Clients.FreeboxDownload +{ + public interface IFreeboxDownloadProxy + { + void Authenticate(FreeboxDownloadSettings settings); + string AddTaskFromUrl(string url, string directory, bool addPaused, bool addFirst, FreeboxDownloadSettings settings); + string AddTaskFromFile(string fileName, byte[] fileContent, string directory, bool addPaused, bool addFirst, FreeboxDownloadSettings settings); + void DeleteTask(string id, bool deleteData, FreeboxDownloadSettings settings); + FreeboxDownloadConfiguration GetDownloadConfiguration(FreeboxDownloadSettings settings); + List GetTasks(FreeboxDownloadSettings settings); + } + + public class FreeboxDownloadProxy : IFreeboxDownloadProxy + { + private readonly IHttpClient _httpClient; + private readonly Logger _logger; + private ICached _authSessionTokenCache; + + public FreeboxDownloadProxy(ICacheManager cacheManager, IHttpClient httpClient, Logger logger) + { + _httpClient = httpClient; + _logger = logger; + _authSessionTokenCache = cacheManager.GetCache(GetType(), "authSessionToken"); + } + + public void Authenticate(FreeboxDownloadSettings settings) + { + var request = BuildRequest(settings).Resource("/login").Build(); + + var response = ProcessRequest(request, settings); + + if (response.Result.LoggedIn == false) + { + throw new DownloadClientAuthenticationException("Not logged"); + } + } + + public string AddTaskFromUrl(string url, string directory, bool addPaused, bool addFirst, FreeboxDownloadSettings settings) + { + var request = BuildRequest(settings).Resource("/downloads/add").Post(); + request.Headers.ContentType = "application/x-www-form-urlencoded"; + + request.AddFormParameter("download_url", System.Web.HttpUtility.UrlPathEncode(url)); + + if (!directory.IsNullOrWhiteSpace()) + { + request.AddFormParameter("download_dir", directory); + } + + var response = ProcessRequest(request.Build(), settings); + + SetTorrentSettings(response.Result.Id, addPaused, addFirst, settings); + + return response.Result.Id; + } + + public string AddTaskFromFile(string fileName, byte[] fileContent, string directory, bool addPaused, bool addFirst, FreeboxDownloadSettings settings) + { + var request = BuildRequest(settings).Resource("/downloads/add").Post(); + + request.AddFormUpload("download_file", fileName, fileContent, "multipart/form-data"); + + if (directory.IsNotNullOrWhiteSpace()) + { + request.AddFormParameter("download_dir", directory); + } + + var response = ProcessRequest(request.Build(), settings); + + SetTorrentSettings(response.Result.Id, addPaused, addFirst, settings); + + return response.Result.Id; + } + + public void DeleteTask(string id, bool deleteData, FreeboxDownloadSettings settings) + { + var uri = "/downloads/" + id; + + if (deleteData == true) + { + uri += "/erase"; + } + + var request = BuildRequest(settings).Resource(uri).Build(); + + request.Method = HttpMethod.Delete; + + ProcessRequest(request, settings); + } + + public FreeboxDownloadConfiguration GetDownloadConfiguration(FreeboxDownloadSettings settings) + { + var request = BuildRequest(settings).Resource("/downloads/config/").Build(); + + return ProcessRequest(request, settings).Result; + } + + public List GetTasks(FreeboxDownloadSettings settings) + { + var request = BuildRequest(settings).Resource("/downloads/").Build(); + + return ProcessRequest>(request, settings).Result; + } + + private static string BuildCachedHeaderKey(FreeboxDownloadSettings settings) + { + return $"{settings.Host}:{settings.AppId}:{settings.AppToken}"; + } + + private void SetTorrentSettings(string id, bool addPaused, bool addFirst, FreeboxDownloadSettings settings) + { + var request = BuildRequest(settings).Resource("/downloads/" + id).Build(); + + request.Method = HttpMethod.Put; + + var body = new Dictionary { }; + + if (addPaused) + { + body.Add("status", FreeboxDownloadTaskStatus.Stopped.ToString().ToLower()); + } + + if (addFirst) + { + body.Add("queue_pos", "1"); + } + + if (body.Count == 0) + { + return; + } + + request.SetContent(body.ToJson()); + + ProcessRequest(request, settings); + } + + private string GetSessionToken(HttpRequestBuilder requestBuilder, FreeboxDownloadSettings settings, bool force = false) + { + var sessionToken = _authSessionTokenCache.Find(BuildCachedHeaderKey(settings)); + + if (sessionToken == null || force) + { + _authSessionTokenCache.Remove(BuildCachedHeaderKey(settings)); + + _logger.Debug($"Client needs a new Session Token to reach the API with App ID '{settings.AppId}'"); + + // Obtaining a Session Token (from official documentation): + // To protect the app_token secret, it will never be used directly to authenticate the + // application, instead the API will provide a challenge the app will combine to its + // app_token to open a session and get a session_token. + // The validity of the session_token is limited in time and the app will have to renew + // this session_token once in a while. + + // Retrieving the 'challenge' value (it changes frequently and have a limited time validity) + // needed to build password + var challengeRequest = requestBuilder.Resource("/login").Build(); + challengeRequest.Method = HttpMethod.Get; + + var challenge = ProcessRequest(challengeRequest, settings).Result.Challenge; + + // The password is computed using the 'challenge' value and the 'app_token' ('App Token' setting) + var enc = System.Text.Encoding.ASCII; + var hmac = new HMACSHA1(enc.GetBytes(settings.AppToken)); + hmac.Initialize(); + var buffer = enc.GetBytes(challenge); + var password = System.BitConverter.ToString(hmac.ComputeHash(buffer)).Replace("-", "").ToLower(); + + // Both 'app_id' ('App ID' setting) and computed password are set to get a Session Token + var sessionRequest = requestBuilder.Resource("/login/session").Post().Build(); + var body = new Dictionary + { + { "app_id", settings.AppId }, + { "password", password } + }; + sessionRequest.SetContent(body.ToJson()); + + sessionToken = ProcessRequest(sessionRequest, settings).Result.SessionToken; + + _authSessionTokenCache.Set(BuildCachedHeaderKey(settings), sessionToken); + + _logger.Debug($"New Session Token stored in cache for App ID '{settings.AppId}', ready to reach API"); + } + + return sessionToken; + } + + private HttpRequestBuilder BuildRequest(FreeboxDownloadSettings settings, bool authentication = true) + { + var requestBuilder = new HttpRequestBuilder(settings.UseSsl, settings.Host, settings.Port, settings.ApiUrl) + { + LogResponseContent = true + }; + + requestBuilder.Headers.ContentType = "application/json"; + + if (authentication == true) + { + requestBuilder.SetHeader("X-Fbx-App-Auth", GetSessionToken(requestBuilder, settings)); + } + + return requestBuilder; + } + + private FreeboxResponse ProcessRequest(HttpRequest request, FreeboxDownloadSettings settings) + { + request.LogResponseContent = true; + request.SuppressHttpError = true; + + HttpResponse response; + + try + { + response = _httpClient.Execute(request); + } + catch (HttpRequestException ex) + { + throw new DownloadClientUnavailableException($"Unable to reach Freebox API. Verify 'Host', 'Port' or 'Use SSL' settings. (Error: {ex.Message})", ex); + } + catch (WebException ex) + { + throw new DownloadClientUnavailableException("Unable to connect to Freebox API, please check your settings", ex); + } + + if (response.StatusCode == HttpStatusCode.Forbidden || response.StatusCode == HttpStatusCode.Unauthorized) + { + _authSessionTokenCache.Remove(BuildCachedHeaderKey(settings)); + + var responseContent = Json.Deserialize>(response.Content); + + var msg = $"Authentication to Freebox API failed. Reason: {responseContent.GetErrorDescription()}"; + _logger.Error(msg); + throw new DownloadClientAuthenticationException(msg); + } + else if (response.StatusCode == HttpStatusCode.NotFound) + { + throw new FreeboxDownloadException("Unable to reach Freebox API. Verify 'API URL' setting for base URL and version."); + } + else if (response.StatusCode == HttpStatusCode.OK) + { + var responseContent = Json.Deserialize>(response.Content); + + if (responseContent.Success) + { + return responseContent; + } + else + { + var msg = $"Freebox API returned error: {responseContent.GetErrorDescription()}"; + _logger.Error(msg); + throw new DownloadClientException(msg); + } + } + else + { + throw new DownloadClientException("Unable to connect to Freebox, please check your settings."); + } + } + } +} diff --git a/src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadSettings.cs b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadSettings.cs new file mode 100644 index 000000000..3810f8e7e --- /dev/null +++ b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/FreeboxDownloadSettings.cs @@ -0,0 +1,84 @@ +using System.Text.RegularExpressions; +using FluentValidation; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.Validation; +using NzbDrone.Core.Validation.Paths; + +namespace NzbDrone.Core.Download.Clients.FreeboxDownload +{ + public class FreeboxDownloadSettingsValidator : AbstractValidator + { + public FreeboxDownloadSettingsValidator() + { + RuleFor(c => c.Host).ValidHost(); + RuleFor(c => c.Port).InclusiveBetween(1, 65535); + RuleFor(c => c.ApiUrl).NotEmpty() + .WithMessage("'API URL' must not be empty."); + RuleFor(c => c.ApiUrl).ValidUrlBase(); + RuleFor(c => c.AppId).NotEmpty() + .WithMessage("'App ID' must not be empty."); + RuleFor(c => c.AppToken).NotEmpty() + .WithMessage("'App Token' must not be empty."); + RuleFor(c => c.Category).Matches(@"^\.?[-a-z]*$", RegexOptions.IgnoreCase) + .WithMessage("Allowed characters a-z and -"); + RuleFor(c => c.DestinationDirectory).IsValidPath() + .When(c => c.DestinationDirectory.IsNotNullOrWhiteSpace()); + RuleFor(c => c.DestinationDirectory).Empty() + .When(c => c.Category.IsNotNullOrWhiteSpace()) + .WithMessage("Cannot use 'Category' and 'Destination Directory' at the same time."); + RuleFor(c => c.Category).Empty() + .When(c => c.DestinationDirectory.IsNotNullOrWhiteSpace()) + .WithMessage("Cannot use 'Category' and 'Destination Directory' at the same time."); + } + } + + public class FreeboxDownloadSettings : IProviderConfig + { + private static readonly FreeboxDownloadSettingsValidator Validator = new FreeboxDownloadSettingsValidator(); + + public FreeboxDownloadSettings() + { + Host = "mafreebox.freebox.fr"; + Port = 443; + UseSsl = true; + ApiUrl = "/api/v1/"; + } + + [FieldDefinition(0, Label = "Host", Type = FieldType.Textbox, HelpText = "Hostname or host IP address of the Freebox, defaults to 'mafreebox.freebox.fr' (will only work if on same network)")] + public string Host { get; set; } + + [FieldDefinition(1, Label = "Port", Type = FieldType.Textbox, HelpText = "Port used to access Freebox interface, defaults to '443'")] + public int Port { get; set; } + + [FieldDefinition(2, Label = "Use SSL", Type = FieldType.Checkbox, HelpText = "Use secured connection when connecting to Freebox API")] + public bool UseSsl { get; set; } + + [FieldDefinition(3, Label = "API URL", Type = FieldType.Textbox, Advanced = true, HelpText = "Define Freebox API base URL with API version, eg http://[host]:[port]/[api_base_url]/[api_version]/, defaults to '/api/v1/'")] + public string ApiUrl { get; set; } + + [FieldDefinition(4, Label = "App ID", Type = FieldType.Textbox, HelpText = "App ID given when creating access to Freebox API (ie 'app_id')")] + public string AppId { get; set; } + + [FieldDefinition(5, Label = "App Token", Type = FieldType.Password, Privacy = PrivacyLevel.Password, HelpText = "App token retrieved when creating access to Freebox API (ie 'app_token')")] + public string AppToken { get; set; } + + [FieldDefinition(6, Label = "Destination Directory", Type = FieldType.Textbox, Advanced = true, HelpText = "Optional location to put downloads in, leave blank to use the default Freebox download location")] + public string DestinationDirectory { get; set; } + + [FieldDefinition(7, Label = "Default Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Prowlarr avoids conflicts with unrelated non-Prowlarr downloads (will create a [category] subdirectory in the output directory)")] + public string Category { get; set; } + + [FieldDefinition(8, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(FreeboxDownloadPriority), HelpText = "Priority to use when grabbing")] + public int Priority { get; set; } + + [FieldDefinition(10, Label = "Add Paused", Type = FieldType.Checkbox)] + public bool AddPaused { get; set; } + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} diff --git a/src/NzbDrone.Core/Download/Clients/FreeboxDownload/Responses/FreeboxDownloadConfiguration.cs b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/Responses/FreeboxDownloadConfiguration.cs new file mode 100644 index 000000000..23850c651 --- /dev/null +++ b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/Responses/FreeboxDownloadConfiguration.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json; + +namespace NzbDrone.Core.Download.Clients.FreeboxDownload.Responses +{ + public class FreeboxDownloadConfiguration + { + [JsonProperty(PropertyName = "download_dir")] + public string DownloadDirectory { get; set; } + public string DecodedDownloadDirectory + { + get + { + return DownloadDirectory.DecodeBase64(); + } + set + { + DownloadDirectory = value.EncodeBase64(); + } + } + } +} diff --git a/src/NzbDrone.Core/Download/Clients/FreeboxDownload/Responses/FreeboxDownloadTask.cs b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/Responses/FreeboxDownloadTask.cs new file mode 100644 index 000000000..faf4f646a --- /dev/null +++ b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/Responses/FreeboxDownloadTask.cs @@ -0,0 +1,137 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using NzbDrone.Common.Serializer; + +namespace NzbDrone.Core.Download.Clients.FreeboxDownload.Responses +{ + public enum FreeboxDownloadTaskType + { + Bt, + Nzb, + Http, + Ftp + } + + public enum FreeboxDownloadTaskStatus + { + Unknown, + Stopped, + Queued, + Starting, + Downloading, + Stopping, + Error, + Done, + Checking, + Repairing, + Extracting, + Seeding, + Retry + } + + public enum FreeboxDownloadTaskIoPriority + { + Low, + Normal, + High + } + + public class FreeboxDownloadTask + { + private static readonly Dictionary Descriptions; + + [JsonProperty(PropertyName = "id")] + public string Id { get; set; } + [JsonProperty(PropertyName = "name")] + public string Name { get; set; } + [JsonProperty(PropertyName = "download_dir")] + public string DownloadDirectory { get; set; } + public string DecodedDownloadDirectory + { + get + { + return DownloadDirectory.DecodeBase64(); + } + set + { + DownloadDirectory = value.EncodeBase64(); + } + } + + [JsonProperty(PropertyName = "info_hash")] + public string InfoHash { get; set; } + [JsonProperty(PropertyName = "queue_pos")] + public int QueuePosition { get; set; } + [JsonConverter(typeof(UnderscoreStringEnumConverter), FreeboxDownloadTaskStatus.Unknown)] + public FreeboxDownloadTaskStatus Status { get; set; } + [JsonProperty(PropertyName = "eta")] + public long Eta { get; set; } + [JsonProperty(PropertyName = "error")] + public string Error { get; set; } + [JsonProperty(PropertyName = "type")] + public string Type { get; set; } + [JsonProperty(PropertyName = "io_priority")] + public string IoPriority { get; set; } + [JsonProperty(PropertyName = "stop_ratio")] + public long StopRatio { get; set; } + [JsonProperty(PropertyName = "piece_length")] + public long PieceLength { get; set; } + [JsonProperty(PropertyName = "created_ts")] + public long CreatedTimestamp { get; set; } + [JsonProperty(PropertyName = "size")] + public long Size { get; set; } + [JsonProperty(PropertyName = "rx_pct")] + public long ReceivedPrct { get; set; } + [JsonProperty(PropertyName = "rx_bytes")] + public long ReceivedBytes { get; set; } + [JsonProperty(PropertyName = "rx_rate")] + public long ReceivedRate { get; set; } + [JsonProperty(PropertyName = "tx_pct")] + public long TransmittedPrct { get; set; } + [JsonProperty(PropertyName = "tx_bytes")] + public long TransmittedBytes { get; set; } + [JsonProperty(PropertyName = "tx_rate")] + public long TransmittedRate { get; set; } + + static FreeboxDownloadTask() + { + Descriptions = new Dictionary + { + { "internal", "Internal error." }, + { "disk_full", "The disk is full." }, + { "unknown", "Unknown error." }, + { "parse_error", "Parse error." }, + { "unknown_host", "Unknown host." }, + { "timeout", "Timeout." }, + { "bad_authentication", "Invalid credentials." }, + { "connection_refused", "Remote host refused connection." }, + { "bt_tracker_error", "Unable to announce on tracker." }, + { "bt_missing_files", "Missing torrent files." }, + { "bt_file_error", "Error accessing torrent files." }, + { "missing_ctx_file", "Error accessing task context file." }, + { "nzb_no_group", "Cannot find the requested group on server." }, + { "nzb_not_found", "Article not fount on the server." }, + { "nzb_invalid_crc", "Invalid article CRC." }, + { "nzb_invalid_size", "Invalid article size." }, + { "nzb_invalid_filename", "Invalid filename." }, + { "nzb_open_failed", "Error opening." }, + { "nzb_write_failed", "Error writing." }, + { "nzb_missing_size", "Missing article size." }, + { "nzb_decode_error", "Article decoding error." }, + { "nzb_missing_segments", "Missing article segments." }, + { "nzb_error", "Other nzb error." }, + { "nzb_authentication_required", "Nzb server need authentication." } + }; + } + + public string GetErrorDescription() + { + if (Descriptions.ContainsKey(Error)) + { + return Descriptions[Error]; + } + + return $"{Error} - Unknown error"; + } + } +} diff --git a/src/NzbDrone.Core/Download/Clients/FreeboxDownload/Responses/FreeboxLogin.cs b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/Responses/FreeboxLogin.cs new file mode 100644 index 000000000..bfb01f050 --- /dev/null +++ b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/Responses/FreeboxLogin.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace NzbDrone.Core.Download.Clients.FreeboxDownload.Responses +{ + public class FreeboxLogin + { + [JsonProperty(PropertyName = "logged_in")] + public bool LoggedIn { get; set; } + [JsonProperty(PropertyName = "challenge")] + public string Challenge { get; set; } + [JsonProperty(PropertyName = "password_salt")] + public string PasswordSalt { get; set; } + [JsonProperty(PropertyName = "password_set")] + public bool PasswordSet { get; set; } + [JsonProperty(PropertyName = "session_token")] + public string SessionToken { get; set; } + } +} diff --git a/src/NzbDrone.Core/Download/Clients/FreeboxDownload/Responses/FreeboxResponse.cs b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/Responses/FreeboxResponse.cs new file mode 100644 index 000000000..5aff5b68a --- /dev/null +++ b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/Responses/FreeboxResponse.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace NzbDrone.Core.Download.Clients.FreeboxDownload.Responses +{ + public class FreeboxResponse + { + private static readonly Dictionary Descriptions; + + [JsonProperty(PropertyName = "success")] + public bool Success { get; set; } + [JsonProperty(PropertyName = "msg")] + public string Message { get; set; } + [JsonProperty(PropertyName = "error_code")] + public string ErrorCode { get; set; } + [JsonProperty(PropertyName = "result")] + public T Result { get; set; } + + static FreeboxResponse() + { + Descriptions = new Dictionary + { + // Common errors + { "invalid_request", "Your request is invalid." }, + { "invalid_api_version", "Invalid API base url or unknown API version." }, + { "internal_error", "Internal error." }, + + // Login API errors + { "auth_required", "Invalid session token, or no session token sent." }, + { "invalid_token", "The app token you are trying to use is invalid or has been revoked." }, + { "pending_token", "The app token you are trying to use has not been validated by user yet." }, + { "insufficient_rights", "Your app permissions does not allow accessing this API." }, + { "denied_from_external_ip", "You are trying to get an app_token from a remote IP." }, + { "ratelimited", "Too many auth error have been made from your IP." }, + { "new_apps_denied", "New application token request has been disabled." }, + { "apps_denied", "API access from apps has been disabled." }, + + // Download API errors + { "task_not_found", "No task was found with the given id." }, + { "invalid_operation", "Attempt to perform an invalid operation." }, + { "invalid_file", "Error with the download file (invalid format ?)." }, + { "invalid_url", "URL is invalid." }, + { "not_implemented", "Method not implemented." }, + { "out_of_memory", "No more memory available to perform the requested action." }, + { "invalid_task_type", "The task type is invalid." }, + { "hibernating", "The downloader is hibernating." }, + { "need_bt_stopped_done", "This action is only valid for Bittorrent task in stopped or done state." }, + { "bt_tracker_not_found", "Attempt to access an invalid tracker object." }, + { "too_many_tasks", "Too many tasks." }, + { "invalid_address", "Invalid peer address." }, + { "port_conflict", "Port conflict when setting config." }, + { "invalid_priority", "Invalid priority." }, + { "ctx_file_error", "Failed to initialize task context file (need to check disk)." }, + { "exists", "Same task already exists." }, + { "port_outside_range", "Incoming port is not available for this customer." } + }; + } + + public string GetErrorDescription() + { + if (Descriptions.ContainsKey(ErrorCode)) + { + return Descriptions[ErrorCode]; + } + + return $"{ErrorCode} - Unknown error"; + } + } +} diff --git a/src/NzbDrone.Core/Download/Clients/FreeboxDownload/TorrentFreeboxDownload.cs b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/TorrentFreeboxDownload.cs new file mode 100644 index 000000000..8e9ce8951 --- /dev/null +++ b/src/NzbDrone.Core/Download/Clients/FreeboxDownload/TorrentFreeboxDownload.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using FluentValidation.Results; +using NLog; +using NzbDrone.Common.Disk; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Download.Clients.FreeboxDownload.Responses; +using NzbDrone.Core.Parser.Model; + +namespace NzbDrone.Core.Download.Clients.FreeboxDownload +{ + public class TorrentFreeboxDownload : TorrentClientBase + { + private readonly IFreeboxDownloadProxy _proxy; + + public TorrentFreeboxDownload(IFreeboxDownloadProxy proxy, + ITorrentFileInfoReader torrentFileInfoReader, + IHttpClient httpClient, + IConfigService configService, + IDiskProvider diskProvider, + Logger logger) + : base(torrentFileInfoReader, httpClient, configService, diskProvider, logger) + { + _proxy = proxy; + } + + public override string Name => "Freebox Download"; + + public override bool SupportsCategories => true; + + protected IEnumerable GetTorrents() + { + return _proxy.GetTasks(Settings).Where(v => v.Type.ToLower() == FreeboxDownloadTaskType.Bt.ToString().ToLower()); + } + + protected override string AddFromMagnetLink(ReleaseInfo release, string hash, string magnetLink) + { + return _proxy.AddTaskFromUrl(magnetLink, + GetDownloadDirectory(release).EncodeBase64(), + ToBePaused(), + ToBeQueuedFirst(), + Settings); + } + + protected override string AddFromTorrentFile(ReleaseInfo release, string hash, string filename, byte[] fileContent) + { + return _proxy.AddTaskFromFile(filename, + fileContent, + GetDownloadDirectory(release).EncodeBase64(), + ToBePaused(), + ToBeQueuedFirst(), + Settings); + } + + protected override string AddFromTorrentLink(ReleaseInfo release, string hash, string torrentLink) + { + return _proxy.AddTaskFromUrl(torrentLink, + GetDownloadDirectory(release).EncodeBase64(), + ToBePaused(), + ToBeQueuedFirst(), + Settings); + } + + protected override void Test(List failures) + { + try + { + _proxy.Authenticate(Settings); + } + catch (DownloadClientUnavailableException ex) + { + failures.Add(new ValidationFailure("Host", ex.Message)); + failures.Add(new ValidationFailure("Port", ex.Message)); + } + catch (DownloadClientAuthenticationException ex) + { + failures.Add(new ValidationFailure("AppId", ex.Message)); + failures.Add(new ValidationFailure("AppToken", ex.Message)); + } + catch (FreeboxDownloadException ex) + { + failures.Add(new ValidationFailure("ApiUrl", ex.Message)); + } + } + + protected override void ValidateCategories(List failures) + { + base.ValidateCategories(failures); + + foreach (var label in Categories) + { + if (!Regex.IsMatch(label.ClientCategory, "^\\.?[-a-z]*$")) + { + failures.AddIfNotNull(new ValidationFailure(string.Empty, "Mapped Categories allowed characters a-z and -")); + } + } + } + + private string GetDownloadDirectory(ReleaseInfo release) + { + if (Settings.DestinationDirectory.IsNotNullOrWhiteSpace()) + { + return Settings.DestinationDirectory.TrimEnd('/'); + } + + var destDir = _proxy.GetDownloadConfiguration(Settings).DecodedDownloadDirectory.TrimEnd('/'); + + if (Settings.Category.IsNotNullOrWhiteSpace()) + { + var category = GetCategoryForRelease(release) ?? Settings.Category; + + destDir = $"{destDir}/{category}"; + } + + return destDir; + } + + private bool ToBeQueuedFirst() + { + if (Settings.Priority == (int)FreeboxDownloadPriority.First) + { + return true; + } + + return false; + } + + private bool ToBePaused() + { + return Settings.AddPaused; + } + } +} From 0e7eaa922153fd24fda451385dd885b16e058c42 Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 31 Dec 2022 17:57:54 -0600 Subject: [PATCH 0732/2320] Simplify logic in HandleRequest --- .../Definitions/Cardigann/CardigannRequestGenerator.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index cbf777533..e0c0a5b97 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -716,15 +716,12 @@ namespace NzbDrone.Core.Indexers.Cardigann if (queryCollection.Count > 0) { - if (!requestLinkStr.Contains("?")) + if (!requestLinkStr.Contains('?')) { requestLinkStr += "?"; - requestLinkStr += queryCollection.GetQueryString(_encoding, separator: request.Queryseparator); - } - else - { - requestLinkStr += queryCollection.GetQueryString(separator: request.Queryseparator); } + + requestLinkStr += queryCollection.GetQueryString(_encoding, separator: request.Queryseparator); } var httpRequest = new HttpRequestBuilder(requestLinkStr) From bf78396164d64d4151cc21f54a994163b21c7722 Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 31 Dec 2022 18:22:07 -0600 Subject: [PATCH 0733/2320] Rewrite test to avoid 6 hours of failures and needing a change every year --- .../CardigannTests/ApplyGoTemplateTextFixture.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NzbDrone.Core.Test/IndexerTests/CardigannTests/ApplyGoTemplateTextFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/CardigannTests/ApplyGoTemplateTextFixture.cs index 0f585abc9..bb4aaeab7 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/CardigannTests/ApplyGoTemplateTextFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/CardigannTests/ApplyGoTemplateTextFixture.cs @@ -71,12 +71,12 @@ namespace NzbDrone.Core.Test.IndexerTests.CardigannTests result.Should().Be(expected); } - [TestCase("{{ .Today.Year }}", "2022")] - public void should_handle_variables_statements(string template, string expected) + [TestCase("{{ .Today.Year }}")] + public void should_handle_variables_statements(string template) { var result = Subject.ApplyGoTemplateText(template, _variables); - result.Should().Be(expected); + result.Should().Be(DateTime.Now.Year.ToString()); } [TestCase("{{if .False }}0{{else}}1{{end}}", "1")] From 9db888c9a3df3ce5e3fe342912fea08fb9371d57 Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 31 Dec 2022 18:49:38 -0600 Subject: [PATCH 0734/2320] Bump Version to 1.0.1 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f9aaacc20..2ed7389ee 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: testsFolder: './_tests' yarnCacheFolder: $(Pipeline.Workspace)/.yarn nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages - majorVersion: '1.0.0' + majorVersion: '1.0.1' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From eff09c1f72a91226d1142cd8d1ca51ab0dedc88d Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 31 Dec 2022 19:32:06 -0600 Subject: [PATCH 0735/2320] Treat Master as a valid branch --- .../HealthCheck/Checks/ReleaseBranchCheckFixture.cs | 6 +++--- src/NzbDrone.Core/Configuration/DeploymentInfoProvider.cs | 2 +- src/NzbDrone.Core/HealthCheck/Checks/ReleaseBranchCheck.cs | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/ReleaseBranchCheckFixture.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/ReleaseBranchCheckFixture.cs index f503d665e..d277404ad 100644 --- a/src/NzbDrone.Core.Test/HealthCheck/Checks/ReleaseBranchCheckFixture.cs +++ b/src/NzbDrone.Core.Test/HealthCheck/Checks/ReleaseBranchCheckFixture.cs @@ -28,15 +28,15 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks [Test] public void should_return_warning_when_branch_not_valid() { - GivenValidBranch("master"); + GivenValidBranch("test"); Subject.Check().ShouldBeWarning(); } - [TestCase("Develop")] - [TestCase("develop")] [TestCase("nightly")] [TestCase("Nightly")] + [TestCase("develop")] + [TestCase("master")] public void should_return_no_warning_when_branch_valid(string branch) { GivenValidBranch(branch); diff --git a/src/NzbDrone.Core/Configuration/DeploymentInfoProvider.cs b/src/NzbDrone.Core/Configuration/DeploymentInfoProvider.cs index db2229a3d..1f96c44b8 100644 --- a/src/NzbDrone.Core/Configuration/DeploymentInfoProvider.cs +++ b/src/NzbDrone.Core/Configuration/DeploymentInfoProvider.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Configuration var releaseInfoPath = Path.Combine(bin, "release_info"); PackageUpdateMechanism = UpdateMechanism.BuiltIn; - DefaultBranch = "develop"; + DefaultBranch = "master"; if (Path.GetFileName(bin) == "bin" && diskProvider.FileExists(packageInfoPath)) { diff --git a/src/NzbDrone.Core/HealthCheck/Checks/ReleaseBranchCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/ReleaseBranchCheck.cs index dad54475e..6126471a5 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/ReleaseBranchCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/ReleaseBranchCheck.cs @@ -31,6 +31,7 @@ namespace NzbDrone.Core.HealthCheck.Checks public enum ReleaseBranches { + Master, Develop, Nightly } From de2fd92b6f0386a205d8232bc4f93787511e57a4 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Sun, 1 Jan 2023 23:14:21 +0200 Subject: [PATCH 0736/2320] Fixed: (Avistaz) Workaround for fetching "retry-after" header not present when using "Accept: application/json" --- .../Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs index aceb18885..c2eb30867 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Avistaz/AvistazRequestGenerator.cs @@ -73,7 +73,8 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz { var searchUrl = SearchUrl + "?" + searchParameters.GetQueryString(); - var request = new IndexerRequest(searchUrl, HttpAccept.Json); + // TODO: Change to HttpAccept.Json after they fix the issue with missing headers + var request = new IndexerRequest(searchUrl, HttpAccept.Html); request.HttpRequest.Headers.Add("Authorization", $"Bearer {Settings.Token}"); yield return request; From 5cc044aa8fbc7ba62d9c32442d8125b9b347d28a Mon Sep 17 00:00:00 2001 From: Qstick Date: Mon, 2 Jan 2023 17:16:46 -0600 Subject: [PATCH 0737/2320] Rarbg Rate Limit Tweaks, Additional back-off level --- .../Indexers/Definitions/Rarbg/Rarbg.cs | 3 +-- .../Indexers/Definitions/Rarbg/RarbgParser.cs | 14 ++------------ .../ThingiProvider/Status/EscalationBackOff.cs | 3 ++- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs index 123547357..82dc52844 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs @@ -107,7 +107,6 @@ namespace NzbDrone.Core.Indexers.Rarbg var response = await FetchIndexerResponse(request); // try and recover from token errors - // Response of 200 and rate_limt of 1 requires a 5 minute backoff. Handle in Response Parsing & do not page further if rate_limit is populated. var jsonResponse = new HttpResponse(response.HttpResponse); if (jsonResponse.Resource.error_code.HasValue) @@ -126,7 +125,7 @@ namespace NzbDrone.Core.Indexers.Rarbg } else if (jsonResponse.Resource.error_code == 5) { - _logger.Debug("Rarbg temp rate limit hit, retying request"); + _logger.Debug("Rarbg temp rate limit hit, retrying request"); response = await FetchIndexerResponse(request); } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs index e837279e1..e33f083d8 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs @@ -23,19 +23,15 @@ namespace NzbDrone.Core.Indexers.Rarbg public IList ParseResponse(IndexerResponse indexerResponse) { var results = new List(); - var retryTime = TimeSpan.FromMinutes(1); var responseCode = (int)indexerResponse.HttpResponse.StatusCode; switch (responseCode) { case (int)HttpStatusCode.TooManyRequests: - retryTime = TimeSpan.FromMinutes(2); - throw new TooManyRequestsException(indexerResponse.HttpRequest, indexerResponse.HttpResponse, retryTime); + throw new TooManyRequestsException(indexerResponse.HttpRequest, indexerResponse.HttpResponse, TimeSpan.FromMinutes(2)); case 520: - retryTime = TimeSpan.FromMinutes(3); - throw new TooManyRequestsException(indexerResponse.HttpRequest, indexerResponse.HttpResponse, retryTime); + throw new TooManyRequestsException(indexerResponse.HttpRequest, indexerResponse.HttpResponse, TimeSpan.FromMinutes(3)); case (int)HttpStatusCode.OK: - retryTime = TimeSpan.FromMinutes(5); break; default: throw new IndexerException(indexerResponse, "Indexer API call returned an unexpected StatusCode [{0}]", responseCode); @@ -43,12 +39,6 @@ namespace NzbDrone.Core.Indexers.Rarbg var jsonResponse = new HttpResponse(indexerResponse.HttpResponse); - // Handle 200 Rate Limiting - if (jsonResponse.Resource.rate_limit == 1) - { - throw new TooManyRequestsException(indexerResponse.HttpRequest, indexerResponse.HttpResponse, retryTime); - } - if (jsonResponse.Resource.error_code.HasValue) { if (jsonResponse.Resource.error_code == 20 || jsonResponse.Resource.error_code == 8 diff --git a/src/NzbDrone.Core/ThingiProvider/Status/EscalationBackOff.cs b/src/NzbDrone.Core/ThingiProvider/Status/EscalationBackOff.cs index 304613d58..71dafe7e4 100644 --- a/src/NzbDrone.Core/ThingiProvider/Status/EscalationBackOff.cs +++ b/src/NzbDrone.Core/ThingiProvider/Status/EscalationBackOff.cs @@ -1,10 +1,11 @@ -namespace NzbDrone.Core.ThingiProvider.Status +namespace NzbDrone.Core.ThingiProvider.Status { public static class EscalationBackOff { public static readonly int[] Periods = { 0, + 60, 5 * 60, 15 * 60, 30 * 60, From 264ffdcc267dabba1dfd10fb37feaa8742cc9eaa Mon Sep 17 00:00:00 2001 From: Qstick Date: Mon, 2 Jan 2023 17:41:41 -0600 Subject: [PATCH 0738/2320] Fixup Provider Tests --- .../ThingiProviderTests/ProviderStatusServiceFixture.cs | 6 +++--- src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs | 5 ----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/NzbDrone.Core.Test/ThingiProviderTests/ProviderStatusServiceFixture.cs b/src/NzbDrone.Core.Test/ThingiProviderTests/ProviderStatusServiceFixture.cs index f9c0d4325..8e2f6b8c6 100644 --- a/src/NzbDrone.Core.Test/ThingiProviderTests/ProviderStatusServiceFixture.cs +++ b/src/NzbDrone.Core.Test/ThingiProviderTests/ProviderStatusServiceFixture.cs @@ -90,7 +90,7 @@ namespace NzbDrone.Core.Test.ThingiProviderTests var status = Subject.GetBlockedProviders().FirstOrDefault(); status.Should().NotBeNull(); status.DisabledTill.Should().HaveValue(); - status.DisabledTill.Value.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(5), 500); + status.DisabledTill.Value.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(1), 500); } [Test] @@ -133,7 +133,7 @@ namespace NzbDrone.Core.Test.ThingiProviderTests var status = Subject.GetBlockedProviders().FirstOrDefault(); status.Should().NotBeNull(); status.DisabledTill.Should().HaveValue(); - status.DisabledTill.Value.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(15), 500); + status.DisabledTill.Value.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(5), 500); } [Test] @@ -160,7 +160,7 @@ namespace NzbDrone.Core.Test.ThingiProviderTests status.Should().NotBeNull(); origStatus.EscalationLevel.Should().Be(3); - status.DisabledTill.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(5), 500); + status.DisabledTill.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(1), 500); } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs index 82dc52844..27f053d0d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs @@ -1,19 +1,14 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Net.Http.Json; using System.Threading.Tasks; using System.Web; -using Newtonsoft.Json; using NLog; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; using NzbDrone.Core.Exceptions; -using NzbDrone.Core.Http.CloudFlare; -using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; using NzbDrone.Core.Validation; From cc841fe3d19df4ce5da4098902486546312bea00 Mon Sep 17 00:00:00 2001 From: Qstick Date: Mon, 2 Jan 2023 18:06:34 -0600 Subject: [PATCH 0739/2320] Remove Preview from Page Title --- frontend/src/index.ejs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/index.ejs b/frontend/src/index.ejs index 2df008f31..a2f8bcabc 100644 --- a/frontend/src/index.ejs +++ b/frontend/src/index.ejs @@ -11,7 +11,7 @@ - + - Prowlarr (Preview) + Prowlarr + 6.0-all true false AnyCPU diff --git a/src/NzbDrone.Common/Extensions/StringExtensions.cs b/src/NzbDrone.Common/Extensions/StringExtensions.cs index 8144b6a92..b35d0afb1 100644 --- a/src/NzbDrone.Common/Extensions/StringExtensions.cs +++ b/src/NzbDrone.Common/Extensions/StringExtensions.cs @@ -131,7 +131,7 @@ namespace NzbDrone.Common.Extensions public static string WrapInQuotes(this string text) { - if (!text.Contains(" ")) + if (!text.Contains(' ')) { return text; } @@ -255,7 +255,7 @@ namespace NzbDrone.Common.Extensions public static string ToUrlHost(this string input) { - return input.Contains(":") ? $"[{input}]" : input; + return input.Contains(':') ? $"[{input}]" : input; } } } diff --git a/src/NzbDrone.Common/OAuth/OAuthTools.cs b/src/NzbDrone.Common/OAuth/OAuthTools.cs index 20ea671b6..866890966 100644 --- a/src/NzbDrone.Common/OAuth/OAuthTools.cs +++ b/src/NzbDrone.Common/OAuth/OAuthTools.cs @@ -226,7 +226,7 @@ namespace NzbDrone.Common.OAuth #if WINRT return CultureInfo.InvariantCulture.CompareInfo.Compare(left, right, CompareOptions.IgnoreCase) == 0; #else - return string.Compare(left, right, StringComparison.InvariantCultureIgnoreCase) == 0; + return string.Equals(left, right, StringComparison.InvariantCultureIgnoreCase); #endif } diff --git a/src/NzbDrone.Common/ServiceProvider.cs b/src/NzbDrone.Common/ServiceProvider.cs index 7da62e6fd..d9a95192e 100644 --- a/src/NzbDrone.Common/ServiceProvider.cs +++ b/src/NzbDrone.Common/ServiceProvider.cs @@ -64,7 +64,7 @@ namespace NzbDrone.Common var args = $"create {serviceName} " + $"DisplayName= \"{serviceName}\" " + - $"binpath= \"{Process.GetCurrentProcess().MainModule.FileName}\" " + + $"binpath= \"{Environment.ProcessPath}\" " + "start= auto " + "depend= EventLog/Tcpip/http " + "obj= \"NT AUTHORITY\\LocalService\""; diff --git a/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs index 9018763a7..e5a6f6c32 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs @@ -162,7 +162,7 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests releaseInfo.InfoHash.Should().Be("(removed)"); releaseInfo.Seeders.Should().Be(3); releaseInfo.Peers.Should().Be(3); - releaseInfo.Categories.Count().Should().Be(4); + releaseInfo.Categories.Count.Should().Be(4); } [Test] diff --git a/src/NzbDrone.Core/Datastore/Migration/Framework/SqliteSyntaxReader.cs b/src/NzbDrone.Core/Datastore/Migration/Framework/SqliteSyntaxReader.cs index 77d53175c..0a0b519aa 100644 --- a/src/NzbDrone.Core/Datastore/Migration/Framework/SqliteSyntaxReader.cs +++ b/src/NzbDrone.Core/Datastore/Migration/Framework/SqliteSyntaxReader.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Data; using System.Text; @@ -250,7 +250,7 @@ namespace NzbDrone.Core.Datastore.Migration.Framework } Index = end + 1; - identifier.Append(Buffer.Substring(start, end - start)); + identifier.Append(Buffer.AsSpan(start, end - start)); if (Buffer[Index] != escape) { diff --git a/src/NzbDrone.Core/History/HistoryService.cs b/src/NzbDrone.Core/History/HistoryService.cs index cd3ba6b3d..247c8f4e1 100644 --- a/src/NzbDrone.Core/History/HistoryService.cs +++ b/src/NzbDrone.Core/History/HistoryService.cs @@ -173,7 +173,7 @@ namespace NzbDrone.Core.History history.Data.Add("Categories", string.Join(",", message.Query.Categories) ?? string.Empty); history.Data.Add("Source", message.Query.Source ?? string.Empty); history.Data.Add("Host", message.Query.Host ?? string.Empty); - history.Data.Add("QueryResults", message.QueryResult.Releases?.Count().ToString() ?? string.Empty); + history.Data.Add("QueryResults", message.QueryResult.Releases?.Count.ToString() ?? string.Empty); history.Data.Add("Url", message.QueryResult.Response?.Request.Url.FullUri ?? string.Empty); _historyRepository.Insert(history); diff --git a/src/NzbDrone.Core/Http/CloudFlare/CloudFlareDetectionService.cs b/src/NzbDrone.Core/Http/CloudFlare/CloudFlareDetectionService.cs index 54dc2338e..8f38c032e 100644 --- a/src/NzbDrone.Core/Http/CloudFlare/CloudFlareDetectionService.cs +++ b/src/NzbDrone.Core/Http/CloudFlare/CloudFlareDetectionService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using NLog; +using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; namespace NzbDrone.Core.Http.CloudFlare @@ -41,7 +42,7 @@ namespace NzbDrone.Core.Http.CloudFlare // detect Custom CloudFlare for EbookParadijs, Film-Paleis, MuziekFabriek and Puur-Hollands if (response.Headers.Vary == "Accept-Encoding,User-Agent" && - response.Headers.ContentEncoding == "" && + response.Headers.ContentEncoding.IsNullOrWhiteSpace() && response.Content.ToLower().Contains("ddos")) { return true; diff --git a/src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs b/src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs index 42cd79cad..e0a9bace7 100644 --- a/src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs +++ b/src/NzbDrone.Core/IndexerStats/IndexerStatisticsService.cs @@ -59,7 +59,7 @@ namespace NzbDrone.Core.IndexerStats var elapsedTimeEvents = sortedEvents.Where(h => int.TryParse(h.Data.GetValueOrDefault("elapsedTime"), out temp)) .Select(h => temp); - indexerStats.AverageResponseTime = elapsedTimeEvents.Count() > 0 ? (int)elapsedTimeEvents.Average() : 0; + indexerStats.AverageResponseTime = elapsedTimeEvents.Any() ? (int)elapsedTimeEvents.Average() : 0; foreach (var historyEvent in sortedEvents) { diff --git a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs index d3f0c2410..804cfe848 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/AnimeBytes.cs @@ -425,7 +425,7 @@ namespace NzbDrone.Core.Indexers.Definitions } var releaseGroup = releaseTags.LastOrDefault(); - if (releaseGroup != null && releaseGroup.Contains("(") && releaseGroup.Contains(")")) + if (releaseGroup != null && releaseGroup.Contains('(') && releaseGroup.Contains(')')) { //// Skip raws if set //if (releaseGroup.ToLowerInvariant().StartsWith("raw") && !AllowRaws) diff --git a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs index 860925474..4481c8fe1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BakaBT.cs @@ -281,7 +281,7 @@ namespace NzbDrone.Core.Indexers.Definitions var stringSeparator = new[] { " | " }; var titles = titleSeries.Split(stringSeparator, StringSplitOptions.RemoveEmptyEntries); - if (titles.Count() > 1 && !_settings.AddRomajiTitle) + if (titles.Length > 1 && !_settings.AddRomajiTitle) { titles = titles.Skip(1).ToArray(); } @@ -293,7 +293,7 @@ namespace NzbDrone.Core.Indexers.Definitions release.Title = (name + releaseInfo).Trim(); // Ensure the season is defined as this tracker only deals with full seasons - if (release.Title.IndexOf("Season") == -1 && _settings.AppendSeason) + if (!release.Title.Contains("Season", StringComparison.CurrentCulture) && _settings.AppendSeason) { // Insert before the release info var aidx = release.Title.IndexOf('('); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs index ebfea2aef..5e841d7c9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannParser.cs @@ -66,7 +66,7 @@ namespace NzbDrone.Core.Indexers.Cardigann { if (request.SearchPath.Response != null && request.SearchPath.Response.NoResultsMessage != null && - ((request.SearchPath.Response.NoResultsMessage != string.Empty && results.Contains(request.SearchPath.Response.NoResultsMessage)) || (request.SearchPath.Response.NoResultsMessage == string.Empty && results == string.Empty))) + ((request.SearchPath.Response.NoResultsMessage.IsNotNullOrWhiteSpace() && results.Contains(request.SearchPath.Response.NoResultsMessage)) || (request.SearchPath.Response.NoResultsMessage.IsNullOrWhiteSpace() && results.IsNullOrWhiteSpace()))) { return releases; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Shazbat.cs b/src/NzbDrone.Core/Indexers/Definitions/Shazbat.cs index c0b738ee2..2748810f7 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Shazbat.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Shazbat.cs @@ -351,7 +351,7 @@ public class ShazbatParser : IParseIndexerResponse private static string ParseTitle(IElement titleRow) { - var title = titleRow?.ChildNodes.First(n => n.NodeType == NodeType.Text && n.TextContent.Trim() != string.Empty); + var title = titleRow?.ChildNodes.First(n => n.NodeType == NodeType.Text && n.TextContent.Trim().IsNotNullOrWhiteSpace()); return title?.TextContent.Trim(); } diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index 9885fd52d..dde3112b2 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -34,7 +34,7 @@ namespace NzbDrone.Core.Indexers public override Encoding Encoding => Encoding.UTF8; public override string Language => "en-US"; - public override string[] LegacyUrls => new string[] { }; + public override string[] LegacyUrls => Array.Empty(); public override bool FollowRedirect => false; public override IndexerCapabilities Capabilities { get; protected set; } diff --git a/src/NzbDrone.Core/Localization/LocalizationService.cs b/src/NzbDrone.Core/Localization/LocalizationService.cs index 5b0b42c01..632b5215a 100644 --- a/src/NzbDrone.Core/Localization/LocalizationService.cs +++ b/src/NzbDrone.Core/Localization/LocalizationService.cs @@ -160,7 +160,7 @@ namespace NzbDrone.Core.Localization await CopyInto(dictionary, baseFilenamePath).ConfigureAwait(false); - if (culture.Contains("_")) + if (culture.Contains('_')) { var languageBaseFilenamePath = Path.Combine(prefix, GetResourceFilename(culture.Split('_')[0])); await CopyInto(dictionary, languageBaseFilenamePath).ConfigureAwait(false); diff --git a/src/NzbDrone.Core/Parser/DateTimeRoutines.cs b/src/NzbDrone.Core/Parser/DateTimeRoutines.cs index 0592ed222..d0aea643a 100644 --- a/src/NzbDrone.Core/Parser/DateTimeRoutines.cs +++ b/src/NzbDrone.Core/Parser/DateTimeRoutines.cs @@ -219,11 +219,11 @@ namespace NzbDrone.Core.Parser } } - if (string.Compare(m.Groups["ampm"].Value, "PM", true) == 0 && hour < 12) + if (string.Equals(m.Groups["ampm"].Value, "PM", StringComparison.InvariantCultureIgnoreCase) && hour < 12) { hour += 12; } - else if (string.Compare(m.Groups["ampm"].Value, "AM", true) == 0 && hour == 12) + else if (string.Equals(m.Groups["ampm"].Value, "AM", StringComparison.InvariantCultureIgnoreCase) && hour == 12) { hour -= 12; } diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index 55284346a..35e930b6e 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -50,7 +50,7 @@ namespace NzbDrone.Host try { Logger.Info("Starting Prowlarr - {0} - Version {1}", - Process.GetCurrentProcess().MainModule.FileName, + Environment.ProcessPath, Assembly.GetExecutingAssembly().GetName().Version); var startupContext = new StartupContext(args); diff --git a/src/NzbDrone.Host/Startup.cs b/src/NzbDrone.Host/Startup.cs index f70d90be0..e833ed876 100644 --- a/src/NzbDrone.Host/Startup.cs +++ b/src/NzbDrone.Host/Startup.cs @@ -125,7 +125,7 @@ namespace NzbDrone.Host c.AddSecurityRequirement(new OpenApiSecurityRequirement { - { apiKeyHeader, new string[] { } } + { apiKeyHeader, Array.Empty() } }); var apikeyQuery = new OpenApiSecurityScheme @@ -156,7 +156,7 @@ namespace NzbDrone.Host c.AddSecurityRequirement(new OpenApiSecurityRequirement { - { apikeyQuery, new string[] { } } + { apikeyQuery, Array.Empty() } }); }); diff --git a/src/NzbDrone.Test.Common/ConcurrencyCounter.cs b/src/NzbDrone.Test.Common/ConcurrencyCounter.cs index 6ee4554db..f3c12023f 100644 --- a/src/NzbDrone.Test.Common/ConcurrencyCounter.cs +++ b/src/NzbDrone.Test.Common/ConcurrencyCounter.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Test.Common public int Start() { - int threadId = Thread.CurrentThread.ManagedThreadId; + int threadId = Environment.CurrentManagedThreadId; lock (_mutex) { _threads[threadId] = 1; diff --git a/src/Prowlarr.Api.V1/System/Backup/BackupController.cs b/src/Prowlarr.Api.V1/System/Backup/BackupController.cs index 8c70239e5..15f8b5889 100644 --- a/src/Prowlarr.Api.V1/System/Backup/BackupController.cs +++ b/src/Prowlarr.Api.V1/System/Backup/BackupController.cs @@ -93,7 +93,7 @@ namespace Prowlarr.Api.V1.System.Backup throw new BadRequestException("file must be provided"); } - var file = files.First(); + var file = files[0]; var extension = Path.GetExtension(file.FileName); if (!ValidExtensions.Contains(extension)) diff --git a/src/Prowlarr.Http/Frontend/Mappers/IndexHtmlMapper.cs b/src/Prowlarr.Http/Frontend/Mappers/IndexHtmlMapper.cs index 5f2aeaaf3..a5801a6b2 100644 --- a/src/Prowlarr.Http/Frontend/Mappers/IndexHtmlMapper.cs +++ b/src/Prowlarr.Http/Frontend/Mappers/IndexHtmlMapper.cs @@ -35,7 +35,7 @@ namespace Prowlarr.Http.Frontend.Mappers return !resourceUrl.StartsWith("/content") && !resourceUrl.StartsWith("/mediacover") && - !resourceUrl.Contains(".") && + !resourceUrl.Contains('.') && !resourceUrl.StartsWith("/login"); } } From b41cb80e3336cfe9577af8b409b9acd7d293cc5c Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 18 Feb 2023 12:19:56 -0600 Subject: [PATCH 0875/2320] Use const where appropriate The value of a const field is computed at compile time and stored in the metadata, which improves run-time performance when it is compared to a static readonly field. --- .editorconfig | 2 -- src/NzbDrone.Core/Authentication/UserService.cs | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.editorconfig b/.editorconfig index fc4494c93..7b0cce5c0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -179,8 +179,6 @@ dotnet_diagnostic.CA1720.severity = suggestion dotnet_diagnostic.CA1721.severity = suggestion dotnet_diagnostic.CA1724.severity = suggestion dotnet_diagnostic.CA1725.severity = suggestion -dotnet_diagnostic.CA1801.severity = suggestion -dotnet_diagnostic.CA1802.severity = suggestion dotnet_diagnostic.CA1805.severity = suggestion dotnet_diagnostic.CA1806.severity = suggestion dotnet_diagnostic.CA1810.severity = suggestion diff --git a/src/NzbDrone.Core/Authentication/UserService.cs b/src/NzbDrone.Core/Authentication/UserService.cs index 9b4553788..068487e67 100644 --- a/src/NzbDrone.Core/Authentication/UserService.cs +++ b/src/NzbDrone.Core/Authentication/UserService.cs @@ -19,14 +19,14 @@ namespace NzbDrone.Core.Authentication public class UserService : IUserService { + private const int ITERATIONS = 10000; + private const int SALT_SIZE = 128 / 8; + private const int NUMBER_OF_BYTES = 256 / 8; + private readonly IUserRepository _repo; private readonly IAppFolderInfo _appFolderInfo; private readonly IDiskProvider _diskProvider; - private static readonly int ITERATIONS = 10000; - private static readonly int SALT_SIZE = 128 / 8; - private static readonly int NUMBER_OF_BYTES = 256 / 8; - public UserService(IUserRepository repo, IAppFolderInfo appFolderInfo, IDiskProvider diskProvider) { _repo = repo; From 5bb3ea080669fa07543363b23f04ae92e8c38b31 Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 18 Feb 2023 12:23:08 -0600 Subject: [PATCH 0876/2320] Remove unnecessary assignments to default type value The .NET runtime initializes all fields of reference types to their default values before running the constructor. In most cases, explicitly initializing a field to its default value in a constructor is redundant, adding maintenance costs and potentially degrading performance --- .editorconfig | 1 - .../TPL/LimitedConcurrencyLevelTaskScheduler.cs | 4 ++-- src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs | 6 +++--- src/NzbDrone.Core/Datastore/WhereBuilderSqlite.cs | 6 +++--- src/NzbDrone.Core/HealthCheck/HealthCheckService.cs | 4 ++-- .../Indexers/Definitions/Cardigann/CardigannDefinition.cs | 8 ++++---- src/NzbDrone.Mono/Disk/ProcMountProvider.cs | 2 +- 7 files changed, 15 insertions(+), 16 deletions(-) diff --git a/.editorconfig b/.editorconfig index 7b0cce5c0..8a07e89a8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -179,7 +179,6 @@ dotnet_diagnostic.CA1720.severity = suggestion dotnet_diagnostic.CA1721.severity = suggestion dotnet_diagnostic.CA1724.severity = suggestion dotnet_diagnostic.CA1725.severity = suggestion -dotnet_diagnostic.CA1805.severity = suggestion dotnet_diagnostic.CA1806.severity = suggestion dotnet_diagnostic.CA1810.severity = suggestion dotnet_diagnostic.CA1812.severity = suggestion diff --git a/src/NzbDrone.Common/TPL/LimitedConcurrencyLevelTaskScheduler.cs b/src/NzbDrone.Common/TPL/LimitedConcurrencyLevelTaskScheduler.cs index 2f1a295b5..a6137486b 100644 --- a/src/NzbDrone.Common/TPL/LimitedConcurrencyLevelTaskScheduler.cs +++ b/src/NzbDrone.Common/TPL/LimitedConcurrencyLevelTaskScheduler.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -19,7 +19,7 @@ namespace NzbDrone.Common.TPL private readonly int _maxDegreeOfParallelism; /// Whether the scheduler is currently processing work items. - private int _delegatesQueuedOrRunning = 0; + private int _delegatesQueuedOrRunning; /// /// Initializes an instance of the LimitedConcurrencyLevelTaskScheduler class with the diff --git a/src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs b/src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs index f3e31e179..91f910c9e 100644 --- a/src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs +++ b/src/NzbDrone.Core/Datastore/WhereBuilderPostgres.cs @@ -15,9 +15,9 @@ namespace NzbDrone.Core.Datastore private const DbType EnumerableMultiParameter = (DbType)(-1); private readonly string _paramNamePrefix; - private readonly bool _requireConcreteValue = false; - private int _paramCount = 0; - private bool _gotConcreteValue = false; + private readonly bool _requireConcreteValue; + private int _paramCount; + private bool _gotConcreteValue; public WhereBuilderPostgres(Expression filter, bool requireConcreteValue, int seq) { diff --git a/src/NzbDrone.Core/Datastore/WhereBuilderSqlite.cs b/src/NzbDrone.Core/Datastore/WhereBuilderSqlite.cs index 54b24d7e1..8725361e9 100644 --- a/src/NzbDrone.Core/Datastore/WhereBuilderSqlite.cs +++ b/src/NzbDrone.Core/Datastore/WhereBuilderSqlite.cs @@ -15,9 +15,9 @@ namespace NzbDrone.Core.Datastore private const DbType EnumerableMultiParameter = (DbType)(-1); private readonly string _paramNamePrefix; - private readonly bool _requireConcreteValue = false; - private int _paramCount = 0; - private bool _gotConcreteValue = false; + private readonly bool _requireConcreteValue; + private int _paramCount; + private bool _gotConcreteValue; public WhereBuilderSqlite(Expression filter, bool requireConcreteValue, int seq) { diff --git a/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs b/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs index 8735efe3d..1538674ab 100644 --- a/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs +++ b/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs @@ -34,8 +34,8 @@ namespace NzbDrone.Core.HealthCheck private readonly ICached _healthCheckResults; - private bool _hasRunHealthChecksAfterGracePeriod = false; - private bool _isRunningHealthChecksAfterGracePeriod = false; + private bool _hasRunHealthChecksAfterGracePeriod; + private bool _isRunningHealthChecksAfterGracePeriod; public HealthCheckService(IEnumerable healthChecks, IServerSideNotificationService serverSideNotificationService, diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs index 094e9b07e..491bae1d3 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannDefinition.cs @@ -44,7 +44,7 @@ namespace NzbDrone.Core.Indexers.Cardigann public double? RequestDelay { get; set; } public List Links { get; set; } public List Legacylinks { get; set; } - public bool Followredirect { get; set; } = false; + public bool Followredirect { get; set; } public bool TestLinkTorrent { get; set; } = true; public List Certificates { get; set; } public CapabilitiesBlock Caps { get; set; } @@ -95,7 +95,7 @@ namespace NzbDrone.Core.Indexers.Cardigann public List Cookies { get; set; } public string Method { get; set; } public string Form { get; set; } - public bool Selectors { get; set; } = false; + public bool Selectors { get; set; } public Dictionary Inputs { get; set; } public Dictionary Selectorinputs { get; set; } public Dictionary Getselectorinputs { get; set; } @@ -114,7 +114,7 @@ namespace NzbDrone.Core.Indexers.Cardigann public class SelectorBlock { public string Selector { get; set; } - public bool Optional { get; set; } = false; + public bool Optional { get; set; } public string Text { get; set; } public string Attribute { get; set; } public string Remove { get; set; } @@ -157,7 +157,7 @@ namespace NzbDrone.Core.Indexers.Cardigann public int After { get; set; } public SelectorBlock Dateheaders { get; set; } public SelectorBlock Count { get; set; } - public bool Multiple { get; set; } = false; + public bool Multiple { get; set; } } public class SearchPathBlock : RequestBlock diff --git a/src/NzbDrone.Mono/Disk/ProcMountProvider.cs b/src/NzbDrone.Mono/Disk/ProcMountProvider.cs index 5900d203c..2cce7d8b6 100644 --- a/src/NzbDrone.Mono/Disk/ProcMountProvider.cs +++ b/src/NzbDrone.Mono/Disk/ProcMountProvider.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Mono.Disk private static Dictionary _fileSystems; - private bool _hasLoggedProcMountFailure = false; + private bool _hasLoggedProcMountFailure; public ProcMountProvider(Logger logger) { From da898fe958a4dff44c5525b7d1a909816314484b Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 18 Feb 2023 12:25:21 -0600 Subject: [PATCH 0877/2320] Remove Non-Failing Rules --- .editorconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/.editorconfig b/.editorconfig index 8a07e89a8..8e8bd5f52 100644 --- a/.editorconfig +++ b/.editorconfig @@ -198,9 +198,6 @@ dotnet_diagnostic.CA2000.severity = suggestion dotnet_diagnostic.CA2002.severity = suggestion dotnet_diagnostic.CA2007.severity = suggestion dotnet_diagnostic.CA2008.severity = suggestion -dotnet_diagnostic.CA2009.severity = suggestion -dotnet_diagnostic.CA2010.severity = suggestion -dotnet_diagnostic.CA2011.severity = suggestion dotnet_diagnostic.CA2012.severity = suggestion dotnet_diagnostic.CA2013.severity = suggestion dotnet_diagnostic.CA2100.severity = suggestion From acf7a425b56c58a7b20feb0195b6203bddb218c1 Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 18 Feb 2023 13:24:23 -0600 Subject: [PATCH 0878/2320] Add global analyzer config --- .editorconfig | 1 - src/.globalconfig | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 src/.globalconfig diff --git a/.editorconfig b/.editorconfig index 8e8bd5f52..c4d1ace90 100644 --- a/.editorconfig +++ b/.editorconfig @@ -117,7 +117,6 @@ dotnet_diagnostic.CA1003.severity = suggestion dotnet_diagnostic.CA1008.severity = suggestion dotnet_diagnostic.CA1010.severity = suggestion dotnet_diagnostic.CA1012.severity = suggestion -dotnet_diagnostic.CA1014.severity = suggestion dotnet_diagnostic.CA1016.severity = suggestion dotnet_diagnostic.CA1017.severity = suggestion dotnet_diagnostic.CA1018.severity = suggestion diff --git a/src/.globalconfig b/src/.globalconfig new file mode 100644 index 000000000..6c8ed149b --- /dev/null +++ b/src/.globalconfig @@ -0,0 +1,3 @@ +is_global = true + +dotnet_diagnostic.CA1014.severity = none From fcb3c964553dfa590f8c4e70a5ba11680cfd8e3d Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 18 Feb 2023 13:39:00 -0600 Subject: [PATCH 0879/2320] Call async methods when in an async method --- src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs index 27688234b..b34949879 100644 --- a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs +++ b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs @@ -113,7 +113,7 @@ namespace NzbDrone.Common.Http.Dispatchers { if (request.ResponseStream != null && responseMessage.StatusCode == HttpStatusCode.OK) { - responseMessage.Content.CopyTo(request.ResponseStream, null, cts.Token); + await responseMessage.Content.CopyToAsync(request.ResponseStream, null, cts.Token); } else { From 0984976378914d47e2ff4fbafc6a3a62be8dae27 Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 18 Feb 2023 21:12:08 -0600 Subject: [PATCH 0880/2320] Bump DryIoc, YamlDotNet, AngleSharp --- src/NzbDrone.Common/Prowlarr.Common.csproj | 2 +- src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj | 2 +- src/NzbDrone.Core/Prowlarr.Core.csproj | 6 +++--- src/NzbDrone.Host/Prowlarr.Host.csproj | 4 ++-- src/NzbDrone.Update/Prowlarr.Update.csproj | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/NzbDrone.Common/Prowlarr.Common.csproj b/src/NzbDrone.Common/Prowlarr.Common.csproj index 02bfadf2f..d5db0d5cd 100644 --- a/src/NzbDrone.Common/Prowlarr.Common.csproj +++ b/src/NzbDrone.Common/Prowlarr.Common.csproj @@ -4,7 +4,7 @@ ISMUSL - + diff --git a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj index 47a54f144..3609cb943 100644 --- a/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/Prowlarr.Core.Test.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index 7dfe7ff8d..5379d315b 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -3,7 +3,7 @@ net6.0 - + @@ -22,8 +22,8 @@ - - + + diff --git a/src/NzbDrone.Host/Prowlarr.Host.csproj b/src/NzbDrone.Host/Prowlarr.Host.csproj index 7aa32bf91..0855c7ee6 100644 --- a/src/NzbDrone.Host/Prowlarr.Host.csproj +++ b/src/NzbDrone.Host/Prowlarr.Host.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/src/NzbDrone.Update/Prowlarr.Update.csproj b/src/NzbDrone.Update/Prowlarr.Update.csproj index d34e071f0..94f6aa8f2 100644 --- a/src/NzbDrone.Update/Prowlarr.Update.csproj +++ b/src/NzbDrone.Update/Prowlarr.Update.csproj @@ -4,8 +4,8 @@ net6.0 - - + + From 773e8ff1f4f9ab8d6104fda5cbafbe0d1868e1a1 Mon Sep 17 00:00:00 2001 From: Qstick Date: Sun, 19 Feb 2023 00:15:54 -0600 Subject: [PATCH 0881/2320] Bump version to 1.2.2 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c5b79519e..19a13b6c0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ variables: testsFolder: './_tests' yarnCacheFolder: $(Pipeline.Workspace)/.yarn nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages - majorVersion: '1.2.1' + majorVersion: '1.2.2' minorVersion: $[counter('minorVersion', 1)] prowlarrVersion: '$(majorVersion).$(minorVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' From caa8bb05a72e29f718cc0ca2bb6fc679d6a68c17 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Sun, 19 Feb 2023 01:06:28 +0200 Subject: [PATCH 0882/2320] Fixed: (Newznab API) Response with StatusCode 429 when limits are reached --- .../Http/TooManyRequestsException.cs | 8 +- src/NzbDrone.Core/Download/DownloadService.cs | 6 +- .../History/HistoryRepository.cs | 20 +++ src/NzbDrone.Core/History/HistoryService.cs | 6 + .../Indexers/IndexerLimitService.cs | 45 +++++- .../Indexers/NewznabController.cs | 142 +++++++++++++++--- 6 files changed, 188 insertions(+), 39 deletions(-) diff --git a/src/NzbDrone.Common/Http/TooManyRequestsException.cs b/src/NzbDrone.Common/Http/TooManyRequestsException.cs index 1d86740ca..599c81e24 100644 --- a/src/NzbDrone.Common/Http/TooManyRequestsException.cs +++ b/src/NzbDrone.Common/Http/TooManyRequestsException.cs @@ -11,15 +11,13 @@ namespace NzbDrone.Common.Http { if (response.Headers.ContainsKey("Retry-After")) { - var retryAfter = response.Headers["Retry-After"].ToString(); - int seconds; - DateTime date; + var retryAfter = response.Headers["Retry-After"]; - if (int.TryParse(retryAfter, out seconds)) + if (int.TryParse(retryAfter, out var seconds)) { RetryAfter = TimeSpan.FromSeconds(seconds); } - else if (DateTime.TryParse(retryAfter, out date)) + else if (DateTime.TryParse(retryAfter, out var date)) { RetryAfter = date.ToUniversalTime() - DateTime.UtcNow; } diff --git a/src/NzbDrone.Core/Download/DownloadService.cs b/src/NzbDrone.Core/Download/DownloadService.cs index ccb590518..99b66d2cc 100644 --- a/src/NzbDrone.Core/Download/DownloadService.cs +++ b/src/NzbDrone.Core/Download/DownloadService.cs @@ -92,8 +92,7 @@ namespace NzbDrone.Core.Download } catch (ReleaseDownloadException ex) { - var http429 = ex.InnerException as TooManyRequestsException; - if (http429 != null) + if (ex.InnerException is TooManyRequestsException http429) { _indexerStatusService.RecordFailure(release.IndexerId, http429.RetryAfter); } @@ -141,8 +140,7 @@ namespace NzbDrone.Core.Download } catch (ReleaseDownloadException ex) { - var http429 = ex.InnerException as TooManyRequestsException; - if (http429 != null) + if (ex.InnerException is TooManyRequestsException http429) { _indexerStatusService.RecordFailure(indexerId, http429.RetryAfter); } diff --git a/src/NzbDrone.Core/History/HistoryRepository.cs b/src/NzbDrone.Core/History/HistoryRepository.cs index c61effdbd..b1435c190 100644 --- a/src/NzbDrone.Core/History/HistoryRepository.cs +++ b/src/NzbDrone.Core/History/HistoryRepository.cs @@ -19,6 +19,7 @@ namespace NzbDrone.Core.History List Since(DateTime date, HistoryEventType? eventType); void Cleanup(int days); int CountSince(int indexerId, DateTime date, List eventTypes); + History FindFirstForIndexerSince(int indexerId, DateTime date, List eventTypes, int limit); } public class HistoryRepository : BasicRepository, IHistoryRepository @@ -115,5 +116,24 @@ namespace NzbDrone.Core.History return conn.ExecuteScalar(sql.RawSql, sql.Parameters); } } + + public History FindFirstForIndexerSince(int indexerId, DateTime date, List eventTypes, int limit) + { + var intEvents = eventTypes.Select(t => (int)t).ToList(); + + var builder = Builder() + .Where(x => x.IndexerId == indexerId) + .Where(x => x.Date >= date) + .Where(x => intEvents.Contains((int)x.EventType)); + + var query = Query(builder); + + if (limit > 0) + { + query = query.OrderByDescending(h => h.Date).Take(limit).ToList(); + } + + return query.MinBy(h => h.Date); + } } } diff --git a/src/NzbDrone.Core/History/HistoryService.cs b/src/NzbDrone.Core/History/HistoryService.cs index 247c8f4e1..27c53d29c 100644 --- a/src/NzbDrone.Core/History/HistoryService.cs +++ b/src/NzbDrone.Core/History/HistoryService.cs @@ -27,6 +27,7 @@ namespace NzbDrone.Core.History List Between(DateTime start, DateTime end); List Since(DateTime date, HistoryEventType? eventType); int CountSince(int indexerId, DateTime date, List eventTypes); + History FindFirstForIndexerSince(int indexerId, DateTime date, List eventTypes, int limit); } public class HistoryService : IHistoryService, @@ -232,5 +233,10 @@ namespace NzbDrone.Core.History { return _historyRepository.CountSince(indexerId, date, eventTypes); } + + public History FindFirstForIndexerSince(int indexerId, DateTime date, List eventTypes, int limit) + { + return _historyRepository.FindFirstForIndexerSince(indexerId, date, eventTypes, limit); + } } } diff --git a/src/NzbDrone.Core/Indexers/IndexerLimitService.cs b/src/NzbDrone.Core/Indexers/IndexerLimitService.cs index 9c3087d18..bad49daab 100644 --- a/src/NzbDrone.Core/Indexers/IndexerLimitService.cs +++ b/src/NzbDrone.Core/Indexers/IndexerLimitService.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using NLog; -using NzbDrone.Common.Extensions; using NzbDrone.Core.History; namespace NzbDrone.Core.Indexers @@ -10,6 +9,8 @@ namespace NzbDrone.Core.Indexers { bool AtDownloadLimit(IndexerDefinition indexer); bool AtQueryLimit(IndexerDefinition indexer); + int CalculateRetryAfterDownloadLimit(IndexerDefinition indexer); + int CalculateRetryAfterQueryLimit(IndexerDefinition indexer); } public class IndexerLimitService : IIndexerLimitService @@ -31,9 +32,9 @@ namespace NzbDrone.Core.Indexers var grabCount = _historyService.CountSince(indexer.Id, DateTime.Now.AddHours(-24), new List { HistoryEventType.ReleaseGrabbed }); var grabLimit = ((IIndexerSettings)indexer.Settings).BaseSettings.GrabLimit; - if (grabCount > grabLimit) + if (grabCount >= grabLimit) { - _logger.Info("Indexer {0} has exceeded maximum grab limit for last 24 hours", indexer.Name); + _logger.Info("Indexer {0} has performed {1} of possible {2} grabs in last 24 hours, exceeding the maximum grab limit", indexer.Name, grabCount, grabLimit); return true; } @@ -51,9 +52,9 @@ namespace NzbDrone.Core.Indexers var queryCount = _historyService.CountSince(indexer.Id, DateTime.Now.AddHours(-24), new List { HistoryEventType.IndexerQuery, HistoryEventType.IndexerRss }); var queryLimit = ((IIndexerSettings)indexer.Settings).BaseSettings.QueryLimit; - if (queryCount > queryLimit) + if (queryCount >= queryLimit) { - _logger.Info("Indexer {0} has exceeded maximum query limit for last 24 hours", indexer.Name); + _logger.Info("Indexer {0} has performed {1} of possible {2} queries in last 24 hours, exceeding the maximum query limit", indexer.Name, queryCount, queryLimit); return true; } @@ -63,5 +64,39 @@ namespace NzbDrone.Core.Indexers return false; } + + public int CalculateRetryAfterDownloadLimit(IndexerDefinition indexer) + { + if (indexer.Id > 0 && ((IIndexerSettings)indexer.Settings).BaseSettings.GrabLimit.HasValue) + { + var grabLimit = ((IIndexerSettings)indexer.Settings).BaseSettings.GrabLimit.GetValueOrDefault(); + + var firstHistorySince = _historyService.FindFirstForIndexerSince(indexer.Id, DateTime.Now.AddHours(-24), new List { HistoryEventType.ReleaseGrabbed }, grabLimit); + + if (firstHistorySince != null) + { + return Convert.ToInt32(firstHistorySince.Date.ToLocalTime().AddHours(24).Subtract(DateTime.Now).TotalSeconds); + } + } + + return 0; + } + + public int CalculateRetryAfterQueryLimit(IndexerDefinition indexer) + { + if (indexer.Id > 0 && ((IIndexerSettings)indexer.Settings).BaseSettings.QueryLimit.HasValue) + { + var queryLimit = ((IIndexerSettings)indexer.Settings).BaseSettings.QueryLimit.GetValueOrDefault(); + + var firstHistorySince = _historyService.FindFirstForIndexerSince(indexer.Id, DateTime.Now.AddHours(-24), new List { HistoryEventType.IndexerQuery, HistoryEventType.IndexerRss }, queryLimit); + + if (firstHistorySince != null) + { + return Convert.ToInt32(firstHistorySince.Date.ToLocalTime().AddHours(24).Subtract(DateTime.Now).TotalSeconds); + } + } + + return 0; + } } } diff --git a/src/Prowlarr.Api.V1/Indexers/NewznabController.cs b/src/Prowlarr.Api.V1/Indexers/NewznabController.cs index 5d6720eb3..32890495f 100644 --- a/src/Prowlarr.Api.V1/Indexers/NewznabController.cs +++ b/src/Prowlarr.Api.V1/Indexers/NewznabController.cs @@ -1,21 +1,25 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Net; +using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Download; -using NzbDrone.Core.History; +using NzbDrone.Core.Exceptions; using NzbDrone.Core.Indexers; using NzbDrone.Core.IndexerSearch; -using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.ThingiProvider.Status; using Prowlarr.Http.Extensions; using Prowlarr.Http.REST; +using BadRequestException = NzbDrone.Core.Exceptions.BadRequestException; namespace NzbDrone.Api.V1.Indexers { @@ -27,18 +31,21 @@ namespace NzbDrone.Api.V1.Indexers private IIndexerFactory _indexerFactory { get; set; } private ISearchForNzb _nzbSearchService { get; set; } private IIndexerLimitService _indexerLimitService { get; set; } + private IIndexerStatusService _indexerStatusService; private IDownloadMappingService _downloadMappingService { get; set; } private IDownloadService _downloadService { get; set; } public NewznabController(IndexerFactory indexerFactory, ISearchForNzb nzbSearchService, IIndexerLimitService indexerLimitService, + IIndexerStatusService indexerStatusService, IDownloadMappingService downloadMappingService, IDownloadService downloadService) { _indexerFactory = indexerFactory; _nzbSearchService = nzbSearchService; _indexerLimitService = indexerLimitService; + _indexerStatusService = indexerStatusService; _downloadMappingService = downloadMappingService; _downloadService = downloadService; } @@ -54,7 +61,7 @@ namespace NzbDrone.Api.V1.Indexers if (requestType.IsNullOrWhiteSpace()) { - return Content(CreateErrorXML(200, "Missing parameter (t)"), "application/rss+xml"); + return CreateResponse(CreateErrorXML(200, "Missing parameter (t)"), statusCode: StatusCodes.Status400BadRequest); } request.imdbid = request.imdbid?.TrimStart('t') ?? null; @@ -63,7 +70,7 @@ namespace NzbDrone.Api.V1.Indexers { if (!int.TryParse(request.imdbid, out var imdb) || imdb == 0) { - return Content(CreateErrorXML(201, "Incorrect parameter (imdbid)"), "application/rss+xml"); + return CreateResponse(CreateErrorXML(201, "Incorrect parameter (imdbid)"), statusCode: StatusCodes.Status400BadRequest); } } @@ -97,25 +104,27 @@ namespace NzbDrone.Api.V1.Indexers caps.Categories.AddCategoryMapping(1, cat); } - return Content(caps.ToXml(), "application/rss+xml"); + return CreateResponse(caps.ToXml()); case "search": case "tvsearch": case "music": case "book": case "movie": - var results = new NewznabResults(); - results.Releases = new List + var results = new NewznabResults { - new ReleaseInfo + Releases = new List { - Title = "Test Release", - Guid = "https://prowlarr.com", - DownloadUrl = "https://prowlarr.com", - PublishDate = DateTime.Now + new () + { + Title = "Test Release", + Guid = "https://prowlarr.com", + DownloadUrl = "https://prowlarr.com", + PublishDate = DateTime.Now + } } }; - return Content(results.ToXml(DownloadProtocol.Usenet), "application/rss+xml"); + return CreateResponse(results.ToXml(DownloadProtocol.Usenet)); } } @@ -126,19 +135,37 @@ namespace NzbDrone.Api.V1.Indexers throw new NotFoundException("Indexer Not Found"); } + if (!indexerDef.Enable) + { + return CreateResponse(CreateErrorXML(410, "Indexer is disabled"), statusCode: StatusCodes.Status410Gone); + } + var indexer = _indexerFactory.GetInstance(indexerDef); + var blockedIndexerStatus = GetBlockedIndexerStatus(indexer); + + if (blockedIndexerStatus?.DisabledTill != null) + { + var retryAfterDisabledTill = Convert.ToInt32(blockedIndexerStatus.DisabledTill.Value.ToLocalTime().Subtract(DateTime.Now).TotalSeconds); + AddRetryAfterHeader(retryAfterDisabledTill); + + return CreateResponse(CreateErrorXML(429, $"Indexer is disabled till {blockedIndexerStatus.DisabledTill.Value.ToLocalTime()} due to recent failures."), statusCode: StatusCodes.Status429TooManyRequests); + } + //TODO Optimize this so it's not called here and in NzbSearchService (for manual search) if (_indexerLimitService.AtQueryLimit(indexerDef)) { - return Content(CreateErrorXML(429, $"Request limit reached ({((IIndexerSettings)indexer.Definition.Settings).BaseSettings.QueryLimit})"), "application/rss+xml"); + var retryAfterQueryLimit = _indexerLimitService.CalculateRetryAfterQueryLimit(indexerDef); + AddRetryAfterHeader(retryAfterQueryLimit); + + return CreateResponse(CreateErrorXML(429, $"User configurable Indexer Query Limit of {((IIndexerSettings)indexer.Definition.Settings).BaseSettings.QueryLimit} reached."), statusCode: StatusCodes.Status429TooManyRequests); } switch (requestType) { case "caps": var caps = indexer.GetCapabilities(); - return Content(caps.ToXml(), "application/rss+xml"); + return CreateResponse(caps.ToXml()); case "search": case "tvsearch": case "music": @@ -156,9 +183,9 @@ namespace NzbDrone.Api.V1.Indexers } } - return Content(results.ToXml(indexer.Protocol), "application/rss+xml"); + return CreateResponse(results.ToXml(indexer.Protocol)); default: - return Content(CreateErrorXML(202, $"No such function ({requestType})"), "application/rss+xml"); + return CreateResponse(CreateErrorXML(202, $"No such function ({requestType})"), statusCode: StatusCodes.Status400BadRequest); } } @@ -167,11 +194,35 @@ namespace NzbDrone.Api.V1.Indexers public async Task GetDownload(int id, string link, string file) { var indexerDef = _indexerFactory.Get(id); + + if (indexerDef == null) + { + throw new NotFoundException("Indexer Not Found"); + } + + if (!indexerDef.Enable) + { + return CreateResponse(CreateErrorXML(410, "Indexer is disabled"), statusCode: StatusCodes.Status410Gone); + } + var indexer = _indexerFactory.GetInstance(indexerDef); + var blockedIndexerStatus = GetBlockedIndexerStatus(indexer); + + if (blockedIndexerStatus?.DisabledTill != null) + { + var retryAfterDisabledTill = Convert.ToInt32(blockedIndexerStatus.DisabledTill.Value.ToLocalTime().Subtract(DateTime.Now).TotalSeconds); + AddRetryAfterHeader(retryAfterDisabledTill); + + return CreateResponse(CreateErrorXML(429, $"Indexer is disabled till {blockedIndexerStatus.DisabledTill.Value.ToLocalTime()} due to recent failures."), statusCode: StatusCodes.Status429TooManyRequests); + } + if (_indexerLimitService.AtDownloadLimit(indexerDef)) { - return Content(CreateErrorXML(429, $"Grab limit reached ({((IIndexerSettings)indexer.Definition.Settings).BaseSettings.GrabLimit})"), "application/rss+xml"); + var retryAfterDownloadLimit = _indexerLimitService.CalculateRetryAfterDownloadLimit(indexerDef); + AddRetryAfterHeader(retryAfterDownloadLimit); + + return CreateResponse(CreateErrorXML(429, $"User configurable Indexer Grab Limit of {((IIndexerSettings)indexer.Definition.Settings).BaseSettings.GrabLimit} reached."), statusCode: StatusCodes.Status429TooManyRequests); } if (link.IsNullOrWhiteSpace() || file.IsNullOrWhiteSpace()) @@ -181,11 +232,6 @@ namespace NzbDrone.Api.V1.Indexers file = WebUtility.UrlDecode(file); - if (indexerDef == null) - { - throw new NotFoundException("Indexer Not Found"); - } - var source = UserAgentParser.ParseSource(Request.Headers["User-Agent"]); var host = Request.GetHostName(); @@ -198,8 +244,27 @@ namespace NzbDrone.Api.V1.Indexers return RedirectPermanent(unprotectedlLink); } - var downloadBytes = Array.Empty(); - downloadBytes = await _downloadService.DownloadReport(unprotectedlLink, id, source, host, file); + byte[] downloadBytes; + + try + { + downloadBytes = await _downloadService.DownloadReport(unprotectedlLink, id, source, host, file); + } + catch (ReleaseUnavailableException ex) + { + return CreateResponse(CreateErrorXML(410, ex.Message), statusCode: StatusCodes.Status410Gone); + } + catch (ReleaseDownloadException ex) when (ex.InnerException is TooManyRequestsException http429) + { + var http429RetryAfter = Convert.ToInt32(http429.RetryAfter.TotalSeconds); + AddRetryAfterHeader(http429RetryAfter); + + return CreateResponse(CreateErrorXML(429, ex.Message), statusCode: StatusCodes.Status429TooManyRequests); + } + catch (Exception ex) + { + return CreateResponse(CreateErrorXML(500, ex.Message), statusCode: StatusCodes.Status500InternalServerError); + } // handle magnet URLs if (downloadBytes.Length >= 7 @@ -232,5 +297,32 @@ namespace NzbDrone.Api.V1.Indexers return xdoc.Declaration + Environment.NewLine + xdoc; } + + private ContentResult CreateResponse(string content, string contentType = "application/rss+xml", int statusCode = StatusCodes.Status200OK) + { + var mediaTypeHeaderValue = MediaTypeHeaderValue.Parse(contentType); + + return new ContentResult + { + StatusCode = statusCode, + Content = content, + ContentType = mediaTypeHeaderValue.ToString() + }; + } + + private ProviderStatusBase GetBlockedIndexerStatus(IIndexer indexer) + { + var blockedIndexers = _indexerStatusService.GetBlockedProviders().ToDictionary(v => v.ProviderId, v => v); + + return blockedIndexers.TryGetValue(indexer.Definition.Id, out var blockedIndexerStatus) ? blockedIndexerStatus : null; + } + + private void AddRetryAfterHeader(int retryAfterSeconds) + { + if (!HttpContext.Response.Headers.ContainsKey("Retry-After") && retryAfterSeconds > 0) + { + HttpContext.Response.Headers.Add("Retry-After", $"{retryAfterSeconds}"); + } + } } } From 34c560fd3aaa42db37d13da38d98e61cd76a70c8 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Sun, 19 Feb 2023 10:33:56 +0200 Subject: [PATCH 0883/2320] Fixed: (CardigannBase) Remedy for casting strings to booleans --- .../Indexers/Definitions/Cardigann/CardigannBase.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs index a39a050da..af6637b26 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannBase.cs @@ -300,7 +300,12 @@ namespace NzbDrone.Core.Indexers.Cardigann } else if (setting.Type == "checkbox") { - variables[name] = ((bool)value) ? ".True" : null; + if (value is string stringValue && bool.TryParse(stringValue, out var result)) + { + value = result; + } + + variables[name] = (bool)value ? ".True" : null; } else if (setting.Type == "select") { @@ -328,12 +333,12 @@ namespace NzbDrone.Core.Indexers.Cardigann } else { - throw new NotSupportedException(); + throw new NotSupportedException($"Type {setting.Type} is not supported."); } - if (setting.Type != "password" && setting.Name != "apikey" && setting.Name != "rsskey" && indexerLogging) + if (setting.Type != "password" && setting.Name != "apikey" && setting.Name != "rsskey" && indexerLogging && variables.ContainsKey(name)) { - _logger.Debug($"Setting {setting.Name} to {variables[name]}"); + _logger.Debug($"Setting {setting.Name} to {variables[name].ToJson()}"); } } From 04276eb587c2220e22219dcce316b89d79efbe46 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sun, 19 Feb 2023 10:23:18 -0600 Subject: [PATCH 0884/2320] Fixed: (Rarbg) Updated app_id per site request (#1447) --- src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs | 2 +- src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs | 2 +- .../Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs | 2 +- .../Indexers/Definitions/Rarbg/RarbgTokenProvider.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs index 39a9c84a7..3a7bd8f27 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/RarbgTests/RarbgFixture.cs @@ -53,7 +53,7 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests torrentInfo.Title.Should().Be("Sense8.S01E01.WEBRip.x264-FGT"); torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent); torrentInfo.DownloadUrl.Should().Be("magnet:?xt=urn:btih:d8bde635f573acb390c7d7e7efc1556965fdc802&dn=Sense8.S01E01.WEBRip.x264-FGT&tr=http%3A%2F%2Ftracker.trackerfix.com%3A80%2Fannounce&tr=udp%3A%2F%2F9.rarbg.me%3A2710&tr=udp%3A%2F%2F9.rarbg.to%3A2710&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce"); - torrentInfo.InfoUrl.Should().Be($"https://torrentapi.org/redirect_to_info.php?token=i5cx7b9agd&p=8_6_4_4_5_6__d8bde635f5&app_id={BuildInfo.AppName}"); + torrentInfo.InfoUrl.Should().Be($"https://torrentapi.org/redirect_to_info.php?token=i5cx7b9agd&p=8_6_4_4_5_6__d8bde635f5&app_id={BuildInfo.AppName}_{BuildInfo.Version}"); torrentInfo.Indexer.Should().Be(Subject.Definition.Name); torrentInfo.PublishDate.Should().Be(DateTime.Parse("2015-06-05 16:58:11 +0000").ToUniversalTime()); torrentInfo.Size.Should().Be(564198371); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs index 4eb6cba6d..c2bffe85f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/Rarbg.cs @@ -151,7 +151,7 @@ namespace NzbDrone.Core.Indexers.Rarbg Settings.Validate().Filter("BaseUrl").ThrowOnError(); var request = new HttpRequestBuilder(Settings.BaseUrl.Trim('/')) - .Resource($"/pubapi_v2.php?get_token=get_token&app_id={BuildInfo.AppName}") + .Resource($"/pubapi_v2.php?get_token=get_token&app_id={BuildInfo.AppName}_{BuildInfo.Version}") .Accept(HttpAccept.Json) .Build(); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs index 9f80745e8..753a26b9d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgParser.cs @@ -84,7 +84,7 @@ namespace NzbDrone.Core.Indexers.Rarbg Title = torrent.title, Size = torrent.size, DownloadUrl = torrent.download, - InfoUrl = $"{torrent.info_page}&app_id={BuildInfo.AppName}", + InfoUrl = $"{torrent.info_page}&app_id={BuildInfo.AppName}_{BuildInfo.Version}", PublishDate = torrent.pubdate.ToUniversalTime(), Seeders = torrent.seeders, Peers = torrent.leechers + torrent.seeders, diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs index ca57fb341..253b1b20d 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgRequestGenerator.cs @@ -61,7 +61,7 @@ namespace NzbDrone.Core.Indexers.Rarbg requestBuilder.AddQueryParam("limit", "100"); requestBuilder.AddQueryParam("token", _tokenProvider.GetToken(Settings)); requestBuilder.AddQueryParam("format", "json_extended"); - requestBuilder.AddQueryParam("app_id", BuildInfo.AppName); + requestBuilder.AddQueryParam("app_id", $"{BuildInfo.AppName}_{BuildInfo.Version}"); yield return new IndexerRequest(requestBuilder.Build()); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs index 4ccb5da42..8ed497a18 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Rarbg/RarbgTokenProvider.cs @@ -38,7 +38,7 @@ namespace NzbDrone.Core.Indexers.Rarbg { var requestBuilder = new HttpRequestBuilder(settings.BaseUrl.Trim('/')) .WithRateLimit(5.0) - .Resource($"/pubapi_v2.php?get_token=get_token&app_id={BuildInfo.AppName}") + .Resource($"/pubapi_v2.php?get_token=get_token&app_id={BuildInfo.AppName}_{BuildInfo.Version}") .Accept(HttpAccept.Json); var response = _httpClient.Get(requestBuilder.Build()); From 99bc56efb61dc450b8bfadc7ee0380585dec3be0 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Sun, 19 Feb 2023 11:55:50 +0200 Subject: [PATCH 0885/2320] Fixed: (Indexers) Rate limit for download and auth --- src/NzbDrone.Core/Download/DownloadService.cs | 9 -- .../Definitions/Cardigann/Cardigann.cs | 58 +------- .../Cardigann/CardigannRequestGenerator.cs | 125 ++++++++++++------ .../Indexers/Definitions/Nebulance.cs | 13 +- .../Indexers/Definitions/Orpheus.cs | 2 +- .../Indexers/Definitions/Redacted.cs | 52 +++----- .../Definitions/SpeedApp/SpeedAppBase.cs | 70 ++-------- src/NzbDrone.Core/Indexers/HttpIndexerBase.cs | 96 ++++++++++++++ .../Indexers/TorrentIndexerBase.cs | 81 +----------- .../Indexers/UsenetIndexerBase.cs | 64 +-------- 10 files changed, 222 insertions(+), 348 deletions(-) diff --git a/src/NzbDrone.Core/Download/DownloadService.cs b/src/NzbDrone.Core/Download/DownloadService.cs index 99b66d2cc..d28b801c4 100644 --- a/src/NzbDrone.Core/Download/DownloadService.cs +++ b/src/NzbDrone.Core/Download/DownloadService.cs @@ -1,7 +1,6 @@ using System; using System.Threading.Tasks; using NLog; -using NzbDrone.Common.EnsureThat; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Common.Instrumentation.Extensions; @@ -61,14 +60,6 @@ namespace NzbDrone.Core.Download // Get the seed configuration for this release. // remoteMovie.SeedConfiguration = _seedConfigProvider.GetSeedConfiguration(remoteMovie); - - // Limit grabs to 2 per second. - if (release.DownloadUrl.IsNotNullOrWhiteSpace() && !release.DownloadUrl.StartsWith("magnet:")) - { - var url = new HttpUri(release.DownloadUrl); - _rateLimitService.WaitAndPulse(url.Host, TimeSpan.FromSeconds(2)); - } - var indexer = _indexerFactory.GetInstance(_indexerFactory.Get(release.IndexerId)); string downloadClientId; diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs index 69540cf3e..5edfd8b5f 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/Cardigann.cs @@ -1,15 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Net; -using System.Text; using System.Threading.Tasks; using FluentValidation.Results; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; -using NzbDrone.Core.Exceptions; using NzbDrone.Core.IndexerVersions; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.ThingiProvider; @@ -53,7 +50,8 @@ namespace NzbDrone.Core.Indexers.Cardigann var generator = _generatorCache.Get(Settings.DefinitionFile, () => new CardigannRequestGenerator(_configService, _definitionService.GetCachedDefinition(Settings.DefinitionFile), - _logger) + _logger, + RateLimit) { HttpClient = _httpClient, Definition = Definition, @@ -180,63 +178,15 @@ namespace NzbDrone.Core.Indexers.Cardigann await generator.DoLogin(); } - public override async Task Download(Uri link) + protected override async Task GetDownloadRequest(Uri link) { var generator = (CardigannRequestGenerator)GetRequestGenerator(); var request = await generator.DownloadRequest(link); - if (request.Url.Scheme == "magnet") - { - ValidateMagnet(request.Url.FullUri); - - return Encoding.UTF8.GetBytes(request.Url.FullUri); - } - request.AllowAutoRedirect = true; - var downloadBytes = Array.Empty(); - - try - { - var response = await _httpClient.ExecuteProxiedAsync(request, Definition); - downloadBytes = response.ResponseData; - } - catch (HttpException ex) - { - if (ex.Response.StatusCode == HttpStatusCode.NotFound) - { - _logger.Error(ex, "Downloading torrent file for release failed since it no longer exists ({0})", request.Url.FullUri); - throw new ReleaseUnavailableException("Downloading torrent failed", ex); - } - - if (ex.Response.StatusCode == HttpStatusCode.TooManyRequests) - { - _logger.Error("API Grab Limit reached for {0}", request.Url.FullUri); - } - else - { - _logger.Error(ex, "Downloading torrent file for release failed ({0})", request.Url.FullUri); - } - - throw new ReleaseDownloadException("Downloading torrent failed", ex); - } - catch (WebException ex) - { - _logger.Error(ex, "Downloading torrent file for release failed ({0})", request.Url.FullUri); - - throw new ReleaseDownloadException("Downloading torrent failed", ex); - } - catch (Exception) - { - _indexerStatusService.RecordFailure(Definition.Id); - _logger.Error("Downloading torrent failed"); - throw; - } - - ValidateTorrent(downloadBytes); - - return downloadBytes; + return request; } protected override async Task Test(List failures) diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs index 740b45ab1..0742c98aa 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/CardigannRequestGenerator.cs @@ -4,7 +4,6 @@ using System.Collections.Specialized; using System.Linq; using System.Net; using System.Net.Http; -using System.Text; using System.Threading.Tasks; using AngleSharp.Html.Dom; using AngleSharp.Html.Parser; @@ -29,11 +28,15 @@ namespace NzbDrone.Core.Indexers.Cardigann protected IHtmlDocument landingResultDocument; protected override string SiteLink => ResolveSiteLink(); + private readonly TimeSpan _rateLimit; + public CardigannRequestGenerator(IConfigService configService, CardigannDefinition definition, - Logger logger) + Logger logger, + TimeSpan rateLimit) : base(configService, definition, logger) { + _rateLimit = rateLimit; } public Func> GetCookies { get; set; } @@ -218,9 +221,12 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.AddFormParameter(pair.Key, pair.Value); } - requestBuilder.Headers.Add("Referer", SiteLink); + var request = requestBuilder + .SetHeader("Referer", SiteLink) + .WithRateLimit(_rateLimit.TotalSeconds) + .Build(); - var response = await HttpClient.ExecuteProxiedAsync(requestBuilder.Build(), Definition); + var response = await HttpClient.ExecuteProxiedAsync(request, Definition); Cookies = response.GetCookies(); @@ -356,11 +362,13 @@ namespace NzbDrone.Core.Indexers.Cardigann Encoding = _encoding }; - requestBuilder.SetCookies(Cookies); + var request = requestBuilder + .SetCookies(Cookies) + .SetHeader("Referer", loginUrl) + .WithRateLimit(_rateLimit.TotalSeconds) + .Build(); - requestBuilder.Headers.Add("Referer", loginUrl); - - var simpleCaptchaResult = await HttpClient.ExecuteProxiedAsync(requestBuilder.Build(), Definition); + var simpleCaptchaResult = await HttpClient.ExecuteProxiedAsync(request, Definition); var simpleCaptchaJSON = JObject.Parse(simpleCaptchaResult.Content); var captchaSelection = simpleCaptchaJSON["images"][0]["hash"].ToString(); @@ -424,10 +432,6 @@ namespace NzbDrone.Core.Indexers.Cardigann Encoding = _encoding }; - requestBuilder.Headers.Add("Referer", SiteLink); - - requestBuilder.SetCookies(Cookies); - foreach (var pair in pairs) { requestBuilder.AddFormParameter(pair.Key, pair.Value); @@ -438,7 +442,12 @@ namespace NzbDrone.Core.Indexers.Cardigann requestBuilder.SetHeader(header.Key, header.Value); } - var request = requestBuilder.Build(); + var request = requestBuilder + .SetCookies(Cookies) + .SetHeader("Referer", SiteLink) + .WithRateLimit(_rateLimit.TotalSeconds) + .Build(); + request.SetContent(body); loginResult = await HttpClient.ExecuteProxiedAsync(request, Definition); @@ -454,15 +463,18 @@ namespace NzbDrone.Core.Indexers.Cardigann Encoding = _encoding }; - requestBuilder.SetCookies(Cookies); - requestBuilder.Headers.Add("Referer", loginUrl); - foreach (var pair in pairs) { requestBuilder.AddFormParameter(pair.Key, pair.Value); } - loginResult = await HttpClient.ExecuteProxiedAsync(requestBuilder.Build(), Definition); + var request = requestBuilder + .SetCookies(Cookies) + .SetHeader("Referer", loginUrl) + .WithRateLimit(_rateLimit.TotalSeconds) + .Build(); + + loginResult = await HttpClient.ExecuteProxiedAsync(request, Definition); } Cookies = loginResult.GetCookies(); @@ -496,9 +508,12 @@ namespace NzbDrone.Core.Indexers.Cardigann Encoding = _encoding }; - requestBuilder.Headers.Add("Referer", SiteLink); + var request = requestBuilder + .SetHeader("Referer", SiteLink) + .WithRateLimit(_rateLimit.TotalSeconds) + .Build(); - var response = await HttpClient.ExecuteProxiedAsync(requestBuilder.Build(), Definition); + var response = await HttpClient.ExecuteProxiedAsync(request, Definition); Cookies = response.GetCookies(); @@ -521,9 +536,12 @@ namespace NzbDrone.Core.Indexers.Cardigann Encoding = _encoding }; - requestBuilder.Headers.Add("Referer", SiteLink); + var request = requestBuilder + .SetHeader("Referer", SiteLink) + .WithRateLimit(_rateLimit.TotalSeconds) + .Build(); - var response = await HttpClient.ExecuteProxiedAsync(requestBuilder.Build(), Definition); + var response = await HttpClient.ExecuteProxiedAsync(request, Definition); Cookies = response.GetCookies(); @@ -594,14 +612,15 @@ namespace NzbDrone.Core.Indexers.Cardigann Encoding = _encoding }; - requestBuilder.Headers.Add("Referer", SiteLink); - if (Cookies != null) { requestBuilder.SetCookies(Cookies); } - var request = requestBuilder.Build(); + var request = requestBuilder + .SetHeader("Referer", SiteLink) + .WithRateLimit(_rateLimit.TotalSeconds) + .Build(); landingResult = await HttpClient.ExecuteProxiedAsync(request, Definition); @@ -646,6 +665,7 @@ namespace NzbDrone.Core.Indexers.Cardigann .SetCookies(landingResult.GetCookies()) .SetHeader("Referer", loginUrl.AbsoluteUri) .SetEncoding(_encoding) + .WithRateLimit(_rateLimit.TotalSeconds) .Build(); var response = await HttpClient.ExecuteProxiedAsync(request, Definition); @@ -656,10 +676,8 @@ namespace NzbDrone.Core.Indexers.Cardigann ImageData = response.ResponseData }; } - else - { - _logger.Debug("CardigannIndexer ({0}): No captcha image found", _definition.Id); - } + + _logger.Debug("CardigannIndexer ({0}): No captcha image found", _definition.Id); } else { @@ -724,23 +742,28 @@ namespace NzbDrone.Core.Indexers.Cardigann requestLinkStr += queryCollection.GetQueryString(_encoding, separator: request.Queryseparator); } - var httpRequest = new HttpRequestBuilder(requestLinkStr) - .SetCookies(Cookies ?? new Dictionary()) - .SetEncoding(_encoding) - .SetHeader("Referer", referer); - - httpRequest.Method = method; + var httpRequestBuilder = new HttpRequestBuilder(requestLinkStr) + { + Method = method, + Encoding = _encoding + }; // Add form data for POST requests if (method == HttpMethod.Post) { foreach (var param in pairs) { - httpRequest.AddFormParameter(param.Key, param.Value); + httpRequestBuilder.AddFormParameter(param.Key, param.Value); } } - var response = await HttpClient.ExecuteProxiedAsync(httpRequest.Build(), Definition); + var httpRequest = httpRequestBuilder + .SetCookies(Cookies ?? new Dictionary()) + .SetHeader("Referer", referer) + .WithRateLimit(_rateLimit.TotalSeconds) + .Build(); + + var response = await HttpClient.ExecuteProxiedAsync(httpRequest, Definition); _logger.Debug("CardigannIndexer ({0}): handleRequest() remote server returned {1}", _definition.Id, response.StatusCode); return response; @@ -766,6 +789,7 @@ namespace NzbDrone.Core.Indexers.Cardigann .SetCookies(Cookies ?? new Dictionary()) .SetHeaders(headers ?? new Dictionary()) .SetEncoding(_encoding) + .WithRateLimit(_rateLimit.TotalSeconds) .Build(); request.AllowAutoRedirect = true; @@ -856,6 +880,7 @@ namespace NzbDrone.Core.Indexers.Cardigann .SetCookies(Cookies ?? new Dictionary()) .SetHeaders(headers ?? new Dictionary()) .SetEncoding(_encoding) + .WithRateLimit(_rateLimit.TotalSeconds) .Build(); response = await HttpClient.ExecuteProxiedAsync(testLinkRequest, Definition); @@ -875,6 +900,7 @@ namespace NzbDrone.Core.Indexers.Cardigann .SetCookies(Cookies ?? new Dictionary()) .SetHeaders(headers ?? new Dictionary()) .SetEncoding(_encoding) + .WithRateLimit(_rateLimit.TotalSeconds) .Build(); selectorDownloadRequest.Method = method; @@ -895,6 +921,7 @@ namespace NzbDrone.Core.Indexers.Cardigann .SetCookies(Cookies ?? new Dictionary()) .SetHeaders(headers ?? new Dictionary()) .SetEncoding(_encoding) + .WithRateLimit(_rateLimit.TotalSeconds) .Build(); downloadRequest.Method = method; @@ -1096,16 +1123,18 @@ namespace NzbDrone.Core.Indexers.Cardigann _logger.Info($"Adding request: {searchUrl}"); - var requestbuilder = new HttpRequestBuilder(searchUrl); - - requestbuilder.Method = method; + var requestBuilder = new HttpRequestBuilder(searchUrl) + { + Method = method, + Encoding = _encoding + }; // Add FormData for searchs that POST if (method == HttpMethod.Post) { foreach (var param in queryCollection) { - requestbuilder.AddFormParameter(param.Key, param.Value); + requestBuilder.AddFormParameter(param.Key, param.Value); } } @@ -1113,14 +1142,22 @@ namespace NzbDrone.Core.Indexers.Cardigann if (search.Headers != null) { var headers = ParseCustomHeaders(search.Headers, variables); - requestbuilder.SetHeaders(headers ?? new Dictionary()); + requestBuilder.SetHeaders(headers ?? new Dictionary()); } - var request = new CardigannRequest(requestbuilder.SetEncoding(_encoding).Build(), variables, searchPath); + var request = requestBuilder + .WithRateLimit(_rateLimit.TotalSeconds) + .Build(); - request.HttpRequest.AllowAutoRedirect = searchPath.Followredirect; + var cardigannRequest = new CardigannRequest(request, variables, searchPath) + { + HttpRequest = + { + AllowAutoRedirect = searchPath.Followredirect + } + }; - yield return request; + yield return cardigannRequest; } } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs index efa3ff1a7..2750211b5 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs @@ -46,12 +46,17 @@ namespace NzbDrone.Core.Indexers.Definitions return new NebulanceParser(Settings); } - public override async Task Download(Uri link) + protected override Task GetDownloadRequest(Uri link) { - // Invalidate cookies before downloading to prevent redirect to login page. - UpdateCookies(null, null); + // Avoid using cookies to prevent redirects to login page + var requestBuilder = new HttpRequestBuilder(link.AbsoluteUri) + { + AllowAutoRedirect = FollowRedirect + }; - return await base.Download(link); + var request = requestBuilder.Build(); + + return Task.FromResult(request); } private IndexerCapabilities SetCapabilities() diff --git a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs index fc69df97c..ecb9108f1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Orpheus.cs @@ -112,7 +112,7 @@ namespace NzbDrone.Core.Indexers.Definitions _logger.Error("Download failed"); } - ValidateTorrent(downloadBytes); + ValidateDownloadData(downloadBytes); return downloadBytes; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs b/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs index 2460c7f3d..e8fba9c96 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Redacted.cs @@ -50,6 +50,20 @@ namespace NzbDrone.Core.Indexers.Definitions return new RedactedParser(Settings, Capabilities.Categories); } + protected override Task GetDownloadRequest(Uri link) + { + var requestBuilder = new HttpRequestBuilder(link.AbsoluteUri) + { + AllowAutoRedirect = FollowRedirect + }; + + var request = requestBuilder + .SetHeader("Authorization", Settings.Apikey) + .Build(); + + return Task.FromResult(request); + } + private IndexerCapabilities SetCapabilities() { var caps = new IndexerCapabilities @@ -74,30 +88,6 @@ namespace NzbDrone.Core.Indexers.Definitions return caps; } - - public override async Task Download(Uri link) - { - var request = new HttpRequestBuilder(link.AbsoluteUri) - .SetHeader("Authorization", Settings.Apikey) - .Build(); - - var downloadBytes = Array.Empty(); - - try - { - var response = await _httpClient.ExecuteProxiedAsync(request, Definition); - downloadBytes = response.ResponseData; - } - catch (Exception) - { - _indexerStatusService.RecordFailure(Definition.Id); - _logger.Error("Download failed"); - } - - ValidateTorrent(downloadBytes); - - return downloadBytes; - } } public class RedactedRequestGenerator : IIndexerRequestGenerator @@ -188,18 +178,12 @@ namespace NzbDrone.Core.Indexers.Definitions queryCats.ForEach(cat => parameters.Set($"filter_cat[{cat}]", "1")); } - var request = RequestBuilder() - .Resource($"/ajax.php?{parameters.GetQueryString()}") - .Build(); + var searchUrl = _settings.BaseUrl.TrimEnd('/') + $"/ajax.php?{parameters.GetQueryString()}"; - yield return new IndexerRequest(request); - } + var request = new IndexerRequest(searchUrl, HttpAccept.Json); + request.HttpRequest.Headers.Set("Authorization", _settings.Apikey); - private HttpRequestBuilder RequestBuilder() - { - return new HttpRequestBuilder($"{_settings.BaseUrl.TrimEnd('/')}") - .Accept(HttpAccept.Json) - .SetHeader("Authorization", _settings.Apikey); + yield return request; } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs index b7ffde0d6..91f4aa0c5 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/SpeedApp/SpeedAppBase.cs @@ -15,7 +15,6 @@ using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Annotations; using NzbDrone.Core.Configuration; -using NzbDrone.Core.Exceptions; using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.IndexerSearch.Definitions; @@ -104,70 +103,18 @@ namespace NzbDrone.Core.Indexers.Definitions request.HttpRequest.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}"); } - public override async Task Download(Uri link) + protected override Task GetDownloadRequest(Uri link) { - Cookies = GetCookies(); - - if (link.Scheme == "magnet") + var requestBuilder = new HttpRequestBuilder(link.AbsoluteUri) { - ValidateMagnet(link.OriginalString); + AllowAutoRedirect = FollowRedirect + }; - return Encoding.UTF8.GetBytes(link.OriginalString); - } + var request = requestBuilder + .SetHeader("Authorization", $"Bearer {Settings.ApiKey}") + .Build(); - var requestBuilder = new HttpRequestBuilder(link.AbsoluteUri); - - if (Cookies != null) - { - requestBuilder.SetCookies(Cookies); - } - - var request = requestBuilder.Build(); - request.AllowAutoRedirect = FollowRedirect; - request.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}"); - - byte[] torrentData; - - try - { - var response = await _httpClient.ExecuteProxiedAsync(request, Definition); - torrentData = response.ResponseData; - } - catch (HttpException ex) - { - if (ex.Response.StatusCode == HttpStatusCode.NotFound) - { - _logger.Error(ex, "Downloading torrent file for release failed since it no longer exists ({0})", link.AbsoluteUri); - throw new ReleaseUnavailableException("Downloading torrent failed", ex); - } - - if (ex.Response.StatusCode == HttpStatusCode.TooManyRequests) - { - _logger.Error("API Grab Limit reached for {0}", link.AbsoluteUri); - } - else - { - _logger.Error(ex, "Downloading torrent file for release failed ({0})", link.AbsoluteUri); - } - - throw new ReleaseDownloadException("Downloading torrent failed", ex); - } - catch (WebException ex) - { - _logger.Error(ex, "Downloading torrent file for release failed ({0})", link.AbsoluteUri); - - throw new ReleaseDownloadException("Downloading torrent failed", ex); - } - catch (Exception) - { - _indexerStatusService.RecordFailure(Definition.Id); - _logger.Error("Downloading torrent failed"); - throw; - } - - ValidateTorrent(torrentData); - - return torrentData; + return Task.FromResult(request); } protected virtual IndexerCapabilities SetCapabilities() @@ -276,7 +223,6 @@ namespace NzbDrone.Core.Indexers.Definitions var searchUrl = _settings.BaseUrl + "api/torrent?" + parameters.GetQueryString(duplicateKeysIfMulti: true); var request = new IndexerRequest(searchUrl, HttpAccept.Json); - request.HttpRequest.Headers.Set("Authorization", $"Bearer {_settings.ApiKey}"); yield return request; diff --git a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs index dde3112b2..e1d61c2b6 100644 --- a/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/HttpIndexerBase.cs @@ -6,10 +6,12 @@ using System.Net.Http; using System.Text; using System.Threading.Tasks; using FluentValidation.Results; +using MonoTorrent; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Exceptions; using NzbDrone.Core.Http.CloudFlare; using NzbDrone.Core.Indexers.Events; using NzbDrone.Core.Indexers.Exceptions; @@ -101,6 +103,95 @@ namespace NzbDrone.Core.Indexers return FetchReleases(g => SetCookieFunctions(g).GetSearchRequests(searchCriteria)); } + public override async Task Download(Uri link) + { + Cookies = GetCookies(); + + var request = await GetDownloadRequest(link); + + if (request.Url.Scheme == "magnet") + { + ValidateMagnet(request.Url.FullUri); + return Encoding.UTF8.GetBytes(request.Url.FullUri); + } + + if (request.RateLimit < RateLimit) + { + request.RateLimit = RateLimit; + } + + byte[] fileData; + + try + { + var response = await _httpClient.ExecuteProxiedAsync(request, Definition); + fileData = response.ResponseData; + + _logger.Debug("Downloaded for release finished ({0} bytes from {1})", fileData.Length, link.AbsoluteUri); + } + catch (HttpException ex) + { + if (ex.Response.StatusCode == HttpStatusCode.NotFound) + { + _logger.Error(ex, "Downloading file for release failed since it no longer exists ({0})", link.AbsoluteUri); + throw new ReleaseUnavailableException("Download failed", ex); + } + + if (ex.Response.StatusCode == HttpStatusCode.TooManyRequests) + { + _logger.Error("API Grab Limit reached for {0}", link.AbsoluteUri); + } + else + { + _logger.Error(ex, "Downloading for release failed ({0})", link.AbsoluteUri); + } + + throw new ReleaseDownloadException("Download failed", ex); + } + catch (WebException ex) + { + _logger.Error(ex, "Downloading for release failed ({0})", link.AbsoluteUri); + + throw new ReleaseDownloadException("Download failed", ex); + } + catch (Exception) + { + _indexerStatusService.RecordFailure(Definition.Id); + _logger.Error("Download failed"); + throw; + } + + ValidateDownloadData(fileData); + + return fileData; + } + + protected virtual Task GetDownloadRequest(Uri link) + { + var requestBuilder = new HttpRequestBuilder(link.AbsoluteUri) + { + AllowAutoRedirect = FollowRedirect + }; + + if (Cookies != null) + { + requestBuilder.SetCookies(Cookies); + } + + var request = requestBuilder.Build(); + + return Task.FromResult(request); + } + + protected virtual void ValidateDownloadData(byte[] fileData) + { + } + + protected void ValidateMagnet(string link) + { + MagnetLink.Parse(link); + } + protected IIndexerRequestGenerator SetCookieFunctions(IIndexerRequestGenerator generator) { //A func ensures cookies are always updated to the latest. This way, the first page could update the cookies and then can be reused by the second page. @@ -420,6 +511,11 @@ namespace NzbDrone.Core.Indexers request.RequestTimeout = TimeSpan.FromSeconds(15); } + if (request.RateLimit < RateLimit) + { + request.RateLimit = RateLimit; + } + var response = await _httpClient.ExecuteProxiedAsync(request, Definition); _eventAggregator.PublishEvent(new IndexerAuthEvent(Definition.Id, !response.HasHttpError, response.ElapsedTime)); diff --git a/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs b/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs index dda66a713..aabf2c101 100644 --- a/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/TorrentIndexerBase.cs @@ -1,12 +1,7 @@ -using System; -using System.Net; using System.Text; -using System.Threading.Tasks; using MonoTorrent; using NLog; -using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; -using NzbDrone.Core.Exceptions; using NzbDrone.Core.Messaging.Events; namespace NzbDrone.Core.Indexers @@ -19,85 +14,15 @@ namespace NzbDrone.Core.Indexers { } - public override async Task Download(Uri link) - { - Cookies = GetCookies(); - - if (link.Scheme == "magnet") - { - ValidateMagnet(link.OriginalString); - - return Encoding.UTF8.GetBytes(link.OriginalString); - } - - var requestBuilder = new HttpRequestBuilder(link.AbsoluteUri); - - if (Cookies != null) - { - requestBuilder.SetCookies(Cookies); - } - - var request = requestBuilder.Build(); - request.AllowAutoRedirect = FollowRedirect; - - byte[] torrentData; - - try - { - var response = await _httpClient.ExecuteProxiedAsync(request, Definition); - torrentData = response.ResponseData; - } - catch (HttpException ex) - { - if (ex.Response.StatusCode == HttpStatusCode.NotFound) - { - _logger.Error(ex, "Downloading torrent file for release failed since it no longer exists ({0})", link.AbsoluteUri); - throw new ReleaseUnavailableException("Downloading torrent failed", ex); - } - - if (ex.Response.StatusCode == HttpStatusCode.TooManyRequests) - { - _logger.Error("API Grab Limit reached for {0}", link.AbsoluteUri); - } - else - { - _logger.Error(ex, "Downloading torrent file for release failed ({0})", link.AbsoluteUri); - } - - throw new ReleaseDownloadException("Downloading torrent failed", ex); - } - catch (WebException ex) - { - _logger.Error(ex, "Downloading torrent file for release failed ({0})", link.AbsoluteUri); - - throw new ReleaseDownloadException("Downloading torrent failed", ex); - } - catch (Exception) - { - _indexerStatusService.RecordFailure(Definition.Id); - _logger.Error("Downloading torrent failed"); - throw; - } - - ValidateTorrent(torrentData); - - return torrentData; - } - - protected void ValidateMagnet(string link) - { - MagnetLink.Parse(link); - } - - protected void ValidateTorrent(byte[] torrentData) + protected override void ValidateDownloadData(byte[] fileData) { try { - Torrent.Load(torrentData); + Torrent.Load(fileData); } catch { - _logger.Trace("Invalid torrent file contents: {0}", Encoding.ASCII.GetString(torrentData)); + _logger.Trace("Invalid torrent file contents: {0}", Encoding.ASCII.GetString(fileData)); throw; } } diff --git a/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs b/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs index f8104a844..b40d8fba8 100644 --- a/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs +++ b/src/NzbDrone.Core/Indexers/UsenetIndexerBase.cs @@ -1,11 +1,6 @@ -using System; -using System.Net; -using System.Threading.Tasks; using NLog; -using NzbDrone.Common.Http; using NzbDrone.Core.Configuration; using NzbDrone.Core.Download; -using NzbDrone.Core.Exceptions; using NzbDrone.Core.Messaging.Events; namespace NzbDrone.Core.Indexers @@ -21,64 +16,9 @@ namespace NzbDrone.Core.Indexers _nzbValidationService = nzbValidationService; } - public override async Task Download(Uri link) + protected override void ValidateDownloadData(byte[] fileData) { - Cookies = GetCookies(); - - var requestBuilder = new HttpRequestBuilder(link.AbsoluteUri); - - if (Cookies != null) - { - requestBuilder.SetCookies(Cookies); - } - - var request = requestBuilder.Build(); - request.AllowAutoRedirect = FollowRedirect; - - byte[] nzbData; - - try - { - var response = await _httpClient.ExecuteProxiedAsync(request, Definition); - nzbData = response.ResponseData; - - _logger.Debug("Downloaded nzb for release finished ({0} bytes from {1})", nzbData.Length, link.AbsoluteUri); - } - catch (HttpException ex) - { - if (ex.Response.StatusCode == HttpStatusCode.NotFound) - { - _logger.Error(ex, "Downloading nzb file for release failed since it no longer exists ({0})", link.AbsoluteUri); - throw new ReleaseUnavailableException("Downloading nzb failed", ex); - } - - if (ex.Response.StatusCode == HttpStatusCode.TooManyRequests) - { - _logger.Error("API Grab Limit reached for {0}", link.AbsoluteUri); - } - else - { - _logger.Error(ex, "Downloading nzb for release failed ({0})", link.AbsoluteUri); - } - - throw new ReleaseDownloadException("Downloading nzb failed", ex); - } - catch (WebException ex) - { - _logger.Error(ex, "Downloading nzb for release failed ({0})", link.AbsoluteUri); - - throw new ReleaseDownloadException("Downloading nzb failed", ex); - } - catch (Exception) - { - _indexerStatusService.RecordFailure(Definition.Id); - _logger.Error("Downloading nzb failed"); - throw; - } - - _nzbValidationService.Validate(nzbData); - - return nzbData; + _nzbValidationService.Validate(fileData); } } } From 1640980e2bbc56500d0c5a7b3abd4a702a7a6b01 Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 19 Nov 2022 12:07:08 -0600 Subject: [PATCH 0886/2320] New: OnGrab Notifications --- frontend/src/Search/Table/SearchIndexRow.js | 18 ++++- frontend/src/Search/Table/SearchIndexTable.js | 5 +- .../Search/Table/SearchIndexTableConnector.js | 5 +- .../Notifications/Notification.js | 46 +---------- .../Notifications/NotificationEventItems.js | 28 +++++++ .../Store/Actions/Settings/notifications.js | 3 - frontend/src/Store/Actions/releaseActions.js | 29 +++++++ frontend/src/Utilities/createAjaxRequest.js | 6 ++ src/NzbDrone.Common/Http/UserAgentParser.cs | 5 -- .../NotificationBaseFixture.cs | 8 +- .../029_add_on_grab_to_notifications.cs | 15 ++++ src/NzbDrone.Core/Datastore/TableMapping.cs | 1 + src/NzbDrone.Core/Download/DownloadService.cs | 67 +++++++++++++--- src/NzbDrone.Core/History/HistoryService.cs | 2 +- .../Indexers/Events/IndexerDownloadEvent.cs | 19 ++++- src/NzbDrone.Core/Localization/Core/en.json | 4 +- .../Notifications/Apprise/Apprise.cs | 5 ++ .../Notifications/Boxcar/Boxcar.cs | 6 ++ .../Notifications/Discord/Discord.cs | 59 ++++++++++++++ .../Notifications/Discord/DiscordFieldType.cs | 31 ++------ .../Notifications/Discord/DiscordSettings.cs | 4 - .../Notifications/Email/Email.cs | 5 ++ .../Notifications/Gotify/Gotify.cs | 5 ++ .../Notifications/GrabMessage.cs | 25 ++++++ .../Notifications/INotification.cs | 2 + src/NzbDrone.Core/Notifications/Join/Join.cs | 5 ++ .../Notifications/Notifiarr/Notifiarr.cs | 6 ++ .../Notifications/NotificationBase.cs | 7 ++ .../Notifications/NotificationDefinition.cs | 5 +- .../Notifications/NotificationFactory.cs | 7 ++ .../Notifications/NotificationService.cs | 77 ++++++++++++++++++- src/NzbDrone.Core/Notifications/Ntfy/Ntfy.cs | 5 ++ .../Notifications/Prowl/Prowl.cs | 5 ++ .../Notifications/PushBullet/PushBullet.cs | 5 ++ .../Notifications/Pushover/Pushover.cs | 5 ++ .../Notifications/SendGrid/SendGrid.cs | 5 ++ .../Notifications/Simplepush/Simplepush.cs | 5 ++ .../Notifications/Telegram/Telegram.cs | 5 ++ .../Notifications/Twitter/Twitter.cs | 6 ++ .../Notifications/Webhook/Webhook.cs | 5 ++ .../Notifications/Webhook/WebhookBase.cs | 16 ++++ .../Webhook/WebhookGrabPayload.cs | 15 ++++ .../Notifications/Webhook/WebhookRelease.cs | 22 ++++++ .../Indexers/NewznabController.cs | 4 +- .../Notifications/NotificationResource.cs | 9 +++ src/Prowlarr.Api.V1/Search/ReleaseResource.cs | 16 ++++ .../Search/SearchController.cs | 4 +- .../Extensions/RequestExtensions.cs | 12 ++- 48 files changed, 543 insertions(+), 111 deletions(-) create mode 100644 src/NzbDrone.Core/Datastore/Migration/029_add_on_grab_to_notifications.cs create mode 100644 src/NzbDrone.Core/Notifications/GrabMessage.cs create mode 100644 src/NzbDrone.Core/Notifications/Webhook/WebhookGrabPayload.cs create mode 100644 src/NzbDrone.Core/Notifications/Webhook/WebhookRelease.cs diff --git a/frontend/src/Search/Table/SearchIndexRow.js b/frontend/src/Search/Table/SearchIndexRow.js index a54876c8f..2645c02eb 100644 --- a/frontend/src/Search/Table/SearchIndexRow.js +++ b/frontend/src/Search/Table/SearchIndexRow.js @@ -71,6 +71,19 @@ class SearchIndexRow extends Component { }); }; + onSavePress = () => { + const { + downloadUrl, + fileName, + onSavePress + } = this.props; + + onSavePress({ + downloadUrl, + fileName + }); + }; + // // Render @@ -85,7 +98,6 @@ class SearchIndexRow extends Component { publishDate, title, infoUrl, - downloadUrl, indexer, size, files, @@ -300,7 +312,7 @@ class SearchIndexRow extends Component { className={styles.downloadLink} name={icons.SAVE} title={translate('Save')} - to={downloadUrl} + onPress={this.onSavePress} /> ); @@ -323,6 +335,7 @@ SearchIndexRow.propTypes = { ageMinutes: PropTypes.number.isRequired, publishDate: PropTypes.string.isRequired, title: PropTypes.string.isRequired, + fileName: PropTypes.string.isRequired, infoUrl: PropTypes.string.isRequired, downloadUrl: PropTypes.string.isRequired, indexerId: PropTypes.number.isRequired, @@ -335,6 +348,7 @@ SearchIndexRow.propTypes = { indexerFlags: PropTypes.arrayOf(PropTypes.string).isRequired, columns: PropTypes.arrayOf(PropTypes.object).isRequired, onGrabPress: PropTypes.func.isRequired, + onSavePress: PropTypes.func.isRequired, isGrabbing: PropTypes.bool.isRequired, isGrabbed: PropTypes.bool.isRequired, grabError: PropTypes.string, diff --git a/frontend/src/Search/Table/SearchIndexTable.js b/frontend/src/Search/Table/SearchIndexTable.js index 7f1f44118..844628062 100644 --- a/frontend/src/Search/Table/SearchIndexTable.js +++ b/frontend/src/Search/Table/SearchIndexTable.js @@ -51,7 +51,8 @@ class SearchIndexTable extends Component { timeFormat, selectedState, onSelectedChange, - onGrabPress + onGrabPress, + onSavePress } = this.props; const release = items[rowIndex]; @@ -71,6 +72,7 @@ class SearchIndexTable extends Component { longDateFormat={longDateFormat} timeFormat={timeFormat} onGrabPress={onGrabPress} + onSavePress={onSavePress} /> ); @@ -134,6 +136,7 @@ SearchIndexTable.propTypes = { timeFormat: PropTypes.string.isRequired, onSortPress: PropTypes.func.isRequired, onGrabPress: PropTypes.func.isRequired, + onSavePress: PropTypes.func.isRequired, allSelected: PropTypes.bool.isRequired, allUnselected: PropTypes.bool.isRequired, selectedState: PropTypes.object.isRequired, diff --git a/frontend/src/Search/Table/SearchIndexTableConnector.js b/frontend/src/Search/Table/SearchIndexTableConnector.js index e73b9ab9a..13ab84c7d 100644 --- a/frontend/src/Search/Table/SearchIndexTableConnector.js +++ b/frontend/src/Search/Table/SearchIndexTableConnector.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { grabRelease, setReleasesSort } from 'Store/Actions/releaseActions'; +import { grabRelease, saveRelease, setReleasesSort } from 'Store/Actions/releaseActions'; import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector'; import SearchIndexTable from './SearchIndexTable'; @@ -25,6 +25,9 @@ function createMapDispatchToProps(dispatch, props) { }, onGrabPress(payload) { dispatch(grabRelease(payload)); + }, + onSavePress(payload) { + dispatch(saveRelease(payload)); } }; } diff --git a/frontend/src/Settings/Notifications/Notifications/Notification.js b/frontend/src/Settings/Notifications/Notifications/Notification.js index e4a2847d9..1331a7c8b 100644 --- a/frontend/src/Settings/Notifications/Notifications/Notification.js +++ b/frontend/src/Settings/Notifications/Notifications/Notification.js @@ -56,17 +56,9 @@ class Notification extends Component { id, name, onGrab, - onDownload, - onUpgrade, - onRename, - onDelete, onHealthIssue, onApplicationUpdate, supportsOnGrab, - supportsOnDownload, - supportsOnUpgrade, - supportsOnRename, - supportsOnDelete, supportsOnHealthIssue, supportsOnApplicationUpdate } = this.props; @@ -88,34 +80,6 @@ class Notification extends Component { } - { - supportsOnDelete && onDelete && - - } - - { - supportsOnDownload && onDownload && - - } - - { - supportsOnUpgrade && onDownload && onUpgrade && - - } - - { - supportsOnRename && onRename && - - } - { supportsOnHealthIssue && onHealthIssue &&